Index: code/trunk/src/CMakeLists.txt
===================================================================
--- code/trunk/src/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/CMakeLists.txt	(revision 7163)
@@ -31,5 +31,5 @@
 INCLUDE(OrxonoxConfig.cmake)
 
-################ Library Defines ################
+####### Library Behaviour (dependencies) ########
 
 # Disable Boost auto linking completely
@@ -40,5 +40,4 @@
 ADD_COMPILER_FLAGS("-DENET_DLL"           WIN32 LINK_ENET_DYNAMIC)
 ADD_COMPILER_FLAGS("-DLUA_BUILD_AS_DLL"   WIN32 LINK_LUA_DYNAMIC)
-ADD_COMPILER_FLAGS("-DOIS_DYNAMIC_LIB")
 ADD_COMPILER_FLAGS("-DZLIB_DLL"           WIN32 LINK_ZLIB_DYNAMIC)
 # If no defines are specified, these libs get linked dynamically
@@ -47,6 +46,22 @@
 ADD_COMPILER_FLAGS("-DSTATIC_BUILD"       WIN32 NOT LINK_TCL_DYNAMIC)
 
+######### Library Behaviour (external) ##########
+
 # Use TinyXML++
 ADD_COMPILER_FLAGS("-DTIXML_USE_TICPP")
+
+# Default linking for externals is SHARED
+SET(ORXONOX_EXTERNAL_LINK_MODE SHARED CACHE STRING "Link mode for external libraries that we build ourselves. Note: on Windows, some libraries cannot be linked shared.")
+
+IF(ORXONOX_EXTERNAL_LINK_MODE STREQUAL "SHARED")
+  SET(_external_shared_link TRUE)
+ELSE()
+  SET(_external_shared_link FALSE)
+ENDIF()
+# If no defines are specified, these libs get linked dynamically
+ADD_COMPILER_FLAGS("-DCEGUILUA_STATIC"             WIN32 NOT _external_shared_link)
+ADD_COMPILER_FLAGS("-DOGRE_GUIRENDERER_STATIC_LIB" WIN32 NOT _external_shared_link)
+ADD_COMPILER_FLAGS("-DOIS_STATIC_LIB"              WIN32 NOT _external_shared_link)
+ADD_COMPILER_FLAGS("-DTOLUA_STATIC_BUILD"          WIN32 NOT _external_shared_link)
 
 ############## Include Directories ##############
Index: code/trunk/src/OrxonoxConfig.cmake
===================================================================
--- code/trunk/src/OrxonoxConfig.cmake	(revision 6906)
+++ code/trunk/src/OrxonoxConfig.cmake	(revision 7163)
@@ -27,7 +27,4 @@
 
 #################### Options ####################
-
-# Default linking is SHARED
-SET(ORXONOX_DEFAULT_LINK SHARED)
 
 # Use, i.e. don't skip the full RPATH for the build tree
Index: code/trunk/src/external/ceguilua/CMakeLists.txt
===================================================================
--- code/trunk/src/external/ceguilua/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/external/ceguilua/CMakeLists.txt	(revision 7163)
@@ -56,10 +56,10 @@
 ADD_CUSTOM_COMMAND(
   OUTPUT ${CEGUILUA_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lua_CEGUI.cpp
-  COMMAND tolua++app_orxonox -n CEGUI
-                             -w ${CEGUILUA_BINARY_DIR}
-                             -o ${CMAKE_CFG_INTDIR}/lua_CEGUI.cpp
-                             -L exceptions.lua
-                             -s ${TOLUA_PARSER_SOURCE}
-                                CEGUI.pkg
+  COMMAND toluaapp_orxonox -n CEGUI
+                           -w ${CEGUILUA_BINARY_DIR}
+                           -o ${CMAKE_CFG_INTDIR}/lua_CEGUI.cpp
+                           -L exceptions.lua
+                           -s ${TOLUA_PARSER_SOURCE}
+                              CEGUI.pkg
   DEPENDS              ${TOLUA_PARSER_DEPENDENCIES}
   WORKING_DIRECTORY    ${RUNTIME_LIBRARY_DIRECTORY}
@@ -79,5 +79,5 @@
     ${CEGUI_VERSION}
   LINK_LIBRARIES
-    tolua++_orxonox
+    tolua_orxonox
     ${LUA_LIBRARIES}
     ${CEGUI_LIBRARY}
Index: code/trunk/src/external/ceguilua/ceguilua-0.6.0/ceguilua/CEGUILua.h
===================================================================
--- code/trunk/src/external/ceguilua/ceguilua-0.6.0/ceguilua/CEGUILua.h	(revision 6906)
+++ code/trunk/src/external/ceguilua/ceguilua-0.6.0/ceguilua/CEGUILua.h	(revision 7163)
@@ -35,5 +35,5 @@
 	Import / Export control macros
 *************************************************************************/
-#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUI_STATIC)
+#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUILUA_STATIC)
 #   ifdef CEGUILUA_EXPORTS
 #       define CEGUILUA_API __declspec(dllexport)
Index: code/trunk/src/external/ceguilua/ceguilua-0.6.0/ceguilua/changes_orxonox.diff
===================================================================
--- code/trunk/src/external/ceguilua/ceguilua-0.6.0/ceguilua/changes_orxonox.diff	(revision 6906)
+++ code/trunk/src/external/ceguilua/ceguilua-0.6.0/ceguilua/changes_orxonox.diff	(revision 7163)
@@ -67,5 +67,10 @@
 --- CEGUILua.h	Wed Jul  9 18:24:49 2008
 +++ CEGUILua.h	Thu Jan 29 10:17:07 2009
-@@ -38,7 +38,11 @@
+@@ -34,11 +34,15 @@
+ /*************************************************************************
+ 	Import / Export control macros
+ *************************************************************************/
+-#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUI_STATIC)
++#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUILUA_STATIC)
  #   ifdef CEGUILUA_EXPORTS
  #       define CEGUILUA_API __declspec(dllexport)
Index: code/trunk/src/external/ceguilua/ceguilua-0.6.1/ceguilua/CEGUILua.h
===================================================================
--- code/trunk/src/external/ceguilua/ceguilua-0.6.1/ceguilua/CEGUILua.h	(revision 6906)
+++ code/trunk/src/external/ceguilua/ceguilua-0.6.1/ceguilua/CEGUILua.h	(revision 7163)
@@ -35,5 +35,5 @@
 	Import / Export control macros
 *************************************************************************/
-#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUI_STATIC)
+#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUILUA_STATIC)
 #   ifdef CEGUILUA_EXPORTS
 #       define CEGUILUA_API __declspec(dllexport)
Index: code/trunk/src/external/ceguilua/ceguilua-0.6.1/ceguilua/changes_orxonox.diff
===================================================================
--- code/trunk/src/external/ceguilua/ceguilua-0.6.1/ceguilua/changes_orxonox.diff	(revision 6906)
+++ code/trunk/src/external/ceguilua/ceguilua-0.6.1/ceguilua/changes_orxonox.diff	(revision 7163)
@@ -1,5 +1,10 @@
 --- CEGUILua.h	Mi Jul  9 18:24:49 2008
 +++ CEGUILua.h	Do Jan 29 10:18:14 2009
-@@ -38,7 +38,11 @@
+@@ -34,11 +34,15 @@
+ /*************************************************************************
+ 	Import / Export control macros
+ *************************************************************************/
+-#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUI_STATIC)
++#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUILUA_STATIC)
  #   ifdef CEGUILUA_EXPORTS
  #       define CEGUILUA_API __declspec(dllexport)
Index: code/trunk/src/external/ceguilua/ceguilua-0.6.2/ceguilua/CEGUILua.h
===================================================================
--- code/trunk/src/external/ceguilua/ceguilua-0.6.2/ceguilua/CEGUILua.h	(revision 6906)
+++ code/trunk/src/external/ceguilua/ceguilua-0.6.2/ceguilua/CEGUILua.h	(revision 7163)
@@ -35,5 +35,5 @@
 	Import / Export control macros
 *************************************************************************/
-#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUI_STATIC)
+#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUILUA_STATIC)
 #   ifdef CEGUILUA_EXPORTS
 #       define CEGUILUA_API __declspec(dllexport)
Index: code/trunk/src/external/ceguilua/ceguilua-0.6.2/ceguilua/changes_orxonox.diff
===================================================================
--- code/trunk/src/external/ceguilua/ceguilua-0.6.2/ceguilua/changes_orxonox.diff	(revision 6906)
+++ code/trunk/src/external/ceguilua/ceguilua-0.6.2/ceguilua/changes_orxonox.diff	(revision 7163)
@@ -82,5 +82,10 @@
 --- CEGUILua.h	Sun Jan 25 18:32:57 2009
 +++ CEGUILua.h	Thu Jan 29 10:17:42 2009
-@@ -38,7 +38,11 @@
+@@ -34,11 +34,15 @@
+ /*************************************************************************
+ 	Import / Export control macros
+ *************************************************************************/
+-#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUI_STATIC)
++#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUILUA_STATIC)
  #   ifdef CEGUILUA_EXPORTS
  #       define CEGUILUA_API __declspec(dllexport)
Index: code/trunk/src/external/ogreceguirenderer/CMakeLists.txt
===================================================================
--- code/trunk/src/external/ogreceguirenderer/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/external/ogreceguirenderer/CMakeLists.txt	(revision 7163)
@@ -32,11 +32,11 @@
 ORXONOX_ADD_LIBRARY(ogreceguirenderer_orxonox
   ORXONOX_EXTERNAL
-  LINK_LIBRARIES
-    ${OGRE_LIBRARY}
-    ${CEGUI_LIBRARY}
   DEFINE_SYMBOL
     "OGRE_GUIRENDERER_EXPORTS"
   VERSION
     1.4.9
+  LINK_LIBRARIES
+    ${OGRE_LIBRARY}
+    ${CEGUI_LIBRARY}
   SOURCE_FILES
     ${OCR_FILES}
Index: code/trunk/src/external/ogreceguirenderer/OgreCEGUIRenderer.h
===================================================================
--- code/trunk/src/external/ogreceguirenderer/OgreCEGUIRenderer.h	(revision 6906)
+++ code/trunk/src/external/ogreceguirenderer/OgreCEGUIRenderer.h	(revision 7163)
@@ -38,5 +38,5 @@
 #include <OgreTextureUnitState.h>
 
-#if (OGRE_PLATFORM == OGRE_PLATFORM_WIN32) && !defined(OGRE_STATIC_LIB)
+#if (OGRE_PLATFORM == OGRE_PLATFORM_WIN32) && !defined(OGRE_GUIRENDERER_STATIC_LIB)
 #   ifdef OGRE_GUIRENDERER_EXPORTS
 #       define OGRE_GUIRENDERER_API __declspec(dllexport)
Index: code/trunk/src/external/ogreceguirenderer/changes_orxonox.diff
===================================================================
--- code/trunk/src/external/ogreceguirenderer/changes_orxonox.diff	(revision 6906)
+++ code/trunk/src/external/ogreceguirenderer/changes_orxonox.diff	(revision 7163)
@@ -32,5 +32,5 @@
 --- OgreCEGUIRenderer.h	Wed Jan 28 21:14:09 2009
 +++ OgreCEGUIRenderer.h	Wed Jan 28 21:06:46 2009
-@@ -29,9 +29,9 @@
+@@ -29,15 +29,15 @@
  #ifndef _OgreCEGUIRenderer_h_
  #define _OgreCEGUIRenderer_h_
@@ -45,4 +45,11 @@
  #include <OgreRenderQueueListener.h>
  #include <OgreSceneManagerEnumerator.h>
+ #include <OgreTextureUnitState.h>
+
+-#if (OGRE_PLATFORM == OGRE_PLATFORM_WIN32) && !defined(OGRE_STATIC_LIB)
++#if (OGRE_PLATFORM == OGRE_PLATFORM_WIN32) && !defined(OGRE_GUIRENDERER_STATIC_LIB)
+ #   ifdef OGRE_GUIRENDERER_EXPORTS
+ #       define OGRE_GUIRENDERER_API __declspec(dllexport)
+ #   else
 --- OgreCEGUIResourceProvider.cpp	Wed Jan 28 21:14:09 2009
 +++ OgreCEGUIResourceProvider.cpp	Wed Jan 28 21:07:15 2009
Index: code/trunk/src/external/ois/OISPrereqs.h
===================================================================
--- code/trunk/src/external/ois/OISPrereqs.h	(revision 6906)
+++ code/trunk/src/external/ois/OISPrereqs.h	(revision 7163)
@@ -61,5 +61,5 @@
 #	else
 #		define OIS_WIN32_PLATFORM
-#		if defined( OIS_DYNAMIC_LIB )
+#		if !defined( OIS_STATIC_LIB )
 #			undef _OISExport
 			//Ignorable Dll interface warning...
Index: code/trunk/src/external/ois/changes_orxonox.diff
===================================================================
--- code/trunk/src/external/ois/changes_orxonox.diff	(revision 6906)
+++ code/trunk/src/external/ois/changes_orxonox.diff	(revision 7163)
@@ -1,2 +1,13 @@
+--- OISPrereqs.h	(revision 7141)
++++ OISPrereqs.h	(working copy)
+@@ -60,7 +60,7 @@
+ #		define OIS_XBOX_PLATFORM
+ #	else
+ #		define OIS_WIN32_PLATFORM
+-#		if defined( OIS_DYNAMIC_LIB )
++#		if !defined( OIS_STATIC_LIB )
+ #			undef _OISExport
+ 			//Ignorable Dll interface warning...
+ #           if !defined(OIS_MINGW_COMPILER)
 --- linux/EventHelpers.cpp	(revision 5668)
 +++ linux/EventHelpers.cpp	(working copy)
Index: code/trunk/src/external/tinyxml/CMakeLists.txt
===================================================================
--- code/trunk/src/external/tinyxml/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/external/tinyxml/CMakeLists.txt	(revision 7163)
@@ -18,5 +18,5 @@
  #
 
-SET_SOURCE_FILES(TINYXML++_FILES
+SET_SOURCE_FILES(TINYXML_FILES
   ticpp.h
   ticpprc.h
@@ -33,5 +33,5 @@
 )
 
-ORXONOX_ADD_LIBRARY(tinyxml++_orxonox
+ORXONOX_ADD_LIBRARY(tinyxml_orxonox
   ORXONOX_EXTERNAL
   NO_DLL_INTERFACE
@@ -39,4 +39,4 @@
     2.5.3
   SOURCE_FILES
-    ${TINYXML++_FILES}
+    ${TINYXML_FILES}
 )
Index: code/trunk/src/external/tolua/CMakeLists.txt
===================================================================
--- code/trunk/src/external/tolua/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/external/tolua/CMakeLists.txt	(revision 7163)
@@ -20,5 +20,5 @@
 ################### Tolua++ library ###################
 
-SET_SOURCE_FILES(TOLUA++_FILES
+SET_SOURCE_FILES(TOLUA_FILES
   tolua_event.h
   tolua++.h
@@ -32,5 +32,5 @@
 )
 
-ORXONOX_ADD_LIBRARY(tolua++_orxonox
+ORXONOX_ADD_LIBRARY(tolua_orxonox
   ORXONOX_EXTERNAL
   DEFINE_SYMBOL
@@ -41,5 +41,5 @@
     ${LUA_LIBRARIES}
   SOURCE_FILES
-    ${TOLUA++_FILES}
+    ${TOLUA_FILES}
 )
 
@@ -47,5 +47,5 @@
 ################## Tolua++ generator ##################
 
-ORXONOX_ADD_EXECUTABLE(tolua++app_orxonox
+ORXONOX_ADD_EXECUTABLE(toluaapp_orxonox
   ORXONOX_EXTERNAL
   VERSION
@@ -61,5 +61,5 @@
 SET(TOLUA_PARSER_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/all-${LUA_VERSION}.lua" CACHE INTERNAL "")
 SET(TOLUA_PARSER_DEPENDENCIES
-  tolua++app_orxonox
+  toluaapp_orxonox
   ${CMAKE_CURRENT_SOURCE_DIR}/all-${LUA_VERSION}.lua
   ${CMAKE_CURRENT_SOURCE_DIR}/lua/compat-5.1.lua
Index: code/trunk/src/libraries/core/BaseObject.cc
===================================================================
--- code/trunk/src/libraries/core/BaseObject.cc	(revision 6906)
+++ code/trunk/src/libraries/core/BaseObject.cc	(revision 7163)
@@ -75,4 +75,5 @@
             this->setScene(this->creator_->getScene(), this->creator_->getSceneID());
             this->setGametype(this->creator_->getGametype());
+            this->setLevel(this->creator_->getLevel());
         }
         else
@@ -83,4 +84,5 @@
             this->sceneID_ = OBJECTID_UNKNOWN;
             this->gametype_ = 0;
+            this->level_ = 0;
         }
     }
@@ -103,5 +105,5 @@
         }
     }
-    
+
     /** @brief Adds an object which listens to the events of this object. */
     void BaseObject::registerEventListener(BaseObject* object)
@@ -123,5 +125,5 @@
         XMLPortParam(BaseObject, "mainstate", setMainStateName, getMainStateName, xmlelement, mode);
         XMLPortParamTemplate(BaseObject, "template", addTemplate, getSingleTemplate, xmlelement, mode, const std::string&);
-        
+
         XMLPortObjectTemplate(BaseObject, Template, "templates", addTemplate, getTemplate, xmlelement, mode, Template*);
         XMLPortObject(BaseObject, BaseObject, "eventlisteners", addEventListener, getEventListener, xmlelement, mode);
@@ -194,4 +196,11 @@
     {
         this->templates_.insert(temp);
+        if( temp->isLink() )
+        {
+          this->networkTemplateNames_.insert(temp->getLink());
+          assert( !Template::getTemplate(temp->getLink())->isLink() );
+        }
+        else
+          this->networkTemplateNames_.insert(temp->getName());
         temp->applyOn(this);
     }
@@ -363,5 +372,5 @@
     {
         this->registerEventStates();
-        
+
         COUT(4) << this->getIdentifier()->getName() << " (&" << this << ") processing event. originator: " << event.originator_->getIdentifier()->getName() << " (&" << event.originator_ << "), activate: " << event.activate_ << ", name: " << event.name_ << ", statename: " << event.statename_ << "." << std::endl;
 
Index: code/trunk/src/libraries/core/BaseObject.h
===================================================================
--- code/trunk/src/libraries/core/BaseObject.h	(revision 6906)
+++ code/trunk/src/libraries/core/BaseObject.h	(revision 7163)
@@ -51,4 +51,5 @@
     class Scene;
     class Gametype;
+    class Level;
 
     //! The BaseObject is the parent of all classes representing an instance in the game.
@@ -154,4 +155,15 @@
             virtual void changedGametype() {}
 
+            inline void setLevel(const SmartPtr<Level>& level)
+            {
+                if (level != this->level_)
+                {
+                    this->level_ = level;
+                    this->changedLevel();
+                }
+            }
+            inline const SmartPtr<Level>& getLevel() const { return this->level_; }
+            virtual void changedLevel() {}
+
             void addEventSource(BaseObject* source, const std::string& state);
             void removeEventSource(BaseObject* source);
@@ -179,10 +191,11 @@
             EventState* getEventState(const std::string& name) const;
 
-            std::string name_;                                 //!< The name of the object
-            std::string oldName_;                              //!< The old name of the object
-            mbool       bActive_;                              //!< True = the object is active
-            mbool       bVisible_;                             //!< True = the object is visible
-            std::string mainStateName_;
-            Functor*    mainStateFunctor_;
+            std::string             name_;                     //!< The name of the object
+            std::string             oldName_;                  //!< The old name of the object
+            mbool                   bActive_;                  //!< True = the object is active
+            mbool                   bVisible_;                 //!< True = the object is visible
+            std::string             mainStateName_;
+            Functor*                mainStateFunctor_;
+            std::set<std::string>   networkTemplateNames_;
 
         private:
@@ -209,4 +222,5 @@
             SmartPtr<Gametype>     gametype_;
             Gametype*              oldGametype_;
+            SmartPtr<Level>        level_;
             std::set<Template*>    templates_;
 
Index: code/trunk/src/libraries/core/CMakeLists.txt
===================================================================
--- code/trunk/src/libraries/core/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/libraries/core/CMakeLists.txt	(revision 7163)
@@ -96,6 +96,4 @@
     input/KeyBinder.h
     input/KeyBinderManager.h
-  DEFINE_SYMBOL
-    "CORE_SHARED_BUILD"
   PCH_FILE
     CorePrecompiledHeaders.h
@@ -112,6 +110,6 @@
     ogreceguirenderer_orxonox
     ois_orxonox
-    tinyxml++_orxonox
-    tolua++_orxonox
+    tinyxml_orxonox
+    tolua_orxonox
     util
   SOURCE_FILES
Index: code/trunk/src/libraries/core/ConfigFileManager.cc
===================================================================
--- code/trunk/src/libraries/core/ConfigFileManager.cc	(revision 6906)
+++ code/trunk/src/libraries/core/ConfigFileManager.cc	(revision 7163)
@@ -33,4 +33,5 @@
 #include "util/Convert.h"
 #include "util/Math.h"
+#include "util/StringUtils.h"
 #include "ConsoleCommand.h"
 #include "ConfigValueContainer.h"
Index: code/trunk/src/libraries/core/ConfigFileManager.h
===================================================================
--- code/trunk/src/libraries/core/ConfigFileManager.h	(revision 6906)
+++ code/trunk/src/libraries/core/ConfigFileManager.h	(revision 7163)
@@ -39,5 +39,4 @@
 
 #include "util/Singleton.h"
-#include "util/StringUtils.h"
 
 namespace orxonox // tolua_export
Index: code/trunk/src/libraries/core/Core.cc
===================================================================
--- code/trunk/src/libraries/core/Core.cc	(revision 6906)
+++ code/trunk/src/libraries/core/Core.cc	(revision 7163)
@@ -79,4 +79,5 @@
     SetCommandLineArgument(settingsFile, "orxonox.ini").information("THE configuration file");
     SetCommandLineSwitch(noIOConsole).information("Use this if you don't want to use the IOConsole (for instance for Lua debugging)");
+
 #ifdef ORXONOX_PLATFORM_WINDOWS
     SetCommandLineArgument(limitToCPU, 1).information("Limits the program to one CPU/core (1, 2, 3, etc.). Default is the first core (faster than off)");
Index: code/trunk/src/libraries/core/Event.cc
===================================================================
--- code/trunk/src/libraries/core/Event.cc	(revision 6906)
+++ code/trunk/src/libraries/core/Event.cc	(revision 7163)
@@ -60,5 +60,5 @@
 
         COUT(4) << "Processing event (EventState) : originator: " << event.originator_->getIdentifier()->getName() << " (&" << event.originator_ << "), activate: " << event.activate_ << ", name: " << event.name_ << ", statename: " << event.statename_ << ", object: " << object->getIdentifier()->getName() << " (&" << object << ")" << "." << std::endl;
-        
+
         // check if the originator is an instance of the requested class
         if (event.originator_->isA(this->subclass_))
Index: code/trunk/src/libraries/core/EventIncludes.h
===================================================================
--- code/trunk/src/libraries/core/EventIncludes.h	(revision 6906)
+++ code/trunk/src/libraries/core/EventIncludes.h	(revision 7163)
@@ -52,5 +52,5 @@
     } \
     XMLPortEventStateIntern(xmlportevent##function, classname, statename, xmlelement, mode)
-    
+
 #define XMLPortEventSink(classname, subclassname, statename, function, xmlelement, mode) \
     orxonox::EventState* containername##function = this->getEventState(statename); \
Index: code/trunk/src/libraries/core/Executor.cc
===================================================================
--- code/trunk/src/libraries/core/Executor.cc	(revision 6906)
+++ code/trunk/src/libraries/core/Executor.cc	(revision 7163)
@@ -30,5 +30,10 @@
 #include "Executor.h"
 
+#include <algorithm>
+
 #include "util/Convert.h"
+#include "util/Debug.h"
+#include "util/StringUtils.h"
+#include "util/SubString.h"
 #include "Language.h"
 
@@ -63,5 +68,87 @@
     bool Executor::parse(const std::string& params, const std::string& delimiter) const
     {
-        EXECUTOR_PARSE(normal);
+        unsigned int paramCount = this->functor_->getParamCount();
+       
+        if (paramCount == 0)
+        {
+            COUT(5) << "Calling Executor " << this->name_ << " through parser without parameters." << std::endl;
+            (*this->functor_)();
+        }
+        else if (paramCount == 1)
+        {
+            const std::string& temp = getStripped(params);
+            if (!temp.empty())
+            {
+                COUT(5) << "Calling Executor " << this->name_ << " through parser with one parameter, using whole string: " << params << std::endl;
+                (*this->functor_)(MultiType(params));
+            }
+            else if (this->bAddedDefaultValue_[0])
+            {
+                COUT(5) << "Calling Executor " << this->name_ << " through parser with one parameter, using default value: " << this->defaultValue_[0] << std::endl;
+                (*this->functor_)(this->defaultValue_[0]);
+            }
+            else
+            {
+                COUT(2) << "Warning: Can't call executor " << this->name_ << " through parser: Not enough parameters or default values given (input: " << temp << ")." << std::endl;
+                return false;
+            }
+        }
+        else
+        {
+            SubString tokens(params, delimiter, SubString::WhiteSpaces, false, '\\', true, '"', true, '(', ')', true, '\0');
+           
+            for (unsigned int i = tokens.size(); i < this->functor_->getParamCount(); i++)
+            {
+                if (!this->bAddedDefaultValue_[i])
+                {
+                    COUT(2) << "Warning: Can't call executor " << this->name_ << " through parser: Not enough parameters or default values given (input:" << params << ")." << std::endl;
+                    return false;
+                }
+            }
+           
+            MultiType param[MAX_FUNCTOR_ARGUMENTS];
+            COUT(5) << "Calling Executor " << this->name_ << " through parser with " << paramCount << " parameters, using " << tokens.size() << " tokens (";
+            for (unsigned int i = 0; i < tokens.size() && i < MAX_FUNCTOR_ARGUMENTS; i++)
+            {
+                param[i] = tokens[i];
+                if (i != 0)
+                {
+                    COUT(5) << ", ";
+                }
+                COUT(5) << tokens[i];
+            }
+            COUT(5) << ") and " << std::max((int)paramCount - (int)tokens.size(), 0) << " default values (";
+            for (unsigned int i = tokens.size(); i < paramCount; i++)
+            {
+                param[i] = this->defaultValue_[i];
+                if (i != 0)
+                {
+                    COUT(5) << ", ";
+                }
+                COUT(5) << this->defaultValue_[i];
+            }
+            COUT(5) << ")." << std::endl;
+           
+            if ((tokens.size() > paramCount) && (this->functor_->getTypenameParam(paramCount - 1) == "string"))
+                param[paramCount - 1] = tokens.subSet(paramCount - 1).join();
+           
+            switch(paramCount)
+            {
+                case 2:
+                    (*this->functor_)(param[0], param[1]);
+                    break;
+                case 3:
+                    (*this->functor_)(param[0], param[1], param[2]);
+                    break;
+                case 4:
+                    (*this->functor_)(param[0], param[1], param[2], param[3]);
+                    break;
+                case 5:
+                    (*this->functor_)(param[0], param[1], param[2], param[3], param[4]);
+                    break;
+            }
+        }
+
+        return true;
     }
 
Index: code/trunk/src/libraries/core/Executor.h
===================================================================
--- code/trunk/src/libraries/core/Executor.h	(revision 6906)
+++ code/trunk/src/libraries/core/Executor.h	(revision 7163)
@@ -33,108 +33,7 @@
 #include "CorePrereqs.h"
 
-#include <algorithm>
 #include <string>
-
-#include "util/Debug.h"
-#include "util/Math.h"
-#include "util/StringUtils.h"
-#include "util/SubString.h"
+#include "util/MultiType.h"
 #include "Functor.h"
-
-
-#define EXECUTOR_PARSE_FUNCTORCALL(mode) EXECUTOR_PARSE_FUNCTORCALL##mode
-#define EXECUTOR_PARSE_FUNCTORCALLnormal (*this->functor_)
-#define EXECUTOR_PARSE_FUNCTORCALLobject (*((FunctorMember<T>*)this->functor_))
-
-#define EXECUTOR_PARSE_OBJECT(mode, comma) EXECUTOR_PARSE_OBJECT##mode##comma
-#define EXECUTOR_PARSE_OBJECTnormal0
-#define EXECUTOR_PARSE_OBJECTnormal1
-#define EXECUTOR_PARSE_OBJECTobject0 object
-#define EXECUTOR_PARSE_OBJECTobject1 object,
-
-#define EXECUTOR_PARSE(mode) \
-    unsigned int paramCount = this->functor_->getParamCount(); \
-    \
-    if (paramCount == 0) \
-    { \
-        COUT(5) << "Calling Executor " << this->name_ << " through parser without parameters." << std::endl; \
-        EXECUTOR_PARSE_FUNCTORCALL(mode)(EXECUTOR_PARSE_OBJECT(mode, 0)); \
-    } \
-    else if (paramCount == 1) \
-    { \
-        const std::string& temp = getStripped(params); \
-        if (!temp.empty()) \
-        { \
-            COUT(5) << "Calling Executor " << this->name_ << " through parser with one parameter, using whole string: " << params << std::endl; \
-            EXECUTOR_PARSE_FUNCTORCALL(mode)(EXECUTOR_PARSE_OBJECT(mode, 1) MultiType(params)); \
-        } \
-        else if (this->bAddedDefaultValue_[0]) \
-        { \
-            COUT(5) << "Calling Executor " << this->name_ << " through parser with one parameter, using default value: " << this->defaultValue_[0] << std::endl; \
-            EXECUTOR_PARSE_FUNCTORCALL(mode)(EXECUTOR_PARSE_OBJECT(mode, 1) this->defaultValue_[0]); \
-        } \
-        else \
-        { \
-            COUT(2) << "Warning: Can't call executor " << this->name_ << " through parser: Not enough parameters or default values given (input: " << temp << ")." << std::endl; \
-            return false; \
-        } \
-    } \
-    else \
-    { \
-        SubString tokens(params, delimiter, SubString::WhiteSpaces, false, '\\', true, '"', true, '(', ')', true, '\0'); \
-        \
-        for (unsigned int i = tokens.size(); i < this->functor_->getParamCount(); i++) \
-        { \
-            if (!this->bAddedDefaultValue_[i]) \
-            { \
-                COUT(2) << "Warning: Can't call executor " << this->name_ << " through parser: Not enough parameters or default values given (input:" << params << ")." << std::endl; \
-                return false; \
-            } \
-        } \
-        \
-        MultiType param[MAX_FUNCTOR_ARGUMENTS]; \
-        COUT(5) << "Calling Executor " << this->name_ << " through parser with " << paramCount << " parameters, using " << tokens.size() << " tokens ("; \
-        for (unsigned int i = 0; i < tokens.size() && i < MAX_FUNCTOR_ARGUMENTS; i++) \
-        { \
-            param[i] = tokens[i]; \
-            if (i != 0) \
-            { \
-                COUT(5) << ", "; \
-            } \
-            COUT(5) << tokens[i]; \
-        } \
-        COUT(5) << ") and " << std::max(static_cast<int>(paramCount) - static_cast<int>(tokens.size()), 0) << " default values ("; \
-        for (unsigned int i = tokens.size(); i < paramCount; i++) \
-        { \
-            param[i] = this->defaultValue_[i]; \
-            if (i != 0) \
-            { \
-                COUT(5) << ", "; \
-            } \
-            COUT(5) << this->defaultValue_[i]; \
-        } \
-        COUT(5) << ")." << std::endl; \
-        \
-        if ((tokens.size() > paramCount) && (this->functor_->getTypenameParam(paramCount - 1) == "string")) \
-            param[paramCount - 1] = tokens.subSet(paramCount - 1).join(); \
-        \
-        switch(paramCount) \
-        { \
-            case 2: \
-                EXECUTOR_PARSE_FUNCTORCALL(mode)(EXECUTOR_PARSE_OBJECT(mode, 1) param[0], param[1]); \
-                break; \
-            case 3: \
-                EXECUTOR_PARSE_FUNCTORCALL(mode)(EXECUTOR_PARSE_OBJECT(mode, 1) param[0], param[1], param[2]); \
-                break; \
-            case 4: \
-                EXECUTOR_PARSE_FUNCTORCALL(mode)(EXECUTOR_PARSE_OBJECT(mode, 1) param[0], param[1], param[2], param[3]); \
-                break; \
-            case 5: \
-                EXECUTOR_PARSE_FUNCTORCALL(mode)(EXECUTOR_PARSE_OBJECT(mode, 1) param[0], param[1], param[2], param[3], param[4]); \
-                break; \
-        } \
-    } \
-    \
-    return true
 
 namespace orxonox
@@ -284,10 +183,24 @@
             bool parse(T* object, const std::string& params, const std::string& delimiter = " ") const
             {
-                EXECUTOR_PARSE(object);
+                static_cast<FunctorMember<T>*>(this->functor_)->setObject(object);
+                if (Executor::parse(params, delimiter))
+                    return true;
+                else
+                {
+                    static_cast<FunctorMember<T>*>(this->functor_)->setObject((T*)NULL);
+                    return false;
+                }
             }
 
             bool parse(const T* object, const std::string& params, const std::string& delimiter = " ") const
             {
-                EXECUTOR_PARSE(object);
+                static_cast<FunctorMember<T>*>(this->functor_)->setObject(object);
+                if (Executor::parse(params, delimiter))
+                    return true;
+                else
+                {
+                    static_cast<FunctorMember<T>*>(this->functor_)->setObject((T*)NULL);
+                    return false;
+                }
             }
     };
Index: code/trunk/src/libraries/core/GUIManager.cc
===================================================================
--- code/trunk/src/libraries/core/GUIManager.cc	(revision 6906)
+++ code/trunk/src/libraries/core/GUIManager.cc	(revision 7163)
@@ -321,5 +321,5 @@
     }
 
-    void GUIManager::keyPressed(const KeyEvent& evt)
+    void GUIManager::buttonPressed(const KeyEvent& evt)
     {
         this->protectedCall(boost::bind(&CEGUI::System::injectKeyDown, _1, evt.getKeyCode()));
@@ -327,5 +327,5 @@
     }
 
-    void GUIManager::keyReleased(const KeyEvent& evt)
+    void GUIManager::buttonReleased(const KeyEvent& evt)
     {
         this->protectedCall(boost::bind(&CEGUI::System::injectKeyUp, _1, evt.getKeyCode()));
Index: code/trunk/src/libraries/core/GUIManager.h
===================================================================
--- code/trunk/src/libraries/core/GUIManager.h	(revision 6906)
+++ code/trunk/src/libraries/core/GUIManager.h	(revision 7163)
@@ -84,4 +84,6 @@
         //! Creates a new InputState to be used with a GUI Sheet
         const std::string& createInputState(const std::string& name, TriBool::Value showCursor = TriBool::True, TriBool::Value useKeyboard = TriBool::True, bool bBlockJoyStick = false); // tolua_export
+        LuaState* getLuaState(void)
+            { return this->luaState_.get(); }
 
         //! Returns the root window for all menu sheets
@@ -95,6 +97,5 @@
         inline void setPlayer(const std::string& guiname, PlayerInfo* player)
             { this->players_[guiname] = player; }
-        inline PlayerInfo* getPlayer(const std::string& guiname) const
-            { std::map<std::string, PlayerInfo*>::const_iterator it = this->players_.find(guiname); return (it != this->players_.end()) ? it->second : 0; }
+        inline orxonox::PlayerInfo* getPlayer(const std::string& guiname) const { std::map<std::string, PlayerInfo*>::const_iterator it = this->players_.find(guiname); return (it != this->players_.end()) ? it->second : 0; } // tolua_export
 
         // TODO: Temporary hack because the tolua exported CEGUI method does not seem to work
@@ -105,12 +106,12 @@
     private:
         GUIManager(const GUIManager& instance); //!< private and undefined copy c'tor (this is a singleton class)
+        void executeCode(const std::string& str);
 
-        void executeCode(const std::string& str);
         template <typename FunctionType>
         bool protectedCall(FunctionType function);
 
         // keyHandler functions
-        void keyPressed (const KeyEvent& evt);
-        void keyReleased(const KeyEvent& evt);
+        void buttonPressed (const KeyEvent& evt);
+        void buttonReleased(const KeyEvent& evt);
 
         // mouseHandler functions
Index: code/trunk/src/libraries/core/OrxonoxClass.h
===================================================================
--- code/trunk/src/libraries/core/OrxonoxClass.h	(revision 6906)
+++ code/trunk/src/libraries/core/OrxonoxClass.h	(revision 7163)
@@ -108,5 +108,5 @@
             bool isParentOf(const OrxonoxClass* object);
             bool isDirectParentOf(const OrxonoxClass* object);
-            
+
             virtual void clone(OrxonoxClass*& item) {}
 
@@ -172,7 +172,7 @@
             std::vector<std::pair<unsigned int, void*> > objectPointers_;
     };
-    
-    SUPER_FUNCTION(11, OrxonoxClass, clone, true);
-    
+
+    SUPER_FUNCTION(11, OrxonoxClass, clone, false);
+
 }
 
Index: code/trunk/src/libraries/core/Super.h
===================================================================
--- code/trunk/src/libraries/core/Super.h	(revision 6906)
+++ code/trunk/src/libraries/core/Super.h	(revision 7163)
@@ -267,17 +267,17 @@
     #define SUPER_changedGametype(classname, functionname, ...) \
         SUPER_NOARGS(classname, functionname)
-        
+
     #define SUPER_changedUsed(classname, functionname, ...) \
         SUPER_NOARGS(classname, functionname)
-        
+
     #define SUPER_clone(classname, functionname, ...) \
         SUPER_ARGS(classname, functionname, __VA_ARGS__)
-        
+
     #define SUPER_changedCarrier(classname, functionname, ...) \
         SUPER_NOARGS(classname, functionname)
-        
+
     #define SUPER_changedPickedUp(classname, functionname, ...) \
         SUPER_NOARGS(classname, functionname)
-        
+
     // (1/3) --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <--
 
@@ -530,5 +530,5 @@
             ()
         SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
-        
+
         SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(10, changedUsed, false)
             ()
@@ -538,9 +538,9 @@
             (item)
         SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
-        
+
         SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(12, changedCarrier, false)
             ()
         SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
-        
+
         SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(13, changedPickedUp, false)
             ()
Index: code/trunk/src/libraries/core/Template.cc
===================================================================
--- code/trunk/src/libraries/core/Template.cc	(revision 6906)
+++ code/trunk/src/libraries/core/Template.cc	(revision 7163)
@@ -99,5 +99,5 @@
     }
 
-    const TiXmlElement& Template::getXMLElement() const
+    const TiXmlElement& Template::getXMLElement()
     {
         if (this->bIsLink_)
@@ -106,4 +106,6 @@
             if (temp)
             {
+                this->bLoadDefaults_ = temp->bLoadDefaults_;
+
                 if (!temp->bIsReturningXMLElement_)
                 {
Index: code/trunk/src/libraries/core/Template.h
===================================================================
--- code/trunk/src/libraries/core/Template.h	(revision 6906)
+++ code/trunk/src/libraries/core/Template.h	(revision 7163)
@@ -51,4 +51,6 @@
             inline const std::string& getLink() const
                 { return this->link_; }
+            inline bool isLink() const
+                { return this->bIsLink_; }
 
             inline void setLoadDefaults(bool bLoadDefaults)
@@ -58,5 +60,5 @@
 
             void setXMLElement(const TiXmlElement& xmlelement);
-            const TiXmlElement& getXMLElement() const;
+            const TiXmlElement& getXMLElement();
 
             void setBaseclass(const std::string& baseclass);
Index: code/trunk/src/libraries/core/XMLPort.cc
===================================================================
--- code/trunk/src/libraries/core/XMLPort.cc	(revision 6906)
+++ code/trunk/src/libraries/core/XMLPort.cc	(revision 7163)
@@ -41,3 +41,98 @@
         return ((!this->bApplyLoaderMask_) || identifier->isA(ClassIdentifier<Namespace>::getIdentifier()) || Loader::currentMask_s.isIncluded(identifier));
     }
+
+    XMLPortObjectContainer& XMLPortObjectContainer::port(BaseObject* object, Element& xmlelement, XMLPort::Mode mode)
+    {
+        if ((mode == XMLPort::LoadObject) || (mode == XMLPort::ExpandObject))
+        {
+            try
+            {
+                Element* xmlsubelement;
+                if (!this->sectionname_.empty())
+                    xmlsubelement = xmlelement.FirstChildElement(this->sectionname_, false);
+                else
+                    xmlsubelement = &xmlelement;
+
+                if (!xmlsubelement)
+                    return (*this);
+
+                for (ticpp::Iterator<ticpp::Element> child = xmlsubelement->FirstChildElement(false); child != child.end(); child++)
+                {
+                    Identifier* identifier = Identifier::getIdentifierByString(child->Value());
+                    if (!identifier)
+                    {
+                        if (!this->sectionname_.empty())
+                        {
+                            COUT(2) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a valid classname." << std::endl;
+                        }
+                        else
+                        {
+                            // It's probably just another subsection
+                        }
+                        continue;
+                    }
+                    if (!identifier->isA(objectIdentifier_))
+                    {
+                        COUT(2) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a '" << objectIdentifier_->getName() << "'." << std::endl;
+                        continue;
+                    }
+                    if (!identifier->isLoadable())
+                    {
+                        COUT(2) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not loadable." << std::endl;
+                        continue;
+                    }
+                    if (!this->identifierIsIncludedInLoaderMask(identifier))
+                        continue;
+
+                    try
+                    {
+                        COUT(4) << object->getLoaderIndentation() << "fabricating " << child->Value() << "..." << std::endl;
+
+                        BaseObject* newObject = identifier->fabricate(object);
+                        newObject->setLoaderIndentation(object->getLoaderIndentation() + "  ");
+
+                        if (this->bLoadBefore_)
+                        {
+                            newObject->XMLPort(*child, XMLPort::LoadObject);
+                            COUT(4) << object->getLoaderIndentation() << "assigning " << child->Value() << " (objectname " << newObject->getName() << ") to " << this->identifier_->getName() << " (objectname " << static_cast<BaseObject*>(object)->getName() << ')' << std::endl;
+                        }
+                        else
+                        {
+                            COUT(4) << object->getLoaderIndentation() << "assigning " << child->Value() << " (object not yet loaded) to " << this->identifier_->getName() << " (objectname " << static_cast<BaseObject*>(object)->getName() << ')' << std::endl;
+                        }
+
+                        COUT(5) << object->getLoaderIndentation();
+
+                        this->callLoadExecutor(object, newObject);
+
+                        if (!this->bLoadBefore_)
+                            newObject->XMLPort(*child, XMLPort::LoadObject);
+
+                        COUT(5) << object->getLoaderIndentation() << "...fabricated " << child->Value() << " (objectname " << newObject->getName() << ")." << std::endl;
+                    }
+                    catch (AbortLoadingException& ex)
+                    {
+                        COUT(1) << "An error occurred while loading object, abort loading..." << std::endl;
+                        throw ex;
+                    }
+                    catch (...)
+                    {
+                        COUT(1) << "An error occurred while loading object:" << std::endl;
+                        COUT(1) << Exception::handleMessage() << std::endl;
+                    }
+                }
+            }
+            catch (ticpp::Exception& ex)
+            {
+                COUT(1) << std::endl;
+                COUT(1) << "An error occurred in XMLPort.h while loading a '" << objectIdentifier_->getName() << "' in '" << this->sectionname_ << "' of '" << this->identifier_->getName() << "' (objectname: " << object->getName() << ") in " << object->getFilename() << ':' << std::endl;
+                COUT(1) << ex.what() << std::endl;
+            }
+        }
+        else if (mode == XMLPort::SaveObject)
+        {
+        }
+
+        return (*this);
+    }
 }
Index: code/trunk/src/libraries/core/XMLPort.h
===================================================================
--- code/trunk/src/libraries/core/XMLPort.h	(revision 6906)
+++ code/trunk/src/libraries/core/XMLPort.h	(revision 7163)
@@ -197,5 +197,5 @@
     @param loadfunction The function to add a new object to the class
     @param loadfunction The function to get all added objects from the class
-    @param xmlelement The XMLElement (recieved through the XMLPort function)
+    @param xmlelement The XMLElement (received through the XMLPort function)
     @param mode The mode (load/save) (received through the XMLPort function)
     @param bApplyLoaderMask If this is true, an added sub-object gets loaded only if it's class is included in the Loaders ClassTreeMask (this is usually false)
@@ -495,4 +495,8 @@
             virtual ~XMLPortObjectContainer() {}
 
+            XMLPortObjectContainer& port(BaseObject* object, Element& xmlelement, XMLPort::Mode mode);
+
+            virtual void callLoadExecutor(BaseObject* object, BaseObject* newObject) = 0;
+
             inline const std::string& getName() const
                 { return this->sectionname_; }
@@ -508,4 +512,5 @@
             bool bLoadBefore_;
             Identifier* identifier_;
+            Identifier* objectIdentifier_;
     };
 
@@ -518,4 +523,6 @@
                 this->sectionname_ = sectionname;
                 this->identifier_ = identifier;
+                assert(identifier->isA(ClassIdentifier<T>::getIdentifier()));
+                this->objectIdentifier_ = ClassIdentifier<O>::getIdentifier();
                 this->loadexecutor_ = loadexecutor;
                 this->saveexecutor_ = saveexecutor;
@@ -532,106 +539,12 @@
             }
 
-            XMLPortObjectContainer& port(T* object, Element& xmlelement, XMLPort::Mode mode)
-            {
-                if ((mode == XMLPort::LoadObject) || (mode == XMLPort::ExpandObject))
-                {
-                    try
-                    {
-                        Element* xmlsubelement;
-                        if (!this->sectionname_.empty())
-                            xmlsubelement = xmlelement.FirstChildElement(this->sectionname_, false);
-                        else
-                            xmlsubelement = &xmlelement;
-
-                        if (xmlsubelement)
-                        {
-                            for (ticpp::Iterator<ticpp::Element> child = xmlsubelement->FirstChildElement(false); child != child.end(); child++)
-                            {
-                                Identifier* identifier = Identifier::getIdentifierByString(child->Value());
-                                if (identifier)
-                                {
-                                    if (identifier->isA(ClassIdentifier<O>::getIdentifier()))
-                                    {
-                                        if (identifier->isLoadable())
-                                        {
-                                            if (this->identifierIsIncludedInLoaderMask(identifier))
-                                            {
-                                                try
-                                                {
-                                                    COUT(4) << object->getLoaderIndentation() << "fabricating " << child->Value() << "..." << std::endl;
-
-                                                    BaseObject* newObject = identifier->fabricate(static_cast<BaseObject*>(object));
-                                                    assert(newObject);
-                                                    newObject->setLoaderIndentation(object->getLoaderIndentation() + "  ");
-
-                                                    O* castedObject = orxonox_cast<O*>(newObject);
-                                                    assert(castedObject);
-
-                                                    if (this->bLoadBefore_)
-                                                    {
-                                                        newObject->XMLPort(*child, XMLPort::LoadObject);
-                                                        COUT(4) << object->getLoaderIndentation() << "assigning " << child->Value() << " (objectname " << newObject->getName() << ") to " << this->identifier_->getName() << " (objectname " << static_cast<BaseObject*>(object)->getName() << ')' << std::endl;
-                                                    }
-                                                    else
-                                                    {
-                                                        COUT(4) << object->getLoaderIndentation() << "assigning " << child->Value() << " (object not yet loaded) to " << this->identifier_->getName() << " (objectname " << static_cast<BaseObject*>(object)->getName() << ')' << std::endl;
-                                                    }
-
-                                                    COUT(5) << object->getLoaderIndentation();
-                                                    (*this->loadexecutor_)(object, castedObject);
-
-                                                    if (!this->bLoadBefore_)
-                                                        newObject->XMLPort(*child, XMLPort::LoadObject);
-
-                                                    COUT(5) << object->getLoaderIndentation() << "...fabricated " << child->Value() << " (objectname " << newObject->getName() << ")." << std::endl;
-                                                }
-                                                catch (AbortLoadingException& ex)
-                                                {
-                                                    COUT(1) << "An error occurred while loading object, abort loading..." << std::endl;
-                                                    throw ex;
-                                                }
-                                                catch (...)
-                                                {
-                                                    COUT(1) << "An error occurred while loading object:" << std::endl;
-                                                    COUT(1) << Exception::handleMessage() << std::endl;
-                                                }
-                                            }
-                                        }
-                                        else
-                                        {
-                                            COUT(2) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not loadable." << std::endl;
-                                        }
-                                    }
-                                    else
-                                    {
-                                        COUT(2) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a '" << ClassIdentifier<O>::getIdentifier()->getName() << "'." << std::endl;
-                                    }
-                                }
-                                else
-                                {
-                                    if (!this->sectionname_.empty())
-                                    {
-                                        COUT(2) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a valid classname." << std::endl;
-                                    }
-                                    else
-                                    {
-                                        // It's probably just another subsection
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    catch (ticpp::Exception& ex)
-                    {
-                        COUT(1) << std::endl;
-                        COUT(1) << "An error occurred in XMLPort.h while loading a '" << ClassIdentifier<O>::getIdentifier()->getName() << "' in '" << this->sectionname_ << "' of '" << this->identifier_->getName() << "' (objectname: " << object->getName() << ") in " << object->getFilename() << ':' << std::endl;
-                        COUT(1) << ex.what() << std::endl;
-                    }
-                }
-                else if (mode == XMLPort::SaveObject)
-                {
-                }
-
-                return (*this);
+            void callLoadExecutor(BaseObject* object, BaseObject* newObject)
+            {
+                T* castedObject = orxonox_cast<T*>(object);
+                assert(castedObject);
+                O* castedNewObject = orxonox_cast<O*>(newObject);
+                assert(castedNewObject);
+
+                (*this->loadexecutor_)(castedObject, castedNewObject);
             }
 
Index: code/trunk/src/libraries/network/CMakeLists.txt
===================================================================
--- code/trunk/src/libraries/network/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/libraries/network/CMakeLists.txt	(revision 7163)
@@ -29,4 +29,6 @@
   GamestateClient.cc
   GamestateHandler.cc
+  LANDiscoverable.cc
+  LANDiscovery.cc
   NetworkFunction.cc
   Host.cc
@@ -48,4 +50,6 @@
   GamestateManager.h
   Host.h
+  LANDiscoverable.h
+  LANDiscovery.h
   NetworkFunction.h
   NetworkPrecompiledHeaders.h
@@ -60,6 +64,7 @@
 
 ORXONOX_ADD_LIBRARY(network
-  DEFINE_SYMBOL
-    "NETWORK_SHARED_BUILD"
+  TOLUA_FILES
+    Client.h
+    LANDiscovery.h
   PCH_FILE
     NetworkPrecompiledHeaders.h
Index: code/trunk/src/libraries/network/ChatListener.cc
===================================================================
--- code/trunk/src/libraries/network/ChatListener.cc	(revision 6906)
+++ code/trunk/src/libraries/network/ChatListener.cc	(revision 7163)
@@ -36,4 +36,14 @@
         RegisterRootObject(ChatListener);
     }
+
+    //void ChatListener::incomingChat( const std::string& message,
+      //unsigned int senderID )
+    //{
+      //COUT(0) << "Chat: \"" << message << "\"\n";
+
+
+    //}
+
+
 }
 
Index: code/trunk/src/libraries/network/ChatListener.h
===================================================================
--- code/trunk/src/libraries/network/ChatListener.h	(revision 6906)
+++ code/trunk/src/libraries/network/ChatListener.h	(revision 7163)
@@ -38,7 +38,9 @@
     {
         public:
+            /* constructor, destructor */
             ChatListener();
             virtual ~ChatListener() {}
 
+            /* What to do with incoming chat */
             virtual void incomingChat(const std::string& message, unsigned int senderID) = 0;
     };
Index: code/trunk/src/libraries/network/Client.cc
===================================================================
--- code/trunk/src/libraries/network/Client.cc	(revision 6906)
+++ code/trunk/src/libraries/network/Client.cc	(revision 7163)
@@ -50,9 +50,12 @@
 #include "FunctionCallManager.h"
 #include "core/CoreIncludes.h"
+#include "core/CommandLineParser.h"
 #include "core/Game.h"
+#include "core/ScopedSingletonManager.h"
 
 namespace orxonox
 {
 
+  ManageScopedSingleton( Client, ScopeID::Root, true );
 
   /**
@@ -61,25 +64,14 @@
   */
   Client::Client():
+      gamestate(0),
       isSynched_(false),
       gameStateFailure_(false),
       timeSinceLastUpdate_(0)
   {
-  }
-
-  /**
-  * Constructor for the Client class
-  * @param address the server address
-  * @param port port of the application on the server
-  */
-  Client::Client(const std::string& address, int port):
-      isSynched_(false),
-      gameStateFailure_(false),
-      timeSinceLastUpdate_(0)
-  {
-      setPort( port );
-      setServerAddress( address );
-  }
-
-  Client::~Client(){
+    this->setDestination( CommandLineParser::getValue("dest").getString(), CommandLineParser::getValue("port") );
+  }
+
+  Client::~Client()
+  {
     if ( ClientConnection::isConnected() )
       closeConnection();
@@ -90,7 +82,15 @@
   * @return true/false
   */
-  bool Client::establishConnection(){
+  bool Client::establishConnection()
+  {
     Synchronisable::setClient(true);
-    return ClientConnection::establishConnection();
+    this->gamestate = new GamestateClient();
+    if( ClientConnection::establishConnection() )
+    {
+      Host::setActive(true);
+      return true;
+    }
+    else
+      return false;
   }
 
@@ -99,9 +99,21 @@
   * @return true/false
   */
-  bool Client::closeConnection(){
+  bool Client::closeConnection()
+  {
+    assert(this->gamestate);
+    delete this->gamestate;
+    this->gamestate = 0;
+    Host::setActive(false);
     return ClientConnection::closeConnection();
   }
-
-  bool Client::queuePacket(ENetPacket *packet, int clientID){
+  
+  void Client::setDestination(const std::string& serverAddress, unsigned int port)
+  {
+    ClientConnection::setServerAddress(serverAddress);
+    ClientConnection::setPort(port);
+  }
+
+  bool Client::queuePacket(ENetPacket *packet, int clientID)
+  {
     bool b = ClientConnection::addPacket(packet);
     assert(b);
@@ -109,10 +121,12 @@
   }
 
-  bool Client::processChat(const std::string& message, unsigned int playerID){
+  bool Client::processChat(const std::string& message, unsigned int playerID)
+  {
 //    COUT(1) << "Player " << playerID << ": " << message << std::endl;
     return true;
   }
 
-  void Client::printRTT(){
+  void Client::printRTT()
+  {
     COUT(0) << "Round trip time to server is " << ClientConnection::getRTT() << " ms" << endl;
   }
@@ -123,5 +137,6 @@
    * @return result(true/false)
    */
-  bool Client::chat(const std::string& message){
+  bool Client::chat(const std::string& message)
+  {
     packet::Chat *m = new packet::Chat(message, Host::getPlayerID());
     return m->send();
@@ -133,5 +148,6 @@
    * @param time
    */
-  void Client::update(const Clock& time){
+  void Client::update(const Clock& time)
+  {
     //this steers our network frequency
     timeSinceLastUpdate_+=time.getDeltaTime();
@@ -143,5 +159,5 @@
       {
         COUT(4) << "popping partial gamestate: " << std::endl;
-        packet::Gamestate *gs = gamestate.getGamestate();
+        packet::Gamestate *gs = gamestate->getGamestate();
         //assert(gs); <--- there might be the case that no data has to be sent, so its commented out now
         if(gs){
@@ -157,10 +173,10 @@
 
     Connection::processQueue();
-    if(gamestate.processGamestates())
+    if(gamestate->processGamestates())
     {
       if(!isSynched_)
         isSynched_=true;
     }
-    gamestate.cleanup();
+    gamestate->cleanup();
     Connection::sendPackets();
 
@@ -184,3 +200,5 @@
   }
 
+
+
 }
Index: code/trunk/src/libraries/network/Client.h
===================================================================
--- code/trunk/src/libraries/network/Client.h	(revision 6906)
+++ code/trunk/src/libraries/network/Client.h	(revision 7163)
@@ -47,10 +47,15 @@
 
 #include "util/UtilPrereqs.h"
+#include "util/Singleton.h"
 #include "ClientConnection.h"
 #include "GamestateClient.h"
 #include "Host.h"
+#include "LANDiscovery.h"
+#include "packet/ServerInformation.h"
 
+// tolua_begin
 namespace orxonox
 {
+// tolua_end
   /**
   Client *client;
@@ -60,11 +65,16 @@
   *
   */
-  class _NetworkExport Client : public Host, public ClientConnection{
+  class _NetworkExport Client // tolua_export
+    : public Host, protected ClientConnection, public Singleton<Client>
+  { // tolua_export
+  friend class Singleton<Client>;
   public:
     Client();
-    Client(const std::string& address, int port);
     ~Client();
+    
+    static Client* getInstance(){ return singletonPtr_s; } // tolua_export
 
     bool establishConnection();
+    void setDestination( const std::string& serverAddress, unsigned int port ); // tolua_export
     bool closeConnection();
     bool queuePacket(ENetPacket *packet, int clientID);
@@ -81,13 +91,14 @@
     virtual bool isServer_(){return false;}
 
-    GamestateClient gamestate;
+    static Client* singletonPtr_s;
+    GamestateClient* gamestate;
     bool isSynched_;
 
     bool gameStateFailure_;
     float timeSinceLastUpdate_;
-  };
+  }; // tolua_export
 
 
-}
+} // tolua_export
 
 #endif /* _Client_H__ */
Index: code/trunk/src/libraries/network/Connection.cc
===================================================================
--- code/trunk/src/libraries/network/Connection.cc	(revision 6906)
+++ code/trunk/src/libraries/network/Connection.cc	(revision 7163)
@@ -36,11 +36,11 @@
 namespace orxonox
 {
-  Connection *Connection::instance_=0;
+//   Connection *Connection::instance_=0;
 
   Connection::Connection():
     host_(0)
   {
-    assert(instance_==0);
-    Connection::instance_=this;
+//     assert(instance_==0);
+//     Connection::instance_=this;
     enet_initialize();
     atexit(enet_deinitialize);
@@ -48,5 +48,5 @@
 
   Connection::~Connection(){
-    Connection::instance_=0;
+//     Connection::instance_=0;
   }
 
@@ -67,5 +67,5 @@
 
   bool Connection::sendPackets() {
-    if ( !Connection::instance_ || this->host_==NULL )
+    if ( /*!Connection::instance_ || */this->host_==NULL )
       return false;
     enet_host_flush(this->host_);
Index: code/trunk/src/libraries/network/Connection.h
===================================================================
--- code/trunk/src/libraries/network/Connection.h	(revision 6906)
+++ code/trunk/src/libraries/network/Connection.h	(revision 7163)
@@ -61,5 +61,5 @@
   protected:
     Connection();
-    static Connection* getInstance(){ return Connection::instance_; }
+//     static Connection* getInstance(){ return Connection::instance_; }
 
     int service(ENetEvent* event);
@@ -75,5 +75,5 @@
     ENetAddress *bindAddress_;
 
-    static Connection *instance_;
+//     static Connection *instance_;
 
   };
Index: code/trunk/src/libraries/network/GamestateClient.cc
===================================================================
--- code/trunk/src/libraries/network/GamestateClient.cc	(revision 6906)
+++ code/trunk/src/libraries/network/GamestateClient.cc	(revision 7163)
@@ -161,16 +161,19 @@
       assert(b);
     }
-    if(gs->isDiffed()){
-      packet::Gamestate *base = gamestateMap_[gs->getBaseID()];
-      if(!base){
-        COUT(3) << "could not find base gamestate id: " << gs->getBaseID() << endl;
-        delete gs;
-        return 0;
-      }
-//       assert(base); //TODO: fix this
-      packet::Gamestate *undiffed = gs->undiff(base);
-      delete gs;
-      gs=undiffed;
-      COUT(5) << "successfully undiffed gamestate id: " << undiffed->getID() << std::endl;
+    if(gs->isDiffed())
+    {
+      assert(0);
+//       packet::Gamestate *base = gamestateMap_[gs->getBaseID()];
+//       if(!base)
+//       {
+//         COUT(0) << "could not find base gamestate id: " << gs->getBaseID() << endl;
+//         assert(0);
+//         delete gs;
+//         return 0;
+//       }
+//       packet::Gamestate *undiffed = gs->undiff(base);
+//       delete gs;
+//       gs=undiffed;
+//       COUT(5) << "successfully undiffed gamestate id: " << undiffed->getID() << std::endl;
     }
     if(gs->spreadData(0x2))
@@ -178,5 +181,6 @@
     else
     {
-      COUT(3) << "could not spread gamestate" << endl;
+      COUT(0) << "could not spread gamestate" << endl;
+      assert(0);
       return NULL;
     }
Index: code/trunk/src/libraries/network/GamestateManager.cc
===================================================================
--- code/trunk/src/libraries/network/GamestateManager.cc	(revision 6906)
+++ code/trunk/src/libraries/network/GamestateManager.cc	(revision 7163)
@@ -43,4 +43,5 @@
 #include <cassert>
 #include <queue>
+#include "util/Clock.h"
 // #include <boost/thread/mutex.hpp>
 
@@ -158,5 +159,5 @@
 
       clientGamestates.push(0);
-      finishGamestate( cid, &clientGamestates.back(), client, reference );
+      finishGamestate( cid, clientGamestates.back(), client, reference );
       //FunctorMember<GamestateManager>* functor =
 //       ExecutorMember<GamestateManager>* executor = createExecutor( createFunctor(&GamestateManager::finishGamestate, this) );
@@ -180,5 +181,5 @@
 
 
-  void GamestateManager::finishGamestate( unsigned int clientID, packet::Gamestate** destgamestate, packet::Gamestate* base, packet::Gamestate* gamestate ) {
+  void GamestateManager::finishGamestate( unsigned int clientID, packet::Gamestate*& destgamestate, packet::Gamestate* base, packet::Gamestate* gamestate ) {
     //why are we searching the same client's gamestate id as we searched in
     //Server::sendGameState?
@@ -186,6 +187,8 @@
     //chose wheather the next gamestate is the first or not
 
-    packet::Gamestate *gs = gamestate->doSelection(clientID, 20000);
-//     packet::Gamestate *gs = new packet::Gamestate(*gamestate);
+//     packet::Gamestate *gs = gamestate->doSelection(clientID, 20000);
+//       packet::Gamestate* gs = new packet::Gamestate(*gamestate);
+//     packet::Gamestate* gs = gamestate;
+    packet::Gamestate *gs = new packet::Gamestate(*gamestate); //TODO: is this neccessary ?
 //     packet::Gamestate *gs = new packet::Gamestate();
 //     gs->collectData( id_, 0x1 );
@@ -193,19 +196,20 @@
     gamestateMap_[clientID][gamestate->getID()]=gs;
 //     this->threadMutex_->unlock();
+      Clock clock;
+      clock.capture();
 
     if(base)
     {
-
-//       COUT(3) << "diffing" << std::endl;
-//       packet::Gamestate* gs1  = gs;
-      packet::Gamestate *diffed = gs->diff(base);
-      //packet::Gamestate *gs2 = diffed->undiff(gs);
-//       assert(*gs == *gs2);
-      gs = diffed;
-//       packet::Gamestate* gs2 = gs->undiff(client);
-//       gs = new packet::Gamestate(*gs);
-//       assert(*gs1==*gs2);
-    }
-    else{
+      packet::Gamestate *diffed1 = gs->diffVariables(base);
+      if( diffed1->getDataSize() == 0 )
+      {
+        delete diffed1;
+        destgamestate = 0;
+        return;
+      }
+      gs = diffed1;
+    }
+    else
+    {
       gs = new packet::Gamestate(*gs);
     }
@@ -214,11 +218,13 @@
     bool b = gs->compressData();
     assert(b);
-//     COUT(4) << "sending gamestate with id " << gs->getID();
+      clock.capture();
+      COUT(0) << "diff time: " << clock.getDeltaTime() << endl;
+//     COUT(5) << "sending gamestate with id " << gs->getID();
 //     if(gamestate->isDiffed())
-//     COUT(4) << " and baseid " << gs->getBaseID() << endl;
+//       COUT(5) << " and baseid " << gs->getBaseID() << endl;
 //     else
-//     COUT(4) << endl;
+//       COUT(5) << endl;
     gs->setClientID(clientID);
-    *destgamestate = gs;
+    destgamestate = gs;
   }
 
Index: code/trunk/src/libraries/network/GamestateManager.h
===================================================================
--- code/trunk/src/libraries/network/GamestateManager.h	(revision 6906)
+++ code/trunk/src/libraries/network/GamestateManager.h	(revision 7163)
@@ -76,5 +76,5 @@
     void sendGamestates();
 //     packet::Gamestate *popGameState(unsigned int clientID);
-    void finishGamestate( unsigned int clientID, packet::Gamestate** destgamestate, packet::Gamestate* base, packet::Gamestate* gamestate );
+    void finishGamestate( unsigned int clientID, packet::Gamestate*& destgamestate, packet::Gamestate* base, packet::Gamestate* gamestate );
 
     bool getSnapshot();
Index: code/trunk/src/libraries/network/Host.cc
===================================================================
--- code/trunk/src/libraries/network/Host.cc	(revision 6906)
+++ code/trunk/src/libraries/network/Host.cc	(revision 7163)
@@ -38,81 +38,127 @@
 namespace orxonox {
 
-SetConsoleCommandShortcut(Host, Chat);
+  SetConsoleCommandShortcut(Host, Chat);
 
-Host *Host::instance_=0;
+  // Host*               Host::instance_=0;
+  uint32_t            Host::clientID_s=0;
+  uint32_t            Host::shipID_s=-1;
+  std::vector<Host*>  Host::instances_s;
 
-/**
- * @brief Constructor: assures that only one reference will be created and sets the pointer
- */
-Host::Host()
-{
-  clientID_=0;
-  assert(instance_==0);
-  instance_=this;
-  this->printRTTCC_ = createConsoleCommand( createFunctor(&Host::printRTT, this), "printRTT" );
-  CommandExecutor::addConsoleCommandShortcut( this->printRTTCC_ );
-}
+  /**
+  * @brief Constructor: assures that only one reference will be created and sets the pointer
+  */
+  Host::Host()
+  {
+  //   assert(instance_==0);
+    instances_s.push_back(this);
+    this->printRTTCC_ = createConsoleCommand( createFunctor(&Host::printRTT, this), "printRTT" );
+    CommandExecutor::addConsoleCommandShortcut( this->printRTTCC_ );
+    this->bIsActive_ = false;
+  }
 
 
-/**
- * @brief Destructor: resets the instance pointer to 0
- */
-Host::~Host()
-{
-  instance_=0;
-  if( this->printRTTCC_ )
-    delete this->printRTTCC_;
-}
+  /**
+  * @brief Destructor: resets the instance pointer to 0
+  */
+  Host::~Host()
+  {
+    assert( std::find( instances_s.begin(), instances_s.end(), this )!=instances_s.end() );
+    instances_s.erase(std::find( instances_s.begin(), instances_s.end(), this ));
+    if( this->printRTTCC_ )
+      delete this->printRTTCC_;
+  }
 
-/**
- * This function is used to add an enetpacket to be sent to another peer
- * @param packet Packet to be added
- * @param clientID ID of the client the packet should be sent to
- * @return success?
- */
-bool Host::addPacket(ENetPacket *packet, int clientID){
-  if(instance_)
-    return instance_->queuePacket(packet, clientID);
-  else
-    return false;
-}
+  /**
+  * This function is used to add an enetpacket to be sent to another peer
+  * @param packet Packet to be added
+  * @param clientID ID of the client the packet should be sent to
+  * @return success?
+  */
+  bool Host::addPacket(ENetPacket *packet, int clientID)
+  {
+    bool result = true;
+    for( std::vector<Host*>::iterator it = instances_s.begin(); it!=instances_s.end(); ++it )
+    {
+      if( (*it)->isActive() )
+      {
+        if( !(*it)->queuePacket(packet, clientID) )
+          result = false;
+      }
+    }
+    return result;
+  }
 
-/**
- * This function returns the ID of the player
- * @return playerID
- */
-unsigned int Host::getPlayerID(){
-  if(!instance_)
-    return 0;
-  return instance_->clientID_;
-}
+  bool Host::Chat(const std::string& message)
+  {
+    if(instances_s.size()==0)
+    {
+      for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
+        it->incomingChat(message, 0);
+      return true;
+    }
+    else
+    {
+      bool result = true;
+      for( std::vector<Host*>::iterator it = instances_s.begin(); it!=instances_s.end(); ++it )
+      {
+        if( (*it)->isActive() )
+        {
+          if( !(*it)->chat(message) )
+            result = false;
+        }
+      }
+      return result;
+    }
+  }
 
-bool Host::Chat(const std::string& message){
-  if(!instance_)
+  bool Host::Broadcast(const std::string& message)
+  {
+    if(instances_s.size()==0)
+    {
+      for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
+        it->incomingChat(message, CLIENTID_UNKNOWN);
+      return true;
+    }
+    else
+    {
+      bool result = true;
+      for( std::vector<Host*>::iterator it = instances_s.begin(); it!=instances_s.end(); ++it )
+      {
+        if( (*it)->isActive() )
+        {
+          if( !(*it)->broadcast(message) )
+            result = false;
+        }
+      }
+      return result;
+    }
+  }
+
+  bool Host::incomingChat(const std::string& message, unsigned int playerID)
   {
     for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
-      it->incomingChat(message, 0);
-    return true;
+      it->incomingChat(message, playerID);
+    
+    bool result = true;
+    for( std::vector<Host*>::iterator it = instances_s.begin(); it!=instances_s.end(); ++it )
+    {
+      if( (*it)->isActive() )
+      {
+        if( !(*it)->processChat(message, playerID) )
+          result = false;
+      }
+    }
+    return result;
   }
-  return instance_->chat(message);
-}
 
-bool Host::Broadcast(const std::string& message){
-  if(!instance_)
+  bool Host::isServer()
   {
-    for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
-      it->incomingChat(message, CLIENTID_UNKNOWN);
-    return true;
+    for (std::vector<Host*>::iterator it=instances_s.begin(); it!=instances_s.end(); ++it )
+    {
+      if( (*it)->isServer_() )
+        return true;
+    }
+    return false;
   }
-  else
-    return instance_->broadcast(message);
-}
-
-bool Host::incomingChat(const std::string& message, unsigned int playerID){
-  for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
-    it->incomingChat(message, playerID);
-
-  return instance_->processChat(message, playerID);
-}
 
 }//namespace orxonox
Index: code/trunk/src/libraries/network/Host.h
===================================================================
--- code/trunk/src/libraries/network/Host.h	(revision 6906)
+++ code/trunk/src/libraries/network/Host.h	(revision 7163)
@@ -33,8 +33,10 @@
 #include "core/CorePrereqs.h"
 
+#include <vector>
+
 namespace orxonox {
 
   const unsigned int CLIENTID_SERVER = 0;
-  const unsigned int NETWORK_FREQUENCY = 30;
+  const unsigned int NETWORK_FREQUENCY = 25;
   const float NETWORK_PERIOD = 1.0f/NETWORK_FREQUENCY;
 
@@ -49,5 +51,5 @@
 class _NetworkExport Host{
   private:
-    //TODO add theese functions or adequate
+    //TODO add these functions or adequate
     //virtual bool processChat(packet::Chat *message, unsigned int clientID)=0;
     //virtual bool sendChat(packet::Chat *chat)=0;
@@ -63,24 +65,29 @@
     Host();
     virtual ~Host();
-    static Host *instance_;
-    unsigned int clientID_;
-    unsigned int shipID_;
+    void setActive( bool bActive ){ bIsActive_ = bActive; }
+//     static Host *instance_;
 
   public:
-    static bool running(){return instance_!=0;}
+//     static Host* getInstance(){ return instance_; }
+    static bool running(){ return instances_s.size(); }
     static bool addPacket(ENetPacket *packet, int clientID=0);
     //static bool chat(std::string& message);
 //     static bool receiveChat(packet::Chat *message, unsigned int clientID);
-    static unsigned int getPlayerID();
-    static unsigned int getShipID(){return instance_->shipID_;}
-    static void setClientID(unsigned int id){ instance_->clientID_ = id; }
-    static void setShipID(unsigned int id){ instance_->shipID_ = id; }
-    static bool isServer(){ return instance_->isServer_(); }
+    static unsigned int getPlayerID(){ return clientID_s; }
+    static unsigned int getShipID(){return shipID_s;}
+    static void setClientID(unsigned int id){ clientID_s = id; }
+    static void setShipID(unsigned int id){ shipID_s = id; }
+    static bool isServer();
     static bool Chat(const std::string& message);
     static bool Broadcast(const std::string& message);
     static bool incomingChat(const std::string& message, unsigned int playerID);
     virtual void printRTT()=0;
+    bool isActive(){ return bIsActive_; }
   private:
     ConsoleCommand* printRTTCC_;
+    static uint32_t clientID_s;
+    static uint32_t shipID_s;
+    static std::vector<Host*> instances_s;
+    bool bIsActive_;
 };
 
Index: code/trunk/src/libraries/network/LANDiscoverable.cc
===================================================================
--- code/trunk/src/libraries/network/LANDiscoverable.cc	(revision 7163)
+++ code/trunk/src/libraries/network/LANDiscoverable.cc	(revision 7163)
@@ -0,0 +1,109 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oliver Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "LANDiscoverable.h"
+
+#include "NetworkPrereqs.h"
+#include "packet/ServerInformation.h"
+
+#include <enet/enet.h>
+#include <cassert>
+#include <cstring>
+
+namespace orxonox
+{
+  const char* LAN_DISCOVERY_MESSAGE = "Orxonox Client";
+  const char* LAN_DISCOVERY_ACK     = "Orxonox Server Ack";
+
+  LANDiscoverable::LANDiscoverable()
+  {
+    this->host_ = 0;
+    this->bActive_ = false;
+    this->setActivity(true);
+  }
+
+  LANDiscoverable::~LANDiscoverable()
+  {
+    if( this->host_ )
+    {
+      enet_host_destroy( this->host_ );
+      assert( this->bActive_ );
+    }
+  }
+
+  void LANDiscoverable::setActivity(bool bActive)
+  {
+    if( bActive == this->bActive_ )        // no change
+      return;
+    
+    if( bActive )
+    {
+      ENetAddress bindAddress = { ENET_HOST_ANY, LAN_DISCOVERY_PORT };
+      assert( this->host_ == 0 );
+      this->host_ = enet_host_create( &bindAddress, 10, 0, 0 );
+    }
+    else
+    {
+      enet_host_destroy( this->host_ );
+      this->host_ = 0;
+    }
+      this->bActive_ = bActive;
+  }
+
+  void LANDiscoverable::update()
+  {
+    ENetEvent event;
+    
+    if( this->bActive_==false )
+      return;
+    assert(this->host_);
+    
+    while( enet_host_service( this->host_, &event, 0 ) > 0 )
+    {
+      switch(event.type)
+      {
+        case ENET_EVENT_TYPE_CONNECT:
+        case ENET_EVENT_TYPE_DISCONNECT:
+        case ENET_EVENT_TYPE_NONE:
+          break;
+        case ENET_EVENT_TYPE_RECEIVE:
+          if( strcmp( LAN_DISCOVERY_MESSAGE, (char*)event.packet->data ) == 0 )      // check for a suitable orxonox client
+          {
+            packet::ServerInformation info;
+            info.setServerName("Orxonox Server");
+            info.send(event.peer);
+//             ENetPacket* packet = enet_packet_create( LAN_DISCOVERY_ACK, strlen(LAN_DISCOVERY_ACK)+1, ENET_PACKET_FLAG_RELIABLE );
+//             enet_peer_send(event.peer, 0, packet );
+            enet_host_flush(this->host_);
+          }
+          break;
+      }
+    }
+  }
+
+}
Index: code/trunk/src/libraries/network/LANDiscoverable.h
===================================================================
--- code/trunk/src/libraries/network/LANDiscoverable.h	(revision 7163)
+++ code/trunk/src/libraries/network/LANDiscoverable.h	(revision 7163)
@@ -0,0 +1,52 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oliver Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _LANDISCOVERABLE_H__
+#define _LANDISCOVERABLE_H__
+
+#include "NetworkPrereqs.h"
+
+namespace orxonox
+{
+  
+  class LANDiscoverable
+  {
+    public:
+      LANDiscoverable();
+      ~LANDiscoverable();
+      void setActivity( bool bActive );
+      void update();
+      
+    private:
+      bool            bActive_;
+      ENetHost*       host_;
+  };
+
+}
+
+#endif // LANDISCOVERABLE_H
Index: code/trunk/src/libraries/network/LANDiscovery.cc
===================================================================
--- code/trunk/src/libraries/network/LANDiscovery.cc	(revision 7163)
+++ code/trunk/src/libraries/network/LANDiscovery.cc	(revision 7163)
@@ -0,0 +1,113 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "LANDiscovery.h"
+
+#include <enet/enet.h>
+#include <cstring>
+
+#include "core/CoreIncludes.h"
+#include "core/ScopedSingletonManager.h"
+
+
+namespace orxonox
+{ 
+  ManageScopedSingleton(LANDiscovery, ScopeID::Root, true);
+  
+  LANDiscovery::LANDiscovery()
+  {
+    this->host_ = enet_host_create(NULL, 10, 0, 0 );
+  }
+
+  LANDiscovery::~LANDiscovery()
+  {
+    enet_host_destroy(this->host_);
+  }
+  
+  void LANDiscovery::discover()
+  {
+    this->servers_.clear();
+    ENetAddress address;
+    enet_address_set_host(&address, "255.255.255.255");
+    address.port = LAN_DISCOVERY_PORT;
+    
+    ENetPeer* peer;
+    peer = enet_host_connect(this->host_, &address, 0);
+    
+    ENetEvent event;
+    while( enet_host_service(this->host_, &event, 1000 ) )
+    {
+      switch( event.type )
+      {
+        case ENET_EVENT_TYPE_CONNECT:
+        {
+          COUT(0) << "connect from server: " << event.peer->address.host << endl;
+          ENetPacket* packet = enet_packet_create(LAN_DISCOVERY_MESSAGE, strlen(LAN_DISCOVERY_MESSAGE)+1, ENET_PACKET_FLAG_RELIABLE);
+          enet_peer_send(event.peer, 0, packet);
+          break;
+        }
+        case ENET_EVENT_TYPE_RECEIVE:
+          {
+            packet::ServerInformation info(&event);
+            COUT(0) << "received server information; name: " << info.getServerName() << ", IP: " << info.getServerIP() << ", RTT: " << info.getServerRTT() << endl;
+            std::vector<packet::ServerInformation>::iterator it;
+            for( it=this->servers_.begin(); it!=this->servers_.end(); ++it )
+            {
+              if( (*it).getServerIP() == info.getServerIP() )
+                break;
+            }
+            if( it==this->servers_.end() )
+              this->servers_.push_back(info);
+          }
+//           enet_address_get_host_ip(&event.peer->address, buffer, buflen );
+//           serverIPs.push_back(std::string(buffer));
+          break;
+        default:
+          break;
+      }
+    }
+  }
+  
+  std::string LANDiscovery::getServerListItemName(unsigned int index)
+  {
+    if( index >= this->servers_.size() )
+      return BLANKSTRING;
+    else
+      return this->servers_[index].getServerName();
+  }
+  
+  std::string LANDiscovery::getServerListItemIP(unsigned int index)
+  {
+    if( index >= this->servers_.size() )
+      return BLANKSTRING;
+    else
+      return this->servers_[index].getServerIP();
+  }
+  
+  
+} // namespace orxonox
Index: code/trunk/src/libraries/network/LANDiscovery.h
===================================================================
--- code/trunk/src/libraries/network/LANDiscovery.h	(revision 7163)
+++ code/trunk/src/libraries/network/LANDiscovery.h	(revision 7163)
@@ -0,0 +1,63 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef LANDISCOVERY_H
+#define LANDISCOVERY_H
+
+#include "NetworkPrereqs.h"
+#include "packet/ServerInformation.h"
+#include "util/Singleton.h"
+
+#include <vector>
+
+// tolua_begin
+namespace orxonox
+{
+
+  class _NetworkExport LANDiscovery
+// tolua_end
+    : public Singleton<LANDiscovery>
+  { // tolua_export
+    friend class Singleton<LANDiscovery>;
+    public:
+      LANDiscovery();
+      ~LANDiscovery();
+      void discover(); // tolua_export
+      std::string getServerListItemName( unsigned int index ); // tolua_export
+      std::string getServerListItemIP( unsigned int index ); // tolua_export
+      static LANDiscovery& getInstance(){ return Singleton<LANDiscovery>::getInstance(); } // tolua_export
+      
+    private:
+      static LANDiscovery* singletonPtr_s;
+      ENetHost* host_;
+      std::vector<packet::ServerInformation> servers_;
+  }; // tolua_export
+
+} // tolua_export
+
+#endif // LANDISCOVERY_H
Index: code/trunk/src/libraries/network/NetworkPrereqs.h
===================================================================
--- code/trunk/src/libraries/network/NetworkPrereqs.h	(revision 6906)
+++ code/trunk/src/libraries/network/NetworkPrereqs.h	(revision 7163)
@@ -64,6 +64,9 @@
 namespace orxonox
 {
-  static const unsigned int GAMESTATEID_INITIAL = static_cast<unsigned int>(-1);
-  static const unsigned int CLIENTID_UNKNOWN    = static_cast<unsigned int>(-2);
+  static const unsigned int GAMESTATEID_INITIAL     = static_cast<unsigned int>(-1);
+  static const unsigned int CLIENTID_UNKNOWN        = static_cast<unsigned int>(-2);
+  extern const char* LAN_DISCOVERY_MESSAGE;
+  extern const char* LAN_DISCOVERY_ACK;
+  static const unsigned int LAN_DISCOVERY_PORT      = 55557;
 }
 
Index: code/trunk/src/libraries/network/Server.cc
===================================================================
--- code/trunk/src/libraries/network/Server.cc	(revision 6906)
+++ code/trunk/src/libraries/network/Server.cc	(revision 7163)
@@ -69,9 +69,11 @@
   *
   */
-  Server::Server() {
+  Server::Server()
+  {
     this->timeSinceLastUpdate_=0;
   }
 
-  Server::Server(int port){
+  Server::Server(int port)
+  {
     this->setPort( port );
     this->timeSinceLastUpdate_=0;
@@ -83,5 +85,6 @@
   * @param bindAddress Address to listen on
   */
-  Server::Server(int port, const std::string& bindAddress) {
+  Server::Server(int port, const std::string& bindAddress)
+  {
     this->setPort( port );
     this->setBindAddress( bindAddress );
@@ -92,5 +95,6 @@
   * @brief Destructor
   */
-  Server::~Server(){
+  Server::~Server()
+  {
   }
 
@@ -98,7 +102,10 @@
   * This function opens the server by creating the listener thread
   */
-  void Server::open() {
+  void Server::open()
+  {
+    Host::setActive(true);
     COUT(4) << "opening server" << endl;
     this->openListener();
+    LANDiscoverable::setActivity(true);
     return;
   }
@@ -107,12 +114,16 @@
   * This function closes the server
   */
-  void Server::close() {
+  void Server::close()
+  {
+    Host::setActive(false);
     COUT(4) << "closing server" << endl;
     this->disconnectClients();
     this->closeListener();
+    LANDiscoverable::setActivity(false);
     return;
   }
 
-  bool Server::processChat(const std::string& message, unsigned int playerID){
+  bool Server::processChat(const std::string& message, unsigned int playerID)
+  {
     ClientInformation *temp = ClientInformation::getBegin();
     packet::Chat *chat;
@@ -134,7 +145,10 @@
   * @param time time since last tick
   */
-  void Server::update(const Clock& time) {
+  void Server::update(const Clock& time)
+  {
     // receive incoming packets
     Connection::processQueue();
+    // receive and process incoming discovery packets
+    LANDiscoverable::update();
 
     if ( ClientInformation::hasClients() )
@@ -157,5 +171,6 @@
   }
 
-  bool Server::queuePacket(ENetPacket *packet, int clientID){
+  bool Server::queuePacket(ENetPacket *packet, int clientID)
+  {
     return ServerConnection::addPacket(packet, clientID);
   }
@@ -164,5 +179,6 @@
    * @brief: returns ping time to client in milliseconds
    */
-  unsigned int Server::getRTT(unsigned int clientID){
+  unsigned int Server::getRTT(unsigned int clientID)
+  {
     assert(ClientInformation::findClient(clientID));
     return ClientInformation::findClient(clientID)->getRTT();
@@ -178,5 +194,6 @@
    * @brief: return packet loss ratio to client (scales from 0 to 1)
    */
-  double Server::getPacketLoss(unsigned int clientID){
+  double Server::getPacketLoss(unsigned int clientID)
+  {
     assert(ClientInformation::findClient(clientID));
     return ClientInformation::findClient(clientID)->getPacketLoss();
@@ -186,5 +203,6 @@
   * takes a new snapshot of the gamestate and sends it to the clients
   */
-  void Server::updateGamestate() {
+  void Server::updateGamestate()
+  {
     if( ClientInformation::getBegin()==NULL )
       //no client connected
@@ -208,5 +226,6 @@
   * sends the gamestate
   */
-  bool Server::sendGameState() {
+  bool Server::sendGameState()
+  {
 //     COUT(5) << "Server: starting function sendGameState" << std::endl;
 //     ClientInformation *temp = ClientInformation::getBegin();
@@ -244,5 +263,6 @@
   }
 
-  bool Server::sendObjectDeletes(){
+  bool Server::sendObjectDeletes()
+  {
     ClientInformation *temp = ClientInformation::getBegin();
     if( temp == NULL )
@@ -257,5 +277,6 @@
 //     COUT(3) << "sending DeleteObjects" << std::endl;
     while(temp != NULL){
-      if( !(temp->getSynched()) ){
+      if( !(temp->getSynched()) )
+      {
         COUT(5) << "Server: not sending gamestate" << std::endl;
         temp=temp->next();
@@ -276,10 +297,12 @@
 
 
-  void Server::addPeer(ENetEvent *event){
+  void Server::addPeer(ENetEvent *event)
+  {
     static unsigned int newid=1;
 
     COUT(2) << "Server: adding client" << std::endl;
     ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
-    if(!temp){
+    if(!temp)
+    {
       COUT(2) << "Server: could not add client" << std::endl;
     }
@@ -310,7 +333,9 @@
   }
 
-  bool Server::createClient(int clientID){
+  bool Server::createClient(int clientID)
+  {
     ClientInformation *temp = ClientInformation::findClient(clientID);
-    if(!temp){
+    if(!temp)
+    {
       COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
       return false;
@@ -345,5 +370,6 @@
   }
 
-  void Server::disconnectClient( ClientInformation *client ){
+  void Server::disconnectClient( ClientInformation *client )
+  {
     ServerConnection::disconnectClient( client );
     GamestateManager::removeClient(client);
@@ -352,16 +378,20 @@
   }
 
-  bool Server::chat(const std::string& message){
+  bool Server::chat(const std::string& message)
+  {
       return this->sendChat(message, Host::getPlayerID());
   }
 
-  bool Server::broadcast(const std::string& message){
+  bool Server::broadcast(const std::string& message)
+  {
       return this->sendChat(message, CLIENTID_UNKNOWN);
   }
 
-  bool Server::sendChat(const std::string& message, unsigned int clientID){
+  bool Server::sendChat(const std::string& message, unsigned int clientID)
+  {
     ClientInformation *temp = ClientInformation::getBegin();
     packet::Chat *chat;
-    while(temp){
+    while(temp)
+    {
       chat = new packet::Chat(message, clientID);
       chat->setClientID(temp->getID());
@@ -377,5 +407,6 @@
   }
 
-  void Server::syncClassid(unsigned int clientID) {
+  void Server::syncClassid(unsigned int clientID)
+  {
     int failures=0;
     packet::ClassID *classid = new packet::ClassID();
Index: code/trunk/src/libraries/network/Server.h
===================================================================
--- code/trunk/src/libraries/network/Server.h	(revision 6906)
+++ code/trunk/src/libraries/network/Server.h	(revision 7163)
@@ -37,4 +37,5 @@
 #include "GamestateManager.h"
 #include "ServerConnection.h"
+#include "LANDiscoverable.h"
 
 namespace orxonox
@@ -45,5 +46,5 @@
   * It implements all functions necessary for a Server
   */
-  class _NetworkExport Server : public Host, public ServerConnection, public GamestateManager{
+  class _NetworkExport Server : public Host, public ServerConnection, public GamestateManager, public LANDiscoverable{
   public:
     Server();
Index: code/trunk/src/libraries/network/ServerConnection.cc
===================================================================
--- code/trunk/src/libraries/network/ServerConnection.cc	(revision 6906)
+++ code/trunk/src/libraries/network/ServerConnection.cc	(revision 7163)
@@ -94,7 +94,7 @@
 
   bool ServerConnection::addPacketAll(ENetPacket *packet) {
-    if ( !Connection::getInstance() )
-      return false;
-    enet_host_broadcast( Connection::getInstance()->getHost(), 0, packet);
+//     if ( !Connection::getInstance() )
+//       return false;
+    enet_host_broadcast( Connection::getHost(), 0, packet);
     return true;
   }
Index: code/trunk/src/libraries/network/ServerConnection.h
===================================================================
--- code/trunk/src/libraries/network/ServerConnection.h	(revision 6906)
+++ code/trunk/src/libraries/network/ServerConnection.h	(revision 7163)
@@ -56,6 +56,6 @@
     bool openListener();
     bool closeListener();
-    static bool addPacket(ENetPacket *packet, unsigned int ID);
-    static bool addPacketAll(ENetPacket *packet);
+    bool addPacket(ENetPacket *packet, unsigned int ID);
+    bool addPacketAll(ENetPacket *packet);
     virtual void disconnectClient(ClientInformation *client);
     void disconnectClient(int clientID);
Index: code/trunk/src/libraries/network/packet/CMakeLists.txt
===================================================================
--- code/trunk/src/libraries/network/packet/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/libraries/network/packet/CMakeLists.txt	(revision 7163)
@@ -11,4 +11,5 @@
   Welcome.cc
 COMPILATION_END
+  ServerInformation.cc
 )
 
@@ -23,4 +24,5 @@
   Gamestate.h
   Packet.h
+  ServerInformation.h
   Welcome.h
 )
Index: code/trunk/src/libraries/network/packet/Chat.cc
===================================================================
--- code/trunk/src/libraries/network/packet/Chat.cc	(revision 6906)
+++ code/trunk/src/libraries/network/packet/Chat.cc	(revision 7163)
@@ -37,4 +37,6 @@
 
 #define   PACKET_FLAGS_CHAT PacketFlag::Reliable
+
+/* Some lengths */
 #define   _PACKETID         0
 const int _PLAYERID     =   _PACKETID + sizeof(Type::Value);
@@ -45,10 +47,20 @@
  : Packet()
 {
+  /* Add chat flag to packet flags */
   flags_ = flags_ | PACKET_FLAGS_CHAT;
+
+  /* set message length to length of input string + 1 */
   messageLength_ = message.length()+1;
+
+  /* allocate memory for the data */
   data_=new unsigned char[ getSize() ];
+
   *(Type::Value *)(data_ + _PACKETID ) = Type::Chat;
   *(unsigned int *)(data_ + _PLAYERID ) = playerID;
   *(unsigned int *)(data_ + _MESSAGELENGTH ) = messageLength_;
+
+  /* cast the hell out of the message string, and copy it into the
+   * data buffer.
+   */
   memcpy( data_+_MESSAGE, static_cast<void*>(const_cast<char*>(message.c_str())), messageLength_ );
 }
Index: code/trunk/src/libraries/network/packet/Chat.h
===================================================================
--- code/trunk/src/libraries/network/packet/Chat.h	(revision 6906)
+++ code/trunk/src/libraries/network/packet/Chat.h	(revision 7163)
@@ -41,15 +41,29 @@
 {
 public:
+  /* constructors */
   Chat( const std::string& message, unsigned int playerID );
   Chat( uint8_t* data, unsigned int clientID );
+
+  /* destructor */
   ~Chat();
 
+  /* get size of packet */
   inline unsigned int getSize() const;
+
+  /* process chat message packet and remove it afterwards */
   bool process();
 
+  /* Get the length of the message (not the full size of the packet) */
   unsigned int getMessageLength(){ return messageLength_; };
+
+  /* return message content */
   unsigned char *getMessage();
+
 private:
+
+  /* Message length */
   uint32_t messageLength_;
+
+  /* Client ID (an integral value for identification) */
   unsigned int clientID_;
 };
Index: code/trunk/src/libraries/network/packet/ClassID.cc
===================================================================
--- code/trunk/src/libraries/network/packet/ClassID.cc	(revision 6906)
+++ code/trunk/src/libraries/network/packet/ClassID.cc	(revision 7163)
@@ -65,5 +65,5 @@
     tempQueue.push( std::pair<unsigned int, std::string>(network_id, classname) );
     ++nrOfClasses;
-    packetSize += (classname.size()+1)+sizeof(uint32_t)+sizeof(uint32_t);
+    packetSize += (classname.size()+1)+sizeof(network_id)+sizeof(uint32_t);
   }
 
@@ -80,4 +80,5 @@
   // now save all classids and classnames
   std::pair<uint32_t, std::string> tempPair;
+  uint32_t tempsize = 2*sizeof(uint32_t); // packetid and nrOfClasses
   while( !tempQueue.empty() ){
     tempPair = tempQueue.front();
@@ -87,5 +88,7 @@
     memcpy(temp+2*sizeof(uint32_t), tempPair.second.c_str(), tempPair.second.size()+1);
     temp+=2*sizeof(uint32_t)+tempPair.second.size()+1;
+    tempsize+=2*sizeof(uint32_t)+tempPair.second.size()+1;
   }
+  assert(tempsize==packetSize);
 
   COUT(5) << "classid packetSize is " << packetSize << endl;
@@ -111,4 +114,5 @@
   for(unsigned int i=0; i<nrOfClasses; i++){
     totalsize += 2*sizeof(uint32_t) + *(uint32_t*)(temp + sizeof(uint32_t));
+    temp += 2*sizeof(uint32_t) + *(uint32_t*)(temp + sizeof(uint32_t));
   }
   return totalsize;
@@ -141,5 +145,5 @@
     COUT(3) << "processing classid: " << networkID << " name: " << classname << " id: " << id << std::endl;
     if(id==NULL){
-      COUT(0) << "Recieved a bad classname" << endl;
+      COUT(0) << "Received a bad classname" << endl;
       abort();
     }
Index: code/trunk/src/libraries/network/packet/Gamestate.cc
===================================================================
--- code/trunk/src/libraries/network/packet/Gamestate.cc	(revision 6906)
+++ code/trunk/src/libraries/network/packet/Gamestate.cc	(revision 7163)
@@ -45,13 +45,32 @@
 #define PACKET_FLAG_GAMESTATE  PacketFlag::Reliable
 
-
-Gamestate::Gamestate()
+inline bool memzero( uint8_t* data, uint32_t datalength)
+{
+  uint64_t* d = (uint64_t*)data;
+
+  for( unsigned int i=0; i<datalength/8; i++ )
+  {
+    if( *(d+i) != 0 )
+      return false;
+  }
+  // now process the rest (when datalength isn't a multiple of 4)
+  for( unsigned int j = 8*(datalength/8); j<datalength; j++ )
+  {
+    if( *(data+j) != 0 )
+      return false;
+  }
+  return true;
+}
+
+
+Gamestate::Gamestate():
+  header_(0)
 {
   flags_ = flags_ | PACKET_FLAG_GAMESTATE;
-  header_ = 0;
-}
+}
+
 
 Gamestate::Gamestate(uint8_t *data, unsigned int clientID):
-    Packet(data, clientID)
+  Packet(data, clientID)
 {
   flags_ = flags_ | PACKET_FLAG_GAMESTATE;
@@ -59,16 +78,19 @@
 }
 
+
 Gamestate::Gamestate(uint8_t *data)
 {
   flags_ = flags_ | PACKET_FLAG_GAMESTATE;
-  data_=data;
+  data_ = data;
   header_ = new GamestateHeader(data_);
 }
 
+
 Gamestate::Gamestate(const Gamestate& g) :
-    Packet( *(Packet*)&g )
+    Packet( *(Packet*)&g ), nrOfVariables_(0)
 {
   flags_ = flags_ | PACKET_FLAG_GAMESTATE;
   header_ = new GamestateHeader(data_);
+  sizes_ = g.sizes_;
 }
 
@@ -79,4 +101,5 @@
     delete header_;
 }
+
 
 bool Gamestate::collectData(int id, uint8_t mode)
@@ -91,5 +114,6 @@
     return false;
   data_ = new uint8_t[size + GamestateHeader::getSize()];
-  if(!data_){
+  if(!data_)
+  {
     COUT(2) << "GameStateManager: could not allocate memory" << std::endl;
     return false;
@@ -101,17 +125,19 @@
 
   //start collect data synchronisable by synchronisable
-  uint8_t *mem=data_;
+  uint8_t *mem = data_; // in this stream store all data of the variables and the headers of the synchronisable
   mem += GamestateHeader::getSize();
   ObjectList<Synchronisable>::iterator it;
-  for(it = ObjectList<Synchronisable>::begin(); it; ++it){
+  for(it = ObjectList<Synchronisable>::begin(); it; ++it)
+  {
 
 //     tempsize=it->getSize(id, mode);
 
-    tempsize = it->getData(mem, id, mode);
+    tempsize = it->getData(mem, this->sizes_, id, mode);
     if ( tempsize != 0 )
       dataVector_.push_back( obj(it->getObjectID(), it->getCreatorID(), tempsize, mem-data_) );
 
 #ifndef NDEBUG
-    if(currentsize+tempsize > size){
+    if(currentsize+tempsize > size)
+    {
       assert(0); // if we don't use multithreading this part shouldn't be neccessary
       // start allocate additional memory
@@ -148,4 +174,5 @@
 }
 
+
 bool Gamestate::spreadData(uint8_t mode)
 {
@@ -153,10 +180,10 @@
   assert(data_);
   assert(!header_->isCompressed());
-  assert(!header_->isDiffed());
   uint8_t *mem=data_+GamestateHeader::getSize();
   Synchronisable *s;
 
   // update the data of the objects we received
-  while(mem < data_+GamestateHeader::getSize()+header_->getDataSize()){
+  while(mem < data_+GamestateHeader::getSize()+header_->getDataSize())
+  {
     SynchronisableHeader objectheader(mem);
 
@@ -170,5 +197,5 @@
       else
       {
-        mem += objectheader.getDataSize();
+        mem += objectheader.getDataSize() + ( objectheader.isDiffed() ? SynchronisableHeaderLight::getSize() : SynchronisableHeader::getSize() );
       }
     }
@@ -181,10 +208,14 @@
    // In debug mode, check first, whether there are no duplicate objectIDs
 #ifndef NDEBUG
-  if(this->getID()%1000==0){
+  if(this->getID()%1000==1)
+  {
     std::list<uint32_t> v1;
     ObjectList<Synchronisable>::iterator it;
-    for (it = ObjectList<Synchronisable>::begin(); it != ObjectList<Synchronisable>::end(); ++it) {
-      if (it->getObjectID() == OBJECTID_UNKNOWN) {
-        if (it->objectMode_ != 0x0) {
+    for (it = ObjectList<Synchronisable>::begin(); it != ObjectList<Synchronisable>::end(); ++it)
+    {
+      if (it->getObjectID() == OBJECTID_UNKNOWN)
+      {
+        if (it->objectMode_ != 0x0)
+        {
           COUT(0) << "Found object with OBJECTID_UNKNOWN on the client with objectMode != 0x0!" << std::endl;
           COUT(0) << "Possible reason for this error: Client created a synchronized object without the Server's approval." << std::endl;
@@ -193,8 +224,11 @@
         }
       }
-      else {
+      else
+      {
         std::list<uint32_t>::iterator it2;
-        for (it2 = v1.begin(); it2 != v1.end(); ++it2) {
-          if (it->getObjectID() == *it2) {
+        for (it2 = v1.begin(); it2 != v1.end(); ++it2)
+        {
+          if (it->getObjectID() == *it2)
+          {
             COUT(0) << "Found duplicate objectIDs on the client!" << std::endl
                     << "Are you sure you don't create a Sychnronisable objcect with 'new' \
@@ -211,4 +245,5 @@
 }
 
+
 uint32_t Gamestate::getSize() const
 {
@@ -222,5 +257,7 @@
 }
 
-bool Gamestate::operator==(packet::Gamestate gs){
+
+bool Gamestate::operator==(packet::Gamestate gs)
+{
   uint8_t *d1 = data_+GamestateHeader::getSize();
   uint8_t *d2 = gs.data_+GamestateHeader::getSize();
@@ -233,9 +270,9 @@
 }
 
+
 bool Gamestate::process()
 {
   return GamestateHandler::addGamestate(this, getClientID());
 }
-
 
 
@@ -253,5 +290,6 @@
   int retval;
   retval = compress( dest, &buffer, source, (uLong)(header_->getDataSize()) );
-  switch ( retval ) {
+  switch ( retval )
+  {
     case Z_OK: COUT(5) << "G.St.Man: compress: successfully compressed" << std::endl; break;
     case Z_MEM_ERROR: COUT(1) << "G.St.Man: compress: not enough memory available in gamestate.compress" << std::endl; return false;
@@ -270,7 +308,9 @@
   header_->setCompSize( buffer );
   header_->setCompressed( true );
-  COUT(5) << "gamestate compress datasize: " << header_->getDataSize() << " compsize: " << header_->getCompSize() << std::endl;
+  COUT(0) << "gamestate compress datasize: " << header_->getDataSize() << " compsize: " << header_->getCompSize() << std::endl;
   return true;
 }
+
+
 bool Gamestate::decompressData()
 {
@@ -289,5 +329,6 @@
   uLongf length=bufsize;
   retval = uncompress( dest, &length, source, (uLong)compsize );
-  switch ( retval ) {
+  switch ( retval )
+  {
     case Z_OK: COUT(5) << "successfully decompressed" << std::endl; break;
     case Z_MEM_ERROR: COUT(1) << "not enough memory available" << std::endl; return false;
@@ -301,10 +342,12 @@
   delete temp;
 
-  if (this->bDataENetAllocated_){
+  if (this->bDataENetAllocated_)
+  {
     // Memory was allocated by ENet. --> We let it be since enet_packet_destroy will
     // deallocated it anyway. So data and packet stay together.
     this->bDataENetAllocated_ = false;
   }
-  else{
+  else
+  {
     // We allocated the memory in the first place (unlikely). So we destroy the old data
     // and overwrite it with the new decompressed data.
@@ -320,42 +363,221 @@
 }
 
-/*Gamestate *Gamestate::diff(Gamestate *base)
-{
-  assert(data_);
-  assert(!header_->isCompressed());
+
+Gamestate* Gamestate::diffVariables(Gamestate *base)
+{
+  assert(this && base); assert(data_ && base->data_);
+  assert(!header_->isCompressed() && !base->header_->isCompressed());
   assert(!header_->isDiffed());
-  GamestateHeader diffHeader(base->data_);
-  uint8_t *basep = GAMESTATE_START(base->data_), *gs = GAMESTATE_START(this->data_);
-  uint32_t of=0; // pointers offset
-  uint32_t dest_length=0;
-  dest_length=header_->getDataSize();
-  if(dest_length==0)
-    return NULL;
-  uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()];
-  uint8_t *dest = ndata + GamestateHeader::getSize();
-  while(of < diffHeader.getDataSize() && of < header_->getDataSize()){
-    *(dest+of)=*(basep+of)^*(gs+of); // do the xor
-    ++of;
-  }
-  if(diffHeader.getDataSize()!=header_->getDataSize()){
-    uint8_t n=0;
-    if(diffHeader.getDataSize() < header_->getDataSize()){
-      while(of<dest_length){
-        *(dest+of)=n^*(gs+of);
-        of++;
-      }
-    }
-  }
-
-  Gamestate *g = new Gamestate(ndata, getClientID());
+
+
+  // *** first do a raw diff of the two gamestates
+
+  uint8_t *baseData = GAMESTATE_START(base->data_);
+  uint8_t *origData = GAMESTATE_START(this->data_);
+  uint32_t origLength = header_->getDataSize();
+  uint32_t baseLength = base->header_->getDataSize();
+
+  assert( origLength && baseLength );
+
+  uint8_t *nData = new uint8_t[origLength + GamestateHeader::getSize() + sizeof(uint32_t)*this->nrOfVariables_]; // this is the maximum size needed in the worst case
+  uint8_t *dest = GAMESTATE_START(nData);
+
+  uint32_t baseOffset = 0; //offset in the diffed stream
+  uint32_t origOffset = 0; //offset in the new stream with removed 0's
+  std::vector<uint32_t>::iterator sizes = this->sizes_.begin();
+
+  while( origOffset < origLength )
+  {
+    //iterate through all objects
+
+    SynchronisableHeader h(origData+origOffset);
+
+    // Find (if possible) the current object in the datastream of the old gamestate
+    // Start at the current offset position
+    if(baseOffset >= baseLength)
+      baseOffset = 0;
+    uint8_t* temp = baseData + baseOffset;
+    uint32_t objectID = h.getObjectID();
+    assert(temp < baseData+baseLength);
+    assert(dest < nData + origLength + GamestateHeader::getSize() + sizeof(uint32_t)*this->nrOfVariables_);
+    assert(sizes != this->sizes_.end());
+    while ( temp < baseData+baseLength )
+    {
+      SynchronisableHeader htemp(temp);
+      assert( htemp.getDataSize()!=0 );
+      if ( htemp.getObjectID() == objectID )
+      {
+        assert( h.getClassID() == htemp.getClassID() );
+        goto DODIFF;
+      }
+//       {
+//         SynchronisableHeader htemp2(temp+htemp.getDataSize()+SynchronisableHeader::getSize());
+//         if( temp+htemp.getDataSize()+SynchronisableHeader::getSize() < baseData+baseLength )
+//         {
+//           assert(htemp2.getClassID()<500);
+//           assert(htemp2.getDataSize()!=0 && htemp2.getDataSize()<1000);
+//           assert(htemp2.isDiffed()==false);
+//         }
+//       }
+      temp += htemp.getDataSize()+SynchronisableHeader::getSize();
+        
+    }
+    // If not found start looking at the beginning
+    assert( temp==baseData+baseLength );
+    temp = baseData;
+//     {
+//       SynchronisableHeader htemp2(temp);
+//       if( temp < baseData+baseLength )
+//       {
+//         assert(htemp2.getClassID()<500);
+//         assert(htemp2.getDataSize()!=0 && htemp2.getDataSize()<1000);
+//         assert(htemp2.isDiffed()==false);
+//       }
+//     }
+    while ( temp < baseData+baseOffset )
+    {
+      SynchronisableHeader htemp(temp);
+      if ( htemp.getObjectID() == objectID )
+      {
+        assert( h.getClassID() == htemp.getClassID() );
+        goto DODIFF;
+      }
+//       {
+//         SynchronisableHeader htemp2(temp+htemp.getDataSize()+SynchronisableHeader::getSize());
+//         if( temp+htemp.getDataSize()+SynchronisableHeader::getSize() < baseData+baseLength )
+//         {
+//           assert(htemp2.getClassID()<500);
+//           assert(htemp2.getDataSize()!=0 && htemp2.getDataSize()<1000);
+//           assert(htemp2.isDiffed()==false);
+//         }
+//       }
+      temp += htemp.getDataSize()+SynchronisableHeader::getSize();
+    }
+    // Object is new, thus never transmitted -> just copy over
+    goto DOCOPY;
+
+
+DODIFF:
+    {
+//       COUT(4) << "dodiff" << endl;
+//       if(baseOffset==0)
+//       {
+//         assert(origOffset==0);
+//       }
+      uint32_t objectOffset = SynchronisableHeader::getSize(); // offset inside the object in the origData and baseData
+      // Check whether the whole object stayed the same
+      if( memcmp( origData+origOffset+objectOffset, temp+objectOffset, h.getDataSize()) == 0 )
+      {
+//         COUT(4) << "skip object" << Synchronisable::getSynchronisable(h.getObjectID())->getIdentifier()->getName() << endl;
+        origOffset += objectOffset+ h.getDataSize(); // skip the whole object
+        baseOffset = temp + h.getDataSize()+SynchronisableHeader::getSize() - baseData;
+        sizes += Synchronisable::getSynchronisable(h.getObjectID())->getNrOfVariables();
+      }
+      else
+      {
+//         if( Synchronisable::getSynchronisable(h.getObjectID())->getIdentifier()->getName() == "Bot" )
+//           COUT(0) << "blub" << endl;
+//         COUT(4) << "object diff: " << Synchronisable::getSynchronisable(h.getObjectID())->getIdentifier()->getName() << endl;
+//         COUT(4) << "diff " << h.getObjectID() << ":";
+        // Now start to diff the Object
+        SynchronisableHeaderLight h2(dest);
+        h2 = h; // copy over the objectheader
+        VariableID variableID = 0;
+        uint32_t newObjectOffset = SynchronisableHeaderLight::getSize();
+        // iterate through all variables
+        while( objectOffset < h.getDataSize()+SynchronisableHeader::getSize() )
+        {
+          // check whether variable changed and write id and copy over variable to the new stream
+          // otherwise skip variable
+          assert(sizes != this->sizes_.end());
+          uint32_t varSize = *sizes;
+          assert( varSize == Synchronisable::getSynchronisable(h.getObjectID())->getVarSize(variableID) );
+          if ( varSize != 0 )
+          {
+            if ( memcmp(origData+origOffset+objectOffset, temp+objectOffset, varSize) != 0 )
+            {
+//               COUT(4) << "copy variable" << endl;
+              *(VariableID*)(dest+newObjectOffset) = variableID; // copy over the variableID
+              newObjectOffset += sizeof(VariableID);
+              memcpy( dest+newObjectOffset, origData+origOffset+objectOffset, varSize );
+              newObjectOffset += varSize;
+              objectOffset += varSize;
+            }
+            else
+            {
+//               COUT(4) << "skip variable" << endl;
+              objectOffset += varSize;
+            }
+          }
+//           else
+//             COUT(4) << "varsize 0" << endl;
+
+          ++variableID;
+          ++sizes;
+        }
+        
+        if( Synchronisable::getSynchronisable(h.getObjectID())->getNrOfVariables() != variableID )
+          sizes += Synchronisable::getSynchronisable(h.getObjectID())->getNrOfVariables() - variableID;
+//         COUT(4) << endl;
+        h2.setDiffed(true);
+        h2.setDataSize(newObjectOffset-SynchronisableHeaderLight::getSize());
+        assert(objectOffset == h.getDataSize()+SynchronisableHeader::getSize());
+        origOffset += objectOffset;
+//         baseOffset += temp + h.getDataSize()+SynchronisableHeader::getSize() - baseData;
+        //baseOffset += objectOffset;
+//         SynchronisableHeader htemp(temp);
+//         baseOffset += SynchronisableHeader::getSize() + htemp.getDataSize();
+//         {
+//           SynchronisableHeader htemp2( baseData+(temp-baseData+objectOffset) );
+//           if( baseData+(temp-baseData+objectOffset) < baseData+baseLength )
+//           {
+//             assert(htemp2.getClassID()<500);
+//             assert(htemp2.getDataSize()!=0 && htemp2.getDataSize()<1000);
+//             assert(htemp2.isDiffed()==false);
+//           }
+//         }
+        baseOffset = temp-baseData + objectOffset;
+        dest += newObjectOffset;
+      }
+
+      continue;
+    }
+
+DOCOPY:
+    {
+//       COUT(4) << "docopy" << endl;
+      // Just copy over the whole Object
+      memcpy( dest, origData+origOffset, h.getDataSize()+SynchronisableHeader::getSize() );
+      dest += h.getDataSize()+SynchronisableHeader::getSize();
+      origOffset += h.getDataSize()+SynchronisableHeader::getSize();
+      assert( Synchronisable::getSynchronisable(h.getObjectID()) );
+//       COUT(4) << "copy " << h.getObjectID() << endl;
+//       COUT(4) << "copy " << h.getObjectID() << ":";
+      //sizes += Synchronisable::getSynchronisable(h.getObjectID())->getNrOfVariables();
+      for( unsigned int i = 0; i < Synchronisable::getSynchronisable(h.getObjectID())->getNrOfVariables(); ++i )
+      {
+//         COUT(4) << " " << *sizes;
+        ++sizes;
+      }
+//       COUT(4) << endl;
+      assert(sizes != this->sizes_.end() || origOffset>=origLength);
+      continue;
+    }
+  }
+
+
+  Gamestate *g = new Gamestate(nData, getClientID());
+  assert(g->header_);
   *(g->header_) = *header_;
-  g->header_->setDiffed( true );
   g->header_->setBaseID( base->getID() );
+  g->header_->setDataSize(dest - nData - GamestateHeader::getSize());
   g->flags_=flags_;
   g->packetDirection_ = packetDirection_;
+  assert(!g->isCompressed());
   return g;
-}*/
-
-Gamestate *Gamestate::diff(Gamestate *base)
+}
+
+
+Gamestate* Gamestate::diffData(Gamestate *base)
 {
   assert(this && base); assert(data_ && base->data_);
@@ -393,5 +615,6 @@
 }
 
-Gamestate *Gamestate::undiff(Gamestate *base)
+
+Gamestate* Gamestate::undiff(Gamestate *base)
 {
   assert(this && base); assert(data_ && base->data_);
@@ -423,57 +646,4 @@
 
 
-// Gamestate *Gamestate::diff(Gamestate *base)
-// {
-//   assert(data_);
-//   assert(!header_->isCompressed());
-//   assert(!header_->isDiffed());
-//   GamestateHeader diffHeader(base->data_);
-//   uint8_t *basep = GAMESTATE_START(base->data_), *gs = GAMESTATE_START(this->data_);
-//   uint32_t of=0; // pointers offset
-//   uint32_t dest_length=0;
-//   dest_length=header_->getDataSize();
-//   if(dest_length==0)
-//     return NULL;
-//   uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()];
-//   uint8_t *dest = ndata + GamestateHeader::getSize();
-//
-//
-//   // LOOP-UNROLLED DIFFING
-//   uint32_t *dest32 = (uint32_t*)dest, *base32 = (uint32_t*)basep, *gs32 = (uint32_t*)gs;
-//   // diff in 4-byte steps
-//   while( of < (uint32_t)(header_->getDataSize())/4 ){
-//     if( of < (uint32_t)(diffHeader.getDataSize())/4 )
-//     {
-//       *(dest32+of)=*(base32+of) ^ *(gs32+of); // do the xor
-//       ++of;
-//     }
-//     else
-//     {
-//       *(dest32+of)=*(gs32+of); // same as 0 ^ *(gs32+of)
-//       ++of;
-//     }
-//   }
-//   for( unsigned int of2 = 0; of2 < header_->getDataSize()%4; ++of2 )
-//   {
-//     if( of*4+of2 < diffHeader.getDataSize() )
-//     {
-//       *(dest+4*of+of2)=*(basep+4*of+of2) ^ *(gs+4*of+of2); // do the xor
-//     }
-//     else
-//     {
-//       *(dest+4*of+of2)=*(gs+4*of+of2); // same as 0 ^ *(gs32+of)
-//     }
-//   }
-//
-//   Gamestate *g = new Gamestate(ndata, getClientID());
-//   *(g->header_) = *header_;
-//   g->header_->setDiffed( true );
-//   g->header_->setBaseID( base->getID() );
-//   g->flags_=flags_;
-//   g->packetDirection_ = packetDirection_;
-//   return g;
-// }
-
-
 void Gamestate::rawDiff( uint8_t* newdata, uint8_t* data, uint8_t* basedata, uint32_t datalength, uint32_t baselength)
 {
@@ -501,4 +671,5 @@
   assert(j==datalength);
 }
+
 
 Gamestate* Gamestate::doSelection(unsigned int clientID, unsigned int targetSize){
@@ -529,23 +700,21 @@
 //   COUT(0) << "myvector contains:";
 //   for ( itt=dataVector_.begin() ; itt!=dataVector_.end(); itt++ )
-//     COUT(0) << ' ' << (*itt).objID;
+//     COUT(0) << " " << (*itt).objID;
 //   COUT(0) << endl;
   for(it=dataVector_.begin(); it!=dataVector_.end();){
     SynchronisableHeader oldobjectheader(origdata);
     SynchronisableHeader newobjectheader(newdata);
-    if ( it->objSize == 0 )
+    if ( (*it).objSize == 0 )
     {
       ++it;
       continue;
     }
-    objectsize = oldobjectheader.getDataSize();
+    objectsize = oldobjectheader.getDataSize()+SynchronisableHeader::getSize();
     objectOffset=SynchronisableHeader::getSize(); //skip the size and the availableData variables in the objectheader
-    if ( it->objID == oldobjectheader.getObjectID() ){
+    if ( (*it).objID == oldobjectheader.getObjectID() ){
       memcpy(newdata, origdata, objectsize);
-      assert(newobjectheader.isDataAvailable()==true);
       ++it;
     }else{
       newobjectheader = oldobjectheader;
-      newobjectheader.setDataAvailable(false);
       memset(newdata+objectOffset, 0, objectsize-objectOffset);
     }
@@ -559,5 +728,5 @@
   {
     SynchronisableHeader oldobjectheader(origdata);
-    objectsize = oldobjectheader.getDataSize();
+    objectsize = oldobjectheader.getDataSize()+SynchronisableHeader::getSize();
     origdata += objectsize;
     origsize += objectsize;
@@ -571,52 +740,20 @@
 
 
-/*Gamestate *Gamestate::undiff(Gamestate *base)
-{
-  assert(this && base);assert(data_);
-  assert(header_->isDiffed());
-  assert(!header_->isCompressed() && !base->header_->isCompressed());
-  uint8_t *basep = GAMESTATE_START(base->data_);
-  uint8_t *gs = GAMESTATE_START(this->data_);
-  uint32_t of=0; // pointers offset
-  uint32_t dest_length=0;
-  dest_length=header_->getDataSize();
-  if(dest_length==0)
-    return NULL;
-  uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()];
-  uint8_t *dest = ndata + GamestateHeader::getSize();
-  while(of < base->header_->getDataSize() && of < header_->getDataSize()){
-    *(dest+of)=*(basep+of)^*(gs+of); // do the xor
-    ++of;
-  }
-  if(base->header_->getDataSize()!=header_->getDataSize()){
-    uint8_t n=0;
-    if(base->header_->getDataSize() < header_->getDataSize()){
-      while(of < dest_length){
-        *(dest+of)=n^*(gs+of);
-        of++;
-      }
-    }
-  }
-  Gamestate *g = new Gamestate(ndata, getClientID());
-  assert(g->header_);
-  *(g->header_) = *header_;
-  g->header_->setDiffed( false );
-  g->flags_=flags_;
-  g->packetDirection_ = packetDirection_;
-  assert(!g->isDiffed());
-  assert(!g->isCompressed());
-  return g;
-}*/
-
 uint32_t Gamestate::calcGamestateSize(int32_t id, uint8_t mode)
 {
-  uint32_t size=0;
+  uint32_t size = 0;
+  uint32_t nrOfVariables = 0;
     // get the start of the Synchronisable list
   ObjectList<Synchronisable>::iterator it;
     // get total size of gamestate
-  for(it = ObjectList<Synchronisable>::begin(); it; ++it)
+  for(it = ObjectList<Synchronisable>::begin(); it; ++it){
     size+=it->getSize(id, mode); // size of the actual data of the synchronisable
+    nrOfVariables += it->getNrOfVariables();
+  }
+//   COUT(0) << "allocating " << nrOfVariables << " ints" << endl;
+  this->sizes_.reserve(nrOfVariables);
   return size;
 }
+
 
 } //namespace packet
Index: code/trunk/src/libraries/network/packet/Gamestate.h
===================================================================
--- code/trunk/src/libraries/network/packet/Gamestate.h	(revision 6906)
+++ code/trunk/src/libraries/network/packet/Gamestate.h	(revision 7163)
@@ -36,4 +36,5 @@
 #include <cstring>
 #include <list>
+#include <vector>
 
 #include "util/CRC32.h"
@@ -113,5 +114,7 @@
     inline bool isCompressed() const { return header_->isCompressed(); }
     inline int32_t getBaseID() const { return header_->getBaseID(); }
-    Gamestate *diff(Gamestate *base);
+    inline uint32_t getDataSize() const { return header_->getDataSize(); }
+    Gamestate* diffVariables(Gamestate *base);
+    Gamestate* diffData(Gamestate *base);
     Gamestate *undiff(Gamestate *base);
     Gamestate* doSelection(unsigned int clientID, unsigned int targetSize);
@@ -123,11 +126,13 @@
   private:
     void rawDiff( uint8_t* newdata, uint8_t* data, uint8_t* basedata, uint32_t datalength, uint32_t baselength);
+    inline uint32_t findObject( const SynchronisableHeader& header, uint8_t* mem, uint32_t dataLength, uint32_t startPosition = 0 );
     virtual uint32_t getSize() const;
     virtual inline bool process();
-
-  private:
     uint32_t calcGamestateSize(int32_t id, uint8_t mode=0x0);
-    std::list<obj> dataVector_;
-    GamestateHeader* header_;
+    
+    std::list<obj>          dataVector_;
+    GamestateHeader*        header_;
+    std::vector<uint32_t>   sizes_;
+    uint32_t                nrOfVariables_;
 };
 
Index: code/trunk/src/libraries/network/packet/Packet.cc
===================================================================
--- code/trunk/src/libraries/network/packet/Packet.cc	(revision 6906)
+++ code/trunk/src/libraries/network/packet/Packet.cc	(revision 7163)
@@ -62,5 +62,6 @@
 std::map<size_t, Packet *> Packet::packetMap_;
 
-Packet::Packet(){
+Packet::Packet()
+{
   flags_ = PACKET_FLAG_DEFAULT;
   packetDirection_ = Direction::Outgoing;
@@ -71,9 +72,6 @@
 }
 
-void blub(ENetPacket *packet){
-  COUT(4) << "blubb" << std::endl;
-}
-
-Packet::Packet(uint8_t *data, unsigned int clientID){
+Packet::Packet(uint8_t *data, unsigned int clientID)
+{
   flags_ = PACKET_FLAG_DEFAULT;
   packetDirection_ = Direction::Incoming;
Index: code/trunk/src/libraries/network/packet/ServerInformation.cc
===================================================================
--- code/trunk/src/libraries/network/packet/ServerInformation.cc	(revision 7163)
+++ code/trunk/src/libraries/network/packet/ServerInformation.cc	(revision 7163)
@@ -0,0 +1,84 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "ServerInformation.h"
+
+#include <enet/enet.h>
+#include <cassert>
+#include <cstring>
+
+#include "util/Serialise.h"
+
+namespace orxonox
+{
+  namespace packet
+  {
+    
+    ServerInformation::ServerInformation()
+    {
+      
+    }
+    
+    ServerInformation::ServerInformation(ENetEvent* event)
+    {
+      // Save Server Round Trip Time
+      this->serverRTT_ = event->peer->roundTripTime;
+      // Save Server IP
+      char* serverIP = new char[16];
+      enet_address_get_host_ip(&event->peer->address, serverIP, 16);
+      this->serverIP_ = std::string(serverIP);
+      // Save ACK
+      uint8_t* temp = event->packet->data;
+      char* ack = new char[strlen(LAN_DISCOVERY_ACK)+1];
+      loadAndIncrease((char*&)ack, temp);
+      assert(strcmp(ack, (const char*)LAN_DISCOVERY_ACK)==0);
+      // Save Server Name
+      loadAndIncrease(this->serverName_, temp);
+    }
+
+    ServerInformation::~ServerInformation()
+    {
+      
+    }
+
+    void ServerInformation::send(ENetPeer* peer)
+    {
+      uint32_t size = returnSize((char*&)LAN_DISCOVERY_ACK) + returnSize(this->serverName_);
+      uint8_t* temp = new uint8_t[size];
+      uint8_t* temp2 = temp;
+      saveAndIncrease((char*&)LAN_DISCOVERY_ACK, temp2);
+      saveAndIncrease(this->serverName_, temp2);
+      ENetPacket* packet = enet_packet_create( temp, size, 0 );
+      enet_peer_send(peer, 0, packet);
+      
+      delete[] temp;
+    }
+  
+  } // namespace packet
+} // namespace orxonox
+
Index: code/trunk/src/libraries/network/packet/ServerInformation.h
===================================================================
--- code/trunk/src/libraries/network/packet/ServerInformation.h	(revision 7163)
+++ code/trunk/src/libraries/network/packet/ServerInformation.h	(revision 7163)
@@ -0,0 +1,63 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "../NetworkPrereqs.h"
+
+#include <string>
+
+#ifndef SERVERINFORMATION_H
+#define SERVERINFORMATION_H
+
+namespace orxonox
+{
+  namespace packet
+  {
+
+    class ServerInformation
+    {
+      public:
+        ServerInformation();
+        ServerInformation(ENetEvent* event);
+        ~ServerInformation();
+        
+        void          send( ENetPeer* peer );
+        std::string   getServerIP() { return this->serverIP_; }
+        std::string   getServerName() { return this->serverName_; }
+        void          setServerName(std::string name) { this->serverName_ = name; }
+        uint32_t      getServerRTT() { return this->serverRTT_; }
+        
+      private:
+        std::string   serverName_;
+        std::string   serverIP_;
+        uint32_t      serverRTT_;
+    };
+
+  }
+}
+
+#endif // SERVERINFORMATION_H
Index: code/trunk/src/libraries/network/synchronisable/Serialise.h
===================================================================
--- code/trunk/src/libraries/network/synchronisable/Serialise.h	(revision 6906)
+++ code/trunk/src/libraries/network/synchronisable/Serialise.h	(revision 7163)
@@ -38,4 +38,6 @@
 #include "util/TypeTraits.h"
 #include "core/CorePrereqs.h"
+#include "core/CoreIncludes.h"
+#include "core/SmartPtr.h"
 
 namespace orxonox{
@@ -72,4 +74,74 @@
             return *(uint32_t*)(mem) == variable->getObjectID();
         else
+            return variable == variable->getSynchronisable(*(uint32_t*)(mem));
+    }
+    
+    // These functions implement loading / saving / etc. for SmartPtr<T>
+    
+    /** @brief returns the size of the objectID needed to synchronise the pointer */
+    template <class T> inline uint32_t returnSize( const SmartPtr<T>& variable )
+    {
+        return sizeof(uint32_t);
+    }
+    
+    /** @brief reads the objectID of a pointer out of the bytestream and increases the mem pointer */
+    template <class T> inline void loadAndIncrease( const SmartPtr<T>& variable, uint8_t*& mem )
+    {
+//         *const_cast<typename Loki::TypeTraits<T*>::UnqualifiedType*>(&variable) = dynamic_cast<T*>(variable->getSynchronisable( *(uint32_t*)(mem) ));
+        *const_cast<typename Loki::TypeTraits<SmartPtr<T> >::UnqualifiedType*>(&variable) = orxonox_cast<T*>(T::getSynchronisable(*(uint32_t*)(mem)));
+        mem += returnSize( variable );
+    }
+    
+    /** @brief saves the objectID of a pointer into the bytestream and increases the mem pointer */
+    template <class T> inline void saveAndIncrease( const SmartPtr<T>& variable, uint8_t*& mem )
+    {
+        if ( variable.get() )
+            *(uint32_t*)(mem) = static_cast<uint32_t>(variable->getObjectID());
+        else
+            *(uint32_t*)(mem) = OBJECTID_UNKNOWN;
+        mem += returnSize( variable );
+    }
+    
+    /** @brief checks whether the objectID of the variable is the same as in the bytestream */
+    template <class T> inline  bool checkEquality( const SmartPtr<T>& variable, uint8_t* mem )
+    {
+        if ( variable.get() )
+            return *(uint32_t*)(mem) == variable->getObjectID();
+        else
+            return *(uint32_t*)(mem) == OBJECTID_UNKNOWN;
+    }
+    
+    // These functions implement loading / saving / etc. for WeakPtr<T>
+    
+    /** @brief returns the size of the objectID needed to synchronise the pointer */
+    template <class T> inline uint32_t returnSize( const WeakPtr<T>& variable )
+    {
+        return sizeof(uint32_t);
+    }
+    
+    /** @brief reads the objectID of a pointer out of the bytestream and increases the mem pointer */
+    template <class T> inline void loadAndIncrease( const WeakPtr<T>& variable, uint8_t*& mem )
+    {
+        //         *const_cast<typename Loki::TypeTraits<T*>::UnqualifiedType*>(&variable) = dynamic_cast<T*>(variable->getSynchronisable( *(uint32_t*)(mem) ));
+        *const_cast<typename Loki::TypeTraits<SmartPtr<T> >::UnqualifiedType*>(&variable) = orxonox_cast<T*>(T::getSynchronisable(*(uint32_t*)(mem)));
+        mem += returnSize( variable );
+    }
+    
+    /** @brief saves the objectID of a pointer into the bytestream and increases the mem pointer */
+    template <class T> inline void saveAndIncrease( const WeakPtr<T>& variable, uint8_t*& mem )
+    {
+        if ( variable.get() )
+            *(uint32_t*)(mem) = static_cast<uint32_t>(variable->getObjectID());
+        else
+            *(uint32_t*)(mem) = OBJECTID_UNKNOWN;
+        mem += returnSize( variable );
+    }
+    
+    /** @brief checks whether the objectID of the variable is the same as in the bytestream */
+    template <class T> inline  bool checkEquality( const WeakPtr<T>& variable, uint8_t* mem )
+    {
+        if ( variable.get() )
+            return *(uint32_t*)(mem) == variable->getObjectID();
+        else
             return *(uint32_t*)(mem) == OBJECTID_UNKNOWN;
     }
Index: code/trunk/src/libraries/network/synchronisable/Synchronisable.cc
===================================================================
--- code/trunk/src/libraries/network/synchronisable/Synchronisable.cc	(revision 6906)
+++ code/trunk/src/libraries/network/synchronisable/Synchronisable.cc	(revision 7163)
@@ -49,9 +49,10 @@
   * Initializes all Variables and sets the right objectID_
   */
-  Synchronisable::Synchronisable(BaseObject* creator ){
+  Synchronisable::Synchronisable(BaseObject* creator )
+  {
     RegisterRootObject(Synchronisable);
     static uint32_t idCounter=0;
     objectMode_=0x1; // by default do not send data to server
-    if ( GameMode::isMaster() || ( Host::running() && Host::isServer() ) )
+    if ( GameMode::isMaster()/* || ( Host::running() && Host::isServer() )*/ )
     {
       this->setObjectID( idCounter++ );
@@ -73,19 +74,4 @@
     else
       this->creatorID_ = OBJECTID_UNKNOWN;
-
-    /*searchcreatorID:
-    if (creator)
-    {
-        Synchronisable* synchronisable_creator = orxonox_cast<Synchronisable*>(creator);
-        if (synchronisable_creator && synchronisable_creator->objectMode_)
-        {
-            this->creatorID = synchronisable_creator->getScene()->getObjectID();
-        }
-        else if (creator != creator->getCreator())
-        {
-            creator = creator->getCreator();
-            goto searchcreatorID;
-        }
-    }*/
   }
 
@@ -94,5 +80,6 @@
    * Delete all callback objects and remove objectID_ from the objectMap_
    */
-  Synchronisable::~Synchronisable(){
+  Synchronisable::~Synchronisable()
+  {
     // delete callback function objects
     if(!Identifier::isCreatingHierarchy()){
@@ -101,9 +88,9 @@
         deletedObjects_.push(objectID_);
     }
-    // delete all Synchronisable Variables from syncList ( which are also in stringList )
-    for(std::vector<SynchronisableVariableBase*>::iterator it = syncList.begin(); it!=syncList.end(); it++)
+    // delete all Synchronisable Variables from syncList_ ( which are also in stringList_ )
+    for(std::vector<SynchronisableVariableBase*>::iterator it = syncList_.begin(); it!=syncList_.end(); it++)
       delete (*it);
-    syncList.clear();
-    stringList.clear();
+    syncList_.clear();
+    stringList_.clear();
     std::map<uint32_t, Synchronisable*>::iterator it;
     it = objectMap_.find(objectID_);
@@ -118,5 +105,6 @@
    * @param b true if this object is located on a client or on a server
    */
-  void Synchronisable::setClient(bool b){
+  void Synchronisable::setClient(bool b)
+  {
     if(b) // client
       state_=0x2;
@@ -135,10 +123,5 @@
   {
     SynchronisableHeader header(mem);
-
-    if(!header.isDataAvailable())
-    {
-      mem += header.getDataSize();
-      return 0;
-    }
+    assert( !header.isDiffed() );
 
     COUT(4) << "fabricating object with id: " << header.getObjectID() << std::endl;
@@ -160,5 +143,5 @@
       if (!synchronisable_creator)
       {
-        mem += header.getDataSize(); //.TODO: this suckz.... remove size from header
+        mem += header.getDataSize()+SynchronisableHeader::getSize(); //.TODO: this suckz.... remove size from header
         assert(0); // TODO: uncomment this if we have a clean objecthierarchy (with destruction of children of objects) ^^
         return 0;
@@ -177,4 +160,6 @@
     no->setClassID(header.getClassID());
     assert(no->creatorID_ == header.getCreatorID());
+    if( creator )
+      bo->setLevel(creator->getLevel());          // Note: this ensures that the level is known on the client for child objects of the scene (and the scene itself)
     //assert(no->classID_ == header.getClassID());
     COUT(4) << "fabricate objectID_: " << no->objectID_ << " classID_: " << no->classID_ << std::endl;
@@ -196,5 +181,6 @@
    * @return true/false
    */
-  bool Synchronisable::deleteObject(uint32_t objectID_){
+  bool Synchronisable::deleteObject(uint32_t objectID_)
+  {
     if(!getSynchronisable(objectID_))
       return false;
@@ -213,17 +199,10 @@
    * @return pointer to the Synchronisable with the objectID_
    */
-  Synchronisable* Synchronisable::getSynchronisable(uint32_t objectID_){
+  Synchronisable* Synchronisable::getSynchronisable(uint32_t objectID_)
+  {
     std::map<uint32_t, Synchronisable*>::iterator it1;
     it1 = objectMap_.find(objectID_);
     if (it1 != objectMap_.end())
       return it1->second;
-
-//     ObjectList<Synchronisable>::iterator it;
-//     for(it = ObjectList<Synchronisable>::begin(); it; ++it){
-//       if( it->getObjectID()==objectID_ ){
-//         objectMap_[objectID_] = *it;
-//         return *it;
-//       }
-//     }
     // if the objects not in the map it should'nt exist at all anymore
     return NULL;
@@ -245,5 +224,7 @@
    * @return true: if !doSync or if everything was successfully saved
    */
-  uint32_t Synchronisable::getData(uint8_t*& mem, int32_t id, uint8_t mode){
+  uint32_t Synchronisable::getData(uint8_t*& mem, std::vector<uint32_t>& sizes, int32_t id, uint8_t mode)
+  {
+    unsigned int test = 0;
     if(mode==0x0)
       mode=state_;
@@ -253,4 +234,5 @@
     uint32_t tempsize = 0;
 #ifndef NDEBUG
+    uint8_t* oldmem = mem;
     if (this->classID_==0)
       COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
@@ -270,18 +252,26 @@
     // end copy header
 
-
-    COUT(5) << "Synchronisable getting data from objectID_: " << objectID_ << " classID_: " << classID_ << std::endl;
+    CCOUT(5) << "getting data from objectID_: " << objectID_ << ", classID_: " << classID_ << std::endl;
+//     COUT(4) << "objectid: " << this->objectID_ << ":";
     // copy to location
-    for(i=syncList.begin(); i!=syncList.end(); ++i){
-      tempsize += (*i)->getData( mem, mode );
+    for(i=syncList_.begin(); i!=syncList_.end(); ++i)
+    {
+      uint32_t varsize = (*i)->getData( mem, mode );
+//       COUT(4) << " " << varsize;
+      tempsize += varsize;
+      sizes.push_back(varsize);
+      ++test;
       //tempsize += (*i)->getSize( mode );
     }
-
-    tempsize += SynchronisableHeader::getSize();
+//     COUT(4) << endl;
+
     header.setObjectID( this->objectID_ );
     header.setCreatorID( this->creatorID_ );
     header.setClassID( this->classID_ );
-    header.setDataAvailable( true );
     header.setDataSize( tempsize );
+    assert( tempsize == mem-oldmem-SynchronisableHeader::getSize() );
+    assert( test == this->getNrOfVariables() );
+    header.setDiffed(false);
+    tempsize += SynchronisableHeader::getSize();
 
 #ifndef NDEBUG
@@ -300,11 +290,12 @@
    * @return true/false
    */
-  bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback){
+  bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback)
+  {
     if(mode==0x0)
       mode=state_;
-    std::vector<SynchronisableVariableBase *>::iterator i;
-    if(syncList.empty()){
+    if(syncList_.empty())
+    {
       assert(0);
-      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
+      COUT(2) << "Synchronisable::updateData syncList_ is empty" << std::endl;
       return false;
     }
@@ -312,23 +303,36 @@
     uint8_t* data=mem;
     // start extract header
-    SynchronisableHeader syncHeader(mem);
-    assert(syncHeader.getObjectID()==this->objectID_);
-    assert(syncHeader.getCreatorID()==this->creatorID_);
-    assert(syncHeader.getClassID()==this->classID_);
-    if(syncHeader.isDataAvailable()==false){
-      mem += syncHeader.getDataSize();
-      return true;
-    }
-
-    mem += SynchronisableHeader::getSize();
-    // stop extract header
+    SynchronisableHeaderLight syncHeaderLight(mem);
+    assert(syncHeaderLight.getObjectID()==this->getObjectID());
 
     //COUT(5) << "Synchronisable: objectID_ " << syncHeader.getObjectID() << ", classID_ " << syncHeader.getClassID() << " size: " << syncHeader.getDataSize() << " synchronising data" << std::endl;
-    for(i=syncList.begin(); i!=syncList.end(); i++)
-    {
-      assert( mem <= data+syncHeader.getDataSize() ); // always make sure we don't exceed the datasize in our stream
-      (*i)->putData( mem, mode, forceCallback );
-    }
-    assert(mem == data+syncHeader.getDataSize());
+    if( !syncHeaderLight.isDiffed() )
+    {
+      SynchronisableHeader syncHeader2(mem);
+      assert( this->getClassID() == syncHeader2.getClassID() );
+      assert( this->getCreatorID() == syncHeader2.getCreatorID() );
+      mem += SynchronisableHeader::getSize();
+      std::vector<SynchronisableVariableBase *>::iterator i;
+      for(i=syncList_.begin(); i!=syncList_.end(); i++)
+      {
+        assert( mem <= data+syncHeader2.getDataSize()+SynchronisableHeader::getSize() ); // always make sure we don't exceed the datasize in our stream
+        (*i)->putData( mem, mode, forceCallback );
+      }
+      assert(mem == data+syncHeaderLight.getDataSize()+SynchronisableHeader::getSize() );
+    }
+    else
+    {
+      mem += SynchronisableHeaderLight::getSize();
+//       COUT(0) << "objectID: " << this->objectID_ << endl;
+      while( mem < data+syncHeaderLight.getDataSize()+SynchronisableHeaderLight::getSize() )
+      {
+        VariableID varID = *(VariableID*)mem;
+//         COUT(0) << "varID: " << varID << endl;
+        assert( varID < syncList_.size() );
+        mem += sizeof(VariableID);
+        syncList_[varID]->putData( mem, mode, forceCallback );
+      }
+      assert(mem == data+syncHeaderLight.getDataSize()+SynchronisableHeaderLight::getSize() );
+    }
     return true;
   }
@@ -340,6 +344,7 @@
   * @return amount of bytes
   */
-  uint32_t Synchronisable::getSize(int32_t id, uint8_t mode){
-    int tsize=SynchronisableHeader::getSize();
+  uint32_t Synchronisable::getSize(int32_t id, uint8_t mode)
+  {
+    uint32_t tsize=SynchronisableHeader::getSize();
     if (mode==0x0)
       mode=state_;
@@ -349,5 +354,6 @@
     tsize += this->dataSize_;
     std::vector<SynchronisableVariableBase*>::iterator i;
-    for(i=stringList.begin(); i!=stringList.end(); ++i){
+    for(i=stringList_.begin(); i!=stringList_.end(); ++i)
+    {
       tsize += (*i)->getSize( mode );
     }
@@ -360,19 +366,9 @@
    * @return true/false
    */
-  bool Synchronisable::doSync(int32_t id, uint8_t mode){
+  bool Synchronisable::doSync(int32_t id, uint8_t mode)
+  {
     if(mode==0x0)
       mode=state_;
-    return ( (this->objectMode_ & mode)!=0 && (!syncList.empty() ) );
-  }
-
-  /**
-   * This function looks at the header located in the bytestream and checks wheter objectID_ and classID_ match with the Synchronisables ones
-   * @param mem pointer to the bytestream
-   */
-  bool Synchronisable::isMyData(uint8_t* mem)
-  {
-    SynchronisableHeader header(mem);
-    assert(header.getObjectID()==this->objectID_);
-    return header.isDataAvailable();
+    return ( (this->objectMode_ & mode)!=0 && (!syncList_.empty() ) );
   }
 
@@ -385,5 +381,6 @@
    * @param mode same as in registerVar
    */
-  void Synchronisable::setSyncMode(uint8_t mode){
+  void Synchronisable::setSyncMode(uint8_t mode)
+  {
     assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3);
     this->objectMode_=mode;
@@ -397,6 +394,41 @@
     else
       sv = new SynchronisableVariable<std::string>(variable, mode, cb);
-    syncList.push_back(sv);
-    stringList.push_back(sv);
+    syncList_.push_back(sv);
+    stringList_.push_back(sv);
+  }
+
+template <> void Synchronisable::unregisterVariable( std::string& variable )
+  {
+    bool unregistered_nonexistent_variable = true;
+    std::vector<SynchronisableVariableBase*>::iterator it = syncList_.begin();
+    while(it!=syncList_.end())
+    {
+      if( ((*it)->getReference()) == &variable )
+      {
+        delete (*it);
+        syncList_.erase(it);
+        unregistered_nonexistent_variable = false;
+        break;
+      }
+      else
+        ++it;
+    }
+    assert(unregistered_nonexistent_variable == false);
+    
+    it = stringList_.begin();
+    while(it!=stringList_.end())
+    {
+      if( ((*it)->getReference()) == &variable )
+      {
+        delete (*it);
+        stringList_.erase(it);
+        return;
+      }
+      else
+        ++it;
+    }
+    unregistered_nonexistent_variable = true;
+    assert(unregistered_nonexistent_variable == false); //if we reach this point something went wrong:
+    // the variable has not been registered before
   }
 
Index: code/trunk/src/libraries/network/synchronisable/Synchronisable.h
===================================================================
--- code/trunk/src/libraries/network/synchronisable/Synchronisable.h	(revision 6906)
+++ code/trunk/src/libraries/network/synchronisable/Synchronisable.h	(revision 7163)
@@ -37,4 +37,5 @@
 #include <map>
 #include <queue>
+#include <set>
 
 #include "util/mbool.h"
@@ -64,4 +65,6 @@
     };
   }
+  
+  typedef uint8_t VariableID;
 
   /**
@@ -71,5 +74,5 @@
    * in an emulated bitset.
    * Bit 1 to 31 store the size of the Data the synchronisable consumes in the stream
-   * Bit 32 is a bool and defines whether the data is actually stored or is just filled up with 0
+   * Bit 32 is a bool and defines whether the variables are stored in diff mode
    * Byte 5 to 8: objectID_
    * Byte 9 to 12: classID_
@@ -77,35 +80,68 @@
    */
   class _NetworkExport SynchronisableHeader{
+    friend class SynchronisableHeaderLight;
     private:
-      uint8_t *data_;
+      uint8_t* data_;
     public:
       SynchronisableHeader(uint8_t* data)
         { data_ = data; }
       inline static uint32_t getSize()
-        { return 16; }
-      inline uint32_t getDataSize() const
-        { return (*(uint32_t*)data_) & 0x7FFFFFFF; } //only use the first 31 bits
-      inline void setDataSize(uint32_t size)
-        { *(uint32_t*)(data_) = (size & 0x7FFFFFFF) | (*(uint32_t*)(data_) & 0x80000000 ); }
-      inline bool isDataAvailable() const
-        { return ( (*(uint32_t*)data_) & 0x80000000 ) == 0x80000000; }
-      inline void setDataAvailable( bool b)
-        { *(uint32_t*)(data_) = (b << 31) | (*(uint32_t*)(data_) & 0x7FFFFFFF ); }
+        { return 14; }
+      inline uint16_t getDataSize() const
+        { return (*(uint16_t*)data_) & 0x7FFF; } //only use the first 15 bits
+      inline void setDataSize(uint16_t size)
+        { *(uint16_t*)(data_) = (size & 0x7FFF) | (*(uint16_t*)(data_) & 0x8000 ); }
+      inline bool isDiffed() const
+        { return ( (*(uint16_t*)data_) & 0x8000 ) == 0x8000; }
+      inline void setDiffed( bool b)
+        { *(uint16_t*)(data_) = (b << 15) | (*(uint16_t*)(data_) & 0x7FFF ); }
       inline uint32_t getObjectID() const
-        { return *(uint32_t*)(data_+4); }
+        { return *(uint32_t*)(data_+2); }
       inline void setObjectID(uint32_t objectID_)
-        { *(uint32_t*)(data_+4) = objectID_; }
+        { *(uint32_t*)(data_+2) = objectID_; }
       inline uint32_t getClassID() const
-        { return *(uint32_t*)(data_+8); }
+        { return *(uint32_t*)(data_+6); }
       inline void setClassID(uint32_t classID_)
-        { *(uint32_t*)(data_+8) = classID_; }
+        { *(uint32_t*)(data_+6) = classID_; }
       inline uint32_t getCreatorID() const
-        { return *(uint32_t*)(data_+12); }
+        { return *(uint32_t*)(data_+10); }
       inline void setCreatorID(uint32_t creatorID_)
-        { *(uint32_t*)(data_+12) = creatorID_; }
+        { *(uint32_t*)(data_+10) = creatorID_; }
       inline void operator=(SynchronisableHeader& h)
         { memcpy(data_, h.data_, getSize()); }
   };
 
+    /**
+   * @brief: stores information about a Synchronisable (light version)
+   *
+   * This class stores the information about a Synchronisable (objectID_, dataSize)
+   * in an emulated bitset.
+   * Bit 1 to 31 store the size of the Data the synchronisable consumes in the stream
+   * Bit 32 is a bool and defines whether the variables are stored in diff mode
+   * Byte 5 to 8: objectID_
+   */
+  class _NetworkExport SynchronisableHeaderLight{
+    private:
+      uint8_t* data_;
+    public:
+      SynchronisableHeaderLight(uint8_t* data)
+        { data_ = data; }
+      inline static uint32_t getSize()
+        { return 6; }
+      inline uint16_t getDataSize() const
+        { return (*(uint16_t*)data_) & 0x7FFF; } //only use the first 31 bits
+      inline void setDataSize(uint16_t size)
+        { *(uint16_t*)(data_) = (size & 0x7FFFFFFF) | (*(uint16_t*)(data_) & 0x8000 ); }
+      inline bool isDiffed() const
+        { return ( (*(uint16_t*)data_) & 0x8000 ) == 0x8000; }
+      inline void setDiffed( bool b)
+        { *(uint16_t*)(data_) = (b << 15) | (*(uint16_t*)(data_) & 0x7FFF ); }
+      inline uint32_t getObjectID() const
+        { return *(uint32_t*)(data_+2); }
+      inline void setObjectID(uint32_t objectID_)
+        { *(uint32_t*)(data_+2) = objectID_; }
+      inline void operator=(SynchronisableHeader& h)
+        { memcpy(data_, h.data_, getSize()); }
+  };
 
   /**
@@ -134,8 +170,14 @@
 
     void setSyncMode(uint8_t mode);
+    
+    inline uint32_t getNrOfVariables(){ return this->syncList_.size(); }
+    inline uint32_t getVarSize( VariableID ID )
+    { return this->syncList_[ID]->getSize(state_); }
 
   protected:
     Synchronisable(BaseObject* creator);
     template <class T> void registerVariable(T& variable, uint8_t mode=0x1, NetworkCallbackBase *cb=0, bool bidirectional=false);
+    template <class T> void registerVariable(std::set<T>& variable, uint8_t mode=0x1, NetworkCallbackBase *cb=0, bool bidirectional=false);
+    template <class T> void unregisterVariable(T& var);
 
     void setPriority(unsigned int freq){ objectFrequency_ = freq; }
@@ -143,8 +185,7 @@
 
   private:
-    uint32_t getData(uint8_t*& men, int32_t id, uint8_t mode=0x0);
+    uint32_t getData(uint8_t*& mem, std::vector<uint32_t>& sizes, int32_t id, uint8_t mode);
     uint32_t getSize(int32_t id, uint8_t mode=0x0);
     bool updateData(uint8_t*& mem, uint8_t mode=0x0, bool forceCallback=false);
-    bool isMyData(uint8_t* mem);
     bool doSync(int32_t id, uint8_t mode=0x0);
 
@@ -156,6 +197,6 @@
     uint32_t classID_;
 
-    std::vector<SynchronisableVariableBase*> syncList;
-    std::vector<SynchronisableVariableBase*> stringList;
+    std::vector<SynchronisableVariableBase*> syncList_;
+    std::vector<SynchronisableVariableBase*> stringList_;
     uint32_t dataSize_; //size of all variables except strings
     static uint8_t state_; // detemines wheter we are server (default) or client
@@ -171,16 +212,46 @@
     if (bidirectional)
     {
-      syncList.push_back(new SynchronisableVariableBidirectional<T>(variable, mode, cb));
-      this->dataSize_ += syncList.back()->getSize(state_);
+      syncList_.push_back(new SynchronisableVariableBidirectional<T>(variable, mode, cb));
+      this->dataSize_ += syncList_.back()->getSize(state_);
     }
     else
     {
-      syncList.push_back(new SynchronisableVariable<T>(variable, mode, cb));
+      syncList_.push_back(new SynchronisableVariable<T>(variable, mode, cb));
       if ( this->state_ == mode )
-        this->dataSize_ += syncList.back()->getSize(state_);
+        this->dataSize_ += syncList_.back()->getSize(state_);
     }
   }
+  
+  template <class T> void Synchronisable::unregisterVariable(T& variable){
+    std::vector<SynchronisableVariableBase*>::iterator it = syncList_.begin();
+    while(it!=syncList_.end()){
+      if( ((*it)->getReference()) == &variable ){
+        this->dataSize_ -= (*it)->getSize(Synchronisable::state_);
+        delete (*it);
+        syncList_.erase(it);
+        return;
+      }
+      else
+        it++;
+    }
+    bool unregistered_nonexistent_variable = false;
+    assert(unregistered_nonexistent_variable); //if we reach this point something went wrong:
+    // the variable has not been registered before
+  }
+
+  template <class T> void Synchronisable::registerVariable( std::set<T>& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional)
+  {
+    SynchronisableVariableBase* sv;
+    if (bidirectional)
+      sv = new SynchronisableVariableBidirectional<std::set<T> >(variable, mode, cb);
+    else
+      sv = new SynchronisableVariable<std::set<T> >(variable, mode, cb);
+    syncList_.push_back(sv);
+    stringList_.push_back(sv);
+  }
 
   template <> _NetworkExport void Synchronisable::registerVariable( std::string& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional);
+//   template <class T> _NetworkExport void Synchronisable::registerVariable<std::set<T> >( std::set<T>& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional);
+  template <> _NetworkExport void Synchronisable::unregisterVariable( std::string& variable );
 
 
Index: code/trunk/src/libraries/tools/CMakeLists.txt
===================================================================
--- code/trunk/src/libraries/tools/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/libraries/tools/CMakeLists.txt	(revision 7163)
@@ -15,10 +15,9 @@
 COMPILATION_END
 )
+#ADD_SUBDIRECTORY(bsp)
 ADD_SUBDIRECTORY(interfaces)
 
 ORXONOX_ADD_LIBRARY(tools
   FIND_HEADER_FILES
-  DEFINE_SYMBOL
-    "TOOLS_SHARED_BUILD"
   LINK_LIBRARIES
     core
Index: code/trunk/src/libraries/tools/ToolsPrereqs.h
===================================================================
--- code/trunk/src/libraries/tools/ToolsPrereqs.h	(revision 6906)
+++ code/trunk/src/libraries/tools/ToolsPrereqs.h	(revision 7163)
@@ -42,5 +42,5 @@
 //-----------------------------------------------------------------------
 
-#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_STATIC_BUILD)
+#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(TOOLS_STATIC_BUILD)
 #  ifdef TOOLS_SHARED_BUILD
 #    define _ToolsExport __declspec(dllexport)
Index: code/trunk/src/libraries/tools/bsp/CMakeLists.txt
===================================================================
--- code/trunk/src/libraries/tools/bsp/CMakeLists.txt	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/CMakeLists.txt	(revision 7163)
@@ -0,0 +1,8 @@
+ADD_SOURCE_FILES(TOOLS_SRC_FILES
+  DemoApp.cpp
+  OgreFramework.cpp
+  OgreGpuCommandBufferFlush.cpp
+  Q3Map.cpp
+  Q3Map_Bezier.cpp
+  Q3Map_BspVertex.cpp
+)
Index: code/trunk/src/libraries/tools/bsp/DemoApp.cpp
===================================================================
--- code/trunk/src/libraries/tools/bsp/DemoApp.cpp	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/DemoApp.cpp	(revision 7163)
@@ -0,0 +1,602 @@
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+#include "DemoApp.hpp"
+
+#include <OgreLight.h>
+#include <OgreWindowEventUtilities.h>
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+DemoApp::DemoApp()
+{
+	
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+DemoApp::~DemoApp()
+{
+	StereoConfig_Write() ; // write out the stereo configuration.  Just rough for now, a binary file
+
+	
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+void DemoApp::startDemo()
+{
+	
+	
+	m_bShutdown = false;
+	
+	
+
+
+
+
+
+		new OgreFramework();
+
+		
+
+		OgreFramework::getSingletonPtr()->initOgre("Video Start", this, 0);
+		
+		BZNConfig_Read() ;
+
+		OgreFramework::getSingletonPtr()->AdditionalSetup() ;
+
+		if(!setupDemoScene()) return ; // failure setting up level
+		
+		
+		
+		//runDemo_Default();
+		runDemo_MethodA();
+
+		OgreFramework::getSingletonPtr()->UnloadMap(true) ;
+		//OgreFramework::getSingletonPtr()->OFBug.MessageInt(333) ;
+		//delete OgreFramework::getSingletonPtr(); // causes a crash on exit in 1.7, was ok in 1.6.3
+		//OgreFramework::getSingletonPtr()->
+		
+		OgreFramework::getSingletonPtr()->FinalShutdown() ;
+
+		
+		//OgreFramework::getSingletonPtr()->OFBug.MessageInt(333) ;
+
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+int DemoApp::setupDemoScene()
+{
+	return OgreFramework::getSingletonPtr()->LoadMap() ;
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
+// four different versions of runDemo() depending on method of GPUBuffer flushing.
+
+int DemoApp::runDemo_Default()
+{
+
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Start main loop (Default)...");
+
+//	char chMessage[1024] ;
+	
+	UINT uFrameStartTime=OgreFramework::getSingletonPtr()->m_pTimer->getMilliseconds();
+	UINT uFrameTotalTime=0 ;
+
+	OgreFramework::getSingletonPtr()->m_pRenderWnd->resetStatistics() ;
+	
+	
+
+
+
+	while(!m_bShutdown && !OgreFramework::getSingletonPtr()->isOgreToBeShutDown()) 
+	{
+
+
+
+
+		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isClosed())m_bShutdown = true;
+
+#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+			Ogre::WindowEventUtilities::messagePump() ;
+#endif	
+
+
+
+
+		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isActive())
+		{
+
+
+         // get start time of frame
+         uFrameStartTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds() ;
+            
+         // update input and physics
+         OgreFramework::getSingletonPtr()->m_pKeyboard->capture();
+         OgreFramework::getSingletonPtr()->m_pMouse->capture();
+         OgreFramework::getSingletonPtr()->updateOgre(uFrameTotalTime/1000.0f);
+
+
+         // render the frame
+				 OgreFramework::getSingletonPtr()->UpdateRenderTargets() ;
+
+
+
+				
+
+			// calculate frame time.
+			uFrameTotalTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds()-uFrameStartTime ;
+
+		}
+		else
+		{
+			Sleep(1000);
+		}
+
+
+	}
+
+
+
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Main loop quit (Default)");
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Shutdown OGRE...");
+
+
+	return 1 ;
+}
+
+int DemoApp::runDemo_MethodA()
+{
+
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Start main loop (MethodA)...");
+
+//	char chMessage[1024] ;
+	
+	UINT uFrameStartTime=OgreFramework::getSingletonPtr()->m_pTimer->getMilliseconds();
+	UINT uFrameTotalTime=0 ;
+
+	OgreFramework::getSingletonPtr()->m_pRenderWnd->resetStatistics() ;
+	
+	
+
+
+	/////////////////////////////////////////////////////////////////////////////////////////////
+	// use a renderQueueListener with 1 to 4 HardwareOcclusionQueries to prevent the CPU from 
+	// getting too far ahead of the GPU and causing input lag from keyboard and mouse.
+	// thanks to Sinbad for this suggestion and code outline.
+	// We aren't actually doing Hardware Occlusion Culling, just exploiting the way we can
+	// make it flush the GPU buffer for prior frames.
+	// Messing with the GPU command buffer can be turned off completely by seting m_nMaxGPUQuery to 0 
+
+	
+	// get the maximum gpu queries to be used.  
+	int nMaxGPUQuery=OgreFramework::getSingletonPtr()->m_nMaxGPUQuery ;
+	unsigned int dummy=0 ;
+	int nNewQuery=0 ;
+	int nOldQuery=0 ;
+	rQueueListener* rqListener=NULL ;
+	Ogre::HardwareOcclusionQuery** pHOQ=NULL ;
+
+	int nQueryReady[MAXGPUQUERY] ;
+		
+
+	if(nMaxGPUQuery!=0) // if querying is turned on
+	{
+		// make sure it is in range.
+		if(nMaxGPUQuery<1) 
+			nMaxGPUQuery=1 ;
+		else
+			if(nMaxGPUQuery>MAXGPUQUERY) 
+			nMaxGPUQuery=MAXGPUQUERY ;
+
+
+		rqListener = new rQueueListener ;
+		
+		OgreFramework::getSingletonPtr()->m_pSceneMgr->addRenderQueueListener(rqListener) ;
+
+		// create our queries
+		pHOQ=rqListener->Query ;
+		for(nNewQuery=0 ; nNewQuery<nMaxGPUQuery ; nNewQuery++)
+			pHOQ[nNewQuery] = OgreFramework::getSingletonPtr()->m_pRoot->getRenderSystem()->createHardwareOcclusionQuery() ;
+
+		nNewQuery=nOldQuery-1 ;
+		if(nNewQuery<0)
+			nNewQuery+=nMaxGPUQuery ;
+
+		// set the queries to not ready
+		for(int nReadyLoop=0 ; nReadyLoop<MAXGPUQUERY ; nReadyLoop++)
+			nQueryReady[nReadyLoop]=0 ;
+	}
+	//
+	/////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+	while(!m_bShutdown && !OgreFramework::getSingletonPtr()->isOgreToBeShutDown()) 
+	{
+
+
+
+
+		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isClosed())m_bShutdown = true;
+
+#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+			Ogre::WindowEventUtilities::messagePump() ;
+#endif	
+
+
+			//OgreFramework::getSingletonPtr()->m_pLog->logMessage("Update START");
+
+
+		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isActive())
+		{
+
+			// get start time of frame
+			uFrameStartTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds() ;
+				
+			// update input and physics
+			OgreFramework::getSingletonPtr()->m_pKeyboard->capture();
+			OgreFramework::getSingletonPtr()->m_pMouse->capture();
+			OgreFramework::getSingletonPtr()->updateOgre(uFrameTotalTime/1000.0f);
+
+			
+			if(nMaxGPUQuery==0) // querying the GPU command buffer is disabled
+			{
+				// render the frame
+				OgreFramework::getSingletonPtr()->UpdateRenderTargets() ;
+			}
+			else								// querying the GPU command buffer is enabled
+			{
+				// increment the buffer.  
+				nNewQuery=nOldQuery ;
+				nOldQuery++ ;
+				if(nOldQuery==nMaxGPUQuery)
+					nOldQuery=0 ;
+
+
+				// define query beginning for this frame
+				pHOQ[ nNewQuery ]->beginOcclusionQuery() ;
+
+				// render the frame
+				//OgreFramework::getSingletonPtr()->m_pRoot->renderOneFrame();
+				OgreFramework::getSingletonPtr()->UpdateRenderTargets() ;
+
+				// define query end for this frame
+				pHOQ[ nNewQuery ]->endOcclusionQuery() ;
+				nQueryReady[ nNewQuery ]=1 ;
+			
+
+
+				// pull query for a prior frame.  Flushes GPU command buffer up to the end of a prior frame but no further.
+				if(nQueryReady[ nOldQuery ])
+				{
+					pHOQ[ nOldQuery ]->pullOcclusionQuery(&dummy) ;
+					nQueryReady[ nOldQuery ]=0 ;
+				}
+			}
+			
+
+
+			// calculate frame time.
+			uFrameTotalTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds()-uFrameStartTime ;
+
+		}
+		else
+		{
+			Sleep(1000);
+		}
+
+
+	}
+
+	if(nMaxGPUQuery>0) // if necessary, clean up our HOQ queries and renderQueueListener
+	{
+	
+		for(nNewQuery=0 ; nNewQuery<nMaxGPUQuery ; nNewQuery++)
+			OgreFramework::getSingletonPtr()->m_pRoot->getRenderSystem()->destroyHardwareOcclusionQuery( pHOQ[nNewQuery] ) ;
+		
+		OgreFramework::getSingletonPtr()->m_pSceneMgr->removeRenderQueueListener(rqListener) ;
+		delete rqListener ;
+	}
+
+
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Main loop quit (MethodA)");
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Shutdown OGRE...");
+
+
+	return 1 ;
+}
+
+int DemoApp::runDemo_MethodB()
+{
+
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Start main loop (MethodB)...");
+
+//	char chMessage[1024] ;
+	
+	UINT uFrameStartTime=OgreFramework::getSingletonPtr()->m_pTimer->getMilliseconds();
+	UINT uFrameTotalTime=0 ;
+
+	OgreFramework::getSingletonPtr()->m_pRenderWnd->resetStatistics() ;
+	
+
+	
+	int numberOfQueuedFrames=1 ;
+	bool GPUBufferSetupDone=false ;
+
+
+	while(!m_bShutdown && !OgreFramework::getSingletonPtr()->isOgreToBeShutDown()) 
+	{
+
+
+
+
+		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isClosed())m_bShutdown = true;
+
+#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+			Ogre::WindowEventUtilities::messagePump() ;
+#endif	
+
+
+		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isActive())
+		{
+
+
+			   if(GPUBufferSetupDone==false) // I added it here because I assume I can be very sure there's an active render window by now.
+         {
+            GPUBufferSetupDone=true ;
+            mBufferFlush.start(numberOfQueuedFrames);
+         }
+
+         // get start time of frame
+         uFrameStartTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds() ;
+            
+         // update input and physics
+         OgreFramework::getSingletonPtr()->m_pKeyboard->capture();
+         OgreFramework::getSingletonPtr()->m_pMouse->capture();
+         OgreFramework::getSingletonPtr()->updateOgre(uFrameTotalTime/1000.0f);
+
+
+         // render the frame
+				 OgreFramework::getSingletonPtr()->UpdateRenderTargets() ;
+
+
+
+
+			// calculate frame time.
+			uFrameTotalTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds()-uFrameStartTime ;
+
+		}
+		else
+		{
+			Sleep(1000);
+		}
+
+
+
+	}
+
+
+	mBufferFlush.stop() ;
+
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Main loop quit (MethodB)");
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Shutdown OGRE...");
+
+
+	return 1 ;
+}
+
+
+int DemoApp::runDemo_MethodC()
+{
+
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Start main loop (MethodC)...");
+
+	char chMessage[1024] ;
+	
+	int uFrameStartTime=OgreFramework::getSingletonPtr()->m_pTimer->getMilliseconds();
+	int uFrameRenderTime=0 ;
+	int uFrameTargetTime=10000 ;
+
+	OgreFramework::getSingletonPtr()->m_pRenderWnd->resetStatistics() ;
+	
+	
+
+	int uSleepTime=0 ;
+
+	while(!m_bShutdown && !OgreFramework::getSingletonPtr()->isOgreToBeShutDown()) 
+	{
+
+
+
+
+		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isClosed())m_bShutdown = true;
+
+#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+			Ogre::WindowEventUtilities::messagePump() ;
+#endif	
+
+
+
+
+		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isActive())
+		{
+
+
+       // get start time of frame
+       uFrameStartTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds() ;
+            
+         // update input and physics
+         OgreFramework::getSingletonPtr()->m_pKeyboard->capture();
+         OgreFramework::getSingletonPtr()->m_pMouse->capture();
+         OgreFramework::getSingletonPtr()->updateOgre(uFrameTargetTime/1000.0f);
+
+
+         // render the frame
+				 OgreFramework::getSingletonPtr()->UpdateRenderTargets() ;
+
+
+			// calculate frame time.
+			uFrameRenderTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds()-uFrameStartTime ;
+			
+
+			uFrameTargetTime-=1000 ;
+			if(uFrameTargetTime<0) uFrameTargetTime=0 ;
+
+			if(uFrameRenderTime>uFrameTargetTime-10000)
+				uFrameTargetTime=uFrameRenderTime+20000 ;
+
+			if(uFrameTargetTime>100000) uFrameTargetTime=100000 ;
+
+
+			
+
+
+			uSleepTime=(int)((uFrameTargetTime-uFrameRenderTime)/1000.0f) ;
+			if(uSleepTime>0) Sleep(uSleepTime) ;
+
+			sprintf(chMessage, "render %i, target %i, sleep %i", uFrameRenderTime, uFrameTargetTime, uSleepTime) ;
+			OgreFramework::getSingletonPtr()->m_pLog->logMessage(chMessage);
+
+		}
+		else
+		{
+			Sleep(1000);
+		}
+
+
+	}
+
+
+
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Main loop quit (MethodC)");
+	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Shutdown OGRE...");
+
+
+	return 1 ;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+void DemoApp::ResetSectionTimer()
+{
+	m_uLastTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds() ;
+}
+
+UINT DemoApp::GetSectionTimer()
+{
+	UINT uThisTime=OgreFramework::getSingletonPtr()->m_pTimer->getMicroseconds() ;
+	UINT uSectionTime=uThisTime-m_uLastTime ;
+	m_uLastTime=uThisTime ;
+	return uSectionTime ;
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+
+bool DemoApp::keyPressed(const OIS::KeyEvent &keyEventRef)
+{
+	
+	OgreFramework::getSingletonPtr()->keyPressed(keyEventRef);
+	
+	if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_F))
+	{
+		 //do something
+	}
+	
+	return true;
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+bool DemoApp::keyReleased(const OIS::KeyEvent &keyEventRef)
+{
+	OgreFramework::getSingletonPtr()->keyReleased(keyEventRef);
+	
+	return true;
+}
+
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+void DemoApp::StereoConfig_Write( void )
+{
+	int fh;
+	if( (fh = _open( "stereoscopic.cfg", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, 
+                               _S_IREAD | _S_IWRITE )) != -1 )
+	{
+		write( fh, (void*)&OgreFramework::getSingletonPtr()->m_nGoggleMode,						sizeof(int)) ;
+		write( fh, (void*)&OgreFramework::getSingletonPtr()->m_flGoggleZPos,					sizeof(float))	;
+		write( fh, (void*)&OgreFramework::getSingletonPtr()->m_flGoggleXGap,					sizeof(float))	;
+		write( fh, (void*)&OgreFramework::getSingletonPtr()->m_flGoggleXScale,				sizeof(float))	;
+		write( fh, (void*)&OgreFramework::getSingletonPtr()->m_flGoggleYScale,				sizeof(float))	;
+		_close( fh );
+	}
+}
+bool DemoApp::StereoConfig_Read(void)
+{
+ 	int fh;
+	bool found_file=true ;
+
+	// Open file for input
+	if( (fh = _open( "stereoscopic.cfg", _O_RDONLY | _O_BINARY )) == -1 )
+	{
+		found_file=false ;
+	}
+	else
+	{
+		read( fh, (void*)&OgreFramework::getSingletonPtr()->m_nGoggleMode,						sizeof(int)) ;
+		read( fh, (void*)&OgreFramework::getSingletonPtr()->m_flGoggleZPos,						sizeof(float))	;
+		read( fh, (void*)&OgreFramework::getSingletonPtr()->m_flGoggleXGap,						sizeof(float))	;
+		read( fh, (void*)&OgreFramework::getSingletonPtr()->m_flGoggleXScale,					sizeof(float))	;
+		read( fh, (void*)&OgreFramework::getSingletonPtr()->m_flGoggleYScale,					sizeof(float))	;
+		_close( fh );
+	 }//  end if else
+	return found_file ;
+}
+
+
+void DemoApp::BZNConfig_Write(void)
+{
+	int fh;
+	if( (fh = _open( "bzn.cfg", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, 
+                               _S_IREAD | _S_IWRITE )) != -1 )
+	{
+		write( fh, (void*)OgreFramework::getSingletonPtr()->m_chBZNConfig,						BZN_CONFIG_SIZE) ;
+		_close( fh );
+	}
+}
+
+bool DemoApp::BZNConfig_Read(void)
+{
+
+	int fh;
+	bool found_file=true ;
+
+	// make sure the config memory is blank
+	ZeroMemory((void*)OgreFramework::getSingletonPtr()->m_chBZNConfig, BZN_CONFIG_SIZE) ;
+
+	// Open file for input
+	if( (fh = _open( "bzn.cfg", _O_RDONLY | _O_BINARY )) == -1 )
+	{
+		found_file=false ;
+	}
+	else
+	{
+		read( fh, (void*)OgreFramework::getSingletonPtr()->m_chBZNConfig,						BZN_CONFIG_SIZE) ;
+		_close( fh );
+		OgreFramework::getSingletonPtr()->ParseBZNConfig() ;
+	 }//  end if else
+	
+	
+	return found_file ;
+
+}
Index: code/trunk/src/libraries/tools/bsp/DemoApp.hpp
===================================================================
--- code/trunk/src/libraries/tools/bsp/DemoApp.hpp	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/DemoApp.hpp	(revision 7163)
@@ -0,0 +1,57 @@
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+#ifndef OGRE_DEMO_HPP
+#define OGRE_DEMO_HPP
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+#include "OgreFramework.hpp"
+
+// for loading/saving the stereo config file
+#include <io.h>
+#include <fcntl.h>      /* Needed only for _O_RDWR definition */
+#include <sys/stat.h>
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+class DemoApp : public OIS::KeyListener
+{
+public:
+	DemoApp();
+	~DemoApp();
+
+	void startDemo();
+	
+	bool keyPressed(const OIS::KeyEvent &keyEventRef);
+	bool keyReleased(const OIS::KeyEvent &keyEventRef);
+
+private:
+	int setupDemoScene();
+	int runDemo_Default(); // no gpu buffer flushing code
+	int runDemo_MethodA(); // my HOQ gpu buffer flushing code
+	int runDemo_MethodB(); // ogre HOQ gpu buffer flushing code
+	int runDemo_MethodC(); // my blit gpu buffer flushing code
+
+	UINT m_uLastTime ;
+	void ResetSectionTimer() ;
+	UINT GetSectionTimer() ;
+
+
+	void StereoConfig_Write( void ) ;
+	bool StereoConfig_Read(void) ;
+
+	void BZNConfig_Write(void) ;
+	bool BZNConfig_Read(void) ;
+
+	
+
+	Ogre::GpuCommandBufferFlush mBufferFlush;
+
+	bool						m_bShutdown;
+};
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+#endif 
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
Index: code/trunk/src/libraries/tools/bsp/ExampleApplication.h
===================================================================
--- code/trunk/src/libraries/tools/bsp/ExampleApplication.h	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/ExampleApplication.h	(revision 7163)
@@ -0,0 +1,257 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+(Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2006 Torus Knot Software Ltd
+Also see acknowledgements in Readme.html
+
+You may use this sample code for anything you like, it is not covered by the
+LGPL like the rest of the engine.
+-----------------------------------------------------------------------------
+*/
+/*
+-----------------------------------------------------------------------------
+Filename:    ExampleApplication.h
+Description: Base class for all the OGRE examples
+-----------------------------------------------------------------------------
+*/
+
+#ifndef __ExampleApplication_H__
+#define __ExampleApplication_H__
+
+#include "Ogre.h"
+#include "OgreConfigFile.h"
+#include "ExampleFrameListener.h"
+
+#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
+#include <CoreFoundation/CoreFoundation.h>
+
+// This function will locate the path to our application on OS X,
+// unlike windows you can not rely on the curent working directory
+// for locating your configuration files and resources.
+std::string macBundlePath()
+{
+    char path[1024];
+    CFBundleRef mainBundle = CFBundleGetMainBundle();
+    assert(mainBundle);
+
+    CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);
+    assert(mainBundleURL);
+
+    CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle);
+    assert(cfStringRef);
+
+    CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);
+
+    CFRelease(mainBundleURL);
+    CFRelease(cfStringRef);
+
+    return std::string(path);
+}
+#endif
+
+using namespace Ogre;
+
+/** Base class which manages the standard startup of an Ogre application.
+    Designed to be subclassed for specific examples if required.
+*/
+class ExampleApplication
+{
+public:
+    /// Standard constructor
+    ExampleApplication()
+    {
+        mFrameListener = 0;
+        mRoot = 0;
+		// Provide a nice cross platform solution for locating the configuration files
+		// On windows files are searched for in the current working directory, on OS X however
+		// you must provide the full path, the helper function macBundlePath does this for us.
+#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
+		mResourcePath = macBundlePath() + "/Contents/Resources/";
+#else
+		mResourcePath = "";
+#endif
+    }
+    /// Standard destructor
+    virtual ~ExampleApplication()
+    {
+        if (mFrameListener)
+            delete mFrameListener;
+        if (mRoot)
+            OGRE_DELETE mRoot;
+    }
+
+    /// Start the example
+    virtual void go(void)
+    {
+        if (!setup())
+            return;
+
+        mRoot->startRendering();
+
+        // clean up
+        destroyScene();
+    }
+
+protected:
+    Root *mRoot;
+    Camera* mCamera;
+    SceneManager* mSceneMgr;
+    ExampleFrameListener* mFrameListener;
+    RenderWindow* mWindow;
+	Ogre::String mResourcePath;
+
+    // These internal methods package up the stages in the startup process
+    /** Sets up the application - returns false if the user chooses to abandon configuration. */
+    virtual bool setup(void)
+    {
+
+		String pluginsPath;
+		// only use plugins.cfg if not static
+#ifndef OGRE_STATIC_LIB
+		pluginsPath = mResourcePath + "plugins.cfg";
+#endif
+		
+        mRoot = OGRE_NEW Root(pluginsPath, 
+            mResourcePath + "ogre.cfg", mResourcePath + "Ogre.log");
+
+        setupResources();
+
+        bool carryOn = configure();
+        if (!carryOn) return false;
+
+        chooseSceneManager();
+        createCamera();
+        createViewports();
+
+        // Set default mipmap level (NB some APIs ignore this)
+        TextureManager::getSingleton().setDefaultNumMipmaps(5);
+
+		// Create any resource listeners (for loading screens)
+		createResourceListener();
+		// Load resources
+		loadResources();
+
+		// Create the scene
+        createScene();
+
+        createFrameListener();
+
+        return true;
+
+    }
+    /** Configures the application - returns false if the user chooses to abandon configuration. */
+    virtual bool configure(void)
+    {
+        // Show the configuration dialog and initialise the system
+        // You can skip this and use root.restoreConfig() to load configuration
+        // settings if you were sure there are valid ones saved in ogre.cfg
+        if(mRoot->showConfigDialog())
+        {
+            // If returned true, user clicked OK so initialise
+            // Here we choose to let the system create a default rendering window by passing 'true'
+            mWindow = mRoot->initialise(true);
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    virtual void chooseSceneManager(void)
+    {
+        // Create the SceneManager, in this case a generic one
+        mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "ExampleSMInstance");
+    }
+    virtual void createCamera(void)
+    {
+        // Create the camera
+        mCamera = mSceneMgr->createCamera("PlayerCam");
+
+        // Position it at 500 in Z direction
+        mCamera->setPosition(Vector3(0,0,500));
+        // Look back along -Z
+        mCamera->lookAt(Vector3(0,0,-300));
+        mCamera->setNearClipDistance(5);
+
+    }
+    virtual void createFrameListener(void)
+    {
+        mFrameListener= new ExampleFrameListener(mWindow, mCamera);
+        mFrameListener->showDebugOverlay(true);
+        mRoot->addFrameListener(mFrameListener);
+    }
+
+    virtual void createScene(void) = 0;    // pure virtual - this has to be overridden
+
+    virtual void destroyScene(void){}    // Optional to override this
+
+    virtual void createViewports(void)
+    {
+        // Create one viewport, entire window
+        Viewport* vp = mWindow->addViewport(mCamera);
+        vp->setBackgroundColour(ColourValue(0,0,0));
+
+        // Alter the camera aspect ratio to match the viewport
+        mCamera->setAspectRatio(
+            Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
+    }
+
+    /// Method which will define the source of resources (other than current folder)
+    virtual void setupResources(void)
+    {
+        // Load resource paths from config file
+        ConfigFile cf;
+        cf.load(mResourcePath + "resources.cfg");
+
+        // Go through all sections & settings in the file
+        ConfigFile::SectionIterator seci = cf.getSectionIterator();
+
+        String secName, typeName, archName;
+        while (seci.hasMoreElements())
+        {
+            secName = seci.peekNextKey();
+            ConfigFile::SettingsMultiMap *settings = seci.getNext();
+            ConfigFile::SettingsMultiMap::iterator i;
+            for (i = settings->begin(); i != settings->end(); ++i)
+            {
+                typeName = i->first;
+                archName = i->second;
+#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
+                // OS X does not set the working directory relative to the app,
+                // In order to make things portable on OS X we need to provide
+                // the loading with it's own bundle path location
+                ResourceGroupManager::getSingleton().addResourceLocation(
+                    String(macBundlePath() + "/" + archName), typeName, secName);
+#else
+                ResourceGroupManager::getSingleton().addResourceLocation(
+                    archName, typeName, secName);
+#endif
+            }
+        }
+    }
+
+	/// Optional override method where you can create resource listeners (e.g. for loading screens)
+	virtual void createResourceListener(void)
+	{
+
+	}
+
+	/// Optional override method where you can perform resource group loading
+	/// Must at least do ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
+	virtual void loadResources(void)
+	{
+		// Initialise, parse scripts etc
+		ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
+
+	}
+
+
+
+};
+
+
+#endif
Index: code/trunk/src/libraries/tools/bsp/ExampleFrameListener.h
===================================================================
--- code/trunk/src/libraries/tools/bsp/ExampleFrameListener.h	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/ExampleFrameListener.h	(revision 7163)
@@ -0,0 +1,419 @@
+/*
+-----------------------------------------------------------------------------
+This source file is part of OGRE
+    (Object-oriented Graphics Rendering Engine)
+For the latest info, see http://www.ogre3d.org/
+
+Copyright (c) 2000-2006 Torus Knot Software Ltd
+Also see acknowledgements in Readme.html
+
+You may use this sample code for anything you like, it is not covered by the
+LGPL like the rest of the engine.
+-----------------------------------------------------------------------------
+*/
+/*
+-----------------------------------------------------------------------------
+Filename:    ExampleFrameListener.h
+Description: Defines an example frame listener which responds to frame events.
+This frame listener just moves a specified camera around based on
+keyboard and mouse movements.
+Mouse:    Freelook
+W or Up:  Forward
+S or Down:Backward
+A:        Step left
+D:        Step right
+             PgUp:     Move upwards
+             PgDown:   Move downwards
+             F:        Toggle frame rate stats on/off
+			 R:        Render mode
+             T:        Cycle texture filtering
+                       Bilinear, Trilinear, Anisotropic(8)
+             P:        Toggle on/off display of camera position / orientation
+-----------------------------------------------------------------------------
+*/
+
+#ifndef __ExampleFrameListener_H__
+#define __ExampleFrameListener_H__
+
+#include "Ogre.h"
+#include "OgreStringConverter.h"
+#include "OgreException.h"
+
+//Use this define to signify OIS will be used as a DLL
+//(so that dll import/export macros are in effect)
+#ifndef OIS_DYNAMIC_LIB
+#  define OIS_DYNAMIC_LIB
+#endif
+#include <OIS/OIS.h>
+
+using namespace Ogre;
+
+class ExampleFrameListener: public FrameListener, public WindowEventListener
+{
+protected:
+	virtual void updateStats(void)
+	{
+		static String currFps = "Current FPS: ";
+		static String avgFps = "Average FPS: ";
+		static String bestFps = "Best FPS: ";
+		static String worstFps = "Worst FPS: ";
+		static String tris = "Triangle Count: ";
+		static String batches = "Batch Count: ";
+
+		// update stats when necessary
+		try {
+			OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
+			OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
+			OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
+			OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");
+
+			const RenderTarget::FrameStats& stats = mWindow->getStatistics();
+			guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
+			guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));
+			guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)
+				+" "+StringConverter::toString(stats.bestFrameTime)+" ms");
+			guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)
+				+" "+StringConverter::toString(stats.worstFrameTime)+" ms");
+
+			OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
+			guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));
+
+			OverlayElement* guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches");
+			guiBatches->setCaption(batches + StringConverter::toString(stats.batchCount));
+
+			OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
+			guiDbg->setCaption(mDebugText);
+		}
+		catch(...) { /* ignore */ }
+	}
+
+public:
+	// Constructor takes a RenderWindow because it uses that to determine input context
+	ExampleFrameListener(RenderWindow* win, Camera* cam, bool bufferedKeys = false, bool bufferedMouse = false,
+			     bool bufferedJoy = false ) :
+		mCamera(cam), mTranslateVector(Vector3::ZERO), mCurrentSpeed(0), mWindow(win), mStatsOn(true), mNumScreenShots(0),
+		mMoveScale(0.0f), mRotScale(0.0f), mTimeUntilNextToggle(0), mFiltering(TFO_BILINEAR),
+		mAniso(1), mSceneDetailIndex(0), mMoveSpeed(100), mRotateSpeed(36), mDebugOverlay(0),
+		mInputManager(0), mMouse(0), mKeyboard(0), mJoy(0)
+	{
+
+		mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
+
+		LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
+		OIS::ParamList pl;
+		size_t windowHnd = 0;
+		std::ostringstream windowHndStr;
+
+		win->getCustomAttribute("WINDOW", &windowHnd);
+		windowHndStr << windowHnd;
+		pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
+
+		mInputManager = OIS::InputManager::createInputSystem( pl );
+
+		//Create all devices (We only catch joystick exceptions here, as, most people have Key/Mouse)
+		mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, bufferedKeys ));
+		mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, bufferedMouse ));
+		try {
+			mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject( OIS::OISJoyStick, bufferedJoy ));
+		}
+		catch(...) {
+			mJoy = 0;
+		}
+
+		//Set initial mouse clipping size
+		windowResized(mWindow);
+
+		showDebugOverlay(true);
+
+		//Register as a Window listener
+		WindowEventUtilities::addWindowEventListener(mWindow, this);
+	}
+
+	//Adjust mouse clipping area
+	virtual void windowResized(RenderWindow* rw)
+	{
+		unsigned int width, height, depth;
+		int left, top;
+		rw->getMetrics(width, height, depth, left, top);
+
+		const OIS::MouseState &ms = mMouse->getMouseState();
+		ms.width = width;
+		ms.height = height;
+	}
+
+	//Unattach OIS before window shutdown (very important under Linux)
+	virtual void windowClosed(RenderWindow* rw)
+	{
+		//Only close for window that created OIS (the main window in these demos)
+		if( rw == mWindow )
+		{
+			if( mInputManager )
+			{
+				mInputManager->destroyInputObject( mMouse );
+				mInputManager->destroyInputObject( mKeyboard );
+				mInputManager->destroyInputObject( mJoy );
+
+				OIS::InputManager::destroyInputSystem(mInputManager);
+				mInputManager = 0;
+			}
+		}
+	}
+
+	virtual ~ExampleFrameListener()
+	{
+		//Remove ourself as a Window listener
+		WindowEventUtilities::removeWindowEventListener(mWindow, this);
+		windowClosed(mWindow);
+	}
+
+	virtual bool processUnbufferedKeyInput(const FrameEvent& evt)
+	{
+
+		if(mKeyboard->isKeyDown(OIS::KC_A))
+			mTranslateVector.x = -mMoveScale;	// Move camera left
+
+		if(mKeyboard->isKeyDown(OIS::KC_D))
+			mTranslateVector.x = mMoveScale;	// Move camera RIGHT
+
+		if(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )
+			mTranslateVector.z = -mMoveScale;	// Move camera forward
+
+		if(mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S) )
+			mTranslateVector.z = mMoveScale;	// Move camera backward
+
+		if(mKeyboard->isKeyDown(OIS::KC_PGUP))
+			mTranslateVector.y = mMoveScale;	// Move camera up
+
+		if(mKeyboard->isKeyDown(OIS::KC_PGDOWN))
+			mTranslateVector.y = -mMoveScale;	// Move camera down
+
+		if(mKeyboard->isKeyDown(OIS::KC_RIGHT))
+			mCamera->yaw(-mRotScale);
+
+		if(mKeyboard->isKeyDown(OIS::KC_LEFT))
+			mCamera->yaw(mRotScale);
+
+		if( mKeyboard->isKeyDown(OIS::KC_ESCAPE) || mKeyboard->isKeyDown(OIS::KC_Q) )
+			return false;
+
+       	if( mKeyboard->isKeyDown(OIS::KC_F) && mTimeUntilNextToggle <= 0 )
+		{
+			mStatsOn = !mStatsOn;
+			showDebugOverlay(mStatsOn);
+			mTimeUntilNextToggle = 1;
+		}
+
+		if( mKeyboard->isKeyDown(OIS::KC_T) && mTimeUntilNextToggle <= 0 )
+		{
+			switch(mFiltering)
+			{
+			case TFO_BILINEAR:
+				mFiltering = TFO_TRILINEAR;
+				mAniso = 1;
+				break;
+			case TFO_TRILINEAR:
+				mFiltering = TFO_ANISOTROPIC;
+				mAniso = 8;
+				break;
+			case TFO_ANISOTROPIC:
+				mFiltering = TFO_BILINEAR;
+				mAniso = 1;
+				break;
+			default: break;
+			}
+			MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
+			MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
+
+			showDebugOverlay(mStatsOn);
+			mTimeUntilNextToggle = 1;
+		}
+
+		if(mKeyboard->isKeyDown(OIS::KC_SYSRQ) && mTimeUntilNextToggle <= 0)
+		{
+			std::ostringstream ss;
+			ss << "screenshot_" << ++mNumScreenShots << ".png";
+			mWindow->writeContentsToFile(ss.str());
+			mTimeUntilNextToggle = 0.5;
+			mDebugText = "Saved: " + ss.str();
+		}
+
+		if(mKeyboard->isKeyDown(OIS::KC_R) && mTimeUntilNextToggle <=0)
+		{
+			mSceneDetailIndex = (mSceneDetailIndex+1)%3 ;
+			switch(mSceneDetailIndex) {
+				case 0 : mCamera->setPolygonMode(PM_SOLID); break;
+				case 1 : mCamera->setPolygonMode(PM_WIREFRAME); break;
+				case 2 : mCamera->setPolygonMode(PM_POINTS); break;
+			}
+			mTimeUntilNextToggle = 0.5;
+		}
+
+		static bool displayCameraDetails = false;
+		if(mKeyboard->isKeyDown(OIS::KC_P) && mTimeUntilNextToggle <= 0)
+		{
+			displayCameraDetails = !displayCameraDetails;
+			mTimeUntilNextToggle = 0.5;
+			if (!displayCameraDetails)
+				mDebugText = "";
+		}
+
+		// Print camera details
+		if(displayCameraDetails)
+			mDebugText = "P: " + StringConverter::toString(mCamera->getDerivedPosition()) +
+						 " " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation());
+
+		// Return true to continue rendering
+		return true;
+	}
+
+	virtual bool processUnbufferedMouseInput(const FrameEvent& evt)
+	{
+
+		// Rotation factors, may not be used if the second mouse button is pressed
+		// 2nd mouse button - slide, otherwise rotate
+		const OIS::MouseState &ms = mMouse->getMouseState();
+		if( ms.buttonDown( OIS::MB_Right ) )
+		{
+			mTranslateVector.x += ms.X.rel * 0.13;
+			mTranslateVector.y -= ms.Y.rel * 0.13;
+		}
+		else
+		{
+			mRotX = Degree(-ms.X.rel * 0.13);
+			mRotY = Degree(-ms.Y.rel * 0.13);
+		}
+
+		return true;
+	}
+
+	virtual void moveCamera()
+	{
+		// Make all the changes to the camera
+		// Note that YAW direction is around a fixed axis (freelook style) rather than a natural YAW
+		//(e.g. airplane)
+		mCamera->yaw(mRotX);
+		mCamera->pitch(mRotY);
+		mCamera->moveRelative(mTranslateVector);
+	}
+
+	virtual void showDebugOverlay(bool show)
+	{
+		if (mDebugOverlay)
+		{
+			if (show)
+				mDebugOverlay->show();
+			else
+				mDebugOverlay->hide();
+		}
+	}
+
+	// Override frameRenderingQueued event to process that (don't care about frameEnded)
+	bool frameRenderingQueued(const FrameEvent& evt)
+	{
+
+		if(mWindow->isClosed())	return false;
+
+		mSpeedLimit = mMoveScale * evt.timeSinceLastFrame;
+
+		//Need to capture/update each device
+		mKeyboard->capture();
+		mMouse->capture();
+		if( mJoy ) mJoy->capture();
+
+		bool buffJ = (mJoy) ? mJoy->buffered() : true;
+
+    	Ogre::Vector3 lastMotion = mTranslateVector;
+
+		//Check if one of the devices is not buffered
+		if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )
+		{
+			// one of the input modes is immediate, so setup what is needed for immediate movement
+			if (mTimeUntilNextToggle >= 0)
+				mTimeUntilNextToggle -= evt.timeSinceLastFrame;
+
+			// Move about 100 units per second
+			mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
+			// Take about 10 seconds for full rotation
+			mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
+
+			mRotX = 0;
+			mRotY = 0;
+			mTranslateVector = Ogre::Vector3::ZERO;
+
+		}
+
+		//Check to see which device is not buffered, and handle it
+		if( !mKeyboard->buffered() )
+			if( processUnbufferedKeyInput(evt) == false )
+				return false;
+		if( !mMouse->buffered() )
+			if( processUnbufferedMouseInput(evt) == false )
+				return false;
+
+		// ramp up / ramp down speed
+    	if (mTranslateVector == Ogre::Vector3::ZERO)
+		{
+			// decay (one third speed)
+			mCurrentSpeed -= evt.timeSinceLastFrame * 0.3;
+			mTranslateVector = lastMotion;
+		}
+		else
+		{
+			// ramp up
+			mCurrentSpeed += evt.timeSinceLastFrame;
+
+		}
+		// Limit motion speed
+		if (mCurrentSpeed > 1.0)
+			mCurrentSpeed = 1.0;
+		if (mCurrentSpeed < 0.0)
+			mCurrentSpeed = 0.0;
+
+		mTranslateVector *= mCurrentSpeed;
+
+
+		if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )
+			moveCamera();
+
+		return true;
+	}
+
+	bool frameEnded(const FrameEvent& evt)
+	{
+		updateStats();
+		return true;
+	}
+
+protected:
+	Camera* mCamera;
+
+	Vector3 mTranslateVector;
+	Real mCurrentSpeed;
+	RenderWindow* mWindow;
+	bool mStatsOn;
+
+	std::string mDebugText;
+
+	unsigned int mNumScreenShots;
+	float mMoveScale;
+	float mSpeedLimit;
+	Degree mRotScale;
+	// just to stop toggles flipping too fast
+	Real mTimeUntilNextToggle ;
+	Radian mRotX, mRotY;
+	TextureFilterOptions mFiltering;
+	int mAniso;
+
+	int mSceneDetailIndex ;
+	Real mMoveSpeed;
+	Degree mRotateSpeed;
+	Overlay* mDebugOverlay;
+
+	//OIS Input devices
+	OIS::InputManager* mInputManager;
+	OIS::Mouse*    mMouse;
+	OIS::Keyboard* mKeyboard;
+	OIS::JoyStick* mJoy;
+};
+
+#endif
Index: code/trunk/src/libraries/tools/bsp/OgreFramework.cpp
===================================================================
--- code/trunk/src/libraries/tools/bsp/OgreFramework.cpp	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/OgreFramework.cpp	(revision 7163)
@@ -0,0 +1,7002 @@
+//|||||||||||||||||||||||||||||||||||||||||||||||
+/*
+===========================================================================
+Copyright (C) 2010 Jared Prince
+
+This file is part of bsp-renderer source code.
+
+bsp-renderer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+bsp-renderer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "OgreFramework.hpp"
+
+#include <io.h>
+#include <fcntl.h>      /* Needed only for _O_RDWR definition */
+#include <sys/stat.h>
+#include "Q3Map_misc.h"	// safe pointer deletes
+
+
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+using namespace Ogre;
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+template<> OgreFramework* Ogre::Singleton<class OgreFramework>::ms_Singleton = 0;
+
+
+
+OgreFramework::OgreFramework()
+{
+
+	m_nNewCount=0 ;
+	ZeroMemory((void*)m_nNewCheck, sizeof(m_nNewCheck)) ;
+
+	m_MoveSpeed			= 0.1;
+	m_RotateSpeed		= 0.3;
+
+	m_bShutDownOgre		= false;
+	m_iNumScreenShots	= 0;
+
+	m_pRoot				= 0;
+	m_pSceneMgr			= 0;
+	m_pRenderWnd		= 0;
+	m_pCamera			= 0;
+	m_pViewport			= 0;
+	m_pLog				= 0;
+	m_pTimer			= 0;
+
+	m_pInputMgr			= 0;
+	m_pKeyboard			= 0;
+	m_pMouse			= 0;
+
+	m_pDebugOverlay		= 0;
+	m_pInfoOverlay		= 0;
+
+	//mRawFileManager=NULL ; // pointer for text file resource handler
+	m_pRawBspFile=NULL ;
+	m_bRawBspFileIsLoaded=false ;
+
+	// pointers for q3map stuff
+	m_TempMem=NULL ;
+	m_Q3Map=NULL ;
+	
+
+	m_pZoneMO=NULL ;
+	m_pZoneMesh=NULL ;
+	m_pZoneEntity=NULL ;
+	m_pZoneEntityMaterialType=NULL ;
+
+	int nPTex=0 ;
+	for(nPTex=0 ; nPTex<MAX_PROJECTORTEX ; nPTex++)
+	{
+		m_pZoneEntityMaterial_Base[nPTex]=NULL ;
+		m_pZoneEntityMaterial_Fast[nPTex]=NULL ;
+	}
+
+	m_pZoneEntityMaterial_Black=NULL ;
+
+	m_pZoneEntityMaterial_DfShColour=NULL ;
+	m_pZoneEntityMaterial_Shadow=NULL ;
+	m_pZoneEntityMaterial_ShadeFront=NULL ;
+	m_pZoneEntityMaterial_ShadeBack=NULL ;
+	m_pZoneEntityMaterial_DfShPosition=NULL ;
+	m_pZoneEntityMaterial_DfShDiffuse=NULL ;
+	//m_pZoneEntityMaterial_DSNormal=NULL ;
+	m_pZoneEntityMaterial_DfShFuncTNB=NULL ;
+	m_pZoneEntityMaterial_DfShSpecular=NULL ;
+	m_pZoneEntityMaterial_DfShEmissive=NULL ;
+	//m_pZoneEntityMaterial_DfShData=NULL ;
+	m_pZoneEntityMaterial_DfShMix=NULL ;
+
+
+	/////////////////////////////////
+
+	m_nMaxEntity=0 ;
+	m_pEntityInfo=NULL ;
+	m_nMaxVisibleEntity=0 ;
+	m_pVisibleEntity=NULL ;
+	m_nMaxFrustumEntity=0 ;
+	m_pFrustumEntity=NULL ;
+
+
+	// debug light meshes
+	m_pLightMO=NULL ;
+	m_pPortalMO=NULL ;
+	m_pPortalNode=NULL ;
+
+	m_pCubeNode			= 0;
+	m_pCubeEntity		= 0;
+
+	nMap=2 ;
+	m_nLoadToggle=0 ;
+	m_nJumpToggle=0 ;
+	m_nJumpVal=-1 ;
+
+	
+
+
+
+	m_nDebugA=0 ;
+	m_nDebugB=0 ;
+	m_nDebugC=0 ;
+	m_nRecurseCount=0 ;
+
+
+	m_nDebugLightBox=0 ;
+	m_nZoneCullingActive=1 ;
+	
+	m_nPortalDebug=0 ;
+	m_nPortalToggle=0 ;
+	m_nPortalState=1 ;
+
+	m_nKeyDown_Shift=0 ;
+	m_nKeyDown_Ctrl=0 ;
+
+
+
+	m_flStereoFrustumTweak=0.0f ;
+
+	m_nGoggleMode=GOGGLE_MODE_OFF ;
+	m_pGoggleL=NULL ;
+	m_pGoggleR=NULL ;
+	m_pNodeGoggles=NULL ;
+
+	// default goggle settings
+	m_flGoggleZPos=-250 ;
+	m_flGoggleXGap=0.0 ;
+	m_flGoggleXScale=1.0 ;
+	m_flGoggleYScale=1.0 ;
+
+	m_nMapLoaded=0 ;
+
+	m_nTime=0 ;
+
+	
+
+	ZeroMemory((void*)m_nFrameTime, sizeof(m_nFrameTime)) ;
+	m_nFrame=0 ;
+	m_nGotInput=0 ;
+
+	ZeroMemory((void*)m_nKeyToggle, sizeof(m_nKeyToggle)) ;
+
+//	OFBug.LogInit() ;
+
+	m_nRTTAssetsExist=0 ;
+	
+	m_nToggle=0 ;
+	
+	m_nFlashLight=0 ;
+
+
+
+	m_flAspectRatio=1.0f ;
+	m_flFOV=60.0f ;
+
+	// whether we are drawing the render or one of the info screens, such as wireframe or one of the deferred screens
+	m_nDisplayInfoMode=0 ;
+
+	m_nSpeedRender=0 ;
+
+	//m_nRenderHDR=0 ;
+
+	srand( (unsigned)time( NULL ) );
+
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+OgreFramework::~OgreFramework()
+{
+//	OFBug.LogSave("OFBug.txt") ;
+
+	/*
+	char chMessage[1024] ;
+	int nFrame=0 ;
+	m_pLog->logMessage("   ");
+	m_pLog->logMessage("   Mircosecs:   Physics    Render    Ideal   Average    Pragma     Total");
+	m_pLog->logMessage("   ----------------------------------------");
+	for(nFrame=0 ; nFrame<MAXFRAME ; nFrame++)
+	{
+		//sprintf(chMessage, "   Frame %3i:  %8i  %8i  %8i", nFrame, m_nFrameTime[nFrame][0], m_nFrameTime[nFrame][1], m_nFrameTime[nFrame][2]) ;
+		sprintf(chMessage, "  Frame %3i:  %8i  %8i  %8i  %8i  %8i  %8i", nFrame, m_nFrameTime[nFrame][0], m_nFrameTime[nFrame][1], m_nFrameTime[nFrame][2], m_nFrameTime[nFrame][3], m_nFrameTime[nFrame][4], m_nFrameTime[nFrame][5]) ;
+		m_pLog->logMessage(chMessage);
+	}
+	m_pLog->logMessage("");
+	*/
+
+	//UnloadMap(true) ;
+
+
+	//mRawFileManager->~RawFileManager() ; //!! is this correct?  
+	//DELETE_POINTER( mRawFileManager ) ;
+
+
+	DELETE_POINTER( m_pKeyboard );
+	DELETE_POINTER( m_pMouse );
+	OIS::InputManager::destroyInputSystem(m_pInputMgr);
+
+	
+	//DELETE_POINTER( m_pRoot );
+	//delete m_pRoot ;
+}
+
+
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+void OgreFramework::initOgre(Ogre::String wndTitle, OIS::KeyListener *pKeyListener, OIS::MouseListener *pMouseListener)
+{
+//	Ogre::LogManager* logMgr = new Ogre::LogManager();
+	
+	m_pLog = Ogre::LogManager::getSingleton().createLog("OgreLogfile.log", true, true, false);
+	m_pLog->setDebugOutputEnabled(true);
+	
+	m_pRoot = new Ogre::Root();
+
+	// our manager for the raw bsp
+	//mRawFileManager = new RawFileManager();
+	//ResourceGroupManager::getSingleton().createResourceGroup("Raw Bsp") ;
+
+	
+
+
+	m_pRoot->showConfigDialog();
+
+	if (!m_pRoot->restoreConfig() && !m_pRoot->showConfigDialog())
+	{
+		throw Exception(52, "User canceled the config dialog!", "Application::setupRenderSystem()");
+	}
+
+	
+	m_pRenderWnd = m_pRoot->initialise(true, wndTitle);
+
+	m_pSceneMgr = m_pRoot->createSceneManager(ST_GENERIC, "SceneManager");
+	m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.0, 0.0, 0.0));
+
+
+	m_pCamera = m_pSceneMgr->createCamera("Camera");
+	m_pCamera->setPosition(Vector3(0, 0, 0));
+	m_pCamera->lookAt(Vector3(0,0,0));
+	m_pCamera->setNearClipDistance(NEARCLIP);
+  m_pCamera->setFarClipDistance(FARCLIP);
+	m_pCamera->setFOVy( Degree(m_flFOV) ) ;
+
+	m_pCameraCopy = m_pSceneMgr->createCamera("CameraCopy");
+	m_pCameraCopy->setNearClipDistance(NEARCLIP);
+  m_pCameraCopy->setFarClipDistance(FARCLIP);
+
+
+	
+	m_pCameraNoJitter = m_pSceneMgr->createCamera("CameraNoJitter");
+
+
+	
+	
+
+	m_pViewport = m_pRenderWnd->addViewport(m_pCamera);
+
+	m_pViewport->setBackgroundColour(ColourValue(0.5, 0.5, 0.5, 1.0));
+
+	m_flAspectRatio= (float)m_pViewport->getActualWidth() / (float)m_pViewport->getActualHeight() ;
+
+	m_flGoggleAspectRatio=m_flAspectRatio ; // we use this to set up the Goggles
+	m_pCamera->setAspectRatio( Real(m_flAspectRatio) );
+	m_pCameraCopy->setAspectRatio(  Real(m_flAspectRatio) );
+	
+	m_pViewport->setCamera(m_pCamera);
+	m_pViewport->setClearEveryFrame(true);//, FBT_DEPTH) ;
+
+	
+
+
+	unsigned long hWnd = 0;
+    OIS::ParamList paramList;
+    m_pRenderWnd->getCustomAttribute("WINDOW", &hWnd);
+
+	paramList.insert(OIS::ParamList::value_type("WINDOW", Ogre::StringConverter::toString(hWnd)));
+
+	m_pInputMgr = OIS::InputManager::createInputSystem(paramList);
+
+  m_pKeyboard = static_cast<OIS::Keyboard*>(m_pInputMgr->createInputObject(OIS::OISKeyboard, true));
+	m_pMouse = static_cast<OIS::Mouse*>(m_pInputMgr->createInputObject(OIS::OISMouse, true));
+
+    
+	m_pMouse->getMouseState().height = m_pRenderWnd->getHeight();
+	m_pMouse->getMouseState().width	 = m_pRenderWnd->getWidth();
+
+	if(pKeyListener == 0)
+		m_pKeyboard->setEventCallback(this);
+	else
+		m_pKeyboard->setEventCallback(pKeyListener);
+
+	if(pMouseListener == 0)
+		m_pMouse->setEventCallback(this);
+	else
+		m_pMouse->setEventCallback(pMouseListener);
+
+	SetupResourceLocations() ;
+
+	// D3D or OGL
+	if (Root::getSingleton().getRenderSystem()->getName().find("GL") != String::npos)
+		m_IsOpenGL = true;
+	else
+		m_IsOpenGL = false;
+
+
+
+
+
+	m_pTimer = new Ogre::Timer();
+	m_pTimer->reset();
+	
+
+	
+
+
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
+	
+
+	
+
+	
+
+	m_nRTTWidth = m_pRenderWnd->getWidth() ;
+	m_nRTTHeight = m_pRenderWnd->getHeight() ;
+	
+
+	m_pRenderWnd->addListener(this);
+	m_pRenderWnd->setActive(true);
+
+
+	// default values, may be changed from the bzn.cfg file
+	m_nShadowMapSize=512 ;
+	m_nShadowRGBSize=512 ;
+	m_nColouredShadow=1 ;
+	m_nRenderHDR=1 ;
+	m_nMaxGPUQuery=1 ;
+	
+}
+
+void OgreFramework::FinalShutdown(void)
+{
+
+	//Ogre::ResourceGroupManager::getSingleton().shutdownAll();
+	//m_pRoot->destroySceneManager(m_pSceneMgr);
+	//m_pRoot->shutdown() ;
+	delete m_pRoot ;
+}
+
+void OgreFramework::AdditionalSetup()
+{
+
+	CreateRTTAssets() ;
+}
+
+
+void OgreFramework::SetupResourceLocations()
+{
+	Ogre::String secName, typeName, archName;
+	Ogre::ConfigFile cf;
+    cf.load("resources.cfg");
+
+	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
+    while (seci.hasMoreElements())
+    {
+        secName = seci.peekNextKey();
+		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
+        Ogre::ConfigFile::SettingsMultiMap::iterator i;
+        for (i = settings->begin(); i != settings->end(); ++i)
+        {
+            typeName = i->first;
+            archName = i->second;
+            Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
+        }
+    }
+	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
+}
+
+
+// create the textures, materials and miniscreens needed for the RTTs
+void OgreFramework::CreateRTTAssets()
+{
+	
+
+	// I originally had problems with OpenGL 2.1.1 suddenly running very slow if I had more than 12 RTT surfaces
+	// but that issue seems to have vanished, perhaps because all my surfaces are now FLOAT16_RGB or FLOAT16_RGBA.
+	// It doesn't like FLOAT32 surfaces, and it also didn't seem to like mixing R8G8B8 with FLOAT16, at least
+	// those configurations seem to have been problems in the past, so I try to keep everything FLOAT16_RGB where possible.
+
+	// I go through quite a few RTT surfaces, and I don't use MRT since I couldn't get it working.
+
+	MaterialManager::getSingleton().initialise() ;
+
+	// need our own resource group so that the RTTs dont get destroyed when we load a new level.
+	Ogre::ResourceGroupManager::getSingleton().createResourceGroup("RTTResources") ;
+
+	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();	
+
+	int RTTWidth = m_nRTTWidth ;//m_pRenderWnd->getWidth() ;
+	int RTTHeight = m_nRTTHeight ; //m_pRenderWnd->getHeight() ;
+
+	int DSWidth = m_nRTTWidth ;
+	int DSHeight = m_nRTTHeight ;
+
+	int DSWidthB = m_nSpeedRender ? m_nRTTWidth/2 : m_nRTTWidth ;
+	int DSHeightB = m_nSpeedRender ? m_nRTTHeight/2 : m_nRTTHeight ;
+
+	int TEMPWidth = m_nRTTWidth ;
+	int TEMPHeight = m_nRTTHeight ;
+
+
+	Ogre::ColourValue ClearColour=Ogre::ColourValue(0,0,0,1) ; // clears alpha as well. for RGBA textures 
+	//!! for now use alpha 1, since Ogre seems to force it to 1 anyway on shadow render.
+
+
+	
+	
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// Shadow
+	
+	RTT_Texture_Shadow = Ogre::TextureManager::getSingleton().createManual("RttTex_Shadow",
+      "RTTResources", TEX_TYPE_2D, m_nShadowMapSize, m_nShadowMapSize, 0, PF_FLOAT16_RGB,
+      TU_RENDERTARGET);
+
+	
+	renderTexture_Shadow = RTT_Texture_Shadow->getBuffer()->getRenderTarget();
+	renderTexture_Shadow->addViewport(m_pCamera);
+	renderTexture_Shadow->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH);
+	renderTexture_Shadow->getViewport(0)->setBackgroundColour(ColourValue::White);
+	renderTexture_Shadow->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_Shadow = MaterialManager::getSingleton().create("RttMat_Shadow", "RTTResources");
+	RTT_Technique_Shadow = RTT_Mat_Shadow->createTechnique();
+	RTT_Technique_Shadow->createPass();
+	TextureUnitState* tState_Shadow = RTT_Mat_Shadow->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_Shadow");
+	tState_Shadow->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_Shadow->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	RTT_Mat_Shadow->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	
+	miniScreen_Shadow = new Ogre::Rectangle2D(true);
+	miniScreen_Shadow->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_Shadow->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_Shadow = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_Shadow");
+	miniScreenNode_Shadow->attachObject(miniScreen_Shadow);
+	miniScreen_Shadow->setMaterial("RttMat_Shadow");
+
+
+	if(m_nColouredShadow)
+	{
+		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		// ShadeFront
+		
+		RTT_Texture_ShadeFront = Ogre::TextureManager::getSingleton().createManual("RttTex_ShadeFront",
+				"RTTResources", TEX_TYPE_2D, m_nShadowRGBSize, m_nShadowRGBSize, 0, PF_FLOAT16_RGBA,
+				TU_RENDERTARGET);
+
+		
+		renderTexture_ShadeFront = RTT_Texture_ShadeFront->getBuffer()->getRenderTarget();
+		renderTexture_ShadeFront->addViewport(m_pCamera);
+		renderTexture_ShadeFront->getViewport(0)->setClearEveryFrame(true);//, FBT_DEPTH);
+		renderTexture_ShadeFront->getViewport(0)->setBackgroundColour(ColourValue::White);
+		renderTexture_ShadeFront->getViewport(0)->setOverlaysEnabled(false);
+
+		RTT_Mat_ShadeFront = MaterialManager::getSingleton().create("RttMat_ShadeFront", "RTTResources");
+		RTT_Technique_ShadeFront = RTT_Mat_ShadeFront->createTechnique();
+		RTT_Technique_ShadeFront->createPass();
+		TextureUnitState* tState_ShadeFront = RTT_Mat_ShadeFront->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_ShadeFront");
+		tState_ShadeFront->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+		RTT_Mat_ShadeFront->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+		RTT_Mat_ShadeFront->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+		
+		miniScreen_ShadeFront = new Ogre::Rectangle2D(true);
+		miniScreen_ShadeFront->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+		miniScreen_ShadeFront->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+		miniScreenNode_ShadeFront = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_ShadeFront");
+		miniScreenNode_ShadeFront->attachObject(miniScreen_ShadeFront);
+		miniScreen_ShadeFront->setMaterial("RttMat_ShadeFront");
+		
+		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		// ShadeBack
+		
+		RTT_Texture_ShadeBack = Ogre::TextureManager::getSingleton().createManual("RttTex_ShadeBack",
+				"RTTResources", TEX_TYPE_2D, m_nShadowRGBSize, m_nShadowRGBSize, 0, PF_FLOAT16_RGBA,
+				TU_RENDERTARGET);
+
+		
+		renderTexture_ShadeBack = RTT_Texture_ShadeBack->getBuffer()->getRenderTarget();
+		renderTexture_ShadeBack->addViewport(m_pCamera);
+		renderTexture_ShadeBack->getViewport(0)->setClearEveryFrame(true);//, FBT_DEPTH);
+		renderTexture_ShadeBack->getViewport(0)->setBackgroundColour(ColourValue::White);
+		renderTexture_ShadeBack->getViewport(0)->setOverlaysEnabled(false);
+
+		RTT_Mat_ShadeBack = MaterialManager::getSingleton().create("RttMat_ShadeBack", "RTTResources");
+		RTT_Technique_ShadeBack = RTT_Mat_ShadeBack->createTechnique();
+		RTT_Technique_ShadeBack->createPass();
+		TextureUnitState* tState_ShadeBack = RTT_Mat_ShadeBack->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_ShadeBack");
+		tState_ShadeBack->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+		RTT_Mat_ShadeBack->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+		RTT_Mat_ShadeBack->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+		
+		miniScreen_ShadeBack = new Ogre::Rectangle2D(true);
+		miniScreen_ShadeBack->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+		miniScreen_ShadeBack->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+		miniScreenNode_ShadeBack = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_ShadeBack");
+		miniScreenNode_ShadeBack->attachObject(miniScreen_ShadeBack);
+		miniScreen_ShadeBack->setMaterial("RttMat_ShadeBack");
+	
+	} // end if coloured shadows
+	
+	
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DfShPosition
+	
+	RTT_Texture_DfShPosition = Ogre::TextureManager::getSingleton().createManual("RttTex_DfShPosition",
+      "RTTResources", TEX_TYPE_2D, DSWidth, DSHeight, 0, PF_FLOAT16_RGB,
+      TU_RENDERTARGET);
+
+	
+	renderTexture_DfShPosition = RTT_Texture_DfShPosition->getBuffer()->getRenderTarget();
+	renderTexture_DfShPosition->addViewport(m_pCamera);
+	renderTexture_DfShPosition->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH);
+	renderTexture_DfShPosition->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DfShPosition->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DfShPosition = MaterialManager::getSingleton().create("RttMat_DfShPosition", "RTTResources");
+	RTT_Technique_DfShPosition = RTT_Mat_DfShPosition->createTechnique();
+	RTT_Technique_DfShPosition->createPass();
+	TextureUnitState* tState_DfShPosition = RTT_Mat_DfShPosition->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DfShPosition");
+	tState_DfShPosition->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DfShPosition->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	RTT_Mat_DfShPosition->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	
+	
+	//renderTexture_DfShPosition->addListener(this);
+
+	miniScreen_DfShPosition = new Ogre::Rectangle2D(true);
+	miniScreen_DfShPosition->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShPosition->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShPosition = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShPosition");
+	miniScreenNode_DfShPosition->attachObject(miniScreen_DfShPosition);
+	miniScreen_DfShPosition->setMaterial("RttMat_DfShPosition");
+	
+	
+
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DfShDiffuse
+	
+	RTT_Texture_DfShDiffuse = Ogre::TextureManager::getSingleton().createManual("RttTex_DfShDiffuse",
+      "RTTResources", TEX_TYPE_2D, DSWidth, DSHeight, 0, PF_FLOAT16_RGB,
+      TU_RENDERTARGET);
+
+	
+	renderTexture_DfShDiffuse = RTT_Texture_DfShDiffuse->getBuffer()->getRenderTarget();
+	renderTexture_DfShDiffuse->addViewport(m_pCamera);
+	renderTexture_DfShDiffuse->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH);
+	renderTexture_DfShDiffuse->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DfShDiffuse->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DfShDiffuse = MaterialManager::getSingleton().create("RttMat_DfShDiffuse", "RTTResources");
+	RTT_Technique_DfShDiffuse = RTT_Mat_DfShDiffuse->createTechnique();
+	RTT_Technique_DfShDiffuse->createPass();
+	TextureUnitState* tState_DfShDiffuse = RTT_Mat_DfShDiffuse->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DfShDiffuse");
+	tState_DfShDiffuse->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DfShDiffuse->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	RTT_Mat_DfShDiffuse->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	
+	
+	//renderTexture_DfShDiffuse->addListener(this);
+
+	miniScreen_DfShDiffuse = new Ogre::Rectangle2D(true);
+	miniScreen_DfShDiffuse->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShDiffuse->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShDiffuse = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShDiffuse");
+	miniScreenNode_DfShDiffuse->attachObject(miniScreen_DfShDiffuse);
+	miniScreen_DfShDiffuse->setMaterial("RttMat_DfShDiffuse");
+
+	/*
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DSNormal
+	
+	RTT_Texture_DSNormal = Ogre::TextureManager::getSingleton().createManual("RttTex_DSNormal",
+      "RTTResources", TEX_TYPE_2D, DSWidth, DSHeight, 0, PF_FLOAT16_RGB,
+      TU_RENDERTARGET);
+
+	
+	renderTexture_DSNormal = RTT_Texture_DSNormal->getBuffer()->getRenderTarget();
+	renderTexture_DSNormal->addViewport(m_pCamera);
+	renderTexture_DSNormal->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH);
+	renderTexture_DSNormal->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DSNormal->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DSNormal = MaterialManager::getSingleton().create("RttMat_DSNormal", "RTTResources");
+	RTT_Technique_DSNormal = RTT_Mat_DSNormal->createTechnique();
+	RTT_Technique_DSNormal->createPass();
+	TextureUnitState* tState_DSNormal = RTT_Mat_DSNormal->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DSNormal");
+	tState_DSNormal->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DSNormal->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	RTT_Mat_DSNormal->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	
+	
+	
+	//renderTexture_DSNormal->addListener(this);
+
+	miniScreen_DSNormal = new Ogre::Rectangle2D(true);
+	miniScreen_DSNormal->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DSNormal->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DSNormal = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DSNormal");
+	miniScreenNode_DSNormal->attachObject(miniScreen_DSNormal);
+	miniScreen_DSNormal->setMaterial("RttMat_DSNormal");
+	
+	*/
+
+	
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DfShFuncTNB
+
+	RTT_Texture_DfShFuncTNB = Ogre::TextureManager::getSingleton().createManual("RttTex_DfShFuncTNB",
+      "RTTResources", TEX_TYPE_2D, DSWidth, DSHeight, 0, PF_FLOAT16_RGB,
+      TU_RENDERTARGET);
+
+	
+	renderTexture_DfShFuncTNB = RTT_Texture_DfShFuncTNB->getBuffer()->getRenderTarget();
+	renderTexture_DfShFuncTNB->addViewport(m_pCamera);
+	renderTexture_DfShFuncTNB->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH);
+	renderTexture_DfShFuncTNB->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DfShFuncTNB->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DfShFuncTNB = MaterialManager::getSingleton().create("RttMat_DfShFuncTNB", "RTTResources");
+	RTT_Technique_DfShFuncTNB = RTT_Mat_DfShFuncTNB->createTechnique();
+	RTT_Technique_DfShFuncTNB->createPass();
+	TextureUnitState* tState_DfShFuncTNB = RTT_Mat_DfShFuncTNB->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DfShFuncTNB");
+	tState_DfShFuncTNB->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DfShFuncTNB->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	RTT_Mat_DfShFuncTNB->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	
+	//renderTexture_DfShFuncTNB->addListener(this);
+
+	miniScreen_DfShFuncTNB = new Ogre::Rectangle2D(true);
+	miniScreen_DfShFuncTNB->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShFuncTNB->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShFuncTNB = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShFuncTNB");
+	miniScreenNode_DfShFuncTNB->attachObject(miniScreen_DfShFuncTNB);
+	miniScreen_DfShFuncTNB->setMaterial("RttMat_DfShFuncTNB");
+
+	
+
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DfShSpecular
+
+	RTT_Texture_DfShSpecular = Ogre::TextureManager::getSingleton().createManual("RttTex_DfShSpecular",
+      "RTTResources", TEX_TYPE_2D, DSWidthB, DSHeightB, 0, PF_FLOAT16_RGBA,
+      TU_RENDERTARGET);
+
+	
+	renderTexture_DfShSpecular = RTT_Texture_DfShSpecular->getBuffer()->getRenderTarget();
+	renderTexture_DfShSpecular->addViewport(m_pCamera);
+	renderTexture_DfShSpecular->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH);
+	renderTexture_DfShSpecular->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DfShSpecular->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DfShSpecular = MaterialManager::getSingleton().create("RttMat_DfShSpecular", "RTTResources");
+	RTT_Technique_DfShSpecular = RTT_Mat_DfShSpecular->createTechnique();
+	RTT_Technique_DfShSpecular->createPass();
+	TextureUnitState* tState_DfShSpecular = RTT_Mat_DfShSpecular->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DfShSpecular");
+	tState_DfShSpecular->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DfShSpecular->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	if(m_nSpeedRender)
+		RTT_Mat_DfShSpecular->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_BILINEAR) ;
+	else
+		RTT_Mat_DfShSpecular->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	
+
+	//renderTexture_DfShSpecular->addListener(this);
+
+	miniScreen_DfShSpecular = new Ogre::Rectangle2D(true);
+	miniScreen_DfShSpecular->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShSpecular->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShSpecular = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShSpecular");
+	miniScreenNode_DfShSpecular->attachObject(miniScreen_DfShSpecular);
+	miniScreen_DfShSpecular->setMaterial("RttMat_DfShSpecular");
+
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DfShEmissive
+
+	RTT_Texture_DfShEmissive = Ogre::TextureManager::getSingleton().createManual("RttTex_DfShEmissive",
+      "RTTResources", TEX_TYPE_2D, DSWidth, DSHeight, 0, PF_FLOAT16_RGB,
+      TU_RENDERTARGET);
+
+	
+	renderTexture_DfShEmissive = RTT_Texture_DfShEmissive->getBuffer()->getRenderTarget();
+	renderTexture_DfShEmissive->addViewport(m_pCamera);
+	renderTexture_DfShEmissive->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH);
+	renderTexture_DfShEmissive->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DfShEmissive->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DfShEmissive = MaterialManager::getSingleton().create("RttMat_DfShEmissive", "RTTResources");
+	RTT_Technique_DfShEmissive = RTT_Mat_DfShEmissive->createTechnique();
+	RTT_Technique_DfShEmissive->createPass();
+	TextureUnitState* tState_DfShEmissive = RTT_Mat_DfShEmissive->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DfShEmissive");
+	tState_DfShEmissive->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DfShEmissive->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	if(m_nSpeedRender)
+		RTT_Mat_DfShEmissive->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_BILINEAR) ;
+	else
+		RTT_Mat_DfShEmissive->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	
+
+	//renderTexture_DfShEmissive->addListener(this);
+
+	miniScreen_DfShEmissive = new Ogre::Rectangle2D(true);
+	miniScreen_DfShEmissive->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShEmissive->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShEmissive = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShEmissive");
+	miniScreenNode_DfShEmissive->attachObject(miniScreen_DfShEmissive);
+	miniScreen_DfShEmissive->setMaterial("RttMat_DfShEmissive");
+
+	
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DfShLamp
+
+	RTT_Texture_DfShLamp = Ogre::TextureManager::getSingleton().createManual("RttTex_DfShLamp",
+      "RTTResources", TEX_TYPE_2D, DSWidth, DSHeight, 0, PF_FLOAT16_RGB, 
+      TU_RENDERTARGET);//, 0, false, 6);
+	
+	renderTexture_DfShLamp = RTT_Texture_DfShLamp->getBuffer()->getRenderTarget();
+	renderTexture_DfShLamp->addViewport(m_pCamera);
+	renderTexture_DfShLamp->getViewport(0)->setClearEveryFrame(true);//, FBT_DEPTH); 
+	renderTexture_DfShLamp->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DfShLamp->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DfShLamp = MaterialManager::getSingleton().create("RttMat_DfShLamp", "RTTResources");
+	RTT_Technique_DfShLamp = RTT_Mat_DfShLamp->createTechnique();
+	RTT_Technique_DfShLamp->createPass();
+	TextureUnitState* tState_DfShLamp = RTT_Mat_DfShLamp->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DfShLamp");
+	tState_DfShLamp->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DfShLamp->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	RTT_Mat_DfShLamp->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	//renderTexture_DfShLamp->addListener(this);
+
+	miniScreen_DfShLamp = new Ogre::Rectangle2D(true);
+	miniScreen_DfShLamp->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShLamp->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShLamp = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShLamp");
+	miniScreenNode_DfShLamp->attachObject(miniScreen_DfShLamp);
+	miniScreen_DfShLamp->setMaterial("RttMat_DfShLamp");
+	
+	
+
+	/*
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DfShData
+
+	RTT_Texture_DfShData = Ogre::TextureManager::getSingleton().createManual("RttTex_DfShData",
+      "RTTResources", TEX_TYPE_2D, DSWidthB, DSHeightB, 0, PF_FLOAT16_RGB,
+      TU_RENDERTARGET);
+	
+	renderTexture_DfShData = RTT_Texture_DfShData->getBuffer()->getRenderTarget();
+	renderTexture_DfShData->addViewport(m_pCamera);
+	renderTexture_DfShData->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH); 
+	renderTexture_DfShData->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DfShData->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DfShData = MaterialManager::getSingleton().create("RttMat_DfShData", "RTTResources");
+	RTT_Technique_DfShData = RTT_Mat_DfShData->createTechnique();
+	RTT_Technique_DfShData->createPass();
+	TextureUnitState* tState_DfShData = RTT_Mat_DfShData->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DfShData");
+	tState_DfShData->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DfShData->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	if(m_nSpeedRender)
+		RTT_Mat_DfShData->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_BILINEAR) ;
+	else
+		RTT_Mat_DfShData->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	//renderTexture_DfShData->addListener(this);
+
+	miniScreen_DfShData = new Ogre::Rectangle2D(true);
+	miniScreen_DfShData->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShData->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShData = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShData");
+	miniScreenNode_DfShData->attachObject(miniScreen_DfShData);
+	miniScreen_DfShData->setMaterial("RttMat_DfShData");
+	
+	*/
+
+	
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DfShTemp
+
+	RTT_Texture_DfShTemp = Ogre::TextureManager::getSingleton().createManual("RttTex_DfShTemp",
+      "RTTResources", TEX_TYPE_2D, TEMPWidth, TEMPHeight, 0, PF_FLOAT16_RGB, 
+      TU_RENDERTARGET);//, 0, false, 6);
+	
+	renderTexture_DfShTemp = RTT_Texture_DfShTemp->getBuffer()->getRenderTarget();
+	renderTexture_DfShTemp->addViewport(m_pCamera);
+	renderTexture_DfShTemp->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH); 
+	renderTexture_DfShTemp->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DfShTemp->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DfShTemp = MaterialManager::getSingleton().create("RttMat_DfShTemp", "RTTResources");
+	RTT_Technique_DfShTemp = RTT_Mat_DfShTemp->createTechnique();
+	RTT_Technique_DfShTemp->createPass();
+	TextureUnitState* tState_DfShTemp = RTT_Mat_DfShTemp->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DfShTemp");
+	tState_DfShTemp->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DfShTemp->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	RTT_Mat_DfShTemp->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+	//renderTexture_DfShTemp->addListener(this);
+
+	miniScreen_DfShTemp = new Ogre::Rectangle2D(true);
+	miniScreen_DfShTemp->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShTemp->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShTemp = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShTemp");
+	miniScreenNode_DfShTemp->attachObject(miniScreen_DfShTemp);
+	miniScreen_DfShTemp->setMaterial("RttMat_DfShTemp");
+
+
+	
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// DfShMix
+
+		RTT_Texture_DfShMix = Ogre::TextureManager::getSingleton().createManual("RttTex_DfShMix",
+      "RTTResources", TEX_TYPE_2D, RTTWidth, RTTHeight, 0, PF_FLOAT16_RGB,
+      TU_RENDERTARGET);
+
+	
+	renderTexture_DfShMix = RTT_Texture_DfShMix->getBuffer()->getRenderTarget();
+	renderTexture_DfShMix->addViewport(m_pCamera);
+	renderTexture_DfShMix->getViewport(0)->setClearEveryFrame(false);//, FBT_DEPTH);
+	renderTexture_DfShMix->getViewport(0)->setBackgroundColour(ColourValue::Black);
+	renderTexture_DfShMix->getViewport(0)->setOverlaysEnabled(false);
+
+	RTT_Mat_DfShMix = MaterialManager::getSingleton().create("RttMat_DfShMix", "RTTResources");
+	RTT_Technique_DfShMix = RTT_Mat_DfShMix->createTechnique();
+	RTT_Technique_DfShMix->createPass();
+	TextureUnitState* tState_DfShMix = RTT_Mat_DfShMix->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_DfShMix");
+	tState_DfShMix->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	RTT_Mat_DfShMix->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+	RTT_Mat_DfShMix->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_NONE) ;
+
+
+	miniScreen_DfShMix = new Ogre::Rectangle2D(true);
+	miniScreen_DfShMix->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShMix->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShMix = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShMix");
+	miniScreenNode_DfShMix->attachObject(miniScreen_DfShMix);
+	miniScreen_DfShMix->setMaterial("RttMat_DfShMix");
+	
+	if(m_nRenderHDR)
+	{
+
+		
+		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		// BlurA
+		
+		RTT_Texture_BlurA = Ogre::TextureManager::getSingleton().createManual("RttTex_BlurA",
+				"RTTResources", TEX_TYPE_2D, DSWidth/2, DSHeight/2, 0, PF_FLOAT16_RGB,
+				TU_RENDERTARGET);
+		
+		renderTexture_BlurA = RTT_Texture_BlurA->getBuffer()->getRenderTarget();
+		renderTexture_BlurA->addViewport(m_pCamera);
+		renderTexture_BlurA->getViewport(0)->setClearEveryFrame(false);
+		renderTexture_BlurA->getViewport(0)->setBackgroundColour(ColourValue::Black);
+		renderTexture_BlurA->getViewport(0)->setOverlaysEnabled(false);
+
+		RTT_Mat_BlurA = MaterialManager::getSingleton().create("RttMat_BlurA", "RTTResources");
+		RTT_Technique_BlurA = RTT_Mat_BlurA->createTechnique();
+		RTT_Technique_BlurA->createPass();
+		TextureUnitState* tState_BlurA = RTT_Mat_BlurA->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_BlurA");
+		tState_BlurA->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+		RTT_Mat_BlurA->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+		RTT_Mat_BlurA->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_BILINEAR) ;
+
+		miniScreen_BlurA = new Ogre::Rectangle2D(true);
+		miniScreen_BlurA->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+		miniScreen_BlurA->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+		miniScreenNode_BlurA = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_BlurA");
+		miniScreenNode_BlurA->attachObject(miniScreen_BlurA);
+		miniScreen_BlurA->setMaterial("RttMat_BlurA");
+
+		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		// BlurB
+		
+		RTT_Texture_BlurB = Ogre::TextureManager::getSingleton().createManual("RttTex_BlurB",
+				"RTTResources", TEX_TYPE_2D, DSWidth/2, DSHeight/2, 0, PF_FLOAT16_RGB,
+				TU_RENDERTARGET);
+		
+		renderTexture_BlurB = RTT_Texture_BlurB->getBuffer()->getRenderTarget();
+		renderTexture_BlurB->addViewport(m_pCamera);
+		renderTexture_BlurB->getViewport(0)->setClearEveryFrame(false);
+		renderTexture_BlurB->getViewport(0)->setBackgroundColour(ColourValue::Black);
+		renderTexture_BlurB->getViewport(0)->setOverlaysEnabled(false);
+
+		RTT_Mat_BlurB = MaterialManager::getSingleton().create("RttMat_BlurB", "RTTResources");
+		RTT_Technique_BlurB = RTT_Mat_BlurB->createTechnique();
+		RTT_Technique_BlurB->createPass();
+		TextureUnitState* tState_BlurB = RTT_Mat_BlurB->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex_BlurB");
+		tState_BlurB->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+		RTT_Mat_BlurB->getTechnique(0)->getPass(0)->setLightingEnabled(false);
+		RTT_Mat_BlurB->getTechnique(0)->getPass(0)->setTextureFiltering(TFO_BILINEAR) ;
+
+		miniScreen_BlurB = new Ogre::Rectangle2D(true);
+		miniScreen_BlurB->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+		miniScreen_BlurB->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+		miniScreenNode_BlurB = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_BlurB");
+		miniScreenNode_BlurB->attachObject(miniScreen_BlurB);
+		miniScreen_BlurB->setMaterial("RttMat_BlurB");
+		
+	} // end if m_nRenderHDR	
+	
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// mixing quad
+	miniScreen_DfShMaster = new Ogre::Rectangle2D(true);
+	miniScreen_DfShMaster->setCorners(-1.0001, 1.0001, 1.0, -1.0);
+	miniScreen_DfShMaster->setBoundingBox(AxisAlignedBox(-100000.0*Vector3::UNIT_SCALE, 100000.0*Vector3::UNIT_SCALE)); 
+	miniScreenNode_DfShMaster = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("MiniScreenNode_DfShMaster");
+	miniScreenNode_DfShMaster->attachObject(miniScreen_DfShMaster);
+	//miniScreen_DfShMaster->setMaterial("RttMat_DfShDiffuse") ;
+	//miniScreen_DfShMaster->setMaterial("DfShMix") ; // doesn't matter what material we use, since we mix from pre-rendered textures
+	
+	//RTT_Mat_Shadow->getTechnique(0)->getPass(0)->getTextureUnitState("RttTex_Shadow")->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP) ;
+	
+}
+
+void OgreFramework::DestroyRTTAssets()
+{
+}
+
+void OgreFramework::UpdateRenderTargets()
+{
+
+	int nZoneList=0 ;
+	int nZone=0 ;
+	Ogre::Entity*	pEntity=NULL ;
+	int nMO=0 ;
+	int nZGStart=0 ;
+	int nZGEnd=0 ;
+
+	int nVisEnt=0 ;
+	int nEntity=0 ;
+//	int nMaxEntity=0 ;
+	int nSubMesh=0 ;
+	int nMaxSubMesh=0 ;
+
+	int nMaxVisibleZone=*m_pGlobal_MaxVisibleZone ;
+
+	SetAllLightsOff() ;
+
+	
+	// extra texture params
+	// TexParam.x is 1 for d3d, -1 for ogl, needed for screen space UV calculations y flip
+	// TexParam.y is game time, in 1/10th of a second since start of level
+
+	Ogre::Vector4 TexParam ;
+	if(m_IsOpenGL) 
+		TexParam.x=-1 ; 
+	else 
+		TexParam.x= 1 ;
+	TexParam.y=m_GameTime/100 ;
+	TexParam.z=512.0f ; // pixelnoise subdivisions for the emmissive data function.
+
+
+	// remove all the nodes, so we start with a clean slate
+	m_pSceneMgr->getRootSceneNode()->removeAllChildren() ; // remove all the objects
+	
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// 
+	// deferred shading data textures
+	//
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	SetZoneNodeAttachments(m_uVisibleZoneListL, &m_nMaxVisibleZoneL, MAT_OPAQUE) ;
+
+	// attach the entity masternode, update positions and orientations
+	for(nVisEnt=0 ; nVisEnt<m_nMaxFrustumEntity ; nVisEnt++)
+	{
+		nEntity=m_pFrustumEntity[nVisEnt] ;
+		m_pEntityInfo[ nEntity ].pMasterNode->setPosition( m_pEntityInfo[nEntity].Postition ) ; // set position.
+		m_pSceneMgr->getRootSceneNode()->addChild(m_pEntityInfo[ nEntity ].pMasterNode) ;
+	}
+
+
+	
+	
+	/////////////////////////////////////////////////////////////////////
+	// DfShPosition
+	
+	// change material
+	for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+	{
+		nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+		nZGStart	=	m_nZoneMOStart[nZone] ;
+		nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+			
+		for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+			if(m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE)
+			{
+				pEntity=m_pZoneEntity[nMO] ;
+				pEntity->setMaterial( m_pZoneEntityMaterial_DfShPosition[nMO] ) ;
+			}// end for entities
+
+	}// end for zonelist
+
+
+	// first time we set materials we need to set non-opaque to the be invisible.  After we don't need to do it, they'll already be invisible
+	// Set the entity material
+
+	for(nVisEnt=0 ; nVisEnt<m_nMaxFrustumEntity ; nVisEnt++)
+	{
+		nEntity=m_pFrustumEntity[nVisEnt] ;
+		nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+		for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+			if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE)
+			{
+				m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_DfShPosition[nSubMesh] ) ;
+				m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setVisible(true) ; // first time around, make sure it is visible
+			}
+			else
+				m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setVisible(false) ;
+	}
+
+
+
+	renderTexture_DfShPosition->update(true) ;
+	
+	/////////////////////////////////////////////////////////////////////
+	// DfShFuncTNB
+
+	// change material
+	for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+	{
+		nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+		nZGStart	=	m_nZoneMOStart[nZone] ;
+		nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+			
+		for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+			if(m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE)
+			{
+				pEntity=m_pZoneEntity[nMO] ;
+				pEntity->setMaterial( m_pZoneEntityMaterial_DfShFuncTNB[nMO] ) ;
+			}// end for entities
+
+	}// end for zonelist
+
+	for(nVisEnt=0 ; nVisEnt<m_nMaxFrustumEntity ; nVisEnt++)
+	{
+		nEntity=m_pFrustumEntity[nVisEnt] ;
+		nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+		for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+			if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE)
+				m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_DfShFuncTNB[nSubMesh] ) ;
+	}
+
+
+	renderTexture_DfShFuncTNB->update(true) ;
+	
+	
+	/////////////////////////////////////////////////////////////////////
+	// DfShDiffuse
+	
+	// the diffuse pass is used for the wireframe render as well
+
+
+
+	if(m_nDisplayInfoMode!=1)
+	{
+		// change material
+		for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+		{
+			nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+			nZGStart	=	m_nZoneMOStart[nZone] ;
+			nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+				
+			for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+				if(m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE)
+				{
+					pEntity=m_pZoneEntity[nMO] ;
+					pEntity->setMaterial( m_pZoneEntityMaterial_DfShDiffuse[nMO] ) ;
+				}// end for entities
+
+		}// end for zonelist
+
+		// set the entity material
+
+		for(nVisEnt=0 ; nVisEnt<m_nMaxFrustumEntity ; nVisEnt++)
+		{
+			nEntity=m_pFrustumEntity[nVisEnt] ;
+			nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+			for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+				if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE)
+					m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_DfShDiffuse[nSubMesh] ) ;
+		}
+
+
+		renderTexture_DfShDiffuse->update(true) ;
+	}
+	else // if we are doing wireframe we use this pass for it
+	{
+		// add gels just for the wireframe
+		SetZoneNodeAttachments(m_uVisibleZoneListL, &m_nMaxVisibleZoneL, MAT_GEL) ;	
+
+
+		// clear the RTT texture, since our wireframe won't clear it.
+		m_pRoot->getRenderSystem()->_setViewport(renderTexture_DfShDiffuse->getViewport(0)) ;
+		m_pRoot->getRenderSystem()->clearFrameBuffer(FBT_COLOUR|FBT_DEPTH, Ogre::ColourValue(0,0,0,1)) ;
+		
+		// set the camera to wireframe mode
+		m_pCamera->setPolygonMode(PM_WIREFRAME);
+
+		// change material
+		for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+		{
+			nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+			nZGStart	=	m_nZoneMOStart[nZone] ;
+			nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+				
+			for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+				if((m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE) || (m_pZoneEntityMaterialType[nMO]==MAT_GEL))
+				{
+					pEntity=m_pZoneEntity[nMO] ;
+					pEntity->setMaterial( MaterialManager::getSingleton().getByName("White") ) ;
+				}// end for entities
+
+		}// end for zonelist
+
+		for(nVisEnt=0 ; nVisEnt<m_nMaxFrustumEntity ; nVisEnt++)
+		{
+			nEntity=m_pFrustumEntity[nVisEnt] ;
+			nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+			for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+			{
+				if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]!=MAT_OPAQUE) // any non-opaque submeshes need to be made visible
+					m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setVisible(true) ;
+
+				m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial(MaterialManager::getSingleton().getByName("White") ) ;
+			}
+		}
+
+		renderTexture_DfShDiffuse->update(true) ;
+	
+		// reset back to pre-wireframe setup
+		m_pCamera->setPolygonMode(PM_SOLID);
+
+		// remove everything and then add back OPAQUE
+		m_pSceneMgr->getRootSceneNode()->removeAllChildren() ; // remove all the objects
+		SetZoneNodeAttachments(m_uVisibleZoneListL, &m_nMaxVisibleZoneL, MAT_OPAQUE) ;
+
+
+		// reattach entities, make non-opaque subentities invisible
+		for(nVisEnt=0 ; nVisEnt<m_nMaxFrustumEntity ; nVisEnt++)
+		{
+			nEntity=m_pFrustumEntity[nVisEnt] ;
+			nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+			m_pSceneMgr->getRootSceneNode()->addChild(m_pEntityInfo[  nEntity  ].pMasterNode) ;
+
+			for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+			{
+				if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]!=MAT_OPAQUE) 
+				m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setVisible(false) ;
+			}
+		}
+
+
+
+	}
+
+	
+	
+	/////////////////////////////////////////////////////////////////////
+	// DfShSpecular
+
+	// change material
+	for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+	{
+		nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+		nZGStart	=	m_nZoneMOStart[nZone] ;
+		nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+			
+		for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+			if(m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE)
+			{
+				pEntity=m_pZoneEntity[nMO] ;
+				pEntity->setMaterial( m_pZoneEntityMaterial_DfShSpecular[nMO] ) ;
+			}// end for entities
+
+	}// end for zonelist
+
+	for(nVisEnt=0 ; nVisEnt<m_nMaxFrustumEntity ; nVisEnt++)
+	{
+		nEntity=m_pFrustumEntity[nVisEnt] ;
+		nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+		// set the entity material
+		for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+			if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE)
+				m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_DfShSpecular[nSubMesh] ) ;
+	}
+
+	renderTexture_DfShSpecular->update(true) ;
+	
+	/*
+	/////////////////////////////////////////////////////////////////////
+	// DfShData
+
+	// change material
+	for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+	{
+		nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+		nZGStart	=	m_nZoneMOStart[nZone] ;
+		nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+			
+		for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+			if(m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE)
+			{
+				pEntity=m_pZoneEntity[nMO] ;
+				pEntity->setMaterial( m_pZoneEntityMaterial_DfShData[nMO] ) ;
+			}// end for entities
+
+	}// end for zonelist
+
+	renderTexture_DfShData->update(true) ;
+	*/
+
+	
+	/////////////////////////////////////////////////////////////////////
+	// DfShEmissive
+
+	// we add the glow entities for this pass, if we are doing HDR
+	if(m_nRenderHDR)
+		SetZoneNodeAttachments(m_uVisibleZoneListL, &m_nMaxVisibleZoneL, MAT_GLOW) ;
+
+
+	// change material
+	for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+	{
+		nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+		nZGStart	=	m_nZoneMOStart[nZone] ;
+		nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+			
+		for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+			if((m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE) || (m_pZoneEntityMaterialType[nMO]==MAT_GLOW))
+			{
+				pEntity=m_pZoneEntity[nMO] ;
+				pEntity->setMaterial( m_pZoneEntityMaterial_DfShEmissive[nMO] ) ;
+
+				TexParam.z=512.0f ; // pixelnoise subdivisions for the emmissive data function.
+				pEntity->getSubEntity(0)->setCustomParameter(4, TexParam) ; // emissive makes use of gametime for some lighting effects
+			}// end for entities
+
+	}// end for zonelist
+
+	// set the entity material
+	for(nVisEnt=0 ; nVisEnt<m_nMaxFrustumEntity ; nVisEnt++)
+	{
+		nEntity=m_pFrustumEntity[nVisEnt] ;
+		nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+		for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+			if((m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE) || (m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GLOW))
+			{
+				// make glow stuff visible
+				if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GLOW)
+					m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setVisible(true) ;
+
+				m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_DfShEmissive[nSubMesh] ) ;
+			}
+	}
+
+	renderTexture_DfShEmissive->update(true) ;
+
+	
+
+	////////////////////////////////////////////////////////////////////
+	// we need to know how to colour stuff if we're seeing it through gel
+	// this colouring will be applied when we mix lamp and emmissive down to DfShMix
+	//
+	// Note that this leaves the light/lamp glow entities attached in HDR mode,
+	// we need them to block the gels otherwise the blur on the lights/lamps 
+	// comes out incorrectly coloured by gel that should be behind it. 
+
+	// add the transparent stuff
+	SetZoneNodeAttachments(m_uVisibleZoneListL, &m_nMaxVisibleZoneL, MAT_GEL) ;
+
+	// change material
+	for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+	{
+		nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+		nZGStart	=	m_nZoneMOStart[nZone] ;
+		nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+			
+		for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+			if((m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE) || (m_pZoneEntityMaterialType[nMO]==MAT_GEL) || (m_pZoneEntityMaterialType[nMO]==MAT_GLOW))
+			{
+				pEntity=m_pZoneEntity[nMO] ;
+				pEntity->setMaterial( m_pZoneEntityMaterial_DfShColour[nMO] ) ;
+			}// end for entities
+
+
+	}// end for zonelist
+
+	for(nVisEnt=0 ; nVisEnt<m_nMaxFrustumEntity ; nVisEnt++)
+	{
+		nEntity=m_pFrustumEntity[nVisEnt] ;
+		nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+		// set the entity material
+		for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+			if((m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE) || (m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GEL) || (m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GLOW))
+			{
+				// make gel stuff visible (glow was already made visible on the emissive pass)
+				if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GEL)
+					m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setVisible(true) ;
+
+				m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_DfShColour[nSubMesh] ) ;
+			}
+	}
+
+	// render colour to the temp surface
+	renderTexture_DfShTemp->update(true) ;
+
+	
+
+	//clear the mix buffer once
+	m_pRoot->getRenderSystem()->_setViewport(renderTexture_DfShMix->getViewport(0)) ;
+	m_pRoot->getRenderSystem()->clearFrameBuffer(FBT_COLOUR|FBT_DEPTH, Ogre::ColourValue(0,0,0,1)) ;
+
+	// remove all the nodes
+	m_pSceneMgr->getRootSceneNode()->removeAllChildren() ; // remove all the objects
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// 
+	// deferred shading non-shadowing point lights
+	//
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+	if(true)
+	{
+		SetZoneNodeAttachments(m_uVisibleZoneListL, &m_nMaxVisibleZoneL, MAT_LAMP) ; // attach the lamp boxes
+
+		// this renders our deferred shader lamps
+		renderTexture_DfShLamp->update(true) ;
+
+		// this shader combines the deferred light render with the emissive render and colours it with any gels
+		miniScreen_DfShMaster->setMaterial("Mix_Lamps") ; 
+
+		// get rid of all the scene geometry
+		m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+
+		// put up a fullscreen quad so DfShMix has some UV coordinates.
+		m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShMaster) ;
+
+		// update DfShMix, but don't swap buffers yet since we may be back again next loop with more lights to add.
+		renderTexture_DfShMix->update(false) ; 
+
+		// now DfShMix has all the deferred render stuff mixed onto it, as well as emissive stuff, 
+		// and it's ready for forward rendered shadowing lights to be additively blended over it.
+	} // end if deferred render active
+
+
+
+	
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// 
+	// forward rendered shadowing spotlights
+	//
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// we now add entities from m_pVisibleEntity instead of m_pFrustumEntity since entities outside the frustum might still contribute shadows.
+	//''
+	if(true)
+	{
+
+
+		// multiple attempts at getting additive blending of the shadows failed, so I have to do an extra pass to "accumulate" the data :(
+
+		int nMaxVisibleLight=*m_pGlobal_MaxVisibleLight ;
+
+		// the texture view projection per light.  We use four Vector4 instead of a single Matrix4 because we have to pass them to the shaders as custom params
+		Ogre::Vector4	tvpMat0 ;
+		Ogre::Vector4	tvpMat1 ;
+		Ogre::Vector4	tvpMat2 ;
+		Ogre::Vector4	tvpMat3 ;
+
+
+
+		int nVisibleLight=0 ;
+		int nLt=0 ;
+		int nProjector=0 ;
+		int nEntLtIndex=0 ;
+		int nEntLtIndexMax=0 ;
+
+		m_nVisibleLightCount=0 ; // total shadow lights added from all loops 
+
+
+		miniScreen_DfShMaster->setMaterial("Mix_ShadowLights") ;
+		
+		
+		// loop through shadow casting lights
+		for(nVisibleLight=0 ; nVisibleLight<nMaxVisibleLight ; nVisibleLight++)
+		{
+			 // copy the camera's original settings because we'll be modifying it
+			m_pCameraCopy->synchroniseBaseSettingsWith(m_pCamera) ;
+
+			nLt=m_pGlobal_VisibleLightList[nVisibleLight] ;
+
+			// setup the light and light's shadow camera, skip if light isn't really visible
+			if(SetupSingleVisibleLightAndShadowCamera(nLt, m_pGlobal_LightVis, m_pGlobal_VisibleLightList, m_pCamera))
+			{
+				// count the light
+				m_nVisibleLightCount++ ;
+				
+				
+
+				
+				/////////////////////////////////////////////////////////////////////////////////////////////////////
+				// Render the shadow map
+
+				// add all the opaque stuff
+				m_pSceneMgr->getRootSceneNode()->removeAllChildren() ; 
+				SetZoneNodeAttachments(m_uVisibleZoneListL, &m_nMaxVisibleZoneL, MAT_OPAQUE) ; 
+
+				
+				for(nVisEnt=0 ; nVisEnt<m_nMaxVisibleEntity ; nVisEnt++)
+				{
+					// check if this entity touches this light
+					nEntity=m_pVisibleEntity[nVisEnt] ;
+					
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pEntityInfo[ nEntity ].pMasterNode) ;
+
+					nEntLtIndexMax=m_pEntityInfo[nEntity].Light[INDEX_LIGHTPERENTITY] ;
+					m_pEntityInfo[nEntity].LightTouch=0 ; // default, doesn't touch this light, use black material
+					for(nEntLtIndex=0 ; nEntLtIndex<nEntLtIndexMax ; nEntLtIndex++)
+						if(m_pEntityInfo[nEntity].Light[nEntLtIndex]==nLt) // found a match, entity is touched by this light
+						{
+							m_pEntityInfo[nEntity].LightTouch=1 ; // touches this light, don't use black
+							break ;
+						}
+
+				}// end for nVisEnt
+				
+
+
+
+
+
+
+				// change to shadow pass material
+				for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+				{
+					nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+					nZGStart	=	m_nZoneMOStart[nZone] ;
+					nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+						
+					for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+						if(m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE)
+						{
+							pEntity=m_pZoneEntity[nMO] ;
+							pEntity->setMaterial( m_pZoneEntityMaterial_Shadow[nMO] ) ;
+						}// end for entities
+
+				}// end for zonelist
+
+				for(nVisEnt=0 ; nVisEnt<m_nMaxVisibleEntity ; nVisEnt++)
+				{
+					nEntity=m_pVisibleEntity[nVisEnt] ;
+					nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+					// set the entity material
+					for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+						if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE)
+							m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_Shadow[nSubMesh] ) ;
+						else
+							m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setVisible(false) ; // non-opaque stuff is invisible
+				}
+
+
+				// render the shadow map out to the Shadow texture
+				renderTexture_Shadow->update(true) ;
+
+				// Opaque nodes are already in the scene, add all the Transparent stuff
+				SetZoneNodeAttachments(m_uVisibleZoneListL, &m_nMaxVisibleZoneL, MAT_GEL) ; 
+
+				// if this light is flagged as needing colourized shadows, we do the slower shadow method
+				// this means rendering an extra couple of coloured shadow maps here, plus a different material for the view render
+				if(m_nColouredShadow)
+				{
+					
+					/////////////////////////////////////////////////////////////////////////////////////////////////////
+					// Render the ShadeFront map
+
+					
+
+					// change to shadow pass material
+					for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+					{
+						nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+						nZGStart	=	m_nZoneMOStart[nZone] ;
+						nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+							
+						for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+							if((m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE) || (m_pZoneEntityMaterialType[nMO]==MAT_GEL))
+							{
+								pEntity=m_pZoneEntity[nMO] ;
+								pEntity->setMaterial( m_pZoneEntityMaterial_ShadeFront[nMO] ) ;
+							}// end for entities
+
+					}// end for zonelist
+
+					for(nVisEnt=0 ; nVisEnt<m_nMaxVisibleEntity ; nVisEnt++)
+					{
+						nEntity=m_pVisibleEntity[nVisEnt] ;
+						nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+						// set the entity material (pClearMaterial is already set)
+						for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+							if((m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE) || (m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GEL))
+							{
+								// make gel stuff visible
+								if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GEL)
+									m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setVisible(true) ;
+
+								m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_ShadeFront[nSubMesh] ) ;
+							}
+					}
+
+					// render the shadow map out to the Shadow texture
+					renderTexture_ShadeFront->update(true) ;
+
+					
+					/////////////////////////////////////////////////////////////////////////////////////////////////////
+					// Render the ShadeBack map
+
+					// change to shadow pass material
+					for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+					{
+						nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+						nZGStart	=	m_nZoneMOStart[nZone] ;
+						nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+							
+						for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+							if((m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE) || (m_pZoneEntityMaterialType[nMO]==MAT_GEL))
+							{
+								pEntity=m_pZoneEntity[nMO] ;
+								pEntity->setMaterial( m_pZoneEntityMaterial_ShadeBack[nMO] ) ;
+							}// end for entities
+
+					}// end for zonelist
+
+					for(nVisEnt=0 ; nVisEnt<m_nMaxVisibleEntity ; nVisEnt++)
+					{
+						nEntity=m_pVisibleEntity[nVisEnt] ;
+						nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+						// set the entity material (pClearMaterial is already set)
+						for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+							if((m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE) || (m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GEL))
+								m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_ShadeBack[nSubMesh] ) ;
+					}
+
+					// render the shadow map out to the Shadow texture
+					renderTexture_ShadeBack->update(true) ;
+					
+				} // end if we need coloured shadows
+
+
+	
+
+
+
+
+				/////////////////////////////////////////////////////////////////////////////////////////////////////
+				// Apply the shadow map to the view
+
+				// calculate the texture view projection matrix for this light
+				Matrix4 TexViewProj=CreateTextureViewProjectionMatrix(m_pCamera) ;
+
+				// change the matrix to four Vector4s so we can pass it in as a shader parameter 
+				tvpMat0[0]=TexViewProj[0][0] ; tvpMat0[1]=TexViewProj[0][1] ; tvpMat0[2]=TexViewProj[0][2] ; tvpMat0[3]=TexViewProj[0][3] ;
+				tvpMat1[0]=TexViewProj[1][0] ; tvpMat1[1]=TexViewProj[1][1] ; tvpMat1[2]=TexViewProj[1][2] ; tvpMat1[3]=TexViewProj[1][3] ;
+				tvpMat2[0]=TexViewProj[2][0] ; tvpMat2[1]=TexViewProj[2][1] ; tvpMat2[2]=TexViewProj[2][2] ; tvpMat2[3]=TexViewProj[2][3] ;
+				tvpMat3[0]=TexViewProj[3][0] ; tvpMat3[1]=TexViewProj[3][1] ; tvpMat3[2]=TexViewProj[3][2] ; tvpMat3[3]=TexViewProj[3][3] ;
+
+				// put the camera back to its proper position and settings.
+				m_pCamera->synchroniseBaseSettingsWith(m_pCameraCopy) ;
+				m_pCamera->setFOVy( Degree(m_flFOV) ) ;
+				m_pCamera->setAspectRatio( Real(m_flAspectRatio) );
+
+
+				nProjector=m_Q3Map->m_pLight[nLt].Texture ; // what projector texture is this light using?
+
+				// change material and set all the tvp custom params
+				for(nZoneList=0 ; nZoneList<nMaxVisibleZone ; nZoneList++)
+				{
+					nZone=m_pGlobal_VisibleZoneList[nZoneList] ;
+					nZGStart	=	m_nZoneMOStart[nZone] ;
+					nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+						
+					for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+						if((m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE) || (m_pZoneEntityMaterialType[nMO]==MAT_GEL))
+						{
+							pEntity=m_pZoneEntity[nMO] ;
+
+
+							// since the spot light pass is one of the slowest, we set the material of all the zones that don't touch
+							// this light to just a black material.  Only the zone of this light gets the real lighting material
+							// We need to have the other zones though or we end up seeing through walls.
+							// ALSO don't set gels to black, or else they block out the light in other zones.
+
+							
+							if((m_pZoneEntityMaterialType[nMO]==MAT_GEL) || (LightTouchesZone(nLt, nZone)) )
+							{
+								if(m_nColouredShadow)
+									pEntity->setMaterial( m_pZoneEntityMaterial_Base[nProjector][nMO] ) ; // coloured shadows
+								else
+									pEntity->setMaterial( m_pZoneEntityMaterial_Fast[nProjector][nMO] ) ; // fast shadows
+							}
+							else
+								pEntity->setMaterial( m_pZoneEntityMaterial_Black[nMO] ) ; // just flat black, alpha tested for some
+
+
+							
+				
+
+							// set the custom parameter, our texture view projection matrix for this light
+							pEntity->getSubEntity(0)->setCustomParameter(0, tvpMat0) ;
+							pEntity->getSubEntity(0)->setCustomParameter(1, tvpMat1) ;
+							pEntity->getSubEntity(0)->setCustomParameter(2, tvpMat2) ;
+							pEntity->getSubEntity(0)->setCustomParameter(3, tvpMat3) ;
+
+							pEntity->getSubEntity(0)->setCustomParameter(4, TexParam) ;
+
+						}// end for entities
+
+				}// end for zonelist
+
+				for(nVisEnt=0 ; nVisEnt<m_nMaxVisibleEntity ; nVisEnt++)
+				{
+					nEntity=m_pVisibleEntity[nVisEnt] ;
+					nMaxSubMesh=m_pEntityInfo[nEntity].MaxSubMesh ;
+
+					// set the entity material
+					for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+						if((m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_OPAQUE) || (m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GEL))
+						{
+
+							// if it's gel or the light touches the entity, use proper material, else use black
+							if((m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GEL) || m_pEntityInfo[nEntity].LightTouch)
+							{
+								if(m_nColouredShadow)
+									m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_Base[nProjector][nSubMesh] ) ; // coloured shadows
+								else
+									m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_Fast[nProjector][nSubMesh] ) ; // fast shadows
+							}
+							else
+								m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( m_pEntityInfo[nEntity].Material_Black[nSubMesh] ) ; // flat black
+
+
+
+							// set the custom parameter, our texture view projection matrix for this light
+								m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setCustomParameter(0, tvpMat0) ;
+								m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setCustomParameter(1, tvpMat1) ;
+								m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setCustomParameter(2, tvpMat2) ;
+								m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setCustomParameter(3, tvpMat3) ;
+
+								m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setCustomParameter(4, TexParam) ;
+						}
+						else
+								m_pEntityInfo[nEntity].pEnt->getSubEntity(nSubMesh)->setMaterial( pClearMaterial ) ;
+				}
+
+
+
+
+				// if this is the first visible light, add emmissive transparent/alphablend particles.  
+				// they are added here so that they render correctly according to gels.
+				// But since they aren't shadowed, we only need render them for one light.
+				if(m_nVisibleLightCount==1)
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pParticleNode) ; // attach the particles
+
+
+
+				/////////////////////////////////////////////////////////////////////////////////////////////
+				// render the scene out to the DfShTemp texture.
+				//
+
+				renderTexture_DfShTemp->update(true) ; 
+
+				//
+				/////////////////////////////////////////////////////////////////////////////////////////////
+				
+				
+				
+				// remove the particles
+				if(m_nVisibleLightCount==1)
+					m_pSceneMgr->getRootSceneNode()->removeChild(m_pParticleNode) ;
+
+
+				///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+				// Render Mix
+
+				//?? unfortunately Ogre shares depth buffers in a manner that won't allow us to just additively render to DfShMix.
+				// If we try, we get glitching from the buffer sharing between Shadow and DfShMix.
+				// So instead we get rid of all geometry and additively render a fullscreen quad of DfShTemp to DfShMix.
+				// Slows things down a little, but at least it works.
+
+				// get rid of all the scene geometry
+				m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+
+				// put up a fullscreen quad so DfShMix has some UV coordinates.
+				m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShMaster) ;
+
+				// update DfShMix, but don't swap buffers yet since we may be back again next loop with more lights to add.
+				renderTexture_DfShMix->update(false) ; 
+
+			}// end if light is visible
+
+
+		}// end for nVisibleLight
+			
+	}// end if forward render active
+
+	///////////////////////////////////////////////////////////////////////////////////////
+
+
+
+	// after we've finished with all the lights and mixing, time to swap the mix buffer
+	renderTexture_DfShMix->swapBuffers(false) ;
+
+	
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// 
+	// HDR bloom
+	//
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	
+	if(m_nRenderHDR)
+	{
+		/////////////////////////////////////////////////////////
+		// copy DfShMix to BlurA
+
+		// get rid of all the scene geometry
+		m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+
+		// this shader renders DfShMix onto a surface 
+		miniScreen_DfShMaster->setMaterial("HDR_MixToBlurA") ; 
+
+		// put up a fullscreen quad so BlurA has some UV coordinates.
+		m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShMaster) ;
+
+		// render DfShMix to BlurA
+		renderTexture_BlurA->update(true) ;
+
+		
+
+
+		//////////////////////////////////////////////////////////////
+		// now we do a few rounds of ping-pong bluring of A to B, B to A.
+		int nMaxBlur=4 ;
+//		int nLastBlur=nMaxBlur-1 ;
+		int nBlurLoop=0 ;
+
+		
+		// opengl and direct3d give different results for the same blur shader, 
+		// the issue is that d3d with bilinear filtering will offset stuff, 
+		// leading to a right-down drift that we need to compensate for.
+		// So we need two versions of the blur shaders, one for ogl and one for d3d.
+
+		if(m_IsOpenGL)
+		{
+			miniScreen_BlurA->setMaterial("HDR_BlurA_ogl");
+			miniScreen_BlurB->setMaterial("HDR_BlurB_ogl");
+		}
+		else
+		{
+			miniScreen_BlurA->setMaterial("HDR_BlurA_d3d");
+			miniScreen_BlurB->setMaterial("HDR_BlurB_d3d");
+		}
+
+				
+		// the main blur
+		for(nBlurLoop=0 ; nBlurLoop<nMaxBlur ; nBlurLoop++)
+		{
+			// blur A onto B
+			m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+			m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_BlurA) ;
+			renderTexture_BlurB->update(true) ;
+
+			// blur B onto A
+			m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+			m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_BlurB) ;
+			renderTexture_BlurA->update(true) ;
+		}
+		
+
+		// If I don't set these materials back to their originals, I get a crash on exit. 
+		// Not sure why.  Something to do with deleting the originals?
+		// Doesn't matter, this fixes things.
+
+		miniScreen_BlurA->setMaterial("RttMat_BlurA");
+		miniScreen_BlurB->setMaterial("RttMat_BlurB");
+		
+		
+
+		//////////////////////////////////////////////////////////////////
+		// blend BlurA onto DfShMix
+
+		// get rid of all the scene geometry
+		m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+
+		// this shader blends BlurA onto a surface
+		if(m_IsOpenGL)
+			miniScreen_DfShMaster->setMaterial("HDR_BlurAToMix_ogl") ;
+		else
+			miniScreen_DfShMaster->setMaterial("HDR_BlurAToMix_d3d") ;
+
+		// put up a fullscreen quad so DfShMix has some UV coordinates.
+		m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShMaster) ;
+
+		// update DfShMix.
+		renderTexture_DfShMix->update(true) ;
+
+	}// end if HDR
+	
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// 
+	// display a rendered window
+	//
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	
+	m_pSceneMgr->getRootSceneNode()->removeAllChildren() ; // remove all the objects
+	
+	
+	if(m_nGoggleMode==GOGGLE_MODE_OFF) // stereo rendering not active
+	{
+		switch(m_nDisplayInfoMode)
+		{
+
+			case 0:	m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShMix) ; break ;
+			case 1:	m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShTemp) ; break ; // for wireframe view
+			case 2:	m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShLamp) ; break ;
+			case 3:	m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_BlurA) ; break ;
+
+			case 4: // instead of showing the original position texture, we show a scaled version, since the original is outside 0-1 range
+
+				// get rid of all the scene geometry
+				m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+
+				// this shader renders DfShMix onto a surface 
+				miniScreen_DfShMaster->setMaterial("Mix_ScalePosition") ; 
+
+				// put up a fullscreen quad so BlurA has some UV coordinates.
+				m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShMaster) ;
+
+				// render DfShPostion to DfShMix
+				renderTexture_DfShMix->update(true) ;
+
+				// display mix, which is a scaled copy of position.
+				m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShMix) ;
+				break ;
+			
+			case 5:	m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShFuncTNB) ; break ;
+			case 6:	m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShDiffuse) ; break ;
+			case 7:	m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShSpecular) ; break ;			
+			case 8:	m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShEmissive) ; break ;
+		}
+
+
+
+
+		
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShPosition) ;
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShFuncTNB) ;
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShSpecular) ;
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShDiffuse) ;
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShEmissive) ;
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShData) ;
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShLamp) ;
+
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_BlurA) ;
+
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShMix) ;
+		
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_Shadow) ;
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShTemp) ;
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_ShadeBack) ;
+		//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_ShadeFront) ;
+	}
+	else
+	{
+		// add and position the Goggles
+		m_pSceneMgr->getRootSceneNode()->addChild(m_pNodeGoggles) ;
+		m_pNodeGoggles->setOrientation( m_pCamera->getOrientation() ) ;
+		m_pNodeGoggles->setPosition( m_pCamera->getPosition() ) ;
+	}
+
+	
+	//m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+	//m_pSceneMgr->getRootSceneNode()->addChild(miniScreenNode_DfShDiffuse) ;
+	
+	
+	m_pRenderWnd->update(true) ;
+
+
+	//m_pSceneMgr->getRootSceneNode()->removeChild(miniScreenNode_DfShSpecular) ;
+	m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+
+	
+
+
+	///////////////////////////////////////////
+	// blittomemory experiment
+	//uchar pixelData[64] ;
+	//RTT_Texture_DfShPosition->getBuffer()->blitToMemory( Box( 0, 0, 1, 1), PixelBox(2, 2, 1, PF_FLOAT16_RGB, (void*)pixelData) ) ;
+
+
+}
+
+// generate the texture view Projection matrix used in shadow mapping
+Ogre::Matrix4 OgreFramework::CreateTextureViewProjectionMatrix(Ogre::Camera* pCamera)
+{
+
+	const Matrix4 PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE(
+		      0.5,    0,    0,  0.5,
+			    0,   -0.5,    0,  0.5,
+				  0,      0,    1,    0,
+					0,      0,    0,    1);
+
+	Matrix4 TexViewProj = PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE * pCamera->getProjectionMatrixWithRSDepth() * pCamera->getViewMatrix();
+
+	return TexViewProj ;
+
+}
+
+void OgreFramework::DestroyGoggles()
+{
+	//m_pGoggleL->~ManualObject() ;
+	//m_pGoggleR->~ManualObject() ;
+
+	//m_pNodeGoggles->~SceneNode() ;
+	
+
+}
+
+// create the "virtual" virtual reality goggles we use to get around stereoscopic driver problems.
+int OgreFramework::CreateGoggles()
+{
+
+	
+	float flMinX=0.0f ;
+	float flMinY=0.0f ;
+	float flMaxX=0.0f ;
+	float flMaxY=0.0f ;
+
+
+	// if they already exist, destroy them so we can recreate them
+	if(m_pNodeGoggles!=NULL)	m_pNodeGoggles->detachAllObjects() ;
+	if(m_pGoggleL!=NULL)			m_pGoggleL->clear() ;
+	if(m_pGoggleR!=NULL)			m_pGoggleR->clear() ;
+	
+
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// left goggle
+
+		if(m_pGoggleL==NULL) m_pGoggleL=m_pSceneMgr->createManualObject("GoggleL") ;
+		m_pGoggleL->begin("RttMat_DfShMix", RenderOperation::OT_TRIANGLE_LIST) ;
+	
+		flMinX=-100*m_flGoggleAspectRatio*m_flGoggleXScale ;
+		flMinY=-50*m_flGoggleYScale ;
+
+
+		flMaxX=0 ;
+		flMaxY=50*m_flGoggleYScale ;
+
+		
+		m_pGoggleL->position(flMinX-m_flGoggleXGap, flMaxY, m_flGoggleZPos) ;
+		m_pGoggleL->normal(0.0, 0.0, -1) ;
+		m_pGoggleL->textureCoord(0.0, 0.0) ;
+		m_pGoggleL->position(flMaxX-m_flGoggleXGap, flMaxY, m_flGoggleZPos) ;
+		m_pGoggleL->normal(0.0, 0.0, -1) ;
+		m_pGoggleL->textureCoord(1.0, 0.0) ;
+		m_pGoggleL->position(flMaxX-m_flGoggleXGap, flMinY, m_flGoggleZPos) ;
+		m_pGoggleL->normal(0.0, 0.0, -1) ;
+		m_pGoggleL->textureCoord(1.0, 1.0) ;
+		m_pGoggleL->position(flMinX-m_flGoggleXGap, flMinY, m_flGoggleZPos) ;
+		m_pGoggleL->normal(0.0, 0.0, -1) ;
+		m_pGoggleL->textureCoord(0.0, 1.0) ;
+
+		m_pGoggleL->quad(3, 2, 1, 0) ;
+		m_pGoggleL->end() ;
+
+		m_pGoggleL->setCastShadows(false) ;
+
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// right goggle
+
+		if(m_pGoggleR==NULL) m_pGoggleR=m_pSceneMgr->createManualObject("GoggleR") ;
+		m_pGoggleR->begin("RttMat_DfShMix", RenderOperation::OT_TRIANGLE_LIST) ;
+
+
+		flMinX=0 ;
+		flMinY=-50*m_flGoggleYScale ;
+
+
+		flMaxX=100*m_flGoggleAspectRatio*m_flGoggleXScale ;
+		flMaxY=50*m_flGoggleYScale ;
+
+		
+		m_pGoggleR->position(flMinX+m_flGoggleXGap, flMaxY, m_flGoggleZPos) ;
+		m_pGoggleR->normal(0.0, 0.0, -1) ;
+		m_pGoggleR->textureCoord(0.0, 0.0) ;
+		m_pGoggleR->position(flMaxX+m_flGoggleXGap, flMaxY, m_flGoggleZPos) ;
+		m_pGoggleR->normal(0.0, 0.0, -1) ;
+		m_pGoggleR->textureCoord(1.0, 0.0) ;
+		m_pGoggleR->position(flMaxX+m_flGoggleXGap, flMinY, m_flGoggleZPos) ;
+		m_pGoggleR->normal(0.0, 0.0, -1) ;
+		m_pGoggleR->textureCoord(1.0, 1.0) ;
+		m_pGoggleR->position(flMinX+m_flGoggleXGap, flMinY, m_flGoggleZPos) ;
+		m_pGoggleR->normal(0.0, 0.0, -1) ;
+		m_pGoggleR->textureCoord(0.0, 1.0) ;
+
+		m_pGoggleR->quad(3, 2, 1, 0) ;
+		m_pGoggleR->end() ;
+
+		m_pGoggleR->setCastShadows(false) ;
+		
+	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// attach the goggles to the node.
+	if(m_pNodeGoggles==NULL) m_pNodeGoggles=m_pSceneMgr->getRootSceneNode()->createChildSceneNode("NodeGoggles") ;
+	m_pNodeGoggles->attachObject(m_pGoggleL) ;
+	m_pNodeGoggles->attachObject(m_pGoggleR) ;
+
+	return 1 ;
+}
+
+// create the "virtual" virtual reality goggles we use to get around stereoscopic driver problems.
+// This version of the goggles just has a test image for setting up the correct real driver settings,
+// so that the left eye sees only the left "goggle" and the right eye only the right "goggle",
+// and the goggles have the right depth relative to the screen (flat to it)
+int OgreFramework::CreateGogglesTestImage() 
+{
+
+	float flMinX=0.0f ;
+	float flMinY=0.0f ;
+	float flMaxX=0.0f ;
+	float flMaxY=0.0f ;
+
+
+	// if they already exist, destroy them so we can recreate them
+	if(m_pNodeGoggles!=NULL)	m_pNodeGoggles->detachAllObjects() ;
+	if(m_pGoggleL!=NULL)			m_pGoggleL->clear() ;
+	if(m_pGoggleR!=NULL)			m_pGoggleR->clear() ;
+	
+
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// left goggle
+
+		if(m_pGoggleL==NULL) m_pGoggleL=m_pSceneMgr->createManualObject("GoggleL") ;
+		m_pGoggleL->begin("GoggleTest", RenderOperation::OT_TRIANGLE_LIST) ;
+	
+		flMinX=-100*m_flGoggleAspectRatio*m_flGoggleXScale ;
+		flMinY=-50*m_flGoggleYScale ;
+
+
+		flMaxX=0 ;
+		flMaxY=50*m_flGoggleYScale ;
+
+		
+		m_pGoggleL->position(flMinX-m_flGoggleXGap, flMaxY, m_flGoggleZPos) ;
+		m_pGoggleL->normal(0.0, 0.0, -1) ;
+		m_pGoggleL->textureCoord(0.0, 0.0) ;
+		m_pGoggleL->position(flMaxX-m_flGoggleXGap, flMaxY, m_flGoggleZPos) ;
+		m_pGoggleL->normal(0.0, 0.0, -1) ;
+		m_pGoggleL->textureCoord(1.0, 0.0) ;
+		m_pGoggleL->position(flMaxX-m_flGoggleXGap, flMinY, m_flGoggleZPos) ;
+		m_pGoggleL->normal(0.0, 0.0, -1) ;
+		m_pGoggleL->textureCoord(1.0, 1.0) ;
+		m_pGoggleL->position(flMinX-m_flGoggleXGap, flMinY, m_flGoggleZPos) ;
+		m_pGoggleL->normal(0.0, 0.0, -1) ;
+		m_pGoggleL->textureCoord(0.0, 1.0) ;
+
+		m_pGoggleL->quad(3, 2, 1, 0) ;
+		m_pGoggleL->end() ;
+
+		m_pGoggleL->setCastShadows(false) ;
+
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// right goggle
+
+		if(m_pGoggleR==NULL) m_pGoggleR=m_pSceneMgr->createManualObject("GoggleR") ;
+		m_pGoggleR->begin("GoggleTest", RenderOperation::OT_TRIANGLE_LIST) ;
+
+
+		flMinX=0 ;
+		flMinY=-50*m_flGoggleYScale ;
+
+
+		flMaxX=100*m_flGoggleAspectRatio*m_flGoggleXScale ;
+		flMaxY=50*m_flGoggleYScale ;
+
+		
+		m_pGoggleR->position(flMinX+m_flGoggleXGap, flMaxY, m_flGoggleZPos) ;
+		m_pGoggleR->normal(0.0, 0.0, -1) ;
+		m_pGoggleR->textureCoord(1.0, 1.0) ;
+		m_pGoggleR->position(flMaxX+m_flGoggleXGap, flMaxY, m_flGoggleZPos) ;
+		m_pGoggleR->normal(0.0, 0.0, -1) ;
+		m_pGoggleR->textureCoord(0.0, 1.0) ;
+		m_pGoggleR->position(flMaxX+m_flGoggleXGap, flMinY, m_flGoggleZPos) ;
+		m_pGoggleR->normal(0.0, 0.0, -1) ;
+		m_pGoggleR->textureCoord(0.0, 0.0) ;
+		m_pGoggleR->position(flMinX+m_flGoggleXGap, flMinY, m_flGoggleZPos) ;
+		m_pGoggleR->normal(0.0, 0.0, -1) ;
+		m_pGoggleR->textureCoord(1.0, 0.0) ;
+
+		m_pGoggleR->quad(3, 2, 1, 0) ;
+		m_pGoggleR->end() ;
+
+		m_pGoggleR->setCastShadows(false) ;
+		
+	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// attach the goggles to the node.
+	if(m_pNodeGoggles==NULL) m_pNodeGoggles=m_pSceneMgr->getRootSceneNode()->createChildSceneNode("NodeGoggles") ;
+	m_pNodeGoggles->attachObject(m_pGoggleL) ;
+	m_pNodeGoggles->attachObject(m_pGoggleR) ;
+
+	return 1 ;
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+bool OgreFramework::keyPressed(const OIS::KeyEvent &keyEventRef)
+{
+	//m_pLog->logMessage("OgreFramework::keyPressed");
+	
+	if(m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
+	{
+			m_bShutDownOgre = true;
+			return true;
+	}
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_SYSRQ))
+	{
+		std::ostringstream ss;
+		ss << "screenshot_" << ++m_iNumScreenShots << ".png";
+		m_pRenderWnd->writeContentsToFile(ss.str());
+		return true;
+	}
+
+	/*
+	if(m_pKeyboard->isKeyDown(OIS::KC_M))
+	{
+		static int mode = 0;
+		
+		if(mode == 2)
+		{
+			m_pCamera->setPolygonMode(PM_SOLID);
+			mode = 0;
+		}
+		else if(mode == 0)
+		{
+			 m_pCamera->setPolygonMode(PM_WIREFRAME);
+			 mode = 1;
+		}
+		else if(mode == 1)
+		{
+			m_pCamera->setPolygonMode(PM_POINTS);
+			mode = 2;
+		}
+	}
+	*/
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_O))
+	{
+		if(m_pDebugOverlay)
+		{
+			if(!m_pDebugOverlay->isVisible())
+				m_pDebugOverlay->show();
+			else
+				m_pDebugOverlay->hide();
+		}
+	}
+
+
+
+	return true;
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+bool OgreFramework::keyReleased(const OIS::KeyEvent &keyEventRef)
+{
+	return true;
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+bool OgreFramework::mouseMoved(const OIS::MouseEvent &evt)
+{
+	m_pCamera->yaw(Degree(evt.state.X.rel * -0.1));
+	m_pCamera->pitch(Degree(evt.state.Y.rel * -0.1));
+	
+	return true;
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+bool OgreFramework::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
+{
+	return true;
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+bool OgreFramework::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
+{
+	return true;
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+void OgreFramework::updateOgre(double timeSinceLastFrame)
+{
+
+
+
+
+	// update the game time
+	m_GameTime+=timeSinceLastFrame ;
+
+
+	m_MoveScale = m_MoveSpeed   * timeSinceLastFrame;
+	m_RotScale  = m_RotateSpeed * timeSinceLastFrame;
+		
+	m_TranslateVector = Vector3::ZERO;
+
+//	char chMessage[1024] ;
+	//sprintf(chMessage, "winmessage %u, %u, %u", m_pRenderWnd->m_Test_uMsg, (UINT)m_pRenderWnd->m_Test_wParam, (UINT)m_pRenderWnd->m_Test_lParam) ; 
+	//m_pLog->logMessage(chMessage) ;
+
+
+
+	/*
+	if((m_pRenderWnd->m_Test_uMsg==258) && (m_pRenderWnd->m_Test_wParam==0x78))
+	//if(GetAsyncKeyState(0x78))
+	{
+
+		m_TranslateVector.z = -m_MoveScale;
+		//m_nGotInput=1 ;
+		
+		//sprintf(chMessage, "T %i: winmessage %u, %u, %u", m_nTime, m_pRenderWnd->m_Test_uMsg, (UINT)m_pRenderWnd->m_Test_wParam, (UINT)m_pRenderWnd->m_Test_lParam) ; 
+		//m_pLog->logMessage(chMessage) ;
+	}
+	else
+		m_nGotInput=0 ;
+	*/
+
+	// add a test particle to the system
+	/*
+	if( m_ps->getNumParticles() < m_ps->getParticleQuota() )
+	{
+		Ogre::Particle *p = m_ps->createParticle() ;
+		p->setDimensions( m_ps->getDefaultWidth(), m_ps->getDefaultHeight() ) ;
+		p->colour = Ogre::ColourValue::White;
+		p->direction = Ogre::Vector3::UNIT_Y;
+		p->position = Ogre::Vector3::ZERO;
+		p->timeToLive = p->totalTimeToLive = 10;
+		p->rotation = Ogre::Radian(0);   
+		p->rotationSpeed = Ogre::Radian(0);
+	}
+	*/
+
+
+	m_ps->_update(timeSinceLastFrame/1000.0f) ;
+
+	getInput();
+
+	moveCamera();
+
+
+	//Ogre::Vector3 Pos ;
+	//float CamPos[3] ;
+	//Pos=m_pCamera->getPosition() ;
+	//CamPos[0]=Pos.x ;
+	//CamPos[1]=Pos.y ;
+	//CamPos[2]=Pos.z ;
+
+
+
+	if(m_nGoggleMode==GOGGLE_MODE_OFF)
+	{
+
+
+		m_pCameraCopy->synchroniseBaseSettingsWith(m_pCamera) ; // copy the camera's original settings because we'll be modifying it for the LR views.
+		m_pCameraCopy->setFOVy( Degree(m_flFOV) ) ;
+		m_pCameraCopy->setAspectRatio( Real(m_flAspectRatio) );
+
+
+
+		if(m_nMapLoaded)
+		{
+			SetupEntityZones() ;
+			
+			CalculateZoneVisibility(m_pCameraCopy, &m_nCameraZoneL, m_chZoneVisL, m_chLightVisL, m_chSubLightVisL, m_chPortalVisL, &m_nMaxVisibleLightL, m_uVisibleLightListL) ;
+			CalculateEntityVisibility(m_pCameraCopy, m_chZoneVisL) ;
+
+			UpdateVisibleZoneList(m_chZoneVisL, m_uVisibleZoneListL, &m_nMaxVisibleZoneL) ;
+
+			//m_nVisibleLightCount=m_nMaxVisibleLightL ;
+			m_nVisibleZoneCount=m_nMaxVisibleZoneL ;
+		}
+
+
+
+		m_pGlobal_VisibleZoneList=m_uVisibleZoneListL ;
+		m_pGlobal_MaxVisibleZone=&m_nMaxVisibleZoneL ;
+
+		m_pGlobal_VisibleLightList	=	m_uVisibleLightListL ;
+		m_pGlobal_MaxVisibleLight		=	&m_nMaxVisibleLightL ;
+		m_pGlobal_LightVis					=	m_chLightVisL ;
+
+
+	}
+	else
+	{
+		// "virtual" stereo goggle mode.  Render everything twice, L and R view, and output to L quad and a R quad.
+
+		m_pCameraCopy->synchroniseBaseSettingsWith(m_pCamera) ; // copy the camera's original settings because we'll be modifying it for the LR views.
+
+		if(m_nMapLoaded)
+		{
+			SetupEntityZones() ;
+
+			CalculateZoneVisibility(m_pCameraCopy, &m_nCameraZoneL, m_chZoneVisL, m_chLightVisL, m_chSubLightVisL, m_chPortalVisL, &m_nMaxVisibleLightL, m_uVisibleLightListL) ;
+			UpdateVisibleZoneList(m_chZoneVisL, m_uVisibleZoneListL, &m_nMaxVisibleZoneL) ;
+
+			
+			//m_nVisibleLightCount=m_nMaxVisibleLightL ;
+			m_nVisibleZoneCount=m_nMaxVisibleZoneL ;
+		}
+
+		m_pGlobal_VisibleZoneList=m_uVisibleZoneListL ;
+		m_pGlobal_MaxVisibleZone=&m_nMaxVisibleZoneL ;
+	}
+
+
+	updateStats();
+
+
+	//,,
+	//sprintf(m_chFrame, "End of updateOgre frame %i",m_nFrame) ;
+	//OFBug.LogAddCR(m_chFrame) ;
+	
+
+
+	m_nFrame++ ;
+
+
+	
+}
+
+
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+void OgreFramework::updateStats() 
+{ 
+	
+	
+	Ogre::Vector3 Pos ;
+	Pos=m_pCamera->getPosition() ;
+	Ogre::Real nCamX=Pos.x ;
+	Ogre::Real nCamY=Pos.y ;
+	Ogre::Real nCamZ=Pos.z ;
+
+
+	static String currFps = "FPS: "; 
+    static String avgFps = "Av FPS: "; 
+    static String bestFps = "Best FPS: "; 
+    static String worstFps = "Worst FPS: "; 
+    static String tris = "Triangle Count: "; 
+    static String batches = "Batch Count: "; 
+
+ 
+    OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps"); 
+    OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps"); 
+    OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps"); 
+    OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps"); 
+
+	const RenderTarget::FrameStats& stats = m_pRenderWnd->getStatistics();
+    
+		//int LastFrameTime=1000000/stats.lastFPS ;
+		float LastFrameTime=1000/stats.lastFPS ;
+
+
+
+
+
+		switch(m_nDisplayInfoMode)
+		{
+
+			case 0:
+				if(m_IsOpenGL)
+					guiCurr->setCaption("OGL FPS: " + StringConverter::toString(stats.lastFPS) +" "+StringConverter::toString(LastFrameTime)+" ms"); 
+				else
+					guiCurr->setCaption("D3D FPS: " + StringConverter::toString(stats.lastFPS) +" "+StringConverter::toString(LastFrameTime)+" ms"); 
+				break ;
+
+			case 1: guiCurr->setCaption("Wireframe") ; break ;
+			case 2: guiCurr->setCaption("Lamps") ; break ;
+			case 3: guiCurr->setCaption("HDR Blur") ; break ;
+			case 4: guiCurr->setCaption("DefShade Position (Scaled)") ; break ;
+			case 5: guiCurr->setCaption("DefShade Normals") ; break ;
+			case 6: guiCurr->setCaption("DefShade Diffuse") ; break ;
+			case 7: guiCurr->setCaption("DefShade Specular") ; break ;
+			case 8: guiCurr->setCaption("DefShade Emissive") ; break ;
+
+		}
+
+		guiAvg->setCaption("Lt: " + StringConverter::toString(m_nVisibleLightCount)
+			+ " Zn: " + StringConverter::toString(m_nVisibleZoneCount)  
+			+ " Cam: "+StringConverter::toString(nCamX)+" "+StringConverter::toString(nCamY)+" "+StringConverter::toString(nCamZ));
+
+
+
+
+		//m_flDebug0=m_nTotalTriangles ;
+		//m_flDebug1=m_nMaxVisibleEntity ;
+		//m_flDebug2=m_nMaxFrustumEntity ;
+		guiWorst->setCaption("ZnEnt: " + StringConverter::toString(m_nMaxVisibleEntity) + " Tri: " + StringConverter::toString(m_nVisibleEntityTriangleCount) + " FwdTri: " + StringConverter::toString(m_nVisibleEntityTriangleCount)    ) ;
+		guiBest->setCaption("FrEnt: " + StringConverter::toString(m_nMaxFrustumEntity) + " Tri: " + StringConverter::toString(m_nFrustumEntityTriangleCount) + " DefTri: " + StringConverter::toString(m_nFrustumEntityTriangleCount)    ) ;
+
+
+
+
+		//guiWorst->setCaption(StringConverter::toString(m_flDebug0) + " " + StringConverter::toString(m_flDebug1) + " " + StringConverter::toString(m_flDebug2)) ;
+		//guiBest->setCaption(StringConverter::toString(m_flDebug3) + " " + StringConverter::toString(m_flDebug4) + " " + StringConverter::toString(m_flDebug5)) ;
+		/*
+		guiWorst->setCaption(
+			" A "+StringConverter::toString(m_flDebugMatrix[0][0])+" "+StringConverter::toString(m_flDebugMatrix[0][1])+" "+StringConverter::toString(m_flDebugMatrix[0][2])+" "+StringConverter::toString(m_flDebugMatrix[0][3]) +
+			" B "+StringConverter::toString(m_flDebugMatrix[1][0])+" "+StringConverter::toString(m_flDebugMatrix[1][1])+" "+StringConverter::toString(m_flDebugMatrix[1][2])+" "+StringConverter::toString(m_flDebugMatrix[1][3]) ) ;
+
+		guiBest->setCaption(
+			" C "+StringConverter::toString(m_flDebugMatrix[2][0])+" "+StringConverter::toString(m_flDebugMatrix[2][1])+" "+StringConverter::toString(m_flDebugMatrix[2][2])+" "+StringConverter::toString(m_flDebugMatrix[2][3]) +
+			" D "+StringConverter::toString(m_flDebugMatrix[3][0])+" "+StringConverter::toString(m_flDebugMatrix[3][1])+" "+StringConverter::toString(m_flDebugMatrix[3][2])+" "+StringConverter::toString(m_flDebugMatrix[3][3]) ) ;
+		*/
+	
+		
+		
+		
+		//guiWorst->setCaption(StringConverter::toString(flVarA)+" "+StringConverter::toString(flVarB)+" "+StringConverter::toString(flVarC)+" "+StringConverter::toString(flVarD)
+   
+	//guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS) 
+  //          +" "+StringConverter::toString(stats.bestFrameTime)+" ms"); 
+	//guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS) 
+  //          +" "+StringConverter::toString(stats.worstFrameTime)+" ms"); 
+	
+	//guiWorst->setCaption(worstFps + StringConverter::toString(nCamX)+" " + StringConverter::toString(nCamY)+" " + StringConverter::toString(nCamZ)+" ") ;
+    
+	
+	OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris"); 
+	guiTris->setCaption("MpTri: " + StringConverter::toString(m_nTotalTriangles)); 
+
+	OverlayElement* guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches"); 
+    guiBatches->setCaption(batches + StringConverter::toString(stats.batchCount)); 
+
+	OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText"); 
+		guiDbg->setCaption("A:"+StringConverter::toString(m_nDebugA) + " B:" + StringConverter::toString(m_nDebugB) + " C:" + StringConverter::toString(m_nDebugC) + " ") ;
+	
+	//guiDbg->setCaption(
+	//	" A "+StringConverter::toString(m_flDebugMatrix[0][0])+" "+StringConverter::toString(m_flDebugMatrix[0][1])+" "+StringConverter::toString(m_flDebugMatrix[0][2])+" "+StringConverter::toString(m_flDebugMatrix[0][3]) +
+	//	" B "+StringConverter::toString(m_flDebugMatrix[1][0])+" "+StringConverter::toString(m_flDebugMatrix[1][1])+" "+StringConverter::toString(m_flDebugMatrix[1][2])+" "+StringConverter::toString(m_flDebugMatrix[1][3]) +
+	//	" C "+StringConverter::toString(m_flDebugMatrix[2][0])+" "+StringConverter::toString(m_flDebugMatrix[2][1])+" "+StringConverter::toString(m_flDebugMatrix[2][2])+" "+StringConverter::toString(m_flDebugMatrix[2][3]) +
+	//	" D "+StringConverter::toString(m_flDebugMatrix[3][0])+" "+StringConverter::toString(m_flDebugMatrix[3][1])+" "+StringConverter::toString(m_flDebugMatrix[3][2])+" "+StringConverter::toString(m_flDebugMatrix[3][3]) ) ;
+
+
+
+
+	//guiDbg->setCaption("");
+} 
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+void OgreFramework::moveCamera()
+{
+	if( m_nKeyDown_Ctrl && m_nKeyDown_Shift ) // super slow
+			m_pCamera->moveRelative(m_TranslateVector/50);
+		else
+			if(m_nKeyDown_Shift)	// fast
+				m_pCamera->moveRelative(m_TranslateVector*10);
+			else
+				if(m_nKeyDown_Ctrl) // slow 
+					m_pCamera->moveRelative(m_TranslateVector/5);
+				else
+					m_pCamera->moveRelative(m_TranslateVector*2); // normal
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+void OgreFramework::getInput()
+{
+	if(m_pKeyboard->isKeyDown(OIS::KC_LCONTROL))
+		m_nKeyDown_Ctrl=1 ;
+	else
+		m_nKeyDown_Ctrl=0 ;
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_LSHIFT))
+		m_nKeyDown_Shift=1 ;
+	else
+		m_nKeyDown_Shift=0 ;
+
+
+
+
+
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_A))
+	{
+		m_TranslateVector.x = -m_MoveScale;
+	}
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_D))
+	{
+		m_TranslateVector.x = m_MoveScale;
+	}
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_W))
+	{
+		m_TranslateVector.z = -m_MoveScale;
+		m_nGotInput=1 ;
+	}
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_S))
+	{
+		m_TranslateVector.z = m_MoveScale;
+	}
+
+
+	// generic toggle for debugging
+	if(m_pKeyboard->isKeyDown(OIS::KC_T))
+	{
+		if(m_nKeyToggle[OIS::KC_T]==0)
+		{
+			m_nKeyToggle[OIS::KC_T]=1 ; // toggle to stop key repeating
+			m_nToggle=1-m_nToggle ;
+			//OFBug.MessageInt(m_nToggle) ;
+		}
+	}
+	else
+		m_nKeyToggle[OIS::KC_T]=0 ;
+
+	//m_flDebug0=m_nKeyToggle[OIS::KC_T] ;
+	//m_flDebug1=m_nToggle ;
+
+	/*
+	if(m_pKeyboard->isKeyDown(OIS::KC_LEFT))
+	{
+		m_pCamera->yaw(m_RotScale);
+	}
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_RIGHT))
+	{
+		m_pCamera->yaw(-m_RotScale);
+	}
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_UP))
+	{
+		m_pCamera->pitch(m_RotScale);
+	}
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_DOWN))
+	{
+		m_pCamera->pitch(-m_RotScale);
+	}
+	*/
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////
+	//
+	// Stereo controls
+
+	
+
+	// toggle stereo test image mode
+	if(m_pKeyboard->isKeyDown(OIS::KC_DELETE))
+	{
+		if(m_nKeyToggle[OIS::KC_DELETE]==0)
+		{
+			m_nKeyToggle[OIS::KC_DELETE]=1 ; // toggle to stop key repeating
+			
+			m_nGoggleMode++ ; // cyle through the goggle modes
+			if(m_nGoggleMode>=GOGGLE_MODE_MAX)
+				m_nGoggleMode=GOGGLE_MODE_OFF ;
+
+			if(m_nGoggleMode==GOGGLE_MODE_TEST)
+				CreateGogglesTestImage() ; // create the test goggles
+			else
+				if(m_nGoggleMode==GOGGLE_MODE_ON)
+					CreateGoggles() ; // create the stereo goggles
+		}
+	}
+	else
+		m_nKeyToggle[OIS::KC_DELETE]=0 ;
+
+	if(m_nGoggleMode==GOGGLE_MODE_TEST) // controls for setting up the test image
+	{
+		int nDoPause=0 ; // if any control gets used we do a quick pause to make the rate of change a bit more consistent, not as frame-rate dependent
+
+		if(m_pKeyboard->isKeyDown(OIS::KC_PGUP))
+		{
+			nDoPause=1 ;
+
+			if(m_nKeyDown_Shift)
+				m_flGoggleZPos-=1.0 ;
+			else
+				if(m_nKeyDown_Ctrl)
+					m_flGoggleZPos-=0.01 ;
+				else
+					m_flGoggleZPos-=0.1 ;
+
+			CreateGogglesTestImage() ;
+		}
+
+		if(m_pKeyboard->isKeyDown(OIS::KC_PGDOWN))
+		{
+			nDoPause=1 ;
+
+			if(m_nKeyDown_Shift)
+				m_flGoggleZPos+=1.0 ;
+			else
+				if(m_nKeyDown_Ctrl)
+					m_flGoggleZPos+=0.01 ;
+				else
+					m_flGoggleZPos+=0.1 ;
+
+			CreateGogglesTestImage() ;
+		}
+
+		if(m_pKeyboard->isKeyDown(OIS::KC_HOME))
+		{
+			nDoPause=1 ;
+
+			if(m_nKeyDown_Shift)
+				m_flGoggleXGap-=0.1 ;
+			else
+				if(m_nKeyDown_Ctrl)
+					m_flGoggleXGap-=0.001 ;
+				else
+					m_flGoggleXGap-=0.01 ;
+
+			if(m_flGoggleXGap<0)
+				m_flGoggleXGap=0 ;
+
+			CreateGogglesTestImage() ;
+		}
+
+		if(m_pKeyboard->isKeyDown(OIS::KC_END))
+		{
+			nDoPause=1 ;
+
+			if(m_nKeyDown_Shift)
+				m_flGoggleXGap+=0.1 ;
+			else
+				if(m_nKeyDown_Ctrl)
+					m_flGoggleXGap+=0.001 ;
+				else
+					m_flGoggleXGap+=0.01 ;
+
+			if(m_flGoggleXGap<0)
+				m_flGoggleXGap=0 ;
+
+			CreateGogglesTestImage() ;
+		}
+
+		if(m_pKeyboard->isKeyDown(OIS::KC_UP))
+		{
+			nDoPause=1 ;
+
+			if(m_nKeyDown_Shift && m_nKeyDown_Ctrl)
+				m_flGoggleYScale=1.0 ;
+			else
+				if(m_nKeyDown_Shift)
+					m_flGoggleYScale+=0.002 ;
+				else
+					if(m_nKeyDown_Ctrl)
+						m_flGoggleYScale+=0.00002 ;
+					else
+						m_flGoggleYScale+=0.0002 ;
+
+				if(m_flGoggleYScale<0)
+					m_flGoggleYScale=0 ;
+
+				CreateGogglesTestImage() ;
+		}
+
+		if(m_pKeyboard->isKeyDown(OIS::KC_DOWN))
+		{
+			nDoPause=1 ;
+
+			if(m_nKeyDown_Shift && m_nKeyDown_Ctrl)
+				m_flGoggleYScale=1.0 ;
+			else
+				if(m_nKeyDown_Shift)
+					m_flGoggleYScale-=0.002 ;
+				else
+					if(m_nKeyDown_Ctrl)
+						m_flGoggleYScale-=0.00002 ;
+					else
+						m_flGoggleYScale-=0.0002 ;
+
+			if(m_flGoggleYScale<0)
+				m_flGoggleYScale=0 ;
+
+			CreateGogglesTestImage() ;
+		}
+
+		if(m_pKeyboard->isKeyDown(OIS::KC_LEFT))
+		{
+			nDoPause=1 ;
+
+			if(m_nKeyDown_Shift && m_nKeyDown_Ctrl)
+				m_flGoggleXScale=1.0 ;
+			else
+				if(m_nKeyDown_Shift)
+					m_flGoggleXScale+=0.002 ;
+				else
+					if(m_nKeyDown_Ctrl)
+						m_flGoggleXScale+=0.00002 ;
+					else
+						m_flGoggleXScale+=0.0002 ;
+
+			if(m_flGoggleXScale<0)
+				m_flGoggleXScale=0 ;
+
+			CreateGogglesTestImage() ;
+		}
+
+		if(m_pKeyboard->isKeyDown(OIS::KC_RIGHT))
+		{
+			nDoPause=1 ;
+
+			if(m_nKeyDown_Shift && m_nKeyDown_Ctrl)
+				m_flGoggleXScale=1.0 ;
+			else
+				if(m_nKeyDown_Shift)
+					m_flGoggleXScale-=0.002 ;
+				else
+					if(m_nKeyDown_Ctrl)
+						m_flGoggleXScale-=0.00002 ;
+					else
+						m_flGoggleXScale-=0.0002 ;
+
+			if(m_flGoggleXScale<0)
+				m_flGoggleXScale=0 ;
+
+			CreateGogglesTestImage() ;
+		}
+
+		
+
+		if(nDoPause) Sleep(20) ; // pause makes rate more consisent, less frame rate dependent.
+
+	}// end test image controls
+
+	
+
+	//
+	//
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// flashlight
+	if(m_pKeyboard->isKeyDown(OIS::KC_F))
+	{
+		if(m_nKeyToggle[OIS::KC_F]==0)
+		{
+			m_nKeyToggle[OIS::KC_F]=1 ; // toggle to stop key repeating
+			m_nFlashLight=1-m_nFlashLight ;
+			m_nDebugA=m_nFlashLight ;
+			//OFBug.MessageInt(m_nToggle) ;
+		}
+	}
+	else
+		m_nKeyToggle[OIS::KC_F]=0 ;
+
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_J))
+	{
+		if(m_nJumpToggle==0)
+		{
+			m_nJumpToggle=1 ;
+
+
+			m_nJumpVal++ ;
+			if(m_nJumpVal>=m_Q3Map->m_nLightMax)
+				m_nJumpVal=0 ;
+
+			//m_flDebug0=m_nJumpVal ;
+			
+			
+			//m_nJumpVal=12 ; // for now always jump to light 0
+			//m_pCamera->setPosition(m_Q3Map->m_pLight[m_nJumpVal].Position[0], m_Q3Map->m_pLight[m_nJumpVal].Position[1], m_Q3Map->m_pLight[m_nJumpVal].Position[2]) ;
+			//m_nJumpVal=13 ;
+			//m_pCamera->lookAt(Vector3(m_Q3Map->m_pLight[m_nJumpVal].Position[0], m_Q3Map->m_pLight[m_nJumpVal].Position[1], m_Q3Map->m_pLight[m_nJumpVal].Position[2]));
+			
+			//m_pCamera->setPosition(166, 222, -111) ;
+			//m_pCamera->setDirection(0.707, 0, -0.707) ;
+
+			//m_pCamera->setPosition(m_Q3Map->m_pLight[0].Position[0], m_Q3Map->m_pLight[0].Position[1], m_Q3Map->m_pLight[0].Position[2]) ;
+			//m_pCamera->setDirection(m_Q3Map->m_pLight[0].Direction[0], m_Q3Map->m_pLight[0].Direction[1], m_Q3Map->m_pLight[0].Direction[2]) ;
+			//m_pCamera->setFOVy( Degree(m_Q3Map->m_pLight[0].Angle ) ) ;
+
+			//m_pCamera->setDirection(m_pLight[m_nJumpVal].Direction[0], m_pLight[m_nJumpVal].Direction[1], m_pLight[m_nJumpVal].Direction[2]) ;
+			// 880 120 -340
+			//m_pCamera->lookAt(Vector3(880,120,-340));
+			//m_pCamera->lookAt(Vector3(915,155,-340));
+
+
+			m_pCamera->setPosition(600, 200, -250) ;
+			//m_pCamera->setDirection(1.0, 0.0, 0.0) ;
+			m_pCamera->lookAt(700, 200, -450);
+
+			
+
+		}
+	}
+	else
+		m_nJumpToggle=0 ;
+	
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_L))
+	{
+		if(m_nLoadToggle==0)
+		{
+			UnloadMap(false) ;
+			nMap++ ;
+			LoadMap() ;
+			//m_nLoadToggle=1 ;
+		}
+	}
+	else
+		m_nLoadToggle=0 ;
+
+
+		// generic toggle for debugging
+	if(m_pKeyboard->isKeyDown(OIS::KC_M))
+	{
+		if(m_nKeyToggle[OIS::KC_M]==0)
+		{
+			m_nKeyToggle[OIS::KC_M]=1 ; // toggle to stop key repeating
+
+			m_nDisplayInfoMode++ ;
+			if(m_nDisplayInfoMode==9)
+				m_nDisplayInfoMode=0 ;
+
+
+
+		}
+	}
+	else
+		m_nKeyToggle[OIS::KC_M]=0 ;
+
+
+
+
+
+	//if(m_pKeyboard->isKeyDown(OIS::KC_K)) m_nVideoRestart=1 ;
+
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_P))
+	{
+		if(m_nPortalToggle==0)
+		{
+			m_nPortalState=1-m_nPortalState ;
+			m_nPortalToggle=1 ;
+		}
+	}
+	else
+		m_nPortalToggle=0 ;
+
+	if(m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
+	{
+			m_bShutDownOgre = true;
+	}
+
+}
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+//shutdown
+// the dynamic memory deletes are all safe, so it's ok to try and delete them even if they don't exist.
+void OgreFramework::UnloadMap(bool bShutdown)
+{	
+
+	//if(!bShutdown) DestroyRTTAssets() ;
+
+	//if(ResourceGroupManager::getSingleton().isResourceGroupLoaded("Raw Bsp"))
+	//	ResourceGroupManager::getSingleton().clearResourceGroup("Raw Bsp") ; 
+
+
+	// only do if there was a definitely a map loaded.
+	if(m_nMapLoaded)
+	{
+		char chSceneNodeName[1024] ;
+		// make sure all the zone nodes are re-attached to the root node or they won't get deleted
+		for(int nZone=0 ; nZone<m_Q3Map->m_nMaxZone ; nZone++)
+		{
+			// Opaque nodes
+			if(m_nOpaqueNodeUsed[nZone]) // only do this if the node actually exists
+			{
+				if(!m_pOpaqueNode[nZone]->isInSceneGraph())
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pOpaqueNode[nZone]) ;
+
+				sprintf(chSceneNodeName, "Opaque%05i", nZone) ;
+				m_pSceneMgr->getRootSceneNode()->removeAndDestroyChild(chSceneNodeName) ;
+
+			}
+
+			// Trans nodes
+			if(m_nTransNodeUsed[nZone]) // only do this if the node actually exists
+			{
+				if(!m_pTransNode[nZone]->isInSceneGraph())
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pTransNode[nZone]) ;
+
+				sprintf(chSceneNodeName, "Trans%05i", nZone) ;
+				m_pSceneMgr->getRootSceneNode()->removeAndDestroyChild(chSceneNodeName) ;
+
+			}
+
+			// Lamp nodes
+			if(m_nLampNodeUsed[nZone]) // only do this if the node actually exists
+			{
+				if(!m_pLampNode[nZone]->isInSceneGraph())
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pLampNode[nZone]) ;
+
+				sprintf(chSceneNodeName, "Lamp%05i", nZone) ;
+				m_pSceneMgr->getRootSceneNode()->removeAndDestroyChild(chSceneNodeName) ;
+
+			}
+
+			// Glow nodes
+			if(m_nGlowNodeUsed[nZone]) // only do this if the node actually exists
+			{
+				if(!m_pGlowNode[nZone]->isInSceneGraph())
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pGlowNode[nZone]) ;
+
+				sprintf(chSceneNodeName, "Glow%05i", nZone) ;
+				m_pSceneMgr->getRootSceneNode()->removeAndDestroyChild(chSceneNodeName) ;
+
+			}
+
+		}
+
+
+		// reattach all entity scenenodes.
+		int nLoop=0 ;
+//		int nSubMesh=0 ;
+//		int nMaxSubMesh=0 ;
+		for(nLoop=0 ; nLoop<m_nMaxEntity ; nLoop++)
+			m_pSceneMgr->getRootSceneNode()->addChild(m_pEntityInfo[nLoop].pMasterNode) ;
+
+	}// end if map loaded
+
+
+	// free ogre stuff
+	//Ogre::ResourceGroupManager::getSingleton().clearResourceGroup(ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME) ;
+
+	//Ogre::ResourcePtr RTT=Ogre::TextureManager::getSingleton().getByName("RttTex") ;
+	//Ogre::TextureManager::getSingleton().remove(RTT) ;
+	
+	//RTT_Texture->unload() ;
+
+	
+
+
+	
+	
+
+	//m_pSceneMgr->clearScene() ;
+	m_pSceneMgr->getRootSceneNode()->removeAndDestroyAllChildren() ; // destroy all scenenodes
+	
+	m_pSceneMgr->destroyAllEntities() ;
+	m_pSceneMgr->destroyAllLights() ;
+	m_pSceneMgr->destroyAllManualObjects() ;
+	
+
+	/*
+	// unload all the meshes
+	int nMaxMesh=m_nZoneMOStart[m_Q3Map->m_nMaxZone] ;
+	int nMesh=0 ;
+	for(nMesh=0 ; nMesh<nMaxMesh ; nMesh++)
+	{
+		m_pSceneMgr->destroyEntity(m_pZoneEntity[nMesh]) ;
+		//m_pZoneMesh[nMesh]->cleanupDictionary() ;
+		//m_pZoneMesh[nMesh]->unload() ;
+
+
+	}
+	*/
+	
+	MeshManager::getSingleton().removeAll() ; // this destroys all the meshes
+
+	
+
+	//OFBug.MessageInt(333) ;
+	//Ogre::TextureManager::getSingleton().unloadAll() ;
+	//Ogre::TextureManager::getSingleton().removeAll() ;
+	
+	//Ogre::MaterialManager::getSingleton().unloadAll() ;
+	//Ogre::MaterialManager::getSingleton().removeAll() ;
+
+	
+
+
+
+	//SetupResourceLocations() ;
+
+	// delete our array of Zone group manual objects 
+	//CHECKDELETE_ARRAY( m_pZoneMO ) ;
+	CHECKDELETE_ARRAY( m_pZoneMesh, NEW_CHECK_m_pZoneMesh ) ; 
+	CHECKDELETE_ARRAY( m_pZoneEntity, NEW_CHECK_m_pZoneEntity  ) ; 
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterialType, NEW_CHECK_m_pZoneEntityMaterialType  ) ; 
+
+
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_Shadow, NEW_CHECK_m_pZoneEntityMaterial_Shadow  ) ; 
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_ShadeFront, NEW_CHECK_m_pZoneEntityMaterial_ShadeFront  ) ; 
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_ShadeBack, NEW_CHECK_m_pZoneEntityMaterial_ShadeBack  ) ; 
+
+	int nPTex=0 ;
+	for(nPTex=0 ; nPTex<MAX_PROJECTORTEX ; nPTex++)
+	{
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_Base[nPTex], NEW_CHECK_m_pZoneEntityMaterial_Base  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_Fast[nPTex], NEW_CHECK_m_pZoneEntityMaterial_Fast  ) ; 
+	}
+
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_Black, NEW_CHECK_m_pZoneEntityMaterial_Black  ) ; 
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShColour, NEW_CHECK_m_pZoneEntityMaterial_DfShColour  ) ; 
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShPosition, NEW_CHECK_m_pZoneEntityMaterial_DfShPosition  ) ; 
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShDiffuse, NEW_CHECK_m_pZoneEntityMaterial_DfShDiffuse  ) ; 
+	//CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DSNormal ) ;
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShFuncTNB, NEW_CHECK_m_pZoneEntityMaterial_DfShFuncTNB  ) ; 
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShSpecular, NEW_CHECK_m_pZoneEntityMaterial_DfShSpecular  ) ; 
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShEmissive, NEW_CHECK_m_pZoneEntityMaterial_DfShEmissive  ) ; 
+	//CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShData ) ;
+	CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShMix, NEW_CHECK_m_pZoneEntityMaterial_DfShMix  ) ; 
+
+	////////////////////////////////////////////////////////
+	CHECKDELETE_ARRAY( m_pEntityInfo, NEW_CHECK_m_pEntityInfo  ) ; 
+	CHECKDELETE_ARRAY( m_pVisibleEntity, NEW_CHECK_m_pVisibleEntity  ) ;
+	CHECKDELETE_ARRAY( m_pFrustumEntity, NEW_CHECK_m_pFrustumEntity  ) ;
+
+
+	// was leaking before, but this seems to have fixed things.
+	Ogre::ResourceGroupManager::getSingleton().clearResourceGroup(ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME) ;
+
+	// delete our debug light manualobjects/zones
+//	CHECKDELETE_ARRAY( m_pLightMO ) ;
+
+//	CHECKDELETE_ARRAY( m_pPortalMO ) ;
+//	CHECKDELETE_ARRAY( m_pPortalNode ) ;
+
+	// free our dynamic memory
+	if(m_Q3Map)
+	{
+		m_Q3Map->~Q3Map() ;		// get rid of all the m_Q3Map stuff
+		CHECKDELETE_POINTER( m_Q3Map, NEW_CHECK_m_Q3Map) ;  
+		m_Q3Map=NULL ;
+	}
+
+	if(m_bRawBspFileIsLoaded) 
+	{
+		//m_pRawBspFile->unload() ;
+		CHECKDELETE_ARRAY(m_pRawBspFile, NEW_CHECK_m_pRawBspFile ) ;  
+		m_bRawBspFileIsLoaded=false ;
+	}
+
+	// indicate that there is no map.
+	m_nMapLoaded=0 ;
+
+	
+
+	
+	int nCheck=0 ;
+	for(nCheck=0 ; nCheck<MAX_NEW_CHECK ; nCheck++)
+	if(m_nNewCheck[nCheck]!=0)
+	{
+		sprintf(m_chBug, "MEMORY LEAK: NewCheck %i, NewCount %i", nCheck, m_nNewCheck[nCheck]) ;
+		m_pLog->logMessage(m_chBug) ;
+	}
+
+
+		//OFBug.MessageInt(333) ;
+		//Sleep(50) ;
+}
+
+
+
+
+
+
+
+
+ /***********************************************************************************************************\
+                                               
+                                                 LOAD MAP 
+                                                
+ \***********************************************************************************************************/
+
+
+
+
+int OgreFramework::LoadMap(void)
+{	
+	m_pLog->logMessage("LoadMap.") ;
+
+
+
+	ZeroMemory((void*)m_nKeyToggle, sizeof(m_nKeyToggle)) ; // good place to clear the keytoggle just in case
+
+	m_pLog->logMessage("Pre InitAllResourceGroups.") ;
+	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();	
+	m_pLog->logMessage("Post InitAllResourceGroups.") ;
+
+	// setup the clear material
+	pClearMaterial=MaterialManager::getSingleton().getByName("Clear") ;
+
+	
+	//CreateRTTAssets() ;
+
+
+
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+		m_pDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
+		m_pDebugOverlay->show();
+
+		//m_MapName="test04e.bsp" ;
+		//m_MapName="test04g.bsp" ;
+		//m_MapName="test03f.bsp" ;
+
+		//m_MapName="testnew00a.bsp" ;
+		//m_MapName="test04gNew.bsp" ;
+
+		//m_MapName="test10a.bsp" ;
+		m_MapName="testmap06.bsp" ;
+		
+
+		//////////////////////////////////////////////////////////////////////////////////////////////////
+		// Load the file, get the data
+	
+
+
+		// open the stream to the bsp
+		Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(m_MapName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true);
+
+		// create memory to hold the bsp
+		size_t Size = stream->size() ;
+		m_pRawBspFile= new char[Size] ;
+		if( m_pRawBspFile==NULL) 
+			{ m_pLog->logMessage("Error loading map: Initial load out of memory.")			; UnloadMap(false) ; return 0 ; }
+		else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pRawBspFile]++ ; }
+
+		// stream bsp into memory
+		stream->read((void*)m_pRawBspFile, Size) ;
+
+		// close the stream, don't need it anymore
+		stream->close() ;
+		
+		// indicate that the raw bsp is loaded
+		m_bRawBspFileIsLoaded=true ;
+
+
+
+	
+
+		
+		//////////////////////////////////////////////////////////////////////////////////////////////////
+		// Setup Q3Map
+
+		m_Q3Map=new Q3Map();
+		if(m_Q3Map==NULL) 
+			{ m_pLog->logMessage("Error loading map: New Map.")			; UnloadMap(false) ; return 0 ; }
+		else
+			{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_Q3Map]++ ; }
+
+
+
+		m_pLog->logMessage("pre ParseMap") ;
+
+		// process the bsp, log errors and fail if needed.
+		switch(m_Q3Map->ParseAndTriangulateMap( m_pRawBspFile, Size ) )
+		{
+			case ERROR_ParseMap:						m_pLog->logMessage("Error loading map: Parse Map.") ;							UnloadMap(false) ; return 0 ;
+			case ERROR_ParseEntities:				m_pLog->logMessage("Error loading map: Parse Entities.") ;				UnloadMap(false) ; return 0 ;
+			case ERROR_AllocateVertex:			m_pLog->logMessage("Error loading map: Allocate Vertex.") ;				UnloadMap(false) ; return 0 ;
+			case ERROR_AllocateTriangle:		m_pLog->logMessage("Error loading map: Allocate Triangle.") ;			UnloadMap(false) ; return 0 ;
+			case ERROR_InitializeFaces:			m_pLog->logMessage("Error loading map: Initialize Faces") ;				UnloadMap(false) ; return 0 ;
+			case ERROR_ConvertFaces:				m_pLog->logMessage("Error loading map: Convert Faces.") ;					UnloadMap(false) ; return 0 ;
+			case ERROR_ConvertPatches:			m_pLog->logMessage("Error loading map: Convert Patches.") ;				UnloadMap(false) ; return 0 ;
+			case ERROR_ConvertTexLamp:			m_pLog->logMessage("Error loading map: Convert TexLamps.") ;			UnloadMap(false) ; return 0 ;
+			case ERROR_ConvertLamps:				m_pLog->logMessage("Error loading map: Convert Lamps.") ;					UnloadMap(false) ; return 0 ;
+			case ERROR_ConvertLampGlow:			m_pLog->logMessage("Error loading map: Convert Lamp Glow.") ;			UnloadMap(false) ; return 0 ;
+			case ERROR_ConvertLightGlow:		m_pLog->logMessage("Error loading map: Convert Light Glow.") ;		UnloadMap(false) ; return 0 ;
+			case ERROR_AssignTriangles:			m_pLog->logMessage("Error loading map: Assign Triangles") ;				UnloadMap(false) ; return 0 ;
+			case ERROR_SortTriangles:				m_pLog->logMessage("Error loading map: Sort Triangles") ;					UnloadMap(false) ; return 0 ;
+			case ERROR_SetupTransTextures:	m_pLog->logMessage("Error loading map: Setup Trans Textures") ;		UnloadMap(false) ; return 0 ;
+			case ERROR_SortGroups:					m_pLog->logMessage("Error loading map: Sort Groups") ;						UnloadMap(false) ; return 0 ;
+		}
+
+		m_pLog->logMessage("post ParseMap") ;
+
+		//////////////////////////////////////////////////////////////////////////////////////////////////
+		// use the triangles to build our zone/texture manualObjects, which make up the map
+		if(!ConstructMapFromTriangles()){ m_pLog->logMessage("Error loading map: Construct Map") ;		UnloadMap(false) ; return 0 ; }
+
+		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		// delete all the stuff that was only needed for parsing the bsp and converting it into manaulObjects.
+		m_Q3Map->FreeParseMem() ;
+	
+
+
+		
+
+		
+		
+		//////////////////////////////////////////////////////////////////////////////////////////////////
+		// Create the scenenodes for the zones and attach the manualObjects
+
+		int nZone=0 ;
+		char chSceneNodeName[1024] ;
+		int nMO=0 ;
+		int nZGStart=0 ;
+		int nZGEnd=0 ;
+
+		char chMessage[1024] ;
+		sprintf(chMessage, "Max Zones %i", m_Q3Map->m_nMaxZone) ; m_pLog->logMessage(chMessage) ;
+		for(nZone=0 ; nZone<m_Q3Map->m_nMaxZone ; nZone++)
+		{
+			//sprintf(chMessage, "Zone %i Top", nZone) ; m_pLog->logMessage(chMessage) ;
+
+
+			// create Opaque node if needed
+			if(m_nOpaqueNodeUsed[nZone])
+			{
+				sprintf(chSceneNodeName, "Opaque%05i", nZone) ;
+				m_pOpaqueNode[nZone]=m_pSceneMgr->getRootSceneNode()->createChildSceneNode(chSceneNodeName) ;
+			}
+
+			// create Trans node if needed
+			if(m_nTransNodeUsed[nZone])
+			{
+				sprintf(chSceneNodeName, "Trans%05i", nZone) ;
+				m_pTransNode[nZone]=m_pSceneMgr->getRootSceneNode()->createChildSceneNode(chSceneNodeName) ;
+			}
+
+			// create Lamp node if needed
+			if(m_nLampNodeUsed[nZone])
+			{
+				sprintf(chSceneNodeName, "Lamp%05i", nZone) ;
+				m_pLampNode[nZone]=m_pSceneMgr->getRootSceneNode()->createChildSceneNode(chSceneNodeName) ;
+			}
+
+			// create Glow node if needed
+			if(m_nGlowNodeUsed[nZone])
+			{
+				sprintf(chSceneNodeName, "Glow%05i", nZone) ;
+				m_pGlowNode[nZone]=m_pSceneMgr->getRootSceneNode()->createChildSceneNode(chSceneNodeName) ;
+			}
+
+			// get start and end of this zone's batches.  
+			// If there's none, the start and end will be the same. (don't have to worry about checking for m_pZoneMO[nZone]==NULL)
+			nZGStart	=	m_nZoneMOStart[nZone] ;
+			nZGEnd		=	m_nZoneMOStart[nZone+1] ;
+			
+			//sprintf(chMessage, "  Zone %i, ZGStart %i, ZGEnd %i", nZone, nZGStart, nZGEnd) ; m_pLog->logMessage(chMessage) ;
+
+			for(nMO=nZGStart ; nMO<nZGEnd ; nMO++)
+			{
+				//sprintf(chMessage, "    Zone %i, nMO %i", nZone, nMO) ; m_pLog->logMessage(chMessage) ;
+
+				// attach the entity to the appropriate node
+
+				if(m_pZoneEntityMaterialType[nMO]==MAT_OPAQUE)
+					m_pOpaqueNode[nZone]->attachObject( m_pZoneEntity[nMO] ) ;
+				else
+				if(m_pZoneEntityMaterialType[nMO]==MAT_GEL)
+					m_pTransNode[nZone]->attachObject( m_pZoneEntity[nMO] ) ;
+				else
+				if(m_pZoneEntityMaterialType[nMO]==MAT_LAMP)
+					m_pLampNode[nZone]->attachObject( m_pZoneEntity[nMO] ) ;
+				else
+				if(m_pZoneEntityMaterialType[nMO]==MAT_GLOW)
+					m_pGlowNode[nZone]->attachObject( m_pZoneEntity[nMO] ) ;
+			}
+
+		}
+
+
+		// add the game entities
+		if(!SetupGameEntities()) { m_pLog->logMessage("Error loading map: Setup Entities") ;		UnloadMap(false) ; return 0 ; }
+
+
+		// prior to the first frame, all zone scenenodes are detached.
+		m_pSceneMgr->getRootSceneNode()->removeAllChildren() ;
+
+		//////////////////////////////////////////////////////////////////////////////////////////////////////
+		// Setup the lights
+
+
+
+		
+		initLight() ; 
+
+		//if(m_nDebugLightBox)
+		//	AddLightCullingBoxes() ;
+
+
+		//if(m_nPortalDebug)
+		//	AddPortalBoxes() ;
+
+
+		///////////////////////////////////////////////////////////////////////////////////////////////////
+		// misc finalization of the map
+
+		m_nCameraZone=-1 ; // indicate that we need to look up the zone the player is in.
+		m_nCameraZoneL=-1 ;
+		m_nCameraZoneR=-1 ;
+
+		m_nMapLoaded=1 ; // map was loaded ok
+
+
+
+		// set the camera's start position here.
+		// I tried setting it during startup, but for some strange reason it didn't work IF the camera was in a zone 
+		// but was ok if the camera started outside a zone.  Bit of a mystery... but it makes more sense to set it here anyway.
+		m_pCamera->setPosition(Vector3(0, 0, 0));
+
+		if(m_Q3Map->m_nLightMax>0) // make sure there's at least one light before we point to it!
+			m_pCamera->lookAt(Ogre::Vector3(m_Q3Map->m_pLight[0].Position[0], m_Q3Map->m_pLight[0].Position[1], m_Q3Map->m_pLight[0].Position[2])) ;
+
+
+		
+
+		if(m_nGoggleMode==GOGGLE_MODE_TEST)
+				CreateGogglesTestImage() ; // create the test goggles
+			else
+				if(m_nGoggleMode==GOGGLE_MODE_ON)
+					CreateGoggles() ; // create the stereo goggles
+
+
+		SetupParticles() ;
+
+
+		m_pLog->logMessage("LoadMap bottom.") ;
+
+		// reset the game timer
+		m_GameTime=0.0 ;
+		m_nFrame=0 ;
+
+
+
+		//OFBug.MessageInt(m_nNewCount) ;
+
+		return 1 ;
+}
+
+//''
+int OgreFramework::SetupParticles()
+{
+			ParticleSystem::setDefaultNonVisibleUpdateTimeout(5);  // set nonvisible timeout
+
+		
+
+    // create some nice fireworks and place it at the origin
+    //m_ps = m_pSceneMgr->createParticleSystem("Fireworks", "particle/fallspark00");
+		m_ps = m_pSceneMgr->createParticleSystem("Fireworks", "particle/spark00");
+		m_pParticleNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("ParticleNode") ;
+		m_pParticleNode->attachObject(m_ps) ;
+
+		//m_pParticleNode->setPosition(360.0f, 360.0f, -860.0f) ;
+		m_pParticleNode->setPosition(586.0f, 228.0f, -520.0f) ;
+
+
+	return 1 ;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// take the sorted list of triangles and contruct our Zone manualObjects array, m_pZoneMO, etc
+// and setup all the materials.
+int OgreFramework::ConstructMapFromTriangles(void)
+{
+
+
+	int nVert=0 ;
+	int nMaxVertex=0 ;
+	
+	float flPosX=0.0f ;
+	float flPosY=0.0f ;
+	float flPosZ=0.0f ;
+	float	flNormX=0.0f ;
+	float	flNormY=0.0f ;
+	float	flNormZ=0.0f ;
+	float flTexU=0.0f ;
+	float flTexV=0.0f ;
+
+	float flLampPosX=0.0f ;
+	float flLampPosY=0.0f ;
+	float flLampPosZ=0.0f ;
+	float flLampBrightness=0.0f ;
+	float flLampR=0.0f ;
+	float flLampG=0.0f ;
+	float flLampB=0.0f ;
+
+	int nVertA=0 ;
+	int nVertB=0 ;
+	int nVertC=0 ;
+
+	char chMessage[1024] ;
+
+	int nZone=0 ;
+	char chManualName[1024] ; // name for manual objects we create
+	char chMeshName[1024] ;
+
+	int nTriangle=0 ;
+//	int nStart=0 ;
+	int nEnd=0 ;
+	int nMaterial=0 ;
+	int nGroup=0 ;
+	int nTri=0 ;
+	int nPos=0 ;
+
+	ZeroMemory((void*)m_nOpaqueNodeUsed, sizeof(m_nOpaqueNodeUsed)) ; // set all as unused
+	ZeroMemory((void*)m_nTransNodeUsed, sizeof(m_nTransNodeUsed)) ; // set all as unused
+	ZeroMemory((void*)m_nLampNodeUsed, sizeof(m_nLampNodeUsed)) ; // set all as unused
+	ZeroMemory((void*)m_nGlowNodeUsed, sizeof(m_nGlowNodeUsed)) ; // set all as unused
+	
+	char chMaterial_Base[1024] ;
+	MaterialPtr pMaterial_Base ; // used for checking if material scripts exist, and stored for the material switching that happens in deferred shading
+	
+	char chMaterial_Fast[1024] ;
+	MaterialPtr pMaterial_Fast ; // faster version of the base, mainly non-coloured shadowning.
+
+	char chMaterial_Black[1024] ;
+	MaterialPtr pMaterial_Black ; // just plain black, or black with alpha testing.
+
+	char chMaterial_DfShColour[1024] ;
+	MaterialPtr pMaterial_DfShColour ; // used for checking if material scripts exist, and stored for the material switching that happens in deferred shading
+	
+
+	char chMaterial_Shadow[1024] ;
+	MaterialPtr pMaterial_Shadow ;
+
+	char chMaterial_ShadeFront[1024] ;
+	MaterialPtr pMaterial_ShadeFront ;
+
+	char chMaterial_ShadeBack[1024] ;
+	MaterialPtr pMaterial_ShadeBack ;
+
+	char chMaterial_DfShPosition[1024] ;
+	MaterialPtr pMaterial_DfShPosition ;
+	
+	char chMaterial_DfShDiffuse[1024] ;
+	MaterialPtr pMaterial_DfShDiffuse ;
+	
+	//char chMaterial_DSNormal[1024] ;
+	//MaterialPtr pMaterial_DSNormal ;
+	
+	char chMaterial_DfShFuncTNB[1024] ;
+	MaterialPtr pMaterial_DfShFuncTNB ;
+
+	char chMaterial_DfShSpecular[1024] ;
+	MaterialPtr pMaterial_DfShSpecular ;
+
+	char chMaterial_DfShEmissive[1024] ;
+	MaterialPtr pMaterial_DfShEmissive ;
+
+	//char chMaterial_DfShData[1024] ;
+	//MaterialPtr pMaterial_DfShData ;
+
+	char chMaterial_DfShMix[1024] ;
+	MaterialPtr pMaterial_DfShMix ;
+
+	char chCompare[1024] ;
+
+	// for calculating bounds of mesh
+	float flMinX=0.0f ;
+	float flMinY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxX=0.0f ;
+	float flMaxY=0.0f ;
+	float flMaxZ=0.0f ;
+//	float flMidX=0.0f ;
+//	float flMidY=0.0f ;
+//	float flMidZ=0.0f ;
+	float flDisX=0.0f ;
+	float flDisY=0.0f ;
+	float flDisZ=0.0f ;
+	float flRadius=0.0f ;
+	AxisAlignedBox AABB ;
+	unsigned short src, dest; // for tangent vectors
+
+
+	// Work out how many manual objects we are going to need.  We need one for every group within every material within every zone.
+	// Groups tend to all be 0 except for transparent triangles which have different groups within the same material/zone,
+	// due to the need to sort and render transparent things in a specific depth order relative to the camera.
+
+
+	int nMOCount=0 ;
+	nMaterial=-1 ;
+	nZone=-1 ;
+	nGroup=-1 ;
+
+	// loop through all triangles to count how many manual objects we'll need.
+	for(nTri=0 ; nTri<m_Q3Map->m_nTriangleMax ; nTri++)
+	{
+		
+		if(m_Q3Map->m_pTriangle[nTri].Zone!=nZone) // found a new zone
+		{
+			nZone=m_Q3Map->m_pTriangle[nTri].Zone ; 
+			nMaterial=m_Q3Map->m_pTriangle[nTri].Texture ;
+			nGroup=m_Q3Map->m_pTriangle[nTri].Group ;
+			nMOCount++ ;
+		}
+		else
+			if(m_Q3Map->m_pTriangle[nTri].Texture!=nMaterial) // found a new material within the current zone
+			{
+				nMaterial=m_Q3Map->m_pTriangle[nTri].Texture ;
+				nGroup=m_Q3Map->m_pTriangle[nTri].Group ;
+				nMOCount++ ;
+			}
+			else
+				if(m_Q3Map->m_pTriangle[nTri].Group!=nGroup) // found a new group within the current material within the current zone
+				{
+					nGroup=m_Q3Map->m_pTriangle[nTri].Group ;
+					nMOCount++ ;
+				}
+
+	}// end for tri
+	
+
+
+	// create the manualobject array for our zones and materials
+	m_pZoneMO = new Ogre::ManualObject*[nMOCount] ;
+	if(m_pZoneMO==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneMO]++ ; }
+
+	m_pZoneMesh = new Ogre::MeshPtr[nMOCount] ;
+	if(m_pZoneMesh==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneMesh]++ ; }
+
+	// our entities for the meshes
+	m_pZoneEntity = new Ogre::Entity*[nMOCount] ;
+	if(m_pZoneEntity==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntity]++ ; }
+
+	// need to keep track of which entities are transparent
+	m_pZoneEntityMaterialType = new int[nMOCount] ;
+	if(m_pZoneEntityMaterialType==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterialType]++ ; }
+	ZeroMemory((void*)m_pZoneEntityMaterialType, nMOCount*sizeof(int)) ; // set all as non-transparent
+
+
+	int nPTex=0 ;
+	for(nPTex=0 ; nPTex<MAX_PROJECTORTEX ; nPTex++)
+	{
+		// our base materials for the meshes
+		m_pZoneEntityMaterial_Base[nPTex] = new Ogre::MaterialPtr[nMOCount] ;
+		if(m_pZoneEntityMaterial_Base[nPTex]==NULL) 
+			return 0 ; // fail, out of mem
+		else
+			{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_Base]++ ; }
+
+		// our fast materials for the meshes
+		m_pZoneEntityMaterial_Fast[nPTex] = new Ogre::MaterialPtr[nMOCount] ;
+		if(m_pZoneEntityMaterial_Fast[nPTex]==NULL) 
+			return 0 ; // fail, out of mem
+		else
+			{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_Fast]++ ; }
+	}
+
+	// our black materials for the meshes
+	m_pZoneEntityMaterial_Black = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_Black==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_Black]++ ; }
+
+	// our base materials for the meshes
+	m_pZoneEntityMaterial_DfShColour = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_DfShColour==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_DfShColour]++ ; }
+
+	// materials for the meshes
+	m_pZoneEntityMaterial_Shadow = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_Shadow==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_Shadow]++ ; }
+
+	// materials for the meshes
+	m_pZoneEntityMaterial_ShadeFront = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_ShadeFront==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_ShadeFront]++ ; }
+
+	// materials for the meshes
+	m_pZoneEntityMaterial_ShadeBack = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_ShadeBack==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_ShadeBack]++ ; }
+
+	// materials for the meshes
+	m_pZoneEntityMaterial_DfShPosition = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_DfShPosition==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_DfShPosition]++ ; }
+
+	// materials for the meshes
+	m_pZoneEntityMaterial_DfShDiffuse = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_DfShDiffuse==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_DfShDiffuse]++ ; }
+
+	// materials for the meshes
+	//m_pZoneEntityMaterial_DSNormal = new Ogre::MaterialPtr[nMOCount] ;
+	//if(m_pZoneEntityMaterial_DSNormal==NULL) return 0 ; // fail, out of mem
+
+	// materials for the meshes
+	m_pZoneEntityMaterial_DfShFuncTNB = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_DfShFuncTNB==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_DfShFuncTNB]++ ; }
+
+	// materials for the meshes
+	m_pZoneEntityMaterial_DfShSpecular = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_DfShSpecular==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_DfShSpecular]++ ; }
+
+	// materials for the meshes
+	m_pZoneEntityMaterial_DfShEmissive = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_DfShEmissive==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_DfShEmissive]++ ; }
+
+
+	// materials for the meshes
+	//m_pZoneEntityMaterial_DfShData = new Ogre::MaterialPtr[nMOCount] ;
+	//if(m_pZoneEntityMaterial_DfShData==NULL) return 0 ; // fail, out of mem
+
+	// materials for the meshes
+	m_pZoneEntityMaterial_DfShMix = new Ogre::MaterialPtr[nMOCount] ;
+	if(m_pZoneEntityMaterial_DfShMix==NULL) 
+		return 0 ; // fail, out of mem
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pZoneEntityMaterial_DfShMix]++ ; }
+
+
+	// memory for keeping track of re-assigned verts, since we only add verts to a manualobject if they are needed, we don't add every vertex
+	int* pVertIndex = new int [m_Q3Map->m_nVertexMax] ; // at most, there can be m_Q3Map->m_nVertexMax verts in a zone if the map is one big subzone.
+	if(pVertIndex==NULL) //{ CHECKDELETE_ARRAY( m_pZoneMO ) ; return 0 ; } // fail, out of mem
+		return 0 ;
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_pVertIndex]++ ; }
+
+
+
+
+
+	// go through all the zones and create their manualobjects in m_pZoneMO, one for each material
+	int nMOIndex=0 ;
+	for(nZone=0 ; nZone<m_Q3Map->m_nMaxZone ; nZone++)
+	{
+		m_nZoneTriangleCount[nZone]=0 ; // just for our stats
+
+
+		m_nZoneMOStart[nZone]=nMOIndex ; // record where we start from.
+
+		// because the triangles have been sorted in order of zone, if there are any triangles in this zone
+		// then nTriangle will already be on the first example.  However it could be there is a zone that contains
+		// no triangles.  If we have such an empty zone, we don't create any manual object for it and set its pointer
+		// to NULL.
+
+		if(m_Q3Map->m_pTriangle[nTriangle].Zone!=nZone)
+		{
+			m_pZoneMO[nMOIndex]=NULL ;
+			continue ;
+			//break ;
+		}
+
+		
+
+
+		// scan through all triangles in this zone
+		while((nTriangle<m_Q3Map->m_nTriangleMax) && (m_Q3Map->m_pTriangle[nTriangle].Zone==nZone))
+		{
+			
+
+			
+			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+			//
+			// start adding a begin/end block of all triangles in a zone with the same material/group
+			//
+			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+			
+			nMaterial=m_Q3Map->m_pTriangle[nTriangle].Texture ;
+			nGroup=m_Q3Map->m_pTriangle[nTriangle].Group ;
+			
+
+			
+
+			// create the zone's manualobject
+			sprintf(chManualName, "ZoneMO_%04i_%04i_%05i", nZone, nMaterial, nTriangle) ;
+			m_pZoneMO[nMOIndex]=m_pSceneMgr->createManualObject(chManualName) ;
+			
+			
+
+			// scan forward to find the end of this block of triangles with the same texture and group
+			nEnd=nTriangle+1 ;
+			while(
+								(nEnd<m_Q3Map->m_nTriangleMax) 
+							&&(m_Q3Map->m_pTriangle[nEnd].Zone==nZone)
+							&&(m_Q3Map->m_pTriangle[nEnd].Texture==nMaterial)
+							&&(m_Q3Map->m_pTriangle[nEnd].Group==nGroup)
+						)
+				nEnd++ ;
+
+			// copy the material name.
+			// q3 texture names are a max of 64 characters ( Q3NAMESIZE ) and may not be null terminated.  They have no extension either.
+			nPos=-1 ;
+			while((++nPos<Q3NAMESIZE) && (m_Q3Map->m_pTexture[nMaterial].name[nPos]!=' ') && (m_Q3Map->m_pTexture[nMaterial].name[nPos]!='\0'))
+				chMaterial_Base[nPos]=m_Q3Map->m_pTexture[nMaterial].name[nPos] ;
+
+			// make sure name is null terminated
+			chMaterial_Base[nPos]='\0' ;
+
+
+
+			//..
+
+			//if(strcmp(chMaterial_Base, "textures/common/exptex")==0) strcpy(chMaterial_Base, "GEL_ShinyGlassPlateTL") ; 
+			//if(strcmp(chMaterial_Base, "textures/common/exptex")==0) strcpy(chMaterial_Base, "GEL_DSC_Prototype") ; 
+			//if(strcmp(chMaterial_Base, "textures/common/exptex")==0) strcpy(chMaterial_Base, "GEL_DSC_Prototype") ; 
+			if(strcmp(chMaterial_Base, "textures/common/exptex")==0) strcpy(chMaterial_Base, "GEL_DSC_glassred") ; 
+			if(strcmp(chMaterial_Base, "textures/common/exptex2")==0) strcpy(chMaterial_Base, "GEL_GreyGlass") ; 
+			if(strcmp(chMaterial_Base, "textures/common/alphaplate")==0) strcpy(chMaterial_Base, "ALPHAPF_DSCE_Prototype") ;
+			//if(strcmp(chMaterial_Base, "textures/common/alphaplate")==0) strcpy(chMaterial_Base, "OPAQUE_DSC_SimplePlateB") ;
+			//if(strcmp(chMaterial_Base, "textures/common/alphaplate")==0) strcpy(chMaterial_Base, "ALPHAPF_DS_alphaplategreen") ;
+
+
+			
+			// if the material is a lamp material we need to specify either an OpenGl or Direct3D version
+			strcpy(chCompare, chMaterial_Base) ;
+			chCompare[12]='\0' ;
+			if(strcmp("lights/lamp_", chCompare)==0) // material is LAMP 
+			{
+				if(m_IsOpenGL)
+					strcat(chMaterial_Base, "_ogl") ;
+				else
+					strcat(chMaterial_Base, "_d3d") ;
+
+			}
+
+			strcpy(chCompare, chMaterial_Base) ;
+			chCompare[17]='\0' ;
+			if(strcmp("lights/lamp2pass_", chCompare)==0) // material is LAMP, 2 pass version 
+			{
+				if(m_IsOpenGL)
+					strcat(chMaterial_Base, "_ogl") ;
+				else
+					strcat(chMaterial_Base, "_d3d") ;
+			}
+			
+
+
+			// check that this material script exists, if not set to the default
+			pMaterial_Base=MaterialManager::getSingleton().getByName(chMaterial_Base) ;
+			if(pMaterial_Base.isNull())
+			{
+				strcat(chMaterial_Base, " *** MISSING ***") ;
+//				OFBug.LogAddCR(chMaterial_Base) ;
+				
+				//sprintf(chMessage, "Missing material, using default: %s", chMaterial_Base) ;
+				//m_pLog->logMessage(chMessage);
+
+				/*
+				switch(rand()%6)
+				{
+					case 0: strcpy(chMaterial_Base, "OPAQUE_DSC_Plate2x2A") ;					break ;
+					case 1: strcpy(chMaterial_Base, "OPAQUE_DSC_HexColourA") ;				break ;
+					case 2: strcpy(chMaterial_Base, "OPAQUE_DSC_SimplePlateB") ;			break ;
+					case 3: strcpy(chMaterial_Base, "OPAQUE_DSC_FloorA") ;						break ;
+					case 4: strcpy(chMaterial_Base, "OPAQUE_DSCE_WallTrimUD_A") ;			break ;
+					case 5: strcpy(chMaterial_Base, "OPAQUE_DSCE_TechRadar") ;				break ;
+				}
+				*/
+
+				//strcpy(chMaterial_Base, "OPAQUE_DSC_SimplePlateB") ;	
+
+				//strcpy(chMaterial_Base, "OPAQUE_DSC_Plate2x2A") ;
+				//strcpy(chMaterial_Base, "OPAQUE_DSC_HexColourA") ;
+				//strcpy(chMaterial_Base, "OPAQUE_DSC_SimplePlateB") ;
+				//strcpy(chMaterial_Base, "OPAQUE_DSC_FloorA") ;
+				strcpy(chMaterial_Base, "textures/metaltech/OPAQUE_DSCE_TechRadar") ;
+				//strcpy(chMaterial_Base, "OPAQUE_DSCE_WallTrimA") ;
+				//strcpy(chMaterial_Base, "OPAQUE_DSCE_WallTrimB") ;
+
+				//strcpy(chMaterial_Base, "Standard_Normal") ;
+				//strcpy(chMaterial_Base, "test") ;
+				//strcpy(chMaterial_Base, "metalN") ;
+				//strcpy(chMaterial_Base, "OPAQUE_DSC_Prototype") ;
+				
+				//strcpy(chMaterial_Base, "textures/common/exptex") ;
+				//strcpy(chMaterial_Base, "metalN_DSNormal") ;
+				//strcpy(chMaterial_Base, "metalN_DfShFuncTNB") ;
+				//strcpy(chMaterial_Base, "metalN_DfShDiffuse") ;
+				//strcpy(chMaterial_Base, "metalN_DfShPosition") ;
+				//strcpy(chMaterial_Base, "metalD") ;
+				//strcpy(chMaterial_Base, "metalR") ;	
+				//strcpy(chMaterial_Base, "WonderShader_Lim3_Fast") ;
+				//strcpy(chMaterial_Base, "reliefMaterial") ;
+				//strcpy(chMaterial_Base, "tute02") ;reliefMaterial
+				//strcpy(chMaterial_Base, "Examples/OffsetMapping/Specular") ;
+				pMaterial_Base=MaterialManager::getSingleton().getByName(chMaterial_Base) ;
+			}
+			else
+//				OFBug.LogAddCR(chMaterial_Base) ;
+
+
+
+			if(nMOIndex==20)
+			{
+				sprintf(m_chBug, "****** %s *******", chMaterial_Base) ;
+				m_pLog->logMessage(m_chBug);
+			}
+
+
+
+
+			// setup whether this material and it's entities are transparent or whatever
+
+			if(strstr(chMaterial_Base, "OPAQUE")!=NULL) // material and its entity are OPAQUE
+			{
+				m_nOpaqueNodeUsed[nZone]=1 ;
+				m_pZoneEntityMaterialType[nMOIndex]=MAT_OPAQUE ; // note that the derived entity will be opaque
+			}
+			else
+			{
+
+				if(strstr(chMaterial_Base, "ALPHAPF")!=NULL) // material and its entity are ALPHAPF
+				{
+					m_nOpaqueNodeUsed[nZone]=1 ;
+					m_pZoneEntityMaterialType[nMOIndex]=MAT_OPAQUE ; // note that the derived entity will be opaque
+				}
+				else
+				{
+
+					if(strstr(chMaterial_Base, "GEL")!=NULL) // material and its entity are GEL
+					{
+						m_nTransNodeUsed[nZone]=1 ;
+						m_pZoneEntityMaterialType[nMOIndex]=MAT_GEL ; // note that the derived entity will be transparent
+					}
+					else
+					{
+
+						strcpy(chCompare, chMaterial_Base) ;
+						chCompare[12]='\0' ;
+						if(strcmp("lights/lamp_", chCompare)==0) // material and its entity are LAMP (spotlights don't ever make triangles, only lamps)
+						{
+							m_nLampNodeUsed[nZone]=1 ;
+							m_pZoneEntityMaterialType[nMOIndex]=MAT_LAMP ; // note that the derived entity will be lamp
+						}
+						else
+						{
+							strcpy(chCompare, chMaterial_Base) ;
+							chCompare[17]='\0' ;
+							if(strcmp("lights/lamp2pass_", chCompare)==0) // material and its entity are LAMP (spotlights don't ever make triangles, only lamps)
+							{
+								m_nLampNodeUsed[nZone]=1 ;
+								m_pZoneEntityMaterialType[nMOIndex]=MAT_LAMP ; // note that the derived entity will be lamp
+							}
+							else
+							{
+
+								if(strstr(chMaterial_Base, "GLOW_")!=NULL) // material and its entity are GLOW
+								{
+									m_nGlowNodeUsed[nZone]=1 ;
+									m_pZoneEntityMaterialType[nMOIndex]=MAT_GLOW ; // note that the derived entity will be glow
+								}
+							}	
+						}					
+					}
+				}
+			}
+
+
+
+
+
+
+			///////////////////////////////////////////////////////////////////////////////////////////////////////
+			//
+			// Setup the different material names and pointers needed for various passes
+			//
+			// Lamps need only one material, pMaterial_Base, which is already assigned above, so it skips all this.
+			//
+			// Glow needs two materials, pMaterial_Base plus pMaterial_DfShColour for the coloured gel deferred pass.
+			// However it's better to make a third, and duplicate the pMaterial_Base to pMaterial_Emissive, since
+			// when glow gets rendered on the Emmisive pass it would be odd to switch to the base material instead
+			// of the emmisive.
+			//
+			// Other objects need multiple materials for various different deferred shading and FX passes
+			
+			if((m_pZoneEntityMaterialType[nMOIndex]!=MAT_LAMP) && (m_pZoneEntityMaterialType[nMOIndex]!=MAT_GLOW))
+			{
+
+				// material for fast shading
+				strcpy(chMaterial_Fast, chMaterial_Base) ;
+				strcat(chMaterial_Fast, "_Fast") ;
+
+				pMaterial_Fast=MaterialManager::getSingleton().getByName(chMaterial_Fast) ;
+				if(pMaterial_Fast.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_Fast) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_Fast, "Fast") ;
+					pMaterial_Fast=MaterialManager::getSingleton().getByName(chMaterial_Fast) ;
+				}
+
+				// material for black shading
+				strcpy(chMaterial_Black, chMaterial_Base) ;
+				strcat(chMaterial_Black, "_Black") ;
+				pMaterial_Black=MaterialManager::getSingleton().getByName(chMaterial_Black) ;
+				if(pMaterial_Black.isNull())
+				{
+					// only issue a warning if this is an alpha testing material, others don't need specialized Black materials
+					if(strstr(chMaterial_Base, "ALPHAPF")!=NULL)
+					{
+						sprintf(chMessage, "Missing material, using default: %s", chMaterial_Black) ;
+						m_pLog->logMessage(chMessage);
+					}
+
+					strcpy(chMaterial_Black, "Black") ;
+					pMaterial_Black=MaterialManager::getSingleton().getByName(chMaterial_Black) ;
+				}
+				
+				// material for shadow casting
+				strcpy(chMaterial_Shadow, chMaterial_Base) ;
+				strcat(chMaterial_Shadow, "_Shadow") ;
+				pMaterial_Shadow=MaterialManager::getSingleton().getByName(chMaterial_Shadow) ;
+				if(pMaterial_Shadow.isNull())
+				{
+					strcpy(chMaterial_Shadow, "OPAQUE_Shadow") ;
+					pMaterial_Shadow=MaterialManager::getSingleton().getByName(chMaterial_Shadow) ;
+				}
+
+				
+				
+				// material for shadow casting
+				strcpy(chMaterial_ShadeFront, chMaterial_Base) ;
+				strcat(chMaterial_ShadeFront, "_ShadeFront") ;
+				pMaterial_ShadeFront=MaterialManager::getSingleton().getByName(chMaterial_ShadeFront) ;
+				if(pMaterial_ShadeFront.isNull())
+				{
+					 // standard opaque ShadeFront.  
+					// Transparent surfaces MUST have their own _ShadeFront material or they will not colour light and can interfere with other trans surfaces.
+					strcpy(chMaterial_ShadeFront, "OPAQUE_ShadeFront") ;
+
+					pMaterial_ShadeFront=MaterialManager::getSingleton().getByName(chMaterial_ShadeFront) ;
+				}
+
+
+				// material for shadow casting
+				strcpy(chMaterial_ShadeBack, chMaterial_Base) ;
+				strcat(chMaterial_ShadeBack, "_ShadeBack") ;
+				pMaterial_ShadeBack=MaterialManager::getSingleton().getByName(chMaterial_ShadeBack) ;
+				if(pMaterial_ShadeBack.isNull())
+				{
+					 // standard opaque ShadeBack.  
+					// Transparent surfaces MUST have their own _ShadeBack material or they will not colour light and can interfere with other trans surfaces.
+					strcpy(chMaterial_ShadeBack, "OPAQUE_ShadeBack") ;
+
+					pMaterial_ShadeBack=MaterialManager::getSingleton().getByName(chMaterial_ShadeBack) ;
+				}
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShColour, chMaterial_Base) ;
+				strcat(chMaterial_DfShColour, "_DfShColour") ;
+				pMaterial_DfShColour=MaterialManager::getSingleton().getByName(chMaterial_DfShColour) ;
+				if(pMaterial_DfShColour.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShColour) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShColour, "DfShColour") ;
+					pMaterial_DfShColour=MaterialManager::getSingleton().getByName(chMaterial_DfShColour) ;
+				}
+				
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShPosition, chMaterial_Base) ;
+				strcat(chMaterial_DfShPosition, "_DfShPosition") ;
+				pMaterial_DfShPosition=MaterialManager::getSingleton().getByName(chMaterial_DfShPosition) ;
+				if(pMaterial_DfShPosition.isNull())
+				{
+					// only issue a warning if this is an alpha testing material, others don't need specialized DfShPosition materials
+					if(strstr(chMaterial_Base, "ALPHAPF")!=NULL)
+					{
+						sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShPosition) ;
+						m_pLog->logMessage(chMessage);
+					}
+
+					strcpy(chMaterial_DfShPosition, "DfShPosition") ;
+					pMaterial_DfShPosition=MaterialManager::getSingleton().getByName(chMaterial_DfShPosition) ;
+				}
+				
+				// material for deferred shading
+				strcpy(chMaterial_DfShDiffuse, chMaterial_Base) ;
+				strcat(chMaterial_DfShDiffuse, "_DfShDiffuse") ;
+				pMaterial_DfShDiffuse=MaterialManager::getSingleton().getByName(chMaterial_DfShDiffuse) ;
+				if(pMaterial_DfShDiffuse.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShDiffuse) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShDiffuse, "DfShDiffuse") ;
+					pMaterial_DfShDiffuse=MaterialManager::getSingleton().getByName(chMaterial_DfShDiffuse) ;
+				}
+
+				/*
+				// material for deferred shading // UNUSED
+				strcpy(chMaterial_DSNormal, chMaterial_Base) ;
+				strcat(chMaterial_DSNormal, "_DSNormal") ;
+				pMaterial_DSNormal=MaterialManager::getSingleton().getByName(chMaterial_DSNormal) ;
+				if(pMaterial_DSNormal.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DSNormal) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DSNormal, "DSNormal") ;
+					pMaterial_DSNormal=MaterialManager::getSingleton().getByName(chMaterial_DSNormal) ;
+				}
+				*/
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShFuncTNB, chMaterial_Base) ;
+				strcat(chMaterial_DfShFuncTNB, "_DfShFuncTNB") ;
+				pMaterial_DfShFuncTNB=MaterialManager::getSingleton().getByName(chMaterial_DfShFuncTNB) ;
+				if(pMaterial_DfShFuncTNB.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShFuncTNB) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShFuncTNB, "DfShFuncTNB") ;
+					pMaterial_DfShFuncTNB=MaterialManager::getSingleton().getByName(chMaterial_DfShFuncTNB) ;
+				}
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShSpecular, chMaterial_Base) ;
+				strcat(chMaterial_DfShSpecular, "_DfShSpecular") ;
+				pMaterial_DfShSpecular=MaterialManager::getSingleton().getByName(chMaterial_DfShSpecular) ;
+				if(pMaterial_DfShSpecular.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShSpecular) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShSpecular, "DfShSpecular") ;
+					pMaterial_DfShSpecular=MaterialManager::getSingleton().getByName(chMaterial_DfShSpecular) ;
+				}
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShEmissive, chMaterial_Base) ;
+				strcat(chMaterial_DfShEmissive, "_DfShEmissive") ;
+				pMaterial_DfShEmissive=MaterialManager::getSingleton().getByName(chMaterial_DfShEmissive) ;
+				if(pMaterial_DfShEmissive.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShEmissive) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShEmissive, "DfShEmissive") ;
+					pMaterial_DfShEmissive=MaterialManager::getSingleton().getByName(chMaterial_DfShEmissive) ;
+				}
+
+
+				/*
+				// material for deferred shading
+				strcpy(chMaterial_DfShData, chMaterial_Base) ;
+				strcat(chMaterial_DfShData, "_DfShData") ;
+				pMaterial_DfShData=MaterialManager::getSingleton().getByName(chMaterial_DfShData) ;
+				if(pMaterial_DfShData.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShData) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShData, "DfShData") ; 
+					pMaterial_DfShData=MaterialManager::getSingleton().getByName(chMaterial_DfShData) ;
+				}
+				*/
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShMix, chMaterial_Base) ;
+				strcat(chMaterial_DfShMix, "_DfShMix") ;
+				pMaterial_DfShMix=MaterialManager::getSingleton().getByName(chMaterial_DfShMix) ;
+				if(pMaterial_DfShMix.isNull())
+				{
+					// Pretty much all materials just use the default mix material,
+					// so don't issue warnings if there isn't a specialized version
+					//sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShMix) ;
+					//m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShMix, "DfShMix") ;
+					pMaterial_DfShMix=MaterialManager::getSingleton().getByName(chMaterial_DfShMix) ;
+				}
+				
+			
+
+
+
+			}// end if not MAT_LAMP or MAT_GLOW
+			else
+				if(m_pZoneEntityMaterialType[nMOIndex]==MAT_GLOW) // the two materials that glow needs
+				{
+
+					// when I get around to allowing user defined GLOW materials as well as the automatic ones,
+					// this'll be the place to add it.  
+					// For now, just the automatically generated lamp/light stuff has a glow.
+					
+					// if the base material was "GLOW_lamp"	
+					strcpy(chCompare, chMaterial_Base) ;
+					chCompare[strlen("GLOW_lamp")]='\0' ;
+					if(strcmp("GLOW_lamp", chCompare)==0) 
+					{
+						strcpy(chMaterial_DfShColour, "GLOW_lampcol") ;
+						pMaterial_DfShColour=MaterialManager::getSingleton().getByName(chMaterial_DfShColour) ;
+
+						strcpy(chMaterial_DfShEmissive, "GLOW_lamp") ;
+						pMaterial_DfShEmissive=MaterialManager::getSingleton().getByName(chMaterial_DfShEmissive) ;
+					}
+					else
+					{
+
+						// if the base material was "GLOW_light"
+						strcpy(chCompare, chMaterial_Base) ;
+						chCompare[strlen("GLOW_light")]='\0' ;
+						if(strcmp("GLOW_light", chCompare)==0) 
+						{
+							strcpy(chMaterial_DfShColour, "GLOW_lightcol") ;
+							pMaterial_DfShColour=MaterialManager::getSingleton().getByName(chMaterial_DfShColour) ;
+
+							strcpy(chMaterial_DfShEmissive, "GLOW_light") ;
+							pMaterial_DfShEmissive=MaterialManager::getSingleton().getByName(chMaterial_DfShEmissive) ;
+						}
+
+					}
+				}
+
+
+
+
+
+
+			// work out which vertices we'll need, we don't add every vertex, just used ones.
+			nMaxVertex=0 ;
+			for(nVert=0 ; nVert<m_Q3Map->m_nVertexMax ; nVert++)
+				pVertIndex[nVert]=-1 ; // initialize all verts as unused.
+			
+
+			// start defining the manualObject
+			m_pZoneMO[nMOIndex]->begin(chMaterial_Base, RenderOperation::OT_TRIANGLE_LIST) ;
+
+
+			// reset the min max stuff
+			flMinX=flMinY=flMinZ=MINMAXLIMIT ;
+			flMaxX=flMaxY=flMaxZ=-MINMAXLIMIT ;
+	
+
+			// add the verts.  We avoid repeating the same vert multiple times where it is used by many triangles
+			for(nTri=nTriangle ; nTri<nEnd ; nTri++)
+				for(nVert=0 ; nVert<3 ; nVert++)
+				{
+					if(pVertIndex[ m_Q3Map->m_pTriangle[nTri].VIndex[nVert] ]==-1) // this vert hasn't been added yet
+					{
+						pVertIndex[ m_Q3Map->m_pTriangle[nTri].VIndex[nVert] ]=nMaxVertex++ ; // so we can correctly look it up when we add the triangles
+
+						flPosX=m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]  ].position[0] ;
+						flPosY=m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].position[1] ;
+						flPosZ=m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].position[2] ;
+						flNormX=m_Q3Map->m_pVertex[ m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].normal[0] ;
+						flNormY=m_Q3Map->m_pVertex[ m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].normal[1] ;
+						flNormZ=m_Q3Map->m_pVertex[ m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].normal[2] ;
+						
+						
+						
+						// lamps have some different vertex data, also glow
+						// lamp needs colour and also info about the origin, which is stored in the UVs.
+						// glow only needs the colour, but it doesn't hurt to store the orgin too, no harm and simpler code.
+						if((m_pZoneEntityMaterialType[nMOIndex]==MAT_LAMP) || (m_pZoneEntityMaterialType[nMOIndex]==MAT_GLOW))
+						{
+							flLampPosX =			m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].texcoord[0][0] ;
+							flLampPosY =			m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].texcoord[0][1] ;
+							flLampPosZ =			m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].texcoord[1][0] ;
+							flLampBrightness=	m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].texcoord[1][1] ;
+
+							flLampR=m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].color[0]/255.0f ;
+							flLampG=m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].color[1]/255.0f ;
+							flLampB=m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].color[2]/255.0f ;
+
+							// set the vertex data
+							m_pZoneMO[nMOIndex]->position(flPosX, flPosY, flPosZ) ;
+							m_pZoneMO[nMOIndex]->normal(flNormX, flNormY, flNormZ) ;
+							m_pZoneMO[nMOIndex]->textureCoord(flLampPosX, flLampPosY, flLampPosZ, flLampBrightness) ;
+							m_pZoneMO[nMOIndex]->colour(flLampR, flLampG, flLampB) ;
+
+						}
+						else // non-lamps
+						{
+							flTexU=m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].texcoord[0][0] ;
+							flTexV=m_Q3Map->m_pVertex[	m_Q3Map->m_pTriangle[nTri].VIndex[nVert]	].texcoord[0][1] ;
+
+							// set the vertex data
+							m_pZoneMO[nMOIndex]->position(flPosX, flPosY, flPosZ) ;
+							m_pZoneMO[nMOIndex]->normal(flNormX, flNormY, flNormZ) ;
+							m_pZoneMO[nMOIndex]->textureCoord(flTexU, flTexV) ;
+						}
+
+						// update bounds
+						if(flPosX<flMinX) flMinX=flPosX ;
+						if(flPosY<flMinY) flMinY=flPosY ;
+						if(flPosZ<flMinZ) flMinZ=flPosZ ;
+						if(flPosX>flMaxX) flMaxX=flPosX ;
+						if(flPosY>flMaxY) flMaxY=flPosY ;
+						if(flPosZ>flMaxZ) flMaxZ=flPosZ ;
+
+					}// end if adding vert
+				}
+
+			// add the triangles
+			for(nTri=nTriangle ; nTri<nEnd ; nTri++)
+			{
+				nVertA=pVertIndex[ m_Q3Map->m_pTriangle[nTri].VIndex[0] ] ;
+				nVertB=pVertIndex[ m_Q3Map->m_pTriangle[nTri].VIndex[1] ] ;
+				nVertC=pVertIndex[ m_Q3Map->m_pTriangle[nTri].VIndex[2] ] ;
+				m_pZoneMO[nMOIndex]->triangle(nVertA, nVertC, nVertB) ;
+				m_nZoneTriangleCount[nZone]++ ;
+				//m_pZoneMO[nMOIndex]->triangle(nVertA, nVertB, nVertC) ;
+			}
+
+
+			// all done for this block of material
+			m_pZoneMO[nMOIndex]->end() ;
+			m_pZoneMO[nMOIndex]->setCastShadows(true) ;
+			m_pZoneMO[nMOIndex]->setDynamic(false) ;
+
+			// convert the manualobject to a mesh
+			sprintf(chMeshName, "ZoneMesh_%04i_%04i_%05i", nZone, nMaterial, nTriangle) ;
+			m_pZoneMesh[nMOIndex]= m_pZoneMO[nMOIndex]->convertToMesh(chMeshName);
+
+			// don't need the manual object anymore
+			m_pSceneMgr->destroyManualObject(m_pZoneMO[nMOIndex]) ;
+
+
+			// temp cludge to add thickness
+			flMinX-=1.0f ;
+			flMinY-=1.0f ;
+			flMinZ-=1.0f ;
+			flMaxX+=1.0f ;
+			flMaxY+=1.0f ;
+			flMaxZ+=1.0f ;
+
+			// set axis aligned bounding box of this mesh
+			AABB.setMinimumX(flMinX) ; 
+			AABB.setMinimumY(flMinY) ; 
+			AABB.setMinimumZ(flMinZ) ;
+			AABB.setMaximumX(flMaxX) ; 
+			AABB.setMaximumY(flMaxY) ; 
+			AABB.setMaximumZ(flMaxZ) ;
+			m_pZoneMesh[nMOIndex]->_setBounds(AABB, false) ;
+			
+			// set bounding sphere of this mesh
+			flDisX=flMaxX-flMinX ;
+			flDisY=flMaxY-flMinY ;
+			flDisZ=flMaxZ-flMinZ ;
+			flRadius=sqrt( flDisX*flDisX + flDisY*flDisY + flDisZ*flDisZ )/2.0 ;
+			m_pZoneMesh[nMOIndex]->_setBoundingSphereRadius(flRadius) ;
+
+
+			//if(strcmp(chMaterial_Base, "textures/metaltech/GEL_DSC_glassred")==0)
+			//	OFBug.MessageFloat(flRadius, flMinX, flMinY, flMinZ, flMaxX, flMaxY, flMaxZ) ;
+
+			//if(strcmp(chMaterial_Base, "textures/metaltech/GEL_DSC_glassgreen")==0)
+			//	OFBug.MessageFloat(flRadius, flMinX, flMinY, flMinZ, flMaxX, flMaxY, flMaxZ) ;
+
+			// calculate tangents for the mesh		
+			if((m_pZoneEntityMaterialType[nMOIndex]!=MAT_LAMP) && (m_pZoneEntityMaterialType[nMOIndex]!=MAT_GLOW))// lamps and glow don't need tangent vectors
+			{
+				m_pZoneMesh[nMOIndex]->suggestTangentVectorBuildParams(VES_TANGENT, src, dest) ;
+				m_pZoneMesh[nMOIndex]->buildTangentVectors(VES_TANGENT, src, dest);
+			}
+   	
+			m_pZoneMesh[nMOIndex]->load() ;
+
+			m_pZoneMesh[nMOIndex]->getSubMesh(0)->generateExtremes(8) ;
+
+			// create an entity for this mesh.  We need this so we can change the material during deferred shading
+			m_pZoneEntity[nMOIndex]=m_pSceneMgr->createEntity(m_pZoneMesh[nMOIndex]->getName(), m_pZoneMesh[nMOIndex]->getName()) ;
+
+			// if the entity is a lamp or glow, set its material because they never get changed
+			if((m_pZoneEntityMaterialType[nMOIndex]==MAT_LAMP) || (m_pZoneEntityMaterialType[nMOIndex]==MAT_GLOW)) 
+				m_pZoneEntity[nMOIndex]->setMaterial( pMaterial_Base) ;
+
+
+			//AABB=m_pZoneEntity[nMOIndex]->getBoundingBox() ;
+			//Ogre::Vector3 mn, mx ;
+			//mn=AABB.getMinimum() ;
+			//mx=AABB.getMaximum() ;
+			//if(strcmp(chMaterial_Base, "textures/metaltech/GEL_DSC_glassred")==0)
+			//	OFBug.MessageFloat(mn.x, mn.y, mn.z, mx.x, mx.y, mx.z) ; 
+
+
+
+
+
+
+			// store the pointers to the materials of this entity
+			//m_pZoneEntityMaterial_Base[nMOIndex]=pMaterial_Base ;
+			//m_pZoneEntityMaterial_Fast[nMOIndex]=pMaterial_Fast ;
+			m_pZoneEntityMaterial_Black[nMOIndex]=pMaterial_Black ;
+			m_pZoneEntityMaterial_DfShColour[nMOIndex]=pMaterial_DfShColour ;
+			m_pZoneEntityMaterial_Shadow[nMOIndex]=pMaterial_Shadow ;
+			m_pZoneEntityMaterial_ShadeFront[nMOIndex]=pMaterial_ShadeFront ;
+			m_pZoneEntityMaterial_ShadeBack[nMOIndex]=pMaterial_ShadeBack ;
+			m_pZoneEntityMaterial_DfShPosition[nMOIndex]=pMaterial_DfShPosition ;
+			m_pZoneEntityMaterial_DfShDiffuse[nMOIndex]=pMaterial_DfShDiffuse ;
+			//m_pZoneEntityMaterial_DSNormal[nMOIndex]=pMaterial_DSNormal ;
+			m_pZoneEntityMaterial_DfShFuncTNB[nMOIndex]=pMaterial_DfShFuncTNB ;
+			m_pZoneEntityMaterial_DfShSpecular[nMOIndex]=pMaterial_DfShSpecular ;
+			m_pZoneEntityMaterial_DfShEmissive[nMOIndex]=pMaterial_DfShEmissive ;
+			//m_pZoneEntityMaterial_DfShData[nMOIndex]=pMaterial_DfShData ;
+			m_pZoneEntityMaterial_DfShMix[nMOIndex]=pMaterial_DfShMix ;
+
+
+			//////////////////////////////////////////////////////////////////////////////////////////
+
+			char chNewName[1024] ;
+			for(nPTex=0 ; nPTex<MAX_PROJECTORTEX ; nPTex++)
+			{
+				Ogre::AliasTextureNamePairList AliasList ;
+				
+				// check the necessary texture exists
+				//if(TextureManager::getSingleton().getByName(m_Q3Map->m_chSpotlightTexture[nPTex]).isNull())
+				//	OFBug.MessageInt(666) ;
+				
+				
+				AliasList.insert(AliasTextureNamePairList::value_type("projector_tex", m_Q3Map->m_chSpotlightTexture[nPTex]));
+
+				
+
+				sprintf(chNewName, "%s_%i", chMaterial_Base, 0) ;
+				m_pZoneEntityMaterial_Base[nPTex][nMOIndex]=pMaterial_Base->clone(chNewName) ;
+				// change the texture unit
+				m_pZoneEntityMaterial_Base[nPTex][nMOIndex]->applyTextureAliases(AliasList) ;
+
+				sprintf(chNewName, "%s_%i", chMaterial_Fast, 0) ;
+				m_pZoneEntityMaterial_Fast[nPTex][nMOIndex]=pMaterial_Fast->clone(chNewName) ;
+				// change the texture unit
+				m_pZoneEntityMaterial_Fast[nPTex][nMOIndex]->applyTextureAliases(AliasList) ;
+
+			}
+
+
+
+			//////////////////////////////////////////////////////////////////////////////////////////
+
+
+			// move to the end of this block of materials
+			nTriangle=nEnd ;
+			nMOIndex++ ;
+
+
+			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+			//
+			// end adding a begin/end block of all triangles in a zone with the same material
+			//
+			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+		}// end scanning triangles in a zone
+
+
+
+	}// end looping through all zones
+
+	m_nZoneMOStart[m_Q3Map->m_nMaxZone]=nMOIndex ; // indicates the end pos of all the manual objects 
+
+	CHECKDELETE_ARRAY( pVertIndex, NEW_CHECK_pVertIndex  );  // free the vert index memory we used
+
+	CHECKDELETE_ARRAY( m_pZoneMO, NEW_CHECK_m_pZoneMO  ) ;  // free the manual object memory we used
+	// quick check
+	if(nMOCount!=nMOIndex)
+	{
+		sprintf(chMessage, "ERROR ConstructMap: MOIndex %i does not match MOCount %i", nMOIndex, nMOCount) ;
+		m_pLog->logMessage(chMessage);
+		//CHECKDELETE_ARRAY( m_pZoneMO ) ;
+		CHECKDELETE_ARRAY( m_pZoneMesh, NEW_CHECK_m_pZoneMesh  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntity, NEW_CHECK_m_pZoneEntity  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterialType, NEW_CHECK_m_pZoneEntityMaterialType  ) ; 
+
+		for(nPTex=0 ; nPTex<MAX_PROJECTORTEX ; nPTex++)
+		{
+			CHECKDELETE_ARRAY( m_pZoneEntityMaterial_Base[nPTex], NEW_CHECK_m_pZoneEntityMaterial_Base  ) ; 
+			CHECKDELETE_ARRAY( m_pZoneEntityMaterial_Fast[nPTex], NEW_CHECK_m_pZoneEntityMaterial_Fast  ) ; 
+		}
+
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_Black, NEW_CHECK_m_pZoneEntityMaterial_Black  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShColour, NEW_CHECK_m_pZoneEntityMaterial_DfShColour  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_Shadow, NEW_CHECK_m_pZoneEntityMaterial_Shadow  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_ShadeFront, NEW_CHECK_m_pZoneEntityMaterial_ShadeFront  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_ShadeBack, NEW_CHECK_m_pZoneEntityMaterial_ShadeBack  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShPosition, NEW_CHECK_m_pZoneEntityMaterial_DfShPosition  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShDiffuse, NEW_CHECK_m_pZoneEntityMaterial_DfShDiffuse  ) ; 
+		//CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DSNormal ) ;
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShFuncTNB, NEW_CHECK_m_pZoneEntityMaterial_DfShFuncTNB  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShSpecular, NEW_CHECK_m_pZoneEntityMaterial_DfShSpecular  ) ; 
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShEmissive, NEW_CHECK_m_pZoneEntityMaterial_DfShEmissive  ) ; 
+		//CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShData ) ;
+		CHECKDELETE_ARRAY( m_pZoneEntityMaterial_DfShMix, NEW_CHECK_m_pZoneEntityMaterial_DfShMix  ) ; 
+
+
+		return 0 ;
+	}
+
+
+	return 1 ;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// setup the game entities
+//
+
+int OgreFramework::SetupGameEntities(void)
+{
+	int nEntity=0 ;
+	char chMeshName[1024] ;
+	
+
+	// work out the maximum number of entities we need
+	m_nMaxEntity=10 ;
+	int nHalfMax=m_nMaxEntity/2 ;
+	
+
+
+
+	// create the dynamic memory for the entities
+	m_pEntityInfo=new ENTITYINFO[m_nMaxEntity] ;
+	if(m_pEntityInfo==NULL) 
+		return 0 ;
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pEntityInfo]++ ; }
+
+	m_pVisibleEntity=new int[m_nMaxEntity] ;
+	if(m_pVisibleEntity==NULL) 
+		return 0 ;
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pVisibleEntity]++ ; }
+
+	m_pFrustumEntity=new int[m_nMaxEntity] ;
+	if(m_pFrustumEntity==NULL) 
+		return 0 ;
+	else
+		{m_nNewCount++ ; m_nNewCheck[NEW_CHECK_m_pFrustumEntity]++ ; }
+
+
+
+	// setup materials and default data for the entities
+	for(nEntity=0 ; nEntity<m_nMaxEntity ; nEntity++)
+	{
+		//switch(nEntity%3)
+		//{
+		//	case 0: strcpy(chMeshName, "robot.mesh") ; break ;
+		//	case 1: strcpy(chMeshName, "ninja.mesh") ; break ;
+		//	case 2: strcpy(chMeshName, "athene.mesh") ; break ;
+		//}
+
+		strcpy(chMeshName, "robot.mesh") ;
+
+		SetupEntity(nEntity, chMeshName) ;
+	}
+
+
+
+
+	// setup start data for each entity
+	for(nEntity=0 ; nEntity<nHalfMax ; nEntity++)
+	{
+		m_pEntityInfo[nEntity].Postition=Ogre::Vector3(750.0f, 128.0f, -1950.0f-nEntity*40.0f) ;
+		//m_pEntityInfo[nEntity].pMasterNode->setPosition(750.0f, 128.0f, -1950.0f-nEntity*40.0f) ;
+	}
+
+	for(nEntity=nHalfMax ; nEntity<m_nMaxEntity ; nEntity++)
+	{
+		m_pEntityInfo[nEntity].Postition=Ogre::Vector3(590.0f, 128.0f, -320.0f-nEntity*40.0f) ;
+		//m_pEntityInfo[nEntity].pMasterNode->setPosition(590.0f, 128.0f, -320.0f-nEntity*40.0f) ;
+	}
+
+	
+
+	for(nEntity=0 ; nEntity<m_nMaxEntity ; nEntity++)
+	{
+		m_pEntityInfo[nEntity].Active=1 ;
+		m_pVisibleEntity[nEntity]=nEntity ;
+		m_pFrustumEntity[nEntity]=nEntity ;
+	}
+
+
+	m_nMaxVisibleEntity=m_nMaxEntity ;
+	m_nMaxFrustumEntity=m_nMaxEntity ;
+
+	return 1 ;
+
+}
+
+
+int OgreFramework::SetupEntity(int nEntity, char *chMeshName)
+{
+
+	char chEntityName[1024] ;
+	//char chMeshName[1024] ;
+
+
+	int nSubMesh=0 ;
+	int nMaxSubMesh=0 ;
+
+
+
+	Ogre::String MaterialName ;
+
+
+	char chMaterial_Base[1024] ;
+	MaterialPtr pMaterial_Base ; // used for checking if material scripts exist, and stored for the material switching that happens in deferred shading
+	
+	char chMaterial_Fast[1024] ;
+	MaterialPtr pMaterial_Fast ; // faster version of the base, mainly non-coloured shadowning.
+
+	char chMaterial_Black[1024] ;
+	MaterialPtr pMaterial_Black ; // just plain black, or black with alpha testing.
+
+	char chMaterial_DfShColour[1024] ;
+	MaterialPtr pMaterial_DfShColour ; // used for checking if material scripts exist, and stored for the material switching that happens in deferred shading
+	
+
+	char chMaterial_Shadow[1024] ;
+	MaterialPtr pMaterial_Shadow ;
+
+	char chMaterial_ShadeFront[1024] ;
+	MaterialPtr pMaterial_ShadeFront ;
+
+	char chMaterial_ShadeBack[1024] ;
+	MaterialPtr pMaterial_ShadeBack ;
+
+	char chMaterial_DfShPosition[1024] ;
+	MaterialPtr pMaterial_DfShPosition ;
+	
+	char chMaterial_DfShDiffuse[1024] ;
+	MaterialPtr pMaterial_DfShDiffuse ;
+	
+	//char chMaterial_DSNormal[1024] ;
+	//MaterialPtr pMaterial_DSNormal ;
+	
+	char chMaterial_DfShFuncTNB[1024] ;
+	MaterialPtr pMaterial_DfShFuncTNB ;
+
+	char chMaterial_DfShSpecular[1024] ;
+	MaterialPtr pMaterial_DfShSpecular ;
+
+	char chMaterial_DfShEmissive[1024] ;
+	MaterialPtr pMaterial_DfShEmissive ;
+
+	//char chMaterial_DfShData[1024] ;
+	//MaterialPtr pMaterial_DfShData ;
+
+	char chMaterial_DfShMix[1024] ;
+	MaterialPtr pMaterial_DfShMix ;
+
+	char chCompare[1024] ;
+
+	unsigned short src, dest; // for tangent vectors
+
+	char chMasterNodeName[1024] ;
+	char chSubNodeName[1024] ;
+
+	char chMessage[1024] ;
+	int nPTex=0 ;
+
+
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+		sprintf(chEntityName, "Entity_%05i", nEntity) ;
+		//strcpy(chMeshName, "robot.mesh") ;
+
+
+		// load the mesh
+
+		m_pEntityInfo[nEntity].pEnt=m_pSceneMgr->createEntity( chEntityName, chMeshName );
+
+		m_pEntityInfo[nEntity].TriangleCount=0 ;
+		
+
+		// create the master scenenode
+		sprintf(chMasterNodeName, "Entity_%05i", nEntity) ;
+		m_pEntityInfo[nEntity].pMasterNode=m_pSceneMgr->getRootSceneNode()->createChildSceneNode(chMasterNodeName) ;
+		m_pEntityInfo[nEntity].pMasterNode->attachObject(m_pEntityInfo[nEntity].pEnt) ;
+
+		nMaxSubMesh=m_pEntityInfo[nEntity].pEnt->getMesh()->getNumSubMeshes() ;
+		if(nMaxSubMesh>MAX_SUBMESH)
+		{
+			sprintf(m_chBug, "MESH ERROR: Mesh %s has %i submeshes, max is %i", chMeshName, m_pEntityInfo[nEntity].MaxSubMesh, MAX_SUBMESH) ;
+			m_pLog->logMessage(m_chBug);
+			nMaxSubMesh=MAX_SUBMESH ;
+		}
+		m_pEntityInfo[nEntity].MaxSubMesh=nMaxSubMesh ;
+
+		sprintf(m_chBug, "Entity %i, Mesh %s, MaxSubMesh %i", nEntity, chMeshName,  m_pEntityInfo[nEntity].MaxSubMesh) ;
+		m_pLog->logMessage(m_chBug);
+
+		// assign all the materials needed for all the submeshes
+		for(nSubMesh=0 ; nSubMesh<nMaxSubMesh ; nSubMesh++)
+		{
+			// we count the triangles just for stats
+			m_pEntityInfo[nEntity].TriangleCount += m_pEntityInfo[nEntity].pEnt->getMesh()->getSubMesh(nSubMesh)->indexData->indexCount/3 ;
+
+
+			MaterialName=m_pEntityInfo[nEntity].pEnt->getMesh()->getSubMesh(nSubMesh)->getMaterialName() ;
+		
+			
+			
+
+			if(MaterialName.size()<512) // make sure name isn't too long before we copy it.
+				strcpy(chMaterial_Base, MaterialName.c_str()) ;
+			else
+			{
+				sprintf(m_chBug, "MESH ERROR: Mesh %s submesh %i material name is too long.", chMeshName, nSubMesh) ;
+				m_pLog->logMessage(m_chBug);
+				m_pLog->logMessage(MaterialName) ;
+				chMaterial_Base[0]='\0' ; // no material
+			}
+
+			sprintf(m_chBug, "Entity %i SubMesh %i, Material %s", nEntity, nSubMesh, chMaterial_Base) ;
+			m_pLog->logMessage(m_chBug);
+
+
+			// if the material is a lamp material we need to specify either an OpenGl or Direct3D version
+			strcpy(chCompare, chMaterial_Base) ;
+			chCompare[12]='\0' ;
+			if(strcmp("lights/lamp_", chCompare)==0) // material is LAMP 
+			{
+				if(m_IsOpenGL)
+					strcat(chMaterial_Base, "_ogl") ;
+				else
+					strcat(chMaterial_Base, "_d3d") ;
+
+			}
+
+			strcpy(chCompare, chMaterial_Base) ;
+			chCompare[17]='\0' ;
+			if(strcmp("lights/lamp2pass_", chCompare)==0) // material is LAMP, 2 pass version 
+			{
+				if(m_IsOpenGL)
+					strcat(chMaterial_Base, "_ogl") ;
+				else
+					strcat(chMaterial_Base, "_d3d") ;
+			}
+			
+			// check that this material script exists, if not set to the default
+			pMaterial_Base=MaterialManager::getSingleton().getByName(chMaterial_Base) ;
+			if(true)//pMaterial_Base.isNull())
+			{
+				strcat(chMaterial_Base, " *** MISSING ***") ;
+//				OFBug.LogAddCR(chMaterial_Base) ;
+				
+				strcpy(chMaterial_Base, "textures/metaltech/OPAQUE_DSCE_TechRadar") ;
+				pMaterial_Base=MaterialManager::getSingleton().getByName(chMaterial_Base) ;
+			}
+
+
+			// setup whether this material and it's entities are transparent or whatever
+			
+			m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]=0 ;// default to nothing
+			
+			if(strstr(chMaterial_Base, "OPAQUE")!=NULL) // material and its entity are OPAQUE
+			{
+				m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]=MAT_OPAQUE ; // note that the derived entity will be opaque
+
+			}
+			else
+			{
+
+				if(strstr(chMaterial_Base, "ALPHAPF")!=NULL) // material and its entity are ALPHAPF
+				{
+					m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]=MAT_OPAQUE ; // note that the derived entity will be opaque
+				}
+				else
+				{
+
+					if(strstr(chMaterial_Base, "GEL")!=NULL) // material and its entity are GEL
+					{
+						m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]=MAT_GEL ; // note that the derived entity will be transparent
+					}
+					else
+					{
+
+						strcpy(chCompare, chMaterial_Base) ;
+						chCompare[12]='\0' ;
+						if(strcmp("lights/lamp_", chCompare)==0) // material and its entity are LAMP (spotlights don't ever make triangles, only lamps)
+						{
+							m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]=MAT_LAMP ; // note that the derived entity will be lamp
+						}
+						else
+						{
+							strcpy(chCompare, chMaterial_Base) ;
+							chCompare[17]='\0' ;
+							if(strcmp("lights/lamp2pass_", chCompare)==0) // material and its entity are LAMP (spotlights don't ever make triangles, only lamps)
+							{
+								m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]=MAT_LAMP ; // note that the derived entity will be lamp
+							}
+							else
+							{
+
+								if(strstr(chMaterial_Base, "GLOW_")!=NULL) // material and its entity are GLOW
+								{
+									m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]=MAT_GLOW ; // note that the derived entity will be glow
+								}
+							}	
+						}					
+					}
+				}
+			}
+
+
+
+			
+
+			///////////////////////////////////////////////////////////////////////////////////////////////////////
+			//
+			// Setup the different material names and pointers needed for various passes
+			//
+			// Lamps need only one material, pMaterial_Base, which is already assigned above, so it skips all this.
+			//
+			// Glow needs two materials, pMaterial_Base plus pMaterial_DfShColour for the coloured gel deferred pass.
+			// However it's better to make a third, and duplicate the pMaterial_Base to pMaterial_Emissive, since
+			// when glow gets rendered on the Emmisive pass it would be odd to switch to the base material instead
+			// of the emmisive.
+			//
+			// Other objects need multiple materials for various different deferred shading and FX passes
+			
+			if((m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]!=MAT_LAMP) && (m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]!=MAT_GLOW))
+			{
+
+				// material for fast shading
+				strcpy(chMaterial_Fast, chMaterial_Base) ;
+				strcat(chMaterial_Fast, "_Fast") ;
+				pMaterial_Fast=MaterialManager::getSingleton().getByName(chMaterial_Fast) ;
+				if(pMaterial_Fast.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_Fast) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_Fast, "Fast") ;
+					pMaterial_Fast=MaterialManager::getSingleton().getByName(chMaterial_Fast) ;
+				}
+
+				// material for black shading
+				strcpy(chMaterial_Black, chMaterial_Base) ;
+				strcat(chMaterial_Black, "_Black") ;
+				pMaterial_Black=MaterialManager::getSingleton().getByName(chMaterial_Black) ;
+				if(pMaterial_Black.isNull())
+				{
+					// only issue a warning if this is an alpha testing material, others don't need specialized Black materials
+					if(strstr(chMaterial_Base, "ALPHAPF")!=NULL)
+					{
+						sprintf(chMessage, "Missing material, using default: %s", chMaterial_Black) ;
+						m_pLog->logMessage(chMessage);
+					}
+
+					strcpy(chMaterial_Black, "Black") ;
+					pMaterial_Black=MaterialManager::getSingleton().getByName(chMaterial_Black) ;
+				}
+				
+				// material for shadow casting
+				strcpy(chMaterial_Shadow, chMaterial_Base) ;
+				strcat(chMaterial_Shadow, "_Shadow") ;
+				pMaterial_Shadow=MaterialManager::getSingleton().getByName(chMaterial_Shadow) ;
+				if(pMaterial_Shadow.isNull())
+				{
+					strcpy(chMaterial_Shadow, "OPAQUE_Shadow") ;
+					pMaterial_Shadow=MaterialManager::getSingleton().getByName(chMaterial_Shadow) ;
+				}
+
+				
+				
+				// material for shadow casting
+				strcpy(chMaterial_ShadeFront, chMaterial_Base) ;
+				strcat(chMaterial_ShadeFront, "_ShadeFront") ;
+				pMaterial_ShadeFront=MaterialManager::getSingleton().getByName(chMaterial_ShadeFront) ;
+				if(pMaterial_ShadeFront.isNull())
+				{
+					 // standard opaque ShadeFront.  
+					// Transparent surfaces MUST have their own _ShadeFront material or they will not colour light and can interfere with other trans surfaces.
+					strcpy(chMaterial_ShadeFront, "OPAQUE_ShadeFront") ;
+
+					pMaterial_ShadeFront=MaterialManager::getSingleton().getByName(chMaterial_ShadeFront) ;
+				}
+
+
+				// material for shadow casting
+				strcpy(chMaterial_ShadeBack, chMaterial_Base) ;
+				strcat(chMaterial_ShadeBack, "_ShadeBack") ;
+				pMaterial_ShadeBack=MaterialManager::getSingleton().getByName(chMaterial_ShadeBack) ;
+				if(pMaterial_ShadeBack.isNull())
+				{
+					 // standard opaque ShadeBack.  
+					// Transparent surfaces MUST have their own _ShadeBack material or they will not colour light and can interfere with other trans surfaces.
+					strcpy(chMaterial_ShadeBack, "OPAQUE_ShadeBack") ;
+
+					pMaterial_ShadeBack=MaterialManager::getSingleton().getByName(chMaterial_ShadeBack) ;
+				}
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShColour, chMaterial_Base) ;
+				strcat(chMaterial_DfShColour, "_DfShColour") ;
+				pMaterial_DfShColour=MaterialManager::getSingleton().getByName(chMaterial_DfShColour) ;
+				if(pMaterial_DfShColour.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShColour) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShColour, "DfShColour") ;
+					pMaterial_DfShColour=MaterialManager::getSingleton().getByName(chMaterial_DfShColour) ;
+				}
+				
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShPosition, chMaterial_Base) ;
+				strcat(chMaterial_DfShPosition, "_DfShPosition") ;
+				pMaterial_DfShPosition=MaterialManager::getSingleton().getByName(chMaterial_DfShPosition) ;
+				if(pMaterial_DfShPosition.isNull())
+				{
+					// only issue a warning if this is an alpha testing material, others don't need specialized DfShPosition materials
+					if(strstr(chMaterial_Base, "ALPHAPF")!=NULL)
+					{
+						sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShPosition) ;
+						m_pLog->logMessage(chMessage);
+					}
+
+					strcpy(chMaterial_DfShPosition, "DfShPosition") ;
+					pMaterial_DfShPosition=MaterialManager::getSingleton().getByName(chMaterial_DfShPosition) ;
+				}
+				
+				// material for deferred shading
+				strcpy(chMaterial_DfShDiffuse, chMaterial_Base) ;
+				strcat(chMaterial_DfShDiffuse, "_DfShDiffuse") ;
+				pMaterial_DfShDiffuse=MaterialManager::getSingleton().getByName(chMaterial_DfShDiffuse) ;
+				if(pMaterial_DfShDiffuse.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShDiffuse) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShDiffuse, "DfShDiffuse") ;
+					pMaterial_DfShDiffuse=MaterialManager::getSingleton().getByName(chMaterial_DfShDiffuse) ;
+				}
+
+				/*
+				// material for deferred shading // UNUSED
+				strcpy(chMaterial_DSNormal, chMaterial_Base) ;
+				strcat(chMaterial_DSNormal, "_DSNormal") ;
+				pMaterial_DSNormal=MaterialManager::getSingleton().getByName(chMaterial_DSNormal) ;
+				if(pMaterial_DSNormal.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DSNormal) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DSNormal, "DSNormal") ;
+					pMaterial_DSNormal=MaterialManager::getSingleton().getByName(chMaterial_DSNormal) ;
+				}
+				*/
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShFuncTNB, chMaterial_Base) ;
+				strcat(chMaterial_DfShFuncTNB, "_DfShFuncTNB") ;
+				pMaterial_DfShFuncTNB=MaterialManager::getSingleton().getByName(chMaterial_DfShFuncTNB) ;
+				if(pMaterial_DfShFuncTNB.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShFuncTNB) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShFuncTNB, "DfShFuncTNB") ;
+					pMaterial_DfShFuncTNB=MaterialManager::getSingleton().getByName(chMaterial_DfShFuncTNB) ;
+				}
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShSpecular, chMaterial_Base) ;
+				strcat(chMaterial_DfShSpecular, "_DfShSpecular") ;
+				pMaterial_DfShSpecular=MaterialManager::getSingleton().getByName(chMaterial_DfShSpecular) ;
+				if(pMaterial_DfShSpecular.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShSpecular) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShSpecular, "DfShSpecular") ;
+					pMaterial_DfShSpecular=MaterialManager::getSingleton().getByName(chMaterial_DfShSpecular) ;
+				}
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShEmissive, chMaterial_Base) ;
+				strcat(chMaterial_DfShEmissive, "_DfShEmissive") ;
+				pMaterial_DfShEmissive=MaterialManager::getSingleton().getByName(chMaterial_DfShEmissive) ;
+				if(pMaterial_DfShEmissive.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShEmissive) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShEmissive, "DfShEmissive") ;
+					pMaterial_DfShEmissive=MaterialManager::getSingleton().getByName(chMaterial_DfShEmissive) ;
+				}
+
+
+				/*
+				// material for deferred shading
+				strcpy(chMaterial_DfShData, chMaterial_Base) ;
+				strcat(chMaterial_DfShData, "_DfShData") ;
+				pMaterial_DfShData=MaterialManager::getSingleton().getByName(chMaterial_DfShData) ;
+				if(pMaterial_DfShData.isNull())
+				{
+					sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShData) ;
+					m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShData, "DfShData") ; 
+					pMaterial_DfShData=MaterialManager::getSingleton().getByName(chMaterial_DfShData) ;
+				}
+				*/
+
+				// material for deferred shading
+				strcpy(chMaterial_DfShMix, chMaterial_Base) ;
+				strcat(chMaterial_DfShMix, "_DfShMix") ;
+				pMaterial_DfShMix=MaterialManager::getSingleton().getByName(chMaterial_DfShMix) ;
+				if(pMaterial_DfShMix.isNull())
+				{
+					// Pretty much all materials just use the default mix material,
+					// so don't issue warnings if there isn't a specialized version
+					//sprintf(chMessage, "Missing material, using default: %s", chMaterial_DfShMix) ;
+					//m_pLog->logMessage(chMessage);
+
+					strcpy(chMaterial_DfShMix, "DfShMix") ;
+					pMaterial_DfShMix=MaterialManager::getSingleton().getByName(chMaterial_DfShMix) ;
+				}
+				
+			
+
+
+
+			}// end if not MAT_LAMP or MAT_GLOW
+			else
+				if(m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]==MAT_GLOW) // the two materials that glow needs
+				{
+
+					// when I get around to allowing user defined GLOW materials as well as the automatic ones,
+					// this'll be the place to add it.  
+					// For now, just the automatically generated lamp/light stuff has a glow.
+					
+					// if the base material was "GLOW_lamp"	
+					strcpy(chCompare, chMaterial_Base) ;
+					chCompare[strlen("GLOW_lamp")]='\0' ;
+					if(strcmp("GLOW_lamp", chCompare)==0) 
+					{
+						strcpy(chMaterial_DfShColour, "GLOW_lampcol") ;
+						pMaterial_DfShColour=MaterialManager::getSingleton().getByName(chMaterial_DfShColour) ;
+
+						strcpy(chMaterial_DfShEmissive, "GLOW_lamp") ;
+						pMaterial_DfShEmissive=MaterialManager::getSingleton().getByName(chMaterial_DfShEmissive) ;
+					}
+					else
+					{
+
+						// if the base material was "GLOW_light"
+						strcpy(chCompare, chMaterial_Base) ;
+						chCompare[strlen("GLOW_light")]='\0' ;
+						if(strcmp("GLOW_light", chCompare)==0) 
+						{
+							strcpy(chMaterial_DfShColour, "GLOW_lightcol") ;
+							pMaterial_DfShColour=MaterialManager::getSingleton().getByName(chMaterial_DfShColour) ;
+
+							strcpy(chMaterial_DfShEmissive, "GLOW_light") ;
+							pMaterial_DfShEmissive=MaterialManager::getSingleton().getByName(chMaterial_DfShEmissive) ;
+						}
+
+					}
+				}
+
+
+
+
+			// if the entity is a lamp or glow, set its material because they never get changed
+			//if((m_pZoneEntityMaterialType[nMOIndex]==MAT_LAMP) || (m_pZoneEntityMaterialType[nMOIndex]==MAT_GLOW)) 
+			//	m_pZoneEntity[nMOIndex]->setMaterial( pMaterial_Base) ;
+
+
+			// store the pointers to the materials of this entity
+			//m_pZoneEntityMaterial_Base[nMOIndex]=pMaterial_Base ;
+			//m_pZoneEntityMaterial_Fast[nMOIndex]=pMaterial_Fast ;
+			m_pEntityInfo[nEntity].Material_Black[nSubMesh]=pMaterial_Black ;
+			m_pEntityInfo[nEntity].Material_DfShColour[nSubMesh]=pMaterial_DfShColour ;
+			m_pEntityInfo[nEntity].Material_Shadow[nSubMesh]=pMaterial_Shadow ;
+			m_pEntityInfo[nEntity].Material_ShadeFront[nSubMesh]=pMaterial_ShadeFront ;
+			m_pEntityInfo[nEntity].Material_ShadeBack[nSubMesh]=pMaterial_ShadeBack ;
+			m_pEntityInfo[nEntity].Material_DfShPosition[nSubMesh]=pMaterial_DfShPosition ;
+			m_pEntityInfo[nEntity].Material_DfShDiffuse[nSubMesh]=pMaterial_DfShDiffuse ;
+			//m_pEntityInfo[nEntity].Material_DSNormal[nSubMesh]=pMaterial_DSNormal ;
+			m_pEntityInfo[nEntity].Material_DfShFuncTNB[nSubMesh]=pMaterial_DfShFuncTNB ;
+			m_pEntityInfo[nEntity].Material_DfShSpecular[nSubMesh]=pMaterial_DfShSpecular ;
+			m_pEntityInfo[nEntity].Material_DfShEmissive[nSubMesh]=pMaterial_DfShEmissive ;
+			//m_pEntityInfo[nEntity].Material_DfShData[nSubMesh]=pMaterial_DfShData ;
+			m_pEntityInfo[nEntity].Material_DfShMix[nSubMesh]=pMaterial_DfShMix ;
+
+			
+			//////////////////////////////////////////////////////////////////////////////////////////
+
+			char chNewName[1024] ;
+			for(nPTex=0 ; nPTex<MAX_PROJECTORTEX ; nPTex++)
+			{
+				Ogre::AliasTextureNamePairList AliasList ;
+				
+				// check the necessary texture exists
+				//if(TextureManager::getSingleton().getByName(m_Q3Map->m_chSpotlightTexture[nPTex]).isNull())
+				//	OFBug.MessageInt(666) ;
+				
+				AliasList.insert(AliasTextureNamePairList::value_type("projector_tex", m_Q3Map->m_chSpotlightTexture[nPTex]));
+
+				sprintf(chNewName, "%s_%i", chMaterial_Base, 0) ;
+				m_pEntityInfo[nEntity].Material_Base[nPTex][nSubMesh]=pMaterial_Base->clone(chNewName) ;
+				// change the texture unit
+				m_pEntityInfo[nEntity].Material_Base[nPTex][nSubMesh]->applyTextureAliases(AliasList) ;
+
+				sprintf(chNewName, "%s_%i", chMaterial_Fast, 0) ;
+				m_pEntityInfo[nEntity].Material_Fast[nPTex][nSubMesh]=pMaterial_Fast->clone(chNewName) ;
+				// change the texture unit
+				m_pEntityInfo[nEntity].Material_Fast[nPTex][nSubMesh]->applyTextureAliases(AliasList) ;
+
+			}
+
+			// create the sub scenenodes
+			//sprintf(chSubNodeName, "Entity_%05i_%05i", nEntity, nSubMesh) ;
+			//m_pEntityInfo[nEntity].pSubNode[nSubMesh]=m_pEntityInfo[nEntity].pMasterNode->createChildSceneNode(chSubNodeName) ;
+
+
+			sprintf(m_chBug, "Node %s, Subnode %s, Type %i", chMasterNodeName, chSubNodeName, m_pEntityInfo[nEntity].SubMeshMaterialType[nSubMesh]) ;
+			m_pLog->logMessage(m_chBug);
+		
+		}// end for submesh
+
+		// build tangent vectors for the mesh
+		m_pEntityInfo[nEntity].pEnt->getMesh()->suggestTangentVectorBuildParams(VES_TANGENT, src, dest) ;
+		m_pEntityInfo[nEntity].pEnt->getMesh()->buildTangentVectors(VES_TANGENT, src, dest);
+
+
+	// default to not active, not visible and in no zones
+	m_pEntityInfo[nEntity].Active=0 ;
+	m_pEntityInfo[nEntity].Visible=0 ;
+	m_pEntityInfo[nEntity].Zone[INDEX_ENTITYZONECOUNT]=0 ;
+
+	// add some info about the bounding box
+	Ogre::AxisAlignedBox aabb ;
+	Ogre::Vector3 Minimum ;
+	Ogre::Vector3 Maximum ;
+
+	aabb=m_pEntityInfo[nEntity].pEnt->getBoundingBox() ;
+	Minimum=aabb.getMinimum() ;
+	Maximum=aabb.getMaximum() ;
+
+	m_pEntityInfo[nEntity].AABB=aabb ;
+	m_pEntityInfo[nEntity].Centre.x=(Maximum.x-Minimum.x)/2.0f ;
+	m_pEntityInfo[nEntity].Centre.y=(Maximum.y-Minimum.y)/2.0f ;
+	m_pEntityInfo[nEntity].Centre.z=(Maximum.z-Minimum.z)/2.0f ;
+
+	m_pEntityInfo[nEntity].AABBMin[0]=Minimum.x ;
+	m_pEntityInfo[nEntity].AABBMin[1]=Minimum.y ;
+	m_pEntityInfo[nEntity].AABBMin[2]=Minimum.z ;
+	m_pEntityInfo[nEntity].AABBMax[0]=Maximum.x ;
+	m_pEntityInfo[nEntity].AABBMax[1]=Maximum.y ;
+	m_pEntityInfo[nEntity].AABBMax[2]=Maximum.z ;
+
+
+	m_pEntityInfo[nEntity].Postition=Ogre::Vector3(0.0f, 0.0f, 0.0f) ;
+
+
+
+	return 1 ;
+}
+
+
+// Hmm... wanted to control some CG compiling, mainly to turn shadow filtering on or off, but I couln't get this to work.
+// I ended up just manually creating filtered and unfiltered version of the materials.
+/*
+int OgreFramework::ApplyCGDefines(void)
+{
+	int nZoneMO=0 ;
+	int nMaxZoneMO=m_nZoneMOStart[m_Q3Map->m_nMaxZone] ;
+	int nPTex=0 ;
+	
+	Ogre::Pass *CGPass ;
+	int nPass=0 ;
+	int nMaxPass=0 ;
+
+	for(nZoneMO=0 ; nZoneMO<nMaxZoneMO ; nZoneMO++)
+	{
+		//OFBug.MessageInt(nZoneMO, nMaxZoneMO, m_pZoneEntityMaterialType[nZoneMO]) ;
+		
+		if(m_pZoneEntityMaterialType[nZoneMO]==MAT_OPAQUE)
+			for(nPTex=0 ; nPTex<MAX_PROJECTORTEX ; nPTex++)
+			{
+				//m_pZoneEntityMaterial_Base[nPTex][nZoneMO]->getTechnique(0)->getPass(1)->getFragmentProgram()->setParameter("compile_arguments", "-DFILTER_ON 1") ;
+				nMaxPass=m_pZoneEntityMaterial_Base[nPTex][nZoneMO]->getTechnique(0)->getNumPasses() ;
+				
+				for(nPass=0 ; nPass<nMaxPass ; nPass++)
+				{
+					m_pZoneEntityMaterial_Base[nPTex][nZoneMO]->getTechnique(0)->getPass(nPass)->getFragmentProgram()->setParameter("compile_arguments", "-DFILTER_ON=1") ;
+					//m_pZoneEntityMaterial_Base[nPTex][nZoneMO]->getTechnique(0)->getPass(nPass)->getFragmentProgram()->reload();
+				}	
+				//CGPass=m_pZoneEntityMaterial_Base[nPTex][nZoneMO]->getTechnique(0)->getPass(0) ;
+			}
+	}
+	
+
+	//m_pZoneEntityMaterial_Base[0][0]->getTechnique(0)->getPass(1)->getFragmentProgram()->setParameter("compile_arguments", "-DFILTER_ON 1") ;
+		
+
+	return 1 ;
+
+
+}
+*/
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// create light manual objects, just for debugging/testing.
+// This is an array of manualobject AABBs that show the light culling box (double sided) for each light
+
+int OgreFramework::AddLightCullingBoxes()
+{
+	int nLt=0 ;
+	// for calculating bounds of mesh
+	float flMinX=0.0f ;
+	float flMinY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxX=0.0f ;
+	float flMaxY=0.0f ;
+	float flMaxZ=0.0f ;
+	int nMaxLight=m_Q3Map->m_nLightMax ;
+
+	char chSceneNodeName[1024] ;
+	char chManualName[1024] ;
+
+	m_pLightMO = new Ogre::ManualObject*[nMaxLight] ;
+	if(m_pLightMO==NULL) return 0 ; // fail, out of mem
+
+	for(nLt=0 ; nLt<nMaxLight ; nLt++)
+	{
+		
+		sprintf(chManualName, "LightMO_%05i", nLt) ;
+		m_pLightMO[nLt]=m_pSceneMgr->createManualObject(chManualName) ;
+
+		// start defining the manualObject
+		m_pLightMO[nLt]->begin("lighttest", RenderOperation::OT_TRIANGLE_LIST) ;
+
+		
+		flMinX=m_Q3Map->m_pLight[nLt].Min[0] ;
+		flMinY=m_Q3Map->m_pLight[nLt].Min[1] ;
+		flMinZ=m_Q3Map->m_pLight[nLt].Min[2] ;
+
+		flMaxX=m_Q3Map->m_pLight[nLt].Max[0] ;
+		flMaxY=m_Q3Map->m_pLight[nLt].Max[1] ;
+		flMaxZ=m_Q3Map->m_pLight[nLt].Max[2] ;
+		
+		
+		//////////////////////////////////////////////////////
+		// back face
+		m_pLightMO[nLt]->position(flMinX, flMaxY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMaxY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMinY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 1.0) ;
+
+		m_pLightMO[nLt]->position(flMinX, flMinY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 1.0) ;
+
+		m_pLightMO[nLt]->quad(0, 1, 2, 3) ;
+		m_pLightMO[nLt]->quad(3, 2, 1, 0) ;
+
+		//////////////////////////////////////////////////////
+		// front face
+		m_pLightMO[nLt]->position(flMinX, flMaxY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, 1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMaxY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, 1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMinY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, 1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 1.0) ;
+
+		m_pLightMO[nLt]->position(flMinX, flMinY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, 1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 1.0) ;
+
+		m_pLightMO[nLt]->quad(7, 6, 5, 4) ;
+		m_pLightMO[nLt]->quad(4, 5, 6, 7) ;
+
+		//////////////////////////////////////////////////////
+		// left face
+		m_pLightMO[nLt]->position(flMinX, flMaxY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMinX, flMaxY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMinX, flMinY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 1.0) ;
+
+		m_pLightMO[nLt]->position(flMinX, flMinY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 1.0) ;
+
+		m_pLightMO[nLt]->quad(8, 9, 10, 11) ;
+		m_pLightMO[nLt]->quad(11, 10, 9, 8) ;
+
+		
+		//////////////////////////////////////////////////////
+		// right face
+		m_pLightMO[nLt]->position(flMaxX, flMaxY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, 1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMaxY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, 1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMinY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, 1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 1.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMinY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, 1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 1.0) ;
+
+		m_pLightMO[nLt]->quad(15, 14, 13, 12) ;
+		m_pLightMO[nLt]->quad(12, 13, 14, 15) ;
+
+		//////////////////////////////////////////////////////
+		// top face
+		m_pLightMO[nLt]->position(flMinX, flMaxY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 1.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMaxY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 1.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMaxY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMinX, flMaxY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 0.0) ;
+
+		m_pLightMO[nLt]->quad(16, 17, 18, 19) ;
+		m_pLightMO[nLt]->quad(19, 18, 17, 16) ;
+
+		//////////////////////////////////////////////////////
+		// bottom face
+		m_pLightMO[nLt]->position(flMinX, flMinY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMinY, flMaxZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 0.0) ;
+
+		m_pLightMO[nLt]->position(flMaxX, flMinY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(1.0, 1.0) ;
+
+		m_pLightMO[nLt]->position(flMinX, flMinY, flMinZ) ;
+		m_pLightMO[nLt]->normal(0.0, 0.0, -1) ;
+		m_pLightMO[nLt]->textureCoord(0.0, 1.0) ;
+
+		m_pLightMO[nLt]->quad(23, 22, 21, 20) ;
+		m_pLightMO[nLt]->quad(20, 21, 22, 23) ;
+		//////////////////////////////////////////////////////
+
+		m_pLightMO[nLt]->end() ;
+
+
+
+		sprintf(chSceneNodeName, "LSN%05i", nLt) ;
+		m_pSceneMgr->getRootSceneNode()->createChildSceneNode(chSceneNodeName)->attachObject(m_pLightMO[nLt]) ;
+
+		
+	}
+
+	return 1 ;
+}
+
+int OgreFramework::AddPortalBoxes()
+{
+	int nPt=0 ;
+	// for calculating bounds of mesh
+	float flMinX=0.0f ;
+	float flMinY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxX=0.0f ;
+	float flMaxY=0.0f ;
+	float flMaxZ=0.0f ;
+	int nMaxPortal=m_Q3Map->m_iNumPortals ;
+
+	char chSceneNodeName[1024] ;
+	char chManualName[1024] ;
+
+	m_pPortalMO = new Ogre::ManualObject*[nMaxPortal] ;
+	if(m_pPortalMO==NULL) return 0 ; // fail, out of mem
+
+	m_pPortalNode = new Ogre::Node*[nMaxPortal] ;
+	if(m_pPortalNode==NULL) 
+	{
+		//CHECKDELETE_ARRAY( m_pPortalMO ) ;
+		return 0 ; // fail, out of mem
+	}
+
+	for(nPt=0 ; nPt<nMaxPortal ; nPt++)
+	{
+		
+		sprintf(chManualName, "PortalMO_%05i", nPt) ;
+		m_pPortalMO[nPt]=m_pSceneMgr->createManualObject(chManualName) ;
+
+		// start defining the manualObject
+		m_pPortalMO[nPt]->begin("white", RenderOperation::OT_TRIANGLE_LIST) ;
+
+		flMinX=m_Q3Map->m_pPortals[nPt].Min[0] ;
+		flMinY=m_Q3Map->m_pPortals[nPt].Min[1] ;
+		flMinZ=m_Q3Map->m_pPortals[nPt].Min[2] ;
+
+		flMaxX=m_Q3Map->m_pPortals[nPt].Max[0] ;
+		flMaxY=m_Q3Map->m_pPortals[nPt].Max[1] ;
+		flMaxZ=m_Q3Map->m_pPortals[nPt].Max[2] ;
+		
+		
+		//////////////////////////////////////////////////////
+		// back face
+		m_pPortalMO[nPt]->position(flMinX, flMaxY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMaxY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMinY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 1.0) ;
+
+		m_pPortalMO[nPt]->position(flMinX, flMinY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 1.0) ;
+
+		m_pPortalMO[nPt]->quad(0, 1, 2, 3) ;
+		m_pPortalMO[nPt]->quad(3, 2, 1, 0) ;
+
+		//////////////////////////////////////////////////////
+		// front face
+		m_pPortalMO[nPt]->position(flMinX, flMaxY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, 1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMaxY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, 1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMinY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, 1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 1.0) ;
+
+		m_pPortalMO[nPt]->position(flMinX, flMinY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, 1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 1.0) ;
+
+		m_pPortalMO[nPt]->quad(7, 6, 5, 4) ;
+		m_pPortalMO[nPt]->quad(4, 5, 6, 7) ;
+
+		//////////////////////////////////////////////////////
+		// left face
+		m_pPortalMO[nPt]->position(flMinX, flMaxY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMinX, flMaxY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMinX, flMinY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 1.0) ;
+
+		m_pPortalMO[nPt]->position(flMinX, flMinY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 1.0) ;
+
+		m_pPortalMO[nPt]->quad(8, 9, 10, 11) ;
+		m_pPortalMO[nPt]->quad(11, 10, 9, 8) ;
+
+		
+		//////////////////////////////////////////////////////
+		// right face
+		m_pPortalMO[nPt]->position(flMaxX, flMaxY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, 1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMaxY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, 1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMinY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, 1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 1.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMinY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, 1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 1.0) ;
+
+		m_pPortalMO[nPt]->quad(15, 14, 13, 12) ;
+		m_pPortalMO[nPt]->quad(12, 13, 14, 15) ;
+
+		//////////////////////////////////////////////////////
+		// top face
+		m_pPortalMO[nPt]->position(flMinX, flMaxY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 1.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMaxY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 1.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMaxY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMinX, flMaxY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 0.0) ;
+
+		m_pPortalMO[nPt]->quad(16, 17, 18, 19) ;
+		m_pPortalMO[nPt]->quad(19, 18, 17, 16) ;
+
+		//////////////////////////////////////////////////////
+		// bottom face
+		m_pPortalMO[nPt]->position(flMinX, flMinY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMinY, flMaxZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 0.0) ;
+
+		m_pPortalMO[nPt]->position(flMaxX, flMinY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(1.0, 1.0) ;
+
+		m_pPortalMO[nPt]->position(flMinX, flMinY, flMinZ) ;
+		m_pPortalMO[nPt]->normal(0.0, 0.0, -1) ;
+		m_pPortalMO[nPt]->textureCoord(0.0, 1.0) ;
+
+		m_pPortalMO[nPt]->quad(23, 22, 21, 20) ;
+		m_pPortalMO[nPt]->quad(20, 21, 22, 23) ;
+		//////////////////////////////////////////////////////
+
+		m_pPortalMO[nPt]->end() ;
+
+
+
+		sprintf(chSceneNodeName, "PSN%05i", nPt) ;
+		m_pSceneMgr->getRootSceneNode()->createChildSceneNode(chSceneNodeName)->attachObject(m_pPortalMO[nPt]) ;
+		m_pPortalNode[nPt]=m_pSceneMgr->getRootSceneNode()->getChild(chSceneNodeName) ;
+		
+	}
+
+	return 1 ;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+// this function calculates which zones are visible.  
+// If they are in the view frustum and any connecting portals are open, they're visible.  
+// It calls a recursive functions that goes into each visible zone and scans it's portals 
+// for more visible zones, cutting down the frustum as it goes.
+//
+// This function also checks which lights are visible.
+// First it scans the original zone the camera is in, any light whose centre is in that zone
+// is visible regardless of how many other zones that light touches.
+// Lights that are completely contained in any of the further zones are checked against the
+// current cut down frustum.
+void OgreFramework::CalculateZoneVisibility(Ogre::Camera *pCamera, int *pCameraZone, char* pZoneVis, char* pLightVis, char* pSubLightVis, char* pPortalVis, int* pMaxVisibleLight, unsigned short* pVisibleLightList)
+{
+
+	
+	int nZone=0 ;
+//	int nZoneIndex=0 ;
+	int nSubZone=0 ;
+//	int nSubZoneIndex=0 ;
+	int nMaxSubZone=0 ;
+	int nPortal=0 ;
+//	int nPortalIndex=0 ;
+	int nMaxPortal=0 ;
+//	int nMaxPortalZone=0 ;
+//	int nPortalZone=0 ;
+//	int nPortalZoneIndex=0 ;
+//	int nMaxZone=0 ;
+	
+
+	int nMaxLight=m_Q3Map->m_nLightMax ;
+	int nLt=0 ;
+
+//	int nMaxSubLight=m_Q3Map->m_nSubLightMax ;
+	int nSubLt=0 ;
+	
+	m_nMaxVisibleLight=0 ;
+
+	
+
+	Ogre::Vector3 Pos=pCamera->getPosition() ;
+	float flPos[3]={Pos.x, Pos.y, Pos.z} ;
+
+	Ogre::AxisAlignedBox AAB ;
+
+
+
+	// initially all lights are invisible
+	// set all remaining real lights to invisible
+	SetAllLightsOff() ;
+
+	m_nTotalTriangles=0 ;
+
+	*pMaxVisibleLight=0 ; // no lights in the list 
+	
+	if(m_nZoneCullingActive) // if zone culling is active
+	{
+		
+		// by default, all zones are not visible
+		nZone=m_Q3Map->m_nMaxZone ;
+		while(nZone)
+			pZoneVis[--nZone]=ZONE_UNCHECKED ;
+
+		// by default, all lights are not visible
+		nLt=nMaxLight ;
+		while(nLt)
+			pLightVis[--nLt]=LIGHT_UNCHECKED ;
+
+		// by default, all lights are not visible
+		nSubLt=m_Q3Map->m_nSubLightMax ;
+		while(nSubLt)
+			pSubLightVis[--nSubLt]=LIGHT_UNCHECKED ;
+
+		// by default, all portals are not visible
+		nPortal=m_Q3Map->m_iNumPortals ;
+		while(nPortal)
+			pPortalVis[--nPortal]=PORTAL_UNCHECKED ;
+	}
+	else
+	{
+		// for debugging, all zones are visible
+		nZone=m_Q3Map->m_nMaxZone ;
+		while(nZone)
+			pZoneVis[--nZone]=ZONE_VISIBLE ;
+
+
+		// by default, all lights are visible
+		nLt=nMaxLight ;
+		while(nLt)
+			pLightVis[--nLt]=LIGHT_VISIBLE ;
+
+		nSubLt=m_Q3Map->m_nSubLightMax ;
+		while(nSubLt)
+			pSubLightVis[--nSubLt]=LIGHT_VISIBLE ;
+
+		// by default, all portals are visible
+		nPortal=m_Q3Map->m_iNumPortals ;
+		while(nPortal)
+			pPortalVis[--nPortal]=PORTAL_VISIBLE ;
+
+		return ;
+	}
+
+
+
+
+
+
+
+
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	
+
+
+	/////////////////////////////////////////////////////////////////////////////////////
+	// check camera is actually in the zone designated, otherwise update it.
+
+	if((*pCameraZone==-1) || (!m_Q3Map->PointInZone(flPos, *pCameraZone)) )
+	{
+
+		nSubZone=m_Q3Map->GetNextSubZone(flPos, -1, m_Q3Map->m_iNumSubZones) ;
+			
+		// subzone might still be -1 if the point isn't in any zone.  If this happens, set all zones in the view frustum as visible.
+		// this shouldn't generally happen, but if we aren't clipping and are flying around testing, it can.
+		// Don't worry about optimizing this.
+
+
+
+		if(nSubZone==-1)
+		{
+
+			nMaxSubZone=m_Q3Map->m_iNumSubZones ;
+			for(nSubZone=0 ; nSubZone<nMaxSubZone ; nSubZone++)
+			{
+				AAB.setExtents(m_Q3Map->m_pSubZones[nSubZone].Min[0], m_Q3Map->m_pSubZones[nSubZone].Min[1], m_Q3Map->m_pSubZones[nSubZone].Min[2], m_Q3Map->m_pSubZones[nSubZone].Max[0], m_Q3Map->m_pSubZones[nSubZone].Max[1], m_Q3Map->m_pSubZones[nSubZone].Max[2]) ;
+
+				if(pCamera->isVisible(AAB))
+					pZoneVis[ m_Q3Map->m_pSubZones[nSubZone].Zone ]=ZONE_VISIBLE ;
+			}	
+
+			*pCameraZone=-1 ;
+			return ; // skip everything else
+		}
+
+		*pCameraZone=m_Q3Map->m_pSubZones[nSubZone].Zone ; // update the zone
+	
+	}
+
+	//
+	/////////////////////////////////////////////////////////////////////////////////////
+
+
+	// update the portal states
+	nMaxPortal=m_Q3Map->m_iNumPortals ;
+	nPortal=nMaxPortal ;
+	while(nPortal)
+	{
+		nPortal-- ;
+
+		if(m_nPortalDebug==0)
+			m_chPortalState[nPortal]=PORTALSTATE_OPEN ; 
+		else
+		{
+			//if(m_nPortalState==1)
+				m_chPortalState[nPortal]=PORTALSTATE_OPEN ; 
+			//else
+			//	m_chPortalState[nPortal]=PORTALSTATE_CLOSED ;
+
+
+			
+		}
+		
+		//m_chPortalState[nPortal]|=PORTAL_FLAG_UNCHECKED ; // by default all portals are unchecked
+		
+		//m_chPortalState[nPortal]&=~(PORTAL_FLAG_VISCHECK|PORTAL_FLAG_VISIBLE) ; // by default, all portals are vis unchecked and not visible
+	}
+
+	//m_chPortalState[0]=PORTAL_FLAG_CLOSED ;
+	if(m_nPortalState==1)
+		m_chPortalState[1]=PORTALSTATE_OPEN ;
+	else
+		m_chPortalState[1]=PORTALSTATE_CLOSED ;
+
+
+
+
+	//Ogre::Camera* pTestCamera ;
+	//pTestCamera->synchroniseBaseSettingsWith(pCamera) ;
+
+	//Ogre::Real OrigL, OrigR, OrigT, OrigB ; // original frustum extents
+	//pCamera->getFrustumExtents(OrigL, OrigR, OrigT, OrigB) ;
+	
+	//pCamera->setFrustumExtents(OrigL/2.0, OrigR/2.0, OrigT/2.0, OrigB/2.0) ; // reset the original frustum extents
+
+	m_nRecurseCount=0 ;
+
+	
+	// work out the aspect scaling we'll need
+	Ogre::Real OrigL, OrigR, OrigT, OrigB, ScaleX, ScaleY ; // frustum extents per each portal in this zone
+	Ogre::Real NewL, NewR, NewT, NewB ;
+	pCamera->getFrustumExtents(OrigL, OrigR, OrigT, OrigB) ;
+
+	m_ViewMatrix=pCamera->getViewMatrix(true) ;
+	m_ProjectionMatrix=pCamera->getProjectionMatrix() ;
+	
+
+	//if(m_nOriginalZoneOpenPortals=0) // no portals on player zone are open, so we can only see the current zones.
+	//	pZoneVis[nZone]=ZONE_VISIBLE ; // flag this subzone as visible
+	//else
+	{
+
+		/*
+		// apply the stereofrustum tweak if needed
+		if(m_flStereoFrustumTweak!=0.0f)
+		{
+
+			NewL=OrigL-m_flStereoFrustumTweak ;
+			NewR=OrigR+m_flStereoFrustumTweak ;
+			NewT=OrigT ;
+			NewB=OrigB ;
+			pCamera->setFrustumExtents(NewL, NewR, NewT, NewB) ;
+		}
+		else
+		*/
+		{
+			NewL=OrigL ;
+			NewR=OrigR ;
+			NewT=OrigT ;
+			NewB=OrigB ;
+		}
+		
+		ScaleX=NewR ;
+		ScaleY=NewT ;
+
+
+		PortalScan(pCamera, *pCameraZone, ScaleX, ScaleY, pZoneVis, pLightVis, pSubLightVis, pPortalVis, pMaxVisibleLight, pVisibleLightList) ; // recursively scan portals and work out zone visibility
+
+		
+		pCamera->setFrustumExtents(OrigL, OrigR, OrigT, OrigB) ; // reset the original frustum extents
+
+		CheckMultiZoneLights(*pCameraZone, pZoneVis, pLightVis, pSubLightVis) ;
+		AddZonesFromMultiZoneLights(pZoneVis, pLightVis, pSubLightVis) ;
+
+		// check entity visibility
+		
+
+	}
+
+
+
+
+
+
+
+	
+}
+
+
+void OgreFramework::SetupEntityZones(void)
+{
+	// work out what zones any active entities are in.
+	int nEntity=0 ;
+	float Centre[3] ;
+	float AABBMin[3] ;
+	float AABBMax[3] ;
+	float* pLightMin ;
+	float* pLightMax ;
+	
+	int nOldZone=0 ;
+	int nCurrentZone=0 ;
+	int nMaxOldZone=0 ;
+	int nZonePerZoneIndex=0 ;
+	int nZone=0 ;
+	int nZoneIndex=0 ;
+	int nMaxZone=0 ;
+	int nMaxSubLightIndex=0 ;
+	int nSubLightIndex=0 ;
+	int nSubLight=0 ;
+
+//	int nLight=0;
+	int nLightIndex=0 ;
+
+
+	
+
+	for(nEntity=0 ; nEntity<m_nMaxEntity ; nEntity++)
+		if(m_pEntityInfo[nEntity].Active)
+		{
+			nLightIndex=0 ;
+			// to calculate what zones an entity is in, we test the centre of it's bounding box to get the main zone.
+			// we then test all zones that touch the central zone and see if they touch the entity bounding box.
+
+			// check if the entity central point is still in the same zone as last time.
+			Centre[0]=m_pEntityInfo[nEntity].Centre.x + m_pEntityInfo[nEntity].Postition.x ;
+			Centre[1]=m_pEntityInfo[nEntity].Centre.y + m_pEntityInfo[nEntity].Postition.y ;
+			Centre[2]=m_pEntityInfo[nEntity].Centre.z + m_pEntityInfo[nEntity].Postition.z ;
+
+			nMaxOldZone=m_pEntityInfo[nEntity].Zone[INDEX_ENTITYZONECOUNT] ;
+
+
+
+			if(nMaxOldZone>0)
+			{
+				nOldZone=m_pEntityInfo[nEntity].Zone[0] ;
+				if(m_Q3Map->PointInZone(Centre, nOldZone))
+					nCurrentZone=nOldZone ;	// still in the same zone as last round
+				else
+				{
+					// see if we are in one of the other zones that were touched by this entity's aabb last round
+
+					nCurrentZone=-1 ;
+					for(nZoneIndex=1 ; nZoneIndex<nMaxOldZone ; nZoneIndex++)
+					{
+						if(m_Q3Map->PointInZone(Centre, m_pEntityInfo[nEntity].Zone[nZoneIndex]))
+						{
+							nCurrentZone=m_pEntityInfo[nEntity].Zone[nZoneIndex] ; // found the current zone we are in
+							break ;
+						}// end if point in zone
+
+					}// end for zoneindex
+
+				}// end if not in old zone.
+			}
+			else
+				nCurrentZone=-1 ;
+
+
+			// if we haven't found the current zone so far, we need to check every zone.
+			if(nCurrentZone==-1)
+			{
+				nZone=m_Q3Map->m_nMaxZone ;
+				while(nZone)
+					if(m_Q3Map->PointInZone(Centre, --nZone))
+					{
+						nCurrentZone=nZone ;
+						break ;
+					}
+			}// end if nCurrentZone -1
+
+
+			
+			// now either nCurrentZone is the zone the central point is in, or the entity isn't in any zone
+			if(nCurrentZone==-1)
+				m_pEntityInfo[nEntity].Zone[INDEX_ENTITYZONECOUNT]=0 ;
+			else
+			{
+				// scan through all the zones that touch this entitys central zone
+				// see if the entitys AABB touches those other zones.
+				m_pEntityInfo[nEntity].Zone[0]=nCurrentZone ;
+				nZonePerZoneIndex=1 ;
+				
+				AABBMin[0]=m_pEntityInfo[nEntity].Postition.x + m_pEntityInfo[nEntity].AABBMin[0] ; 
+				AABBMin[1]=m_pEntityInfo[nEntity].Postition.y + m_pEntityInfo[nEntity].AABBMin[1] ; 
+				AABBMin[2]=m_pEntityInfo[nEntity].Postition.z + m_pEntityInfo[nEntity].AABBMin[2] ;
+
+				AABBMax[0]=m_pEntityInfo[nEntity].Postition.x + m_pEntityInfo[nEntity].AABBMax[0] ; 
+				AABBMax[1]=m_pEntityInfo[nEntity].Postition.y + m_pEntityInfo[nEntity].AABBMax[1] ; 
+				AABBMax[2]=m_pEntityInfo[nEntity].Postition.z + m_pEntityInfo[nEntity].AABBMax[2] ;
+
+
+				nMaxZone=m_Q3Map->m_nZoneTouchesZone[nCurrentZone][INDEX_ZONEPERZONECOUNT] ;
+				for(nZoneIndex=0 ; nZoneIndex<nMaxZone ; nZoneIndex++)
+				{
+					nZone=m_Q3Map->m_nZoneTouchesZone[nCurrentZone][nZoneIndex] ;
+
+					if(m_Q3Map->AABBTouchesZone(AABBMin, AABBMax, nZone)) 
+					{
+						m_pEntityInfo[nEntity].Zone[nZonePerZoneIndex]=nZone ;
+						nZonePerZoneIndex++ ;
+
+						if(nZonePerZoneIndex>MAX_ZONEPERENTITY)
+							nZonePerZoneIndex=MAX_ZONEPERENTITY ;
+					}
+
+					
+
+				}// end for nZoneIndex
+
+
+				m_pEntityInfo[nEntity].Zone[INDEX_ENTITYZONECOUNT]=nZonePerZoneIndex ;
+
+				// go through all the zones and check which lights touch this entity AABB
+				for(nZoneIndex=0 ; nZoneIndex<nZonePerZoneIndex ; nZoneIndex++)
+				{
+					nZone=m_pEntityInfo[nEntity].Zone[nZoneIndex] ;
+
+					nMaxSubLightIndex=m_Q3Map->m_nZoneTouchesSubLight[nZone][MAX_LIGHTPERZONE] ;
+					for(nSubLightIndex=0 ; nSubLightIndex<nMaxSubLightIndex ; nSubLightIndex++)
+					{
+						nSubLight=m_Q3Map->m_nZoneTouchesSubLight[nZone][nSubLightIndex] ;
+						pLightMin=m_Q3Map->m_SubLight[nSubLight].Min ;
+						pLightMax=m_Q3Map->m_SubLight[nSubLight].Max ;
+
+						// if the entity overlaps the sublight
+						if(
+									 (AABBMin[0]<pLightMax[0]) && (AABBMax[0]>pLightMin[0])
+								&& (AABBMin[1]<pLightMax[1]) && (AABBMax[1]>pLightMin[1])
+								&& (AABBMin[2]<pLightMax[2]) && (AABBMax[2]>pLightMin[2])
+							)
+						{
+							// add this to the list of lights.
+							// it's possible it might get listed more than once if this is a multizone light, that's ok.
+			
+							m_pEntityInfo[nEntity].Light[nLightIndex]=m_Q3Map->m_SubLight[nSubLight].Light ;
+							nLightIndex++ ;
+							if(nLightIndex>MAX_LIGHTPERENTITY)
+								nLightIndex=MAX_LIGHTPERENTITY ;
+
+
+						} // end if overlap
+
+					}// end for nSubLightIndex
+
+				}// end for nZoneIndex
+
+			}// end if we have a central zone
+			
+			
+			m_pEntityInfo[nEntity].Light[INDEX_LIGHTPERENTITY]=nLightIndex ;
+
+
+		}// end if entity is active
+}
+
+// spotlights need entities set as visible if they are in a visible zone, even if they aren't in the frustum, 
+// because they might cast shadows that are in the frustum.
+// However the deferred render only needs consider entities which are in a visible zone AND in the frustum.
+// m_pVisibleEntity holds entities in visible zones,
+// m_pFrustumEntity holds entities in visible zones that are also in the view frustum.
+void OgreFramework::CalculateEntityVisibility(Ogre::Camera* pCamera, char* pZoneVis)
+{
+
+	int nEntity=0 ;
+	int nMaxZone=0 ;
+	int nZone=0 ;
+	int nZoneIndex=0 ;
+//	int nVisible=0 ;
+	Ogre::AxisAlignedBox AABB ;
+
+
+	m_nMaxVisibleEntity=0 ; // default to an empty list 
+	m_nMaxFrustumEntity=0 ; // default to an empty list 
+
+	m_nVisibleEntityTriangleCount=0 ;
+	m_nFrustumEntityTriangleCount=0 ;
+
+	for(nEntity=0 ; nEntity<m_nMaxEntity ; nEntity++)
+		if(m_pEntityInfo[nEntity].Active)
+		{
+			m_pEntityInfo[nEntity].Visible=0 ; // default to not visible
+			m_pEntityInfo[nEntity].Frustum=0 ; // default to not visible and not in frustum
+
+			nMaxZone=m_pEntityInfo[nEntity].Zone[INDEX_ENTITYZONECOUNT] ;
+
+
+
+				for(nZoneIndex=0 ; nZoneIndex<nMaxZone ; nZoneIndex++)
+				{
+					nZone=m_pEntityInfo[nEntity].Zone[nZoneIndex] ;
+
+					// if a zone this entity touches is visible, test if it is in the view frustrum	
+					if(pZoneVis[nZone]==ZONE_VISIBLE)
+					{
+
+						m_pEntityInfo[nEntity].Visible=1 ;
+						m_nVisibleEntityTriangleCount+=m_pEntityInfo[nEntity].TriangleCount ;
+						m_pVisibleEntity[m_nMaxVisibleEntity++]=nEntity ;
+						
+
+						// is this entity also in the view frustum?
+						AABB.setMinimum( m_pEntityInfo[nEntity].AABB.getMinimum() + m_pEntityInfo[nEntity].Postition ) ;
+						AABB.setMaximum( m_pEntityInfo[nEntity].AABB.getMaximum() + m_pEntityInfo[nEntity].Postition ) ;
+
+						if(pCamera->isVisible(AABB))
+						{
+							m_pEntityInfo[nEntity].Frustum=1 ;
+							m_nFrustumEntityTriangleCount+=m_pEntityInfo[nEntity].TriangleCount ;
+							m_pFrustumEntity[m_nMaxFrustumEntity++]=nEntity ;
+						}
+
+
+
+
+
+						break ; // get out of the loop, we know the entity is visible.
+
+					}// end if zone is visible
+
+				}// end for nZoneIndex
+
+		}// end if entity is active
+
+}
+
+
+
+
+
+void OgreFramework::SetAllLightsOff(void)
+{
+	Light *light;
+	char chLightName[1024] ;
+	int nLt=0 ;
+	for(nLt=0 ; nLt<MAXLIGHTPERLOOP ; nLt++)
+	{
+		sprintf(chLightName, "LT%02i", nLt) ;
+		light=m_pSceneMgr->getLight(chLightName) ;
+		light->setVisible(false) ;
+	}
+}
+
+void OgreFramework::SetSingleVisibleLight(int nLt, bool bOn)
+{
+	Light *light;
+
+	light=m_pSceneMgr->getLight("LT00") ;
+
+
+	// if we're just turning the light off, make it invisible and return.
+	if(bOn==false)
+	{
+		light->setVisible(false) ;
+		return ;
+	}
+
+	
+			
+	light->setDiffuseColour(Ogre::ColourValue(1,1,1));
+	light->setSpecularColour(Ogre::ColourValue(1,1,1));
+			
+	light->setAttenuation(m_Q3Map->m_pLight[nLt].Cutoff, 1.0, 1.0, 0.005);
+	light->setPosition(Ogre::Vector3(m_Q3Map->m_pLight[nLt].Position[0], m_Q3Map->m_pLight[nLt].Position[1], m_Q3Map->m_pLight[nLt].Position[2]));
+	light->setDirection(Ogre::Vector3(m_Q3Map->m_pLight[nLt].Direction[0], m_Q3Map->m_pLight[nLt].Direction[1], m_Q3Map->m_pLight[nLt].Direction[2]));
+			
+	light->setSpotlightRange(Degree(m_Q3Map->m_pLight[nLt].Angle-5.0), Degree(m_Q3Map->m_pLight[nLt].Angle), 1.0) ;
+	light->setVisible(true) ;
+}
+
+
+// sets up a single visible light from the visible light list and assigns the camera to its position and settings
+// returns true if successful, false if not (such as if the light isn't actually visible)
+
+bool OgreFramework::SetupSingleVisibleLightAndShadowCamera(int nLt, char* pLightVis, unsigned short* pVisibleLightList, Ogre::Camera* pCamera)
+{
+	//if(nLt!=4) return false ;
+	
+	if((pLightVis[nLt]&LIGHT_VISIBLE)==0) // we need to check this again, since there's a chance a multi-zone light might have been culled at the last stage
+		return false ;
+
+	
+	Light *light=m_pSceneMgr->getLight("LT00") ;
+	
+	light->setDiffuseColour(Ogre::ColourValue(m_Q3Map->m_pLight[nLt].Colour[0], m_Q3Map->m_pLight[nLt].Colour[1], m_Q3Map->m_pLight[nLt].Colour[2]));
+
+	float	flRange=m_Q3Map->m_pLight[nLt].Cutoff ; // set the range
+	if(flRange<10240.0) //!! Ogre seems to cut off lights wrongly if the range is low, so set it to a minimum.
+		flRange=10240 ;
+
+	// The light attenuation parameters have been co-opted by me... they no longer represent range, constant, linear, quadratic
+	// instead, 
+	// first parameter is the above range, just set high so Ogre doesn't turn lights off itself.  The shaders ignore this parameter.
+	// second parameter is the cutoff used in the shader.  Light suddenly cuts off after this distance.
+	// third parameter is the brightness.  This controls the quadratic falloff of the light.
+	// fourth parameter is unused, leave as 1.0 for now.
+
+	light->setAttenuation(flRange, m_Q3Map->m_pLight[nLt].Cutoff, m_Q3Map->m_pLight[nLt].Brightness, 1.0) ;
+	
+	
+	
+	// Ogre uses a fixed yaw axis which will cause pCamera->setDirection to malfunction if we point directly up or down.
+	// To avoid this we need to check for such lights and shift their direction a little.
+	
+	float DirX=m_Q3Map->m_pLight[nLt].Direction[0] ;
+	float DirY=m_Q3Map->m_pLight[nLt].Direction[1] ;
+	float DirZ=m_Q3Map->m_pLight[nLt].Direction[2] ;
+	
+
+	if((DirY>1.0-CAMERA_EPSILON) && (DirY<1.0+CAMERA_EPSILON)) // camera is pointing directly up
+	{
+		DirX=0.0f ;
+		DirY=1.0f ;
+		DirZ=0.000001f ;
+	}
+	else
+		if((DirY>-1.0-CAMERA_EPSILON) && (DirY<-1.0+CAMERA_EPSILON)) // camera is pointing directly down
+		{
+			DirX=0.0f ;
+			DirY=-1.0f ;
+			DirZ=0.000001f ;
+		}
+	
+	light->setPosition(Ogre::Vector3(m_Q3Map->m_pLight[nLt].Position[0], m_Q3Map->m_pLight[nLt].Position[1], m_Q3Map->m_pLight[nLt].Position[2]));
+	light->setDirection(Ogre::Vector3(DirX, DirY, DirZ));
+			
+	light->setSpotlightRange(Degree(m_Q3Map->m_pLight[nLt].Angle-5.0), Degree(m_Q3Map->m_pLight[nLt].Angle), 1.0) ;
+	light->setVisible(true) ;
+
+	// setup the camera
+	pCamera->setAspectRatio(1) ;
+	pCamera->yaw(Ogre::Radian(0)) ;
+	pCamera->roll(Ogre::Radian(0)) ;
+	pCamera->pitch(Ogre::Radian(0)) ;
+	pCamera->setPosition(m_Q3Map->m_pLight[nLt].Position[0], m_Q3Map->m_pLight[nLt].Position[1], m_Q3Map->m_pLight[nLt].Position[2]) ;
+	pCamera->setDirection(DirX, DirY, DirZ) ;
+	pCamera->setFOVy( Degree(m_Q3Map->m_pLight[nLt].Angle ) ) ;
+
+	return true ;
+
+}
+
+
+void OgreFramework::UpdateVisibleZoneList(char* pZoneVis, unsigned short* pVisibleZoneList, int* pMaxVisibleZone)
+{
+	int nZone=0 ;
+	int nMaxVisibleZone=0 ;
+
+	for(nZone=0 ; nZone<m_Q3Map->m_nMaxZone ; nZone++)
+		if(pZoneVis[nZone]==ZONE_VISIBLE)
+			pVisibleZoneList[nMaxVisibleZone++]=nZone ;
+
+	*pMaxVisibleZone=nMaxVisibleZone ;
+
+}
+
+void OgreFramework::SetZoneNodeAttachments(unsigned short* pVisibleZoneList, int* pMaxVisibleZone, int nMaterialFlags)
+{
+
+		int nListPos=0 ;
+		int nZone=0 ;
+		int nMaxListPos=*pMaxVisibleZone ;
+
+
+
+		for(nListPos=0 ; nListPos<nMaxListPos ; nListPos++)
+		{
+			nZone=pVisibleZoneList[nListPos] ;
+
+				// if the zone node is not already attached, attach it.
+
+				if( m_nOpaqueNodeUsed[nZone] && (nMaterialFlags&MAT_OPAQUE) && !m_pOpaqueNode[nZone]->isInSceneGraph() )
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pOpaqueNode[nZone]) ;
+
+				if( m_nTransNodeUsed[nZone] && (nMaterialFlags&MAT_GEL) && !m_pTransNode[nZone]->isInSceneGraph() )
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pTransNode[nZone]) ;
+
+				if( m_nLampNodeUsed[nZone] && (nMaterialFlags&MAT_LAMP) && !m_pLampNode[nZone]->isInSceneGraph() )
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pLampNode[nZone]) ;
+
+				if( m_nGlowNodeUsed[nZone] && (nMaterialFlags&MAT_GLOW) && !m_pGlowNode[nZone]->isInSceneGraph() )
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pGlowNode[nZone]) ;
+
+		}
+
+
+			
+/*
+		if(m_nDebugLightBox)
+		{
+			int nLt=0 ;
+			int nMaxLight=m_Q3Map->m_nLightMax ;
+
+			for(nLt=0 ; nLt<nMaxLight ; nLt++)
+				if(m_chLightVis[nLt]==LIGHT_VISIBLE)
+				{
+					m_pLightMO[nLt]->setVisible(true) ;
+
+				}
+				else
+					m_pLightMO[nLt]->setVisible(false) ;
+
+
+
+		}
+
+		if(m_nPortalDebug)
+		{
+			int nPt=0 ;
+			int nMaxPortal=m_Q3Map->m_iNumPortals ;
+
+			for(nPt=0 ; nPt<nMaxPortal ; nPt++)
+				if(
+							(m_chPortalVis[nPt]&PORTAL_VISIBLE) 
+							&&
+							(m_chPortalState[nPt]&PORTALSTATE_CLOSED)
+					)
+					m_pPortalMO[nPt]->setVisible(true) ;
+				else
+					m_pPortalMO[nPt]->setVisible(false) ;
+		}		
+			
+	*/
+}
+
+
+void OgreFramework::SetZoneNodeAttachments(unsigned short* pVisibleZoneList, int* pMaxVisibleZone, int nMaterialFlags, int nLight)
+{
+
+		nLight=IGNORE_LIGHT ;
+
+		int nListPos=0 ;
+		int nZone=0 ;
+		int nMaxListPos=*pMaxVisibleZone ;
+
+		int nLightZone=0 ;
+		int nMaxLightZone=0 ;
+		int nFoundZone=0 ;
+
+
+		for(nListPos=0 ; nListPos<nMaxListPos ; nListPos++)
+		{
+			nZone=pVisibleZoneList[nListPos] ;
+
+			// is this zone touched by this light?
+			if(nLight!=IGNORE_LIGHT)
+			{
+				nMaxLightZone=m_Q3Map->m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT] ;
+
+				nFoundZone=0 ;
+				for(nLightZone=0 ; nLightZone<nMaxLightZone ; nLightZone++)
+					if(m_Q3Map->m_nLightTouchesZone[nLight][nLightZone]==nZone)
+					{
+						nFoundZone=1 ;
+						break ;
+					}
+
+			}
+			else
+				nFoundZone=1 ;
+
+
+			if(nFoundZone) // if the light touches this zone, or we're ignoring lights
+			{
+				// if the zone node is not already attached, attach it.
+
+				if( m_nOpaqueNodeUsed[nZone] && (nMaterialFlags&MAT_OPAQUE) && !m_pOpaqueNode[nZone]->isInSceneGraph() )
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pOpaqueNode[nZone]) ;
+
+				if( m_nTransNodeUsed[nZone] && (nMaterialFlags&MAT_GEL) && !m_pTransNode[nZone]->isInSceneGraph() )
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pTransNode[nZone]) ;
+
+				if( m_nLampNodeUsed[nZone] && (nMaterialFlags&MAT_LAMP) && !m_pLampNode[nZone]->isInSceneGraph() )
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pLampNode[nZone]) ;
+
+				if( m_nGlowNodeUsed[nZone] && (nMaterialFlags&MAT_GLOW) && !m_pGlowNode[nZone]->isInSceneGraph() )
+					m_pSceneMgr->getRootSceneNode()->addChild(m_pGlowNode[nZone]) ;
+			}
+		}
+
+}
+
+bool OgreFramework::LightTouchesZone(int nLight, int nZone)
+{
+		int nLightZone=0 ;
+		int nMaxLightZone=0 ;
+
+		nMaxLightZone=m_Q3Map->m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT] ;
+				
+		for(nLightZone=0 ; nLightZone<nMaxLightZone ; nLightZone++)
+			if(m_Q3Map->m_nLightTouchesZone[nLight][nLightZone]==nZone)
+				return true ;
+
+		return false ;
+}
+
+
+// last chance to cull some more multizone lights
+// Then we set all zones the remaining multizone lights touch to visible so that we get correct shadows
+void OgreFramework::CheckMultiZoneLights(int nCameraZone, char* pZoneVis, char* pLightVis, char* pSubLightVis)
+{
+	int nLightMax=m_Q3Map->m_nMaxMultiZoneLight ;
+	int nLight=0 ;
+	int nLightIndex=0 ;
+//	int nLightVal=0 ;
+	int nOpenPortals=0 ;
+//	int nZoneHasOpenPortals=0 ;
+	int nPortal=0 ;
+	int nPortalIndex=0 ;
+	int nMaxPortal=0 ;
+//	int nZone=0 ;
+//	int nMaxZone=0 ;
+//	int nZoneIndex=0 ;
+
+	int nSubLightMax=0 ;
+//	int nSubLightIndex=0 ;
+	int nSubLight=0 ;
+	int nSubLightStart=0 ;
+
+	int nPortalLightMax=0 ;
+	int nPortalLightIndex=0 ;
+//	int nPortalLight=0 ;
+
+	int nCentreZone=0 ;
+
+
+	for(nLightIndex=0 ; nLightIndex<nLightMax ; nLightIndex++)
+	{
+		nLight=m_Q3Map->m_nMultiZoneLight[nLightIndex] ;
+		if(pLightVis[nLight]==LIGHT_VISIBLE) // try to kill multizone lights that are currently set as visible
+		{
+
+			////////////////////////////////////////////////////////////////////////////////////////////////////////////.
+			// if the zone that contains the centre isn't visible, 
+			// and the portals that the light touches are closed,
+			// then this light can't be visible anywhere else
+
+			nCentreZone=m_Q3Map->m_pLight[nLight].CentreZone ;
+			
+			
+			// is the zone that contains the light centre not visible?
+			if(pZoneVis[nCentreZone]!=ZONE_VISIBLE)
+			{
+				// check the portals on the centre sublight zone.  
+				// If the ones that the light touches are closed, 
+				// then this light can't be visible
+
+				
+				nMaxPortal=m_Q3Map->m_nZoneTouchesPortal[nCentreZone][INDEX_PORTALCOUNT] ;
+				nOpenPortals=0 ;
+				nSubLightStart=m_Q3Map->m_pLight[nLight].SubLightStart ; // the first sublight also contains the light centre
+
+				for(nPortalIndex=0 ; nPortalIndex<nMaxPortal ; nPortalIndex++)
+				{
+					nPortal=m_Q3Map->m_nZoneTouchesPortal[nCentreZone][nPortalIndex] ;
+
+					// if portal's open...
+					if(m_chPortalState[nPortal]&PORTALSTATE_OPEN)
+					{
+						nPortalLightMax=m_Q3Map->m_nPortalTouchesLight[nPortal][INDEX_PORTALLIGHTCOUNT] ;
+						
+						// scan all the lights that touch this portal to see if our current light is one of them
+						for(nPortalLightIndex=0 ; nPortalLightIndex<nPortalLightMax ; nPortalLightIndex++)
+							if(m_Q3Map->m_nPortalTouchesLight[nPortal][nPortalLightIndex]==nLight)
+							{
+								nOpenPortals=1 ;
+								break ;
+							}
+
+					}// end if portal is open
+
+					if(nOpenPortals) break ; // get out if we found an open portal that the light touches
+				}// end for portals
+
+
+
+				// if none of the portals touched by the centre light were open, set this light and it's sublights to not visible
+				if(nOpenPortals==0)
+				{
+					pLightVis[nLight]=LIGHT_UNCHECKED ;
+
+					nSubLightStart=m_Q3Map->m_pLight[nLight].SubLightStart ; // the first sublight also contains the light centre
+					nSubLightMax=nSubLightStart+m_Q3Map->m_pLight[nLight].ZoneCount ; 
+
+					for(nSubLight=nSubLightStart ; nSubLight<nSubLightMax ; nSubLight++)
+						pSubLightVis[nSubLightStart]=LIGHT_UNCHECKED ;
+
+				}// end if no light centre portals that touched lights were open
+
+
+
+			}// end if light centre zone isn't visible
+
+		}// end if light is visibile
+
+	}// end for lightindex
+
+}
+
+
+// for lights that touch multiple zones, work out what additional zones we need to make
+// visible in order that lighting will come out with correct shadows.
+void OgreFramework::AddZonesFromMultiZoneLights(char* pZoneVis, char* pLightVis, char* pSubLightVis)
+{
+	int nLightMax=m_Q3Map->m_nMaxMultiZoneLight ;
+	int nLight=0 ;
+	int nLightIndex=0 ;
+	float flMinX=0.0f ;
+	float flMaxX=0.0f ;
+	float flMinY=0.0f ;
+	float flMaxY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxZ=0.0f ;
+
+	int nSubLightMax=0 ;
+//	int nSubLightIndex=0 ;
+	int nSubLight=0 ;
+	int nSubLightStart=0 ;
+	int nSubLightFirst=0 ;
+
+	int nInnerLight=0 ;
+
+
+	for(nLightIndex=0 ; nLightIndex<nLightMax ; nLightIndex++)
+	{
+		nLight=m_Q3Map->m_nMultiZoneLight[nLightIndex] ;
+		if(pLightVis[nLight]==LIGHT_VISIBLE)
+		{
+			nSubLightStart=m_Q3Map->m_pLight[nLight].SubLightStart ; // the first sublight also contains the light centre
+			nSubLightFirst=nSubLightStart+1 ;// start from the first sublight after the one containing the centre
+			nSubLightMax=nSubLightStart+m_Q3Map->m_pLight[nLight].ZoneCount ; 
+			
+
+			for(nSubLight=nSubLightStart ; nSubLight<nSubLightMax ; nSubLight++)	
+				if(pSubLightVis[nSubLight]==LIGHT_VISIBLE) // sublight is visible (and unchecked)
+				{
+					// create the new AABB
+					// this is bounded by this sublight and the centre holding sublight.  
+					flMinX = m_Q3Map->m_SubLight[nSubLight].Min[0] < m_Q3Map->m_SubLight[nSubLightStart].Min[0] ? m_Q3Map->m_SubLight[nSubLight].Min[0] : m_Q3Map->m_SubLight[nSubLightStart].Min[0] ; 
+					flMinY = m_Q3Map->m_SubLight[nSubLight].Min[1] < m_Q3Map->m_SubLight[nSubLightStart].Min[1] ? m_Q3Map->m_SubLight[nSubLight].Min[1] : m_Q3Map->m_SubLight[nSubLightStart].Min[1] ; 
+					flMinZ = m_Q3Map->m_SubLight[nSubLight].Min[2] < m_Q3Map->m_SubLight[nSubLightStart].Min[2] ? m_Q3Map->m_SubLight[nSubLight].Min[2] : m_Q3Map->m_SubLight[nSubLightStart].Min[2] ; 
+				
+					flMaxX = m_Q3Map->m_SubLight[nSubLight].Max[0] > m_Q3Map->m_SubLight[nSubLightStart].Max[0] ? m_Q3Map->m_SubLight[nSubLight].Max[0] : m_Q3Map->m_SubLight[nSubLightStart].Max[0] ; 
+					flMaxY = m_Q3Map->m_SubLight[nSubLight].Max[1] > m_Q3Map->m_SubLight[nSubLightStart].Max[1] ? m_Q3Map->m_SubLight[nSubLight].Max[1] : m_Q3Map->m_SubLight[nSubLightStart].Max[1] ; 
+					flMaxZ = m_Q3Map->m_SubLight[nSubLight].Max[2] > m_Q3Map->m_SubLight[nSubLightStart].Max[2] ? m_Q3Map->m_SubLight[nSubLight].Max[2] : m_Q3Map->m_SubLight[nSubLightStart].Max[2] ; 
+				
+					for(nInnerLight=nSubLightStart ; nInnerLight<nSubLightMax ; nInnerLight++)
+					{
+
+						
+						if(
+									(nInnerLight!=nSubLight) // no need to test itself
+								&&(pZoneVis[  m_Q3Map->m_SubLight[nInnerLight].Zone  ] != ZONE_VISIBLE) // don't test if already visible
+								// if overlap, InnerLight's zone is visible
+								&&(flMinX<m_Q3Map->m_SubLight[nInnerLight].Max[0]) && (flMaxX>m_Q3Map->m_SubLight[nInnerLight].Min[0])
+								&&(flMinY<m_Q3Map->m_SubLight[nInnerLight].Max[1]) && (flMaxY>m_Q3Map->m_SubLight[nInnerLight].Min[1])
+								&&(flMinZ<m_Q3Map->m_SubLight[nInnerLight].Max[2]) && (flMaxZ>m_Q3Map->m_SubLight[nInnerLight].Min[2])
+							)
+						{
+							pZoneVis[  m_Q3Map->m_SubLight[nInnerLight].Zone  ]=ZONE_VISIBLE ; // flag this zone as visible
+							m_nTotalTriangles+=m_nZoneTriangleCount[ m_Q3Map->m_SubLight[nInnerLight].Zone ] ; // just some stats for interest
+						}
+
+					} // end for innerlight
+					
+				}// end if sublight is visible
+
+		}// end if light is visible
+
+	}// end for nLightIndex
+
+}
+
+// scan all the unchecked portals in a subzone to see if they are visible, 
+// then move into any visible subzones and recurse.
+// scalex and scaley will convert the screen space numbers (-1 to 1) into frustum numbers (varies, often -0.5ish to 0.5ish) which is probably due to screen aspect ratios etc
+
+// we also add visible lights if they are in the view frustum
+void OgreFramework::PortalScan(Ogre::Camera *pCamera, int nZone, Ogre::Real ScaleX, Ogre::Real ScaleY, char* pZoneVis, char* pLightVis, char* pSubLightVis, char* pPortalVis, int* pMaxVisibleLight, unsigned short* pVisibleLightList)
+{
+	Ogre::Real OrigL, OrigR, OrigT, OrigB ; // original frustum extents
+	Ogre::Real PortalL, PortalR, PortalT, PortalB ; // frustum extents per each portal in this zone
+	pCamera->getFrustumExtents(OrigL, OrigR, OrigT, OrigB) ;
+	
+
+	
+
+	Ogre::AxisAlignedBox AAB ;
+
+
+	int nPortalMax=m_Q3Map->m_nZoneTouchesPortal[nZone][INDEX_PORTALCOUNT] ;
+	int nPortalIndex=0 ;
+	int nPortal=0 ;
+
+	int nPortalZoneMax=0 ;
+	int nPortalZone=0 ;
+	int nPortalZoneIndex=0 ;
+
+
+	//////////////////////////////////////////////////////////////////////////////////////
+	//
+	// LIGHTING CHECKS
+	//
+
+	int nLight=0;
+	int nLightVal=0 ;
+//	int nLightIndex=0 ;
+//	int nMaxLight=0 ;
+
+	int nSubLight=0 ;
+	int nSubLightIndex=0 ;
+	int nMaxSubLight=0 ;
+//	int nSubLightVal=0 ;
+
+	
+	// check all lights completely contained in this zone to see if they're visible
+	nMaxSubLight=m_Q3Map->m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT] ;
+	for(nSubLightIndex=0 ; nSubLightIndex<nMaxSubLight ; nSubLightIndex++)
+	{
+		nSubLight=m_Q3Map->m_nZoneTouchesSubLight[nZone][nSubLightIndex] ;
+		//nSubLightVal=m_chSubLightVis[nSubLight] ;
+
+		nLight=m_Q3Map->m_SubLight[nSubLight].Light ;
+		nLightVal=pLightVis[nLight] ;
+
+		// if we haven't previously established that the light is visible or out of the frustum, check it.
+
+			AAB.setExtents(m_Q3Map->m_SubLight[nSubLight].Min[0], m_Q3Map->m_SubLight[nSubLight].Min[1], m_Q3Map->m_SubLight[nSubLight].Min[2], m_Q3Map->m_SubLight[nSubLight].Max[0], m_Q3Map->m_SubLight[nSubLight].Max[1], m_Q3Map->m_SubLight[nSubLight].Max[2]) ;
+			if(pCamera->isVisible(AAB)) // sublight is visible
+			{
+				// flag this light and sublight as visible
+				if((nLightVal!=LIGHT_VISIBLE) && (*pMaxVisibleLight<MAXVISIBLELIGHT))
+				{
+					pVisibleLightList[*pMaxVisibleLight]=nLight ;
+					*pMaxVisibleLight=*pMaxVisibleLight+1 ;
+				}
+				pSubLightVis[nSubLight] = pLightVis[nLight] = LIGHT_VISIBLE ;
+				
+			}
+
+
+	}// end for lights in zone
+	
+
+	//
+	///////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+	pZoneVis[nZone]=ZONE_VISIBLE ; // flag this zone as visible
+	m_nTotalTriangles+=m_nZoneTriangleCount[nZone] ; // just some stats for interest
+
+
+	// loop through all the portals in this zone
+	for(nPortalIndex=0 ; nPortalIndex<nPortalMax ; nPortalIndex++)
+	{
+		
+
+		nPortal=m_Q3Map->m_nZoneTouchesPortal[nZone][nPortalIndex] ;
+
+
+		if((pPortalVis[nPortal]&PORTAL_VISCHECK)==0) // portal hasn't already been checked
+		{
+
+			pPortalVis[nPortal] |= PORTAL_VISCHECK ; // flag portal as vischecked
+			AAB.setExtents(m_Q3Map->m_pPortals[nPortal].Min[0], m_Q3Map->m_pPortals[nPortal].Min[1], m_Q3Map->m_pPortals[nPortal].Min[2], m_Q3Map->m_pPortals[nPortal].Max[0], m_Q3Map->m_pPortals[nPortal].Max[1], m_Q3Map->m_pPortals[nPortal].Max[2]) ;
+		
+			if(pCamera->isVisible(AAB)) // portal is in the view frustum
+			{			
+
+				pPortalVis[nPortal] |= PORTAL_VISIBLE ; // flag portal as visible
+
+				// if the portal is open, go in and check the new zone.
+				if(m_chPortalState[nPortal]&PORTALSTATE_OPEN)
+				{
+			
+					// calculate the new frustum extents through this portal
+					PortalL=OrigL ;
+					PortalR=OrigR ;
+					PortalT=OrigT ;
+					PortalB=OrigB ;
+
+					if(CalculatePortalFrustum(pCamera, nPortal, &PortalL, &PortalR, &PortalT, &PortalB, ScaleX, ScaleY))
+					{
+
+
+
+
+
+						// Loop through all the zones attached to this portal
+						nPortalZoneMax=m_Q3Map->m_nPortalTouchesZone[nPortal][INDEX_PORTALZONECOUNT] ;
+						for(nPortalZoneIndex=0 ; nPortalZoneIndex<nPortalZoneMax ; nPortalZoneIndex++)
+						{
+							nPortalZone=m_Q3Map->m_nPortalTouchesZone[nPortal][nPortalZoneIndex] ;
+							if(pZoneVis[nPortalZone]==ZONE_UNCHECKED) // don't go back into zones we've already scanned.
+							{
+
+								pCamera->setFrustumExtents(PortalL, PortalR, PortalT, PortalB) ; // set the frustum extents
+
+								// recurse
+								//m_nRecurseCount++ ;
+								PortalScan(pCamera, nPortalZone, ScaleX, ScaleY, pZoneVis, pLightVis, pSubLightVis, pPortalVis, pMaxVisibleLight, pVisibleLightList) ;
+								//m_nRecurseCount-- ;
+
+								
+								
+							}// end if zone hasn't already been checked
+
+						}// end scanning all zones connected by this portal
+
+					}// end if frustum is still active
+
+				}// end if portal is open
+				
+			}// end if portal is in the view frustum
+		
+		}// end if portal hasn't been checked	
+
+		// reset the frustum
+		pCamera->setFrustumExtents(OrigL, OrigR, OrigT, OrigB) ; // reset the original frustum extents
+	
+	}// end for portalindex
+
+
+}
+
+// gives new frustum settings, and returns 0 if the frustum has been killed completely.
+int OgreFramework::CalculatePortalFrustum(Ogre::Camera *pCamera, int nPortal, Ogre::Real* pPortalL, Ogre::Real* pPortalR, Ogre::Real* pPortalT, Ogre::Real* pPortalB, Ogre::Real ScaleX, Ogre::Real ScaleY)
+{
+
+
+	// if the camera is actually inside the portal then don't change the frustum but return OK
+	Vector3 CamPos=pCamera->getPosition() ;
+
+	if(
+				(CamPos.x>=m_Q3Map->m_pPortals[nPortal].Min[0]) && (CamPos.x<=m_Q3Map->m_pPortals[nPortal].Max[0])
+			&&(CamPos.y>=m_Q3Map->m_pPortals[nPortal].Min[1]) && (CamPos.y<=m_Q3Map->m_pPortals[nPortal].Max[1])
+			&&(CamPos.z>=m_Q3Map->m_pPortals[nPortal].Min[2]) && (CamPos.z<=m_Q3Map->m_pPortals[nPortal].Max[2])
+		)
+		return 1 ;
+
+
+
+
+
+	int nLoop=0 ;
+	int nBehindPoint=0 ; // keep track of how many transformed points are behind the camera
+	//Real OrigL=*pPortalL ;
+	//Real OrigR=*pPortalR ;
+	//Real OrigT=*pPortalT ;
+	//Real OrigB=*pPortalB ;
+
+	Real MinX=MINMAXLIMIT ;
+	Real MaxX=-MINMAXLIMIT ;
+	Real MaxY=-MINMAXLIMIT ;
+	Real MinY=MINMAXLIMIT ;
+
+
+	// set portal corners as 8 individual points.  order is xyz, Xyz, xYz, XYz, xyZ, XyZ, xYZ, XYZ, 
+	Vector3 xyz[8] ;
+
+	
+	xyz[0].x=m_Q3Map->m_pPortals[nPortal].Min[0] ;
+	xyz[0].y=m_Q3Map->m_pPortals[nPortal].Min[1] ;
+	xyz[0].z=m_Q3Map->m_pPortals[nPortal].Min[2] ;
+
+	xyz[1].x=m_Q3Map->m_pPortals[nPortal].Max[0] ;
+	xyz[1].y=m_Q3Map->m_pPortals[nPortal].Min[1] ;
+	xyz[1].z=m_Q3Map->m_pPortals[nPortal].Min[2] ;
+
+	xyz[2].x=m_Q3Map->m_pPortals[nPortal].Min[0] ;
+	xyz[2].y=m_Q3Map->m_pPortals[nPortal].Max[1] ;
+	xyz[2].z=m_Q3Map->m_pPortals[nPortal].Min[2] ;
+
+	xyz[3].x=m_Q3Map->m_pPortals[nPortal].Max[0] ;
+	xyz[3].y=m_Q3Map->m_pPortals[nPortal].Max[1] ;
+	xyz[3].z=m_Q3Map->m_pPortals[nPortal].Min[2] ;
+
+	xyz[4].x=m_Q3Map->m_pPortals[nPortal].Min[0] ;
+	xyz[4].y=m_Q3Map->m_pPortals[nPortal].Min[1] ;
+	xyz[4].z=m_Q3Map->m_pPortals[nPortal].Max[2] ;
+
+	xyz[5].x=m_Q3Map->m_pPortals[nPortal].Max[0] ;
+	xyz[5].y=m_Q3Map->m_pPortals[nPortal].Min[1] ;
+	xyz[5].z=m_Q3Map->m_pPortals[nPortal].Max[2] ;
+
+	xyz[6].x=m_Q3Map->m_pPortals[nPortal].Min[0] ;
+	xyz[6].y=m_Q3Map->m_pPortals[nPortal].Max[1] ;
+	xyz[6].z=m_Q3Map->m_pPortals[nPortal].Max[2] ;
+
+	xyz[7].x=m_Q3Map->m_pPortals[nPortal].Max[0] ;
+	xyz[7].y=m_Q3Map->m_pPortals[nPortal].Max[1] ;
+	xyz[7].z=m_Q3Map->m_pPortals[nPortal].Max[2] ;
+
+	// transform the points to eyespace
+	for(nLoop=0 ; nLoop<8 ; nLoop++)
+		xyz[nLoop]=m_ViewMatrix*xyz[nLoop] ;//pCamera->getViewMatrix(true)*xyz[nLoop] ;
+
+	// transform the points to screen space
+	for(nLoop=0 ; nLoop<8 ; nLoop++)
+		if(xyz[nLoop].z<0) // less than zero means point is in front of camera
+		{
+			xyz[nLoop]=m_ProjectionMatrix*xyz[nLoop] ;// pCamera->getProjectionMatrix()*xyz[nLoop] ;
+			if(xyz[nLoop].x<MinX) MinX=xyz[nLoop].x ;
+			if(xyz[nLoop].x>MaxX) MaxX=xyz[nLoop].x ;
+			if(xyz[nLoop].y<MinY) MinY=xyz[nLoop].y ;
+			if(xyz[nLoop].y>MaxY) MaxY=xyz[nLoop].y ;
+
+		}
+		else // point is behind the camera
+			nBehindPoint++ ;
+		
+
+
+	
+	MinX*=ScaleX ;
+	MaxX*=ScaleX ;
+	MinY*=ScaleY ;
+	MaxY*=ScaleY ;
+	
+	// apply the stereofrustum tweak if needed
+	//float flTweak=0.0f ;
+	//if(m_flStereoFrustumTweak!=0.0f)
+	//{
+	//	MinX-=m_flStereoFrustumTweak ;
+	//	MaxX+=m_flStereoFrustumTweak ;
+	//}
+
+
+	// if we have more than three behindpoints, don't cull
+	if(nBehindPoint>3) return 1 ;
+
+	// use these to cut down the frustum
+	if(MinX>*pPortalL) *pPortalL=MinX ;
+	if(MaxX<*pPortalR) *pPortalR=MaxX ;
+	if(MinY>*pPortalB) *pPortalB=MinY ;
+	if(MaxY<*pPortalT) *pPortalT=MaxY ;
+
+
+
+	
+
+	
+
+	// check if frustum has been cut out of existence
+	// culling at this point didn't work, so this is a hack to make if function.
+	if((*pPortalL>=*pPortalR) || (*pPortalB>=*pPortalT))
+		return 0 ;
+
+
+	/*
+	if(*pPortalL>=*pPortalR)
+	{
+		*pPortalL=(*pPortalL+*pPortalR)/2.0-0.01 ;
+		*pPortalR=*pPortalL+0.02 ;
+	}
+
+	if(*pPortalB>=*pPortalT)
+	{
+		*pPortalB=(*pPortalB+*pPortalT)/2.0-0.01 ;
+		*pPortalT=*pPortalB+0.02 ;
+	}
+	*/
+
+		
+		//return 0 ;
+
+
+	return 1 ;
+}
+
+
+
+
+
+
+
+
+ /***********************************************************************************************************\
+                                               
+                                            LIGHTING SETUP
+                                                
+ \***********************************************************************************************************/
+
+
+
+
+
+void OgreFramework::initLight() 
+{
+//	char chMessage[1024] ;
+
+		// these lights only have placeholder settings to begin with, since they get moved around and reused thoughout the level.
+	
+		int nLt=0 ;
+		int nMaxLt=MAXLIGHTPERLOOP ;
+		Light *light;
+		char chLightName[1024] ;
+
+
+		
+
+		for(nLt=0 ; nLt<nMaxLt ; nLt++)
+		{
+			sprintf(chLightName, "LT%02i", nLt) ;
+			
+			light = m_pSceneMgr->createLight(chLightName);
+			light->setType(Light::LT_SPOTLIGHT);
+			light->setCastShadows(true);
+			light->setVisible(false) ;
+
+		}
+	
+}
+
+ /***********************************************************************************************************\
+                                               
+                                            CONFIG FILE
+                                                
+ \***********************************************************************************************************/
+
+void OgreFramework::ParseBZNConfig(void)
+{
+	const int KVSIZE=1024 ;
+	// make sure the config is a string
+	int nConfigPos=-1 ;
+//	int nPos=0 ;
+	int nKeyPos=0 ;
+	int nValuePos=0 ;
+
+	char chKey[KVSIZE] ;
+	char chValue[KVSIZE] ;
+	int nValue=0 ;
+
+	
+
+	while(nConfigPos<BZN_CONFIG_SIZE)
+	{
+		// scan forward to find the next key
+		while	(			
+								(++nConfigPos<BZN_CONFIG_SIZE)
+						&&	((m_chBZNConfig[nConfigPos]<'A') || (m_chBZNConfig[nConfigPos]>'z'))
+					) ;
+
+		if(nConfigPos<BZN_CONFIG_SIZE)
+		{
+
+
+
+			// find the end of the key
+			nKeyPos=0 ;
+			while	((m_chBZNConfig[nConfigPos]!=' ') && (m_chBZNConfig[nConfigPos]!='/') && (m_chBZNConfig[nConfigPos]!=0x0A) && (m_chBZNConfig[nConfigPos]!=0x0D))
+			{
+				chKey[nKeyPos++]=m_chBZNConfig[nConfigPos++] ;
+				if((nConfigPos==BZN_CONFIG_SIZE) || (nKeyPos==KVSIZE))
+					break ;
+			}
+
+			if((nConfigPos<BZN_CONFIG_SIZE) && (nKeyPos<KVSIZE))
+			{
+				chKey[nKeyPos]='\0' ; // null terminate the key
+			
+				// scan off the the number
+				nValuePos=0 ;
+				
+
+				while	((m_chBZNConfig[nConfigPos]!=0x0A) && (m_chBZNConfig[nConfigPos]!=0x0D) && (m_chBZNConfig[nConfigPos]!='/'))
+				{
+					if(
+									((m_chBZNConfig[nConfigPos]>='0') && (m_chBZNConfig[nConfigPos]<='9'))
+							||	(m_chBZNConfig[nConfigPos]=='-') 
+							||	(m_chBZNConfig[nConfigPos]=='.')
+						)
+						chValue[nValuePos++]=m_chBZNConfig[nConfigPos] ;
+
+					nConfigPos++ ;
+					if((nConfigPos==BZN_CONFIG_SIZE) || (nKeyPos==KVSIZE))
+						break ;
+				}
+
+				if((nConfigPos<BZN_CONFIG_SIZE) && (nValuePos<KVSIZE))
+				{
+					chValue[nValuePos]='\0' ; // null terminate the value
+				
+					// convert value string to a float
+					nValue=atoi(chValue) ;
+
+					// assign that value
+					if(strcmp("r_shadowmapsize", chKey)==0)		{ m_nShadowMapSize=nValue ; if(m_nShadowMapSize<2) m_nShadowMapSize=2 ; }
+					if(strcmp("r_shadowrgbsize", chKey)==0)		{ m_nShadowRGBSize=nValue ; if(m_nShadowRGBSize<2) m_nShadowRGBSize=2 ; }
+					if(strcmp("r_colouredshadow", chKey)==0)	{ m_nColouredShadow=nValue ; }
+					if(strcmp("r_renderhdr", chKey)==0)				{ m_nRenderHDR=nValue ; }
+					if(strcmp("r_maxgpuquery", chKey)==0)			{ m_nMaxGPUQuery=nValue ; if(m_nMaxGPUQuery<0) m_nMaxGPUQuery=0 ; if(m_nMaxGPUQuery>MAXGPUQUERY) m_nMaxGPUQuery=MAXGPUQUERY ; }
+
+					//sprintf(m_chBug, "Key: %s, Value: %i", chKey, nValue) ;
+					//m_pLog->logMessage(m_chBug);
+				
+				}// end found end of value
+
+
+
+
+
+
+
+			}// end found end of key
+
+
+
+
+
+		}// end found start of key
+						
+
+
+	}// end scanning whole config
+
+
+}
Index: code/trunk/src/libraries/tools/bsp/OgreFramework.hpp
===================================================================
--- code/trunk/src/libraries/tools/bsp/OgreFramework.hpp	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/OgreFramework.hpp	(revision 7163)
@@ -0,0 +1,724 @@
+/*
+===========================================================================
+Copyright (C) 2010 Jared Prince
+
+This file is part of bsp-renderer source code.
+
+bsp-renderer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+bsp-renderer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+#ifndef OGRE_FRAMEWORK_HPP
+#define OGRE_FRAMEWORK_HPP
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+#include <OgreCamera.h>
+#include <OgreEntity.h>
+#include <OgreLogManager.h>
+#include <OgreOverlay.h>
+#include <OgreOverlayElement.h>
+#include <OgreOverlayManager.h>
+#include <OgreRoot.h>
+#include <OgreViewport.h>
+#include <OgreSceneManager.h>
+#include <OgreRenderWindow.h>
+#include <OgreConfigFile.h>
+#include <OgreManualObject.h>
+#include <OgreMaterialManager.h>
+#include <OgreRenderSystem.h> 
+#include <OgreOverlayContainer.h> 
+#include <OgreHardwarePixelBuffer.h>
+#include <OgreRenderQueueListener.h>
+#include <OgreHardwareOcclusionQuery.h>
+#include <OgreTextureUnitState.h>
+#include "OgreGpuCommandBufferFlush.h"
+
+
+#include "ExampleFrameListener.h"
+//#include <OgreFrameListener.h>
+//#include <OgreRenderTargetListener.h>
+
+
+#include <OIS/OIS.h>
+#include <OIS/OISEvents.h>
+#include <OIS/OISInputManager.h>
+#include <OIS/OISKeyboard.h>
+#include <OIS/OISMouse.h>
+
+#include "Q3Map.h"
+
+//#include "JarDebug.h" //!! just for debugging, remove from final build
+
+
+#define CHECKDELETE_ARRAY(x, y)		if(x) { delete [] x ; x=0 ; m_nNewCount-- ; m_nNewCheck[y]-- ;}
+#define CHECKDELETE_POINTER(x, y)  if(x) { delete x		; x=0 ; m_nNewCount-- ; m_nNewCheck[y]-- ;}
+
+enum {
+	NEW_CHECK_m_pRawBspFile=0,
+	NEW_CHECK_m_Q3Map,
+	NEW_CHECK_m_pZoneMO,
+	NEW_CHECK_m_pZoneMesh,
+	NEW_CHECK_m_pZoneEntity,
+	NEW_CHECK_m_pZoneEntityMaterialType,
+	NEW_CHECK_m_pZoneEntityMaterial_Base,
+	NEW_CHECK_m_pZoneEntityMaterial_Fast,
+	NEW_CHECK_m_pZoneEntityMaterial_Black,
+	NEW_CHECK_m_pZoneEntityMaterial_DfShColour,
+	NEW_CHECK_m_pZoneEntityMaterial_Shadow,
+	NEW_CHECK_m_pZoneEntityMaterial_ShadeFront,
+	NEW_CHECK_m_pZoneEntityMaterial_ShadeBack,
+	NEW_CHECK_m_pZoneEntityMaterial_DfShPosition,
+	NEW_CHECK_m_pZoneEntityMaterial_DfShDiffuse,
+	NEW_CHECK_m_pZoneEntityMaterial_DfShFuncTNB,
+	NEW_CHECK_m_pZoneEntityMaterial_DfShSpecular,
+	NEW_CHECK_m_pZoneEntityMaterial_DfShEmissive,
+	NEW_CHECK_m_pZoneEntityMaterial_DfShMix,
+	NEW_CHECK_pVertIndex,
+	NEW_CHECK_m_pEntityInfo,
+	NEW_CHECK_m_pVisibleEntity,
+	NEW_CHECK_m_pFrustumEntity,
+	MAX_NEW_CHECK
+} ;
+
+#define MAXFRAME 1000 // debugging/testing, copy out data on a per-frame basis
+
+#define MAXGPUQUERY 4
+
+#define MAXVISIBLELIGHT	128 // most shadow lights ever visible.
+#define MAXLIGHTPERLOOP	1 // most shadow lights rendered per deferred shader sub-loop.  So shadow lights are rendered in lots of 4// no longer used
+
+#define NEARCLIP 1			// camera default near clip distance
+#define FARCLIP 10000		// camera default far clip distance
+
+#define CAMERA_EPSILON  0.000001f // small value to check for up/down cameras that would break with Ogre's fixed Yaw.
+
+#define IGNORE_LIGHT		-1
+
+enum GoggleMode
+{
+	GOGGLE_MODE_OFF = 0,
+	GOGGLE_MODE_TEST,
+	GOGGLE_MODE_ON,
+	GOGGLE_MODE_MAX
+} ;
+
+#define MAT_OPAQUE		1				// Typical solid stuff.  Can have emissive parts.
+#define MAT_TRANS			2				// Unused
+#define MAT_GLOW			4				// Only rendered in the deferred shader emmisive pass.  Used to create the hdr bloom for light points.
+#define MAT_GEL				8				// Translucent, colours spotlights that pass through it.
+#define MAT_ALPHAPF		16			// Same as MAT_OPAQUE, but with alpha testing.
+#define MAT_LAMP			32			// The bounding boxes of deferred shading lights (lamps). Rendered as the last phase in deferred shading.
+
+#define BZN_CONFIG_SIZE	1024
+
+class rQueueListener: public Ogre::RenderQueueListener
+{
+public:
+	
+	rQueueListener() {}
+	~rQueueListener() {}
+
+	Ogre::HardwareOcclusionQuery* Query[MAXGPUQUERY] ;
+
+	void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) {}
+	void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) {}
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define MAX_SUBMESH						16	// most submeshes allowed in a mesh.
+#define MAX_ZONEPERENTITY			8		// the most zones an entity can touch at once.
+#define INDEX_ENTITYZONECOUNT	8		// index to value that holds the count of how many zones this entity touches
+#define MAX_LIGHTPERENTITY		64	// most shadowing lights that an entity can be lit by
+#define INDEX_LIGHTPERENTITY	64	// index to value
+typedef struct
+{
+	int Active ;
+	int Visible ;
+	int Frustum ;
+	int LightTouch ;
+
+	int TriangleCount ;
+
+	Ogre::Vector3 Postition ;
+	Ogre::Quaternion Orientation ;
+
+	Ogre::AxisAlignedBox AABB ;
+	Ogre::Vector3 Centre ;
+	float AABBMin[3] ;
+	float AABBMax[3] ;
+
+	unsigned short Zone[MAX_ZONEPERENTITY+1] ;		// the zones this entity touches.  Last value is a count of how many zones were touched.
+	unsigned short Light[MAX_LIGHTPERENTITY+1] ;	// the shadow casting spotlights this entity touches.  Last value is a count of how many lights.
+
+	int MaxSubMesh ;
+	int SubMeshMaterialType[MAX_SUBMESH] ;
+
+	Ogre::Entity*				pEnt ;
+	Ogre::SceneNode*    pMasterNode ;
+
+	Ogre::MaterialPtr		Material_Base[MAX_PROJECTORTEX][MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_Fast[MAX_PROJECTORTEX][MAX_SUBMESH] ;
+
+	Ogre::MaterialPtr		Material_Black[MAX_SUBMESH] ;
+
+	Ogre::MaterialPtr		Material_DfShColour[MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_Shadow[MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_ShadeFront[MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_ShadeBack[MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_DfShPosition[MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_DfShDiffuse[MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_DfShFuncTNB[MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_DfShSpecular[MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_DfShEmissive[MAX_SUBMESH] ;
+	Ogre::MaterialPtr		Material_DfShMix[MAX_SUBMESH] ;
+}
+ENTITYINFO;
+
+typedef struct
+{
+
+	int Type ;
+
+	Ogre::ParticleSystem*	PSystem ;
+	Ogre::SceneNode*			PNode ;
+
+}
+PARTICLEINFO;
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+class OgreFramework : public Ogre::Singleton<OgreFramework>, OIS::KeyListener, OIS::MouseListener, public RenderTargetListener
+{
+public:
+	OgreFramework();
+	~OgreFramework();
+
+	int m_nNewCount ;
+	int m_nNewCheck[MAX_NEW_CHECK] ;
+
+	int m_nStartTime ;
+	int m_nTime ;
+
+//	CJarDebug OFBug ; //!! just for debugging, remove from final build
+	char m_chBug[10240] ;
+	int m_nFrameTime[MAXFRAME][10] ;
+	int m_nFrame ;
+	char m_chFrame[1024] ;
+	int m_nGotInput ;
+
+	void initOgre(Ogre::String wndTitle, OIS::KeyListener *pKeyListener = 0, OIS::MouseListener *pMouseListener = 0);
+	void AdditionalSetup() ;
+
+	void updateOgre(double timeSinceLastFrame);
+	void updateStats();
+	void moveCamera();
+	void getInput();
+
+	bool isOgreToBeShutDown()const{return m_bShutDownOgre;}  
+
+	bool keyPressed(const OIS::KeyEvent &keyEventRef);
+	bool keyReleased(const OIS::KeyEvent &keyEventRef);
+
+	bool mouseMoved(const OIS::MouseEvent &evt);
+	bool mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id); 
+	bool mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id);
+	
+	Ogre::Root*					m_pRoot;
+	Ogre::SceneManager*			m_pSceneMgr;
+	Ogre::RenderWindow*			m_pRenderWnd;
+	Ogre::Camera*				m_pCamera;
+	Ogre::Viewport*				m_pViewport;
+	Ogre::Log*					m_pLog;
+	Ogre::Timer*				m_pTimer;
+
+	Ogre::Camera* m_pCameraCopy ;
+	Ogre::Camera* m_pCameraNoJitter ;
+
+	float m_flAspectRatio ;
+	float m_flFOV ;
+
+
+	//RawFilePtr m_pRawBspFile ;	bool m_bRawBspFileIsLoaded ;
+
+	char *m_pRawBspFile ;	
+	bool m_bRawBspFileIsLoaded ;
+	
+	OIS::InputManager*			m_pInputMgr;
+	OIS::Keyboard*				m_pKeyboard;
+	OIS::Mouse*					m_pMouse;
+
+	int nMap ;
+	Ogre::String m_MapName ;
+	int m_nLoadToggle ;
+
+	int m_nJumpToggle ;
+	int m_nJumpVal;
+
+	int m_nToggle ;
+
+	void UnloadMap(bool bShutdown) ;
+	int LoadMap(void) ;
+	int m_nMapLoaded ;
+
+	int m_nDebugLightBox ;
+	int m_nZoneCullingActive ;
+	int m_nPortalDebug ;
+	int m_nPortalToggle ;
+	int m_nPortalState ; 
+
+	// Add this to OgreFramework and initialize it from 0 to MAXGPUQUERY
+	// If you're good you'll make it private and add some get/set functions, 
+	// I just made it public for now.
+
+	// A value of 0 means don't mess with the GPU buffers at all.  There
+	// might be some systems where the queries cause problems, so let the user 
+	// deactivate the queries completely if desired.
+
+	// A value of 1 means we flush every frame, so no GPU command buffering.
+	// This is good for low FPS because even just 1 buffer gives noticable
+	// input lag.  However users with high FPS can afford a few buffers.
+	
+	int m_nMaxGPUQuery ;
+
+
+	int m_nDebugA ;
+	int m_nDebugB ;
+	int m_nDebugC ;
+	int m_nVisibleLightCount ;
+	int m_nVisibleZoneCount ;
+
+	float m_flDebugMatrix[4][4] ;
+	
+	int m_nRecurseCount ;
+	char m_chDebug[10240] ;
+	float m_flDebug0 ;
+	float m_flDebug1 ;
+	float m_flDebug2 ;
+	float m_flDebug3 ;
+	float m_flDebug4 ;
+	float m_flDebug5 ;
+
+
+	
+	Ogre::ManualObject* m_pGoggleL ;
+	Ogre::ManualObject* m_pGoggleR ;
+	Ogre::SceneNode*		m_pNodeGoggles ;
+	int m_nGoggleMode ;
+	float m_flGoggleAspectRatio	;
+	float m_flGoggleZPos ;
+	float m_flGoggleXGap ;
+	float m_flGoggleXScale ;
+	float m_flGoggleYScale ;
+	int m_nGoggleTestImage ;
+	void DestroyGoggles() ;
+	int CreateGogglesTestImage() ;
+	int CreateGoggles() ;
+
+
+	void UpdateRenderTargets() ;
+
+	double m_GameTime ;
+
+	char m_chBZNConfig[BZN_CONFIG_SIZE] ;
+	void ParseBZNConfig(void) ;
+
+	void FinalShutdown(void) ;
+
+private:
+	OgreFramework(const OgreFramework&);
+	OgreFramework& operator= (const OgreFramework&);
+
+	Ogre::Overlay*				m_pDebugOverlay;
+	Ogre::Overlay*				m_pInfoOverlay;
+	int							m_iNumScreenShots;
+
+	bool						m_bShutDownOgre;
+	
+	Ogre::Vector3				m_TranslateVector;
+	Ogre::Real					m_MoveSpeed; 
+	Ogre::Degree				m_RotateSpeed; 
+	float						m_MoveScale; 
+	Ogre::Degree				m_RotScale;
+
+	int m_nKeyDown_Shift ;
+	int m_nKeyDown_Ctrl ;
+
+
+	
+
+
+	//RawFileManager *mRawFileManager;
+
+	char* m_TempMem ;
+	Q3Map *m_Q3Map;
+
+
+	Ogre::SceneNode*			m_pCubeNode;
+	Ogre::Entity*				m_pCubeEntity;
+
+	Ogre::SceneNode *m_pOpaqueNode[MAX_ZONE] ;
+	int m_nOpaqueNodeUsed[MAX_ZONE] ; 
+	Ogre::SceneNode *m_pTransNode[MAX_ZONE] ;
+	int m_nTransNodeUsed[MAX_ZONE] ;
+	Ogre::SceneNode *m_pLampNode[MAX_ZONE] ;
+	int m_nLampNodeUsed[MAX_ZONE] ;
+	Ogre::SceneNode *m_pGlowNode[MAX_ZONE] ;
+	int m_nGlowNodeUsed[MAX_ZONE] ;
+
+	Ogre::Matrix4	m_ViewMatrix ;
+	Ogre::Matrix4	m_ProjectionMatrix ;
+
+	Ogre::ManualObject** m_pZoneMO ; // the Zone's manualObject array
+	Ogre::MeshPtr* m_pZoneMesh ;
+	Ogre::Entity** m_pZoneEntity ;
+	int* m_pZoneEntityMaterialType ;
+
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_Base[MAX_PROJECTORTEX] ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_Fast[MAX_PROJECTORTEX] ;
+
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_Black ;
+
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_DfShColour ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_Shadow ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_ShadeFront ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_ShadeBack ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_DfShPosition ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_DfShDiffuse ;
+	//Ogre::MaterialPtr* m_pZoneEntityMaterial_DSNormal ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_DfShFuncTNB ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_DfShSpecular ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_DfShEmissive ;
+	//Ogre::MaterialPtr* m_pZoneEntityMaterial_DfShData ;
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_DfShMix ;
+
+	Ogre::MaterialPtr* m_pZoneEntityMaterial_BlurA ;
+
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+	Ogre::MeshPtr* m_pGameMesh ;
+	ENTITYINFO* m_pEntityInfo ;
+	int* m_pVisibleEntity ; // entities that are in a visible zone
+	int* m_pFrustumEntity ; // entities that are in a visible zone and also in the view frustum
+
+	int m_nMaxGameMesh ;
+	int m_nMaxEntity ;
+	int m_nMaxVisibleEntity ;
+	int m_nMaxFrustumEntity ;
+	int m_nVisibleEntityTriangleCount ;
+	int m_nFrustumEntityTriangleCount ;
+	int m_nTotalTriangles ;
+	int m_nZoneTriangleCount[MAX_ZONE] ;
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	// for debugging/testing, make light volumes into meshes
+	Ogre::ManualObject** m_pLightMO ; // the manualObject array
+	int AddLightCullingBoxes(void) ;
+
+	// for debugging/testing, make portal volumes into meshes
+	Ogre::ManualObject** m_pPortalMO ; // the manualObject array
+	Ogre::Node** m_pPortalNode ; // the node of this portal
+	int AddPortalBoxes(void) ;
+
+	/////////////////////////////////////////////////////////////////////////////////
+
+	
+	
+
+
+	void SetupResourceLocations() ;
+	
+
+
+	float m_flStereoFrustumTweak ; // in stereoscopic mode the portal frustums might be too tight, so enlarge them a bit.
+
+
+	bool m_IsOpenGL ;
+
+	
+	void initLight() ;
+
+	Ogre::Matrix4 CreateTextureViewProjectionMatrix(Ogre::Camera* pCamera) ;
+	bool SetupSingleVisibleLightAndShadowCamera(int nLt, char* pLightVis, unsigned short* pVisibleLightList, Ogre::Camera* pCamera) ;
+	
+
+	int SetupParticles() ;
+	Ogre::ParticleSystem*		m_ps;
+	Ogre::SceneNode*				m_pParticleNode;
+	
+	int m_nMaxParticleSystem ;
+	
+	
+	int ConstructMapFromTriangles(void) ;
+	
+	int SetupGameEntities(void) ;
+	int SetupEntity(int nEntity, char *chMeshName) ;
+	
+	
+
+	int m_nKeyToggle[OIS::KC_MEDIASELECT+1] ; // for preventing multiple key triggers when needed.
+
+	int m_nFlashLight ;
+	
+
+	
+
+
+
+
+	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// left/mono visibility info
+	char m_chZoneVisL[MAX_ZONE] ;
+	char m_chLightVisL[MAX_LIGHT] ;
+	char m_chSubLightVisL[MAX_SUBLIGHT] ;
+	char m_chPortalVisL[MAX_PORTAL] ;
+	int  m_nMaxVisibleZoneL ;
+	unsigned short m_uVisibleZoneListL[MAX_ZONE] ;				// if MAX_ZONE goes above 65536 this will need to change to an int 
+	int  m_nMaxVisibleLightL ;
+	unsigned short m_uVisibleLightListL[MAXVISIBLELIGHT]; // if MAX_LIGHT goes above 65536 this will need to change to an int
+	int m_nCameraZoneL ; // zone player left eye is in.
+	
+	// right visibility info
+	char m_chZoneVisR[MAX_ZONE] ;
+	char m_chLightVisR[MAX_LIGHT] ;
+	char m_chSubLightVisR[MAX_SUBLIGHT] ;
+	char m_chPortalVisR[MAX_PORTAL] ;
+	int  m_nMaxVisibleZoneR ;
+	unsigned short m_uVisibleZoneListR[MAX_ZONE] ;				// if MAX_ZONE goes above 65536 this will need to change to an int 
+	int  m_nMaxVisibleLightR ;
+	unsigned short m_uVisibleLightListR[MAXVISIBLELIGHT]; // if MAX_LIGHT goes above 65536 this will need to change to an int 
+	int m_nCameraZoneR ; // zone player right eye is in.
+	
+	int m_nCameraZone ;  // zone player is in.
+	
+	
+
+
+
+	char* m_pGlobal_ZoneVis ;
+	char* m_pGlobal_LightVis ;
+	unsigned short* m_pGlobal_VisibleZoneList ;
+	int*  m_pGlobal_MaxVisibleZone ;
+	unsigned short* m_pGlobal_VisibleLightList ;
+	int*  m_pGlobal_MaxVisibleLight ;
+
+	char m_chPortalState[MAX_PORTAL] ;
+	
+	int  m_nMaxVisibleLight ;
+
+
+
+
+
+
+
+	int m_nZoneMOStart[MAX_ZONE+1] ; // index into m_pZoneMO for each zone, since each material within a zone is another manualObject.
+
+	void CalculateZoneVisibility(Ogre::Camera* pCamera, int *pCameraZone, char* pZoneVis, char* pLightVis, char* pSubLightVis, char* pPortalVis, int* pMaxVisibleLight, unsigned short* pVisibleLightList) ;
+	void SetupEntityZones(void) ;
+	void CalculateEntityVisibility(Ogre::Camera* pCamera, char* pZoneVis) ;
+
+	void SetAllLightsOff(void) ;
+	void SetSingleVisibleLight(int nLt, bool bOn) ;
+	void UpdateVisibleZoneList(char* pZoneVis, unsigned short* pVisibleZoneList, int* pMaxVisibleZone) ;
+	
+	void SetZoneNodeAttachments(unsigned short* pVisibleZoneList, int* pMaxVisibleZone, int nMaterialFlags) ;
+	void SetZoneNodeAttachments(unsigned short* pVisibleZoneList, int* pMaxVisibleZone, int nMaterialFlags, int nLight) ;
+	bool LightTouchesZone(int nLight, int nZone) ;
+
+	void PortalScan(Ogre::Camera *pCamera, int nZone, Ogre::Real ScaleX, Ogre::Real ScaleY, char* pZoneVis, char* pLightVis, char* pSubLightVis, char* pPortalVis, int* pMaxVisibleLight, unsigned short* pVisibleLightList) ;
+	int m_nOriginalZoneOpenPortals ;
+	void CheckMultiZoneLights(int nCameraZone, char* pZoneVis, char* pLightVis, char* pSubLightVis) ;
+	void AddZonesFromMultiZoneLights(char* pZoneVis, char* pLightVis, char* pSubLightVis) ;
+	int CalculatePortalFrustum(Ogre::Camera *pCamera, int nPortal, Ogre::Real* pPortalL, Ogre::Real* pPortalR, Ogre::Real* pPortalT, Ogre::Real* pPortalB, Ogre::Real ScaleX, Ogre::Real ScaleY) ;
+
+
+
+
+	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	
+
+
+
+	//int ApplyCGDefines(void) ;
+	
+
+	
+
+	int m_nSpeedRender ;
+	int m_nRenderHDR ;
+	int m_nColouredShadow ;
+	int m_nShadowMapSize ;
+	int m_nShadowRGBSize ;
+
+	int m_nDisplayInfoMode ;
+	
+	///////////////////////////////////////////////////////////////////////////////////////////
+	// render to texture quasi-deferred shading stuff
+	
+	void CreateRTTAssets() ;
+	void DestroyRTTAssets() ;
+	int m_nRTTAssetsExist ;
+
+	// Shadow
+	Rectangle2D*					miniScreen_Shadow;
+	Ogre::SceneNode*			miniScreenNode_Shadow;
+	Ogre::TexturePtr			RTT_Texture_Shadow ;
+	Ogre::RenderTexture*	renderTexture_Shadow ;
+	Ogre::MaterialPtr			RTT_Mat_Shadow ;
+	Ogre::Technique*			RTT_Technique_Shadow ;
+
+	// ShadeFront
+	Rectangle2D*					miniScreen_ShadeFront;
+	Ogre::SceneNode*			miniScreenNode_ShadeFront;
+	Ogre::TexturePtr			RTT_Texture_ShadeFront ;
+	Ogre::RenderTexture*	renderTexture_ShadeFront ;
+	Ogre::MaterialPtr			RTT_Mat_ShadeFront ;
+	Ogre::Technique*			RTT_Technique_ShadeFront ;
+
+	// ShadeBack
+	Rectangle2D*					miniScreen_ShadeBack;
+	Ogre::SceneNode*			miniScreenNode_ShadeBack;
+	Ogre::TexturePtr			RTT_Texture_ShadeBack ;
+	Ogre::RenderTexture*	renderTexture_ShadeBack ;
+	Ogre::MaterialPtr			RTT_Mat_ShadeBack ;
+	Ogre::Technique*			RTT_Technique_ShadeBack ;
+
+	// DfShPosition
+	Rectangle2D*					miniScreen_DfShPosition;
+	SceneNode*						miniScreenNode_DfShPosition;
+	TexturePtr						RTT_Texture_DfShPosition ;
+	RenderTexture*				renderTexture_DfShPosition ;
+	MaterialPtr						RTT_Mat_DfShPosition ;
+	Technique*						RTT_Technique_DfShPosition ;
+	RenderTargetListener* Listener_DfShPosition ;
+
+	// DfShDiffuse
+	Rectangle2D*					miniScreen_DfShDiffuse;
+	Ogre::SceneNode*			miniScreenNode_DfShDiffuse;
+	Ogre::TexturePtr			RTT_Texture_DfShDiffuse ;
+	Ogre::RenderTexture*	renderTexture_DfShDiffuse ;
+	Ogre::MaterialPtr			RTT_Mat_DfShDiffuse ;
+	Ogre::Technique*			RTT_Technique_DfShDiffuse ;
+
+	/*
+	// DSNormal // UNUSED
+	Rectangle2D*					miniScreen_DSNormal;
+	Ogre::SceneNode*			miniScreenNode_DSNormal;
+	Ogre::TexturePtr			RTT_Texture_DSNormal ;
+	Ogre::RenderTexture*	renderTexture_DSNormal ;
+	Ogre::MaterialPtr			RTT_Mat_DSNormal ;
+	Ogre::Technique*			RTT_Technique_DSNormal ;
+	*/
+
+	// DfShFuncTNB
+	Rectangle2D*					miniScreen_DfShFuncTNB;
+	Ogre::SceneNode*			miniScreenNode_DfShFuncTNB;
+	Ogre::TexturePtr			RTT_Texture_DfShFuncTNB ;
+	Ogre::RenderTexture*	renderTexture_DfShFuncTNB ;
+	Ogre::MaterialPtr			RTT_Mat_DfShFuncTNB ;
+	Ogre::Technique*			RTT_Technique_DfShFuncTNB ;
+
+	// DfShSpecular
+	Rectangle2D*					miniScreen_DfShSpecular;
+	Ogre::SceneNode*			miniScreenNode_DfShSpecular;
+	Ogre::TexturePtr			RTT_Texture_DfShSpecular ;
+	Ogre::RenderTexture*	renderTexture_DfShSpecular ;
+	Ogre::MaterialPtr			RTT_Mat_DfShSpecular ;
+	Ogre::Technique*			RTT_Technique_DfShSpecular ;
+
+	// DfShEmissive
+	Rectangle2D*					miniScreen_DfShEmissive;
+	Ogre::SceneNode*			miniScreenNode_DfShEmissive;
+	Ogre::TexturePtr			RTT_Texture_DfShEmissive ;
+	Ogre::RenderTexture*	renderTexture_DfShEmissive ;
+	Ogre::MaterialPtr			RTT_Mat_DfShEmissive ;
+	Ogre::Technique*			RTT_Technique_DfShEmissive ;
+
+	// DfShLamp
+	Rectangle2D*					miniScreen_DfShLamp;
+	Ogre::SceneNode*			miniScreenNode_DfShLamp;
+	Ogre::TexturePtr			RTT_Texture_DfShLamp ;
+	Ogre::RenderTexture*	renderTexture_DfShLamp ;
+	Ogre::MaterialPtr			RTT_Mat_DfShLamp ;
+	Ogre::Technique*			RTT_Technique_DfShLamp ;
+
+	/*
+	// DfShData
+	Rectangle2D*					miniScreen_DfShData;
+	Ogre::SceneNode*			miniScreenNode_DfShData;
+	Ogre::TexturePtr			RTT_Texture_DfShData ;
+	Ogre::RenderTexture*	renderTexture_DfShData ;
+	Ogre::MaterialPtr			RTT_Mat_DfShData ;
+	Ogre::Technique*			RTT_Technique_DfShData ;
+	*/
+
+	// DfShMix
+	Rectangle2D*					miniScreen_DfShMix;
+	Ogre::SceneNode*			miniScreenNode_DfShMix;
+	Ogre::TexturePtr			RTT_Texture_DfShMix ;
+	Ogre::RenderTexture*	renderTexture_DfShMix ;
+	Ogre::MaterialPtr			RTT_Mat_DfShMix ;
+	Ogre::Technique*			RTT_Technique_DfShMix ;
+
+	
+	// DfShTemp
+	Rectangle2D*					miniScreen_DfShTemp;
+	Ogre::SceneNode*			miniScreenNode_DfShTemp;
+	Ogre::TexturePtr			RTT_Texture_DfShTemp ;
+	Ogre::RenderTexture*	renderTexture_DfShTemp ;
+	Ogre::MaterialPtr			RTT_Mat_DfShTemp ;
+	Ogre::Technique*			RTT_Technique_DfShTemp ;
+
+	Rectangle2D*					miniScreen_DfShMaster;
+	Ogre::SceneNode*			miniScreenNode_DfShMaster;
+
+	int m_nRTTWidth ;
+	int m_nRTTHeight ;
+
+	// blur for hdr
+	Rectangle2D*					miniScreen_BlurA;
+	Ogre::SceneNode*			miniScreenNode_BlurA;
+	Ogre::TexturePtr			RTT_Texture_BlurA ;
+	Ogre::RenderTexture*	renderTexture_BlurA ;
+	Ogre::MaterialPtr			RTT_Mat_BlurA ;
+	Ogre::Technique*			RTT_Technique_BlurA ;
+
+	Rectangle2D*					miniScreen_BlurB;
+	Ogre::SceneNode*			miniScreenNode_BlurB;
+	Ogre::TexturePtr			RTT_Texture_BlurB ;
+	Ogre::RenderTexture*	renderTexture_BlurB ;
+	Ogre::MaterialPtr			RTT_Mat_BlurB ;
+	Ogre::Technique*			RTT_Technique_BlurB ;
+	
+	
+
+	Ogre::MaterialPtr			pClearMaterial ;
+
+
+};
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
+
+#endif 
+
+//|||||||||||||||||||||||||||||||||||||||||||||||
Index: code/trunk/src/libraries/tools/bsp/OgreGpuCommandBufferFlush.cpp
===================================================================
--- code/trunk/src/libraries/tools/bsp/OgreGpuCommandBufferFlush.cpp	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/OgreGpuCommandBufferFlush.cpp	(revision 7163)
@@ -0,0 +1,105 @@
+#include "OgreGpuCommandBufferFlush.h"
+#include "OgreRoot.h"
+#include "OgreRenderSystem.h"
+#include "OgreHardwareOcclusionQuery.h"
+
+namespace Ogre
+{
+	//---------------------------------------------------------------------
+	GpuCommandBufferFlush::GpuCommandBufferFlush()
+		: mUseOcclusionQuery(true)
+		, mMaxQueuedFrames(2)
+		, mCurrentFrame(0)
+		, mStartPull(false)
+		, mStarted(false)
+	{
+
+	}
+	//---------------------------------------------------------------------
+	GpuCommandBufferFlush::~GpuCommandBufferFlush()
+	{
+		stop();
+	}
+	//---------------------------------------------------------------------
+	void GpuCommandBufferFlush::start(size_t maxQueuedFrames)
+	{
+		if (!Root::getSingletonPtr() || !Root::getSingletonPtr()->getRenderSystem())
+			return;
+
+		stop();
+		mMaxQueuedFrames = maxQueuedFrames;
+		RenderSystem* rsys = Root::getSingleton().getRenderSystem();
+		mUseOcclusionQuery = rsys->getCapabilities()->hasCapability(RSC_HWOCCLUSION);
+
+		if (mUseOcclusionQuery)
+		{
+			for (size_t i = 0; i < mMaxQueuedFrames; ++i)
+			{
+				HardwareOcclusionQuery* hoq = rsys->createHardwareOcclusionQuery();
+				mHOQList.push_back(hoq);
+			}
+		}
+
+		mCurrentFrame = 0;
+		mStartPull = false;
+
+		Root::getSingleton().addFrameListener(this);
+
+		mStarted = true;
+
+	}
+	//---------------------------------------------------------------------
+	void GpuCommandBufferFlush::stop()
+	{
+		if (!mStarted || !Root::getSingletonPtr() || !Root::getSingletonPtr()->getRenderSystem())
+			return;
+
+		RenderSystem* rsys = Root::getSingleton().getRenderSystem();
+		for (HOQList::iterator i = mHOQList.begin(); i != mHOQList.end(); ++i)
+		{
+			rsys->destroyHardwareOcclusionQuery(*i);
+		}
+		mHOQList.clear();
+
+		Root::getSingleton().removeFrameListener(this);
+
+		mStarted = false;
+
+	}
+	//---------------------------------------------------------------------
+	bool GpuCommandBufferFlush::frameStarted(const FrameEvent& evt)
+	{
+		if (mUseOcclusionQuery)
+		{
+
+			mHOQList[mCurrentFrame]->beginOcclusionQuery();
+
+		}
+
+		return true;
+	}
+	//---------------------------------------------------------------------
+	bool GpuCommandBufferFlush::frameEnded(const FrameEvent& evt)
+	{
+		if (mUseOcclusionQuery)
+		{
+			mHOQList[mCurrentFrame]->endOcclusionQuery();
+		}
+		mCurrentFrame = (mCurrentFrame + 1) % mMaxQueuedFrames;
+		// If we've wrapped around, time to start pulling
+		if (mCurrentFrame == 0)
+			mStartPull = true;
+
+		if (mStartPull)
+		{
+			unsigned int dummy;
+			mHOQList[mCurrentFrame]->pullOcclusionQuery(&dummy);
+		}
+
+		return true;
+	}
+	//---------------------------------------------------------------------
+
+
+}
+
Index: code/trunk/src/libraries/tools/bsp/OgreGpuCommandBufferFlush.h
===================================================================
--- code/trunk/src/libraries/tools/bsp/OgreGpuCommandBufferFlush.h	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/OgreGpuCommandBufferFlush.h	(revision 7163)
@@ -0,0 +1,43 @@
+#ifndef __GPUCOMMANDBUFFERFLUSH_H__
+#define __GPUCOMMANDBUFFERFLUSH_H__
+
+#include "OgrePrerequisites.h"
+#include "OgreFrameListener.h"
+
+namespace Ogre
+{
+	
+	/** Helper class which can assist you in making sure the GPU command
+		buffer is regularly flushed, so in cases where the CPU is outpacing the
+		GPU we do not hit a situation where the CPU suddenly has to stall to 
+		wait for more space in the buffer.
+	*/
+	class GpuCommandBufferFlush : public FrameListener
+	{
+	protected:
+		bool mUseOcclusionQuery;
+		typedef std::vector<HardwareOcclusionQuery*> HOQList;
+		HOQList mHOQList;
+		size_t mMaxQueuedFrames;
+		size_t mCurrentFrame;
+		bool mStartPull;
+		bool mStarted;
+
+	public:
+		GpuCommandBufferFlush();
+		virtual ~GpuCommandBufferFlush();
+
+		void start(size_t maxQueuedFrames = 2);
+		void stop();
+		bool frameStarted(const FrameEvent& evt);
+		bool frameEnded(const FrameEvent& evt);
+
+	};
+
+
+}
+
+
+#endif
+
+
Index: code/trunk/src/libraries/tools/bsp/Q3Map.cpp
===================================================================
--- code/trunk/src/libraries/tools/bsp/Q3Map.cpp	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/Q3Map.cpp	(revision 7163)
@@ -0,0 +1,4881 @@
+/*
+===========================================================================
+Copyright (C) 2008 Daniel Örstadius
+Copyright (C) 2009 Jared Prince
+
+This file is part of bsp-renderer source code.
+
+bsp-renderer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+bsp-renderer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+// Q3Map.cpp -- handles the map data
+
+#include <string>
+#include <math.h>
+
+#include "Q3Map.h"
+#include "Q3Map_misc.h"
+
+
+//temp
+//#include <io.h>
+//#include <fcntl.h>      /* Needed only for _O_RDWR definition */
+//#include <sys/stat.h>
+
+Q3Map::Q3Map()
+{
+	m_nDebugA=0 ;
+
+	m_nNewCount=0 ;
+	
+  m_pTexturesOrig=NULL ;
+  m_pFaces=NULL ;
+  m_pVertices=NULL ;
+  m_pMeshVerts=NULL ;
+  m_pLeafs=NULL ;
+  m_pLeafFaces=NULL ;
+  m_pPlanes=NULL ;
+  m_pNodes=NULL ;
+
+	//m_VisData->vecs=NULL ; // can't NULL this because m_VisData doesn't exist yet!
+	m_VisData=NULL ;
+   
+  m_pBrushes=NULL ;
+  m_pLeafBrushes=NULL ;
+  m_pBrushSides=NULL ;
+  m_pLightMaps=NULL ;
+  m_pEntities=NULL ;
+
+	m_pSubZones=NULL ;
+	m_pPortals=NULL ;
+	//////////////////////////////////////////////////////
+
+	// initiallize our triangle memory management
+	m_nTriangleSize=0 ;
+	m_pTriangleMem=NULL ;
+	m_pTriangle=NULL ;
+	m_nTriangleMax=0 ;
+	m_nTriangleLimit=0 ;
+
+	m_nVertexSize=0 ;
+	m_pVertexMem=NULL ;
+	m_pVertex=NULL ;
+	m_nVertexMax=0 ;
+	m_nVertexLimit=0 ;
+
+	m_nLightSize=0 ;
+	m_pLightMem=NULL ;
+	m_pLight=NULL ;
+	m_nLightMax=0 ;
+	m_nLightLimit=0 ;
+	m_nMaxMultiZoneLight=0 ;
+
+	m_nLampSize=0 ;
+	m_pLampMem=NULL ;
+	m_pLamp=NULL ;
+	m_nLampMax=0 ;
+	m_nLampLimit=0 ;
+
+	m_nTextureSize=0 ;
+	m_pTextureMem=NULL ;
+	m_pTexture=NULL ;
+	m_nTextureMax=0 ;
+	m_nTextureLimit=0 ;
+
+	m_nTexLampSize=0 ;
+	m_pTexLampMem=NULL ;
+	m_pTexLamp=NULL ;
+	m_nTexLampMax=0 ;
+	m_nTexLampLimit=0 ;
+
+	m_BspFaces=NULL;
+
+	m_pTransTexture=NULL ;
+
+
+//	Q3Bug.LogInit() ;
+
+}
+
+Q3Map::~Q3Map()
+{
+//	Q3Bug.LogSave("Q3Bug.log") ;
+
+	DELETE_ARRAY(m_pTransTexture) ;
+	//DELETE_ARRAY(m_pSubZones) ;
+	DELETE_ARRAY(mVisibleFaces) ;
+
+	FreeLightMemory() ;
+	FreeLampMemory() ;
+	FreeVertexMemory() ;
+	FreeTriangleMemory() ;
+	FreeTextureMemory() ;
+	FreeTexLampMemory() ;
+	DestroyBspFacesMemory() ;	// free up face and patch data.  Normally already done if we're just loading a new level or quitting, but we might also be here due to a loading fail or something.
+
+	// no need to delete any of the pointers to the lumps since their memory belongs to m_pRawBspFile over in OgreFramework.
+
+	
+}
+
+void Q3Map::DestroyBspFacesMemory(void)
+{
+	if(m_BspFaces) 
+	{
+		// clean up any memory declared for patches
+		for (int i=0; i < m_NumBspFaces; i++)
+      if ((m_BspFaces[i].type == PATCH) && (m_BspFaces[i].patch != NULL))
+			{
+				DELETE_ARRAY( m_BspFaces[i].patch->bezier ) ;
+				DELETE_POINTER( m_BspFaces[i].patch ) ;
+			}
+
+		// delete the faces memory
+		DELETE_ARRAY( m_BspFaces ) ;
+	}
+}
+
+
+
+int Q3Map::parseMap(const char* pMem, size_t Size)
+{	
+	// we check all lump info to make sure it isn't trying to go out of bounds,
+	// in case some mangled bsp is trying to do something devious or is just corrupted
+	
+	
+	
+
+
+	m_BspHeader=*((Q3BspHeader_t*)pMem) ; // pointer to the header
+
+	// run a check that the total size of all the iLengths plus the header isn't too large
+	size_t TotalLength=sizeof(Q3BspHeader_t) ; // initialize to the size of the header
+	int nLump=0 ;
+	int nOther=0 ;
+	int nLumpMin=0 ;
+	int nLumpMax=0 ;
+	int nOtherMin=0 ;
+	int nOtherMax=0 ;
+	for(nLump=0 ; nLump<MAX_LUMP ; nLump++)
+	{
+		if(m_BspHeader.Lumps[nLump].iLength<0) return -1 ; // lumps shouldn't have a negative size. FAIL!
+		if(m_BspHeader.Lumps[nLump].iLength>MAX_LUMP_SIZE) return -2 ; // no lump has a right to be this big... FAIL!
+		
+		
+		if( (m_BspHeader.Lumps[nLump].iLength>0) && (m_BspHeader.Lumps[nLump].iOffset<sizeof(Q3BspHeader_t)) )
+			return -3 ; // lump overlaps header, FAIL!
+
+		if((m_BspHeader.Lumps[nLump].iLength==0) && (m_BspHeader.Lumps[nLump].iOffset!=0))
+			return -4 ; // lump size is zero and yet offset is not zero???  FAIL!
+
+
+		TotalLength+=m_BspHeader.Lumps[nLump].iLength ;
+		if(TotalLength>Size) return -5 ;// this file is messed up, the lumps add up to more than the file size.  FAIL!
+
+		// make sure this lump doesn't overlap any other lumps
+		nLumpMin=m_BspHeader.Lumps[nLump].iOffset ;
+		nLumpMax=nLumpMin+m_BspHeader.Lumps[nLump].iLength-1 ;
+
+		for(nOther=nLump+1 ; nOther<MAX_LUMP ; nOther++)
+			if((m_BspHeader.Lumps[nLump].iLength>0) && (m_BspHeader.Lumps[nOther].iLength>0)) // don't check zero sized lumps
+			{
+				nOtherMin=m_BspHeader.Lumps[nOther].iOffset ;
+				nOtherMax=nOtherMin+m_BspHeader.Lumps[nOther].iLength-1 ;
+
+				if((nLumpMax>=nOtherMin) && (nLumpMin<=nOtherMax)) 
+				return -6 ; // lump overlaps another lump, FAIL!
+			}
+	}
+
+	
+
+
+	// setup pointers to the lumps
+
+	if((m_BspHeader.Lumps[0].iOffset<0) || (m_BspHeader.Lumps[0].iOffset>=Size)) return -7 ; // fail if out of memory bounds
+	m_pEntities=(char*)(pMem+m_BspHeader.Lumps[0].iOffset) ;
+
+	if((m_BspHeader.Lumps[Faces].iOffset<0) || (m_BspHeader.Lumps[Faces].iOffset>=Size)) return -8 ; // out of bounds
+	if(m_BspHeader.Lumps[Faces].iOffset+m_BspHeader.Lumps[Faces].iLength>Size) return -9 ; // out of bounds
+  m_iNumFaces = m_BspHeader.Lumps[Faces].iLength / sizeof(Q3BspFace_t);
+	m_pFaces=(Q3BspFace_t*)(pMem+m_BspHeader.Lumps[Faces].iOffset) ;
+
+	if((m_BspHeader.Lumps[Vertices].iOffset<0) || (m_BspHeader.Lumps[Vertices].iOffset>=Size)) return -10 ; // out of bounds
+	if(m_BspHeader.Lumps[Vertices].iOffset+m_BspHeader.Lumps[Vertices].iLength>Size) return -11 ; // out of bounds
+  m_iNumVertices = m_BspHeader.Lumps[Vertices].iLength / sizeof(Q3BspVertex);
+	m_pVertices=(Q3BspVertex*)(pMem+m_BspHeader.Lumps[Vertices].iOffset) ;
+
+	if((m_BspHeader.Lumps[MeshVerts].iOffset<0) || (m_BspHeader.Lumps[MeshVerts].iOffset>=Size)) return -12 ; // out of bounds
+	if(m_BspHeader.Lumps[MeshVerts].iOffset+m_BspHeader.Lumps[MeshVerts].iLength>Size) return -13 ; // out of bounds
+  m_iNumMeshVerts = m_BspHeader.Lumps[MeshVerts].iLength / sizeof(int);
+	m_pMeshVerts=(int*)(pMem+m_BspHeader.Lumps[MeshVerts].iOffset) ;
+
+	if((m_BspHeader.Lumps[Leafs].iOffset<0) || (m_BspHeader.Lumps[Leafs].iOffset>=Size)) return -14 ; // out of bounds
+	if(m_BspHeader.Lumps[Leafs].iOffset+m_BspHeader.Lumps[Leafs].iLength>Size) return -15 ; // out of bounds
+  m_iNumLeafs = m_BspHeader.Lumps[Leafs].iLength / sizeof(Q3BspLeaf);
+	m_pLeafs=(Q3BspLeaf*)(pMem+m_BspHeader.Lumps[Leafs].iOffset) ;
+
+	if((m_BspHeader.Lumps[LeafFaces].iOffset<0) || (m_BspHeader.Lumps[LeafFaces].iOffset>=Size)) return -16 ; // out of bounds
+	if(m_BspHeader.Lumps[LeafFaces].iOffset+m_BspHeader.Lumps[LeafFaces].iLength>Size) return -17 ; // out of bounds
+  m_iNumLeafFaces = m_BspHeader.Lumps[LeafFaces].iLength / sizeof(int);
+	m_pLeafFaces=(int*)(pMem+m_BspHeader.Lumps[LeafFaces].iOffset) ;
+
+	if((m_BspHeader.Lumps[LeafBrushes].iOffset<0) || (m_BspHeader.Lumps[LeafBrushes].iOffset>=Size)) return -18 ; // out of bounds
+	if(m_BspHeader.Lumps[LeafBrushes].iOffset+m_BspHeader.Lumps[LeafBrushes].iLength>Size) return -19 ; // out of bounds
+  m_iNumLeafBrushes = m_BspHeader.Lumps[LeafBrushes].iLength / sizeof(int);
+	m_pLeafBrushes=(int*)(pMem+m_BspHeader.Lumps[LeafBrushes].iOffset) ;
+
+	if((m_BspHeader.Lumps[Textures].iOffset<0) || (m_BspHeader.Lumps[Textures].iOffset>=Size)) return -20 ; // out of bounds
+	if(m_BspHeader.Lumps[Textures].iOffset+m_BspHeader.Lumps[Textures].iLength>Size) return -21 ; // out of bounds
+  m_iNumTexs = m_BspHeader.Lumps[Textures].iLength / sizeof(Q3BspTexture);
+	m_pTexturesOrig=(Q3BspTexture*)(pMem+m_BspHeader.Lumps[Textures].iOffset) ;
+
+	if((m_BspHeader.Lumps[Planes].iOffset<0) || (m_BspHeader.Lumps[Planes].iOffset>=Size)) return -22 ; // out of bounds
+	if(m_BspHeader.Lumps[Planes].iOffset+m_BspHeader.Lumps[Planes].iLength>Size) return -23 ; // out of bounds
+  m_iNumPlanes = m_BspHeader.Lumps[Planes].iLength / sizeof(Q3BspPlane);
+	m_pPlanes=(Q3BspPlane*)(pMem+m_BspHeader.Lumps[Planes].iOffset) ;
+
+	if((m_BspHeader.Lumps[Nodes].iOffset<0) || (m_BspHeader.Lumps[Nodes].iOffset>=Size)) return -24 ; // out of bounds
+	if(m_BspHeader.Lumps[Nodes].iOffset+m_BspHeader.Lumps[Nodes].iLength>Size) return -25 ; // out of bounds
+  m_iNumNodes = m_BspHeader.Lumps[Nodes].iLength / sizeof(Q3BspNode);
+	m_pNodes=(Q3BspNode*)(pMem+m_BspHeader.Lumps[Nodes].iOffset) ;
+
+  //m_iNumModels = m_BspHeader.Lumps[Models].iLength / sizeof(Q3BspModel);
+  //m_pModels = new Q3BspModel[m_iNumModels];
+
+	// bzn doesn't use lightmaps
+  //m_iNumLightMaps = m_BspHeader.Lumps[LightMaps].iLength / sizeof(Q3BspLightMap);
+	//m_pLightMaps=(Q3BspLightMap*)(pMem+m_BspHeader.Lumps[LightMaps].iOffset) ;
+
+	if((m_BspHeader.Lumps[Brushes].iOffset<0) || (m_BspHeader.Lumps[Brushes].iOffset>=Size)) return -26 ; // out of bounds
+	if(m_BspHeader.Lumps[Brushes].iOffset+m_BspHeader.Lumps[Brushes].iLength>Size) return -27 ; // out of bounds
+  m_iNumBrushes = m_BspHeader.Lumps[Brushes].iLength / sizeof(Q3BspBrush);
+	m_pBrushes=(Q3BspBrush*)(pMem+m_BspHeader.Lumps[Brushes].iOffset) ;
+
+
+	if((m_BspHeader.Lumps[BrushSides].iOffset<0) || (m_BspHeader.Lumps[BrushSides].iOffset>=Size)) return -28 ; // out of bounds
+	if(m_BspHeader.Lumps[BrushSides].iOffset+m_BspHeader.Lumps[BrushSides].iLength>Size) return -29 ; // out of bounds
+  m_iNumBrushSides = m_BspHeader.Lumps[BrushSides].iLength / sizeof(Q3BspBrushSide);
+	m_pBrushSides=(Q3BspBrushSide*)(pMem+m_BspHeader.Lumps[BrushSides].iOffset) ;
+
+  //m_iNumEffects = m_BspHeader.Lumps[Effects].iLength / sizeof(Q3BspEffect);
+  //m_pEffects = new Q3BspEffect[m_iNumEffects];
+  //
+  //m_pImages = new BDTexture[m_iNumTexs];
+
+	// bzn doesn't use visdata
+	//m_VisData=(Q3BspVisData*)(pMem+m_BspHeader.Lumps[VisData].iOffset) ;
+	//m_VisData->vecs=(unsigned char*)(pMem+m_BspHeader.Lumps[VisData].iOffset + 2*sizeof(int)) ;
+
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// bzn specific data
+	if((m_BspHeader.Lumps[SubZoneData].iOffset<0) || (m_BspHeader.Lumps[SubZoneData].iOffset>=Size)) return -30 ; // out of bounds
+	if(m_BspHeader.Lumps[SubZoneData].iOffset+m_BspHeader.Lumps[SubZoneData].iLength>Size) return -31 ; // out of bounds
+	m_iNumSubZones = m_BspHeader.Lumps[SubZoneData].iLength / sizeof(BZN_SubZone_t);
+  m_pSubZones=(BZN_SubZone_t*)(pMem+m_BspHeader.Lumps[SubZoneData].iOffset) ;
+
+	if((m_BspHeader.Lumps[PortalData].iOffset<0) || (m_BspHeader.Lumps[PortalData].iOffset>=Size)) return -32 ; // out of bounds
+	if(m_BspHeader.Lumps[PortalData].iOffset+m_BspHeader.Lumps[PortalData].iLength>Size) return -33 ; // out of bounds
+	m_iNumPortals = m_BspHeader.Lumps[PortalData].iLength / sizeof(BZN_Portal_t);
+	m_pPortals=(BZN_Portal_t*)(pMem+m_BspHeader.Lumps[PortalData].iOffset) ;
+
+	
+
+
+
+
+	// fix coords and setup face memory
+	swizzleCoords();
+  mVisibleFaces = new int[m_iNumFaces];
+
+
+	// we need a new version of the textures, because when we parse the lights they will have textures to add to it,
+	// and we can't expand the texture lump because it's in the middle of a block of memory containing all the lumps.
+
+	// copy the texture lump
+	int nTexture=0 ;
+	for(nTexture=0 ; nTexture<m_iNumTexs ; nTexture++)
+	{
+		if(!AddTexture(m_pTexturesOrig[nTexture])) return -34 ; // failed to add texture, probably out of memory
+	}
+	
+	return 0 ;
+
+}
+
+
+void Q3Map::swizzleCoords(void)
+{
+  //DEBUG_OUTPUT("swizziling data...");
+  // vertices
+  for (int i=0; i < m_iNumVertices; i++)
+  {
+    swizzleFloat3(m_pVertices[i].position);
+    swizzleFloat3(m_pVertices[i].normal);
+    //m_pVertices[i].texcoord[0][0] = 1.0f - m_pVertices[i].texcoord[0][0];		
+  }
+
+  // leafs
+  for (int i=0; i < m_iNumLeafs; i++)
+  {
+    swizzleInt3(m_pLeafs[i].maxs);
+    swizzleInt3(m_pLeafs[i].mins);
+  }
+
+  // faces, do lightmaps later...
+  for (int i=0; i < m_iNumFaces; i++)
+  {
+    swizzleFloat3(m_pFaces[i].normal);
+  }
+
+  // planes
+  for (int i=0; i < m_iNumPlanes; i++)
+  {
+    swizzleFloat3(m_pPlanes[i].normal);		
+  }
+
+  // nodes
+  for (int i=0; i < m_iNumNodes; i++)
+  {
+    swizzleInt3(m_pNodes[i].maxs);
+    swizzleInt3(m_pNodes[i].mins);
+  }
+
+	
+	// subzones
+	float flTemp=0.0f ;
+	for (int i=0; i < m_iNumSubZones; i++)
+  {
+		swizzleFloat3(m_pSubZones[i].Max);		
+		swizzleFloat3(m_pSubZones[i].Min);
+
+		// swizzling will mix up z max and min due to the sign change, so swap them
+		flTemp=m_pSubZones[i].Max[2] ;
+		m_pSubZones[i].Max[2]=m_pSubZones[i].Min[2] ;
+		m_pSubZones[i].Min[2]=flTemp ;
+
+  }
+
+	// portals
+	for (int i=0; i < m_iNumPortals; i++)
+  {
+		swizzleFloat3(m_pPortals[i].Max);		
+		swizzleFloat3(m_pPortals[i].Min);
+
+		// swizzling will mix up z max and min due to the sign change, so swap them
+		flTemp=m_pPortals[i].Max[2] ;
+		m_pPortals[i].Max[2]=m_pPortals[i].Min[2] ;
+		m_pPortals[i].Min[2]=flTemp ;
+
+  }
+
+	
+	
+
+}
+
+void Q3Map::swizzleFloat3(float t[3])
+{	
+  float temp;
+  temp = t[1];
+  t[1] = t[2];
+  t[2] = -temp;
+}
+
+void Q3Map::swizzleInt3(int t[3])
+{	
+  int temp;
+  temp = t[1];
+  t[1] = t[2];
+  t[2] = -temp;
+}
+
+
+
+Q3BspPatch *Q3Map::handlePatch(int faceIndex)
+{
+  Q3BspPatch *q3patch;
+  q3patch = new Q3BspPatch;
+
+  int patch_size_x = (m_pFaces[faceIndex].size[0] - 1) / 2;
+  int patch_size_y = (m_pFaces[faceIndex].size[1] - 1) / 2;
+  int num_bezier_patches = patch_size_y * patch_size_x;
+
+  q3patch->size = num_bezier_patches;
+  q3patch->bezier = new Bezier[q3patch->size];
+
+  int patchIndex =  0;
+  int ii, n, j, nn;
+  for (ii = 0, n = 0; n < patch_size_x; n++, ii = 2*n)
+  {				
+    for (j=0, nn=0; nn < patch_size_y; nn++, j = 2*nn)
+    {
+      int index = 0;
+      for (int ctr = 0; ctr < 3; ctr++)
+      { 
+        int pos = ctr * m_pFaces[faceIndex].size[0];
+
+        q3patch->bezier[patchIndex].mControls[index++] = 
+          BspVertex(
+          // position
+          m_pVertices[m_pFaces[faceIndex].vertex + 
+          ii + 
+          m_pFaces[faceIndex].size[0] * j + 
+          pos].position,
+          // texture coordinates
+          m_pVertices[m_pFaces[faceIndex].vertex + 
+          ii + 
+          m_pFaces[faceIndex].size[0] * j +
+          pos].texcoord,
+          // normal
+          m_pVertices[m_pFaces[faceIndex].vertex +
+          ii +
+          m_pFaces[faceIndex].size[0] * j +
+          pos].normal);
+
+        q3patch->bezier[patchIndex].mControls[index++] = 
+                BspVertex(
+                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 1].position,
+                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 1].texcoord,
+                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 1].normal);
+
+        q3patch->bezier[patchIndex].mControls[index++] = 
+                BspVertex(
+                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 2].position,
+                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 2].texcoord,
+                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 2].normal);						
+      }      
+      q3patch->bezier[patchIndex].tessellate(5);
+      patchIndex++;
+    }
+  }
+
+  return q3patch;
+}
+
+
+int Q3Map::findVisibleFaces(const QVECTOR *camPos, int *facesToRender)
+{
+  int leaf;
+  int visCluster;	
+
+  leaf = findLeaf(camPos);	
+
+  visCluster = m_pLeafs[leaf].cluster;
+
+  memset(mVisibleFaces, 0, sizeof(int) * m_iNumFaces);	
+
+  int faceindex;
+  int renderindex=0;
+  m_ClusterCount=0 ;
+  
+  for (int i=0; i < m_iNumLeafs; i++)
+  {
+    if (isClusterVisible(visCluster, m_pLeafs[i].cluster))
+    {				
+			m_ClusterCount++ ;
+      bool vis=true ;//bool vis = mViewFrustum->checkIfBoxInside(m_pLeafs[i].mins, m_pLeafs[i].maxs);						
+      
+	  if (vis)
+      {
+        for (int k=0; k < m_pLeafs[i].n_leaffaces; k++)
+        {					
+          faceindex =	m_pLeafFaces[m_pLeafs[i].leafface + k];				
+          if (mVisibleFaces[faceindex] == 0)
+          {
+            mVisibleFaces[faceindex] = 1;						
+            facesToRender[renderindex++] = faceindex;
+          }
+        }
+      }			
+    }
+  }
+  
+
+  facesToRender[renderindex] = -1;	
+
+  return renderindex;
+}
+
+
+int Q3Map::findLeaf(const QVECTOR *camPos) const
+{
+  int index = 0;
+
+  while (index >= 0)
+  {
+    const Q3BspNode *node = &m_pNodes[index];
+    const Q3BspPlane *plane = &m_pPlanes[node->plane];
+
+    // distance from point to plane
+    //QVECTOR normal = QVECTOR(plane->normal);		 
+    QVECTOR normal ;
+	normal[0]=plane->normal[0] ;
+	normal[1]=plane->normal[1] ;
+	normal[2]=plane->normal[2] ;
+	
+	
+	//const float distance = D3DXVec3Dot(&normal,camPos) - plane->dist;
+
+	const float distance=(normal[0]* *camPos[0] + normal[1]* *camPos[1] + normal[2]* *camPos[2]) - plane->dist ;
+
+    if(distance >= 0)
+      index = node->children[0];
+    else
+      index = node->children[1];
+  }
+
+  return -index - 1;
+}
+
+bool Q3Map::isClusterVisible(int visCluster, int testCluster) const
+{
+  if (m_VisData == NULL)
+    return true;
+
+  if ((m_VisData->vecs == NULL) || (visCluster < 0)) 	
+    return true;    
+
+  int i = (visCluster * m_VisData->sz_vecs) + (testCluster >> 3);
+  unsigned char visSet = m_VisData->vecs[i];
+
+  return (visSet & (1 << (testCluster & 7))) != 0;
+}
+
+Q3BspFace_t *Q3Map::getFaces(void)
+{
+  return m_pFaces;
+}
+
+
+
+
+
+ /***********************************************************************************************************\
+                                               
+                                   New Parsing and Triangulation Functions 
+                                                
+ \***********************************************************************************************************/
+
+
+
+
+// This routine is basically an overview of the entire process that converts the BSP
+// into something our Ogre code can use to construct the map's mesh and level data.
+// In essence, it converts the map geometry into a list of triangles sorted by zone and material,
+// as well as extracting other map info like zone and portal bounding boxes, lights, entities etc.
+
+int Q3Map::ParseAndTriangulateMap(const char* pData, size_t Size)
+{
+	
+//	char chMessage[1024] ;
+	int nError=0 ;
+
+		// setup pointers to the various lumps and get their quantities
+		nError=parseMap( pData, Size ) ;
+		if(nError<0)
+		{
+			//sprintf(chMessage, "Parse Map Error: %i", nError) ; 
+			//Q3Bug.LogAddCR(chMessage) ;
+			return ERROR_ParseMap ;
+		}
+
+		// extract entities such as lights, monsters, etc
+		if(!ParseEntities())										return ERROR_ParseEntities ;
+
+		// initial memory allocation for triangles
+		m_nVertexMax=0 ;
+		if(!AllocateVertexMemory(m_iNumVertices))	return ERROR_AllocateVertex ;
+		if(!AllocateTriangleMemory())						return ERROR_AllocateTriangle ;
+		if(!initFaces())												return ERROR_InitializeFaces ;
+
+		// no new map textures should be added after here, or else SetupTransTextures won't work
+		if(!SetupTransTextures())								return ERROR_SetupTransTextures ;
+
+		// work out the zones
+		SetupZones() ;
+
+		// convert faces to triangles
+		if(!ConvertFacesToTriangles())					return ERROR_ConvertFaces ;
+
+		if(!ConvertPatchesToTriangles())				return ERROR_ConvertPatches ;
+
+		if(!ConvertLampsToTriangles())					return ERROR_ConvertLamps ;
+
+		if(!ConvertLampsToGlowTriangles())			return ERROR_ConvertLampGlow ;
+
+		if(!ConvertLightsToGlowTriangles())			return ERROR_ConvertLightGlow ;
+
+		GetTexLampTextureNumbers() ; // find out which textures, if any, are textures/common/bzn_lightnode0 to textures/common/bzn_lightnode3
+
+		// assign triangles to zones, splitting them where necessary
+		if(!AssignTrianglesToZones())						return ERROR_AssignTriangles ;
+
+		if(!ConvertTexLampsToLampTriangles())		return ERROR_ConvertTexLamp ;
+
+		// sort by group and re-range the group numbers
+		if(!SortTrianglesIntoGroups())					return ERROR_SortGroups ;
+
+		// sort the triangles in order of zone and texture.  This will also get rid of any unsubzoned triangles.
+		if(!SortTrianglesIntoBatches())					return ERROR_SortTriangles ;
+
+		
+
+
+		// Setup the portals, lights and various bits of map connectivity
+		AssignPortalsToZones() ;		// what portals each zone touches
+		AssignLightsToZones() ;			// what lights each zone touches
+		AssignLightsToPortals() ;		// what lights each portal touches
+		AssignZonesToZones() ;			// what zones each zone touches
+
+
+		return NOERROR ;
+}
+
+void Q3Map::FreeParseMem(void)
+{
+	FreeVertexMemory() ;
+	FreeTriangleMemory() ;
+	DestroyBspFacesMemory() ;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// memory management
+
+int Q3Map::AllocateTriangleMemory(void)
+{
+	// memory for the Triangle
+	m_nTriangleSize=MEMADD ; // starting memory size
+	m_pTriangleMem=malloc(m_nTriangleSize) ; // allocate starting memory space
+	m_pTriangle=(triangle_t*)m_pTriangleMem ; // a pointer to the memory cast as a triangle_t
+	m_nTriangleMax=0 ;
+	m_nTriangleLimit=m_nTriangleSize/sizeof(triangle_t) ; // if pos reaches this memory must expand
+
+	if(m_pTriangleMem==NULL)
+		return 0 ;
+
+	return 1 ;
+}
+
+void Q3Map::FreeTriangleMemory(void)
+{
+	if(m_pTriangleMem) free(m_pTriangleMem) ;
+	m_pTriangleMem=NULL ;
+	m_pTriangle=NULL ;
+	m_nTriangleMax=0 ;
+	m_nTriangleLimit=0 ;
+}
+
+// increase size of Triangle memory, return 0 if failed
+int Q3Map::ExpandTriangleMemory(void)
+{
+	m_nTriangleSize+=MEMADD ; // increase size
+	m_pTriangleMem=realloc(m_pTriangleMem, m_nTriangleSize) ; // reallocate the memory
+	if(m_pTriangleMem==NULL) return 0 ; // failed to allocate memory, get out and return false
+
+	// if here then memory allocation succeeded
+	m_pTriangle=(triangle_t*)m_pTriangleMem ; // pointer to the memory cast as a triangle_t
+	m_nTriangleLimit=m_nTriangleSize/sizeof(triangle_t) ; // if pos reaches this memory must expand
+	return 1 ; // ok
+}
+
+int Q3Map::AddTriangle(triangle_t Triangle)
+{
+	if(m_nTriangleMax>=m_nTriangleLimit)
+		if( !ExpandTriangleMemory() )
+			return 0 ;
+
+	m_pTriangle[m_nTriangleMax++]=Triangle ;
+
+	return 1 ;
+}
+
+int Q3Map::AllocateVertexMemory(int nVertNum)
+{
+	// memory for the Vertex
+	m_nVertexSize=nVertNum*sizeof(Q3BspVertex)+MEMADD ; // starting memory size
+	m_pVertexMem=malloc(m_nVertexSize) ; // allocate starting memory space
+	m_pVertex=(Q3BspVertex*)m_pVertexMem ; // a pointer to the memory cast as a triangle_t
+	m_nVertexLimit=m_nVertexSize/sizeof(Q3BspVertex) ; // if pos reaches this memory must expand
+
+	if(m_pVertexMem==NULL)
+		return 0 ;
+
+	return 1 ;
+}
+
+void Q3Map::FreeVertexMemory(void)
+{
+	if(m_pVertexMem) free(m_pVertexMem) ;
+	m_pVertexMem=NULL ;
+	m_pVertex=NULL ;
+	m_nVertexMax=0 ;
+	m_nVertexLimit=0 ;
+}
+
+// increase size of Vertex memory, return 0 if failed
+int Q3Map::ExpandVertexMemory(void)
+{
+	m_nVertexSize+=MEMADD ; // increase size
+	m_pVertexMem=realloc(m_pVertexMem, m_nVertexSize) ; // reallocate the memory
+	if(m_pVertexMem==NULL) return 0 ; // failed to allocate memory, get out and return false
+
+	// if here then memory allocation succeeded
+	m_pVertex=(Q3BspVertex*)m_pVertexMem ; // pointer to the memory cast as a triangle_t
+	m_nVertexLimit=m_nVertexSize/sizeof(Q3BspVertex) ; // if pos reaches this memory must expand
+	return 1 ; // ok
+}
+
+int Q3Map::AddVertex(Q3BspVertex Vertex)
+{
+
+	if(m_nVertexMax>=m_nVertexLimit)
+		if( !ExpandVertexMemory() )
+			return 0 ;
+
+	m_pVertex[m_nVertexMax++]=Vertex ;
+
+	return 1 ;
+}
+
+int Q3Map::AllocateLightMemory(void)
+{
+	// memory for the Light
+	m_nLightSize=MEMADD ; // starting memory size
+	m_pLightMem=malloc(m_nLightSize) ; // allocate starting memory space
+	m_pLight=(light_t*)m_pLightMem ; // a pointer to the memory cast as a light_t
+	m_nLightMax=0 ;
+	m_nLightLimit=m_nLightSize/sizeof(light_t) ; // if pos reaches this memory must expand
+
+	if(m_pLightMem==NULL)
+		return 0 ;
+
+	return 1 ;
+}
+
+void Q3Map::FreeLightMemory(void)
+{
+	if(m_pLightMem) free(m_pLightMem) ;
+	m_pLightMem=NULL ;
+	m_pLight=NULL ;
+	m_nLightMax=0 ;
+	m_nLightLimit=0 ;
+}
+
+// increase size of Light memory, return 0 if failed
+int Q3Map::ExpandLightMemory(void)
+{
+	m_nLightSize+=MEMADD ; // increase size
+	m_pLightMem=realloc(m_pLightMem, m_nLightSize) ; // reallocate the memory
+	if(m_pLightMem==NULL) return 0 ; // failed to allocate memory, get out and return false
+
+	// if here then memory allocation succeeded
+	m_pLight=(light_t*)m_pLightMem ; // pointer to the memory cast as a light_t
+	m_nLightLimit=m_nLightSize/sizeof(light_t) ; // if pos reaches this memory must expand
+	return 1 ; // ok
+}
+
+int Q3Map::AddLight(light_t Light)
+{
+	if(m_nLightLimit==0) // light memory hasn't been allocated yet
+	{
+		if( !AllocateLightMemory() )
+			return 0 ;
+	}
+	else
+		if(m_nLightMax>=m_nLightLimit)
+			if( !ExpandLightMemory() )
+				return 0 ;
+
+	m_pLight[m_nLightMax++]=Light ;
+
+	return 1 ;
+}
+
+// lamps are deferred shading, non-shadowing point lights
+int Q3Map::AllocateLampMemory(void)
+{
+	// memory for the Lamp
+	m_nLampSize=MEMADD ; // starting memory size
+	m_pLampMem=malloc(m_nLampSize) ; // allocate starting memory space
+	m_pLamp=(lamp_t*)m_pLampMem ; // a pointer to the memory cast as a lamp_t
+	m_nLampMax=0 ;
+	m_nLampLimit=m_nLampSize/sizeof(lamp_t) ; // if pos reaches this memory must expand
+
+	if(m_pLampMem==NULL)
+		return 0 ;
+
+	return 1 ;
+}
+
+void Q3Map::FreeLampMemory(void)
+{
+	if(m_pLampMem) free(m_pLampMem) ;
+	m_pLampMem=NULL ;
+	m_pLamp=NULL ;
+	m_nLampMax=0 ;
+	m_nLampLimit=0 ;
+}
+
+// increase size of Lamp memory, return 0 if failed
+int Q3Map::ExpandLampMemory(void)
+{
+	m_nLampSize+=MEMADD ; // increase size
+	m_pLampMem=realloc(m_pLampMem, m_nLampSize) ; // reallocate the memory
+	if(m_pLampMem==NULL) return 0 ; // failed to allocate memory, get out and return false
+
+	// if here then memory allocation succeeded
+	m_pLamp=(lamp_t*)m_pLampMem ; // pointer to the memory cast as a lamp_t
+	m_nLampLimit=m_nLampSize/sizeof(lamp_t) ; // if pos reaches this memory must expand
+	return 1 ; // ok
+}
+
+int Q3Map::AddLamp(lamp_t Lamp)
+{
+	if(m_nLampLimit==0) // Lamp memory hasn't been allocated yet
+	{
+		if( !AllocateLampMemory() )
+			return 0 ;
+	}
+	else
+		if(m_nLampMax>=m_nLampLimit)
+			if( !ExpandLampMemory() )
+				return 0 ;
+
+	m_pLamp[m_nLampMax++]=Lamp ;
+
+	return 1 ;
+}
+
+//////////////
+// Q3BspTexture textures.  We duplicate the loaded texture mem and then add lighting textures to it.
+
+int Q3Map::AllocateTextureMemory(void)
+{
+	// memory for the Texture
+	m_nTextureSize=MEMADD ; // starting memory size
+	m_pTextureMem=malloc(m_nTextureSize) ; // allocate starting memory space
+	m_pTexture=(Q3BspTexture*)m_pTextureMem ; // a pointer to the memory cast as a Q3BspTexture
+	m_nTextureMax=0 ;
+	m_nTextureLimit=m_nTextureSize/sizeof(Q3BspTexture) ; // if pos reaches this memory must expand
+
+	if(m_pTextureMem==NULL)
+		return 0 ;
+
+	return 1 ;
+}
+
+void Q3Map::FreeTextureMemory(void)
+{
+	if(m_pTextureMem) free(m_pTextureMem) ;
+	m_pTextureMem=NULL ;
+	m_pTexture=NULL ;
+	m_nTextureMax=0 ;
+	m_nTextureLimit=0 ;
+}
+
+// increase size of Texture memory, return 0 if failed
+int Q3Map::ExpandTextureMemory(void)
+{
+	m_nTextureSize+=MEMADD ; // increase size
+	m_pTextureMem=realloc(m_pTextureMem, m_nTextureSize) ; // reallocate the memory
+	if(m_pTextureMem==NULL) return 0 ; // failed to allocate memory, get out and return false
+
+	// if here then memory allocation succeeded
+	m_pTexture=(Q3BspTexture*)m_pTextureMem ; // pointer to the memory cast as a Q3BspTexture
+	m_nTextureLimit=m_nTextureSize/sizeof(Q3BspTexture) ; // if pos reaches this memory must expand
+	return 1 ; // ok
+}
+
+int Q3Map::AddTexture(Q3BspTexture Texture)
+{
+	if(m_nTextureLimit==0) // Texture memory hasn't been allocated yet
+	{
+		if( !AllocateTextureMemory() )
+			return 0 ;
+	}
+	else
+		if(m_nTextureMax>=m_nTextureLimit)
+			if( !ExpandTextureMemory() )
+				return 0 ;
+
+	m_pTexture[m_nTextureMax++]=Texture ;
+
+	return 1 ;
+}
+
+// special version of the Add function, will not add if the texture name already exist.  
+// Will succeed even if the texture is already on the list, but fails if it can't add a new texture
+// returns texture index, or -1 on fail
+// Q3 texture names can be tricky, I think I've had cases where they ended in spaces instead of nulls,
+// and they might go all the way to the end without either.
+
+int Q3Map::AddTextureUnique(Q3BspTexture Texture)
+{
+	if(m_nTextureLimit==0) // Texture memory hasn't been allocated yet
+		if( !AllocateTextureMemory() )
+			return ADDTEXTUREUNIQUE_FAIL ; // fail
+
+
+	// scan through all the newly added textures so far and see if this one already exists.
+	int nTexture=0 ;
+	int nPos=0 ;
+
+	bool bMatch=false ;
+
+	for(nTexture=0 ; nTexture<m_nTextureMax ; nTexture++)
+	{
+		bMatch=true ;
+		// scan through the characters of the texture names, comparing them.  We start after the original textures
+		//for(nPos=m_iNumTexs ; nPos<Q3NAMESIZE ; nPos++)
+		for(nPos=0 ; nPos<Q3NAMESIZE ; nPos++)
+		{
+			// is it the end of the texture name?  
+			if(
+						((Texture.name[nPos]							==0)	|| (Texture.name[nPos]							==' ')) // Texture    name end
+					&&((m_pTexture[nTexture].name[nPos] ==0)	|| (m_pTexture[nTexture].name[nPos]	==' ')) // m_pTexture name end
+				)
+				break ;
+
+			// do the two textures have a difference in the name at this position?
+			if(Texture.name[nPos]!=m_pTexture[nTexture].name[nPos])
+			{
+				bMatch=false ;
+				break ;
+			}
+		
+		}// end scanning name
+
+		if(bMatch) // found a match, so return ok but don't add a texture
+		{
+			return nTexture ;  // we don't add any new texture, return this texture's index
+		}
+	}
+
+	// if we got this far, we must have a unique texture
+
+	// add the texture, it is unique
+	if(m_nTextureMax>=m_nTextureLimit)
+		if( !ExpandTextureMemory() )
+			return ADDTEXTUREUNIQUE_FAIL ; // fail
+
+	m_pTexture[m_nTextureMax++]=Texture ;
+
+	return m_nTextureMax-1 ; // return this new texture's index
+
+}
+
+
+////////////////////////////////////////
+
+int Q3Map::AllocateTexLampMemory(void)
+{
+	// memory for the TexLamp
+	m_nTexLampSize=MEMADD ; // starting memory size
+	m_pTexLampMem=malloc(m_nTexLampSize) ; // allocate starting memory space
+	m_pTexLamp=(int*)m_pTexLampMem ; // a pointer to the memory cast as an int
+	m_nTexLampMax=0 ;
+	m_nTexLampLimit=m_nTexLampSize/sizeof(int) ; // if pos reaches this memory must expand
+
+	if(m_pTexLampMem==NULL)
+		return 0 ;
+
+	return 1 ;
+}
+
+void Q3Map::FreeTexLampMemory(void)
+{
+	if(m_pTexLampMem) free(m_pTexLampMem) ;
+	m_pTexLampMem=NULL ;
+	m_pTexLamp=NULL ;
+	m_nTexLampMax=0 ;
+	m_nTexLampLimit=0 ;
+}
+
+// increase size of TexLamp memory, return 0 if failed
+int Q3Map::ExpandTexLampMemory(void)
+{
+	m_nTexLampSize+=MEMADD ; // increase size
+	m_pTexLampMem=realloc(m_pTexLampMem, m_nTexLampSize) ; // reallocate the memory
+	if(m_pTexLampMem==NULL) return 0 ; // failed to allocate memory, get out and return false
+
+	// if here then memory allocation succeeded
+	m_pTexLamp=(int*)m_pTexLampMem ; // pointer to the memory cast as an int
+	m_nTexLampLimit=m_nTexLampSize/sizeof(int) ; // if pos reaches this memory must expand
+	return 1 ; // ok
+}
+
+int Q3Map::AddTexLamp(int TexLamp)
+{
+	if(m_nTexLampMax>=m_nTexLampLimit)
+		if( !ExpandTexLampMemory() )
+			return 0 ;
+
+	m_pTexLamp[m_nTexLampMax++]=TexLamp ;
+
+	return 1 ;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// extract entities from bsp entities lump
+int Q3Map::ParseEntities(void)
+{
+//	char chKey[MAX_TOKENSIZE+1] ;   // +1 to leave room for null terminator
+//	char chValue[MAX_TOKENSIZE+1] ; // +1 to leave room for null terminator
+	int nPos=0 ;
+	int nMaxPos=m_BspHeader.Lumps[0].iLength ;
+	int nEntityType=0 ;
+
+
+	// reset the spotlight textures
+	m_nMaxSpotlightTexture=0 ;
+	for(nPos=0 ; nPos<MAX_PROJECTORTEX ; nPos++)
+		m_chSpotlightTexture[nPos][0]='\0' ;
+
+	strcpy(m_chSpotlightTexture[m_nMaxSpotlightTexture], "spotlight.dds") ; // the default spotlight texture
+	m_nMaxSpotlightTexture++ ;
+
+	////////////////////////////////////////////////////////////////////////////
+	// before adding all the entities we need to add some default textures
+	Q3BspTexture Texture ;
+	Texture.contents=0 ;
+	Texture.flags=0 ;
+
+	// default lamp texture
+	strcpy(Texture.name, "lights/lamp_default") ;
+	m_nDefaultTextureIndexLamp=AddTextureUnique(Texture) ;
+	if(m_nDefaultTextureIndexLamp==ADDTEXTUREUNIQUE_FAIL) return 0 ;
+
+	// default lamp2Pass texture
+	strcpy(Texture.name, "lights/lamp2pass_default") ;
+	m_nDefaultTextureIndexLamp2Pass=AddTextureUnique(Texture) ;
+	if(m_nDefaultTextureIndexLamp2Pass==ADDTEXTUREUNIQUE_FAIL) return 0 ;
+
+	// default glow texture
+	strcpy(Texture.name, "GLOW_lamp") ;
+	m_nDefaultTextureIndexGlowLamp=AddTextureUnique(Texture) ;
+	if(m_nDefaultTextureIndexGlowLamp==ADDTEXTUREUNIQUE_FAIL) return 0 ;
+
+	// default glow texture
+	strcpy(Texture.name, "GLOW_light") ;
+	m_nDefaultTextureIndexGlowLight=AddTextureUnique(Texture) ;
+	if(m_nDefaultTextureIndexGlowLight==ADDTEXTUREUNIQUE_FAIL) return 0 ;
+
+
+	// default spotlight texture
+	//strcpy(Texture.name, "lights/light_default") ;
+	//m_nDefaultTextureIndexSpotlight=AddTextureUnique(Texture) ;
+	//if(m_nDefaultTextureIndexSpotlight==ADDTEXTUREUNIQUE_FAIL) return 0 ;
+
+	//
+	///////////////////////////////////////////////////////////////////////////
+
+
+	nPos=-1 ;
+	while(NextEntity(&nPos, nMaxPos))
+	{
+		
+		nEntityType=GetEntityType(nPos, nMaxPos) ; // what type of entity is it?
+
+
+		switch(nEntityType)
+		{
+			case ENTITY_ERROR: return 0 ; // something is wrong with the entity data
+
+			case ENTITY_LIGHT: 
+				if(!ParseAndAddLight(&nPos, nMaxPos)) 
+					return 0 ; // something went wrong with parsing the light
+				break ;
+		}// end switch entity type
+
+
+	}// end get next entity
+
+
+
+	// everything is ok.
+	return 1 ;
+}
+
+// move to the beginning of the next entity.
+// fail if there are no more.
+int Q3Map::NextEntity(int* pPos, int nMaxPos)
+{
+	while((++*pPos<nMaxPos) && (m_pEntities[*pPos]!='{')) ;
+
+	if(*pPos==nMaxPos) 
+		return 0 ;
+
+	return 1 ;
+}
+
+// find out what type of entity this is.
+// Since the classname might not be at the beginning we have to scan through the whole entity
+// This function also doesn't update the position like the others do,
+// since scanning of further key/values will have to start at the beginning of the entity again.
+int Q3Map::GetEntityType(int nPos, int nMaxPos)
+{
+	char chKey[MAX_TOKENSIZE+1] ;   // +1 to leave room for null terminator
+	char chValue[MAX_TOKENSIZE+1] ; // +1 to leave room for null terminator
+
+	while(nPos<nMaxPos)
+	{
+		if(GetEntityKeyAndValue(&nPos, nMaxPos, chKey, chValue)!=KEY_OK) return ENTITY_ERROR ; // something went wrong, couldn't find any good keys
+		
+		if(strcmp(chKey, "classname")==0) // found the classname key
+		{
+			if(strcmp(chValue, "worldspawn")==0)			return ENTITY_WORLDSPAWN ;
+			if(strcmp(chValue, "light")==0)						return ENTITY_LIGHT ;
+
+			// wasn't any entity we recognize
+			return ENTITY_UNKNOWN ;
+
+		}// end if got entity classname
+
+	}// end while nPos
+
+	// didn't find any classname
+	return ENTITY_ERROR ;
+}
+
+// get next entity key and value
+int Q3Map::GetEntityKeyAndValue(int* pPos, int nMaxPos, char* pKey, char* pValue)
+{
+
+	char* pEntText=m_pEntities ;
+	int nEntPos=*pPos ;
+	int nKeyPos=-1 ;
+	int nValuePos=-1 ;
+
+	// clear key and value strings
+	pKey[0]='\0' ;
+	pValue[0]='\0' ;
+
+	/////////////////////////////////////////////////////////////////////////////////////////
+	// Key
+
+	// find the next "
+	while((++nEntPos<nMaxPos) && (pEntText[nEntPos]!='}') && (pEntText[nEntPos]!='"')) ;
+
+	// didn't find key, get out
+	if((nEntPos==nMaxPos) || (pEntText[nEntPos]=='}'))
+		return KEY_NONE ;
+
+
+	// copy key
+	while((++nEntPos<nMaxPos) && (nKeyPos<MAX_TOKENSIZE) && (pEntText[nEntPos]!='}') && (pEntText[nEntPos]!='"')) 
+		pKey[++nKeyPos]=pEntText[nEntPos] ;
+
+	if((nEntPos==nMaxPos) || (nKeyPos==MAX_TOKENSIZE) || (pEntText[nEntPos]=='}'))
+		return KEY_ERROR ; // entity was incomplete or too big
+
+	pKey[++nKeyPos]='\0' ;
+
+	/////////////////////////////////////////////////////////////////////////////////////////
+	// value
+
+	// find the next "
+	while((++nEntPos<nMaxPos) && (pEntText[nEntPos]!='}') && (pEntText[nEntPos]!='"')) ;
+
+	// didn't find value, get out
+	if((nEntPos==nMaxPos) || (pEntText[nEntPos]=='}'))
+		return KEY_ERROR ; 
+
+	// copy value
+	while((++nEntPos<nMaxPos) && (nValuePos<MAX_TOKENSIZE) && (pEntText[nEntPos]!='}') && (pEntText[nEntPos]!='"')) 
+		pValue[++nValuePos]=pEntText[nEntPos] ;
+
+	if((nEntPos==nMaxPos) || (nValuePos==MAX_TOKENSIZE) || (pEntText[nEntPos]=='}'))
+		return KEY_ERROR ; // entity was incomplete or too big
+
+	pValue[++nValuePos]='\0' ;
+
+	/////////////////////////////////////////////////////////////////////////////////////////
+
+	*pPos=nEntPos+1 ;
+
+	return KEY_OK ;
+}
+
+
+// fills array pNumber with the values extracted from pValue, returns how many numbers it got.
+// float version
+int Q3Map::GetNumbersFromValue(char* pValue, float *pNumber, int nNumberSize)
+{
+	int nLength=strlen(pValue) ;
+	if(nLength<1) return 0 ;
+
+	int nPos=-1 ;
+	int nCount=0 ;
+	char chTemp[MAX_TOKENSIZE+1] ;
+	int nTempPos=0 ;
+
+	do
+	{
+
+		nPos++ ;
+		
+		if(
+				((pValue[nPos]>='0') && (pValue[nPos]<='9')) // found another digit
+				||
+				(pValue[nPos]=='.')
+				||
+				(pValue[nPos]=='-')
+			)
+		{
+			chTemp[nTempPos++]=pValue[nPos] ;
+			if(nTempPos==MAX_TOKENSIZE) return 0 ; // number too big
+		}
+		else // anything else means the end of the number
+		{
+			
+			chTemp[nTempPos]='\0' ;
+			pNumber[nCount++]=atof(chTemp) ;
+			nTempPos=0 ;
+		}
+		
+
+	}while((nPos<nLength) && (nCount<nNumberSize) && (pValue[nPos]!='\0')) ;
+
+
+	return nCount ;
+}
+
+// integer version
+int Q3Map::GetNumbersFromValue(char* pValue, int *pNumber, int nNumberSize)
+{
+	int nLength=strlen(pValue) ;
+	if(nLength<1) return 0 ;
+
+	int nPos=-1 ;
+	int nCount=0 ;
+	char chTemp[MAX_TOKENSIZE+1] ;
+	int nTempPos=0 ;
+
+	do
+	{
+
+		nPos++ ;
+		
+		if(
+				((pValue[nPos]>='0') && (pValue[nPos]<='9')) // found another digit
+				||
+				(pValue[nPos]=='.')
+				||
+				(pValue[nPos]=='-')
+			)
+		{
+			chTemp[nTempPos++]=pValue[nPos] ;
+			if(nTempPos==MAX_TOKENSIZE) return 0 ; // number too big
+		}
+		else // anything else means the end of the number
+		{
+			
+			chTemp[nTempPos]='\0' ;
+			pNumber[nCount++]=atoi(chTemp) ;
+			nTempPos=0 ;
+		}
+		
+
+	}while((nPos<nLength) && (nCount<nNumberSize) && (pValue[nPos]!='\0')) ;
+
+
+	return nCount ;
+}
+
+//''
+// extracts data for either forward rendered shadow casting spotlights or deferred shading non-shadowing point lights
+// the point lights ("lamps") will later be changed into map triangles.
+int Q3Map::ParseAndAddLight(int* pPos, int nMaxPos)
+{
+//	char chMessage[1024] ;
+
+
+	char chKey[MAX_TOKENSIZE+1] ;   // +1 to leave room for null terminator
+	char chValue[MAX_TOKENSIZE+1] ; // +1 to leave room for null terminator
+	float flOrigin[3]={0.0f, 0.0f, 0.0f} ;
+	float flColour[3]={1.0f, 1.0f, 1.0f} ;
+	float flCentre[3]={0.0f, 0.0f, 0.0f} ;
+	float flAimvec[3]={0.0f, 0.0f, 0.0f} ;
+	float flRadius[3]={0.0f, 0.0f, 0.0f} ;
+	
+	float flTemp[3]={0.0f, 0.0f, 0.0f} ;
+	int nTemp[3] ;
+
+	float flAngle=0.0f ;
+	float flCutoff=0.0f ;
+	float flLength=0.0f ;
+	float flBrightness=0.0f ;
+	int nLightNode=-1 ;
+
+	bool bSpotLight=false ;
+
+	Q3BspTexture Q3Texture ;
+	Q3Texture.flags=0 ;
+	Q3Texture.contents=0 ;
+	Q3Texture.name[0]=0 ;
+
+
+	light_t NewLight ; // forward rendered shadow casting spotlight
+	ZeroMemory((void*)&NewLight, sizeof(light_t)) ;
+
+	lamp_t NewLamp ; // deferred shading non-shadowing point light
+	ZeroMemory((void*)&NewLamp, sizeof(lamp_t)) ;
+
+	int nKeyReturn=KEY_NONE ; 
+
+	do
+	{
+		nKeyReturn=GetEntityKeyAndValue(pPos, nMaxPos, chKey, chValue) ;
+	
+		if(nKeyReturn==KEY_OK) // found a key
+		{
+
+			if(strcmp(chKey, "origin")==0)
+			{
+				if(GetNumbersFromValue(chValue, flOrigin, 3)!=3) return 0 ; // extract the numbers
+				swizzleFloat3(flOrigin) ; // fix coordinates
+			}
+			else
+			if(strcmp(chKey, "_color")==0)
+			{
+				if(GetNumbersFromValue(chValue, flColour, 3)!=3) return 0 ; // extract the numbers
+			}
+			else
+			if(strcmp(chKey, "light_center")==0)
+			{
+				if(GetNumbersFromValue(chValue, flCentre, 3)!=3) return 0 ; // extract the numbers		
+				swizzleFloat3(flCentre) ; // fix coordinates
+			}
+			else
+			if(strcmp(chKey, "light_target")==0)
+			{
+				if(GetNumbersFromValue(chValue, flAimvec, 3)!=3) return 0 ; // extract the numbers		
+				swizzleFloat3(flAimvec) ; // fix coordinates
+				bSpotLight=true ; // if there's a target key, then this must be a spotlight
+			}
+			else
+			if(strcmp(chKey, "light_radius")==0)
+			{
+				if(GetNumbersFromValue(chValue, flRadius, 3)!=3) return 0 ; // extract the numbers
+				swizzleFloat3(flRadius) ; // fix coordinates
+				// make sure all values are positive
+				flRadius[0]=fabs(flRadius[0]) ;
+				flRadius[1]=fabs(flRadius[1]) ;
+				flRadius[2]=fabs(flRadius[2]) ;
+			}
+			else
+			if(strcmp(chKey, "light_abc")==0)
+			{
+				if(GetNumbersFromValue(chValue, flTemp, 3)!=3) return 0 ; // extract the numbers
+				flAngle				= flTemp[0] ;
+				flBrightness	= flTemp[1] ;
+				flCutoff			= flTemp[2] ;
+			}
+			else
+			if(strcmp(chKey, "texture")==0)
+			{
+				strcpy(Q3Texture.name, chValue) ;
+			}
+			if(strcmp(chKey, "light_node")==0)
+			{
+				if(GetNumbersFromValue(chValue, nTemp, 1)!=1) return 0 ; // extract the number
+				nLightNode				= nTemp[0] ;	
+				if((nLightNode<0) || (nLightNode>3)) return 0 ; // something dodgy about the lightnode number
+			}
+
+		}// end if key ok
+
+		
+
+	}while(nKeyReturn==KEY_OK) ;  // end do looping through keys
+
+
+	// return a fail if there was a problem with the keys
+	if(nKeyReturn==KEY_ERROR) return 0 ; 
+
+
+	if(bSpotLight)// found a light_target so this must be a spotlight
+	{
+		// light settings.
+		NewLight.Position[0]=flOrigin[0]+flCentre[0] ;
+		NewLight.Position[1]=flOrigin[1]+flCentre[1] ;
+		NewLight.Position[2]=flOrigin[2]+flCentre[2] ;
+
+		NewLight.Min[0]=flOrigin[0]-flRadius[0] ;
+		NewLight.Min[1]=flOrigin[1]-flRadius[1] ;
+		NewLight.Min[2]=flOrigin[2]-flRadius[2] ;
+
+		NewLight.Max[0]=flOrigin[0]+flRadius[0] ;
+		NewLight.Max[1]=flOrigin[1]+flRadius[1] ;
+		NewLight.Max[2]=flOrigin[2]+flRadius[2] ;
+
+		NewLight.Colour[0]=flColour[0] ;
+		NewLight.Colour[1]=flColour[1] ;
+		NewLight.Colour[2]=flColour[2] ;
+
+		NewLight.Angle=flAngle ;
+		NewLight.Cutoff=flCutoff ;
+		NewLight.Brightness=flBrightness * BRIGHTNESSTWEAK ;
+
+
+		// direction light points, as a normal
+		flLength=sqrt( flAimvec[0]*flAimvec[0] + flAimvec[1]*flAimvec[1] + flAimvec[2]*flAimvec[2] ) ;
+		if(flLength>0.0f)
+		{
+			NewLight.Direction[0]=flAimvec[0]/flLength ;
+			NewLight.Direction[1]=flAimvec[1]/flLength ;
+			NewLight.Direction[2]=flAimvec[2]/flLength ;
+		}
+		else
+		{ // default to pointing down
+			NewLight.Direction[0]=0.0f ;
+			NewLight.Direction[1]=1.0f ;
+			NewLight.Direction[2]=0.0f ;
+		}
+
+		NewLight.ZoneCount=0 ;
+		NewLight.CentreZone=0 ;
+	
+		
+		if(Q3Texture.name[0]==0)	
+			strcpy(Q3Texture.name, "spotlight.dds") ;
+		
+		NewLight.Texture=AddSpolightTexture(Q3Texture.name) ;
+
+
+		if(NewLight.Texture==ADDSPOTLIGHTTEXTURE_FAIL)
+			return 0 ; // failure	
+	
+		//AddTextureUnique(Q3Texture) ;
+		/*
+		// add the light's texture index
+		if(Q3Texture.name[0]==0)
+			NewLight.Texture=m_nDefaultTextureIndexSpotlight ;
+		else
+		{
+			NewLight.Texture=AddTextureUnique(Q3Texture) ; // this will add the texture name to the list if it is unique, as well as setting the index
+			if(NewLight.Texture==ADDTEXTUREUNIQUE_FAIL) 
+				return 0 ;
+		}
+		*/
+
+		return AddLight(NewLight) ;
+	}
+	else // add a non-shadowing deferred shading point light
+	{
+		// light settings.
+		NewLamp.Position[0]=flOrigin[0]+flCentre[0] ;
+		NewLamp.Position[1]=flOrigin[1]+flCentre[1] ;
+		NewLamp.Position[2]=flOrigin[2]+flCentre[2] ;
+
+		NewLamp.Min[0]=flOrigin[0]-flRadius[0] ;
+		NewLamp.Min[1]=flOrigin[1]-flRadius[1] ;
+		NewLamp.Min[2]=flOrigin[2]-flRadius[2] ;
+
+		NewLamp.Max[0]=flOrigin[0]+flRadius[0] ;
+		NewLamp.Max[1]=flOrigin[1]+flRadius[1] ;
+		NewLamp.Max[2]=flOrigin[2]+flRadius[2] ;
+
+		NewLamp.Colour[0]=flColour[0] ;
+		NewLamp.Colour[1]=flColour[1] ;
+		NewLamp.Colour[2]=flColour[2] ;
+
+		NewLamp.Brightness=flBrightness * BRIGHTNESSTWEAK ;
+
+		NewLamp.LightNode=nLightNode ; // typically -1, but may be 0 to 3 if this lamp is the node for some TexLamp freeform deferred shading geometry.
+
+
+		// Note that m_pLamp.Zone will be set after we first convert lamps into triangles and then 
+		// assign those triangles to zones.  At that point, if the assigned triangle is also flagged as
+		// coming from a lamp, then the lamp's list of zones will be updated.
+
+				// add the light's texture index
+		if(Q3Texture.name[0]==0)
+		{
+			if(nLightNode==-1)
+				NewLamp.Texture=m_nDefaultTextureIndexLamp ; // normal 1 pass deferred shading
+			else
+				NewLamp.Texture=m_nDefaultTextureIndexLamp2Pass ; // special 2 pass deferred shading to texlamps
+		}
+		else
+		{
+			NewLamp.Texture=AddTextureUnique(Q3Texture) ; // this will add the texture name to the list if it is unique, as well as setting the index
+			if(NewLamp.Texture==ADDTEXTUREUNIQUE_FAIL) 
+				return 0 ;
+		}	
+
+		return AddLamp(NewLamp) ;
+	}
+
+}
+
+// adds a spotlight texture name if it is unique, returns the index to that texture name either way.
+// returns ADDSPOTLIGHTTEXTURE_FAIL on a fail
+
+int Q3Map::AddSpolightTexture(char TEXNAME[])
+{
+	if((strlen(TEXNAME)>Q3NAMESIZE) || (m_nMaxSpotlightTexture>=MAX_PROJECTORTEX))
+		return ADDSPOTLIGHTTEXTURE_FAIL ;
+
+
+	// scan through all the newly added textures so far and see if this one already exists.
+	int nTexture=0 ;
+	int nPos=0 ;
+
+	bool bMatch ;
+
+	for(nTexture=0 ; nTexture<m_nMaxSpotlightTexture ; nTexture++)
+	{
+		bMatch=true ;
+		// scan through the characters of the texture names, comparing them. 
+		for(nPos=0 ; nPos<Q3NAMESIZE ; nPos++)
+		{
+			// do the two textures have a difference in the name at this position?
+			if(m_chSpotlightTexture[nTexture][nPos]!=TEXNAME[nPos])
+			{
+				bMatch=false ;
+				break ;
+			}
+
+			// is it the end of the texture name?  
+			if(TEXNAME[nPos]=='\0') // end of texture
+				break ;
+		
+		}// end scanning name
+
+		if(bMatch) // found a match, so return ok but don't add a texture
+			return nTexture ;  // we don't add any new texture, return this texture's index
+	}
+
+	// if we got this far, we must have a unique texture
+	strcpy(m_chSpotlightTexture[m_nMaxSpotlightTexture], TEXNAME) ;
+	m_nMaxSpotlightTexture++ ;
+
+	return m_nMaxSpotlightTexture-1 ; // return this new texture's index
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+int Q3Map::initFaces(void)
+{
+
+	m_nGroup=0 ; // reset the group counter, used to work out transparent groupings for triangles.
+	
+  Q3BspFace_t *faces = getFaces();
+
+  m_BspFaces = new Q3BspFaceRenderer[m_iNumFaces];
+	if(m_BspFaces==NULL) return 0 ; // fail, out of memory.
+  m_NumBspFaces = m_iNumFaces;
+
+	
+  for (int i=0; i < m_NumBspFaces; i++)
+  {					
+    m_BspFaces[i].lm_index = faces[i].lm_index;
+    m_BspFaces[i].meshvert = faces[i].meshvert;
+    m_BspFaces[i].n_meshverts = faces[i].n_meshverts;
+    m_BspFaces[i].n_vertexes = faces[i].n_vertexes;
+    for (int j=0; j<3; j++)
+      m_BspFaces[i].normal[j] = faces[i].normal[j];
+    m_BspFaces[i].texture = faces[i].texture;
+    m_BspFaces[i].type = faces[i].type;
+    m_BspFaces[i].vertex = faces[i].vertex;
+
+    m_BspFaces[i].n_triangles = m_BspFaces[i].n_meshverts / 3;
+
+    if (m_BspFaces[i].type == PATCH)
+    {
+      m_BspFaces[i].patch = handlePatch(i);
+    }
+    else
+    {
+      m_BspFaces[i].patch = NULL;
+    }
+
+
+  }
+
+
+	// check patches aren't degenerate
+	int numIndex = 0;
+  int numVertex = 0;
+
+
+    for (int i=0; i < m_NumBspFaces; i++)
+    {		
+
+			numIndex = 0;
+			numVertex = 0;
+
+      if ((m_BspFaces[i].type == PATCH) && (m_BspFaces[i].patch != NULL))
+			{
+          for (int j=0; j < m_BspFaces[i].patch->size; j++)
+          {
+            numIndex += m_BspFaces[i].patch->bezier[j].mNumIndex;
+            numVertex += m_BspFaces[i].patch->bezier[j].mNumVertex;
+          }
+
+					if((numIndex==0) || (numVertex==0))
+					{
+						DELETE_ARRAY( m_BspFaces[i].patch->bezier ) ;
+						DELETE_POINTER( m_BspFaces[i].patch ) ;
+					}
+
+      }// end if patch
+
+
+    }// end for 
+
+
+
+	// copy the vertices over.  
+	// We need to work on a copy because we need to create new verts when splitting triangles that cross subzones, and for patches
+	for(int i=0 ; i<m_iNumVertices ; i++)
+	{
+		m_pVertex[i]=m_pVertices[i] ;
+		m_nVertexMax++ ; // need to update this manually since we aren't adding new verts, but filling in the original mem.
+	}
+
+
+	return 1 ;
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// stuff for assigning triangles to subzones, splitting them where necessary.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void Q3Map::SetupZones(void)
+{
+	int nSubZone=0 ;
+	int nZone=0 ;
+	int nPos=0 ;
+
+//	float flMinX=0.0f ;
+//	float flMinY=0.0f ;
+//	float flMinZ=0.0f ;
+//	float flMaxX=0.0f ;
+//	float flMaxY=0.0f ;
+//	float flMaxZ=0.0f ;
+
+	m_nMaxZone=0 ;
+	
+	for(nZone=0 ; nZone<MAX_ZONE ; nZone++)
+	{
+		m_nZone[nZone][INDEX_SUBZONECOUNT]=0 ;
+		m_ZoneBoundary[nZone].Min[0]=MINMAXLIMIT ;
+		m_ZoneBoundary[nZone].Min[1]=MINMAXLIMIT ;
+		m_ZoneBoundary[nZone].Min[2]=MINMAXLIMIT ;
+		m_ZoneBoundary[nZone].Max[0]=-MINMAXLIMIT ;
+		m_ZoneBoundary[nZone].Max[1]=-MINMAXLIMIT ;
+		m_ZoneBoundary[nZone].Max[2]=-MINMAXLIMIT ;
+	}
+
+
+	// find the highest used zone number, then +1 to get our limit.
+	for(nSubZone=0 ; nSubZone<m_iNumSubZones ; nSubZone++)
+		if(m_pSubZones[nSubZone].Zone>m_nMaxZone)
+			m_nMaxZone=m_pSubZones[nSubZone].Zone ;
+
+	m_nMaxZone++ ; // our limit
+
+	
+	//char chMessage[1024] ;
+
+
+	// fill in what subzones are in each zone
+	for(nSubZone=0 ; nSubZone<m_iNumSubZones ; nSubZone++)
+	{
+		
+
+		nZone=m_pSubZones[nSubZone].Zone ;
+
+		// find next empty slot in this zone
+		nPos=0 ;
+		while((nPos<MAX_SUBZONEPERZONE) && (nPos<m_nZone[nZone][INDEX_SUBZONECOUNT]))
+			nPos++ ;
+
+		// if there's room, add the subzone to this zone
+		if(nPos<MAX_SUBZONEPERZONE) 
+		{
+			m_nZone[nZone][nPos]=nSubZone ;
+
+			// limits used for cutting up lights (not useful for other boundary stuff, check subzones instead)
+			if(m_pSubZones[nSubZone].Min[0]<m_ZoneBoundary[nZone].Min[0]) 
+				m_ZoneBoundary[nZone].Min[0]= m_pSubZones[nSubZone].Min[0] ;
+			if(m_pSubZones[nSubZone].Min[1]<m_ZoneBoundary[nZone].Min[1]) 
+				m_ZoneBoundary[nZone].Min[1]= m_pSubZones[nSubZone].Min[1] ;
+			if(m_pSubZones[nSubZone].Min[2]<m_ZoneBoundary[nZone].Min[2]) 
+				m_ZoneBoundary[nZone].Min[2]= m_pSubZones[nSubZone].Min[2] ;
+
+			if(m_pSubZones[nSubZone].Max[0]>m_ZoneBoundary[nZone].Max[0]) 
+				m_ZoneBoundary[nZone].Max[0]= m_pSubZones[nSubZone].Max[0] ;
+			if(m_pSubZones[nSubZone].Max[1]>m_ZoneBoundary[nZone].Max[1]) 
+				m_ZoneBoundary[nZone].Max[1]= m_pSubZones[nSubZone].Max[1] ;
+			if(m_pSubZones[nSubZone].Max[2]>m_ZoneBoundary[nZone].Max[2]) 
+				m_ZoneBoundary[nZone].Max[2]= m_pSubZones[nSubZone].Max[2] ;
+
+			m_nZone[nZone][INDEX_SUBZONECOUNT]++ ;
+		}
+
+
+	}
+
+
+}
+
+
+// work out what zone each triangle is in.
+// if it is in more than one, cut it up into smaller triangles that are only in one zone each.
+int Q3Map::AssignTrianglesToZones(void)
+{
+	int nCurrentTriangle=0 ;
+//	int nZone=0 ;
+
+
+	/*
+	char chMessage[1024] ;
+	float flPos[3] ;
+	int nTri=0 ;
+	float flVert[3][3] ;
+	
+
+	for(nTri=0 ; nTri<m_nTriangleMax ; nTri++)
+	{
+		flVert[0][0]=m_pVertex[  m_pTriangle[nTri].VIndex[0]  ].position[0] ;
+		flVert[0][1]=m_pVertex[  m_pTriangle[nTri].VIndex[0]  ].position[1] ;
+		flVert[0][2]=m_pVertex[  m_pTriangle[nTri].VIndex[0]  ].position[2] ;
+
+		flVert[1][0]=m_pVertex[  m_pTriangle[nTri].VIndex[1]  ].position[0] ;
+		flVert[1][1]=m_pVertex[  m_pTriangle[nTri].VIndex[1]  ].position[1] ;
+		flVert[1][2]=m_pVertex[  m_pTriangle[nTri].VIndex[1]  ].position[2] ;
+
+		flVert[2][0]=m_pVertex[  m_pTriangle[nTri].VIndex[2]  ].position[0] ;
+		flVert[2][1]=m_pVertex[  m_pTriangle[nTri].VIndex[2]  ].position[1] ;
+		flVert[2][2]=m_pVertex[  m_pTriangle[nTri].VIndex[2]  ].position[2] ;
+
+
+		flPos[0]=(flVert[0][0]+flVert[1][0]+flVert[2][0])/3.0f ;
+		flPos[1]=(flVert[0][1]+flVert[1][1]+flVert[2][1])/3.0f ;
+		flPos[2]=(flVert[0][2]+flVert[1][2]+flVert[2][2])/3.0f ;
+
+		nZone=0 ;
+		while((nZone<m_iNumSubZones) && !PointInZone(flPos, nZone))
+			nZone++ ;
+
+
+
+
+	}
+	*/
+
+
+
+	for(nCurrentTriangle=0 ; nCurrentTriangle<m_nTriangleMax ; nCurrentTriangle++)
+	{
+		if(!SetupTriangleZone(nCurrentTriangle)) return 0 ; // what zone completely contains this triangle, if any
+
+	}// end for current triangle
+
+	return 1 ;
+}
+
+// return the zone this triangle is in, or -1 if it is not entirely contained by any zone
+// this is also a convienient spot for us to update Lamp zones when we discover what zones its triangles are in,
+// and also a handy place to note if the triangle is a TexLamp or not 
+// (TexLamp is free form geometry that is bound to a lamp and gets converted to deferred shading lights, allowing us to do fake shadowing)
+
+int Q3Map::FindTriangleZone(int nTriangle)
+{
+	int nZone=0 ;
+//	int nSubZone=0 ;
+	int nPos=0 ;
+	bool bVertInSubZone=false ;
+	int nVert=0 ;
+	bool bTriangleInZone=false ;
+//	int nMaxSubZone=m_iNumSubZones ;
+	float flVert[6][3] ; // verts 0, 1, 2 are the original triangle corners, verts 3, 4, 5 are interpolated edge points.
+	// we need the edge points, since it's possible for all the 
+	// triangle verts to be in one L shaped zone but the triangle they form not be in that zone. 
+	// (such as if there's a vert at the corner and two ends of the "L")
+
+
+	flVert[0][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[0] ;
+	flVert[0][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[1] ;
+	flVert[0][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[2] ;
+
+	flVert[1][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[0] ;
+	flVert[1][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[1] ;
+	flVert[1][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[2] ;
+
+	flVert[2][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[0] ;
+	flVert[2][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[1] ;
+	flVert[2][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[2] ;
+
+	flVert[3][0]=(flVert[0][0]+flVert[1][0])/2.0f ;
+	flVert[3][1]=(flVert[0][1]+flVert[1][1])/2.0f ;
+	flVert[3][2]=(flVert[0][2]+flVert[1][2])/2.0f ;
+
+	flVert[4][0]=(flVert[1][0]+flVert[2][0])/2.0f ;
+	flVert[4][1]=(flVert[1][1]+flVert[2][1])/2.0f ;
+	flVert[4][2]=(flVert[1][2]+flVert[2][2])/2.0f ;
+
+	flVert[5][0]=(flVert[2][0]+flVert[0][0])/2.0f ;
+	flVert[5][1]=(flVert[2][1]+flVert[0][1])/2.0f ;
+	flVert[5][2]=(flVert[2][2]+flVert[0][2])/2.0f ;
+
+
+	// scan through the zones until:
+	// a) we find a zone that completely contains the six vertices
+	// b) we run out of zones.
+
+
+	do
+	{
+		nVert=0 ;
+		bTriangleInZone=false ;
+
+		// scan through the verts until:
+		// a) we find a vert that isn't in this zone
+		// b) we run out of verts
+
+		do
+		{
+
+			// scan through the zone's subzones until: 
+			// a) we find one that contains this vert, 
+			// b) we hit the subzoneperzone limit, 
+			// c) this zone runs out of subzones
+
+			nPos=0 ;
+			do
+			{
+				bVertInSubZone=PointInSubZone(flVert[nVert], m_nZone[nZone][nPos]) ;
+			}while( !bVertInSubZone && (++nPos<MAX_SUBZONEPERZONE) && (nPos<m_nZone[nZone][INDEX_SUBZONECOUNT])) ;
+
+			// if bVertInSubZone is false, we found a vert that isn't in this zone.
+
+		}while(bVertInSubZone && (++nVert<6)) ;
+
+		if(bVertInSubZone) bTriangleInZone=true ;
+
+	}while(!bTriangleInZone && (++nZone<m_nMaxZone)) ;
+
+
+	
+
+
+	if(!bTriangleInZone)
+		return -1 ;
+	else
+	{
+
+		// if this triangle came from a lamp entity, we note in that lamp entity that it touches this zone
+		int nLamp=m_pTriangle[nTriangle].Lamp ;
+		if(nLamp>-1) // if we have a lamp
+		{
+
+
+			int nSlot=m_pLamp[nLamp].Zone[MAX_ZONEPERLIGHT] ;
+
+			if(nSlot<MAX_ZONEPERLIGHT) // if the lamp isn't maxed out on zones
+			{
+				// check if we already have this zone recorded
+				int nCheckSlot=0 ;
+				int nFoundDuplicate=0 ;
+				for(nCheckSlot=0 ; nCheckSlot<nSlot ; nCheckSlot++)
+					if(m_pLamp[nLamp].Zone[nCheckSlot]==nZone)
+					{
+						nFoundDuplicate=1 ;
+						break ;
+					}
+
+				if(!nFoundDuplicate)
+				{
+					m_pLamp[nLamp].Zone[nSlot]=nZone ;  // write the zone into this slot
+					m_pLamp[nLamp].Zone[MAX_ZONEPERLIGHT]++ ; // note that we have one more zone
+				}
+
+			}
+		}
+
+
+		// if this triangle is a TexLamp triangle (free form deferred lighting shapes)
+		// then we remember this, in order to make assigning it to a lamp faster
+		int nTexture=m_pTriangle[nTriangle].Texture ;
+		if((nTexture==m_nBZN_LightNode0) || (nTexture==m_nBZN_LightNode1) || (nTexture==m_nBZN_LightNode2) || (nTexture==m_nBZN_LightNode3))
+			if(!AddTexLamp(nTriangle)) 
+				return ADDTEXLAMP_FAIL ; //if we failed to note the texlamp (probably out of memory), the whole level load will fail.
+
+
+		// finally, return the zone the triangle is in.
+		return nZone ;
+	}
+}
+
+
+
+// work out what zone a triangle is in, cut it up if it's in more than one.
+int Q3Map::SetupTriangleZone(int nTriangle)
+{
+
+
+	int nZone=0 ;
+
+	nZone=FindTriangleZone(nTriangle) ;
+
+	if(nZone==ADDTEXLAMP_FAIL)
+		return 0 ; 
+
+
+	if(nZone!=-1) // triangle was completely in a zone
+		m_pTriangle[nTriangle].Zone=nZone ;
+	else
+	{
+		// This triangle is in more than one zone.  (Or no subzone at all)
+		// we chop it up along the edges of every subzone it is in (regardless of whether they are a common zone or not)
+		// so that the resulting triangles will all be in just one subzone, and therefore in only one zone.
+		// this might produce a few extra triangles more than we strictly need, since some will both be in the same zone,
+		// but it is simple and the extra triangles are trivial in number.
+
+		// As we go to each new cut plane, it must be applied progressively to all newly created triangles too.
+
+		int nInitialTrianglePos=m_nTriangleMax ; // where we start adding new triangles
+
+		int nTriLoop=0 ;
+		int nTriangleToCut=0 ;
+		int nMaxTriangle=0 ;
+		int nSide=0 ;
+		int nAxis=0 ;
+		float flCutPos=0.0f ;
+		int nSubZone=0 ;
+		int nMaxSubZone=m_iNumSubZones ;
+		int nVert=0 ;
+		float flVert[6][3] ; // verts 0, 1, 2 are the original triangle corners, verts 3, 4, 5 are interpolated edge points.
+		// we need the edge points, since it's possible for all the 
+		// triangle verts to be in one L shaped zone but the triangle they form not be in that zone. 
+		// (such as if there's a vert at the corner and two ends of the "L")
+
+
+		flVert[0][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[0] ;
+		flVert[0][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[1] ;
+		flVert[0][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[2] ;
+
+		flVert[1][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[0] ;
+		flVert[1][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[1] ;
+		flVert[1][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[2] ;
+
+		flVert[2][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[0] ;
+		flVert[2][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[1] ;
+		flVert[2][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[2] ;
+
+		flVert[3][0]=(flVert[0][0]+flVert[1][0])/2.0f ;
+		flVert[3][1]=(flVert[0][1]+flVert[1][1])/2.0f ;
+		flVert[3][2]=(flVert[0][2]+flVert[1][2])/2.0f ;
+
+		flVert[4][0]=(flVert[1][0]+flVert[2][0])/2.0f ;
+		flVert[4][1]=(flVert[1][1]+flVert[2][1])/2.0f ;
+		flVert[4][2]=(flVert[1][2]+flVert[2][2])/2.0f ;
+
+		flVert[5][0]=(flVert[2][0]+flVert[0][0])/2.0f ;
+		flVert[5][1]=(flVert[2][1]+flVert[0][1])/2.0f ;
+		flVert[5][2]=(flVert[2][2]+flVert[0][2])/2.0f ;
+	
+
+
+
+		for(nSubZone=0 ; nSubZone<nMaxSubZone ; nSubZone++)
+		{
+			// are any of our original verts in this subzone?
+
+			nVert=0 ;
+			while( !PointInSubZone(flVert[nVert], nSubZone) && (++nVert<6)) ;
+
+			if(nVert<6) // one of the verts must have been in this subzone.
+			{
+				// cutup all triangles by the sides of this subzone.
+				// we'll need to cut more and more triangles as this progresses. (or at least test if they need to be cut)
+				for(nSide=0 ; nSide<6 ; nSide++)
+				{
+					switch(nSide)
+					{
+						case 0: nAxis=AXIS_X ; flCutPos=m_pSubZones[nSubZone].Min[0] ; break ;
+						case 1: nAxis=AXIS_X ; flCutPos=m_pSubZones[nSubZone].Max[0] ; break ;
+						case 2: nAxis=AXIS_Y ; flCutPos=m_pSubZones[nSubZone].Min[1] ; break ;
+						case 3: nAxis=AXIS_Y ; flCutPos=m_pSubZones[nSubZone].Max[1] ; break ;
+						case 4: nAxis=AXIS_Z ; flCutPos=m_pSubZones[nSubZone].Min[2] ; break ;
+						case 5: nAxis=AXIS_Z ; flCutPos=m_pSubZones[nSubZone].Max[2] ; break ;
+					}
+
+
+					nMaxTriangle=m_nTriangleMax-nInitialTrianglePos ;  // how may new triangles have been created since we first started cutting the original.
+
+					for(nTriLoop=-1 ; nTriLoop<nMaxTriangle ; nTriLoop++)
+					{
+						// work out if we are cutting up the original triangle or one of the newly created ones.
+						if(nTriLoop==-1)
+							nTriangleToCut=nTriangle ; // the original triangle, perhaps heavily cutup by now.
+						else
+							nTriangleToCut=nInitialTrianglePos+nTriLoop ;  // one of the newly created triangles.
+
+						if(!SplitTriangle(nTriangleToCut, nAxis, flCutPos)) return 0 ; // cut up the triangle, fail if we're out of memory or whatever.
+
+
+					}// end for nTriLoop
+
+				}// end cutting by each side of the subzone
+
+			}// end if one of the verts was in this subzone
+
+		}// end going through all subzones
+
+
+		// now that the triangle is well and truly chopped up, assign it a zone.
+		// Even though it should be entirely in a subzone by now, there's still the chance that
+		// it might not be inside any subzone at all.  If so, it will be assigned -1 zone and 
+		// exluded from the manualobjects
+		
+		m_pTriangle[nTriangle].Zone=FindTriangleZone(nTriangle) ;
+
+		// we don't have to worry about assigning zones to the newly created triangles, 
+		// they'll get theirs when the AssignTrianglesToZones loop reaches them at the end.
+
+	}// end if triangle was in more than one subzone (or no subzone at all)
+
+	return 1 ;
+}
+
+
+// cut a triangle along some axial plane, turning into 2 or 3 triangles.
+// If the plane doesn't go through the triangle then nothing will happen.
+int Q3Map::SplitTriangle(int nTriangle, int nAxis, float flCutPos)
+{
+
+	triangle_t NewTri ;
+
+	// these will stay -1 if no vert is created, else will be index of the new vert
+	int nABNum=-1 ;
+	int nBCNum=-1 ;
+	int nCANum=-1 ;
+
+	Q3BspVertex	VertA = m_pVertex[  m_pTriangle[ nTriangle ].VIndex[0]  ] ;
+	Q3BspVertex	VertB = m_pVertex[  m_pTriangle[ nTriangle ].VIndex[1]  ] ;
+	Q3BspVertex	VertC = m_pVertex[  m_pTriangle[ nTriangle ].VIndex[2]  ] ;
+	Q3BspVertex	VertexAB ;
+	Q3BspVertex	VertexBC ;
+	Q3BspVertex	VertexCA ;
+
+	float flSpan=0.0f ;
+	float flCutSpan=0.0f ;
+	float flPercent=0.0f ;
+
+	switch(nAxis)
+	{
+
+		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		case AXIS_X:
+
+			////////////////////////////////////////////////////////////////////////////////////////////////
+			// if VertA is on one side of the cut and VertB is on the other, create VertexAB on the cutline.
+			if( 
+					((VertA.position[0]<flCutPos-SUBZONE_EPSILON) && (VertB.position[0]>flCutPos+SUBZONE_EPSILON))
+					||
+					((VertA.position[0]>flCutPos+SUBZONE_EPSILON) && (VertB.position[0]<flCutPos-SUBZONE_EPSILON))
+				)
+			{
+				// work out the span and percentage
+				if(VertA.position[0]<flCutPos)
+				{
+					flSpan=VertB.position[0]-VertA.position[0] ;
+					flCutSpan=flCutPos-VertA.position[0] ;
+					flPercent=1.0f-flCutSpan/flSpan ;
+				}
+				else
+				{
+					flSpan=VertA.position[0]-VertB.position[0] ;
+					flCutSpan=flCutPos-VertB.position[0] ;
+					flPercent=flCutSpan/flSpan ;
+				}
+
+				CreateTweenVert(&VertA, &VertB, flPercent, &VertexAB) ;
+				nABNum=m_nVertexMax ;
+				if(!AddVertex(VertexAB)) 
+					return 0 ;
+			}// end if need create VertexAB
+
+			////////////////////////////////////////////////////////////////////////////////////////////////
+			// if VertB is on one side of the cut and VertC is on the other, create VertexBC on the cutline.
+			if( 
+					((VertB.position[0]<flCutPos-SUBZONE_EPSILON) && (VertC.position[0]>flCutPos+SUBZONE_EPSILON))
+					||
+					((VertB.position[0]>flCutPos+SUBZONE_EPSILON) && (VertC.position[0]<flCutPos-SUBZONE_EPSILON))
+				)
+			{
+				// work out the span and percentage
+				if(VertB.position[0]<flCutPos)
+				{
+					flSpan=VertC.position[0]-VertB.position[0] ;
+					flCutSpan=flCutPos-VertB.position[0] ;
+					flPercent=1.0f-flCutSpan/flSpan ;
+				}
+				else
+				{
+					flSpan=VertB.position[0]-VertC.position[0] ;
+					flCutSpan=flCutPos-VertC.position[0] ;
+					flPercent=flCutSpan/flSpan ;
+				}
+
+				CreateTweenVert(&VertB, &VertC, flPercent, &VertexBC) ;
+				nBCNum=m_nVertexMax ;
+				if(!AddVertex(VertexBC)) 
+					return 0 ;
+
+			}// end if need create VertexBC
+
+			////////////////////////////////////////////////////////////////////////////////////////////////
+			// if VertC is on one side of the cut and VertA is on the other, create VertexCA on the cutline.
+			if( 
+					((VertC.position[0]<flCutPos) && (VertA.position[0]>flCutPos))
+					||
+					((VertC.position[0]>flCutPos) && (VertA.position[0]<flCutPos))
+				)
+			{
+				// work out the span and percentage
+				if(VertC.position[0]<flCutPos)
+				{
+					flSpan=VertA.position[0]-VertC.position[0] ;
+					flCutSpan=flCutPos-VertC.position[0] ;
+					flPercent=1.0f-flCutSpan/flSpan ;
+				}
+				else
+				{
+					flSpan=VertC.position[0]-VertA.position[0] ;
+					flCutSpan=flCutPos-VertA.position[0] ;
+					flPercent=flCutSpan/flSpan ;
+				}
+
+				CreateTweenVert(&VertC, &VertA, flPercent, &VertexCA) ;
+				nCANum=m_nVertexMax ;
+				if(!AddVertex(VertexCA)) 
+					return 0 ;
+
+			}// end if need create VertexCA
+			break ;
+
+		
+		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		case AXIS_Y:
+
+			////////////////////////////////////////////////////////////////////////////////////////////////
+			// if VertA is on one side of the cut and VertB is on the other, create VertexAB on the cutline.
+			if( 
+					((VertA.position[1]<flCutPos-SUBZONE_EPSILON) && (VertB.position[1]>flCutPos+SUBZONE_EPSILON))
+					||
+					((VertA.position[1]>flCutPos+SUBZONE_EPSILON) && (VertB.position[1]<flCutPos-SUBZONE_EPSILON))
+				)
+			{
+				// work out the span and percentage
+				if(VertA.position[1]<flCutPos)
+				{
+					flSpan=VertB.position[1]-VertA.position[1] ;
+					flCutSpan=flCutPos-VertA.position[1] ;
+					flPercent=1.0f-flCutSpan/flSpan ;
+				}
+				else
+				{
+					flSpan=VertA.position[1]-VertB.position[1] ;
+					flCutSpan=flCutPos-VertB.position[1] ;
+					flPercent=flCutSpan/flSpan ;
+				}
+
+				CreateTweenVert(&VertA, &VertB, flPercent, &VertexAB) ;
+				nABNum=m_nVertexMax ;
+				if(!AddVertex(VertexAB)) 
+					return 0 ;
+			}// end if need create VertexAB
+
+			////////////////////////////////////////////////////////////////////////////////////////////////
+			// if VertB is on one side of the cut and VertC is on the other, create VertexBC on the cutline.
+			if( 
+					((VertB.position[1]<flCutPos-SUBZONE_EPSILON) && (VertC.position[1]>flCutPos+SUBZONE_EPSILON))
+					||
+					((VertB.position[1]>flCutPos+SUBZONE_EPSILON) && (VertC.position[1]<flCutPos-SUBZONE_EPSILON))
+				)
+			{
+				// work out the span and percentage
+				if(VertB.position[1]<flCutPos)
+				{
+					flSpan=VertC.position[1]-VertB.position[1] ;
+					flCutSpan=flCutPos-VertB.position[1] ;
+					flPercent=1.0f-flCutSpan/flSpan ;
+				}
+				else
+				{
+					flSpan=VertB.position[1]-VertC.position[1] ;
+					flCutSpan=flCutPos-VertC.position[1] ;
+					flPercent=flCutSpan/flSpan ;
+				}
+
+				CreateTweenVert(&VertB, &VertC, flPercent, &VertexBC) ;
+				nBCNum=m_nVertexMax ;
+				if(!AddVertex(VertexBC)) 
+					return 0 ;
+
+			}// end if need create VertexBC
+
+			////////////////////////////////////////////////////////////////////////////////////////////////
+			// if VertC is on one side of the cut and VertA is on the other, create VertexCA on the cutline.
+			if( 
+					((VertC.position[1]<flCutPos) && (VertA.position[1]>flCutPos))
+					||
+					((VertC.position[1]>flCutPos) && (VertA.position[1]<flCutPos))
+				)
+			{
+				// work out the span and percentage
+				if(VertC.position[1]<flCutPos)
+				{
+					flSpan=VertA.position[1]-VertC.position[1] ;
+					flCutSpan=flCutPos-VertC.position[1] ;
+					flPercent=1.0f-flCutSpan/flSpan ;
+				}
+				else
+				{
+					flSpan=VertC.position[1]-VertA.position[1] ;
+					flCutSpan=flCutPos-VertA.position[1] ;
+					flPercent=flCutSpan/flSpan ;
+				}
+
+				CreateTweenVert(&VertC, &VertA, flPercent, &VertexCA) ;
+				nCANum=m_nVertexMax ;
+				if(!AddVertex(VertexCA)) 
+					return 0 ;
+
+			}// end if need create VertexCA
+			break ;
+
+		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		case AXIS_Z:
+
+			////////////////////////////////////////////////////////////////////////////////////////////////
+			// if VertA is on one side of the cut and VertB is on the other, create VertexAB on the cutline.
+			if( 
+					((VertA.position[2]<flCutPos-SUBZONE_EPSILON) && (VertB.position[2]>flCutPos+SUBZONE_EPSILON))
+					||
+					((VertA.position[2]>flCutPos+SUBZONE_EPSILON) && (VertB.position[2]<flCutPos-SUBZONE_EPSILON))
+				)
+			{
+				// work out the span and percentage
+				if(VertA.position[2]<flCutPos)
+				{
+					flSpan=VertB.position[2]-VertA.position[2] ;
+					flCutSpan=flCutPos-VertA.position[2] ;
+					flPercent=1.0f-flCutSpan/flSpan ;
+				}
+				else
+				{
+					flSpan=VertA.position[2]-VertB.position[2] ;
+					flCutSpan=flCutPos-VertB.position[2] ;
+					flPercent=flCutSpan/flSpan ;
+				}
+
+				CreateTweenVert(&VertA, &VertB, flPercent, &VertexAB) ;
+				nABNum=m_nVertexMax ;
+				if(!AddVertex(VertexAB)) 
+					return 0 ;
+			}// end if need create VertexAB
+
+			////////////////////////////////////////////////////////////////////////////////////////////////
+			// if VertB is on one side of the cut and VertC is on the other, create VertexBC on the cutline.
+			if( 
+					((VertB.position[2]<flCutPos-SUBZONE_EPSILON) && (VertC.position[2]>flCutPos+SUBZONE_EPSILON))
+					||
+					((VertB.position[2]>flCutPos+SUBZONE_EPSILON) && (VertC.position[2]<flCutPos-SUBZONE_EPSILON))
+				)
+			{
+				// work out the span and percentage
+				if(VertB.position[2]<flCutPos)
+				{
+					flSpan=VertC.position[2]-VertB.position[2] ;
+					flCutSpan=flCutPos-VertB.position[2] ;
+					flPercent=1.0f-flCutSpan/flSpan ;
+				}
+				else
+				{
+					flSpan=VertB.position[2]-VertC.position[2] ;
+					flCutSpan=flCutPos-VertC.position[2] ;
+					flPercent=flCutSpan/flSpan ;
+				}
+
+				CreateTweenVert(&VertB, &VertC, flPercent, &VertexBC) ;
+				nBCNum=m_nVertexMax ;
+				if(!AddVertex(VertexBC)) 
+					return 0 ;
+
+			}// end if need create VertexBC
+
+			////////////////////////////////////////////////////////////////////////////////////////////////
+			// if VertC is on one side of the cut and VertA is on the other, create VertexCA on the cutline.
+			if( 
+					((VertC.position[2]<flCutPos) && (VertA.position[2]>flCutPos))
+					||
+					((VertC.position[2]>flCutPos) && (VertA.position[2]<flCutPos))
+				)
+			{
+				// work out the span and percentage
+				if(VertC.position[2]<flCutPos)
+				{
+					flSpan=VertA.position[2]-VertC.position[2] ;
+					flCutSpan=flCutPos-VertC.position[2] ;
+					flPercent=1.0f-flCutSpan/flSpan ;
+				}
+				else
+				{
+					flSpan=VertC.position[2]-VertA.position[2] ;
+					flCutSpan=flCutPos-VertA.position[2] ;
+					flPercent=flCutSpan/flSpan ;
+				}
+
+				CreateTweenVert(&VertC, &VertA, flPercent, &VertexCA) ;
+				nCANum=m_nVertexMax ;
+				if(!AddVertex(VertexCA)) 
+					return 0 ;
+
+			}// end if need create VertexCA
+			break ;
+
+
+	}
+
+//	int nInitialTrianglePos=m_nTriangleMax ; // debugging
+
+	// default parameters for all new triangles
+	NewTri.Texture	=	m_pTriangle[ nTriangle ].Texture ;
+	//NewTri.Lightmap	=	m_pTriangle[ nTriangle ].Lightmap ; // bzn doesn't use lightmaps
+	NewTri.Lamp			= m_pTriangle[ nTriangle ].Lamp ; 
+	NewTri.Group = m_pTriangle[ nTriangle ].Group ;
+
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	// now we create new triangles depending on the verts we created.
+	if((nABNum!=-1) && (nCANum!=-1))
+	{
+		// add (AB, B, C)
+		NewTri.VIndex[0]=nABNum ;
+		NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[1] ;
+		NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[2] ;
+		if(!AddTriangle(NewTri)) return 0 ;
+
+		// add (C, CA, AB)
+		NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[2] ;
+		NewTri.VIndex[1]=nCANum ;
+		NewTri.VIndex[2]=nABNum ;
+		if(!AddTriangle(NewTri)) return 0 ;
+
+		// overwrite the original triangle with (A, AB, CA)
+		NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[0] ;
+		NewTri.VIndex[1]=nABNum ;
+		NewTri.VIndex[2]=nCANum ;
+		m_pTriangle[ nTriangle ]=NewTri ;
+	}
+	else
+	if((nABNum!=-1) && (nBCNum!=-1))
+	{
+		// add (BC, C, A)
+		NewTri.VIndex[0]=nBCNum ;
+		NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[2] ;
+		NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[0] ;
+		if(!AddTriangle(NewTri)) return 0 ;
+
+		// add (A, AB, BC)
+		NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[0] ;
+		NewTri.VIndex[1]=nABNum ;
+		NewTri.VIndex[2]=nBCNum ;
+		if(!AddTriangle(NewTri)) return 0 ;
+
+		// overwrite the original triangle with (B, BC, AB)
+		NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[1] ;
+		NewTri.VIndex[1]=nBCNum ;
+		NewTri.VIndex[2]=nABNum ;
+		m_pTriangle[ nTriangle ]=NewTri ;
+	}
+	else
+	if((nBCNum!=-1) && (nCANum!=-1))
+	{
+		// add (CA, A, B)
+		NewTri.VIndex[0]=nCANum ;
+		NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[0] ;
+		NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[1] ;
+		if(!AddTriangle(NewTri)) return 0 ;
+
+		// add (B, BC, CA)
+		NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[1] ;
+		NewTri.VIndex[1]=nBCNum ;
+		NewTri.VIndex[2]=nCANum ;
+		if(!AddTriangle(NewTri)) return 0 ;
+
+		// overwrite the original triangle with (C, CA, BC)
+		NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[2] ;
+		NewTri.VIndex[1]=nCANum ;
+		NewTri.VIndex[2]=nBCNum ;
+		m_pTriangle[ nTriangle ]=NewTri ;
+	}
+	else
+	if(nABNum!=-1)
+	{
+		// add (AB, B, C)
+		NewTri.VIndex[0]=nABNum ;
+		NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[1] ;
+		NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[2] ;
+		if(!AddTriangle(NewTri)) return 0 ;
+
+		// overwrite the original triangle with (A, AB, C)
+		NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[0] ;
+		NewTri.VIndex[1]=nABNum ;
+		NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[2] ;
+		m_pTriangle[ nTriangle ]=NewTri ;
+	}
+	else
+	if(nBCNum!=-1)
+	{
+		// add (BC, C, A)
+		NewTri.VIndex[0]=nBCNum ;
+		NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[2] ;
+		NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[0] ;
+		if(!AddTriangle(NewTri)) return 0 ;
+
+		// overwrite the original triangle with (B, BC, A)
+		NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[1] ;
+		NewTri.VIndex[1]=nBCNum ;
+		NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[0] ;
+		m_pTriangle[ nTriangle ]=NewTri ;
+	}
+	else
+	if(nCANum!=-1)
+	{
+		// add (CA, A, B)
+		NewTri.VIndex[0]=nCANum ;
+		NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[0] ;
+		NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[1] ;
+		if(!AddTriangle(NewTri)) return 0 ;
+
+		// overwrite the original triangle with (C, CA, B)
+		NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[2] ;
+		NewTri.VIndex[1]=nCANum ;
+		NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[1] ;
+		m_pTriangle[ nTriangle ]=NewTri ;
+	}
+
+	return 1 ;
+}
+
+void Q3Map::CreateTweenVert(Q3BspVertex* pVertA, Q3BspVertex* pVertB, float flPercent0, Q3BspVertex* pVertexAB)
+{
+	float flPercent1=1.0f-flPercent0 ;
+
+	pVertexAB->color[0]=(unsigned char)(flPercent0*pVertA->color[0] + flPercent1*pVertB->color[0]) ;
+	pVertexAB->color[1]=(unsigned char)(flPercent0*pVertA->color[1] + flPercent1*pVertB->color[1]) ;
+	pVertexAB->color[2]=(unsigned char)(flPercent0*pVertA->color[2] + flPercent1*pVertB->color[2]) ;
+	pVertexAB->color[3]=(unsigned char)(flPercent0*pVertA->color[3] + flPercent1*pVertB->color[3]) ;
+
+	pVertexAB->position[0]=flPercent0*pVertA->position[0] + flPercent1*pVertB->position[0] ;
+	pVertexAB->position[1]=flPercent0*pVertA->position[1] + flPercent1*pVertB->position[1] ;
+	pVertexAB->position[2]=flPercent0*pVertA->position[2] + flPercent1*pVertB->position[2] ;
+				
+	pVertexAB->texcoord[0][0]=flPercent0*pVertA->texcoord[0][0] + flPercent1*pVertB->texcoord[0][0] ;
+	pVertexAB->texcoord[0][1]=flPercent0*pVertA->texcoord[0][1] + flPercent1*pVertB->texcoord[0][1] ;
+	pVertexAB->texcoord[1][0]=flPercent0*pVertA->texcoord[1][0] + flPercent1*pVertB->texcoord[1][0] ;
+	pVertexAB->texcoord[1][1]=flPercent0*pVertA->texcoord[1][1] + flPercent1*pVertB->texcoord[1][1] ;
+
+	pVertexAB->normal[0]=flPercent0*pVertA->normal[0] + flPercent1*pVertB->normal[0] ;
+	pVertexAB->normal[1]=flPercent0*pVertA->normal[1] + flPercent1*pVertB->normal[1] ;
+	pVertexAB->normal[2]=flPercent0*pVertA->normal[2] + flPercent1*pVertB->normal[2] ;
+	// normalize
+	float flLen=sqrt(pVertexAB->normal[0]*pVertexAB->normal[0] + pVertexAB->normal[1]*pVertexAB->normal[1] + pVertexAB->normal[2]*pVertexAB->normal[2]) ;
+	if(flLen!=0.0f) // don't divide by zero... but normal is messed up.
+	{
+		pVertexAB->normal[0]/=flLen ;
+		pVertexAB->normal[1]/=flLen ;
+		pVertexAB->normal[2]/=flLen ;
+	}
+	else
+	{
+		// default a messed up normal to point upward
+		pVertexAB->normal[0]=0.0f ;
+		pVertexAB->normal[1]=1.0f ;
+		pVertexAB->normal[2]=0.0f ;
+	}
+}
+
+// returns the next subzone a point is in after the start subzone, or -1 if there are no more subzones
+int Q3Map::GetNextSubZone(float *flPoint, int nStart, int nMax)
+{
+	while(++nStart<nMax)
+		if(PointInSubZone(flPoint, nStart))
+			break ;
+
+	if(nStart==nMax)
+		return -1 ;
+	else
+		return nStart ;
+}
+
+// returns true if a point is in a subzone.
+bool Q3Map::PointInSubZone(float *flPoint, int nSubZone)
+{
+	if(
+				(flPoint[0]>=m_pSubZones[nSubZone].Min[0]-SUBZONE_EPSILON) && (flPoint[0]<=m_pSubZones[nSubZone].Max[0]+SUBZONE_EPSILON)
+			&&(flPoint[1]>=m_pSubZones[nSubZone].Min[1]-SUBZONE_EPSILON) && (flPoint[1]<=m_pSubZones[nSubZone].Max[1]+SUBZONE_EPSILON)
+			&&(flPoint[2]>=m_pSubZones[nSubZone].Min[2]-SUBZONE_EPSILON) && (flPoint[2]<=m_pSubZones[nSubZone].Max[2]+SUBZONE_EPSILON)
+		)
+		return true ;
+
+	return false ;
+}
+
+// returns true if a point is in a zone.
+bool Q3Map::PointInZone(float *flPos, int nZone)
+{
+	int nMaxSubZone=m_nZone[nZone][INDEX_SUBZONECOUNT] ;
+
+	for(int nSubZoneIndex=0 ; nSubZoneIndex<nMaxSubZone ; nSubZoneIndex++)
+		if(PointInSubZone(flPos, m_nZone[nZone][nSubZoneIndex]))
+			return true ;
+		
+	return false ;
+}
+
+// returns true if an axis aligned bounding box touches a subzone.
+bool Q3Map::AABBTouchesSubZone(float *flPointMin, float *flPointMax, int nSubZone)
+{
+	// if test AABB overlaps the subzone AABB
+	if(
+				 (m_pSubZones[nSubZone].Min[0]<flPointMax[0]) && (m_pSubZones[nSubZone].Max[0]>flPointMin[0])
+			&& (m_pSubZones[nSubZone].Min[1]<flPointMax[1]) && (m_pSubZones[nSubZone].Max[1]>flPointMin[1])
+			&& (m_pSubZones[nSubZone].Min[2]<flPointMax[2]) && (m_pSubZones[nSubZone].Max[2]>flPointMin[2])
+		)
+		return true ;
+
+	return false ;
+}
+
+// returns true if an axis aligned bounding box touches a zone.
+bool Q3Map::AABBTouchesZone(float *flPosMin, float *flPosMax, int nZone)
+{
+	int nMaxSubZone=m_nZone[nZone][INDEX_SUBZONECOUNT] ;
+
+	for(int nSubZoneIndex=0 ; nSubZoneIndex<nMaxSubZone ; nSubZoneIndex++)
+		if(AABBTouchesSubZone(flPosMin, flPosMax, m_nZone[nZone][nSubZoneIndex]))
+			return true ;
+		
+	return false ;
+}
+
+// take the faces from the BSP and add them to our list of triangles.
+int Q3Map::ConvertFacesToTriangles(void)
+{
+	int nFaceIndex = 0 ;
+	
+//	int nVertex=0 ;
+//	int nVertexMax=0 ;
+	int nTriangle=0 ;
+	int nTriangleMax=0 ;
+
+//	float flPosX=0.0f ;
+//	float flPosY=0.0f ;
+//	float flPosZ=0.0f ;
+//	float	flNormX=0.0f ;
+//	float	flNormY=0.0f ;
+//	float	flNormZ=0.0f ;
+//	float flTexU=0.0f ;
+//	float flTexV=0.0f ;
+	int nMeshVert=0 ;
+//	int nMeshVertA=0 ;
+//	int nMeshVertB=0 ;
+//	int nMeshVertC=0 ;
+
+//	Q3BspVertex *vertices = m_pVertices ;
+	int *meshverts = m_pMeshVerts ;
+	
+	QVECTOR junk ;
+	junk[0]=0.0f ;
+	junk[1]=0.0f ;
+	junk[2]=0.0f ;
+
+
+	nFaceIndex = 0 ;	
+	while(nFaceIndex<m_iNumFaces)
+	{
+
+		switch (m_BspFaces[nFaceIndex].type)
+		{
+			case MESH:    
+			case POLYGON:	
+
+				nTriangleMax=m_BspFaces[nFaceIndex].n_triangles ;
+				nMeshVert=m_BspFaces[nFaceIndex].meshvert ;
+				
+				for(nTriangle=0 ; nTriangle<nTriangleMax ; nTriangle++)
+				{
+
+					// if we are out of memory, grow it.  If we can't grow it, fail
+					if(m_nTriangleMax>=m_nTriangleLimit)
+						if(!ExpandTriangleMemory())
+							return 0 ;
+
+					
+
+					m_pTriangle[ m_nTriangleMax ].Texture=		m_BspFaces[nFaceIndex].texture ;
+					//m_pTriangle[ m_nTriangleMax ].Lightmap=		m_BspFaces[nFaceIndex].lm_index ; // bzn doesn't use lightmaps
+					m_pTriangle[ m_nTriangleMax ].VIndex[0]=	meshverts[ nMeshVert++ ]+m_BspFaces[nFaceIndex].vertex ;
+					m_pTriangle[ m_nTriangleMax ].VIndex[1]=	meshverts[ nMeshVert++ ]+m_BspFaces[nFaceIndex].vertex ;
+					m_pTriangle[ m_nTriangleMax ].VIndex[2]=	meshverts[ nMeshVert++ ]+m_BspFaces[nFaceIndex].vertex ;
+
+					m_pTriangle[ m_nTriangleMax ].Lamp=-1 ; // assume it didn't come from a lamp, this will be updated later
+					
+					m_pTriangle[ m_nTriangleMax ].Group=m_nGroup ; // increment group number.  
+
+					m_nTriangleMax++ ;
+				}// end for nTriangle
+				m_nGroup++ ; // increment group.  Every face is a new group.
+				
+			break ;
+
+		}// end switch
+		
+		nFaceIndex++;
+	} // end while	
+
+	return 1 ;
+
+}
+
+
+// convert the patch info from the BSP into bezier curved triangle meshes and add to our triangle list.
+int Q3Map::ConvertPatchesToTriangles(void)
+{
+
+//	float flPosX=0.0f ;
+//	float flPosY=0.0f ;
+//	float flPosZ=0.0f ;
+//	float	flNormX=0.0f ;
+//	float	flNormY=0.0f ;
+//	float	flNormZ=0.0f ;
+//	float flTexU=0.0f ;
+//	float flTexV=0.0f ;
+//	int nMeshVert=0 ;
+	int nMeshVertA=0 ;
+	int nMeshVertB=0 ;
+	int nMeshVertC=0 ;
+
+
+	int nTriPerRow=0 ;
+	int nRow=0 ;
+
+	int nFirstVertex=m_nVertexMax ;
+	
+	int nVertCount=nFirstVertex ;
+//	int nPatchCount=0 ;
+
+	int* pIndexBuffer=NULL ;
+
+	Q3BspVertex NewVert ;
+		
+
+
+
+	int nCount=0 ;
+	int nCountB=0 ;
+
+
+
+		
+    int indexBufferindex = 0;
+	
+    int vertexBufferindex = 0;
+
+    for (int faceIndex=0; faceIndex < m_iNumFaces; faceIndex++)
+    {		
+
+			nCount++ ;
+			if(nCount==1)
+			{
+				nCountB+=nCount ;
+				nCount=0 ;
+			}
+
+
+      if (m_BspFaces[faceIndex].type == PATCH)
+      {
+        Q3BspPatch *patch = m_BspFaces[faceIndex].patch;
+
+        if (patch != NULL)
+        {
+					
+          for (int bezierIndex=0; bezierIndex < patch->size; bezierIndex++)
+          {
+						indexBufferindex = 0;
+						pIndexBuffer = new int[patch->bezier[bezierIndex].mNumIndex] ;
+						if(pIndexBuffer==NULL) return 0 ; // ran out of memory
+
+
+            for (int index=0; index < patch->bezier[bezierIndex].mNumIndex; index++)
+            {	
+              pIndexBuffer[indexBufferindex] = patch->bezier[bezierIndex].mIndex[index];
+              indexBufferindex++;
+            }
+
+            for (int vertex=0; vertex < patch->bezier[bezierIndex].mNumVertex; vertex++)
+            {
+
+              BspVertex *bspVertex = &patch->bezier[bezierIndex].mVertex[vertex];
+
+							NewVert.position[0]=bspVertex->mPosition[0] ;
+							NewVert.position[1]=bspVertex->mPosition[1] ;
+							NewVert.position[2]=bspVertex->mPosition[2] ;
+							NewVert.normal[0]=bspVertex->mNormal[0] ;
+							NewVert.normal[1]=bspVertex->mNormal[1] ;
+							NewVert.normal[2]=bspVertex->mNormal[2] ;
+							NewVert.texcoord[0][0]=bspVertex->mTexcoord[0][0] ;
+							NewVert.texcoord[0][1]=bspVertex->mTexcoord[0][1] ;
+
+							
+
+							// if we are out of memory, grow it.  If we can't grow it, fail
+							if(m_nVertexMax>=m_nVertexLimit)
+								if(!ExpandVertexMemory())
+								{
+									if(pIndexBuffer) DELETE_ARRAY( pIndexBuffer ) ;
+									return 0 ;
+								}
+
+
+							if(!AddVertex(NewVert)) 
+							{
+								if(pIndexBuffer) DELETE_ARRAY( pIndexBuffer ) ;
+								return 0 ;
+							}
+
+							nVertCount++ ;
+              vertexBufferindex++;
+
+            }// end for vertex
+
+
+						for (int j=0; j < 5; j++)
+						{
+							nRow=m_BspFaces[faceIndex].patch->bezier[bezierIndex].mRowIndex[j] ;
+							nTriPerRow=m_BspFaces[faceIndex].patch->bezier[bezierIndex].mTrianglesPerRow[j] ;
+
+							nMeshVertA=pIndexBuffer[nRow+0]+nFirstVertex ;
+							nMeshVertB=pIndexBuffer[nRow+1]+nFirstVertex ;
+							
+							for(int nVert=2 ; nVert<nTriPerRow ; nVert++)
+							{
+								// if we are out of memory, grow it.  If we can't grow it, fail
+								if(m_nTriangleMax>=m_nTriangleLimit)
+									if(!ExpandTriangleMemory())
+									{
+										if(pIndexBuffer) DELETE_ARRAY( pIndexBuffer ) ;
+										return 0 ;
+									}
+
+								m_pTriangle[ m_nTriangleMax ].Texture=		m_BspFaces[faceIndex].texture ;
+								//m_pTriangle[ m_nTriangleMax ].Lightmap=		m_BspFaces[faceIndex].lm_index ; // bzn doesn't use lightmaps
+
+								
+								
+								nMeshVertC=pIndexBuffer[nRow+nVert]+nFirstVertex ;
+
+
+								if(nVert&1)
+								{
+									m_pTriangle[ m_nTriangleMax ].VIndex[0]=	nMeshVertB ;
+									m_pTriangle[ m_nTriangleMax ].VIndex[1]=	nMeshVertA ;
+									m_pTriangle[ m_nTriangleMax ].VIndex[2]=	nMeshVertC ;
+								}
+								else
+								{
+									m_pTriangle[ m_nTriangleMax ].VIndex[0]=	nMeshVertA ;
+									m_pTriangle[ m_nTriangleMax ].VIndex[1]=	nMeshVertB ;
+									m_pTriangle[ m_nTriangleMax ].VIndex[2]=	nMeshVertC ;
+								}
+
+								m_pTriangle[ m_nTriangleMax ].Lamp=-1 ; // assume it didn't come from a lamp, this will be updated later
+
+
+								m_pTriangle[ m_nTriangleMax ].Group=m_nGroup ;
+
+
+								m_nTriangleMax++ ;
+
+								nMeshVertA=nMeshVertB ;
+								nMeshVertB=nMeshVertC ;
+							}
+				
+
+						}
+						
+
+						// finished with the index buffer
+						if(pIndexBuffer) 
+							DELETE_ARRAY( pIndexBuffer ) ; 
+
+						nFirstVertex=nVertCount ;
+          }// end for bezier index
+
+
+					m_nGroup++ ; // increment the group number.  Each patch is treated as a single group.
+
+        }// end if patch not null
+      }// end if patch
+    }// end for faceIndex
+
+	return 1 ;
+
+}
+
+//''
+// some triangles might be designed to be deferred shading shapes inside of Lamp entities.
+// If so, change their material to the deferred shading configuration for that lamp entity.
+int Q3Map::ConvertTexLampsToLampTriangles(void)
+{
+
+	float flCentreX=0.0f ;
+	float flCentreY=0.0f ;
+	float flCentreZ=0.0f ;
+
+//	float flMinX=0.0f ;
+//	float flMinY=0.0f ;
+//	float flMinZ=0.0f ;
+//	float flMaxX=0.0f ;
+//	float flMaxY=0.0f ;
+//	float flMaxZ=0.0f ;
+
+//	float	flNormX=0.0f ;
+//	float	flNormY=0.0f ;
+//	float	flNormZ=0.0f ;
+//	float flTexU=0.0f ;
+//	float flTexV=0.0f ;
+
+	float flColR=0.0f ;
+	float flColG=0.0f ;
+	float flColB=0.0f ;
+
+	float flBrightness=0.0f ;
+
+	int nLamp=0 ;
+	int nTriangle=0 ;
+	int nTexLampListPos=0 ;
+	int nLightNode=0 ;
+	int nTexture=0 ;
+	int nZone=0 ;
+//	int nLampZone=0 ;
+//	int nMaxLampZone=0 ;
+//	int nZoneMatch=0 ;
+
+
+	for(nTexLampListPos=0 ; nTexLampListPos<m_nTexLampMax ; nTexLampListPos++)
+	{
+		nTriangle=m_pTexLamp[nTexLampListPos] ;
+
+		nZone=m_pTriangle[nTriangle].Zone ;
+
+		nTexture=m_pTriangle[nTriangle].Texture ;
+
+		if(nTexture==m_nBZN_LightNode0)
+			nLightNode=0 ;
+		else
+		if(nTexture==m_nBZN_LightNode1)
+			nLightNode=1 ;
+		else
+		if(nTexture==m_nBZN_LightNode2)
+			nLightNode=2 ;
+		else
+		if(nTexture==m_nBZN_LightNode3)
+			nLightNode=3 ;
+		else
+			return 0 ; // didn't match any lightnode, something went wrong.
+
+
+		// scan through all the lamps, finding the ones that touch the same zone as this triangle and that have the same lightnode number
+		for(nLamp=0 ; nLamp<m_nLampMax ; nLamp++)
+		{
+			// skip if the lightnode doesn't match
+			if(m_pLamp[nLamp].LightNode!=nLightNode)
+				continue ;
+
+
+			/*
+			// lightnode matches, check if lamp touches the same zone (lamps can touch multiple zones so we have to check them all)
+			nZoneMatch=0 ;
+			nMaxLampZone=m_pLamp[nLamp].Zone[MAX_ZONEPERLIGHT] ;
+			for(nLampZone=0 ; nLampZone<nMaxLampZone ; nLampZone++)
+			{
+				if(m_pLamp[nLamp].Zone[nLampZone]==nZone)
+				{
+					nZoneMatch=1 ;
+					break ;
+				}
+			}
+			
+			
+			// if the zone didn't match, continue
+			if(!nZoneMatch) continue ;
+
+			*/
+
+
+
+			// check if all three vertices of this triangle fall within the bounds of this lamp
+			if(
+						// first vert
+						(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[0]>=m_pLamp[nLamp].Min[0])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[0]<=m_pLamp[nLamp].Max[0])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[1]>=m_pLamp[nLamp].Min[1])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[1]<=m_pLamp[nLamp].Max[1])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[2]>=m_pLamp[nLamp].Min[2])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[2]<=m_pLamp[nLamp].Max[2])	
+					&&
+						// second vert
+						(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[0]>=m_pLamp[nLamp].Min[0])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[0]<=m_pLamp[nLamp].Max[0])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[1]>=m_pLamp[nLamp].Min[1])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[1]<=m_pLamp[nLamp].Max[1])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[2]>=m_pLamp[nLamp].Min[2])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[2]<=m_pLamp[nLamp].Max[2])	
+					&&
+						// third vert
+						(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[0]>=m_pLamp[nLamp].Min[0])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[0]<=m_pLamp[nLamp].Max[0])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[1]>=m_pLamp[nLamp].Min[1])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[1]<=m_pLamp[nLamp].Max[1])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[2]>=m_pLamp[nLamp].Min[2])
+					&&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[2]<=m_pLamp[nLamp].Max[2])	
+	
+					)
+			{
+
+
+				m_pTriangle[nTriangle].Texture=m_pLamp[nLamp].Texture ;
+				m_pTriangle[nTriangle].Lamp=nLamp ;
+
+				flCentreX =		m_pLamp[nLamp].Position[0] ;
+				flCentreY =		m_pLamp[nLamp].Position[1] ;
+				flCentreZ =		m_pLamp[nLamp].Position[2] ;
+				flColR =			m_pLamp[nLamp].Colour[0]*255.0f ;
+				flColG =			m_pLamp[nLamp].Colour[1]*255.0f ;
+				flColB =			m_pLamp[nLamp].Colour[2]*255.0f ;
+				flBrightness=	m_pLamp[nLamp].Brightness ; 
+
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].texcoord[0][0]=flCentreX ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].texcoord[0][1]=flCentreY ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].texcoord[1][0]=flCentreZ ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].texcoord[1][1]=flBrightness ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].color[0]=(unsigned char)flColR ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].color[1]=(unsigned char)flColG ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].color[2]=(unsigned char)flColB ;
+
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].texcoord[0][0]=flCentreX ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].texcoord[0][1]=flCentreY ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].texcoord[1][0]=flCentreZ ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].texcoord[1][1]=flBrightness ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].color[0]=(unsigned char)flColR ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].color[1]=(unsigned char)flColG ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].color[2]=(unsigned char)flColB ;
+
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].texcoord[0][0]=flCentreX ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].texcoord[0][1]=flCentreY ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].texcoord[1][0]=flCentreZ ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].texcoord[1][1]=flBrightness ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].color[0]=(unsigned char)flColR ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].color[1]=(unsigned char)flColG ;
+				m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].color[2]=(unsigned char)flColB ;
+
+				
+				m_pTriangle[ m_nTriangleMax ].Group=m_nGroup ;
+
+
+			}// end triangle is in bounds of lamp
+
+
+			m_nGroup++ ; // increment group number.  Every texture lamp is a group.
+
+
+		}// end for nLamp
+
+
+	}
+
+
+
+	return 1 ;
+}
+
+
+// convert lamps into boxes.  Lamps are deferred shading non-shadowing lights, and are rendered as triangles
+// The texture coords are actually the light centre point, the spot the shaders calculate as the source of the lighting, 
+// and also the brightness
+// The triangles created will remember the lamp they came from, via Triangle.Lamp
+
+int Q3Map::ConvertLampsToTriangles(void)
+{
+	float flCentreX=0.0f ;
+	float flCentreY=0.0f ;
+	float flCentreZ=0.0f ;
+
+	float flMinX=0.0f ;
+	float flMinY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxX=0.0f ;
+	float flMaxY=0.0f ;
+	float flMaxZ=0.0f ;
+
+//	float	flNormX=0.0f ;
+//	float	flNormY=0.0f ;
+//	float	flNormZ=0.0f ;
+//	float flTexU=0.0f ;
+//	float flTexV=0.0f ;
+
+	float flColR=0.0f ;
+	float flColG=0.0f ;
+	float flColB=0.0f ;
+
+	float flBrightness=0.0f ;
+
+	int nLamp=0 ;
+
+	// lower case = min, upper case = max
+	Q3BspVertex Vert_xyz ;
+	Q3BspVertex Vert_Xyz ;
+	Q3BspVertex Vert_xYz ;
+	Q3BspVertex Vert_XYz ;
+	Q3BspVertex Vert_xyZ ;
+	Q3BspVertex Vert_XyZ ;
+	Q3BspVertex Vert_xYZ ;
+	Q3BspVertex Vert_XYZ ;
+
+	int n_xyz=0 ;
+	int n_Xyz=0 ;
+	int n_xYz=0 ;
+	int n_XYz=0 ;
+	int n_xyZ=0 ;
+	int n_XyZ=0 ;
+	int n_xYZ=0 ;
+	int n_XYZ=0 ;
+
+	int nFirstVertex=0 ;
+
+	triangle_t Triangle ;
+	ZeroMemory((void*)&Triangle, sizeof(triangle_t)) ;
+	
+	for(nLamp=0 ; nLamp<m_nLampMax ; nLamp++)
+	{
+		if(m_pLamp[nLamp].LightNode>-1) continue ; // lamps that are lightnodes don't add their own triangles.  They just exist as information for TexLamps.
+
+
+		flCentreX =		m_pLamp[nLamp].Position[0] ;
+		flCentreY =		m_pLamp[nLamp].Position[1] ;
+		flCentreZ =		m_pLamp[nLamp].Position[2] ;
+
+		flMinX =			m_pLamp[nLamp].Min[0] ;
+		flMinY =			m_pLamp[nLamp].Min[1] ;
+		flMinZ =			m_pLamp[nLamp].Min[2] ;
+
+		flMaxX =			m_pLamp[nLamp].Max[0] ;
+		flMaxY =			m_pLamp[nLamp].Max[1] ;
+		flMaxZ =			m_pLamp[nLamp].Max[2] ;
+
+		flColR =			m_pLamp[nLamp].Colour[0]*255.0f ;
+		flColG =			m_pLamp[nLamp].Colour[1]*255.0f ;
+		flColB =			m_pLamp[nLamp].Colour[2]*255.0f ;
+		
+		flBrightness=	m_pLamp[nLamp].Brightness ; 
+		
+		//////////////////////////////////////
+		// setup our 8 vertices.  Normal isn't that important, I just approximate regardless of actual box shape
+
+
+		nFirstVertex=m_nVertexMax ; // we need to remember which vertex is which for defining the triangles
+
+		// vertex numbers
+		n_xyz=nFirstVertex+0 ;
+		n_Xyz=nFirstVertex+1 ;
+		n_xYz=nFirstVertex+2 ;
+		n_XYz=nFirstVertex+3 ;
+		n_xyZ=nFirstVertex+4 ;
+		n_XyZ=nFirstVertex+5 ;
+		n_xYZ=nFirstVertex+6 ;
+		n_XYZ=nFirstVertex+7 ;
+
+
+		Vert_xyz.position[0]=flMinX ;
+		Vert_xyz.position[1]=flMinY ;
+		Vert_xyz.position[2]=flMinZ ;
+		Vert_xyz.normal[0]=-0.5773502691896 ;
+		Vert_xyz.normal[1]=-0.5773502691896 ;
+		Vert_xyz.normal[2]=-0.5773502691896 ;
+		Vert_xyz.texcoord[0][0]=flCentreX ;
+		Vert_xyz.texcoord[0][1]=flCentreY ;
+		Vert_xyz.texcoord[1][0]=flCentreZ ;
+		Vert_xyz.texcoord[1][1]=flBrightness ;
+		Vert_xyz.color[0]=(unsigned char)flColR ;
+		Vert_xyz.color[1]=(unsigned char)flColG ;
+		Vert_xyz.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_xyz)) return 0 ;
+			
+
+		Vert_Xyz.position[0]=flMaxX ;
+		Vert_Xyz.position[1]=flMinY ;
+		Vert_Xyz.position[2]=flMinZ ;
+		Vert_Xyz.normal[0]= 0.5773502691896 ;
+		Vert_Xyz.normal[1]=-0.5773502691896 ;
+		Vert_Xyz.normal[2]=-0.5773502691896 ;
+		Vert_Xyz.texcoord[0][0]=flCentreX ;
+		Vert_Xyz.texcoord[0][1]=flCentreY ;
+		Vert_Xyz.texcoord[1][0]=flCentreZ ;
+		Vert_Xyz.texcoord[1][1]=flBrightness ;
+		Vert_Xyz.color[0]=(unsigned char)flColR ;
+		Vert_Xyz.color[1]=(unsigned char)flColG ;
+		Vert_Xyz.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_Xyz)) return 0 ;
+
+		Vert_xYz.position[0]=flMinX ;
+		Vert_xYz.position[1]=flMaxY ;
+		Vert_xYz.position[2]=flMinZ ;
+		Vert_xYz.normal[0]=-0.5773502691896 ;
+		Vert_xYz.normal[1]= 0.5773502691896 ;
+		Vert_xYz.normal[2]=-0.5773502691896 ;
+		Vert_xYz.texcoord[0][0]=flCentreX ;
+		Vert_xYz.texcoord[0][1]=flCentreY ;
+		Vert_xYz.texcoord[1][0]=flCentreZ ;
+		Vert_xYz.texcoord[1][1]=flBrightness ;
+		Vert_xYz.color[0]=(unsigned char)flColR ;
+		Vert_xYz.color[1]=(unsigned char)flColG ;
+		Vert_xYz.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_xYz)) return 0 ;
+
+		Vert_XYz.position[0]=flMaxX ;
+		Vert_XYz.position[1]=flMaxY ;
+		Vert_XYz.position[2]=flMinZ ;
+		Vert_XYz.normal[0]= 0.5773502691896 ;
+		Vert_XYz.normal[1]= 0.5773502691896 ;
+		Vert_XYz.normal[2]=-0.5773502691896 ;
+		Vert_XYz.texcoord[0][0]=flCentreX ;
+		Vert_XYz.texcoord[0][1]=flCentreY ;
+		Vert_XYz.texcoord[1][0]=flCentreZ ;
+		Vert_XYz.texcoord[1][1]=flBrightness ;
+		Vert_XYz.color[0]=(unsigned char)flColR ;
+		Vert_XYz.color[1]=(unsigned char)flColG ;
+		Vert_XYz.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_XYz)) return 0 ;
+
+		//////////////////////////////////////
+
+		Vert_xyZ.position[0]=flMinX ;
+		Vert_xyZ.position[1]=flMinY ;
+		Vert_xyZ.position[2]=flMaxZ ;
+		Vert_xyZ.normal[0]=-0.5773502691896 ;
+		Vert_xyZ.normal[1]=-0.5773502691896 ;
+		Vert_xyZ.normal[2]= 0.5773502691896 ;
+		Vert_xyZ.texcoord[0][0]=flCentreX ;
+		Vert_xyZ.texcoord[0][1]=flCentreY ;
+		Vert_xyZ.texcoord[1][0]=flCentreZ ;
+		Vert_xyZ.texcoord[1][1]=flBrightness ;
+		Vert_xyZ.color[0]=(unsigned char)flColR ;
+		Vert_xyZ.color[1]=(unsigned char)flColG ;
+		Vert_xyZ.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_xyZ)) return 0 ;
+
+		Vert_XyZ.position[0]=flMaxX ;
+		Vert_XyZ.position[1]=flMinY ;
+		Vert_XyZ.position[2]=flMaxZ ;
+		Vert_XyZ.normal[0]= 0.5773502691896 ;
+		Vert_XyZ.normal[1]=-0.5773502691896 ;
+		Vert_XyZ.normal[2]= 0.5773502691896 ;
+		Vert_XyZ.texcoord[0][0]=flCentreX ;
+		Vert_XyZ.texcoord[0][1]=flCentreY ;
+		Vert_XyZ.texcoord[1][0]=flCentreZ ;
+		Vert_XyZ.texcoord[1][1]=flBrightness ;
+		Vert_XyZ.color[0]=(unsigned char)flColR ;
+		Vert_XyZ.color[1]=(unsigned char)flColG ;
+		Vert_XyZ.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_XyZ)) return 0 ;
+
+		Vert_xYZ.position[0]=flMinX ;
+		Vert_xYZ.position[1]=flMaxY ;
+		Vert_xYZ.position[2]=flMaxZ ;
+		Vert_xYZ.normal[0]=-0.5773502691896 ;
+		Vert_xYZ.normal[1]= 0.5773502691896 ;
+		Vert_xYZ.normal[2]= 0.5773502691896 ;
+		Vert_xYZ.texcoord[0][0]=flCentreX ;
+		Vert_xYZ.texcoord[0][1]=flCentreY ;
+		Vert_xYZ.texcoord[1][0]=flCentreZ ;
+		Vert_xYZ.texcoord[1][1]=flBrightness ;
+		Vert_xYZ.color[0]=(unsigned char)flColR ;
+		Vert_xYZ.color[1]=(unsigned char)flColG ;
+		Vert_xYZ.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_xYZ)) return 0 ;
+
+		Vert_XYZ.position[0]=flMaxX ;
+		Vert_XYZ.position[1]=flMaxY ;
+		Vert_XYZ.position[2]=flMaxZ ;
+		Vert_XYZ.normal[0]= 0.5773502691896 ;
+		Vert_XYZ.normal[1]= 0.5773502691896 ;
+		Vert_XYZ.normal[2]= 0.5773502691896 ;
+		Vert_XYZ.texcoord[0][0]=flCentreX ;
+		Vert_XYZ.texcoord[0][1]=flCentreY ;
+		Vert_XYZ.texcoord[1][0]=flCentreZ ;
+		Vert_XYZ.texcoord[1][1]=flBrightness ;
+		Vert_XYZ.color[0]=(unsigned char)flColR ;
+		Vert_XYZ.color[1]=(unsigned char)flColG ;
+		Vert_XYZ.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_XYZ)) return 0 ;
+
+		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+		Triangle.Texture=m_pLamp[nLamp].Texture ;
+		Triangle.Lamp=nLamp ;
+		Triangle.Group=m_nGroup ;
+
+		/////////////////////////////////////
+
+		Triangle.VIndex[2]=n_xyz ;
+		Triangle.VIndex[1]=n_xyZ ;
+		Triangle.VIndex[0]=n_xYZ ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[2]=n_xYZ ;
+		Triangle.VIndex[1]=n_xYz ;
+		Triangle.VIndex[0]=n_xyz ;
+		if(!AddTriangle(Triangle)) return 0 ;
+	
+		/////////////////////////////////////
+
+		Triangle.VIndex[0]=n_Xyz ;
+		Triangle.VIndex[1]=n_XyZ ;
+		Triangle.VIndex[2]=n_XYZ ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[0]=n_XYZ ;
+		Triangle.VIndex[1]=n_XYz ;
+		Triangle.VIndex[2]=n_Xyz ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		/////////////////////////////////////
+
+		Triangle.VIndex[2]=n_xyz ;
+		Triangle.VIndex[1]=n_xYz ;
+		Triangle.VIndex[0]=n_XYz ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[2]=n_XYz ;
+		Triangle.VIndex[1]=n_Xyz ;
+		Triangle.VIndex[0]=n_xyz ;
+		if(!AddTriangle(Triangle)) return 0 ;
+	
+		/////////////////////////////////////
+
+		Triangle.VIndex[0]=n_xyZ ;
+		Triangle.VIndex[1]=n_xYZ ;
+		Triangle.VIndex[2]=n_XYZ ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[0]=n_XYZ ;
+		Triangle.VIndex[1]=n_XyZ ;
+		Triangle.VIndex[2]=n_xyZ ;
+		if(!AddTriangle(Triangle)) return 0 ;
+	
+		/////////////////////////////////////
+
+		Triangle.VIndex[0]=n_xyz ;
+		Triangle.VIndex[1]=n_xyZ ;
+		Triangle.VIndex[2]=n_XyZ ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[0]=n_XyZ ;
+		Triangle.VIndex[1]=n_Xyz ;
+		Triangle.VIndex[2]=n_xyz ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		/////////////////////////////////////
+
+		Triangle.VIndex[2]=n_xYz ;
+		Triangle.VIndex[1]=n_xYZ ;
+		Triangle.VIndex[0]=n_XYZ ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[2]=n_XYZ ;
+		Triangle.VIndex[1]=n_XYz ;
+		Triangle.VIndex[0]=n_xYz ;
+		if(!AddTriangle(Triangle)) return 0 ;
+	
+		m_nGroup++ ; // increment group once for every lamp
+	}
+	
+
+
+	return 1 ;
+}
+
+
+int Q3Map::ConvertLampsToGlowTriangles(void)
+{
+	float flCentreX=0.0f ;
+	float flCentreY=0.0f ;
+	float flCentreZ=0.0f ;
+
+	float flMinX=0.0f ;
+	float flMinY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxX=0.0f ;
+	float flMaxY=0.0f ;
+	float flMaxZ=0.0f ;
+
+//	float	flNormX=0.0f ;
+//	float	flNormY=0.0f ;
+//	float	flNormZ=0.0f ;
+//	float flTexU=0.0f ;
+//	float flTexV=0.0f ;
+
+	float flColR=0.0f ;
+	float flColG=0.0f ;
+	float flColB=0.0f ;
+
+	float flBrightness=0.0f ;
+
+	int nLamp=0 ;
+
+
+	Q3BspVertex Vert_L ;
+	Q3BspVertex Vert_R ;
+	Q3BspVertex Vert_F ;
+	Q3BspVertex Vert_B ;
+	Q3BspVertex Vert_U ;
+	Q3BspVertex Vert_D ;
+
+
+	int n_L=0 ;
+	int n_R=0 ;
+	int n_F=0 ;
+	int n_B=0 ;
+	int n_U=0 ;
+	int n_D=0 ;
+	
+	int nFirstVertex=0 ;
+
+	float flBaseGlowSize=0.15f ;//0.2f;//0.001f ;
+	float flGlowSize=0.0f ;
+
+
+
+	triangle_t Triangle ;
+	ZeroMemory((void*)&Triangle, sizeof(triangle_t)) ;
+	
+	for(nLamp=0 ; nLamp<m_nLampMax ; nLamp++)
+	{
+
+		flGlowSize=flBaseGlowSize*m_pLamp[nLamp].Brightness ;
+
+		flCentreX =		m_pLamp[nLamp].Position[0] ;
+		flCentreY =		m_pLamp[nLamp].Position[1] ;
+		flCentreZ =		m_pLamp[nLamp].Position[2] ;
+
+		flMinX =			flCentreX-flGlowSize ;
+		flMinY =			flCentreY-flGlowSize ;
+		flMinZ =			flCentreZ-flGlowSize ;
+
+		flMaxX =			flCentreX+flGlowSize ;
+		flMaxY =			flCentreY+flGlowSize ;
+		flMaxZ =			flCentreZ+flGlowSize ;
+
+		flColR =			m_pLamp[nLamp].Colour[0]*255.0f ;
+		flColG =			m_pLamp[nLamp].Colour[1]*255.0f ;
+		flColB =			m_pLamp[nLamp].Colour[2]*255.0f ;
+		
+		flBrightness=	m_pLamp[nLamp].Brightness*4.0f ; 
+		
+		//////////////////////////////////////
+		// setup our 8 vertices.  Normal isn't that important, I just approximate regardless of actual box shape
+
+
+		nFirstVertex=m_nVertexMax ; // we need to remember which vertex is which for defining the triangles
+
+		// vertex numbers
+		n_L=nFirstVertex+0 ;
+		n_R=nFirstVertex+1 ;
+		n_F=nFirstVertex+2 ;
+		n_B=nFirstVertex+3 ;
+		n_U=nFirstVertex+4 ;
+		n_D=nFirstVertex+5 ;
+
+
+
+		Vert_L.position[0]=flMinX ;
+		Vert_L.position[1]=flCentreY ;
+		Vert_L.position[2]=flCentreZ ;
+		Vert_L.normal[0]=-1.0 ;
+		Vert_L.normal[1]=0.0 ;
+		Vert_L.normal[2]=0.0 ;
+		Vert_L.texcoord[0][0]=flCentreX ;
+		Vert_L.texcoord[0][1]=flCentreY ;
+		Vert_L.texcoord[1][0]=flCentreZ ;
+		Vert_L.texcoord[1][1]=flBrightness ;
+		Vert_L.color[0]=(unsigned char)flColR ;
+		Vert_L.color[1]=(unsigned char)flColG ;
+		Vert_L.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_L)) return 0 ;
+
+		Vert_R.position[0]=flMaxX ;
+		Vert_R.position[1]=flCentreY ;
+		Vert_R.position[2]=flCentreZ ;
+		Vert_R.normal[0]=1.0 ;
+		Vert_R.normal[1]=0.0 ;
+		Vert_R.normal[2]=0.0 ;
+		Vert_R.texcoord[0][0]=flCentreX ;
+		Vert_R.texcoord[0][1]=flCentreY ;
+		Vert_R.texcoord[1][0]=flCentreZ ;
+		Vert_R.texcoord[1][1]=flBrightness ;
+		Vert_R.color[0]=(unsigned char)flColR ;
+		Vert_R.color[1]=(unsigned char)flColG ;
+		Vert_R.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_R)) return 0 ;
+
+		Vert_F.position[0]=flCentreX ;
+		Vert_F.position[1]=flCentreY ;
+		Vert_F.position[2]=flMinZ ;
+		Vert_F.normal[0]=0.0 ;
+		Vert_F.normal[1]=0.0 ;
+		Vert_F.normal[2]=-1.0 ;
+		Vert_F.texcoord[0][0]=flCentreX ;
+		Vert_F.texcoord[0][1]=flCentreY ;
+		Vert_F.texcoord[1][0]=flCentreZ ;
+		Vert_F.texcoord[1][1]=flBrightness ;
+		Vert_F.color[0]=(unsigned char)flColR ;
+		Vert_F.color[1]=(unsigned char)flColG ;
+		Vert_F.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_F)) return 0 ;
+		
+		Vert_B.position[0]=flCentreX ;
+		Vert_B.position[1]=flCentreY ;
+		Vert_B.position[2]=flMaxZ ;
+		Vert_B.normal[0]=0.0 ;
+		Vert_B.normal[1]=0.0 ;
+		Vert_B.normal[2]=1.0 ;
+		Vert_B.texcoord[0][0]=flCentreX ;
+		Vert_B.texcoord[0][1]=flCentreY ;
+		Vert_B.texcoord[1][0]=flCentreZ ;
+		Vert_B.texcoord[1][1]=flBrightness ;
+		Vert_B.color[0]=(unsigned char)flColR ;
+		Vert_B.color[1]=(unsigned char)flColG ;
+		Vert_B.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_B)) return 0 ;
+
+		Vert_U.position[0]=flCentreX ;
+		Vert_U.position[1]=flMaxY ;
+		Vert_U.position[2]=flCentreZ ;
+		Vert_U.normal[0]=0.0 ;
+		Vert_U.normal[1]=1.0 ;
+		Vert_U.normal[2]=0.0 ;
+		Vert_U.texcoord[0][0]=flCentreX ;
+		Vert_U.texcoord[0][1]=flCentreY ;
+		Vert_U.texcoord[1][0]=flCentreZ ;
+		Vert_U.texcoord[1][1]=flBrightness ;
+		Vert_U.color[0]=(unsigned char)flColR ;
+		Vert_U.color[1]=(unsigned char)flColG ;
+		Vert_U.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_U)) return 0 ;
+
+		Vert_D.position[0]=flCentreX ;
+		Vert_D.position[1]=flMinY ;
+		Vert_D.position[2]=flCentreZ ;
+		Vert_D.normal[0]=0.0 ;
+		Vert_D.normal[1]=-1.0 ;
+		Vert_D.normal[2]=0.0 ;
+		Vert_D.texcoord[0][0]=flCentreX ;
+		Vert_D.texcoord[0][1]=flCentreY ;
+		Vert_D.texcoord[1][0]=flCentreZ ;
+		Vert_D.texcoord[1][1]=flBrightness ;
+		Vert_D.color[0]=(unsigned char)flColR ;
+		Vert_D.color[1]=(unsigned char)flColG ;
+		Vert_D.color[2]=(unsigned char)flColB ;
+		if(!AddVertex(Vert_D)) return 0 ;
+
+		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+		Triangle.Texture=m_nDefaultTextureIndexGlowLamp ;
+		Triangle.Lamp=-1 ;
+		Triangle.Group=m_nGroup ;
+
+		/////////////////////////////////////
+
+		Triangle.VIndex[0]=n_U ;
+		Triangle.VIndex[1]=n_L ;
+		Triangle.VIndex[2]=n_F ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[0]=n_U ;
+		Triangle.VIndex[1]=n_F ;
+		Triangle.VIndex[2]=n_R ;
+		if(!AddTriangle(Triangle)) return 0 ;
+	
+		Triangle.VIndex[0]=n_U ;
+		Triangle.VIndex[1]=n_R ;
+		Triangle.VIndex[2]=n_B ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[0]=n_U ;
+		Triangle.VIndex[1]=n_B ;
+		Triangle.VIndex[2]=n_L ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		//////////////////////////////////////
+
+		Triangle.VIndex[2]=n_D ;
+		Triangle.VIndex[1]=n_L ;
+		Triangle.VIndex[0]=n_F ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[2]=n_D ;
+		Triangle.VIndex[1]=n_F ;
+		Triangle.VIndex[0]=n_R ;
+		if(!AddTriangle(Triangle)) return 0 ;
+	
+		Triangle.VIndex[2]=n_D ;
+		Triangle.VIndex[1]=n_R ;
+		Triangle.VIndex[0]=n_B ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[2]=n_D ;
+		Triangle.VIndex[1]=n_B ;
+		Triangle.VIndex[0]=n_L ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		m_nGroup++ ; // increment group once for each glow
+		
+	}
+	
+
+
+	return 1 ;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+int Q3Map::ConvertLightsToGlowTriangles(void)
+{
+	float flCentreX=0.0f ;
+	float flCentreY=0.0f ;
+	float flCentreZ=0.0f ;
+
+	float flMinX=0.0f ;
+	float flMinY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxX=0.0f ;
+	float flMaxY=0.0f ;
+	float flMaxZ=0.0f ;
+
+//	float	flNormX=0.0f ;
+//	float	flNormY=0.0f ;
+//	float	flNormZ=0.0f ;
+//	float flTexU=0.0f ;
+//	float flTexV=0.0f ;
+
+	float flColR=0.0f ;
+	float flColG=0.0f ;
+	float flColB=0.0f ;
+
+	float flBrightness=0.0f ;
+
+	int nLight=0 ;
+
+	Q3BspVertex Vert_Or ;
+	Q3BspVertex Vert_A0 ;
+	Q3BspVertex Vert_A1 ;
+	Q3BspVertex Vert_B0 ;
+	Q3BspVertex Vert_B1 ;
+
+
+	int n_Or=0 ;
+	int n_A0=0 ;
+	int n_A1=0 ;
+	int n_B0=0 ;
+	int n_B1=0 ;
+	
+	int nFirstVertex=0 ;
+
+	float flBaseGlowSize=0.2f ;//0.001f ;
+	float flGlowSize=0.0f ;
+
+//	char chMessage[1024] ;
+
+
+
+	triangle_t Triangle ;
+	ZeroMemory((void*)&Triangle, sizeof(triangle_t)) ;
+	
+	for(nLight=0 ; nLight<m_nLightMax ; nLight++)
+	//for(nLight=0 ; nLight<1 ; nLight++)
+	{
+		//if(m_pLight[nLight].LightNode>-1) continue ; // Lights that are lightnodes don't add their own triangles.  They just exist as information for TexLights.
+
+		flGlowSize=flBaseGlowSize*m_pLight[nLight].Brightness ;
+
+		flCentreX =		m_pLight[nLight].Position[0] ;
+		flCentreY =		m_pLight[nLight].Position[1] ;
+		flCentreZ =		m_pLight[nLight].Position[2] ;
+
+		flMinX =			flCentreX-flGlowSize ;
+		flMinY =			flCentreY-flGlowSize ;
+		flMinZ =			flCentreZ-flGlowSize ;
+
+		flMaxX =			flCentreX+flGlowSize ;
+		flMaxY =			flCentreY+flGlowSize ;
+		flMaxZ =			flCentreZ+flGlowSize ;
+
+		flColR =			m_pLight[nLight].Colour[0]*255.0f ;
+		flColG =			m_pLight[nLight].Colour[1]*255.0f ;
+		flColB =			m_pLight[nLight].Colour[2]*255.0f ;
+		
+		flBrightness=	m_pLight[nLight].Brightness * 0.75 ;//*2.0 ; 
+		
+		//////////////////////////////////////
+		// setup our 5 vertices.
+
+
+		nFirstVertex=m_nVertexMax ; // we need to remember which vertex is which for defining the triangles
+
+		// vertex numbers
+		n_Or=nFirstVertex+0 ;
+		n_A0=nFirstVertex+1 ;
+		n_A1=nFirstVertex+2 ;
+		n_B0=nFirstVertex+3 ;
+		n_B1=nFirstVertex+4 ;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+		
+	
+	float flHALFPI =	1.5707963 ;
+	float flTWOPI =		6.2831853 ;
+	float flPI =			3.1415926 ;
+	float flAngle=(m_pLight[nLight].Angle/360.0f*flTWOPI)/2.0 ;
+	float flCutoff=32.0f ;//m_pLight[nLight].Brightness ;
+	
+	Q3BspVertex color ;
+
+	Q3BspVertex NormalVert ;
+	SetVertex(&NormalVert, m_pLight[nLight].Direction[0], m_pLight[nLight].Direction[1], m_pLight[nLight].Direction[2]) ;
+	NormalVert=GetNormalised(&NormalVert) ;
+
+	Q3BspVertex normal ;
+	SetVertex(&normal, m_pLight[nLight].Direction[0]*flCutoff, m_pLight[nLight].Direction[1]*flCutoff, m_pLight[nLight].Direction[2]*flCutoff) ;
+
+	Q3BspVertex adjust=normal ;
+	VertexScale(&adjust, 0.5) ;
+
+	Q3BspVertex start ;		SetVertex(&start, flCentreX, flCentreY, flCentreZ) ;
+	Q3BspVertex end ;			SetVertex(&end, flCentreX+normal.position[0], flCentreY+normal.position[1], flCentreZ+normal.position[2]) ;
+
+	Q3BspVertex xaxis ; SetVertex(&xaxis, 1,0,0) ;
+	Q3BspVertex xaxisneg ; SetVertex(&xaxisneg, -1,0,0) ;
+	Q3BspVertex yaxis ; SetVertex(&yaxis, 0,1,0) ;
+	Q3BspVertex Origin ; SetVertex(&Origin, 0,0,0) ;
+	Q3BspVertex tangentA ;
+	Q3BspVertex tangentB ;
+	Q3BspVertex tangentStart ;
+	Q3BspVertex tangentEnd ;
+	Q3BspVertex tangentEndA0 ;
+	Q3BspVertex tangentEndA1 ;
+	Q3BspVertex tangentEndB0 ;
+	Q3BspVertex tangentEndB1 ;
+
+	Q3BspVertex tangentANorm ;
+	Q3BspVertex tangentBNorm ;
+
+	Q3BspVertex raytangent ;
+
+	Q3BspVertex ray ;
+	float theta=0.0f ;
+	float adjacent=0.0f ;
+	SetVertex(&color, 0.66, 0.66, 0.66) ;
+
+	if(flAngle<0.0001) return 0 ;
+
+	if(flAngle>flPI-0.01) // near on 180 degrees
+		flAngle=flPI-0.01 ;
+
+
+	Q3BspVertex backshift ;
+	backshift=normal ;
+	VertexScale(&backshift, 0.95) ;
+	
+
+	if( !VectorsAreEqual(&NormalVert, &xaxis) && !VectorsAreEqual(&NormalVert, &xaxisneg) )
+		tangentA=NormalizedCrossProduct(Origin, normal, xaxis) ;
+	else
+		tangentA=NormalizedCrossProduct(Origin, normal, yaxis) ;
+	
+	tangentB=NormalizedCrossProduct(Origin, normal, tangentA) ;
+
+	tangentANorm=tangentA ;
+	tangentBNorm=tangentB ;
+
+
+	
+	theta=flHALFPI-flAngle ; // angle between adjacent and hypotenuse (the normal is the "opposite" side, and we know there's a right angle)
+	adjacent=VertexDistance(&Origin, &normal)/tan(theta) ; 
+
+	//////////////////////////////////////////////////////////////////////
+	
+	Vert_Or.position[0]=end.position[0]-backshift.position[0] ;
+	Vert_Or.position[1]=end.position[1]-backshift.position[1] ;
+	Vert_Or.position[2]=end.position[2]-backshift.position[2] ;
+	Vert_Or.normal[0]= NormalVert.position[0] ;
+	Vert_Or.normal[1]= NormalVert.position[1] ;
+	Vert_Or.normal[2]= NormalVert.position[2] ;
+	Vert_Or.texcoord[0][0]=flCentreX ;
+	Vert_Or.texcoord[0][1]=flCentreY ;
+	Vert_Or.texcoord[1][0]=flCentreZ ;
+	Vert_Or.texcoord[1][1]=flBrightness ;
+	Vert_Or.color[0]=(unsigned char)flColR ;
+	Vert_Or.color[1]=(unsigned char)flColG ;
+	Vert_Or.color[2]=(unsigned char)flColB ;
+	if(!AddVertex(Vert_Or)) return 0 ;
+
+
+
+
+	//////////////////////////////////////////////////////////////////////
+
+	flColR=0.0f ;
+	flColG=0.0f ;
+	flColB=0.0f ;
+
+	tangentA=GetNormalised(&tangentA) ;
+	VertexScale(&tangentA,  adjacent) ; 
+
+	tangentStart=start ;
+	tangentEnd=VectorSubtract(&end, &tangentA) ;
+	ray=VectorSubtract(&tangentEnd, &tangentStart) ;
+	ray=GetNormalised(&ray) ;
+	VertexScale(&ray, flCutoff) ;
+	tangentStart=start ;
+	tangentEndA0=VectorAdd(&start, &ray) ;
+
+	raytangent=VectorSubtract(&end, &tangentEndA0) ;
+	raytangent=VectorAdd(&raytangent, &adjust) ;
+	raytangent=GetNormalised(&raytangent) ;
+
+
+
+	tangentEndA0=VectorSubtract(&tangentEndA0, &backshift) ;
+	Vert_A0.position[0]=tangentEndA0.position[0] ;
+	Vert_A0.position[1]=tangentEndA0.position[1] ;
+	Vert_A0.position[2]=tangentEndA0.position[2] ;
+	Vert_A0.normal[0]= -raytangent.position[0] ;
+	Vert_A0.normal[1]= -raytangent.position[1] ;
+	Vert_A0.normal[2]= -raytangent.position[2] ;
+	Vert_A0.texcoord[0][0]=flCentreX ;
+	Vert_A0.texcoord[0][1]=flCentreY ;
+	Vert_A0.texcoord[1][0]=flCentreZ ;
+	Vert_A0.texcoord[1][1]=flBrightness ;
+	Vert_A0.color[0]=(unsigned char)flColR ;//abs(Vert_A0.normal[0])*255 ;//0.0f ;
+	Vert_A0.color[1]=(unsigned char)flColG ;//abs(Vert_A0.normal[1])*255 ;//0.0f ;
+	Vert_A0.color[2]=(unsigned char)flColB ;//abs(Vert_A0.normal[2])*255 ;//0.0f ;
+	if(!AddVertex(Vert_A0)) return 0 ;
+
+
+	tangentStart=start ;
+	tangentEnd=VectorAdd(&end, &tangentA) ;
+	ray=VectorSubtract(&tangentEnd, &tangentStart) ;
+	ray=GetNormalised(&ray) ;
+	VertexScale(&ray, flCutoff) ; //ray.getScaledBy(cutoff) ;
+	tangentStart=start ;
+	tangentEndA1=VectorAdd(&start, &ray) ;
+
+	raytangent=VectorSubtract(&end, &tangentEndA1) ;
+	raytangent=VectorAdd(&raytangent, &adjust) ;
+	raytangent=GetNormalised(&raytangent) ;
+
+	tangentEndA1=VectorSubtract(&tangentEndA1, &backshift) ;
+	Vert_A1.position[0]=tangentEndA1.position[0] ;
+	Vert_A1.position[1]=tangentEndA1.position[1] ;
+	Vert_A1.position[2]=tangentEndA1.position[2] ;
+	Vert_A1.normal[0]= -raytangent.position[0] ;
+	Vert_A1.normal[1]= -raytangent.position[1] ;
+	Vert_A1.normal[2]= -raytangent.position[2] ;
+	Vert_A1.texcoord[0][0]=flCentreX ;
+	Vert_A1.texcoord[0][1]=flCentreY ;
+	Vert_A1.texcoord[1][0]=flCentreZ ;
+	Vert_A1.texcoord[1][1]=flBrightness ;
+	Vert_A1.color[0]=(unsigned char)flColR ;//abs(Vert_A1.normal[0])*255 ;//0.0f ;
+	Vert_A1.color[1]=(unsigned char)flColG ;//abs(Vert_A1.normal[1])*255 ;//0.0f ;
+	Vert_A1.color[2]=(unsigned char)flColB ;//abs(Vert_A1.normal[2])*255 ;//0.0f ;
+	if(!AddVertex(Vert_A1)) return 0 ;
+
+	//////////////////////////////////////////////////////////////////////
+
+	tangentB=GetNormalised(&tangentB) ;
+	VertexScale(&tangentB, adjacent) ; //tangentB.getScaledBy(adjacent) ;
+
+	tangentStart=start ;
+	tangentEnd=VectorSubtract(&end, &tangentB) ;
+	ray=VectorSubtract(&tangentEnd, &tangentStart) ;
+	ray=GetNormalised(&ray) ;
+	VertexScale(&ray, flCutoff) ; //ray.getScaledBy(cutoff) ;
+	tangentStart=start ;
+	tangentEndB0=VectorAdd(&start, &ray) ;
+
+	raytangent=VectorSubtract(&end, &tangentEndB0) ;
+	raytangent=VectorAdd(&raytangent, &adjust) ;
+	raytangent=GetNormalised(&raytangent) ;
+
+	tangentEndB0=VectorSubtract(&tangentEndB0, &backshift) ;
+	Vert_B0.position[0]=tangentEndB0.position[0] ;
+	Vert_B0.position[1]=tangentEndB0.position[1] ;
+	Vert_B0.position[2]=tangentEndB0.position[2] ;
+	Vert_B0.normal[0]= -raytangent.position[0] ;
+	Vert_B0.normal[1]= -raytangent.position[1] ;
+	Vert_B0.normal[2]= -raytangent.position[2] ;
+	Vert_B0.texcoord[0][0]=flCentreX ;
+	Vert_B0.texcoord[0][1]=flCentreY ;
+	Vert_B0.texcoord[1][0]=flCentreZ ;
+	Vert_B0.texcoord[1][1]=flBrightness ;
+	Vert_B0.color[0]=(unsigned char)flColR ;//abs(Vert_B0.normal[0])*255 ;//0.0f ;
+	Vert_B0.color[1]=(unsigned char)flColG ;//abs(Vert_B0.normal[1])*255 ;//0.0f ;
+	Vert_B0.color[2]=(unsigned char)flColB ;//abs(Vert_B0.normal[2])*255 ;//0.0f ;
+	if(!AddVertex(Vert_B0)) return 0 ;
+
+	tangentStart=start ;
+	tangentEnd=VectorAdd(&end, &tangentB) ;
+	ray=VectorSubtract(&tangentEnd, &tangentStart) ;
+	ray=GetNormalised(&ray) ;
+	VertexScale(&ray, flCutoff) ; //ray.getScaledBy(cutoff) ;
+	tangentStart=start ;
+	tangentEndB1=VectorAdd(&start, &ray) ;
+
+	raytangent=VectorSubtract(&end, &tangentEndB1) ;
+	raytangent=VectorAdd(&raytangent, &adjust) ;
+	raytangent=GetNormalised(&raytangent) ;
+
+	tangentEndB1=VectorSubtract(&tangentEndB1, &backshift) ;
+	Vert_B1.position[0]=tangentEndB1.position[0] ;
+	Vert_B1.position[1]=tangentEndB1.position[1] ;
+	Vert_B1.position[2]=tangentEndB1.position[2] ;
+	Vert_B1.normal[0]= -raytangent.position[0] ;
+	Vert_B1.normal[1]= -raytangent.position[1] ;
+	Vert_B1.normal[2]= -raytangent.position[2] ;
+	Vert_B1.texcoord[0][0]=flCentreX ;
+	Vert_B1.texcoord[0][1]=flCentreY ;
+	Vert_B1.texcoord[1][0]=flCentreZ ;
+	Vert_B1.texcoord[1][1]=flBrightness ;
+	Vert_B1.color[0]=(unsigned char)flColR ;//abs(Vert_B1.normal[0])*255 ;//0.0f ;
+	Vert_B1.color[1]=(unsigned char)flColG ;//abs(Vert_B1.normal[1])*255 ;//0.0f ;
+	Vert_B1.color[2]=(unsigned char)flColB ;//abs(Vert_B1.normal[2])*255 ;//0.0f ;
+	if(!AddVertex(Vert_B1)) return 0 ;
+
+	/////////////////////////////////////////////////////////////////////
+
+
+
+
+	// the four verts are position correctly to make the large end of a cone (or rather, pyramid) that would be consistent
+	// with the angle and their distance from the origin.  However we cheat and move them back on top of the origin
+	// so that map lights come out looking better.
+	
+	/*
+	SetVertex(&normal, m_pLight[nLight].Direction[0]*flCutoff, m_pLight[nLight].Direction[1]*flCutoff, m_pLight[nLight].Direction[2]*flCutoff) ;
+
+	tangentEndA0=VectorSubtract(&tangentEndA0, &normal) ;
+	Vert_A0.position[0]=tangentEndA0.position[0] ;
+	Vert_A0.position[1]=tangentEndA0.position[1] ;
+	Vert_A0.position[2]=tangentEndA0.position[2] ;
+
+	tangentEndA1=VectorSubtract(&tangentEndA1, &normal) ;
+	Vert_A1.position[0]=tangentEndA1.position[0] ;
+	Vert_A1.position[1]=tangentEndA1.position[1] ;
+	Vert_A1.position[2]=tangentEndA1.position[2] ;
+
+	tangentEndB0=VectorSubtract(&tangentEndB0, &normal) ;
+	Vert_A0.position[0]=tangentEndB0.position[0] ;
+	Vert_A0.position[1]=tangentEndB0.position[1] ;
+	Vert_A0.position[2]=tangentEndB0.position[2] ;
+
+	tangentEndB1=VectorSubtract(&tangentEndB1, &normal) ;
+	Vert_A1.position[0]=tangentEndB1.position[0] ;
+	Vert_A1.position[1]=tangentEndB1.position[1] ;
+	Vert_A1.position[2]=tangentEndB1.position[2] ;
+	*/
+
+
+	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+		Triangle.Texture=m_nDefaultTextureIndexGlowLight ;
+		Triangle.Lamp=-1 ;
+		Triangle.Group=m_nGroup ;
+
+		/////////////////////////////////////
+
+		Triangle.VIndex[0]=n_Or ;
+		Triangle.VIndex[2]=n_A0 ;
+		Triangle.VIndex[1]=n_B1 ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[0]=n_Or ;
+		Triangle.VIndex[2]=n_B1 ;
+		Triangle.VIndex[1]=n_A1 ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		Triangle.VIndex[0]=n_Or ;
+		Triangle.VIndex[2]=n_A1 ;
+		Triangle.VIndex[1]=n_B0 ;
+		if(!AddTriangle(Triangle)) return 0 ;
+		
+		Triangle.VIndex[0]=n_Or ;
+		Triangle.VIndex[2]=n_B0 ;
+		Triangle.VIndex[1]=n_A0 ;
+		if(!AddTriangle(Triangle)) return 0 ;
+
+		m_nGroup++ ; // increment group once for each glow
+		
+	}
+	
+	return 1 ;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+// some vertex manipulation functions used for setting up the light disk.
+// They only work on the position, so other parts of the struct need to be setup seperately
+
+
+void Q3Map::SetVertex(Q3BspVertex *pVert, float flXPos, float flYPos, float flZPos)
+{
+	pVert->position[0]=flXPos ;
+	pVert->position[1]=flYPos ;
+	pVert->position[2]=flZPos ;
+}
+
+// this doesn't test exact equivalence, but rather within the range of an epsilon VERYSMALL
+bool Q3Map::VectorsAreEqual(Q3BspVertex* pVecA, Q3BspVertex* pVecB)
+{
+	if( fabs(pVecA->position[0] - pVecB->position[0])>VERYSMALL ) return false ;
+	if( fabs(pVecA->position[1] - pVecB->position[1])>VERYSMALL ) return false ;
+	if( fabs(pVecA->position[2] - pVecB->position[2])>VERYSMALL ) return false ;
+
+	return true ;
+}
+
+// VertA is the origin of VertB and VertC
+Q3BspVertex Q3Map::NormalizedCrossProduct(Q3BspVertex VertA, Q3BspVertex VertB, Q3BspVertex VertC)
+{
+
+
+	Q3BspVertex Cross ;
+
+	// edge vectors
+	float flVecXA_CP = VertA.position[0] - VertB.position[0] ;
+	float flVecYA_CP = VertA.position[1] - VertB.position[1] ;
+	float flVecZA_CP = VertA.position[2] - VertB.position[2] ;
+	float flVecXB_CP = VertA.position[0] - VertC.position[0] ;
+	float flVecYB_CP = VertA.position[1] - VertC.position[1] ;
+	float flVecZB_CP = VertA.position[2] - VertC.position[2] ;
+
+	// cross product
+	float flCpx_CP = (flVecZA_CP * flVecYB_CP) - (flVecYA_CP * flVecZB_CP);
+	float flCpy_CP = (flVecXA_CP * flVecZB_CP) - (flVecZA_CP * flVecXB_CP);
+	float flCpz_CP = (flVecYA_CP * flVecXB_CP) - (flVecXA_CP * flVecYB_CP);
+
+	// Normalize 
+	float flR_CP = sqrt(flCpx_CP * flCpx_CP + flCpy_CP * flCpy_CP + flCpz_CP * flCpz_CP);
+
+	Cross.position[0] = flCpx_CP / flR_CP;
+	Cross.position[1] = flCpy_CP / flR_CP;
+	Cross.position[2] = flCpz_CP / flR_CP;
+
+	return Cross ;
+}
+
+float Q3Map::VertexDistance(Q3BspVertex* VertA, Q3BspVertex* VertB)
+{
+	float flXDis=VertA->position[0]-VertB->position[0] ;
+	float flYDis=VertA->position[1]-VertB->position[1] ;
+	float flZDis=VertA->position[2]-VertB->position[2] ;
+
+	return sqrt(flXDis*flXDis+flYDis*flYDis+flZDis*flZDis) ;
+}
+
+void Q3Map::VertexScale(Q3BspVertex* pVert, float flScale)
+{
+	pVert->position[0]*=flScale ;
+	pVert->position[1]*=flScale ;
+	pVert->position[2]*=flScale ;
+}
+
+Q3BspVertex Q3Map::GetNormalised(Q3BspVertex* pVector)
+{
+	float flLength=sqrt((pVector->position[0]*pVector->position[0])+(pVector->position[1]*pVector->position[1])+(pVector->position[2]*pVector->position[2])) ;
+
+	Q3BspVertex Vector=*pVector ;
+
+	Vector.position[0]/=flLength ;
+	Vector.position[1]/=flLength ;
+	Vector.position[2]/=flLength ;
+
+	return Vector ;
+}
+
+Q3BspVertex Q3Map::VectorAdd(Q3BspVertex* pVecA, Q3BspVertex* pVecB)
+{
+	Q3BspVertex Vector ;
+
+	Vector.position[0]=pVecA->position[0] + pVecB->position[0] ;
+	Vector.position[1]=pVecA->position[1] + pVecB->position[1] ;
+	Vector.position[2]=pVecA->position[2] + pVecB->position[2] ;
+
+	return Vector ;
+}
+
+Q3BspVertex Q3Map::VectorSubtract(Q3BspVertex* pVecA, Q3BspVertex* pVecB)
+{
+	Q3BspVertex Vector ;
+
+	Vector.position[0]=pVecA->position[0] - pVecB->position[0] ;
+	Vector.position[1]=pVecA->position[1] - pVecB->position[1] ;
+	Vector.position[2]=pVecA->position[2] - pVecB->position[2] ;
+
+	return Vector ;
+}
+
+Q3BspVertex Q3Map::VectorMultiply(Q3BspVertex* pVecA, Q3BspVertex* pVecB)
+{
+	Q3BspVertex Vector ;
+
+	Vector.position[0]=pVecA->position[0] * pVecB->position[0] ;
+	Vector.position[1]=pVecA->position[1] * pVecB->position[1] ;
+	Vector.position[2]=pVecA->position[2] * pVecB->position[2] ;
+
+	return Vector ;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+void Q3Map::GetTexLampTextureNumbers()
+{
+	m_nBZN_LightNode0=-1 ;
+	m_nBZN_LightNode1=-1 ;
+	m_nBZN_LightNode2=-1 ;
+	m_nBZN_LightNode3=-1 ;
+
+	int nTex=0;
+	char chTexName[1024] ;
+	int nLen=0 ;
+	int nPos=0 ;
+
+	int nMatch=0 ;
+
+	strcpy(chTexName, "textures/common/bzn_lightnode") ;
+	nLen=strlen(chTexName) ;
+
+	for(nTex=0 ; nTex<m_nTextureMax ; nTex++)
+	{
+		nMatch=1 ;
+		for(nPos=nLen-1 ; nPos>=0 ; nPos--) // faster to check backwards since lots of textures will start with "textures/common/"
+			if(m_pTexture[nTex].name[nPos]!=chTexName[nPos])
+			{
+				nMatch=0 ;
+				break ;
+			}
+
+		if(nMatch)
+		{
+			// what is the last character?
+			if(m_pTexture[nTex].name[nLen]=='0')
+				m_nBZN_LightNode0=nTex ;
+			else
+			if(m_pTexture[nTex].name[nLen]=='1')
+				m_nBZN_LightNode1=nTex ;
+			else
+			if(m_pTexture[nTex].name[nLen]=='2')
+				m_nBZN_LightNode2=nTex ;
+			else
+			if(m_pTexture[nTex].name[nLen]=='3')
+				m_nBZN_LightNode3=nTex ;
+			
+		}// end if match
+
+
+	}// end for nTex
+
+}
+
+int Q3Map::SortTrianglesIntoGroups(void)
+{
+
+
+	int nNewSize=0 ; // we will drop non-subzoned (-1 zone) triangles here, so new number of triangles may be less than old number.
+
+	ULONGLONG *pFaceOrder = new ULONGLONG[m_nTriangleMax] ;
+	if(pFaceOrder==NULL) return 0 ; // out of memory.
+
+	// temporary copy of m_pTriangles to make sorting easier
+	triangle_t *TempTriangle = new triangle_t[m_nTriangleMax];
+	if(TempTriangle==NULL) { DELETE_ARRAY( pFaceOrder ) ; return 0 ; } // out of memory
+	memcpy((void*)TempTriangle, (void*)m_pTriangle, m_nTriangleMax*sizeof(triangle_t)) ;
+
+	// create the initial face "value" by setting the most significant bits to it's criteria number
+	for (int i=0; i < m_nTriangleMax; i++)
+		if(m_pTriangle[i].Zone!=-1) // drop unsubzoned triangles
+			pFaceOrder[nNewSize++] = ( ((ULONGLONG)m_pTriangle[i].Zone)<<GROUPSORT_SUBZONE_SHIFT ) + ( ((ULONGLONG)m_pTriangle[i].Texture)<<GROUPSORT_GROUP_SHIFT ) + i ;
+
+	// sort the ULONGLONGs, this will order things according to our criteria
+	// sorting is based firstly on subzone, secondly on texture.  
+	// So all triangles in a subzone will be grouped together, 
+	// and within that group all triangles with the same material will be grouped together.  
+
+	qsort( (void *)pFaceOrder, nNewSize, sizeof(ULONGLONG), &Q3Map::compareGroups);
+
+	// copy the sorted faces back to the original
+	for (int i=0; i < nNewSize; i++)
+		m_pTriangle[i]=TempTriangle[ (pFaceOrder[i]&FACESORT_FACE_MASK) ] ;
+
+	// update m_nTriangleMax to show that there may now be less triangles
+	m_nTriangleMax=nNewSize ;
+
+	// clean up the memory we used
+	DELETE_ARRAY( pFaceOrder ) ;
+	DELETE_ARRAY( TempTriangle ) ;
+
+
+	// now that the triangles are sorting according to zone and group, 
+	// re-assign the group numbers per zone, from 0 to FACESORT_GROUP_LIMIT-1
+	// All non-trans triangles will be group 0, trans triangles will be 1 to FACESORT_GROUP_LIMIT-1
+
+	int nTri=0 ;
+	int nZone=-1 ;
+	int nGroup=-1 ;
+	int nNewGroup=0 ;
+
+	//char chMessage[1024] ;
+
+	for(nTri=0 ; nTri<m_nTriangleMax ; nTri++)
+	{
+		// reset the newgroup if we've got a new zone
+		if(m_pTriangle[nTri].Zone!=nZone) 
+		{
+			nZone=m_pTriangle[nTri].Zone ;
+			nGroup=-1 ;
+			nNewGroup=0 ;
+		}	
+
+		// if we have a new group, increment the newgroup number, fail if we have too many
+		if(m_pTriangle[nTri].Group!=nGroup) 
+		{
+			// if this is a trans triangle, inc the newgroup
+			if(m_pTransTexture[ m_pTriangle[nTri].Texture ])
+			{
+				nNewGroup++ ; // will always be at least 1
+				if(nNewGroup>=FACESORT_GROUP_LIMIT) return 0 ; // too many groups in a zone.
+			}
+
+			nGroup=m_pTriangle[nTri].Group ;
+		}
+
+		if(m_pTransTexture[ m_pTriangle[nTri].Texture ]==0)
+			m_pTriangle[nTri].Group=0 ;
+		else
+			m_pTriangle[nTri].Group=nNewGroup ;
+
+
+
+	}// end for tri
+
+	return 1 ;
+}
+
+
+// static function for sorting groups, required by qsort
+int Q3Map::compareGroups( const void *arg1, const void *arg2 )
+{
+	ULONGLONG FaceA= *(ULONGLONG*)arg1 ;
+	ULONGLONG FaceB= *(ULONGLONG*)arg2 ;
+
+	if(FaceA < FaceB)
+		return -1 ;
+	else
+		if(FaceA > FaceB)
+			return 1 ;
+		
+	return 0 ;
+}
+
+
+
+// sort faces so that we can batch effectively when constructing our manualobjects
+// Currently grouped according to zone and texture.
+// Triangles not in any subzone will be dropped at this stage.
+int Q3Map::SortTrianglesIntoBatches(void)
+{
+
+
+	int nNewSize=0 ; // we will drop non-subzoned (-1 zone) triangles here, so new number of triangles may be less than old number.
+
+	ULONGLONG *pFaceOrder = new ULONGLONG[m_nTriangleMax] ;
+	if(pFaceOrder==NULL) return 0 ; // out of memory.
+
+	// temporary copy of m_pTriangles to make sorting easier
+	triangle_t *TempTriangle = new triangle_t[m_nTriangleMax];
+	if(TempTriangle==NULL) { DELETE_ARRAY( pFaceOrder ) ; return 0 ; } // out of memory
+	memcpy((void*)TempTriangle, (void*)m_pTriangle, m_nTriangleMax*sizeof(triangle_t)) ;
+
+	// create the initial face "value" by setting the most significant bits to it's criteria number
+	for (int i=0; i < m_nTriangleMax; i++)
+		if(m_pTriangle[i].Zone!=-1) // drop unsubzoned triangles
+			pFaceOrder[nNewSize++] = ( ((ULONGLONG)m_pTriangle[i].Zone)<<FACESORT_SUBZONE_SHIFT ) + ( ((ULONGLONG)m_pTriangle[i].Texture)<<FACESORT_TEXTURE_SHIFT ) + ( ((ULONGLONG)m_pTriangle[i].Group)<<FACESORT_GROUP_SHIFT ) + i ;
+
+	// sort the ULONGLONGs, this will order things according to our criteria
+	// sorting is based firstly on subzone, secondly on texture.  
+	// So all triangles in a subzone will be grouped together, 
+	// and within that group all triangles with the same material will be grouped together.  
+
+	qsort( (void *)pFaceOrder, nNewSize, sizeof(ULONGLONG), &Q3Map::compareTriangles);
+
+	// copy the sorted faces back to the original
+	for (int i=0; i < nNewSize; i++)
+		m_pTriangle[i]=TempTriangle[ (pFaceOrder[i]&FACESORT_FACE_MASK) ] ;
+
+	// update m_nTriangleMax to show that there may now be less triangles
+	m_nTriangleMax=nNewSize ;
+
+	// clean up the memory we used
+	DELETE_ARRAY( pFaceOrder ) ;
+	DELETE_ARRAY( TempTriangle ) ;
+
+	return 1 ;
+}
+
+// static function for sorting triangles, required by qsort
+int Q3Map::compareTriangles( const void *arg1, const void *arg2 )
+{
+	ULONGLONG FaceA= *(ULONGLONG*)arg1 ;
+	ULONGLONG FaceB= *(ULONGLONG*)arg2 ;
+
+	if(FaceA < FaceB)
+		return -1 ;
+	else
+		if(FaceA > FaceB)
+			return 1 ;
+		
+	return 0 ;
+}
+
+
+
+
+// note which texture numbers correspond to textures that have transparency.
+// needed for when we work out transparency groups and related stuff
+int Q3Map::SetupTransTextures(void)
+{
+	int nMaterial=0 ;
+	int nPos=0 ;
+	char chMaterial[1024] ;
+
+	// create the memory for the transtextures
+	m_pTransTexture = new int[m_nTextureMax] ;
+	if(m_pTransTexture==NULL) return 0 ; // out of memory.
+
+	for(nMaterial=0 ; nMaterial<m_nTextureMax ; nMaterial++)
+	{
+		// copy the material name.
+		// q3 texture names are a max of 64 characters ( Q3NAMESIZE ) and may not be null terminated.  They have no extension either.
+		nPos=-1 ;
+		while((++nPos<Q3NAMESIZE) && (m_pTexture[nMaterial].name[nPos]!=' ') && (m_pTexture[nMaterial].name[nPos]!='\0'))
+			chMaterial[nPos]=m_pTexture[nMaterial].name[nPos] ;
+
+		// make sure name is null terminated
+		chMaterial[nPos]='\0' ;
+
+
+		// is the texture a type we need to flag as transparent?
+		if(strstr(chMaterial, "GEL")!=NULL)
+			m_pTransTexture[nMaterial]=1 ;
+		else
+			m_pTransTexture[nMaterial]=0 ;
+
+	}// end for nMaterial
+
+	return 1 ;
+
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int Q3Map::AssignPortalsToZones(void)
+{
+	int nZone=0 ;
+	float flMinX=0.0f ;
+	float flMaxX=0.0f ;
+	float flMinY=0.0f ;
+	float flMaxY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxZ=0.0f ;
+	int nMaxSubZone=m_iNumSubZones ;
+	int nSubZone=0 ;
+	int nMaxPortal=m_iNumPortals ;
+	int nPortal=0 ;
+	int nIndex=0 ;
+	int nPos=0 ;
+
+
+
+	// clear the portal settings.
+	for(nZone=0 ; nZone<m_nMaxZone ; nZone++)
+		m_nZoneTouchesPortal[nZone][INDEX_PORTALCOUNT]=0 ;
+
+	for(nPortal=0 ; nPortal<nMaxPortal ; nPortal++)
+		m_nPortalTouchesZone[nPortal][INDEX_PORTALZONECOUNT]=0 ;
+
+
+
+	// now test each subzone against each portal to see what zones each portal contains.
+	for(nSubZone=0 ; nSubZone<nMaxSubZone ; nSubZone++)
+	{
+		nZone=m_pSubZones[nSubZone].Zone ;
+		flMinX=m_pSubZones[nSubZone].Min[0] ;
+		flMaxX=m_pSubZones[nSubZone].Max[0] ;
+		flMinY=m_pSubZones[nSubZone].Min[1] ;
+		flMaxY=m_pSubZones[nSubZone].Max[1] ;
+		flMinZ=m_pSubZones[nSubZone].Min[2] ;
+		flMaxZ=m_pSubZones[nSubZone].Max[2] ;
+
+		// test all the portals to see if any overlap this subzone
+		for(nPortal=0 ; nPortal<nMaxPortal ; nPortal++)
+		{
+
+			// if AABB overlap
+			if(
+						 (flMinX<m_pPortals[nPortal].Max[0]) && (flMaxX>m_pPortals[nPortal].Min[0])
+					&& (flMinY<m_pPortals[nPortal].Max[1]) && (flMaxY>m_pPortals[nPortal].Min[1])
+					&& (flMinZ<m_pPortals[nPortal].Max[2]) && (flMaxZ>m_pPortals[nPortal].Min[2])
+				)
+			{
+
+				// add this portal to the zone's portal list
+				nIndex=m_nZoneTouchesPortal[nZone][INDEX_PORTALCOUNT] ;
+				if(nIndex<MAX_PORTALPERZONE) // only add if we aren't already maxed out.
+				{
+					// we need to check this portal isn't already on the list.
+					// it might have gotten on by another subzone, since a zone can have multiple subzones.
+					nPos=-1 ;
+					while((++nPos<nIndex) && (m_nZoneTouchesPortal[nZone][nPos]!=nPortal)) ; 
+
+					if(nPos==nIndex) // this can only be true if we didn't already find nPortal in the list
+					{
+						m_nZoneTouchesPortal[nZone][nIndex]=nPortal ;
+						m_nZoneTouchesPortal[nZone][INDEX_PORTALCOUNT]++ ;
+					}
+				}
+
+				// add this zone to the portal's list
+				nIndex=m_nPortalTouchesZone[nPortal][INDEX_PORTALZONECOUNT] ;
+				if(nIndex<MAX_ZONEPERPORTAL)
+				{
+					// we need to check this zone isn't already on the list.
+					// it might have gotten on by another subzone, since a zone can have multiple subzones.
+					nPos=-1 ;
+					while((++nPos<nIndex) && (m_nPortalTouchesZone[nPortal][nPos]!=nZone)) ; 
+
+					if(nPos==nIndex) // this can only be true if we didn't already find nZone in the list
+					{
+						m_nPortalTouchesZone[nPortal][nIndex]=nZone ;
+						m_nPortalTouchesZone[nPortal][INDEX_PORTALZONECOUNT]++ ;
+					}
+				}
+
+			}// end if portal overlaps subzone
+
+		}// end for portal
+
+	}// end for subzone
+
+	return 1 ;
+}
+
+int Q3Map::AssignLightsToZones(void)
+{
+	int nZone=0 ;
+	float flMinX=0.0f ;
+	float flMaxX=0.0f ;
+	float flMinY=0.0f ;
+	float flMaxY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxZ=0.0f ;
+	int nMaxSubZone=m_iNumSubZones ;
+	int nSubZone=0 ;
+	int nMaxLight=m_nLightMax ;
+	int nLight=0 ;
+	int nIndex=0 ;
+	int nPos=0 ;
+
+
+
+	// clear the light settings.
+	for(nZone=0 ; nZone<m_nMaxZone ; nZone++)
+		m_nZoneContainsLightCentre[nZone][INDEX_LIGHTCOUNT]=m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT]=0 ;
+
+	for(nLight=0 ; nLight<nMaxLight ; nLight++)
+		m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT]=0 ;
+	
+
+
+
+	// now test each subzone against each light what contains/touches what
+	for(nSubZone=0 ; nSubZone<nMaxSubZone ; nSubZone++)
+	{
+		nZone=m_pSubZones[nSubZone].Zone ;
+		flMinX=m_pSubZones[nSubZone].Min[0] ;
+		flMaxX=m_pSubZones[nSubZone].Max[0] ;
+		flMinY=m_pSubZones[nSubZone].Min[1] ;
+		flMaxY=m_pSubZones[nSubZone].Max[1] ;
+		flMinZ=m_pSubZones[nSubZone].Min[2] ;
+		flMaxZ=m_pSubZones[nSubZone].Max[2] ;
+
+		// test all the lights to see if any have centers inside this subzone
+		for(nLight=0 ; nLight<nMaxLight ; nLight++)
+		{
+
+			/////////////////////////////////////////////////////////////////////////////////////
+
+			// if light center is in this subzone
+			if(
+						 (m_pLight[nLight].Position[0]>=flMinX) && (m_pLight[nLight].Position[0]<=flMaxX)
+					&& (m_pLight[nLight].Position[1]>=flMinY) && (m_pLight[nLight].Position[1]<=flMaxY)
+					&& (m_pLight[nLight].Position[2]>=flMinZ) && (m_pLight[nLight].Position[2]<=flMaxZ)
+				)
+			{
+
+				// add this light to the zone's light list
+				nIndex=m_nZoneContainsLightCentre[nZone][INDEX_LIGHTCOUNT] ;
+				if(nIndex<MAX_LIGHTPERZONE) // only add if we aren't already maxed out.
+				{
+					// we need to check this light isn't already on the list.
+					// it might have gotten on by another subzone, since a zone can have multiple subzones.
+					nPos=-1 ;
+					while((++nPos<nIndex) && (m_nZoneContainsLightCentre[nZone][nPos]!=nLight)) ; 
+
+					if(nPos==nIndex) // this can only be true if we didn't already find nLight in the list
+					{
+						m_nZoneContainsLightCentre[nZone][nIndex]=nLight ;
+						m_nZoneContainsLightCentre[nZone][INDEX_LIGHTCOUNT]++ ;
+
+						// assign this zone as the light's centre.  We only allow one zone to be the light's centre zone,
+						// so this will get overwritten if the light is on the border.
+						m_pLight[nLight].CentreZone=nZone ;
+					}
+				}
+
+			}// end if light centre contained by subzone
+
+			/////////////////////////////////////////////////////////////////////////////////////
+
+			// if light touches subzone (we store it in ZoneTouchesSubLight for now, will overwrite later)
+			// if light AABB overlaps the zone AABB
+			if(
+						 (flMinX<m_pLight[nLight].Max[0]) && (flMaxX>m_pLight[nLight].Min[0])
+					&& (flMinY<m_pLight[nLight].Max[1]) && (flMaxY>m_pLight[nLight].Min[1])
+					&& (flMinZ<m_pLight[nLight].Max[2]) && (flMaxZ>m_pLight[nLight].Min[2])
+				)
+			{
+				// add this light to the zone's light list
+				nIndex=m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT] ;
+				if(nIndex<MAX_LIGHTPERZONE) // only add if we aren't already maxed out.
+				{
+					// we need to check this light isn't already on the list.
+					// it might have gotten on by another subzone, since a zone can have multiple subzones.
+					nPos=-1 ;
+					while((++nPos<nIndex) && (m_nZoneTouchesSubLight[nZone][nPos]!=nLight)) ; 
+
+					if(nPos==nIndex) // this can only be true if we didn't already find nPortal in the list
+					{
+						m_nZoneTouchesSubLight[nZone][nIndex]=nLight ;
+						m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT]++ ;
+					}
+				}
+
+				// add this zone to the light's list
+				nIndex=m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT] ;
+				if(nIndex<MAX_ZONEPERLIGHT)
+				{
+					// we need to check this zone isn't already on the list.
+					// it might have gotten on by another subzone, since a zone can have multiple subzones.
+					nPos=-1 ;
+					while((++nPos<nIndex) && (m_nLightTouchesZone[nLight][nPos]!=nZone)) ; 
+
+					if(nPos==nIndex) // this can only be true if we didn't already find nZone in the list
+					{
+						m_nLightTouchesZone[nLight][nIndex]=nZone ;
+						m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT]++ ;
+					}
+				}
+
+			}// end if light touches contained by subzone
+
+			/////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+		}// end for light
+
+	}// end for subzone
+
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	//
+	// work out the sublights.  These are cut up boxes made from the light boxes, one per zone.
+	// Most lights will just become a single sublight, but multizone lights will be cut up into
+	// multiple sublights.  These are used for calculating light visibility.
+	//
+
+	m_nSubLightMax=0 ;
+	int nMaxZone=0 ;
+	int nZoneIndex=0 ;
+	int nSubLightCentre=0 ;
+	sublight_t TempSubLight ;
+	for(nLight=0 ; nLight<nMaxLight ; nLight++)
+	{
+
+		m_pLight[nLight].ZoneCount=m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT] ; // in the light, note how many zones it touches
+
+		if((m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT]>1) && (m_nMaxMultiZoneLight<MAX_LIGHT))// this is a multizone light
+			m_nMultiZoneLight[m_nMaxMultiZoneLight++]=nLight ;
+
+
+		m_pLight[nLight].SubLightStart=m_nSubLightMax ; // where this light's cut up sublights start in m_SubLight
+
+
+		// break the light up into it's different sublights, cut by zones.
+		nMaxZone=m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT] ;
+		for(nZoneIndex=0 ; nZoneIndex<nMaxZone ; nZoneIndex++)
+		{
+			nZone=m_nLightTouchesZone[nLight][nZoneIndex] ;
+
+			flMinX= m_pLight[nLight].Min[0]<m_ZoneBoundary[nZone].Min[0] ? m_ZoneBoundary[nZone].Min[0] : m_pLight[nLight].Min[0] ; 
+			flMinY= m_pLight[nLight].Min[1]<m_ZoneBoundary[nZone].Min[1] ? m_ZoneBoundary[nZone].Min[1] : m_pLight[nLight].Min[1] ; 
+			flMinZ= m_pLight[nLight].Min[2]<m_ZoneBoundary[nZone].Min[2] ? m_ZoneBoundary[nZone].Min[2] : m_pLight[nLight].Min[2] ;
+
+			flMaxX= m_pLight[nLight].Max[0]>m_ZoneBoundary[nZone].Max[0] ? m_ZoneBoundary[nZone].Max[0] : m_pLight[nLight].Max[0] ; 
+			flMaxY= m_pLight[nLight].Max[1]>m_ZoneBoundary[nZone].Max[1] ? m_ZoneBoundary[nZone].Max[1] : m_pLight[nLight].Max[1] ; 
+			flMaxZ= m_pLight[nLight].Max[2]>m_ZoneBoundary[nZone].Max[2] ? m_ZoneBoundary[nZone].Max[2] : m_pLight[nLight].Max[2] ; 
+
+			// add the cut down light as a sublight
+			m_SubLight[m_nSubLightMax].Light=nLight ;
+			m_SubLight[m_nSubLightMax].Zone=nZone ;
+			m_SubLight[m_nSubLightMax].Min[0]=flMinX ;
+			m_SubLight[m_nSubLightMax].Min[1]=flMinY ;
+			m_SubLight[m_nSubLightMax].Min[2]=flMinZ ;
+			m_SubLight[m_nSubLightMax].Max[0]=flMaxX ;
+			m_SubLight[m_nSubLightMax].Max[1]=flMaxY ;
+			m_SubLight[m_nSubLightMax].Max[2]=flMaxZ ;
+
+			// remember which sublight is the centre
+			if(
+						 (m_pLight[nLight].Position[0]>=flMinX) && (m_pLight[nLight].Position[0]<=flMaxX)
+					&& (m_pLight[nLight].Position[1]>=flMinY) && (m_pLight[nLight].Position[1]<=flMaxY)
+					&& (m_pLight[nLight].Position[2]>=flMinZ) && (m_pLight[nLight].Position[2]<=flMaxZ)
+				)
+				nSubLightCentre=m_nSubLightMax ;
+
+					
+			m_nSubLightMax++ ; // we don't have to worry about bound checking this, because we've already checked there aren't too many lights.
+
+		}// end for zoneindex			
+		
+		// move the sublight that contains the centre to the beginning of the sublights for this light.
+		// We always want the first sublight to contain the centre to make the culling algos work better.
+		TempSubLight=m_SubLight[ m_pLight[nLight].SubLightStart ] ;
+		m_SubLight[ m_pLight[nLight].SubLightStart ] = m_SubLight[ nSubLightCentre ] ;
+		m_SubLight[ nSubLightCentre ] = TempSubLight ;
+
+
+		
+	}// end for light
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	//
+	// recalculate m_nZoneTouchesSubLight using the newly created sublights 
+	// (instead of the complete lights that were originally used)
+	//
+
+	int nSubLight=0 ;
+
+
+	// clear the light settings.
+	for(nZone=0 ; nZone<m_nMaxZone ; nZone++)
+		m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT]=0 ;
+
+	for(nSubZone=0 ; nSubZone<nMaxSubZone ; nSubZone++)
+	{
+		nZone=m_pSubZones[nSubZone].Zone ;
+		flMinX=m_pSubZones[nSubZone].Min[0] ;
+		flMaxX=m_pSubZones[nSubZone].Max[0] ;
+		flMinY=m_pSubZones[nSubZone].Min[1] ;
+		flMaxY=m_pSubZones[nSubZone].Max[1] ;
+		flMinZ=m_pSubZones[nSubZone].Min[2] ;
+		flMaxZ=m_pSubZones[nSubZone].Max[2] ;
+
+		// test all the lights to see if any have centers inside this subzone
+		for(nSubLight=0 ; nSubLight<m_nSubLightMax ; nSubLight++)
+		{
+			// if light touches subzone (we store it in ZoneTouchesSubLight for now, will overwrite later)
+			// if light AABB overlaps the zone AABB
+			if(
+						 (flMinX<m_SubLight[nSubLight].Max[0]) && (flMaxX>m_SubLight[nSubLight].Min[0])
+					&& (flMinY<m_SubLight[nSubLight].Max[1]) && (flMaxY>m_SubLight[nSubLight].Min[1])
+					&& (flMinZ<m_SubLight[nSubLight].Max[2]) && (flMaxZ>m_SubLight[nSubLight].Min[2])
+				)
+			{
+				// add this light to the zone's light list
+				nIndex=m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT] ;
+				if(nIndex<MAX_LIGHTPERZONE) // only add if we aren't already maxed out.
+				{
+					// we need to check this light isn't already on the list.
+					// it might have gotten on by another subzone, since a zone can have multiple subzones.
+					nPos=-1 ;
+					while((++nPos<nIndex) && (m_nZoneTouchesSubLight[nZone][nPos]!=nSubLight)) ; 
+
+					if(nPos==nIndex) // this can only be true if we didn't already find nSubLight in the list
+					{
+						m_nZoneTouchesSubLight[nZone][nIndex]=nSubLight ;
+						m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT]++ ;
+					}
+
+				}
+
+			}// end if overlap
+
+		}// end for nSubLight
+
+	}// end for nSubZone
+
+
+
+
+
+	return 1 ;
+}
+
+
+int Q3Map::AssignLightsToPortals(void)
+{
+	float flMinX=0.0f ;
+	float flMaxX=0.0f ;
+	float flMinY=0.0f ;
+	float flMaxY=0.0f ;
+	float flMinZ=0.0f ;
+	float flMaxZ=0.0f ;
+	int nMaxPortal=m_iNumPortals ;
+	int nPortal=0 ;
+	int nMaxLight=m_nLightMax ;
+	int nLight=0 ;
+	int nIndex=0 ;
+	int nPos=0 ;
+
+
+
+	// clear the light settings.
+	for(nPortal=0 ; nPortal<nMaxPortal ; nPortal++)
+		m_nPortalTouchesLight[nPortal][INDEX_PORTALLIGHTCOUNT]=0 ;
+
+	// now test each portal against each light to see if they touch
+	for(nPortal=0 ; nPortal<nMaxPortal ; nPortal++)
+	{
+		flMinX=m_pPortals[nPortal].Min[0] ;
+		flMaxX=m_pPortals[nPortal].Max[0] ;
+		flMinY=m_pPortals[nPortal].Min[1] ;
+		flMaxY=m_pPortals[nPortal].Max[1] ;
+		flMinZ=m_pPortals[nPortal].Min[2] ;
+		flMaxZ=m_pPortals[nPortal].Max[2] ;
+
+		// test all the lights to see if any touch this portal
+		for(nLight=0 ; nLight<nMaxLight ; nLight++)
+		{
+
+			// if light AABB overlaps the portal AABB
+			if(
+						 (flMinX<m_pLight[nLight].Max[0]) && (flMaxX>m_pLight[nLight].Min[0])
+					&& (flMinY<m_pLight[nLight].Max[1]) && (flMaxY>m_pLight[nLight].Min[1])
+					&& (flMinZ<m_pLight[nLight].Max[2]) && (flMaxZ>m_pLight[nLight].Min[2])
+				)
+			{
+
+				// add this light to the portal's light list
+				nIndex=m_nPortalTouchesLight[nPortal][INDEX_PORTALLIGHTCOUNT] ;
+				if(nIndex<MAX_LIGHTPERPORTAL) // only add if we aren't already maxed out.
+				{
+					// we need to check this light isn't already on the list.
+					// it might have gotten on by another subzone, since a zone can have multiple subzones.
+					nPos=-1 ;
+					while((++nPos<nIndex) && (m_nPortalTouchesLight[nPortal][nPos]!=nLight)) ; 
+
+					if(nPos==nIndex) // this can only be true if we didn't already find nLight in the list
+					{
+						m_nPortalTouchesLight[nPortal][nIndex]=nLight ;
+						m_nPortalTouchesLight[nPortal][INDEX_PORTALLIGHTCOUNT]++ ;
+					}
+				}
+
+				// we don't keep a list of the portals that a light touches, we don't use such a thing.
+
+			}// end if light touches portal
+
+		}// end for light
+
+	}// end for portal
+
+	return 1 ;
+}
+
+// work out all the other zones each zone touches, via portals
+int Q3Map::AssignZonesToZones(void)
+{
+	
+
+	int nCentralZone=0 ;
+	int nPortalZone=0 ;
+	int nMaxPortalZone=0 ;
+	int nPortalZoneIndex=0 ;
+	int nPortal=0 ;
+	int nPortalIndex=0 ;
+	int nMaxPortal=0 ;
+
+	int nTouchZoneIndex=0 ;
+	int nMaxTouchZone=0 ;
+	int nAddZone=0 ;
+
+
+	// scan through all the zones (consider them "central zones")
+	for(nCentralZone=0 ; nCentralZone<m_nMaxZone ; nCentralZone++)
+	{
+		nMaxTouchZone=0 ;
+
+		// scan through all the portals in this centralzone.
+		nMaxPortal=m_nZoneTouchesPortal[nCentralZone][INDEX_PORTALCOUNT] ;
+		for(nPortalIndex=0 ; nPortalIndex<nMaxPortal; nPortalIndex++)
+		{
+			nPortal=m_nZoneTouchesPortal[nCentralZone][nPortalIndex] ;
+
+			// scan through all the zones this portal touches and add then to the central zone's list
+			nMaxPortalZone=m_nPortalTouchesZone[nPortal][INDEX_PORTALZONECOUNT] ;
+			for(nPortalZoneIndex=0 ; nPortalZoneIndex<nMaxPortalZone ; nPortalZoneIndex++)
+			{
+				nPortalZone=m_nPortalTouchesZone[nPortal][nPortalZoneIndex] ;
+
+				// we've got a portal zone.  
+				if(nPortalZone==nCentralZone) continue ; // if it's the central zone, skip it.
+
+				// check we don't already have it listed.
+				nAddZone=1 ;
+				for(nTouchZoneIndex=0 ; nTouchZoneIndex<nMaxTouchZone ; nTouchZoneIndex++)
+				{
+					if(m_nZoneTouchesPortal[nCentralZone][nTouchZoneIndex]==nPortalZone)
+					{
+						nAddZone=0 ;
+						break ;
+					}// end if
+				}// end for nTouchZoneIndex
+	
+				if(nAddZone)
+				{
+					m_nZoneTouchesZone[nCentralZone][nMaxTouchZone]=nPortalZone ;
+					nMaxTouchZone++ ;
+					if(nMaxTouchZone>=MAX_ZONEPERZONE) 
+						nMaxTouchZone=MAX_ZONEPERZONE-1 ;
+
+					
+				}
+
+
+			}// end for portal zone index
+
+
+		}// end for portal index
+		
+		// set the maximum
+		m_nZoneTouchesZone[nCentralZone][INDEX_ZONEPERZONECOUNT]=nMaxTouchZone ;
+
+		/*
+		sprintf(m_chBug, "CentralZone %i, TouchedZoneCount %i", nCentralZone, m_nZoneTouchesPortal[nCentralZone][INDEX_ZONEPERZONECOUNT]) ;
+		Q3Bug.LogAddCR(m_chBug) ;
+		for(nTouchZoneIndex=0 ; nTouchZoneIndex<m_nZoneTouchesZone[nCentralZone][INDEX_ZONEPERZONECOUNT] ; nTouchZoneIndex++)
+		{
+			sprintf(m_chBug, "     TouchedZone %i", m_nZoneTouchesZone[nCentralZone][nTouchZoneIndex]) ;
+			Q3Bug.LogAddCR(m_chBug) ;
+		}
+		*/
+
+
+	}// end for central zone
+
+
+
+
+	return 1 ;
+}
+
+
+
Index: code/trunk/src/libraries/tools/bsp/Q3Map.h
===================================================================
--- code/trunk/src/libraries/tools/bsp/Q3Map.h	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/Q3Map.h	(revision 7163)
@@ -0,0 +1,709 @@
+/*
+===========================================================================
+Copyright (C) 2008 Daniel Örstadius
+Copyright (C) 2009 Jared Prince
+
+This file is part of bsp-renderer source code.
+
+bsp-renderer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+bsp-renderer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+// Q3Map.h -- handles the map data
+
+#ifndef _Q3MAP_H
+#define _Q3MAP_H
+
+#define WIN32_LEAN_AND_MEAN
+#include "windows.h"
+
+#include "Q3Map_Bezier.h"
+
+#include <string>
+#include <vector>
+
+#include "Q3Map_misc.h"
+
+//#include "JarDebug.h" //!! just for debugging, remove from final build
+
+#define MEMADD	65536 // memory is grown in 66k blocks
+#define MAX_TOKENSIZE 1024 // make sure tokens in texts aren't ridiculously large
+
+
+
+#define MINMAXLIMIT 10000000.0
+
+#define BRIGHTNESSTWEAK	0.5f //1.25f				// tweak for spotlight brightness
+
+#define ADDTEXTUREUNIQUE_FAIL		-1
+#define ADDTEXLAMP_FAIL					-2
+
+#define ADDSPOTLIGHTTEXTURE_FAIL	-1
+
+////////////////////////////////////////////////////
+
+#define AXIS_X	0
+#define AXIS_Y	1
+#define AXIS_Z	2
+
+////////////////////////////////////////////////////
+/*
+#define FACESORT_FACE_LIMIT			16777216
+#define FACESORT_FACE_SHIFT			0
+#define FACESORT_FACE_MASK			0x0000000000FFFFFF
+#define FACESORT_TEXTURE_LIMIT	4096
+#define FACESORT_TEXTURE_SHIFT	24
+#define FACESORT_TEXTURE_MASK		0x0000000FFF000000
+#define FACESORT_SUBZONE_LIMIT			4096 // also see MAX_ZONE
+#define FACESORT_SUBZONE_SHIFT			36
+#define FACESORT_SUBZONE_MASK			0x0000FFF000000000
+*/
+
+#define FACESORT_FACE_LIMIT			16777216
+#define FACESORT_FACE_SHIFT			0
+#define FACESORT_FACE_MASK			0x0000000000FFFFFF
+#define FACESORT_GROUP_LIMIT		65536	// also see MAX_TRANS
+#define FACESORT_GROUP_SHIFT		24
+#define FACESORT_GROUP_MASK			0x000000FFFF000000
+#define FACESORT_TEXTURE_LIMIT	4096
+#define FACESORT_TEXTURE_SHIFT	40
+#define FACESORT_TEXTURE_MASK		0x000FFF0000000000
+#define FACESORT_SUBZONE_LIMIT	4096 // also see MAX_ZONE
+#define FACESORT_SUBZONE_SHIFT	52
+#define FACESORT_SUBZONE_MASK		0xFFF0000000000000
+
+#define GROUPSORT_FACE_LIMIT		16777216
+#define GROUPSORT_FACE_SHIFT		0
+#define GROUPSORT_FACE_MASK			0x0000000000FFFFFF
+#define GROUPSORT_GROUP_LIMIT		16777216
+#define GROUPSORT_GROUP_SHIFT		24
+#define GROUPSORT_GROUP_MASK		0x0000FFFFFF000000
+#define GROUPSORT_SUBZONE_LIMIT	4096 // also see MAX_ZONE
+#define GROUPSORT_SUBZONE_SHIFT	52
+#define GROUPSORT_SUBZONE_MASK	0xFFF0000000000000
+
+
+
+////////////////////////////////////////////////////
+
+#define MAX_ZONE	4096							// max subzones and max zones. Also see FACESORT_SUBZONE_LIMIT
+#define MAX_SUBZONEPERZONE	16			// the most subzones that can make up a zone, further subzones ignored. INDEX_SUBZONECOUNT must be same as this
+#define INDEX_SUBZONECOUNT	16			// helps subzone counting in m_nZone.  See MAX_SUBZONEPERZONE
+
+#define MAX_PORTAL	32768						// max subzoneportals in a map.
+#define MAX_PORTALPERZONE 64				// the most portals that a zone can have, further portals ignored.  INDEX_PORTALCOUNT must be same as this
+#define MAX_ZONEPERPORTAL	8					// the most zones a portal can connect, further zones ignored.  INDEX_PORTALZONECOUNT must be the same as this
+#define MAX_LIGHTPERPORTAL 16				// the most lights that can touch a portal, further lights ignored. INDEX_PORTALLIGHTCOUNT must be the same as this
+#define INDEX_PORTALCOUNT	64				// helps portal counting in m_nZoneTouchesPortal. See MAX_PORTALSPERZONE
+#define INDEX_PORTALZONECOUNT 8			// helps portalconnect counting in m_nPortalTouchesZone. See MAX_ZONEPERPORTAL
+#define INDEX_PORTALLIGHTCOUNT 16		// helps portallight counting in m_PortalConnectsLight.	See MAX_LIGHTPERPORTAL
+
+#define MAX_ZONEPERZONE		64				// the most zones that a zone can connect to.
+#define INDEX_ZONEPERZONECOUNT	64  // helps zone per zone counting.
+
+#define MAX_LIGHT		32768						// max lights in a map, both from the map and other things (flashlight, missiles, etc)
+#define MAX_LIGHTPERZONE 64					// the most lights that a zone can have, further lights ignored.  INDEX_LIGHTCOUNT must be same as this
+#define MAX_ZONEPERLIGHT	8					// the most zones a light can touch, further zones ignored.  INDEX_LIGHTZONECOUNT must be the same as this
+#define INDEX_LIGHTCOUNT	64				// helps light counting in m_nZoneContainsLight.  see MAX_LIGHTPERZONE
+#define INDEX_LIGHTZONECOUNT	8			// helps light counting in m_nLightContainedByZone. See MAX_ZONEPERLIGHT
+
+#define MAX_SUBLIGHT	262144				// must be MAX_LIGHT * MAX_ZONEPERLIGHT
+#define MAX_TRANS			65536					// most transparent objects per zone (objects may be defined in various ways).  see FACESORT_TRANS_LIMIT
+
+
+
+////////////////////////////////////////////////////
+
+#define SUBZONE_EPSILON	0.01f	// small buffer of extra size around subzones so that we don't accidentally exclude a point due to float accuracy errors.
+#define FRUSTUM_EPSILON 0.0001f // once frustum is this tiny consider it dead
+#define VERYSMALL 0.00001			// small number
+
+#define PORTAL_UNCHECKED		0
+#define PORTAL_VISCHECK			1
+#define PORTAL_VISIBLE			2
+
+#define PORTALSTATE_OPENCHECK	0
+#define PORTALSTATE_CLOSED			1
+#define PORTALSTATE_OPEN				2
+
+#define ZONE_UNCHECKED			0
+#define ZONE_VISIBLE				1
+
+#define LIGHT_UNCHECKED				0
+#define LIGHT_OUTOFFRUSTUM		1
+#define LIGHT_INSIDEFRUSTUM		2
+#define LIGHT_NOTVISIBLE			4
+#define LIGHT_VISIBLE					8
+#define LIGHT_CHECKED					16
+
+///////////////////////////////////////////////////
+
+#define MAX_PROJECTORTEX	16		// most types of projector textures we can have per map.
+
+
+///////////////////////////////////////////////////
+
+// NOERROR is already defined in a windows file, it is 0
+#define ERROR_ParseMap						1
+#define ERROR_ParseEntities				2
+#define ERROR_AllocateVertex			3
+#define ERROR_AllocateTriangle		4
+#define ERROR_InitializeFaces			5
+#define ERROR_ConvertFaces				6
+#define ERROR_ConvertPatches			7
+#define ERROR_ConvertLamps				8
+#define ERROR_ConvertLampGlow			9
+#define ERROR_ConvertLightGlow		10
+#define ERROR_AssignTriangles			11
+#define ERROR_SortTriangles				12
+#define ERROR_ConvertTexLamp			13
+#define ERROR_SetupTransTextures	14
+#define ERROR_SortGroups					15
+
+
+///////////////////////////////////////////////////
+// error values for parsing key/values
+#define KEY_OK										0
+#define KEY_NONE									1
+#define KEY_ERROR									2
+
+//////////////////////////////////////////////////
+// entity types
+#define ENTITY_ERROR							0
+#define ENTITY_UNKNOWN						1
+#define ENTITY_WORLDSPAWN					2
+#define ENTITY_LIGHT							3
+
+///////////////////////////////////////////////////
+
+
+
+// The lump idexes that make up a bsp file.
+// Bzn bsp lump data is almost identical to q3a bsp lump data,  except that the
+// Effects, Lightmaps and VisData lumps are removed and there are two new lumps, one
+// describing the subzones and one describing the portals. The other difference is the lighting
+// entities (which are stored as normal entities in lump 0) since q3a bsps don't usually
+// store the light entities at all, and BZN has it's own unique set of lighting keys.
+
+const int Textures = 1;
+const int Planes = 2;
+const int Nodes = 3;
+const int Leafs = 4;
+const int LeafFaces = 5;
+const int LeafBrushes = 6;
+const int Brushes = 8;
+const int BrushSides = 9;
+const int Vertices = 10;
+const int MeshVerts = 11;
+const int Effects = 12;				// removed from bzn
+const int Faces = 13;
+const int LightMaps = 14;			// removed from bzn
+const int VisData = 16;				// removed from bzn
+const int SubZoneData = 17 ;	// added to bzn: overlapping subzones form zones. Zones are like groups of axial boxes.
+const int PortalData = 18 ;		// added to bzn: portals overlapping different zones allow them to see each other.
+const int MAX_LUMP = 19 ;
+
+const int MAX_LUMP_SIZE = 100000000 ; // this value is very large and arbitrary, 100 megabytes.  Just make sure MAX_LUMP_SIZE * MAX_LUMP is less than the max size for a size_t or parseMap error checking won't work.
+
+enum {POLYGON = 1, PATCH, MESH, BILLBOARD};
+
+typedef struct{
+  int iOffset;
+  int iLength;
+} direntry_t;
+
+#define Q3NAMESIZE	64
+typedef struct {
+  char name[Q3NAMESIZE];
+  int flags;
+  int contents;
+} Q3BspTexture;
+
+typedef struct{
+  unsigned char magic[4];
+  int version;
+  direntry_t Lumps[MAX_LUMP];
+} Q3BspHeader_t;
+
+typedef struct{
+  int texture;
+  int effect;
+  int type;
+  int vertex;
+  int n_vertexes;
+  int meshvert;
+  int n_meshverts;
+  int lm_index;
+  int lm_start[2];
+  int lm_size[2];
+  float lm_origin[3];
+  float lm_vecs[2][3];
+  float normal[3];
+  int size[2];
+} Q3BspFace_t;
+
+typedef struct{
+  float position[3];
+  float texcoord[2][2];
+  float normal[3];
+  unsigned char color[4];
+} Q3BspVertex;
+
+typedef struct {
+  int cluster;
+  int area;
+  int mins[3];
+  int maxs[3];
+  int leafface;
+  int n_leaffaces;
+  int leafbrush;
+  int n_leafbrushes;
+} Q3BspLeaf;
+
+typedef struct {
+  float normal[3];
+  float dist;
+} Q3BspPlane;
+
+typedef struct {
+  int plane;
+  int children[2];
+  int mins[3];
+  int maxs[3];
+} Q3BspNode;
+
+typedef struct {
+  int brushside;
+  int n_brushsides;
+  int texture;
+} Q3BspBrush;
+
+typedef struct {
+  int plane;
+  int texture;
+} Q3BspBrushSide;
+
+typedef struct {
+  unsigned char lightmap[128][128][3];
+} Q3BspLightMap;
+
+typedef struct {
+  int n_vecs;
+  int sz_vecs;
+  unsigned char *vecs;
+} Q3BspVisData;
+
+typedef struct {
+  int size;
+  Bezier *bezier;
+} Q3BspPatch;
+
+
+// this struct must be the same as in BZNq3map2
+typedef struct
+{
+	int Zone ;
+	float Min[3] ;
+	float Max[3] ;
+}
+BZN_SubZone_t;
+
+// this struct must be the same as in BZNq3map2
+typedef struct
+{
+	float Min[3] ;
+	float Max[3] ;
+}
+BZN_Portal_t;
+
+
+typedef struct{
+	int texture;    
+	int type;
+	int vertex;
+	int n_vertexes;
+	int meshvert;
+	int n_meshverts;
+	int n_triangles;
+	int lm_index;    
+	float normal[3]; 
+	int zone ; // added by Jared 
+	Q3BspPatch *patch;
+} Q3BspFaceRenderer;
+
+//////////////////////////////////////
+typedef struct {
+	int Zone ; // this gets set to -1 for triangles in no zone, and they don't get added to the manualobjects
+	int Texture ;
+	//int Lightmap ; // bzn doesn't use lightmaps
+	int VIndex[3] ;
+	int Lamp ; // which lamp this triangle came from, -1 for most triangles.
+
+	int Group ; // triangles from the same face are the same group, triangles from the same patch are the same group.  Most stuff is group 0 unless it needs special attention, such as transparent stuff
+} triangle_t;
+
+typedef struct {
+	unsigned int Flags ;
+	float	Position[3] ;
+	float Direction[3] ;
+	float Colour[3] ;
+	float Min[3] ;
+	float Max[3] ;
+	float	Cutoff ;
+	float	Angle ;
+	float Brightness ;
+	int Texture ; // texture index of light
+	unsigned int ZoneCount ; // how many zones this light touches
+	unsigned int CentreZone ; // which zone contains the centre of this light.  even if on a boundary, the light will only choose one zone as its centre.
+	short SubLightStart ; // where this light's sublights start in the sublight list.
+} light_t ;
+
+typedef struct {
+	unsigned int Flags ;
+	float	Position[3] ;
+	float Colour[3] ;
+	float Min[3] ;
+	float Max[3] ;
+	float Brightness ;
+	int Texture ; // texture index of light
+	int LightNode ; // -1 if not a node, 0 - 3 if a node.  LightNodes are used as the data for TexLamps, freeform geometry that gets converted to deferred shading lamp triangles.
+	unsigned short Zone[MAX_ZONEPERLIGHT+1] ; // the zones this lamp touches
+} lamp_t ;
+
+typedef struct
+{
+	float Min[3] ;
+	float Max[3] ;
+}
+minmax_t;
+
+// this used for the light culling algo, where each cutup light is treated as a subzone.
+typedef struct
+{
+	unsigned short Light ;
+	unsigned short Zone ;
+	float Min[3] ;
+	float Max[3] ;
+}
+sublight_t;
+
+
+class Q3Map
+{
+public:
+  Q3Map();
+  ~Q3Map();
+
+	int m_nNewCount ;
+
+	int m_nDebugA ;
+
+//	CJarDebug Q3Bug ; //!! just for debugging, remove from final build
+	char m_chBug[10240] ;
+
+	int ParseAndTriangulateMap(const char* pData, size_t Size) ;
+	void FreeParseMem(void) ;
+
+	int parseMap(const char* pMem, size_t Size);
+
+  int findVisibleFaces(const QVECTOR *camPos, int *facesToRender);
+  Q3BspFace_t *getFaces(void);
+  Q3BspPatch *handlePatch(int faceIndex);
+
+	char m_chSpotlightTexture[MAX_PROJECTORTEX][Q3NAMESIZE] ;
+	int m_nMaxSpotlightTexture ;
+	int AddSpolightTexture(char TEXNAME[]) ;
+
+private:
+
+  
+  
+  
+
+  	
+
+  int findLeaf(const QVECTOR *camPos) const;
+  bool isClusterVisible(int visCluster, int testCluster) const;	
+
+  int *mVisibleFaces;
+
+  std::vector<Q3BspVisData> *patches;
+
+public:
+  // map data
+
+  Q3BspHeader_t m_BspHeader;
+
+  char *m_pEntities;
+
+  int m_iNumTexs;
+  Q3BspTexture *m_pTexturesOrig;
+
+  int m_iNumFaces;
+  Q3BspFace_t *m_pFaces; 
+
+  int m_iNumVertices;
+  Q3BspVertex *m_pVertices;
+
+  int m_iNumMeshVerts;	
+  int *m_pMeshVerts;
+
+  int m_iNumLeafs;
+  Q3BspLeaf *m_pLeafs;
+
+  int m_iNumLeafFaces;
+  int *m_pLeafFaces;
+
+  int m_iNumPlanes;
+  Q3BspPlane *m_pPlanes;
+
+  int m_iNumNodes;
+  Q3BspNode *m_pNodes;
+
+  int m_iNumLeafBrushes;
+  int *m_pLeafBrushes;
+
+  int m_iNumBrushes;
+  Q3BspBrush *m_pBrushes;
+
+  int m_iNumBrushSides;
+  Q3BspBrushSide *m_pBrushSides;
+
+  int m_iNumLightMaps;
+  Q3BspLightMap *m_pLightMaps;
+
+  Q3BspVisData *m_VisData;
+
+	int m_iNumSubZones ;
+  BZN_SubZone_t *m_pSubZones;
+
+	int m_iNumPortals ;
+  BZN_Portal_t *m_pPortals;
+
+
+
+
+  int m_ClusterCount ;
+
+	void swizzleCoords(void);
+  void swizzleFloat3(float t[3]);
+  void swizzleInt3(int t[3]);
+
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// memory management for the triangles
+	int AllocateTriangleMemory(void) ;
+	void FreeTriangleMemory(void) ;
+	int ExpandTriangleMemory(void) ;
+	int AddTriangle(triangle_t Triangle) ;
+	int m_nTriangleSize ; // starting memory size
+	void* m_pTriangleMem ; // allocate starting memory space
+	triangle_t* m_pTriangle ; // a pointer to the memory cast as a triangle_t
+	int m_nTriangleMax ;
+	int m_nTriangleLimit ;
+
+	// memory management for the vertices
+	int AllocateVertexMemory(int nVertNum) ;
+	void FreeVertexMemory(void) ;
+	int ExpandVertexMemory(void) ;
+	int AddVertex(Q3BspVertex Vertex) ;
+	int m_nVertexSize ; // starting memory size
+	void* m_pVertexMem ; // allocate starting memory space
+	Q3BspVertex* m_pVertex ; // a pointer to the memory cast as a Q3BspVertex
+	int m_nVertexMax ;
+	int m_nVertexLimit ;
+
+	// memory management for the lights
+	int AllocateLightMemory(void) ;
+	void FreeLightMemory(void) ;
+	int ExpandLightMemory(void) ;
+	int AddLight(light_t Light) ;
+	int m_nLightSize ; // starting memory size
+	void* m_pLightMem ; // allocate starting memory space
+	light_t* m_pLight ; // a pointer to the memory cast as a light_t
+	int m_nLightMax ;
+	int m_nLightLimit ;
+
+	// memory management for the lamps (a lamp is a deferred shading non-shadowing point light)
+	int AllocateLampMemory(void) ;
+	void FreeLampMemory(void) ;
+	int ExpandLampMemory(void) ;
+	int AddLamp(lamp_t Lamp) ;
+	int m_nLampSize ; // starting memory size
+	void* m_pLampMem ; // allocate starting memory space
+	lamp_t* m_pLamp ; // a pointer to the memory cast as a lamp_t
+	int m_nLampMax ;
+	int m_nLampLimit ;
+
+	// memory management for the textures
+	int AllocateTextureMemory(void) ;
+	void FreeTextureMemory(void) ;
+	int ExpandTextureMemory(void) ;
+	int AddTexture(Q3BspTexture Texture) ;
+	int AddTextureUnique(Q3BspTexture Texture) ; // special version of the Add function, will not add if the texture name already exist.  returns texture index, or -1 on fail
+	int m_nTextureSize ; // starting memory size
+	void* m_pTextureMem ; // allocate starting memory space
+	Q3BspTexture* m_pTexture ; // a pointer to the memory cast as a Texture_t
+	int m_nTextureMax ;
+	int m_nTextureLimit ;
+
+	// memory management for the TexLamp Triangles
+	int AllocateTexLampMemory(void) ;
+	void FreeTexLampMemory(void) ;
+	int ExpandTexLampMemory(void) ;
+	int AddTexLamp(int TexLamp) ;
+	int m_nTexLampSize ; // starting memory size
+	void* m_pTexLampMem ; // allocate starting memory space
+	int* m_pTexLamp ; // a pointer to the memory cast as an int
+	int m_nTexLampMax ;
+	int m_nTexLampLimit ;
+
+	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+	int ParseEntities(void) ;
+	int NextEntity(int* pPos, int nMaxPos) ;
+	int GetEntityType(int nPos, int nMaxPos) ;
+	int GetEntityKeyAndValue(int* pPos, int nMaxPos, char* pKey, char* pValue) ;
+	int GetNumbersFromValue(char* pValue, float *pNumber, int nNumberSize) ;
+	int GetNumbersFromValue(char* pValue, int *pNumber, int nNumberSize) ;
+	int ParseAndAddLight(int* pPos, int nMaxPos) ;
+
+	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	Q3BspFaceRenderer *m_BspFaces;	
+	int m_NumBspFaces;
+	void DestroyBspFacesMemory(void) ;
+	int initFaces(void) ;
+
+	// we keep track of common texture indexes to avoid slow calls to AddTextureUnique when we add default light texture indexes
+	int m_nDefaultTextureIndexLamp ;
+	int m_nDefaultTextureIndexLamp2Pass ;
+	int m_nDefaultTextureIndexGlowLamp ;
+	int m_nDefaultTextureIndexGlowLight ;
+	int m_nDefaultTextureIndexSpotlight ;
+
+	void GetTexLampTextureNumbers() ;
+	int m_nBZN_LightNode0 ;
+	int m_nBZN_LightNode1 ;
+	int m_nBZN_LightNode2 ;
+	int m_nBZN_LightNode3 ;
+
+	int m_nGroup ;
+
+	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+	//
+	// Much easier to keep track of how zones/subzones/portals/lights connect to each other using hardwired arrays
+	// than dynamically allocated memory, even if it does waste a little space and impose some design limits.
+	// It's fast, easy to manage, and the total memory used is reasonably small.  
+	// The design limits are generous enough that it's unlikely maps will get anywhere near hitting them.
+	//
+	// Memory Footprints:
+	//
+	// m_nZone:											 4096 * (16+1) * sizeof(unsigned short) =	  139,264
+	// m_ZoneBoundary								 4096 *					 sizeof(minmax_t)24			=	   98,304
+	// m_nZoneTouchesPortal					 4096 * (64+1) * sizeof(unsigned short) =	  532,480
+	// m_nPortalTouchesZone					32768 * ( 8+1) * sizeof(unsigned short) =	  589,824
+	//
+	// m_nZoneContainsLightCentre		 4096 * (64+1) * sizeof(unsigned short) =	  532,480 
+	// m_nLightTouchesZone					32768 * ( 8+1) * sizeof(unsigned short) =	  589,824
+	// m_nZoneTouchesSubLight				 4096 * (64+1) * sizeof(unsigned short) =	  532,480
+	//
+	// m_nMultiZoneLight						32768 *					 sizeof(unsigned short)	=		 65,536	
+	// m_SubLight										32768 * 8			 * sizeof(sublight_t)28		=	6,815,744
+	// m_nZoneTouchesZone						 4096 * (64+1) * sizeof(unsigned short) =	  532,480
+	//
+	//																																TOTAL = 10,428,416 (9.9 meg)
+
+	unsigned short m_nZone[MAX_ZONE][MAX_SUBZONEPERZONE+1] ;									// last index is used as a counter, INDEX_SUBZONECOUNT
+	minmax_t m_ZoneBoundary[MAX_ZONE] ; // min and max of a zone.  Since zones might not be square, NEVER use this as the real zone boundary, work it out using the subzones instead.  This is just for cutting up lights.
+	
+	unsigned short m_nZoneTouchesPortal[MAX_ZONE][MAX_PORTALPERZONE+1] ;			// last index is used as a counter, INDEX_PORTALCOUNT
+	unsigned short m_nPortalTouchesZone[MAX_PORTAL][MAX_ZONEPERPORTAL+1] ;		// last index is used as a counter, INDEX_PORTALZONECOUNT
+	
+	// PortalTouchesLight is true if the light AABB touches the portal.
+	unsigned short m_nPortalTouchesLight[MAX_PORTAL][MAX_LIGHTPERPORTAL+1] ;	// last index is used as a counter, INDEX_PORTALLIGHTCOUNT
+
+	unsigned short m_nZoneContainsLightCentre[MAX_ZONE][MAX_LIGHTPERZONE+1] ;				// last index is used as a counter, INDEX_LIGHTCOUNT
+	unsigned short m_nLightTouchesZone[MAX_LIGHT][MAX_ZONEPERLIGHT+1] ;				// last index is used as a counter, INDEX_LIGHTZONECOUNT
+	unsigned short m_nZoneTouchesSubLight[MAX_ZONE][MAX_LIGHTPERZONE+1] ;				// last index is used as a counter, INDEX_LIGHTCOUNT
+
+	unsigned short m_nZoneTouchesZone[MAX_ZONE][MAX_ZONEPERZONE+1] ;				// last index is used as a counter, INDEX_ZONEPERZONECOUNT
+
+	// list of lights that touche more than one zone.  These require more complex visibility checks
+	unsigned short m_nMultiZoneLight[MAX_LIGHT] ; 
+	int m_nMaxMultiZoneLight ;
+	
+	sublight_t m_SubLight[MAX_SUBLIGHT] ;
+	int m_nSubLightMax ;
+	 
+
+	//
+	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+	int m_nMaxZone ;
+
+	int ConvertFacesToTriangles(void) ;
+	int ConvertPatchesToTriangles(void) ;
+	int ConvertTexLampsToLampTriangles(void) ;
+	int ConvertLampsToTriangles(void) ;
+	int ConvertLampsToGlowTriangles(void) ;
+	int ConvertLightsToGlowTriangles(void) ;
+
+
+	void SetVertex(Q3BspVertex *pVert, float flXPos, float flYPos, float flZPos) ;
+	bool VectorsAreEqual(Q3BspVertex* pVecA, Q3BspVertex* pVecB) ;
+	Q3BspVertex NormalizedCrossProduct(Q3BspVertex VertA, Q3BspVertex VertB, Q3BspVertex VertC) ;
+	float VertexDistance(Q3BspVertex* VertA, Q3BspVertex* VertB) ;
+	void VertexScale(Q3BspVertex* pVert, float flScale) ;
+	Q3BspVertex GetNormalised(Q3BspVertex* pVector) ;
+	Q3BspVertex VectorAdd(Q3BspVertex* pVecA, Q3BspVertex* pVecB) ;
+	Q3BspVertex VectorSubtract(Q3BspVertex* pVecA, Q3BspVertex* pVecB) ;
+	Q3BspVertex VectorMultiply(Q3BspVertex* pVecA, Q3BspVertex* pVecB) ;
+
+	void SetupZones(void) ;
+	int GetNextSubZone(float *flPoint, int nStart, int nMax) ;
+
+	bool PointInSubZone(float *flPoint, int nSubZone) ;
+	bool PointInZone(float *flPos, int nZone) ;
+
+	bool AABBTouchesSubZone(float *flPointMin, float *flPointMax, int nSubZone) ;
+	bool AABBTouchesZone(float *flPosMin, float *flPosMax, int nZone) ;
+
+	int AssignTrianglesToZones(void) ;
+	int FindTriangleZone(int nTriangle) ;
+	int SetupTriangleZone(int nTriangle) ;
+	int SplitTriangle(int nTriangle, int nAxis, float flCutPos) ; // only does axial cuts.  returns false on failure, probably due to lack of memory.
+	void CreateTweenVert(Q3BspVertex* pVertA, Q3BspVertex* pVertB, float flPercent0, Q3BspVertex* pVertAB) ;
+	
+
+	int SortTrianglesIntoGroups(void) ;
+	static int compareGroups( const void *arg1, const void *arg2 ) ;
+
+	int SortTrianglesIntoBatches(void) ;
+	static int compareTriangles( const void *arg1, const void *arg2 ) ;
+
+	int SetupTransTextures(void) ;
+	int* m_pTransTexture ;
+
+
+	int AssignPortalsToZones(void) ;
+	int AssignLightsToPortals(void) ;
+	int AssignLightsToZones(void) ;
+	int AssignZonesToZones(void) ;
+
+};
+
+#endif /* _Q3MAP_H */
Index: code/trunk/src/libraries/tools/bsp/Q3Map_Bezier.cpp
===================================================================
--- code/trunk/src/libraries/tools/bsp/Q3Map_Bezier.cpp	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/Q3Map_Bezier.cpp	(revision 7163)
@@ -0,0 +1,131 @@
+/*
+===========================================================================
+Copyright (C) 2008 Daniel Örstadius
+
+This file is part of bsp-renderer source code.
+
+bsp-renderer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+bsp-renderer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+// Bezier.cpp -- tessellates the Bezier patches
+
+/* The tessellation code is taken from the document 
+"Rendering Quake 3 Maps" at 
+http://graphics.cs.brown.edu/games/quake/quake3.html
+The author states that it is based on code from 
+Paul Baker's Octagon project,
+http://www.paulsprojects.net/opengl/octagon/octagon.html
+which is released under the New BSD license.
+Please see the licenses folder.
+*/
+
+#include "Q3Map_Bezier.h"
+#include "Q3Map_misc.h"
+
+
+Bezier::Bezier()
+{	
+  mVertex = 0;
+  mIndex = 0;
+  mTrianglesPerRow = 0;
+  mRowIndex = 0;
+}
+
+Bezier::~Bezier()
+{
+  DELETE_ARRAY(mVertex);
+  DELETE_ARRAY(mIndex);
+  DELETE_ARRAY(mTrianglesPerRow);
+  DELETE_ARRAY(mRowIndex);
+}
+
+
+
+
+
+void Bezier::tessellate(int L) 
+{
+  // The number of vertices along a side is 1 + num edges
+  const int L1 = L + 1;
+
+  mVertex = new BspVertex[L1*L1];
+  mNumVertex = L1*L1;
+
+  // Compute the vertices    
+  for (int i = 0; i <= L; ++i)
+  {
+    float a = (float)i / L;
+    float b = 1.0f - a;
+
+    mVertex[i] =
+      mControls[0] * (b * b) + 
+      mControls[3] * (2 * b * a) +
+      mControls[6] * (a * a);
+  }
+
+  for (int i = 1; i <= L; i++) 
+  {
+    float a = (float)i / L;
+    float b = 1.0f - a;
+
+    BspVertex temp[3];
+
+    for (int j = 0; j < 3; j++)
+    {
+      int k = 3 * j;
+      temp[j] =
+        mControls[k + 0] * (b * b) + 
+        mControls[k + 1] * (2 * b * a) +
+        mControls[k + 2] * (a * a);
+    }
+
+    for(int j = 0; j <= L; ++j) 
+    {
+      float a = (float)j / L;
+      float b = 1.0f - a;
+
+      mVertex[i * L1 + j]=
+        temp[0] * (b * b) + 
+        temp[1] * (2 * b * a) +
+        temp[2] * (a * a);
+    }
+  }
+
+  // Compute the indices     
+  mIndex = new unsigned int[L * (L + 1) * 2];
+  mNumIndex = L * (L + 1) * 2;
+
+  for (int row = 0; row < L; ++row) 
+  {
+    for(int col = 0; col <= L; ++col)	
+    {
+      mIndex[(row * (L + 1) + col) * 2 + 1] = row       * L1 + col;
+      mIndex[(row * (L + 1) + col) * 2]     = (row + 1) * L1 + col;
+    }
+  }
+
+  mTrianglesPerRow = new unsigned int[L];
+  mRowIndex = new unsigned int[L];
+
+  for (int row = 0; row < L; ++row) 
+  {
+    mTrianglesPerRow[row] = 2 * L1;
+    //rowIndexes[row]      = &indexes[row * 2 * L1];
+    mRowIndex[row]      = row * 2 * L1;
+  }
+
+  for (int i=0; i < L1*L1; i++)
+    mVertex[i].normalise();
+}
Index: code/trunk/src/libraries/tools/bsp/Q3Map_Bezier.h
===================================================================
--- code/trunk/src/libraries/tools/bsp/Q3Map_Bezier.h	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/Q3Map_Bezier.h	(revision 7163)
@@ -0,0 +1,48 @@
+/*
+===========================================================================
+Copyright (C) 2008 Daniel Örstadius
+
+This file is part of bsp-renderer source code.
+
+bsp-renderer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+bsp-renderer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+// Bezier.h -- class for the Bezier patches
+
+#ifndef _BEZIER_H
+#define _BEZIER_H
+
+#include "Q3Map_BspVertex.h"
+
+class Bezier 
+{
+public:
+  Bezier();
+  ~Bezier();
+  
+  void tessellate(int level);
+
+  BspVertex mControls[9];
+  BspVertex *mVertex;
+  unsigned int *mIndex;
+  unsigned int *mTrianglesPerRow;
+  unsigned int *mRowIndex;
+  unsigned int mNumIndex;
+  unsigned int mNumVertex;
+  int mBaseBufferindex;
+  int mBaseVertexIndex;
+};
+
+#endif
Index: code/trunk/src/libraries/tools/bsp/Q3Map_BspVertex.cpp
===================================================================
--- code/trunk/src/libraries/tools/bsp/Q3Map_BspVertex.cpp	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/Q3Map_BspVertex.cpp	(revision 7163)
@@ -0,0 +1,106 @@
+/*
+===========================================================================
+Copyright (C) 2008 Daniel Örstadius
+
+This file is part of bsp-renderer source code.
+
+bsp-renderer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+bsp-renderer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+// BspVertex.cpp -- used in the tessellation of the Bezier patches
+
+
+#include <math.h>
+#include "Q3Map_BspVertex.h"
+
+
+BspVertex::BspVertex()
+{
+  for (int i=0; i<3; i++)
+    mPosition[i] = 0;
+
+  for (int i=0; i<3; i++)
+    mNormal[i] = 0;
+
+  for(int i=0; i<2; i++)
+    for(int j=0; j<2; j++)
+      mTexcoord[i][j] = 0;
+}
+
+BspVertex::BspVertex(float p[3], float texcoord[2][2], float n[3])
+{
+  for (int i=0; i<3; i++)
+    mPosition[i] = p[i];
+
+  for (int i=0; i<3; i++)
+    mNormal[i] = n[i];
+
+  for(int i=0; i<2; i++)
+    for(int j=0; j<2; j++)
+    {		
+      this->mTexcoord[i][j] = texcoord[i][j];
+    }
+}
+
+BspVertex BspVertex::operator+(BspVertex a)
+{
+  BspVertex res;
+
+  for (int i=0; i<3; i++)
+  {
+    res.mPosition[i] = this->mPosition[i] + a.mPosition[i];
+    res.mNormal[i] = this->mNormal[i] + a.mNormal[i];
+  }
+
+  for(int i=0; i<2; i++)
+    for(int j=0; j<2; j++)
+    {			
+      res.mTexcoord[i][j] = this->mTexcoord[i][j] + a.mTexcoord[i][j];
+    }
+
+    return res;
+}
+
+BspVertex BspVertex::operator*(float a)
+{
+  BspVertex res;
+
+  for (int i=0; i<3; i++)
+  {
+    res.mPosition[i] = this->mPosition[i] * a;
+    res.mNormal[i] = this->mNormal[i] * a;
+  }
+
+  for(int i=0; i<2; i++)
+    for(int j=0; j<2; j++)
+      res.mTexcoord[i][j] = this->mTexcoord[i][j] * a;
+
+  return res;
+}
+
+void BspVertex::normalise(void)
+{
+  //QVECTOR n((float)mNormal[0], (float)mNormal[1], (float)mNormal[2]);
+
+  //D3DXVec3Normalize(&n, &n);
+  //mNormal[0] = n.x;
+  //mNormal[1] = n.y;
+  //mNormal[2] = n.z;
+
+	float flLen=sqrt( mNormal[0]*mNormal[0] + mNormal[1]*mNormal[1] + mNormal[2]*mNormal[2] ) ;
+	mNormal[0]/=flLen ;
+	mNormal[1]/=flLen ;
+	mNormal[2]/=flLen ;
+}
Index: code/trunk/src/libraries/tools/bsp/Q3Map_BspVertex.h
===================================================================
--- code/trunk/src/libraries/tools/bsp/Q3Map_BspVertex.h	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/Q3Map_BspVertex.h	(revision 7163)
@@ -0,0 +1,44 @@
+/*
+===========================================================================
+Copyright (C) 2008 Daniel Örstadius
+
+This file is part of bsp-renderer source code.
+
+bsp-renderer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+bsp-renderer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+// BspVertex.h -- used in the tessellation of the Bezier patches
+
+#ifndef _BSPVERTEX_H
+#define _BSPVERTEX_H
+
+class BspVertex
+{
+public:
+  BspVertex();
+  BspVertex(float p[3], float texcoord[2][2], float n[3]);
+
+  float mPosition[3];
+  float mTexcoord[2][2];
+  float mNormal[3];
+
+  BspVertex operator+(BspVertex a);
+  BspVertex operator*(float a);
+
+  void normalise(void);
+
+};
+
+#endif 
Index: code/trunk/src/libraries/tools/bsp/Q3Map_misc.h
===================================================================
--- code/trunk/src/libraries/tools/bsp/Q3Map_misc.h	(revision 7163)
+++ code/trunk/src/libraries/tools/bsp/Q3Map_misc.h	(revision 7163)
@@ -0,0 +1,33 @@
+/*
+===========================================================================
+Copyright (C) 2008 Daniel Örstadius
+Copyright (C) 2009 Jared Prince
+
+This file is part of bsp-renderer source code.
+
+bsp-renderer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+bsp-renderer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+// misc.h -- various definitions and functions
+
+#ifndef _MISC_H
+#define _MISC_H
+
+#define DELETE_POINTER(x) if(x) { delete x		; x=0 ; }
+#define DELETE_ARRAY(x)		if(x) { delete [] x ; x=0 ; }
+
+typedef float QVECTOR[3];
+
+#endif /* _MISC_H */
Index: code/trunk/src/libraries/util/CMakeLists.txt
===================================================================
--- code/trunk/src/libraries/util/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/libraries/util/CMakeLists.txt	(revision 7163)
@@ -27,4 +27,5 @@
   Clipboard.cc
   Clock.cc
+  Convert.cc
   CRC32.cc
   ExprParser.cc
@@ -49,6 +50,4 @@
 ORXONOX_ADD_LIBRARY(util
   FIND_HEADER_FILES
-  DEFINE_SYMBOL
-    "UTIL_SHARED_BUILD"
   LINK_LIBRARIES
     ${CEGUI_LIBRARY}
Index: code/trunk/src/libraries/util/Convert.cc
===================================================================
--- code/trunk/src/libraries/util/Convert.cc	(revision 7163)
+++ code/trunk/src/libraries/util/Convert.cc	(revision 7163)
@@ -0,0 +1,55 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Reto Grieder
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ */
+
+#include "Convert.h"
+#include "StringUtils.h"
+
+namespace orxonox
+{
+    //template <class FromType, class ToType>
+    bool ConverterExplicit<std::string, bool>::convert(bool* output, const std::string& input)
+    {
+        const std::string& stripped = getLowercase(removeTrailingWhitespaces(input));
+        if (stripped == "true" || stripped == "on" || stripped == "yes")
+        {
+            *output = true;
+            return true;
+        }
+        else if (stripped == "false" || stripped == "off" || stripped == "no")
+        {
+            *output = false;
+            return true;
+        }
+
+        std::istringstream iss(input);
+        if (iss >> (*output))
+            return true;
+        else
+            return false;
+    }
+}
Index: code/trunk/src/libraries/util/Convert.h
===================================================================
--- code/trunk/src/libraries/util/Convert.h	(revision 6906)
+++ code/trunk/src/libraries/util/Convert.h	(revision 7163)
@@ -64,5 +64,5 @@
 
     Defining your own functions:
-    There are obviously 4 ways to specifiy a user defined conversion. What should I use?
+    There are obviously 4 ways to specify a user defined conversion. What should you use?
 
     Usually, ConverterFallback fits quite well. You won't have to deal with the conversion from
@@ -70,5 +70,6 @@
 
     However if you want to overwrite an implicit conversion or an iostream operator, you really need to
-    make use of ConverterExplicit.
+    make use of ConverterExplicit. We have to do this for the Ogre classes for instance because they
+    define stream operators we don't particulary like.
 */
 
@@ -388,32 +389,9 @@
     };
 
-    // Declarations to avoid StringUtils.h include
-    _UtilExport std::string removeTrailingWhitespaces(const std::string& str);
-    _UtilExport std::string getLowercase(const std::string& str);
-
     // std::string to bool
     template <>
-    struct ConverterExplicit<std::string, bool>
-    {
-        static bool convert(bool* output, const std::string& input)
-        {
-            const std::string& stripped = getLowercase(removeTrailingWhitespaces(input));
-            if (stripped == "true" || stripped == "on" || stripped == "yes")
-            {
-                *output = true;
-                return true;
-            }
-            else if (stripped == "false" || stripped == "off" || stripped == "no")
-            {
-                *output = false;
-                return true;
-            }
-
-            std::istringstream iss(input);
-            if (iss >> (*output))
-                return true;
-            else
-                return false;
-        }
+    struct _UtilExport ConverterExplicit<std::string, bool>
+    {
+        static bool convert(bool* output, const std::string& input);
     };
 }
Index: code/trunk/src/libraries/util/Serialise.h
===================================================================
--- code/trunk/src/libraries/util/Serialise.h	(revision 6906)
+++ code/trunk/src/libraries/util/Serialise.h	(revision 7163)
@@ -38,4 +38,5 @@
 
 #include <cstring>
+#include <set>
 #include "Math.h"
 #include "mbool.h"
@@ -52,4 +53,33 @@
     template <class T> inline bool checkEquality( const T& variable, uint8_t* mem );
 
+  
+  // =========== char*
+    
+  inline uint32_t returnSize( char*& variable )
+  {
+    return strlen(variable)+1;
+  }
+      
+  inline void saveAndIncrease( char*& variable, uint8_t*& mem )
+  {
+    strcpy((char*)mem, variable);
+    mem += returnSize(variable);
+  }
+        
+  inline void loadAndIncrease( char*& variable, uint8_t*& mem )
+  {
+    if( variable )
+      delete variable;
+    uint32_t len = strlen((char*)mem)+1;
+    variable = new char[len];
+    strcpy((char*)variable, (char*)mem);
+    mem += len;
+  }
+          
+  inline bool checkEquality( char*& variable, uint8_t* mem )
+  {
+    return strcmp(variable, (char*)mem)==0;
+  }
+    
 // =================== Template specialisation stuff =============
 
@@ -393,5 +423,5 @@
         return memcmp(&temp, mem, sizeof(uint64_t))==0;
     }
-
+        
 // =========== string
 
@@ -635,4 +665,69 @@
         return checkEquality( (unsigned char&)((mbool&)variable).getMemory(), mem );
     }
+
+    // =========== std::set
+
+    template <class T> inline uint32_t returnSize( const std::set<T>& variable )
+    {
+        uint32_t tempsize = sizeof(uint32_t); // for the number of entries
+        for( typename std::set<T>::iterator it=((std::set<T>*)(&variable))->begin(); it!=((std::set<T>*)(&variable))->end(); ++it)
+            tempsize += returnSize( *it );
+        return tempsize;
+    }
+
+    template <class T> inline void saveAndIncrease(  const std::set<T>& variable, uint8_t*& mem )
+    {
+        typename std::set<T>::const_iterator it = variable.begin();
+        saveAndIncrease( (uint32_t)variable.size(), mem );
+        for( ; it!=variable.end(); ++it )
+            saveAndIncrease( *it, mem );
+    }
+
+    template <class T> inline void loadAndIncrease( const std::set<T>& variable, uint8_t*& mem )
+    {
+        uint32_t nrOfElements = 0;
+        loadAndIncrease( nrOfElements, mem );
+        typename std::set<T>::const_iterator it = variable.begin();
+        for( uint32_t i = 0; i<nrOfElements; ++i )
+        {
+            T temp;
+            loadAndIncrease(temp, mem);
+            while( it!=variable.end() && *it!=temp )
+            {
+                ((std::set<T>*)(&variable))->erase(it++);
+                ++it;
+            }
+            if( it==variable.end() )
+            {
+                ((std::set<T>*)(&variable))->insert(temp);
+            }
+        }
+    }
+
+    template <class T> inline bool checkEquality( const std::set<T>& variable, uint8_t* mem )
+    {
+        uint8_t* temp = mem;
+        uint32_t nrOfElements;
+        loadAndIncrease(nrOfElements, mem);
+        if( variable.size() == nrOfElements )
+        {
+            T tempT;
+            for( uint32_t i=0; i<nrOfElements; ++i )
+            {
+                loadAndIncrease(tempT, mem);
+                if( variable.find(tempT) == variable.end() )
+                {
+                    mem = temp;
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            mem = temp;
+            return false;
+        }
+        return true;
+    }
 }
 
Index: code/trunk/src/libraries/util/SignalHandler.cc
===================================================================
--- code/trunk/src/libraries/util/SignalHandler.cc	(revision 6906)
+++ code/trunk/src/libraries/util/SignalHandler.cc	(revision 7163)
@@ -124,5 +124,5 @@
       if( SignalHandler::singletonPtr_s == 0 )
       {
-        COUT(0) << "recieved signal " << sigName.c_str() << std::endl << "can't write backtrace because SignalHandler already destroyed" << std::endl;
+        COUT(0) << "received signal " << sigName.c_str() << std::endl << "can't write backtrace because SignalHandler already destroyed" << std::endl;
         exit(EXIT_FAILURE);
       }
@@ -134,5 +134,5 @@
 
 
-      COUT(0) << "recieved signal " << sigName.c_str() << std::endl << "try to write backtrace to file orxonox_crash.log" << std::endl;
+      COUT(0) << "received signal " << sigName.c_str() << std::endl << "try to write backtrace to file orxonox_crash.log" << std::endl;
 
       int sigPipe[2];
Index: code/trunk/src/libraries/util/Singleton.h
===================================================================
--- code/trunk/src/libraries/util/Singleton.h	(revision 6906)
+++ code/trunk/src/libraries/util/Singleton.h	(revision 7163)
@@ -31,5 +31,7 @@
 
 #include "UtilPrereqs.h"
+
 #include <cassert>
+#include <cstring>
 
 namespace orxonox
Index: code/trunk/src/modules/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/CMakeLists.txt	(revision 7163)
@@ -33,2 +33,3 @@
 ADD_SUBDIRECTORY(questsystem)
 ADD_SUBDIRECTORY(weapons)
+ADD_SUBDIRECTORY(designtools)
Index: code/trunk/src/modules/designtools/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/designtools/CMakeLists.txt	(revision 7163)
+++ code/trunk/src/modules/designtools/CMakeLists.txt	(revision 7163)
@@ -0,0 +1,13 @@
+SET_SOURCE_FILES(DESIGNTOOLS_SRC_FILES
+  SkyboxGenerator.cc
+  CreateStars.cc
+  ScreenshotManager.cc
+)
+
+ORXONOX_ADD_LIBRARY(designtools
+  MODULE
+  FIND_HEADER_FILES
+  LINK_LIBRARIES
+    orxonox
+  SOURCE_FILES ${DESIGNTOOLS_SRC_FILES}
+)
Index: code/trunk/src/modules/designtools/CreateStars.cc
===================================================================
--- code/trunk/src/modules/designtools/CreateStars.cc	(revision 7163)
+++ code/trunk/src/modules/designtools/CreateStars.cc	(revision 7163)
@@ -0,0 +1,125 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Gion-Andri Cantieni
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "CreateStars.h"
+
+#include <OgreVector3.h>
+
+#include "core/CoreIncludes.h"
+#include "core/XMLPort.h"
+#include "graphics/Billboard.h"
+
+namespace orxonox
+{
+    CreateFactory(CreateStars);
+
+    static const float pi = 3.14159265359f;
+
+    CreateStars::CreateStars(BaseObject* creator) : BaseObject(creator)
+    {
+        RegisterObject(CreateStars);
+        this->material_ = "Examples/Flare";
+        this->alpha_ = 0.7f;
+        this->alphaDiff_ = 0.5f;
+        this->radiusDiff_ = 0.9f;
+        this->colour_.r = 1;
+        this->colour_.g = 1;
+        this->colour_.b = 1;
+        this->colourDiff_ = 0.1f;
+    }
+
+    CreateStars::~CreateStars()
+    {
+        while( billboards_.size()!=0 )
+        {
+            billboards_.back()->destroy();
+            billboards_.pop_back();
+
+        }
+
+        billboards_.clear();
+    }
+
+    void CreateStars::createBillboards()
+    {
+
+        for(int i=0; i < numStars_; i++)
+        {
+            Billboard* bb = new Billboard(this);
+
+            float r = rnd(-colourDiff_,colourDiff_);
+            float g = rnd(-colourDiff_,colourDiff_);
+            float b = rnd(-colourDiff_,colourDiff_);
+            orxonox::ColourValue thisColour = colour_;
+            float alpha = alpha_+rnd(-alphaDiff_,alphaDiff_);
+            thisColour.r=clamp((thisColour.r+r)*alpha, 0.0f, 1.0f);
+            thisColour.g=clamp((thisColour.g+g)*alpha, 0.0f, 1.0f);
+            thisColour.b=clamp((thisColour.b+b)*alpha, 0.0f, 1.0f);
+
+            bb->setMaterial(material_);
+            bb->setColour(thisColour);
+
+            float phi;
+            float teta;
+
+            while(1)
+            {
+                phi = rnd(2*pi);
+                teta = rnd(pi);
+                float random = rnd(1);
+                if(sin(teta)>random) break;
+            }
+            float radius = rnd(radiusDiff_,1)*radius_;
+            bb->setPosition( PolarToCartesian(phi, teta, radius) );
+            billboards_.push_back(bb);
+        }
+    }
+
+    Vector3 CreateStars::PolarToCartesian(float phi, float teta, float radius)
+    {
+        float x = radius * cos(phi) * sin(teta);
+        float y = radius * sin(phi) * sin(teta);
+        float z = radius * cos(teta);
+        return Vector3(x,y,z);
+    }
+
+    void CreateStars::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(CreateStars, XMLPort, xmlelement, mode);
+
+        XMLPortParam(CreateStars, "numStars", setNumStars, getNumStars, xmlelement, mode);
+        XMLPortParam(CreateStars, "material", setMaterial, getMaterial, xmlelement, mode);
+        XMLPortParam(CreateStars, "colour", setColour, getColour, xmlelement, mode);
+        XMLPortParam(CreateStars, "alpha", setAlpha, getAlpha, xmlelement, mode);
+        XMLPortParam(CreateStars, "colourDiff", setColourDiff, getColourDiff, xmlelement, mode);
+        XMLPortParam(CreateStars, "alphaDiff", setAlphaDiff, getAlphaDiff, xmlelement, mode);
+        XMLPortParam(CreateStars, "radiusDiff", setRadiusDiff, getRadiusDiff, xmlelement, mode);
+        XMLPortParam(CreateStars, "radius", setRadius, getRadius, xmlelement, mode);
+    }
+
+}
Index: code/trunk/src/modules/designtools/CreateStars.h
===================================================================
--- code/trunk/src/modules/designtools/CreateStars.h	(revision 7163)
+++ code/trunk/src/modules/designtools/CreateStars.h	(revision 7163)
@@ -0,0 +1,126 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Gion-Andri Cantieni
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "DesignToolsPrereqs.h"
+
+#include <string>
+#include "util/Math.h"
+#include "core/BaseObject.h"
+
+namespace orxonox
+{
+    class CreateStars : public BaseObject
+    {
+        public:
+            CreateStars(orxonox::BaseObject* creator);
+            virtual ~CreateStars();
+
+            void createBillboards();
+
+            void XMLPort(Element& xmlelement, XMLPort::Mode mode);
+
+            void setNumStars(int num) {
+                this->numStars_ = num;
+            }
+
+            int getNumStars() const {
+                return this->numStars_;
+            }
+
+            void setMaterial(const std::string& material) {
+                this->material_ = material;
+            }
+
+            const std::string& getMaterial() const {
+                return this->material_;
+            }
+
+            void setColour(const orxonox::ColourValue& colour) {
+                this->colour_ = colour;
+            }
+
+            const ColourValue& getColour() const {
+                return this->colour_;
+            }
+
+            void setAlpha(float alpha) {
+                this->alpha_ = alpha;
+            }
+
+            float getAlpha() const {
+                return this->alpha_;
+            }
+
+            void setColourDiff(float colourDiff) {
+                this->colourDiff_ = colourDiff;
+            }
+
+            float getColourDiff() const {
+                return this->colourDiff_;
+            }
+
+            void setAlphaDiff(float alphaDiff) {
+                this->alphaDiff_ = alphaDiff;
+            }
+
+            float getAlphaDiff() const {
+                return this->alphaDiff_;
+            }
+
+            void setRadiusDiff(float radiusDiff) {
+                this->radiusDiff_ = radiusDiff;
+            }
+
+            float getRadiusDiff() const {
+                return this->radiusDiff_;
+            }
+
+            void setRadius(unsigned int dist) {
+                this->radius_ = dist;
+                this->createBillboards();
+            }
+
+            unsigned int getRadius()const {
+                return this->radius_;
+            }
+
+            Vector3 PolarToCartesian(float alpha, float beta, float radius);
+
+        private:
+            int numStars_;
+            std::string material_;
+            ColourValue colour_;
+            std::vector<Billboard*> billboards_;
+            unsigned int radius_;
+            float alpha_;
+            float colourDiff_;
+            float alphaDiff_;
+            float radiusDiff_;
+
+    };
+}
Index: code/trunk/src/modules/designtools/DesignToolsPrereqs.h
===================================================================
--- code/trunk/src/modules/designtools/DesignToolsPrereqs.h	(revision 7163)
+++ code/trunk/src/modules/designtools/DesignToolsPrereqs.h	(revision 7163)
@@ -0,0 +1,69 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oliver Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+/**
+@file
+@brief
+    Shared library macros, enums, constants and forward declarations for the pong module
+*/
+
+#ifndef _DesignToolsPrereqs_H__
+#define _DesignToolsPrereqs_H__
+
+#include "OrxonoxConfig.h"
+#include "OrxonoxPrereqs.h"
+
+//-----------------------------------------------------------------------
+// Shared library settings
+//-----------------------------------------------------------------------
+
+#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(DESIGNTOOLS_STATIC_BUILD)
+#  ifdef DESIGNTOOLS_SHARED_BUILD
+#    define _DesignToolsExport __declspec(dllexport)
+#  else
+#    if defined( __MINGW32__ )
+#      define _DesignToolsExport
+#    else
+#      define _DesignToolsExport __declspec(dllimport)
+#    endif
+#  endif
+#elif defined ( ORXONOX_GCC_VISIBILITY )
+#  define _DesignToolsExport  __attribute__ ((visibility("default")))
+#else
+#  define _DesignToolsExport
+#endif
+
+//-----------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------
+
+namespace orxonox
+{
+}
+
+#endif /* _DesignToolsPrereqs_H__ */
Index: code/trunk/src/modules/designtools/ScreenshotManager.cc
===================================================================
--- code/trunk/src/modules/designtools/ScreenshotManager.cc	(revision 7163)
+++ code/trunk/src/modules/designtools/ScreenshotManager.cc	(revision 7163)
@@ -0,0 +1,174 @@
+/* COPYRIGHT: this code comes from http://www.ogre3d.org/wiki/index.php/High_resolution_screenshots */
+
+#include "ScreenshotManager.h"
+
+#include <OgreRenderWindow.h>
+#include <OgreViewport.h>
+#include <OgreRenderTexture.h>
+#include <OgreCamera.h>
+#include <OgreRoot.h>
+
+#include "core/GraphicsManager.h"
+#include "core/PathConfig.h"
+#include "core/ScopedSingletonManager.h"
+#include "core/ConsoleCommand.h"
+
+#include "CameraManager.h"
+#include "graphics/Camera.h"
+
+namespace orxonox
+{
+    ManageScopedSingleton(ScreenshotManager, ScopeID::Graphics, false);
+    SetConsoleCommandAlias(ScreenshotManager, makeScreenshot_s, "printScreenHD", true);
+
+    ScreenshotManager::ScreenshotManager()
+    {
+        Ogre::RenderWindow* pRenderWindow = GraphicsManager::getInstance().getRenderWindow();
+        int gridSize = 3;
+        std::string fileExtension = ".png";
+        bool overlayFlag = true;
+
+        //set file extension for the Screenshot files
+        mFileExtension   = fileExtension;
+        // the gridsize
+        mGridSize        = gridSize;
+        // flag for overlay rendering
+        mDisableOverlays = overlayFlag;
+        //get current window size
+        mWindowWidth   = pRenderWindow->getWidth();
+        mWindowHeight  = pRenderWindow->getHeight();
+        //create temporary texture
+        mTempTex = Ogre::TextureManager::getSingleton().createManual("ScreenShotTex",
+                                                                  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D,
+                                                                    mWindowWidth, mWindowHeight,0, Ogre::PF_B8G8R8, Ogre::TU_RENDERTARGET);
+
+        //get The current Render Target of the temp Texture
+        mRT = mTempTex->getBuffer()->getRenderTarget();
+
+        //HardwarePixelBufferSharedPtr to the Buffer of the temp Texture
+        mBuffer = mTempTex->getBuffer();
+
+        //create PixelBox
+            uint8_t* data_ = new uint8_t[(mWindowWidth * mGridSize) * (mWindowHeight * mGridSize) * 3];
+        mFinalPicturePB = Ogre::PixelBox(mWindowWidth * mGridSize,mWindowHeight * mGridSize,1,Ogre::PF_B8G8R8,data_);
+
+    }
+
+
+    ScreenshotManager::~ScreenshotManager()
+    {
+        // Don't delete data_. Somehow this pointer points anywhere but to memory location.
+        //delete[] data_;
+    }
+
+
+    /* Creates a screenshot with the given camera.
+    * @param camera Pointer to the camera "looking at" the scene of interest
+    * @param fileName the filename of the screenshot file.
+    */
+    void ScreenshotManager::makeScreenshot() const
+    {
+        Ogre::Camera* camera = CameraManager::getInstance().getActiveCamera()->getOgreCamera();
+        std::string fileName = PathConfig::getInstance().getLogPathString() + "screenshot_" + this->getTimestamp();
+
+        //Remove all viewports, so the added Viewport(camera) ist the only
+        mRT->removeAllViewports();
+        mRT->addViewport(camera);
+
+        //set the viewport settings
+        Ogre::Viewport *vp = mRT->getViewport(0);
+        vp->setClearEveryFrame(true);
+        vp->setOverlaysEnabled(false);
+
+        // remind current overlay flag
+        bool enableOverlayFlag = GraphicsManager::getInstance().getViewport()->getOverlaysEnabled();
+
+        // we disable overlay rendering if it is set in config file and the viewport setting is enabled
+        if(mDisableOverlays && enableOverlayFlag)
+            GraphicsManager::getInstance().getViewport()->setOverlaysEnabled(false);
+
+        if(mGridSize <= 1)
+        {
+            // Simple case where the contents of the screen are taken directly
+            // Also used when an invalid value is passed within gridSize (zero or negative grid size)
+            mRT->update();    //render
+
+            //write the file on the Harddisk
+            mRT->writeContentsToFile(fileName + "." + mFileExtension);
+        }
+        else
+        {
+            //define the original frustum extents variables
+            Ogre::Real originalFrustumLeft, originalFrustumRight, originalFrustumTop, originalFrustumBottom;
+            // set the original Frustum extents
+            camera->getFrustumExtents(originalFrustumLeft, originalFrustumRight, originalFrustumTop, originalFrustumBottom);
+
+            // compute the Stepsize for the drid
+            Ogre::Real frustumGridStepHorizontal  = (originalFrustumRight * 2) / mGridSize;
+            Ogre::Real frustumGridStepVertical  = (originalFrustumTop * 2) / mGridSize;
+
+            // process each grid
+            Ogre::Real frustumLeft, frustumRight, frustumTop, frustumBottom;
+            for (unsigned int nbScreenshots = 0; nbScreenshots < mGridSize * mGridSize; nbScreenshots++)
+            {
+                int y = nbScreenshots / mGridSize;
+                int x = nbScreenshots - y * mGridSize;
+
+                // Shoggoth frustum extents setting
+                // compute the new frustum extents
+                frustumLeft    = originalFrustumLeft + frustumGridStepHorizontal * x;
+                frustumRight  = frustumLeft + frustumGridStepHorizontal;
+                frustumTop    = originalFrustumTop - frustumGridStepVertical * y;
+                frustumBottom  = frustumTop - frustumGridStepVertical;
+
+                // set the frustum extents value to the camera
+                camera->setFrustumExtents(frustumLeft, frustumRight, frustumTop, frustumBottom);
+
+                // ignore time duration between frames
+                Ogre::Root::getSingletonPtr()->clearEventTimes();
+                mRT->update();    //render
+
+                //define the current
+                Ogre::Box subBox = Ogre::Box(x* mWindowWidth,y * mWindowHeight,x * mWindowWidth + mWindowWidth, y * mWindowHeight + mWindowHeight);
+                //copy the content from the temp buffer into the final picture PixelBox
+                //Place the tempBuffer content at the right position
+                mBuffer->blitToMemory(mFinalPicturePB.getSubVolume(subBox));
+
+            }
+
+            // set frustum extents to previous settings
+            camera->resetFrustumExtents();
+
+            Ogre::Image finalImage; //declare the final Image Object
+            //insert the PixelBox data into the Image Object
+            finalImage = finalImage.loadDynamicImage(static_cast<unsigned char*>(mFinalPicturePB.data), mFinalPicturePB.getWidth(),mFinalPicturePB.getHeight(),Ogre::PF_B8G8R8);
+            // Save the Final image to a file
+            finalImage.save(fileName + "." + mFileExtension);
+
+        }
+
+        // do we have to re-enable our overlays?
+        if(enableOverlayFlag)
+            GraphicsManager::getInstance().getViewport()->setOverlaysEnabled(true);
+
+
+        // reset time since last frame to pause the scene
+        Ogre::Root::getSingletonPtr()->clearEventTimes();
+    }
+
+    std::string ScreenshotManager::getTimestamp()
+    {
+        struct tm *pTime;
+        time_t ctTime; time(&ctTime);
+        pTime = localtime( &ctTime );
+        std::ostringstream oss;
+        oss << std::setw(2) << std::setfill('0') << (pTime->tm_mon + 1)
+            << std::setw(2) << std::setfill('0') << pTime->tm_mday
+            << std::setw(2) << std::setfill('0') << (pTime->tm_year + 1900)
+            << "_" << std::setw(2) << std::setfill('0') << pTime->tm_hour
+            << std::setw(2) << std::setfill('0') << pTime->tm_min
+            << std::setw(2) << std::setfill('0') << pTime->tm_sec;
+        return oss.str();
+    }
+
+}
Index: code/trunk/src/modules/designtools/ScreenshotManager.h
===================================================================
--- code/trunk/src/modules/designtools/ScreenshotManager.h	(revision 7163)
+++ code/trunk/src/modules/designtools/ScreenshotManager.h	(revision 7163)
@@ -0,0 +1,70 @@
+/* COPYRIGHT: this code comes from http://www.ogre3d.org/wiki/index.php/High_resolution_screenshots */
+
+#ifndef __ScreenshotManager_h__
+#define __ScreenshotManager_h__
+
+#include "DesignToolsPrereqs.h"
+
+#include <string>
+#include <cstring>
+#include <cstdlib>
+
+#include <OgrePrerequisites.h>
+#include <OgreTexture.h>
+#include <OgreHardwarePixelBuffer.h>
+
+#include "util/Singleton.h"
+#include "core/OrxonoxClass.h"
+
+namespace orxonox
+{
+
+
+    /* Class encapsulates Screenshot functionality and provides a method for making multi grid screenshots.
+    *  pRenderWindow:    Pointer to the render window.  This could be "mWindow" from the ExampleApplication,
+    *              the window automatically created obtained when calling
+    *              Ogre::Root::getSingletonPtr()->initialise(false) and retrieved by calling
+    *              "Ogre::Root::getSingletonPtr()->getAutoCreatedWindow()", or the manually created
+    *              window from calling "mRoot->createRenderWindow()".
+    *  gridSize:      The magnification factor.  A 2 will create a 2x2 grid, doubling the size of the
+                screenshot.  A 3 will create a 3x3 grid, tripling the size of the screenshot.
+    *  fileExtension:    The extension of the screenshot file name, hence the type of graphics file to generate.
+    *              To generate "MyScreenshot.png" this parameter would contain ".png".
+    */
+    class ScreenshotManager : public OrxonoxClass, public Singleton<ScreenshotManager>
+    {
+        friend class Singleton<ScreenshotManager>;
+
+    public:
+        ScreenshotManager();
+        ~ScreenshotManager();
+
+      /* Creates a screenshot with the given camera.
+        * @param camera Pointer to the camera "looking at" the scene of interest
+        * @param fileName the filename of the screenshot file.
+      */
+        void makeScreenshot() const;
+
+        static void makeScreenshot_s()
+            { getInstance().makeScreenshot(); }
+
+    protected:
+        static std::string getTimestamp();
+
+        std::string    mFileExtension;
+        unsigned int   mGridSize, mWindowWidth, mWindowHeight;
+        bool           mDisableOverlays;
+        //temp texture with current screensize
+        Ogre::TexturePtr mTempTex;
+        Ogre::RenderTexture* mRT;
+        Ogre::HardwarePixelBufferSharedPtr mBuffer;
+        //PixelBox for a large Screenshot, if grid size is > 1
+        Ogre::PixelBox  mFinalPicturePB;
+        uint8_t* data_;
+
+        static ScreenshotManager* singletonPtr_s;
+    };
+
+}
+
+#endif  // __ScreenshotManager_h__
Index: code/trunk/src/modules/designtools/SkyboxGenerator.cc
===================================================================
--- code/trunk/src/modules/designtools/SkyboxGenerator.cc	(revision 7163)
+++ code/trunk/src/modules/designtools/SkyboxGenerator.cc	(revision 7163)
@@ -0,0 +1,159 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Gion-Andri Cantieni
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "SkyboxGenerator.h"
+
+#include <string>
+#include <cassert>
+#include <OgreRenderWindow.h>
+#include <OgreCamera.h>
+
+#include "core/ConsoleCommand.h"
+#include "core/CoreIncludes.h"
+#include "core/ConfigValueIncludes.h"
+#include "core/ScopedSingletonManager.h"
+#include "controllers/HumanController.h"
+#include "worldentities/CameraPosition.h"
+#include "worldentities/ControllableEntity.h"
+#include "core/GraphicsManager.h"
+#include "core/CommandExecutor.h"
+#include "graphics/Camera.h"
+
+
+
+namespace orxonox
+{
+
+    SetConsoleCommand(SkyboxGenerator, createSkybox, true);
+
+    ManageScopedSingleton(SkyboxGenerator, ScopeID::Graphics, false);
+
+    SkyboxGenerator::SkyboxGenerator() : iterateOverDirections_(0)
+    {
+        RegisterRootObject(SkyboxGenerator);
+
+        this->setConfigValues();
+        takeScreenshot_ = false;
+        this->captionsRemoved_ = false;
+    }
+
+    SkyboxGenerator::~SkyboxGenerator()
+    {
+
+    }
+
+    void SkyboxGenerator::setConfigValues( )
+    {
+        SetConfigValue(skyboxPrefix_, "SkyboxFile_");
+    }
+
+    void SkyboxGenerator::tick(float dt)
+    {
+        if( takeScreenshot_ == true )
+        {
+            if(!this->captionsRemoved_)
+            {
+                CommandExecutor::execute("setGametypeStatus false");
+                this->captionsRemoved_ = true;
+                return;
+            }
+
+            ControllableEntity* ce = HumanController::getLocalControllerSingleton()->getControllableEntity();
+            Camera* camera = ce->getCamera();
+            assert(ce);
+
+            Ogre::RenderWindow* w = GraphicsManager::getInstance().getRenderWindow();
+
+
+            switch (iterateOverDirections_)
+            {
+            case 0 :
+                fovy_ = camera->getOgreCamera()->getFOVy();
+                camera->getOgreCamera()->setFOVy(Degree(90));
+                aspectRatio_ = camera->getOgreCamera()->getAspectRatio();
+                camera->getOgreCamera()->setAspectRatio(1);
+                iterateOverDirections_++;
+                break;
+            case 1 :
+                w->writeContentsToFile(skyboxPrefix_+"fr.png");
+                ce->yaw(Degree(90));
+                iterateOverDirections_++;
+                break;
+
+            case 2 :
+                w->writeContentsToFile(skyboxPrefix_+"lf.png");
+                ce->yaw(Degree(90));
+                iterateOverDirections_++;
+                break;
+
+            case 3 :
+                w->writeContentsToFile(skyboxPrefix_+"bk.png");
+                ce->yaw(Degree(90));
+                iterateOverDirections_++;
+                break;
+
+            case 4 :
+                w->writeContentsToFile(skyboxPrefix_+"rt.png");
+                ce->yaw(Degree(90));
+                ce->pitch(Degree(90));
+                iterateOverDirections_++;
+                break;
+
+            case 5 :
+                w->writeContentsToFile(skyboxPrefix_+"up.png");
+                ce->pitch(Degree(180));
+                iterateOverDirections_++;
+                break;
+
+            case 6 :
+                w->writeContentsToFile(skyboxPrefix_+"dn.png");
+                ce->pitch(Degree(90));
+                iterateOverDirections_++;
+                break;
+
+            case 7 :
+                camera->getOgreCamera()->setAspectRatio(aspectRatio_);
+                camera->getOgreCamera()->setFOVy(fovy_);
+                iterateOverDirections_++;
+            case 8 :
+                iterateOverDirections_ =0;
+                takeScreenshot_ = false;
+                CommandExecutor::execute("pause");
+                CommandExecutor::execute("setGametypeStatus true");
+                this->captionsRemoved_ = false;
+            }
+
+        }
+    }
+
+    void SkyboxGenerator::createSkybox( )
+    {
+        SkyboxGenerator::getInstance().takeScreenshot_ = true;
+        CommandExecutor::execute("pause");
+    }
+}
Index: code/trunk/src/modules/designtools/SkyboxGenerator.h
===================================================================
--- code/trunk/src/modules/designtools/SkyboxGenerator.h	(revision 7163)
+++ code/trunk/src/modules/designtools/SkyboxGenerator.h	(revision 7163)
@@ -0,0 +1,58 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Gion-Andri Cantieni
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+
+#include "core/OrxonoxClass.h"
+#include "util/Singleton.h"
+#include "tools/interfaces/Tickable.h"
+#include <OgreMath.h>
+
+
+namespace orxonox
+{
+    class SkyboxGenerator : public virtual OrxonoxClass, public Singleton<SkyboxGenerator>, public Tickable
+    {
+        friend class Singleton<SkyboxGenerator>;
+
+        public:
+            SkyboxGenerator();
+            virtual ~SkyboxGenerator();
+            static void createSkybox( );
+            void setConfigValues( );
+            void tick(float dt);
+
+        private:
+            static SkyboxGenerator* singletonPtr_s;
+            std::string skyboxPrefix_;
+            bool takeScreenshot_;
+            int iterateOverDirections_;
+            float aspectRatio_;
+            Ogre::Radian fovy_;
+            bool captionsRemoved_;
+    };
+}
Index: code/trunk/src/modules/objects/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/objects/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/objects/CMakeLists.txt	(revision 7163)
@@ -15,6 +15,4 @@
   PCH_FILE
     ObjectsPrecompiledHeaders.h
-  DEFINE_SYMBOL
-    "OBJECTS_SHARED_BUILD"
   LINK_LIBRARIES
     orxonox
Index: code/trunk/src/modules/objects/ObjectsPrereqs.h
===================================================================
--- code/trunk/src/modules/objects/ObjectsPrereqs.h	(revision 6906)
+++ code/trunk/src/modules/objects/ObjectsPrereqs.h	(revision 7163)
@@ -43,5 +43,5 @@
 //-----------------------------------------------------------------------
 
-#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_STATIC_BUILD)
+#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(OBJECTS_STATIC_BUILD)
 #  ifdef OBJECTS_SHARED_BUILD
 #    define _ObjectsExport __declspec(dllexport)
Index: code/trunk/src/modules/objects/Planet.cc
===================================================================
--- code/trunk/src/modules/objects/Planet.cc	(revision 6906)
+++ code/trunk/src/modules/objects/Planet.cc	(revision 7163)
@@ -70,5 +70,5 @@
         {
             Camera* activeCamera = CameraManager::getInstance().getActiveCamera();
-            if (activeCamera)
+            if (activeCamera && this->billboard_.getBillboardSet())
             {
                 float distance = this->getPosition().distance( activeCamera->getWorldPosition() );
@@ -89,49 +89,52 @@
     void Planet::init()
     {
-        float scaleFactor = this->getScale();
-
-#if OGRE_VERSION >= 0x010700
-        Ogre::Mesh::LodValueList distList;
-#else
-        Ogre::Mesh::LodDistanceList distList;
-#endif
-
-        distList.push_back(10.0f*scaleFactor);
-        distList.push_back(19.0f*scaleFactor);
-        distList.push_back(27.0f*scaleFactor);
-        distList.push_back(34.0f*scaleFactor);
-        distList.push_back(40.0f*scaleFactor);
-        distList.push_back(45.0f*scaleFactor);
-        distList.push_back(49.0f*scaleFactor);
-        distList.push_back(52.0f*scaleFactor);
-        distList.push_back(54.0f*scaleFactor);
-        distList.push_back(55.0f*scaleFactor);
-
-        float reductionValue = 0.2f;
-
-        this->mesh_.getEntity()->getMesh()->generateLodLevels(distList, Ogre::ProgressiveMesh::VRQ_PROPORTIONAL, reductionValue);
-        billboard_.setBillboardSet(this->getScene()->getSceneManager(), this->atmosphere_, Vector3(0,0,0));
-
-        this->attachOgreObject(this->billboard_.getBillboardSet());
-        this->billboard_.getBillboardSet()->setUseAccurateFacing(true);
-        this->setCastShadows(true);
-        this->billboard_.getBillboardSet()->setRenderQueueGroup(this->mesh_.getEntity()->getRenderQueueGroup());
-        this->mesh_.setCastShadows(true);
     }
 
     void Planet::changedMesh()
     {
-        if (this->mesh_.getEntity())
-            this->detachOgreObject(this->mesh_.getEntity());
+        if( GameMode::showsGraphics() )
+        {
+            if (this->mesh_.getEntity())
+                this->detachOgreObject(this->mesh_.getEntity());
 
-        this->mesh_.setMeshSource(this->getScene()->getSceneManager(), this->meshSrc_);
+            this->mesh_.setMeshSource(this->getScene()->getSceneManager(), this->meshSrc_);
 
-        if (this->mesh_.getEntity())
-        {
-            this->attachOgreObject(this->mesh_.getEntity());
-            this->mesh_.getEntity()->setCastShadows(this->bCastShadows_);
-            this->mesh_.setVisible(this->isVisible());
+            if (this->mesh_.getEntity())
+            {
+                this->attachOgreObject(this->mesh_.getEntity());
+                this->mesh_.getEntity()->setCastShadows(this->bCastShadows_);
+                this->mesh_.setVisible(this->isVisible());
+
+                float scaleFactor = this->getScale();
+
+    #if OGRE_VERSION >= 0x010700
+                Ogre::Mesh::LodValueList distList;
+    #else
+                Ogre::Mesh::LodDistanceList distList;
+    #endif
+
+                distList.push_back(10.0f*scaleFactor);
+                distList.push_back(19.0f*scaleFactor);
+                distList.push_back(27.0f*scaleFactor);
+                distList.push_back(34.0f*scaleFactor);
+                distList.push_back(40.0f*scaleFactor);
+                distList.push_back(45.0f*scaleFactor);
+                distList.push_back(49.0f*scaleFactor);
+                distList.push_back(52.0f*scaleFactor);
+                distList.push_back(54.0f*scaleFactor);
+                distList.push_back(55.0f*scaleFactor);
+
+                float reductionValue = 0.2f;
+
+                this->mesh_.getEntity()->getMesh()->generateLodLevels(distList, Ogre::ProgressiveMesh::VRQ_PROPORTIONAL, reductionValue);
+                billboard_.setBillboardSet(this->getScene()->getSceneManager(), this->atmosphere_, Vector3(0,0,0));
+
+                this->attachOgreObject(this->billboard_.getBillboardSet());
+                this->billboard_.getBillboardSet()->setUseAccurateFacing(true);
+                this->setCastShadows(true);
+                this->billboard_.getBillboardSet()->setRenderQueueGroup(this->mesh_.getEntity()->getRenderQueueGroup());
+                this->mesh_.setCastShadows(true);
+            }
         }
-        this->init();
     }
 
@@ -151,12 +154,9 @@
         SUPER(Planet, XMLPort, xmlelement, mode);
 
-        if (GameMode::showsGraphics())
-        {
-            XMLPortParam(Planet, "atmosphere", setAtmosphere, getAtmosphere, xmlelement, mode).defaultValues("planet/Atmosphere");
-            XMLPortParam(Planet, "atmospheresize", setAtmosphereSize, getAtmosphereSize, xmlelement,mode);
-            XMLPortParam(Planet, "imagesize", setImageSize, getImageSize, xmlelement,mode);
-            XMLPortParam(Planet, "mesh", setMeshSource, getMeshSource, xmlelement, mode);
-            XMLPortParam(Planet, "shadow", setCastShadows, getCastShadows, xmlelement, mode).defaultValues(true);
-        }
+        XMLPortParam(Planet, "atmosphere", setAtmosphere, getAtmosphere, xmlelement, mode).defaultValues("planet/Atmosphere");
+        XMLPortParam(Planet, "atmospheresize", setAtmosphereSize, getAtmosphereSize, xmlelement,mode);
+        XMLPortParam(Planet, "imagesize", setImageSize, getImageSize, xmlelement,mode);
+        XMLPortParam(Planet, "mesh", setMeshSource, getMeshSource, xmlelement, mode);
+        XMLPortParam(Planet, "shadow", setCastShadows, getCastShadows, xmlelement, mode).defaultValues(true);
     }
 
@@ -164,8 +164,9 @@
     {
         registerVariable(this->atmosphere_, VariableDirection::ToClient);
+        registerVariable(this->atmosphereSize, VariableDirection::ToClient);
+        registerVariable(this->imageSize, VariableDirection::ToClient);
+        // Note: the meshSrc should be synchronised after atmosphere and other values, because the meshSrc callback setts the atmosphere billboards
         registerVariable(this->meshSrc_, VariableDirection::ToClient, new NetworkCallback<Planet>(this, &Planet::changedMesh));
         registerVariable(this->bCastShadows_, VariableDirection::ToClient, new NetworkCallback<Planet>(this, &Planet::changedShadows));
-        registerVariable(this->atmosphereSize, VariableDirection::ToClient);
-        registerVariable(this->imageSize, VariableDirection::ToClient);
     }
 
Index: code/trunk/src/modules/objects/Planet.h
===================================================================
--- code/trunk/src/modules/objects/Planet.h	(revision 6906)
+++ code/trunk/src/modules/objects/Planet.h	(revision 7163)
@@ -94,7 +94,7 @@
 
         protected:
-            void registerVariables();
 
         private:
+            void registerVariables();
 
             void changedMesh();
Index: code/trunk/src/modules/objects/collisionshapes/BoxCollisionShape.h
===================================================================
--- code/trunk/src/modules/objects/collisionshapes/BoxCollisionShape.h	(revision 6906)
+++ code/trunk/src/modules/objects/collisionshapes/BoxCollisionShape.h	(revision 7163)
@@ -43,5 +43,4 @@
             virtual ~BoxCollisionShape();
 
-            void registerVariables();
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
 
@@ -67,4 +66,6 @@
 
         private:
+            void registerVariables();
+
             btCollisionShape* createNewShape() const;
 
Index: code/trunk/src/modules/objects/collisionshapes/ConeCollisionShape.h
===================================================================
--- code/trunk/src/modules/objects/collisionshapes/ConeCollisionShape.h	(revision 6906)
+++ code/trunk/src/modules/objects/collisionshapes/ConeCollisionShape.h	(revision 7163)
@@ -41,5 +41,4 @@
             virtual ~ConeCollisionShape();
 
-            void registerVariables();
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
 
@@ -55,4 +54,6 @@
 
         private:
+            void registerVariables();
+
             btCollisionShape* createNewShape() const;
 
Index: code/trunk/src/modules/objects/collisionshapes/PlaneCollisionShape.h
===================================================================
--- code/trunk/src/modules/objects/collisionshapes/PlaneCollisionShape.h	(revision 6906)
+++ code/trunk/src/modules/objects/collisionshapes/PlaneCollisionShape.h	(revision 7163)
@@ -43,5 +43,4 @@
             virtual ~PlaneCollisionShape();
 
-            void registerVariables();
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
 
@@ -57,4 +56,6 @@
 
         private:
+            void registerVariables();
+
             btCollisionShape* createNewShape()const;
 
Index: code/trunk/src/modules/objects/collisionshapes/SphereCollisionShape.h
===================================================================
--- code/trunk/src/modules/objects/collisionshapes/SphereCollisionShape.h	(revision 6906)
+++ code/trunk/src/modules/objects/collisionshapes/SphereCollisionShape.h	(revision 7163)
@@ -41,5 +41,4 @@
             virtual ~SphereCollisionShape();
 
-            void registerVariables();
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
 
@@ -50,4 +49,6 @@
 
         private:
+            void registerVariables();
+
             btCollisionShape* createNewShape() const;
 
Index: code/trunk/src/modules/objects/eventsystem/EventListener.cc
===================================================================
--- code/trunk/src/modules/objects/eventsystem/EventListener.cc	(revision 6906)
+++ code/trunk/src/modules/objects/eventsystem/EventListener.cc	(revision 7163)
@@ -61,5 +61,5 @@
             return;
         }
-        
+
         COUT(4) << "EventListener, processing event: originator: " << event.originator_->getIdentifier()->getName() << " (&" << event.originator_ << ")" << ", activate: " << event.activate_ << ", name: " << event.name_ << std::endl;
 
Index: code/trunk/src/modules/objects/triggers/CheckPoint.cc
===================================================================
--- code/trunk/src/modules/objects/triggers/CheckPoint.cc	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/CheckPoint.cc	(revision 7163)
@@ -38,5 +38,7 @@
     CreateFactory(CheckPoint);
 
-    CheckPoint::CheckPoint(BaseObject* creator) : DistanceTrigger(creator)
+    CheckPoint::CheckPoint(BaseObject* creator)
+        : DistanceTrigger(creator)
+        , RadarViewable(creator, static_cast<WorldEntity*>(this))
     {
         RegisterObject(CheckPoint);
Index: code/trunk/src/modules/objects/triggers/DistanceMultiTrigger.cc
===================================================================
--- code/trunk/src/modules/objects/triggers/DistanceMultiTrigger.cc	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/DistanceMultiTrigger.cc	(revision 7163)
@@ -40,15 +40,15 @@
 namespace orxonox
 {
-    
+
     CreateFactory(DistanceMultiTrigger);
 
     /**
     @brief
-        Default Constructor. Registers the object and initializes default values. 
+        Default Constructor. Registers the object and initializes default values.
     */
     DistanceMultiTrigger::DistanceMultiTrigger(BaseObject* creator) : MultiTrigger(creator)
     {
         RegisterObject(DistanceMultiTrigger);
-        
+
         this->distance_ = 100.0f;
         this->targetName_ = BLANKSTRING;
@@ -98,5 +98,5 @@
                 continue;
             }
-            
+
             Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
             // If the object is no longer in range.
@@ -154,5 +154,5 @@
                 if(this->singleTargetMode_)
                     entity = entity->getParent();
-                
+
                 // If no queue has been created, yet.
                 if(queue == NULL)
@@ -166,7 +166,7 @@
             }
         }
-        
+
         return queue;
     }
-    
+
 }
Index: code/trunk/src/modules/objects/triggers/DistanceMultiTrigger.h
===================================================================
--- code/trunk/src/modules/objects/triggers/DistanceMultiTrigger.h	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/DistanceMultiTrigger.h	(revision 7163)
@@ -56,9 +56,9 @@
     class _ObjectsExport DistanceMultiTrigger : public MultiTrigger
     {
-        
+
         public:
             DistanceMultiTrigger(BaseObject* creator); //!< Default Constructor. Registers the object and initializes default values.
             ~DistanceMultiTrigger(); //!< Destructor.
-            
+
             void XMLPort(Element& xmlelement, XMLPort::Mode mode); //!< Method for creating a DistanceMultiTrigger object through XML.
 
@@ -75,5 +75,5 @@
             inline const std::string& getTargetName(void)
                 { return this->targetName_; }
-            
+
             /**
             @brief Set the distance at which the DistanceMultiTrigger triggers.
@@ -88,5 +88,5 @@
             inline float getDistance() const
                 { return this->distance_; }
-                
+
         protected:
             virtual std::queue<MultiTriggerState*>* letTrigger(void); //!< This method is called by the MultiTrigger to get information about new trigger events that need to be looked at.
@@ -106,14 +106,14 @@
             inline bool removeFromRange(WorldEntity* entity)
                 { WeakPtr<WorldEntity>* weakptr = this->range_.find(entity)->second; bool erased = this->range_.erase(entity) > 0; if(erased) delete weakptr; return erased; }
-                
+
         private:
             float distance_; //!< The distance at which the DistanceMultiTrigger triggers.
             std::string targetName_; //!< The target name, used in singleTargetMode.
             bool singleTargetMode_; //!< To indicate whe the MultiDistanceTrigger is in single-target-mode.
-            
+
             std::map<WorldEntity*, WeakPtr<WorldEntity>* > range_; //!< The set of entities that currently are in range of the DistanceMultiTrigger.
-        
+
     };
-    
+
 }
 
Index: code/trunk/src/modules/objects/triggers/DistanceTrigger.cc
===================================================================
--- code/trunk/src/modules/objects/triggers/DistanceTrigger.cc	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/DistanceTrigger.cc	(revision 7163)
@@ -136,5 +136,5 @@
           continue;
       }
-      
+
       Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
       if (distanceVec.length() < this->distance_)
@@ -155,4 +155,5 @@
       }
     }
+
     return false;
   }
Index: code/trunk/src/modules/objects/triggers/DistanceTriggerBeacon.cc
===================================================================
--- code/trunk/src/modules/objects/triggers/DistanceTriggerBeacon.cc	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/DistanceTriggerBeacon.cc	(revision 7163)
@@ -35,9 +35,9 @@
 
     CreateFactory(DistanceTriggerBeacon);
-    
+
     DistanceTriggerBeacon::DistanceTriggerBeacon(BaseObject* creator) : StaticEntity(creator)
     {
         RegisterObject(DistanceTriggerBeacon);
     }
-    
+
 }
Index: code/trunk/src/modules/objects/triggers/DistanceTriggerBeacon.h
===================================================================
--- code/trunk/src/modules/objects/triggers/DistanceTriggerBeacon.h	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/DistanceTriggerBeacon.h	(revision 7163)
@@ -39,5 +39,5 @@
     class _ObjectsExport DistanceTriggerBeacon : public StaticEntity
     {
-        
+
         public:
 
Index: code/trunk/src/modules/objects/triggers/EventMultiTrigger.cc
===================================================================
--- code/trunk/src/modules/objects/triggers/EventMultiTrigger.cc	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/EventMultiTrigger.cc	(revision 7163)
@@ -52,5 +52,5 @@
     EventMultiTrigger::~EventMultiTrigger()
     {
-        
+
     }
 
@@ -61,5 +61,5 @@
         this->setBroadcast(true);
     }
-    
+
     void EventMultiTrigger::XMLEventPort(Element& xmlelement, XMLPort::Mode mode)
     {
Index: code/trunk/src/modules/objects/triggers/EventMultiTrigger.h
===================================================================
--- code/trunk/src/modules/objects/triggers/EventMultiTrigger.h	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/EventMultiTrigger.h	(revision 7163)
@@ -44,5 +44,5 @@
     class _ObjectsExport EventMultiTrigger : public MultiTrigger
     {
-        
+
         public:
             EventMultiTrigger(BaseObject* creator);
Index: code/trunk/src/modules/objects/triggers/MultiTrigger.cc
===================================================================
--- code/trunk/src/modules/objects/triggers/MultiTrigger.cc	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/MultiTrigger.cc	(revision 7163)
@@ -47,5 +47,5 @@
     /*static*/ const std::string MultiTrigger::or_s = "or";
     /*static*/ const std::string MultiTrigger::xor_s = "xor";
-    
+
     CreateFactory(MultiTrigger);
 
@@ -65,5 +65,5 @@
         this->bSwitch_ = false;
         this->bStayActive_ = false;
-        
+
         this->remainingActivations_ = INF_s;
         this->maxNumSimultaniousTriggerers_ = INF_s;
@@ -75,10 +75,10 @@
 
         this->parentTrigger_ = NULL;
-        
+
         this->targetMask_.exclude(Class(BaseObject));
 
         this->setSyncMode(0x0);
     }
-    
+
     /**
     @brief
@@ -95,5 +95,5 @@
         }
     }
-    
+
     /**
     @brief
@@ -117,8 +117,8 @@
         //TODO: Maybe nicer with explicit subgroup, e.g. triggers
         XMLPortObject(MultiTrigger, MultiTrigger, "", addTrigger, getTrigger, xmlelement, mode);
-        
+
         COUT(4) << "MultiTrigger '" << this->getName() << "' (&" << this << ") created." << std::endl;
     }
-    
+
 
     /**
@@ -131,5 +131,5 @@
     {
         // If this is the first tick.
-        //TODO: Determine need for this, else kick it out. 
+        //TODO: Determine need for this, else kick it out.
         if(this->bFirstTick_)
         {
@@ -174,5 +174,5 @@
                     delete state;
                 }
-                
+
                 queue->pop();
             }
@@ -185,5 +185,5 @@
             MultiTriggerState* state;
             float timeRemaining;
-            
+
             // Go through all pending states.
             for(int size = this->stateQueue_.size(); size >= 1; size--)
@@ -212,5 +212,5 @@
                                 this->triggered_.erase(state->originator);
                             }
-                            
+
                             bStateChanged = true;
                         }
@@ -229,5 +229,5 @@
 
                             bool bFire = true;
-                            
+
                             // Add the originator to the objects activating this MultiTrigger.
                             if(bActive == true)
@@ -266,5 +266,5 @@
                                 else
                                     this->fire(bActive, state->originator);
-                                
+
                                 bStateChanged = true;
                             }
@@ -289,5 +289,5 @@
                         }
                     }
-                    
+
                     // Remove the state from the state queue.
                     this->stateQueue_.pop_front();
@@ -509,8 +509,8 @@
             return returnVal;
         }
-        
+
         return true;
     }
-    
+
     /**
     @brief
@@ -547,5 +547,5 @@
             return;
         }
-        
+
         MultiTriggerContainer* container = new MultiTriggerContainer(this, this, originator);
         this->fireEvent(status, container);
@@ -563,5 +563,5 @@
     {
         ClassTreeMask& targetMask = this->getTargetMask();
-        
+
         for(ClassTreeMaskObjectIterator it = targetMask.begin(); it != targetMask.end(); ++it)
         {
@@ -580,9 +580,9 @@
     {
         assert(state);
-        
+
         // If the originator is no target of this MultiTrigger.
         if(!this->isTarget(state->originator))
             return false;
-        
+
         // Add it ot the state queue.
         this->stateQueue_.push_back(std::pair<float, MultiTriggerState*>(this->delay_, state));
Index: code/trunk/src/modules/objects/triggers/MultiTrigger.h
===================================================================
--- code/trunk/src/modules/objects/triggers/MultiTrigger.h	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/MultiTrigger.h	(revision 7163)
@@ -94,8 +94,8 @@
             MultiTrigger(BaseObject* creator); //!< Constructor. Registers the objects and initializes default values.
             ~MultiTrigger(); //!< Destructor.
-            
+
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); //!< Method for creating a MultiTrigger object through XML.
             virtual void tick(float dt); //!< A method that is executed each tick.
-            
+
             bool isActive(BaseObject* triggerer = NULL); //!< Get whether the MultiTrigger is active for a given object.
 
@@ -215,13 +215,13 @@
             void addTargets(const std::string& targets); //!< Add some target to the MultiTrigger.
             void removeTargets(const std::string& targets); //!< Remove some target from the MultiTrigger.
-            
+
             void addTrigger(MultiTrigger* trigger); //!< Adds a MultiTrigger as a sub-trigger to the trigger.
             const MultiTrigger* getTrigger(unsigned int index) const; //!< Get the sub-trigger of this MultiTrigger at the given index.
-            
+
         protected:
             virtual std::queue<MultiTriggerState*>* letTrigger(void); //!< This method is called by the MultiTrigger to get information about new trigger events that need to be looked at.
 
             void changeTriggered(BaseObject* originator = NULL); //!< This method can be called by any class inheriting from MultiTrigger to change it's triggered status for a specified originator.
-            
+
             bool isModeTriggered(BaseObject* triggerer = NULL); //!< Checks whetherx the MultiTrigger is triggered concerning it's sub-triggers.
             bool isTriggered(BaseObject* triggerer = NULL); //!< Get whether the MultiTrigger is triggered for a given object.
@@ -236,5 +236,5 @@
             inline void addParentTrigger(MultiTrigger* parent)
                 { this->parentTrigger_ = parent; }
-            
+
             /**
             @brief Get the target mask used to identify the targets of this MultiTrigger.
@@ -248,5 +248,5 @@
             //TODO: Check if something mus be done here.
             virtual void notifyMaskUpdate(void) {}
-            
+
         private:
             static const int INF_s; //!< Magic number for infinity.
@@ -257,7 +257,7 @@
 
             void subTrigggerActivityChanged(BaseObject* originator); //!< This method is called by any sub-trigger to advertise changes in it's state to it's parent-trigger.
-            
+
             bool addState(MultiTriggerState* state); //!< Helper method. Adds a state to the state queue, where the state will wait to become active.
-            
+
             bool checkAnd(BaseObject* triggerer); //!< Checks whether the sub-triggers amount to true for the 'and' mode for a given object.
             bool checkOr(BaseObject* triggerer); //!< Checks whether the sub-triggers amount to true for the 'or' mode for a given object.
@@ -276,5 +276,5 @@
             bool bSwitch_; //!< Bool for the switch-mode, if true the MultiTrigger behaves like a switch.
             bool bStayActive_; //!< Bool for the stay-active-mode, if true the MultiTrigger stays active after its last activation.;
-            
+
             int remainingActivations_; //!< The remaining activations of this MultiTrigger.
             int maxNumSimultaniousTriggerers_; //!< The maximum number of objects simultaniously trigggering this MultiTrigger.
@@ -287,12 +287,12 @@
             MultiTrigger* parentTrigger_;
             std::set<MultiTrigger*> subTriggers_; //!< The sub-triggers of this MultiTrigger.
-            
+
             std::set<BaseObject*> active_; //!< The set of all objects the MultiTrigger is active for.
             std::set<BaseObject*> triggered_; //!< The set of all objects the MultiTrigger is triggered for.
 
             std::deque< std::pair<float, MultiTriggerState*> > stateQueue_; //!< The queue of states waiting to become active.
-            
+
             ClassTreeMask targetMask_; //!< The target mask, masking all objects that can trigger this MultiTrigger.
-            
+
     };
 
Index: code/trunk/src/modules/objects/triggers/MultiTriggerContainer.cc
===================================================================
--- code/trunk/src/modules/objects/triggers/MultiTriggerContainer.cc	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/MultiTriggerContainer.cc	(revision 7163)
@@ -40,5 +40,5 @@
 
     CreateUnloadableFactory(MultiTriggerContainer);
-    
+
     /**
     @brief
@@ -73,5 +73,5 @@
     MultiTriggerContainer::~MultiTriggerContainer()
     {
-        
+
     }
 
Index: code/trunk/src/modules/objects/triggers/MultiTriggerContainer.h
===================================================================
--- code/trunk/src/modules/objects/triggers/MultiTriggerContainer.h	(revision 6906)
+++ code/trunk/src/modules/objects/triggers/MultiTriggerContainer.h	(revision 7163)
@@ -50,5 +50,5 @@
     class _ObjectsExport MultiTriggerContainer : public BaseObject
     {
-        
+
         public:
             MultiTriggerContainer(BaseObject* creator); //!< Default constructor. Registers the object and creates an empty container.
@@ -68,10 +68,10 @@
             inline BaseObject* getData(void)
                 { return this->data_; }
-            
+
         private:
             MultiTrigger* originator_; //!< The originator.
             BaseObject* data_; //!< The data.
     };
-    
+
 }
 
Index: code/trunk/src/modules/overlays/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/overlays/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/overlays/CMakeLists.txt	(revision 7163)
@@ -14,6 +14,4 @@
   PCH_FILE
     OverlaysPrecompiledHeaders.h
-  DEFINE_SYMBOL
-    "OVERLAYS_SHARED_BUILD"
   LINK_LIBRARIES
     orxonox
Index: code/trunk/src/modules/overlays/GUIOverlay.cc
===================================================================
--- code/trunk/src/modules/overlays/GUIOverlay.cc	(revision 6906)
+++ code/trunk/src/modules/overlays/GUIOverlay.cc	(revision 7163)
@@ -30,6 +30,6 @@
 
 #include <string>
-#include <sstream>
 
+#include "util/Convert.h"
 #include "core/input/InputManager.h"
 #include "core/CoreIncludes.h"
@@ -73,7 +73,5 @@
         if (this->isVisible())
         {
-            std::ostringstream out;
-            out << reinterpret_cast<long>(this);
-            const std::string& str = out.str();
+            const std::string& str = multi_cast<std::string>(reinterpret_cast<long>(this));
             GUIManager::getInstance().showGUIExtra(this->guiName_, str);
 
Index: code/trunk/src/modules/overlays/OverlaysPrereqs.h
===================================================================
--- code/trunk/src/modules/overlays/OverlaysPrereqs.h	(revision 6906)
+++ code/trunk/src/modules/overlays/OverlaysPrereqs.h	(revision 7163)
@@ -43,5 +43,5 @@
 //-----------------------------------------------------------------------
 
-#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_STATIC_BUILD)
+#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(OVERLAYS_STATIC_BUILD)
 #  ifdef OVERLAYS_SHARED_BUILD
 #    define _OverlaysExport __declspec(dllexport)
@@ -78,4 +78,6 @@
     class ChatOverlay;
     class DeathMessage;
+    class GametypeFadingMessage;
+    class GametypeStaticMessage;
     class GametypeStatus;
     class HUDBar;
Index: code/trunk/src/modules/overlays/hud/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/overlays/hud/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/overlays/hud/CMakeLists.txt	(revision 7163)
@@ -13,3 +13,5 @@
   UnderAttackHealthBar.cc
   TeamBaseMatchScore.cc
+  GametypeStaticMessage.cc
+  GametypeFadingMessage.cc
 )
Index: code/trunk/src/modules/overlays/hud/GametypeFadingMessage.cc
===================================================================
--- code/trunk/src/modules/overlays/hud/GametypeFadingMessage.cc	(revision 7163)
+++ code/trunk/src/modules/overlays/hud/GametypeFadingMessage.cc	(revision 7163)
@@ -0,0 +1,62 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "GametypeFadingMessage.h"
+
+#include "core/CoreIncludes.h"
+#include "infos/PlayerInfo.h"
+
+namespace orxonox
+{
+    CreateFactory(GametypeFadingMessage);
+
+    GametypeFadingMessage::GametypeFadingMessage(BaseObject* creator) : FadeoutText(creator)
+    {
+        RegisterObject(GametypeFadingMessage);
+
+        this->owner_ = 0;
+        this->setDelay(2.0f);
+        this->setFadeouttime(0.5f);
+    }
+
+    GametypeFadingMessage::~GametypeFadingMessage()
+    {
+    }
+
+    void GametypeFadingMessage::fadingmessage(const GametypeInfo* gtinfo, const std::string& message)
+    {
+        if (this->owner_ && this->owner_->getGametypeInfo() == gtinfo)
+            this->setCaption(message);
+    }
+
+    void GametypeFadingMessage::changedOwner()
+    {
+        SUPER(GametypeFadingMessage, changedOwner);
+        this->owner_ = orxonox_cast<PlayerInfo*>(this->getOwner());
+    }
+}
Index: code/trunk/src/modules/overlays/hud/GametypeFadingMessage.h
===================================================================
--- code/trunk/src/modules/overlays/hud/GametypeFadingMessage.h	(revision 7163)
+++ code/trunk/src/modules/overlays/hud/GametypeFadingMessage.h	(revision 7163)
@@ -0,0 +1,53 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _GametypeInfoMessage_H__
+#define _GametypeInfoMessage_H__
+
+#include "overlays/OverlaysPrereqs.h"
+
+#include "interfaces/GametypeMessageListener.h"
+#include "overlays/FadeoutText.h"
+
+namespace orxonox
+{
+    class _OverlaysExport GametypeFadingMessage : public FadeoutText, GametypeMessageListener
+    {
+        public:
+            GametypeFadingMessage(BaseObject* creator);
+            virtual ~GametypeFadingMessage();
+
+            virtual void changedOwner();
+
+            void fadingmessage(const GametypeInfo* gtinfo, const std::string& message);
+
+        private:
+            PlayerInfo* owner_;
+    };
+}
+#endif /* _GametypeFadingMessage_H__ */
Index: code/trunk/src/modules/overlays/hud/GametypeStaticMessage.cc
===================================================================
--- code/trunk/src/modules/overlays/hud/GametypeStaticMessage.cc	(revision 7163)
+++ code/trunk/src/modules/overlays/hud/GametypeStaticMessage.cc	(revision 7163)
@@ -0,0 +1,66 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "GametypeStaticMessage.h"
+
+#include "core/CoreIncludes.h"
+#include "infos/GametypeInfo.h"
+#include "infos/PlayerInfo.h"
+
+
+namespace orxonox
+{
+    CreateFactory(GametypeStaticMessage);
+
+
+    GametypeStaticMessage::GametypeStaticMessage(BaseObject* creator) : OverlayText(creator)
+    {
+        RegisterObject(GametypeStaticMessage);
+        this->owner_ = 0;
+    }
+
+    GametypeStaticMessage::~GametypeStaticMessage()
+    {
+    }
+
+    void GametypeStaticMessage::staticmessage(const GametypeInfo* gtinfo, const std::string& message, const ColourValue& colour)
+    {
+    if (this->owner_ && this->owner_->getGametypeInfo() == gtinfo)
+    {
+        this->setColour(colour);
+        this->setCaption(message);
+    }
+    }
+
+    void GametypeStaticMessage::changedOwner()
+    {
+        SUPER(GametypeStaticMessage, changedOwner);
+        this->owner_ = orxonox_cast<PlayerInfo*>(this->getOwner());
+    }
+
+}
Index: code/trunk/src/modules/overlays/hud/GametypeStaticMessage.h
===================================================================
--- code/trunk/src/modules/overlays/hud/GametypeStaticMessage.h	(revision 7163)
+++ code/trunk/src/modules/overlays/hud/GametypeStaticMessage.h	(revision 7163)
@@ -0,0 +1,56 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _GametypeInfoMessage_H__
+#define _GametypeInfoMessage_H__
+
+#include "overlays/OverlaysPrereqs.h"
+
+#include "interfaces/GametypeMessageListener.h"
+#include "overlays/OverlayText.h"
+/*Goal: Every Gametype could add a hud-element that displays text in the gametype. For example instructions for newbies.
+-> you have to add a "GametypeInfoMessage"-object that displays text. How the message change has to be defined in the gametype.
+*/
+
+namespace orxonox
+{
+    class _OverlaysExport GametypeStaticMessage : public OverlayText, GametypeMessageListener
+    {
+        public:
+            GametypeStaticMessage(BaseObject* creator);
+            virtual ~GametypeStaticMessage();
+
+            virtual void changedOwner();
+
+            void staticmessage(const GametypeInfo* gtinfo, const std::string& message, const ColourValue& colour);
+
+        private:
+            PlayerInfo* owner_;
+    };
+}
+#endif /* _GametypeInfoMessage_H__ */
Index: code/trunk/src/modules/overlays/hud/GametypeStatus.cc
===================================================================
--- code/trunk/src/modules/overlays/hud/GametypeStatus.cc	(revision 6906)
+++ code/trunk/src/modules/overlays/hud/GametypeStatus.cc	(revision 7163)
@@ -30,4 +30,5 @@
 
 #include "util/Convert.h"
+#include "core/ConsoleCommand.h"
 #include "core/CoreIncludes.h"
 #include "infos/GametypeInfo.h"
@@ -39,4 +40,7 @@
 {
     CreateFactory(GametypeStatus);
+
+    /*static*/ bool GametypeStatus::noCaption_s = false;
+    SetConsoleCommand(GametypeStatus, setGametypeStatus, true);
 
     GametypeStatus::GametypeStatus(BaseObject* creator) : OverlayText(creator)
@@ -59,4 +63,10 @@
             const GametypeInfo* gtinfo = this->owner_->getGametypeInfo();
             ControllableEntity* ce = this->owner_->getControllableEntity();
+
+            if(GametypeStatus::noCaption_s) // No captions are displayed.
+            {
+                this->setCaption("");
+                return;
+            }
 
             if (!gtinfo->hasStarted() && !gtinfo->isStartCountdownRunning())
@@ -88,3 +98,15 @@
         this->owner_ = orxonox_cast<PlayerInfo*>(this->getOwner());
     }
+
+    /**
+    @brief
+        Sets whether the gametype status is displayed.
+    @param bValue
+        If true captions are displayed, if false, not.
+    */
+    /*static*/ void GametypeStatus::setGametypeStatus(bool bValue)
+    {
+        GametypeStatus::noCaption_s = !bValue;
+    }
+
 }
Index: code/trunk/src/modules/overlays/hud/GametypeStatus.h
===================================================================
--- code/trunk/src/modules/overlays/hud/GametypeStatus.h	(revision 6906)
+++ code/trunk/src/modules/overlays/hud/GametypeStatus.h	(revision 7163)
@@ -46,6 +46,10 @@
             virtual void changedOwner();
 
+            static void setGametypeStatus(bool bValue); //!< Toggles whether the gametype status is displayed.
+
         private:
             PlayerInfo* owner_;
+            static bool noCaption_s;
+
     };
 }
Index: code/trunk/src/modules/overlays/hud/HUDNavigation.cc
===================================================================
--- code/trunk/src/modules/overlays/hud/HUDNavigation.cc	(revision 6906)
+++ code/trunk/src/modules/overlays/hud/HUDNavigation.cc	(revision 7163)
@@ -29,6 +29,6 @@
 #include "HUDNavigation.h"
 
-#include <string>
 #include <OgreCamera.h>
+#include <OgreFontManager.h>
 #include <OgreOverlayManager.h>
 #include <OgreTextAreaOverlayElement.h>
@@ -45,242 +45,368 @@
 #include "controllers/HumanController.h"
 #include "worldentities/pawns/Pawn.h"
+#include "worldentities/WorldEntity.h"
+#include "core/ConfigValueIncludes.h"
+#include "tools/TextureGenerator.h"
+// #include <boost/bind/bind_template.hpp>
+
 
 namespace orxonox
 {
-    CreateFactory(HUDNavigation);
-
-    HUDNavigation::HUDNavigation(BaseObject* creator)
-        : OrxonoxOverlay(creator)
-    {
-        RegisterObject(HUDNavigation);
-
-        // create nav text
-        navText_ = static_cast<Ogre::TextAreaOverlayElement*>(Ogre::OverlayManager::getSingleton()
-            .createOverlayElement("TextArea", "HUDNavigation_navText_" + getUniqueNumberString()));
-
-        // create nav marker
-        navMarker_ = static_cast<Ogre::PanelOverlayElement*>(Ogre::OverlayManager::getSingleton()
-            .createOverlayElement("Panel", "HUDNavigation_navMarker_" + getUniqueNumberString()));
-        navMarker_->setMaterialName("Orxonox/NavArrows");
-
-/*
-        // create aim marker
-        aimMarker_ = static_cast<Ogre::PanelOverlayElement*>(Ogre::OverlayManager::getSingleton()
-            .createOverlayElement("Panel", "HUDNavigation_aimMarker_" + getUniqueNumberString()));
-        aimMarker_->setMaterialName("Orxonox/NavCrosshair");
-        this->wasOutOfView_ = true; // Ensure the material is changed right the first time..
-
-        setFont("Monofur");
-        setTextSize(0.05f);
-        setNavMarkerSize(0.05f);
-        setAimMarkerSize(0.04f);
-*/
-
-        background_->addChild(navMarker_);
-//        background_->addChild(aimMarker_);
-        background_->addChild(navText_);
-
-        // hide at first
-        this->setVisible(false);
-    }
-
-    HUDNavigation::~HUDNavigation()
-    {
-        if (this->isInitialized())
+bool compareDistance ( std::pair<RadarViewable*, unsigned int > a, std::pair<RadarViewable*, unsigned int > b )
+{
+    return a.second<b.second;
+
+}
+
+void HUDNavigation::setConfigValues()
+{
+  SetConfigValue(markerLimit_, 3);
+}
+
+CreateFactory ( HUDNavigation );
+
+HUDNavigation::HUDNavigation ( BaseObject* creator )
+        : OrxonoxOverlay ( creator )
+{
+    RegisterObject ( HUDNavigation );
+    this->setConfigValues();
+
+    // Set default values
+    setFont ( "Monofur" );
+    setTextSize ( 0.05f );
+    setNavMarkerSize ( 0.05f );
+}
+
+HUDNavigation::~HUDNavigation()
+{
+    if ( this->isInitialized() )
+    {
+        for ( ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); )
+            removeObject ( ( it++ )->first );
+
+    }
+
+    sortedObjectList_.clear();
+}
+
+void HUDNavigation::XMLPort ( Element& xmlElement, XMLPort::Mode mode )
+{
+    SUPER ( HUDNavigation, XMLPort, xmlElement, mode );
+
+    XMLPortParam ( HUDNavigation, "font",          setFont,          getFont,          xmlElement, mode );
+    XMLPortParam ( HUDNavigation, "textSize",      setTextSize,      getTextSize,      xmlElement, mode );
+    XMLPortParam ( HUDNavigation, "navMarkerSize", setNavMarkerSize, getNavMarkerSize, xmlElement, mode );
+}
+
+void HUDNavigation::setFont ( const std::string& font )
+{
+    const Ogre::ResourcePtr& fontPtr = Ogre::FontManager::getSingleton().getByName ( font );
+    if ( fontPtr.isNull() )
+    {
+        COUT ( 2 ) << "Warning: HUDNavigation: Font '" << font << "' not found" << std::endl;
+        return;
+    }
+    fontName_ = font;
+    for ( ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); ++it )
+    {
+        if ( it->second.text_ != NULL )
+            it->second.text_->setFontName ( fontName_ );
+    }
+}
+
+const std::string& HUDNavigation::getFont() const
+{
+    return fontName_;
+}
+
+void HUDNavigation::setTextSize ( float size )
+{
+    if ( size <= 0.0f )
+    {
+        COUT ( 2 ) << "Warning: HUDNavigation: Negative font size not allowed" << std::endl;
+        return;
+    }
+    textSize_ = size;
+    for ( ObjectMap::iterator it = activeObjectList_.begin(); it!=activeObjectList_.end(); ++it )
+    {
+        if ( it->second.text_ )
+            it->second.text_->setCharHeight ( size );
+    }
+}
+
+float HUDNavigation::getTextSize() const
+{
+    return textSize_;
+}
+
+
+
+void HUDNavigation::tick ( float dt )
+{
+    SUPER ( HUDNavigation, tick, dt );
+
+    Camera* cam = CameraManager::getInstance().getActiveCamera();
+    if ( cam == NULL )
+        return;
+    const Matrix4& camTransform = cam->getOgreCamera()->getProjectionMatrix() * cam->getOgreCamera()->getViewMatrix();
+
+
+    for ( sortedList::iterator listIt = sortedObjectList_.begin(); listIt != sortedObjectList_.end(); ++listIt )
+    {
+        listIt->second = ( int ) ( ( listIt->first->getRVWorldPosition() - HumanController::getLocalControllerSingleton()->getControllableEntity()->getWorldPosition() ).length() + 0.5f );
+    }
+
+    sortedObjectList_.sort ( compareDistance );
+
+    unsigned int markerCount_ = 0;
+
+//         for (ObjectMap::iterator it = activeObjectList_.begin(); it != activeObjectList_.end(); ++it)
+    for ( sortedList::iterator listIt = sortedObjectList_.begin(); listIt != sortedObjectList_.end(); ++markerCount_, ++listIt )
+    {
+        ObjectMap::iterator it = activeObjectList_.find ( listIt->first );
+
+        if ( markerCount_ < markerLimit_ )
         {
-            Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->navMarker_);
-            Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->navText_);
-//            Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->aimMarker_);
-        }
-    }
-
-    void HUDNavigation::XMLPort(Element& xmlElement, XMLPort::Mode mode)
-    {
-        SUPER(HUDNavigation, XMLPort, xmlElement, mode);
-
-        XMLPortParam(HUDNavigation, "font",     setFont,     getFont,     xmlElement, mode);
-        XMLPortParam(HUDNavigation, "textSize", setTextSize, getTextSize, xmlElement, mode);
-        XMLPortParam(HUDNavigation, "navMarkerSize", setNavMarkerSize, getNavMarkerSize, xmlElement, mode);
-//        XMLPortParam(HUDNavigation, "aimMarkerSize", setAimMarkerSize, getAimMarkerSize, xmlElement, mode);
-    }
-
-    void HUDNavigation::setFont(const std::string& font)
-    {
-        if (this->navText_ && !font.empty())
-            this->navText_->setFontName(font);
-    }
-
-    const std::string& HUDNavigation::getFont() const
-    {
-        if (this->navText_)
-            return this->navText_->getFontName();
-        else
-            return BLANKSTRING;
-    }
-
-    void HUDNavigation::setTextSize(float size)
-    {
-        if (this->navText_ && size >= 0.0f)
-            this->navText_->setCharHeight(size);
-    }
-
-    float HUDNavigation::getTextSize() const
-    {
-        if (this->navText_)
-            return this->navText_->getCharHeight();
-        else
-            return 0.0f;
-    }
-
-    void HUDNavigation::tick(float dt)
-    {
-        SUPER(HUDNavigation, tick, dt);
-
-        // Get radar
-        Radar* radar = this->getOwner()->getScene()->getRadar();
-
-        if (!radar->getFocus())
-        {
-            this->overlay_->hide();
-            return;
-        }
-        else
-        {
-            this->overlay_->show();
-        }
-
-        // set text
-        int dist = static_cast<int>(getDist2Focus());
-        navText_->setCaption(multi_cast<std::string>(dist));
-        float textLength = multi_cast<std::string>(dist).size() * navText_->getCharHeight() * 0.3f;
-
-        orxonox::Camera* cam = CameraManager::getInstance().getActiveCamera();
-        if (!cam)
-            return;
-        const Matrix4& transform = cam->getOgreCamera()->getProjectionMatrix() * cam->getOgreCamera()->getViewMatrix();
-        // transform to screen coordinates
-        Vector3 pos = transform * radar->getFocus()->getRVWorldPosition();
-
-        bool outOfView;
-        if (pos.z > 1.0)
-        {
-            // z > 1.0 means that the object is behind the camera
-            outOfView = true;
-            // we have to switch all coordinates (if you don't know why,
-            // try linear algebra lectures, because I can't explain..)
-            pos.x = -pos.x;
-            pos.y = -pos.y;
-        }
-        else
-            outOfView = pos.x < -1.0 || pos.x > 1.0 || pos.y < -1.0 || pos.y > 1.0;
-
-        if (outOfView)
-        {
-            // object is not in view
-//            aimMarker_->hide();
-
-            if (!wasOutOfView_)
+
+
+            // Get Distance to HumanController and save it in the TextAreaOverlayElement.
+            int dist = listIt->second;
+            it->second.text_->setCaption ( multi_cast<std::string> ( dist ) );
+            float textLength = multi_cast<std::string> ( dist ).size() * it->second.text_->getCharHeight() * 0.3f;
+
+            // Transform to screen coordinates
+            Vector3 pos = camTransform * it->first->getRVWorldPosition();
+
+            bool outOfView = true;
+            if ( pos.z > 1.0 )
             {
-                navMarker_->setMaterialName("Orxonox/NavArrows");
-                wasOutOfView_ = true;
+                // z > 1.0 means that the object is behind the camera
+                outOfView = true;
+                // we have to switch all coordinates (if you don't know why,
+                // try linear algebra lectures, because I can't explain..)
+                pos.x = -pos.x;
+                pos.y = -pos.y;
             }
-
-            if (pos.x < pos.y)
+            else
+                outOfView = pos.x < -1.0 || pos.x > 1.0 || pos.y < -1.0 || pos.y > 1.0;
+            // Get Distance to HumanController and save it in the TextAreaOverlayElement.
+            it->second.text_->setCaption ( multi_cast<std::string> ( dist ) );
+
+            if ( outOfView )
             {
-                if (pos.y > -pos.x)
+                // Object is not in view
+
+                // Change material only if outOfView changed
+                if ( !it->second.wasOutOfView_ )
                 {
-                    // up
-                    float position = pos.x / pos.y + 1.0f;
-                    navMarker_->setPosition((position - navMarker_->getWidth()) * 0.5f, 0.0f);
-                    navMarker_->setUV(0.5f, 0.0f, 1.0f, 0.5f);
-                    navText_->setLeft((position - textLength) * 0.5f);
-                    navText_->setTop(navMarker_->getHeight());
+                    it->second.panel_->setMaterialName( TextureGenerator::getMaterialName( "arrows.tga", it->first->getRadarObjectColour()) );
+                    it->second.wasOutOfView_ = true;
                 }
+
+                // Switch between top, bottom, left and right position of the arrow at the screen border
+                if ( pos.x < pos.y )
+                {
+                    if ( pos.y > -pos.x )
+                    {
+                        // Top
+                        float position = pos.x / pos.y + 1.0f;
+                        it->second.panel_->setPosition ( ( position - it->second.panel_->getWidth() ) * 0.5f, 0.0f );
+                        it->second.panel_->setUV ( 0.5f, 0.0f, 1.0f, 0.5f );
+                        it->second.text_->setLeft ( ( position - textLength ) * 0.5f );
+                        it->second.text_->setTop ( it->second.panel_->getHeight() );
+                    }
+                    else
+                    {
+                        // Left
+                        float position = pos.y / pos.x + 1.0f;
+                        it->second.panel_->setPosition ( 0.0f, ( position - it->second.panel_->getWidth() ) * 0.5f );
+                        it->second.panel_->setUV ( 0.0f, 0.0f, 0.5f, 0.5f );
+                        it->second.text_->setLeft ( it->second.panel_->getWidth() + 0.01f );
+                        it->second.text_->setTop ( ( position - it->second.text_->getCharHeight() ) * 0.5f );
+                    }
+                }
+
                 else
                 {
-                    // left
-                    float position = pos.y / pos.x + 1.0f;
-                    navMarker_->setPosition(0.0f, (position - navMarker_->getWidth()) * 0.5f);
-                    navMarker_->setUV(0.0f, 0.0f, 0.5f, 0.5f);
-                    navText_->setLeft(navMarker_->getWidth() + 0.01f);
-                    navText_->setTop((position - navText_->getCharHeight()) * 0.5f);
+
+                    if ( pos.y < -pos.x )
+                    {
+                        // Bottom
+                        float position = -pos.x / pos.y + 1.0f;
+                        it->second.panel_->setPosition ( ( position - it->second.panel_->getWidth() ) * 0.5f, 1.0f - it->second.panel_->getHeight() );
+                        it->second.panel_->setUV ( 0.0f, 0.5f, 0.5f, 1.0f );
+                        it->second.text_->setLeft ( ( position - textLength ) * 0.5f );
+                        it->second.text_->setTop ( 1.0f - it->second.panel_->getHeight() - it->second.text_->getCharHeight() );
+                    }
+                    else
+                    {
+                        // Right
+                        float position = -pos.y / pos.x + 1.0f;
+                        it->second.panel_->setPosition ( 1.0f - it->second.panel_->getWidth(), ( position - it->second.panel_->getHeight() ) * 0.5f );
+                        it->second.panel_->setUV ( 0.5f, 0.5f, 1.0f, 1.0f );
+                        it->second.text_->setLeft ( 1.0f - it->second.panel_->getWidth() - textLength - 0.01f );
+                        it->second.text_->setTop ( ( position - it->second.text_->getCharHeight() ) * 0.5f );
+                    }
                 }
             }
             else
             {
-                if (pos.y < -pos.x)
+                // Object is in view
+
+                // Change material only if outOfView changed
+                if ( it->second.wasOutOfView_ )
                 {
-                    // down
-                    float position = -pos.x / pos.y + 1.0f;
-                    navMarker_->setPosition((position - navMarker_->getWidth()) * 0.5f, 1.0f - navMarker_->getHeight());
-                    navMarker_->setUV(0.0f, 0.5f, 0.5f, 1.0f);
-                    navText_->setLeft((position - textLength) * 0.5f);
-                    navText_->setTop(1.0f - navMarker_->getHeight() - navText_->getCharHeight());
+                  //it->second.panel_->setMaterialName ( "Orxonox/NavTDC" );
+                    it->second.panel_->setMaterialName( TextureGenerator::getMaterialName( "tdc.tga", it->first->getRadarObjectColour()) );
+                    it->second.wasOutOfView_ = false;
                 }
-                else
-                {
-                    // right
-                    float position = -pos.y / pos.x + 1.0f;
-                    navMarker_->setPosition(1.0f - navMarker_->getWidth(), (position - navMarker_->getHeight()) * 0.5f);
-                    navMarker_->setUV(0.5f, 0.5f, 1.0f, 1.0f);
-                    navText_->setLeft(1.0f - navMarker_->getWidth() - textLength - 0.01f);
-                    navText_->setTop((position - navText_->getCharHeight()) * 0.5f);
-                }
+
+                // Position marker
+                it->second.panel_->setUV ( 0.0f, 0.0f, 1.0f, 1.0f );
+                it->second.panel_->setLeft ( ( pos.x + 1.0f - it->second.panel_->getWidth() ) * 0.5f );
+                it->second.panel_->setTop ( ( -pos.y + 1.0f - it->second.panel_->getHeight() ) * 0.5f );
+
+                // Position text
+                it->second.text_->setLeft ( ( pos.x + 1.0f + it->second.panel_->getWidth() ) * 0.5f );
+                it->second.text_->setTop ( ( -pos.y + 1.0f + it->second.panel_->getHeight() ) * 0.5f );
             }
+
+            // Make sure the overlays are shown
+            it->second.panel_->show();
+            it->second.text_->show();
         }
         else
         {
-            // object is in view
-/*
-            Vector3 aimpos = transform * getPredictedPosition(SpaceShip::getLocalShip()->getPosition(),
-                    Projectile::getSpeed(), Radar::getInstance().getFocus()->getRVWorldPosition(), Radar::getInstance().getFocus()->getRVOrientedVelocity());
+            it->second.panel_->hide();
+            it->second.text_->hide();
+        }
+
+    }
+}
+
+
+/** Overridden method of OrxonoxOverlay.
+@details
+    Usually the entire overlay scales with scale().
+    Here we obviously have to adjust this.
 */
-            if (wasOutOfView_)
-            {
-                navMarker_->setMaterialName("Orxonox/NavTDC");
-                wasOutOfView_ = false;
-            }
-
-            // object is in view
-            navMarker_->setUV(0.0f, 0.0f, 1.0f, 1.0f);
-            navMarker_->setLeft((pos.x + 1.0f - navMarker_->getWidth()) * 0.5f);
-            navMarker_->setTop((-pos.y + 1.0f - navMarker_->getHeight()) * 0.5f);
-
-/*
-            aimMarker_->show();
-            aimMarker_->setLeft((aimpos.x + 1.0f - aimMarker_->getWidth()) * 0.5f);
-            aimMarker_->setTop((-aimpos.y + 1.0f - aimMarker_->getHeight()) * 0.5f);
-*/
-            navText_->setLeft((pos.x + 1.0f + navMarker_->getWidth()) * 0.5f);
-            navText_->setTop((-pos.y + 1.0f + navMarker_->getHeight()) * 0.5f);
+void HUDNavigation::sizeChanged()
+{
+    // Use size to compensate for aspect ratio if enabled.
+    float xScale = this->getActualSize().x;
+    float yScale = this->getActualSize().y;
+
+    for ( ObjectMap::iterator it = activeObjectList_.begin(); it!=activeObjectList_.end(); ++it )
+    {
+        if ( it->second.panel_ != NULL )
+            it->second.panel_->setDimensions ( navMarkerSize_ * xScale, navMarkerSize_ * yScale );
+        if ( it->second.text_ != NULL )
+            it->second.text_->setCharHeight ( it->second.text_->getCharHeight() * yScale );
+    }
+}
+
+void HUDNavigation::addObject ( RadarViewable* object )
+{
+    if( showObject(object)==false )
+        return;
+
+    if ( activeObjectList_.size() >= markerLimit_ )
+        if ( object == NULL )
+            return;
+
+    // Object hasn't been added yet (we know that)
+    assert ( this->activeObjectList_.find ( object ) == this->activeObjectList_.end() );
+
+    // Scales used for dimensions and text size
+    float xScale = this->getActualSize().x;
+    float yScale = this->getActualSize().y;
+
+    // Create everything needed to display the object on the radar and add it to the map
+
+    // Create arrow/marker
+    Ogre::PanelOverlayElement* panel = static_cast<Ogre::PanelOverlayElement*> ( Ogre::OverlayManager::getSingleton()
+                                       .createOverlayElement ( "Panel", "HUDNavigation_navMarker_" + getUniqueNumberString() ) );
+//     panel->setMaterialName ( "Orxonox/NavTDC" );
+    panel->setMaterialName( TextureGenerator::getMaterialName( "tdc.tga", object->getRadarObjectColour()) );
+    panel->setDimensions ( navMarkerSize_ * xScale, navMarkerSize_ * yScale );
+//     panel->setColour( object->getRadarObjectColour() );
+
+    Ogre::TextAreaOverlayElement* text = static_cast<Ogre::TextAreaOverlayElement*> ( Ogre::OverlayManager::getSingleton()
+                                         .createOverlayElement ( "TextArea", "HUDNavigation_navText_" + getUniqueNumberString() ) );
+    text->setFontName ( this->fontName_ );
+    text->setCharHeight ( text->getCharHeight() * yScale );
+    text->setColour( object->getRadarObjectColour() );
+
+    panel->hide();
+    text->hide();
+
+    ObjectInfo tempStruct = {panel, text, false};
+    activeObjectList_[object] = tempStruct;
+
+    this->background_->addChild ( panel );
+    this->background_->addChild ( text );
+
+    sortedObjectList_.push_front ( std::make_pair ( object, ( unsigned int ) 0 ) );
+
+
+}
+
+void HUDNavigation::removeObject ( RadarViewable* viewable )
+{
+    ObjectMap::iterator it = activeObjectList_.find ( viewable );
+
+    if ( activeObjectList_.find ( viewable ) != activeObjectList_.end() )
+    {
+        // Detach overlays
+        this->background_->removeChild ( it->second.panel_->getName() );
+        this->background_->removeChild ( it->second.text_->getName() );
+        // Properly destroy the overlay elements (do not use delete!)
+        Ogre::OverlayManager::getSingleton().destroyOverlayElement ( it->second.panel_ );
+        Ogre::OverlayManager::getSingleton().destroyOverlayElement ( it->second.text_ );
+        // Remove from the list
+        activeObjectList_.erase ( viewable );
+
+
+    }
+
+    for ( sortedList::iterator listIt = sortedObjectList_.begin(); listIt != sortedObjectList_.end(); ++listIt )
+    {
+        if ( (listIt->first) == viewable )
+        {
+            sortedObjectList_.erase ( listIt );
+            break;
         }
-    }
-
-    float HUDNavigation::getDist2Focus() const
-    {
-        Radar* radar = this->getOwner()->getScene()->getRadar();
-        if (radar->getFocus() && HumanController::getLocalControllerEntityAsPawn())
-            return (radar->getFocus()->getRVWorldPosition() - HumanController::getLocalControllerEntityAsPawn()->getWorldPosition()).length();
-        else
-            return 0;
-    }
-
-    /**
-    @brief Overridden method of OrxonoxOverlay. Usually the entire overlay
-           scales with scale(). Here we obviously have to adjust this.
-    */
-    void HUDNavigation::sizeChanged()
-    {
-        // use size to compensate for aspect ratio if enabled.
-        float xScale = this->getActualSize().x;
-        float yScale = this->getActualSize().y;
-        if (this->navMarker_)
-            navMarker_->setDimensions(navMarkerSize_ * xScale, navMarkerSize_ * yScale);
-/*
-        if (this->aimMarker_)
-            aimMarker_->setDimensions(aimMarkerSize_ * xScale, aimMarkerSize_ * yScale);
-*/
-        if (this->navText_)
-            navText_->setCharHeight(navText_->getCharHeight() * yScale);
-    }
-}
+
+    }
+
+}
+
+void HUDNavigation::objectChanged(RadarViewable* viewable)
+{
+    // TODO: niceification neccessary ;)
+    removeObject(viewable);
+    addObject(viewable);
+}
+
+
+bool HUDNavigation::showObject(RadarViewable* rv)
+{
+    if ( rv == dynamic_cast<RadarViewable*> ( this->getOwner() ) )
+        return false;
+    assert( rv->getWorldEntity() );
+    if ( rv->getWorldEntity()->isVisible()==false || rv->getRadarVisibility()==false )
+        return false;
+    return true;
+}
+
+void HUDNavigation::changedOwner()
+{
+
+    const std::set<RadarViewable*>& respawnObjects = this->getOwner()->getScene()->getRadar()->getRadarObjects();
+    for ( std::set<RadarViewable*>::const_iterator it = respawnObjects.begin(); it != respawnObjects.end(); ++it )
+    {
+        if ( ! ( *it )->isHumanShip_ )
+            this->addObject ( *it );
+    }
+}
+}
Index: code/trunk/src/modules/overlays/hud/HUDNavigation.h
===================================================================
--- code/trunk/src/modules/overlays/hud/HUDNavigation.h	(revision 6906)
+++ code/trunk/src/modules/overlays/hud/HUDNavigation.h	(revision 7163)
@@ -32,52 +32,78 @@
 #include "overlays/OverlaysPrereqs.h"
 
+#include <map>
+#include <string>
+
+
 #include "util/OgreForwardRefs.h"
 #include "tools/interfaces/Tickable.h"
+#include "interfaces/RadarListener.h"
 #include "overlays/OrxonoxOverlay.h"
 
 namespace orxonox
 {
-    class _OverlaysExport HUDNavigation : public OrxonoxOverlay, public Tickable
+class _OverlaysExport HUDNavigation : public OrxonoxOverlay, public Tickable, public RadarListener
+{
+public:
+    HUDNavigation ( BaseObject* creator );
+    virtual ~HUDNavigation();
+
+    void setConfigValues();
+
+    virtual void XMLPort ( Element& xmlElement, XMLPort::Mode mode );
+    virtual void tick ( float dt );
+
+    virtual void addObject ( RadarViewable* object );
+    virtual void removeObject ( RadarViewable* viewable );
+    virtual void objectChanged ( RadarViewable* viewable );
+
+    virtual void changedOwner();
+    virtual void sizeChanged();
+    virtual void angleChanged() { }
+    virtual void positionChanged() { }
+    virtual void radarTick ( float dt ) {}
+
+    inline float getRadarSensitivity() const
+    { return 1.0f; }
+
+private:
+    struct ObjectInfo
     {
-    public:
-        HUDNavigation(BaseObject* creator);
-        virtual ~HUDNavigation();
+        Ogre::PanelOverlayElement* panel_;
+        Ogre::TextAreaOverlayElement* text_;
+        bool outOfView_;
+        bool wasOutOfView_;
 
-        virtual void XMLPort(Element& xmlElement, XMLPort::Mode mode);
-        virtual void tick(float dt);
+    };
 
-    private:
-        void sizeChanged();
-        void angleChanged() { }
-        void positionChanged() { }
+    bool showObject( RadarViewable* rv );
 
-        // XMLPort accessors
-        void setNavMarkerSize(float size) { this->navMarkerSize_ = size; this->sizeChanged(); }
-        float getNavMarkerSize() const    { return this->navMarkerSize_; }
+    // XMLPort accessors
+    void setNavMarkerSize ( float size )
+    { navMarkerSize_ = size; this->sizeChanged(); }
+    float getNavMarkerSize() const
+    { return navMarkerSize_; }
 
-/*
-        void setAimMarkerSize(float size) { this->aimMarkerSize_ = size; this->sizeChanged(); }
-        float getAimMarkerSize() const    { return this->aimMarkerSize_; }
-*/
+    void setTextSize ( float size );
+    float getTextSize() const;
 
-        void setTextSize(float size);
-        float getTextSize() const;
+    void setFont ( const std::string& font );
+    const std::string& getFont() const;
 
-        void setFont(const std::string& font);
-        const std::string& getFont() const;
+    typedef std::map<RadarViewable*, ObjectInfo > ObjectMap;
+    ObjectMap activeObjectList_;
 
-        void updateMarker();
-        void updateFocus();
-        float getDist2Focus() const;
+    typedef std::list < std::pair<RadarViewable*, unsigned int > > sortedList;
+    sortedList sortedObjectList_;
 
-        Ogre::PanelOverlayElement* navMarker_;      //!< the panel used to show the arrow and the target marker
-        float navMarkerSize_;                       //!< One paramter size of the navigation marker
-/*
-        Ogre::PanelOverlayElement* aimMarker_;      //!< Panel used to show the aim Marker
-        float aimMarkerSize_;                       //!< One paramter size of the aim marker
-*/
-        Ogre::TextAreaOverlayElement* navText_;     //!< Text overlay to display the target distance
-        bool wasOutOfView_;                         //!< Performance booster variable: setMaterial is not cheap
-    };
+
+    float navMarkerSize_;
+    std::string fontName_;
+    float textSize_;
+
+    unsigned int markerLimit_;; //TODO: is it possible to set this over the console and/or the IG-Setting
+
+
+};
 }
 
Index: code/trunk/src/modules/overlays/hud/HUDRadar.cc
===================================================================
--- code/trunk/src/modules/overlays/hud/HUDRadar.cc	(revision 6906)
+++ code/trunk/src/modules/overlays/hud/HUDRadar.cc	(revision 7163)
@@ -40,4 +40,6 @@
 #include "worldentities/WorldEntity.h"
 #include "worldentities/pawns/Pawn.h"
+#include "Scene.h"
+#include "Radar.h"
 
 namespace orxonox
@@ -72,8 +74,8 @@
         {
             Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->marker_);
-            for (std::vector<Ogre::PanelOverlayElement*>::iterator it = this->radarDots_.begin();
-                it != this->radarDots_.end(); ++it)
+            for (std::map<RadarViewable*,Ogre::PanelOverlayElement*>::iterator it = this->radarObjects_.begin();
+                it != this->radarObjects_.end(); ++it)
             {
-                Ogre::OverlayManager::getSingleton().destroyOverlayElement(*it);
+                Ogre::OverlayManager::getSingleton().destroyOverlayElement(it->second);
             }
         }
@@ -89,80 +91,108 @@
     }
 
-    void HUDRadar::displayObject(RadarViewable* object, bool bIsMarked)
+    void HUDRadar::addObject(RadarViewable* object)
     {
-        if (object == static_cast<RadarViewable*>(this->owner_))
+        if (object == dynamic_cast<RadarViewable*>(this->owner_))
             return;
 
-        const WorldEntity* wePointer = object->getWorldEntity();
+        // Make sure the object hasn't been added yet
+        assert( this->radarObjects_.find(object) == this->radarObjects_.end() );
 
-        // Just to be sure that we actually have a WorldEntity.
-        // We could do a dynamic_cast, but that would be a lot slower.
-        if (!wePointer || !this->owner_)
+        // Create everything needed to display the object on the radar and add it to the map
+        Ogre::PanelOverlayElement* panel;
+        panel = static_cast<Ogre::PanelOverlayElement*>(
+            Ogre::OverlayManager::getSingleton().createOverlayElement("Panel", "RadarDot" + getUniqueNumberString()));
+        this->overlay_->add2D(panel);
+        // get right material
+        panel->setMaterialName(TextureGenerator::getMaterialName(
+            shapeMaterials_[object->getRadarObjectShape()], object->getRadarObjectColour()));
+        this->radarObjects_[object] = panel;
+    }
+
+    void HUDRadar::removeObject(RadarViewable* object)
+    {
+        // If object was added at all then remove it
+        std::map<RadarViewable*,Ogre::PanelOverlayElement*>::iterator it;
+        it = this->radarObjects_.find( object );
+        if( it != this->radarObjects_.end() )
         {
-            if (!wePointer)
-                CCOUT(2) << "Cannot display a non-WorldEntitiy on the radar" << std::endl;
-            if (!this->owner_)
-                CCOUT(2) << "No owner defined" << std::endl;
+            Ogre::OverlayManager::getSingleton().destroyOverlayElement(it->second);
+            this->radarObjects_.erase(it);
+        }
+    }
+
+    void HUDRadar::objectChanged( RadarViewable* rv )
+    {
+        if (rv == dynamic_cast<RadarViewable*>(this->owner_))
             return;
-        }
+        assert( this->radarObjects_.find(rv) != this->radarObjects_.end() );
+        Ogre::PanelOverlayElement* panel = this->radarObjects_[rv];
+        panel->setMaterialName(TextureGenerator::getMaterialName(
+            shapeMaterials_[rv->getRadarObjectShape()], rv->getRadarObjectColour()));
+    }
 
-        // try to find a panel already created
-        Ogre::PanelOverlayElement* panel;
-        //std::map<RadarViewable*, Ogre::PanelOverlayElement*>::iterator it = this->radarDots_.find(object);
-        if (itRadarDots_ == this->radarDots_.end())
-        {
-            // we have to create a new entry
-            panel = static_cast<Ogre::PanelOverlayElement*>(
-                Ogre::OverlayManager::getSingleton().createOverlayElement("Panel", "RadarDot" + getUniqueNumberString()));
-            radarDots_.push_back(panel);
-            // get right material
-            panel->setMaterialName(TextureGenerator::getMaterialName(
-                shapeMaterials_[object->getRadarObjectShape()], object->getRadarObjectColour()));
-            this->overlay_->add2D(panel);
-            this->itRadarDots_ = this->radarDots_.end();
-        }
-        else
-        {
-            panel = *itRadarDots_;
-            ++itRadarDots_;
-            const std::string& materialName = TextureGenerator::getMaterialName(
-                shapeMaterials_[object->getRadarObjectShape()], object->getRadarObjectColour());
-            if (materialName != panel->getMaterialName())
-                panel->setMaterialName(materialName);
-        }
-        panel->show();
-
-        // set size to fit distance...
-        float distance = (wePointer->getWorldPosition() - this->owner_->getPosition()).length();
-        // calculate the size with 1/distance dependency for simplicity (instead of exp(-distance * lambda)
-        float size = maximumDotSize_ * halfDotSizeDistance_ / (halfDotSizeDistance_ + distance);
-        panel->setDimensions(size, size);
-
-        // calc position on radar...
-        Vector2 coord = get2DViewcoordinates(this->owner_->getPosition(), this->owner_->getOrientation() * WorldEntity::FRONT, this->owner_->getOrientation() * WorldEntity::UP, wePointer->getWorldPosition());
-        coord *= Ogre::Math::PI / 3.5f; // small adjustment to make it fit the texture
-        panel->setPosition((1.0f + coord.x - size) * 0.5f, (1.0f - coord.y - size) * 0.5f);
-
-        if (bIsMarked)
-        {
-            this->marker_->show();
-            this->marker_->setDimensions(size * 1.5f, size * 1.5f);
-            this->marker_->setPosition((1.0f + coord.x - size * 1.5f) * 0.5f, (1.0f - coord.y - size * 1.5f) * 0.5f);
-        }
+    void HUDRadar::gatherObjects()
+    {
+        const std::set<RadarViewable*>& objectSet = this->getCreator()->getScene()->getRadar()->getRadarObjects();
+        std::set<RadarViewable*>::const_iterator it;
+        for( it=objectSet.begin(); it!=objectSet.end(); ++it )
+            this->addObject(*it);
     }
 
     void HUDRadar::radarTick(float dt)
     {
-        for (itRadarDots_ = radarDots_.begin(); itRadarDots_ != radarDots_.end(); ++itRadarDots_)
-            (*itRadarDots_)->hide();
-        this->itRadarDots_ = this->radarDots_.begin();
-        this->marker_->hide();
+        // Make sure the owner of the radar was defined
+        if( !this->owner_ )
+        {
+            CCOUT(0) << "No owner defined" << std::endl;
+            assert(0);
+        }
+
+        this->marker_->hide();      // in case that no object is in focus
+        // get the focus object
+        Radar* radar = this->getOwner()->getScene()->getRadar();
+        const RadarViewable* focusObject = radar->getFocus();
+
+        // update the distances for all objects
+        std::map<RadarViewable*,Ogre::PanelOverlayElement*>::iterator it;
+        for( it = this->radarObjects_.begin(); it != this->radarObjects_.end(); ++it )
+        {
+            // Make sure the object really is a WorldEntity
+            const WorldEntity* wePointer = it->first->getWorldEntity();
+            if( !wePointer )
+            {
+                CCOUT(0) << "Cannot display a non-WorldEntitiy on the radar" << std::endl;
+                assert(0);
+            }
+            bool isFocus = (it->first == focusObject);
+            // set size to fit distance...
+            float distance = (wePointer->getWorldPosition() - this->owner_->getPosition()).length();
+            // calculate the size with 1/distance dependency for simplicity (instead of exp(-distance * lambda)
+            float size = maximumDotSize_ * halfDotSizeDistance_ / (halfDotSizeDistance_ + distance);
+            it->second->setDimensions(size, size);
+
+            // calc position on radar...
+            Vector2 coord = get2DViewcoordinates(this->owner_->getPosition(), this->owner_->getOrientation() * WorldEntity::FRONT, this->owner_->getOrientation() * WorldEntity::UP, wePointer->getWorldPosition());
+            coord *= Ogre::Math::PI / 3.5f; // small adjustment to make it fit the texture
+            it->second->setPosition((1.0f + coord.x - size) * 0.5f, (1.0f - coord.y - size) * 0.5f);
+            it->second->show();
+
+            // if this object is in focus, then set the focus marker
+            if (isFocus)
+            {
+                this->marker_->setDimensions(size * 1.5f, size * 1.5f);
+                this->marker_->setPosition((1.0f + coord.x - size * 1.5f) * 0.5f, (1.0f - coord.y - size * 1.5f) * 0.5f);
+                this->marker_->show();
+            }
+        }
     }
 
     void HUDRadar::changedOwner()
     {
-        SUPER(HUDRadar, changedOwner);
+    SUPER(HUDRadar, changedOwner);
 
-        this->owner_ = orxonox_cast<Pawn*>(this->getOwner());
-    }
+    this->owner_ = orxonox_cast<Pawn*>(this->getOwner());
+    assert(this->radarObjects_.size()==0);
+    this->gatherObjects();
 }
+}
Index: code/trunk/src/modules/overlays/hud/HUDRadar.h
===================================================================
--- code/trunk/src/modules/overlays/hud/HUDRadar.h	(revision 6906)
+++ code/trunk/src/modules/overlays/hud/HUDRadar.h	(revision 7163)
@@ -65,11 +65,16 @@
 
         // RadarListener interface
-        void displayObject(RadarViewable* viewable, bool bIsMarked);
+        virtual void addObject(RadarViewable* viewable);
+        virtual void removeObject(RadarViewable* viewable);
+        virtual void objectChanged( RadarViewable* rv );
         void radarTick(float dt);
+
+        void gatherObjects();
 
         std::map<RadarViewable::Shape, std::string> shapeMaterials_;
 
-        std::vector<Ogre::PanelOverlayElement*> radarDots_;
-        std::vector<Ogre::PanelOverlayElement*>::iterator itRadarDots_;
+//         std::vector<Ogre::PanelOverlayElement*> radarDots_;
+//         std::vector<Ogre::PanelOverlayElement*>::iterator itRadarDots_;
+        std::map<RadarViewable*, Ogre::PanelOverlayElement*> radarObjects_;
         Ogre::PanelOverlayElement* marker_;
 
Index: code/trunk/src/modules/pickup/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/pickup/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/pickup/CMakeLists.txt	(revision 7163)
@@ -1,3 +1,4 @@
 SET_SOURCE_FILES(PICKUP_SRC_FILES
+  CollectiblePickup.cc
   DroppedPickup.cc
   Pickup.cc
@@ -17,6 +18,4 @@
     PickupManager.h
     PickupRepresentation.h
-  DEFINE_SYMBOL
-    "PICKUP_SHARED_BUILD"
   PCH_FILE
     PickupPrecompiledHeaders.h
Index: code/trunk/src/modules/pickup/CollectiblePickup.cc
===================================================================
--- code/trunk/src/modules/pickup/CollectiblePickup.cc	(revision 7163)
+++ code/trunk/src/modules/pickup/CollectiblePickup.cc	(revision 7163)
@@ -0,0 +1,164 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Damian 'Mozork' Frick
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+/**
+    @file CollectiblePickup.cc
+    @brief Implementation of the CollectiblePickup class.
+*/
+
+#include "CollectiblePickup.h"
+
+#include "core/CoreIncludes.h"
+#include "PickupCollection.h"
+
+namespace orxonox {
+
+    /**
+    @brief
+        Constructor.
+        Registers the object and initializes variables.
+    */
+    CollectiblePickup::CollectiblePickup() : isInCollection_(false)
+    {
+        RegisterObject(CollectiblePickup);
+
+        this->collection_ = NULL;
+    }
+
+    /**
+    @brief
+        Destructor.
+    */
+    CollectiblePickup::~CollectiblePickup()
+    {
+
+    }
+
+    /**
+    @brief
+        Is called by OrxonoxClass::destroy() before the object is actually destroyed.
+    */
+    void CollectiblePickup::preDestroy(void)
+    {
+        this->Pickupable::preDestroy();
+
+        // The PickupCollection has to be destroyed as well.
+        if(this->isInCollection())
+            this->collection_->Pickupable::destroy();
+    }
+
+    /**
+    @brief
+        Destroys a Pickupable.
+    */
+    void CollectiblePickup::destroyPickup(void)
+    {
+        if(!this->isInCollection()) // If the CollectiblePickup is not in a PickupCollection the destroyPickup method of Pickupable is called.
+            this->Pickupable::destroyPickup();
+        else // Else the ColectiblePickup is dropped and disabled,
+        {
+            this->drop(false);
+            if(this->isInCollection() && this->isEnabled()) // It is only disabled if it is enabled and still ina PickupCollection after having been dropped.
+            {
+                this->setDisabled();
+                this->collection_->pickupDisabled();
+            }
+        }
+    }
+
+    /**
+    @brief
+        Is called by the PickupCarrier when it is being destroyed.
+    */
+    void CollectiblePickup::carrierDestroyed(void)
+    {
+        if(!this->isInCollection())
+            this->Pickupable::destroy();
+        else // If the CollectiblePickup is part of a PickupCollection it is just dropped instead of destroyed.
+            this->drop(false);
+    }
+
+    /**
+    @brief
+        Is called when the pickup has transited from used to unused or the other way around.
+    */
+    void CollectiblePickup::changedUsed(void)
+    {
+        SUPER(CollectiblePickup, changedUsed);
+
+        if(this->isInCollection())
+            this->collection_->pickupChangedUsed(this->isUsed());
+    }
+
+    /**
+    @brief
+        Is called when the pickup has transited from picked up to dropped or the other way around.
+    */
+    void CollectiblePickup::changedPickedUp(void)
+    {
+        SUPER(CollectiblePickup, changedPickedUp);
+
+        if(this->isInCollection())
+            this->collection_->pickupChangedPickedUp(this->isPickedUp());
+    }
+
+    /**
+    @brief
+        Adds this CollectiblePickup to the input PickupCollection.
+    @param collection
+        A pointer to the PickupCollection to which the CollectiblePickup should be added.
+    @return
+        Returns true if the CollectiblePickup was successfully added to the PickupCollection.
+    */
+    bool CollectiblePickup::addToCollection(PickupCollection* collection)
+    {
+        if(this->isInCollection() || collection == NULL) //If the CollectiblePickup already is in a PickupCollection or if the input pointer is NULL.
+            return false;
+
+        this->isInCollection_ = true;
+        this->collection_ = collection;
+        return true;
+    }
+
+    /**
+    @brief
+        Removes this CollectiblePickup from its PickupCollection.
+    @return
+        Returns true if the CollectiblePickup was succcessfully removed.
+    */
+    bool CollectiblePickup::removeFromCollection(void)
+    {
+        if(!this->isInCollection()) //If the CollectiblePickup is not in a PickupCollection.
+            return false;
+
+        this->isInCollection_ = false;
+        this->collection_ = NULL;
+        return true;
+    }
+
+}
Index: code/trunk/src/modules/pickup/CollectiblePickup.h
===================================================================
--- code/trunk/src/modules/pickup/CollectiblePickup.h	(revision 7163)
+++ code/trunk/src/modules/pickup/CollectiblePickup.h	(revision 7163)
@@ -0,0 +1,82 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Damian 'Mozork' Frick
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+/**
+    @file CollectiblePickup.h
+    @brief Definition of the CollectiblePickup class.
+*/
+
+#ifndef _CollectiblePickup_H__
+#define _CollectiblePickup_H__
+
+#include "pickup/PickupPrereqs.h"
+
+#include "interfaces/Pickupable.h"
+
+namespace orxonox {
+
+    /**
+    @brief
+        Collectible Pickup class. Any pickup inheriting from this class can be added to a PickupCollection and thus be part uf such.
+    @author
+        Damian 'Mozork' Frick
+    */
+    class _PickupExport CollectiblePickup : public Pickupable
+    {
+
+        public:
+            CollectiblePickup(); //!< Constructor.
+            virtual ~CollectiblePickup(); //! Destructor.
+
+            virtual void changedUsed(void); //!< Is called when the pickup has transited from used to unused or the other way around.
+            virtual void changedPickedUp(void); //!< Is called when the pickup has transited from picked up to dropped or the other way around.
+
+            /**
+            @brief Check whether the given CollectiblePickup is par of a PickupCollection.
+            @return Returns true if the ColelctiblePickup is part of a PickupCollection.
+            */
+            bool isInCollection(void)
+                { return this->isInCollection_; }
+            
+            bool addToCollection(PickupCollection* collection); //!< Adds this CollectiblePickup to the input PickupCollection.
+            bool removeFromCollection(void); //!< Removes this CollectiblePickup from its PickupCollection.
+
+            void carrierDestroyed(void); //!< Is called by the PickupCarrier when it is being destroyed.
+
+        protected:
+            virtual void preDestroy(void); //!< Is called by OrxonoxClass::destroy() before the object is actually destroyed.
+            virtual void destroyPickup(void); //!< //!< Destroys a Pickupable.
+
+        private:
+            bool isInCollection_; //!< True if the CollectiblePickup is in a PickupCollection.
+            PickupCollection* collection_; //!< A pointer to the PickupCollection this CollectiblePickup is in.
+
+    };
+}
+
+#endif // _CollectiblePickup_H__
Index: code/trunk/src/modules/pickup/DroppedPickup.cc
===================================================================
--- code/trunk/src/modules/pickup/DroppedPickup.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/DroppedPickup.cc	(revision 7163)
@@ -41,7 +41,7 @@
 namespace orxonox
 {
-    
+
     CreateFactory(DroppedPickup);
-    
+
     /**
     @brief
@@ -51,5 +51,5 @@
     {
         RegisterObject(DroppedPickup);
-        
+
     }
 
@@ -67,10 +67,10 @@
     */
     DroppedPickup::DroppedPickup(BaseObject* creator, Pickupable* pickup, PickupCarrier* carrier, float triggerDistance) : PickupSpawner(creator, pickup, triggerDistance, 5, 1)
-    {   
+    {
         RegisterObject(DroppedPickup);
 
         this->setPosition(carrier->getCarrierPosition());
         this->setActive(false);
-        
+
         //TODO: Do more elegantly.
         this->startRespawnTimer();
Index: code/trunk/src/modules/pickup/DroppedPickup.h
===================================================================
--- code/trunk/src/modules/pickup/DroppedPickup.h	(revision 6906)
+++ code/trunk/src/modules/pickup/DroppedPickup.h	(revision 7163)
@@ -41,5 +41,5 @@
 namespace orxonox
 {
-    
+
     /**
     @brief
Index: code/trunk/src/modules/pickup/Pickup.cc
===================================================================
--- code/trunk/src/modules/pickup/Pickup.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/Pickup.cc	(revision 7163)
@@ -48,4 +48,6 @@
     /*static*/ const std::string Pickup::durationTypeOnce_s = "once";
     /*static*/ const std::string Pickup::durationTypeContinuous_s = "continuous";
+
+    CreateUnloadableFactory(Pickup);
 
     Pickup::Pickup(BaseObject* creator) : BaseObject(creator)
@@ -146,9 +148,9 @@
     void Pickup::setActivationType(const std::string& type)
     {
-        if(type == activationTypeImmediate_s)
+        if(Pickup::activationTypeImmediate_s.compare(type) == 0)
         {
             this->activationType_ = pickupActivationType::immediate;
         }
-        else if(type == activationTypeOnUse_s)
+        else if(Pickup::activationTypeOnUse_s.compare(type) == 0)
         {
             this->activationType_ = pickupActivationType::onUse;
@@ -168,9 +170,9 @@
     void Pickup::setDurationType(const std::string& type)
     {
-        if(type == durationTypeOnce_s)
+        if(Pickup::durationTypeOnce_s.compare(type) == 0)
         {
             this->durationType_ = pickupDurationType::once;
         }
-        else if(type == durationTypeContinuous_s)
+        else if(Pickup::durationTypeContinuous_s.compare(type) == 0)
         {
             this->durationType_ = pickupDurationType::continuous;
@@ -192,5 +194,5 @@
 
         //! Sets the Pickup to used if the Pickup has activation type 'immediate' and gets picked up.
-        if(this->getCarrier() != NULL && this->isPickedUp() && this->isImmediate())
+        if(this->isPickedUp() && this->isImmediate())
         {
             this->setUsed(true);
Index: code/trunk/src/modules/pickup/Pickup.h
===================================================================
--- code/trunk/src/modules/pickup/Pickup.h	(revision 6906)
+++ code/trunk/src/modules/pickup/Pickup.h	(revision 7163)
@@ -40,5 +40,5 @@
 #include "core/XMLPort.h"
 
-#include "interfaces/Pickupable.h"
+#include "CollectiblePickup.h"
 
 #include "tools/Timer.h"
@@ -74,11 +74,9 @@
         Damian 'Mozork' Frick
     */
-    class _PickupExport Pickup : public Pickupable, public BaseObject
+    class _PickupExport Pickup : public CollectiblePickup, public BaseObject
     {
 
-        protected:
+        public:
             Pickup(BaseObject* creator); //!< Constructor.
-
-        public:
             virtual ~Pickup(); //!< Destructor.
 
@@ -167,5 +165,5 @@
         private:
             void initialize(void); //!< Initializes the member variables.
-            
+
             //TODO: Problems, when there are more Timers needed? Solutions?
             Timer durationTimer_; //!< Timer at the disposal of each Class implementing Pickup.
Index: code/trunk/src/modules/pickup/PickupCollection.cc
===================================================================
--- code/trunk/src/modules/pickup/PickupCollection.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupCollection.cc	(revision 7163)
@@ -35,4 +35,5 @@
 #include "core/XMLPort.h"
 #include "interfaces/PickupCarrier.h"
+#include "CollectiblePickup.h"
 #include "DroppedPickup.h"
 #include "PickupCollectionIdentifier.h"
@@ -42,5 +43,5 @@
 namespace orxonox
 {
- 
+
     CreateFactory(PickupCollection);
 
@@ -52,8 +53,13 @@
     {
         RegisterObject(PickupCollection);
-        
+
         this->pickupCollectionIdentifier_ = new PickupCollectionIdentifier(this);
-    }
-    
+        this->usedCounter_ = 0;
+        this->pickedUpCounter_ = 0;
+        this->disabledCounter_ = 0;
+        this->processingUsed_ = false;
+        this->processingPickedUp_ = false;
+    }
+
     /**
     @brief
@@ -62,12 +68,13 @@
     PickupCollection::~PickupCollection()
     {
-        //! Destroy all Pickupables constructing this PickupCollection.
-        for(std::vector<WeakPtr<Pickupable> >::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
-        {
-            if((*it).get() != NULL)
-                (*it).get()->destroy();
-        }
-    }
-    
+        // Destroy all Pickupables constructing this PickupCollection.
+        for(std::vector<CollectiblePickup*>::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
+        {
+            (*it)->removeFromCollection();
+            (*it)->destroy();
+        }
+        this->pickups_.clear();
+    }
+
     /**
     @brief
@@ -77,10 +84,10 @@
     {
         SUPER(PickupCollection, XMLPort, xmlelement, mode);
-        
-        XMLPortObject(PickupCollection, Pickupable, "pickupables", addPickupable, getPickupable, xmlelement, mode);
-        
+
+        XMLPortObject(PickupCollection, CollectiblePickup, "pickupables", addPickupable, getPickupable, xmlelement, mode);
+
         this->initializeIdentifier();
     }
-    
+
     /**
     @brief
@@ -89,10 +96,10 @@
     void PickupCollection::initializeIdentifier(void)
     {
-        for(std::vector<WeakPtr<Pickupable> >::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
-        {
-            this->pickupCollectionIdentifier_->addPickup((*it).get()->getPickupIdentifier());
-        }
-    }
-    
+        for(std::vector<CollectiblePickup*>::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
+        {
+            this->pickupCollectionIdentifier_->addPickup((*it)->getPickupIdentifier());
+        }
+    }
+
     /**
     @brief
@@ -103,12 +110,35 @@
     {
         SUPER(PickupCollection, changedUsed);
-        
-        //! Change used for all Pickupables this PickupCollection consists of.
-        for(std::vector<WeakPtr<Pickupable> >::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
-        {
-            (*it).get()->setUsed(this->isUsed());
-        }
-    }
-    
+
+        this->processingUsed_ = true;
+        // Change used for all Pickupables this PickupCollection consists of.
+        for(std::vector<CollectiblePickup*>::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
+        {
+            (*it)->setUsed(this->isUsed());
+        }
+        this->processingUsed_ = false;
+
+        this->changedUsedAction();
+    }
+
+    /**
+    @brief
+        Helper method.
+        Checks whether due to changes in the used status of the pickups of this PickupCollection the used status of this PickupCollection has to change as well.
+    */
+    void PickupCollection::changedUsedAction(void)
+    {
+        if(this->processingUsed_)
+            return;
+
+        // If all the pickups are not in use but the PickupCollection is.
+        if(this->usedCounter_ == 0 && this->isUsed())
+            this->setUsed(false);
+
+        // If all the enabled pickups are in use but the PickupCollection is not.
+        if(this->usedCounter_ != 0 && this->usedCounter_ == this->pickups_.size()-this->disabledCounter_ && !this->isUsed())
+            this->setUsed(true);
+    }
+
     /**
     @brief
@@ -119,12 +149,15 @@
     {
         SUPER(PickupCollection, changedCarrier);
-        
-        //! Change the PickupCarrier for all Pickupables this PickupCollection consists of.
-        for(std::vector<WeakPtr<Pickupable> >::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
-        {
-            (*it).get()->setCarrier(this->getCarrier()->getTarget(*it));
-        }
-    }
-    
+
+        // Change the PickupCarrier for all Pickupables this PickupCollection consists of.
+        for(std::vector<CollectiblePickup*>::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
+        {
+            if(this->getCarrier() == NULL)
+                (*it)->setCarrier(NULL);
+            else
+                (*it)->setCarrier(this->getCarrier()->getTarget(*it));
+        }
+    }
+
     /**
     @brief
@@ -135,12 +168,35 @@
     {
         SUPER(PickupCollection, changedPickedUp);
-        
-        //! Change the pickedUp status for all Pickupables this PickupCollection consists of.
-        for(std::vector<WeakPtr<Pickupable> >::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
-        {
-            (*it).get()->setPickedUp(this->isPickedUp());
-        }
-    }
-    
+
+        this->processingPickedUp_ = true;
+        // Change the pickedUp status for all Pickupables this PickupCollection consists of.
+        for(std::vector<CollectiblePickup*>::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
+        {
+            (*it)->setPickedUp(this->isPickedUp());
+        }
+        this->processingPickedUp_ = false;
+
+        this->changedPickedUpAction();
+    }
+
+    /**
+    @brief
+        Helper method.
+        Checks whether due to changes in the picked up status of the pickups of this PickupCollection the picked up status of this PickupCollection has to change as well.
+    */
+    void PickupCollection::changedPickedUpAction(void)
+    {
+        if(this->processingPickedUp_)
+            return;
+
+        // If at least all the enabled pickups of this PickupCollection are no longer picked up. 
+        if(this->pickedUpCounter_ <= this->disabledCounter_ && this->isPickedUp())
+            this->Pickupable::destroy();
+
+        // If the PickupCollection is no longer picked up.
+        if(!this->isPickedUp())
+            this->pickedUpCounter_ = 0;
+    }
+
     /**
     @brief
@@ -154,18 +210,19 @@
         if(item == NULL)
             item = new PickupCollection(this);
-        
+
         SUPER(PickupCollection, clone, item);
-        
+
         PickupCollection* pickup = dynamic_cast<PickupCollection*>(item);
-        //! Clone all Pickupables this PickupCollection consist of.
-        for(std::vector<WeakPtr<Pickupable> >::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
-        {
-            Pickupable* newPickup = (*it).get()->clone();
-            pickup->addPickupable(newPickup);
+        // Clone all Pickupables this PickupCollection consist of.
+        for(std::vector<CollectiblePickup*>::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
+        {
+            Pickupable* newPickup = (*it)->clone();
+            CollectiblePickup* collectible = static_cast<CollectiblePickup*>(newPickup);
+            pickup->addPickupable(collectible);
         }
 
         pickup->initializeIdentifier();
     }
-    
+
     /**
     @brief
@@ -178,13 +235,13 @@
     bool PickupCollection::isTarget(PickupCarrier* carrier) const
     {
-        for(std::vector<WeakPtr<Pickupable> >::const_iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
-        {
-            if(!carrier->isTarget((*it).get()))
+        for(std::vector<CollectiblePickup*>::const_iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
+        {
+            if(!carrier->isTarget(*it))
                 return false;
         }
-        
+
         return true;
     }
-    
+
     /**
     @brief
@@ -198,5 +255,5 @@
         return this->pickupCollectionIdentifier_;
     }
-    
+
     /**
     @brief
@@ -207,14 +264,14 @@
         Returns true if successful,
     */
-    bool PickupCollection::addPickupable(Pickupable* pickup)
+    bool PickupCollection::addPickupable(CollectiblePickup* pickup)
     {
         if(pickup == NULL)
             return false;
-        
-        WeakPtr<Pickupable> ptr = pickup; //!< Create a weak pointer to be able to test in the constructor if the Pointer is still valid.
-        this->pickups_.push_back(ptr);
+
+        pickup->addToCollection(this);
+        this->pickups_.push_back(pickup);
         return true;
     }
-    
+
     /**
     @brief
@@ -227,7 +284,51 @@
     const Pickupable* PickupCollection::getPickupable(unsigned int index)
     {
-        return this->pickups_[index].get();
-    }
-        
+        return this->pickups_[index];
+    }
+
+    /**
+    @brief
+        Informs the PickupCollection, that one of its pickups has changed its used status to the input value.
+        This is used internally by the CollectiblePickup class.
+    @param changed
+        The value the used status has changed to. 
+    */
+    void PickupCollection::pickupChangedUsed(bool changed)
+    {
+        if(changed)
+            this->usedCounter_++;
+        else
+            this->usedCounter_--;
+
+        this->changedUsedAction();
+    }
+
+    /**
+    @brief
+        Informs the PickupCollection, that one of its pickups has changed its picked up status to the input value.
+        This is used internally by the CollectiblePickup class.
+    @param changed
+        The value the picked up status has changed to.
+    */
+    void PickupCollection::pickupChangedPickedUp(bool changed)
+    {
+        if(changed)
+            this->pickedUpCounter_++;
+        else
+            this->pickedUpCounter_--;
+
+        this->changedPickedUpAction();
+    }
+
+    /**
+    @brief
+        Informs the PickupCollection, that one of its pickups has been disabled.
+        This is used internally by the CollectiblePickup class.
+    */
+    void PickupCollection::pickupDisabled(void)
+    {
+        this->disabledCounter_++;
+    }
+
     /**
     @brief
@@ -245,4 +346,4 @@
         return true;
     }
-    
+
 }
Index: code/trunk/src/modules/pickup/PickupCollection.h
===================================================================
--- code/trunk/src/modules/pickup/PickupCollection.h	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupCollection.h	(revision 7163)
@@ -37,6 +37,6 @@
 #include "PickupPrereqs.h"
 
-#include "interfaces/Pickupable.h"
 #include "core/BaseObject.h"
+#include "CollectiblePickup.h"
 
 #include <list>
@@ -47,16 +47,15 @@
     /**
     @brief
-        The PickupCollection combines different Pickupables to a coherent, single pickup and makes the seem (from the outside looking in) just as if they were just one Pickupable.
+        The PickupCollection combines different Pickupables to a coherent, single pickup and makes them seem (from the outside looking in) just as if they were just one Pickupable.
     @author
         Damian 'Mozork' Frick
     */
-    class _PickupExport PickupCollection : public Pickupable, public BaseObject
+    class _PickupExport PickupCollection : public CollectiblePickup, public BaseObject
     {
-        
+
         public:
-            
             PickupCollection(BaseObject* creator); //!< Default Constructor.
             virtual ~PickupCollection(); //!< Destructor.
-            
+
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); //!< Creates an instance of this Class through XML.
 
@@ -64,27 +63,40 @@
             virtual void changedCarrier(void); //!< Is called when the pickup has changed its PickupCarrier.
             virtual void changedPickedUp(void); //!< Is called when the pickup has transited from picked up to dropped or the other way around.
-            
+
             virtual void clone(OrxonoxClass*& item); //!< Creates a duplicate of the input OrxonoxClass.
-            
+
             virtual bool isTarget(PickupCarrier* carrier) const; //!< Get whether a given class, represented by the input Identifier, is a target of this PickupCollection.
-            
+
             virtual const PickupIdentifier* getPickupIdentifier(void); //!< Get the PickupIdentifier of this PickupCollection.
-            
-            bool addPickupable(Pickupable* pickup); //!< Add the input Pickupable to list of Pickupables combined by this PickupCollection.
+
+            bool addPickupable(CollectiblePickup* pickup); //!< Add the input Pickupable to list of Pickupables combined by this PickupCollection.
             const Pickupable* getPickupable(unsigned int index); //!< Get the Pickupable at the given index.
-            
+
+            void pickupChangedUsed(bool changed); //!< Informs the PickupCollection, that one of its pickups has changed its used status to the input value.
+            void pickupChangedPickedUp(bool changed); //!< Informs the PickupCollection, that one of its pickups has changed its picked up status to the input value.
+            void pickupDisabled(void); //!< Informs the PickupCollection, that one of its pickups has been disabled.
+
         protected:
             void initializeIdentifier(void); //!< Initializes the PickupIdentifier for this pickup.
+
+            virtual bool createSpawner(void); //!< Facilitates the creation of a PickupSpawner upon dropping of the Pickupable.
+
+            PickupCollectionIdentifier* pickupCollectionIdentifier_; //!< The PickupCollectionIdentifier of this PickupCollection. Is used to distinguish different PickupCollections amongst themselves.
+
+        private:
+            void changedUsedAction(void); //!< Helper method.
+            void changedPickedUpAction(void); //!< Helper method.
             
-            virtual bool createSpawner(void); //!< Facilitates the creation of a PickupSpawner upon dropping of the Pickupable.
-            
-            PickupCollectionIdentifier* pickupCollectionIdentifier_; //!< The PickupCollectionIdentifier of this PickupCollection. Is used to distinguish different PickupCollections amongst themselves.
-            
-        private:
-            
-            std::vector<WeakPtr<Pickupable> > pickups_; //!< The list of the pointers of all the Pickupables this PickupCollection consists of. They are weak pointers to facilitate testing, whether the pointers are still valid.
-        
+            std::vector<CollectiblePickup*> pickups_; //!< The list of the pointers of all the Pickupables this PickupCollection consists of. They are weak pointers to facilitate testing, whether the pointers are still valid.
+
+            unsigned int usedCounter_; //!< Keeps track of the number of pickups of this PickupCollection, that are in use.
+            unsigned int pickedUpCounter_; //!< Keeps track of the number of pickups of this PickupCollection, that are picked up.
+            unsigned int disabledCounter_; //!< Keeps track of the number of pickups of this PickupCollection, that are disabled.
+
+            bool processingUsed_; //!< Boolean to ensure, that the PickupCollection doesn't update its used status while its internal state is inconsistent.
+            bool processingPickedUp_; //!< Boolean to ensure, that the PickupCollection doesn't update its picked upp status while its internal state is inconsistent.
+
     };
-    
+
 }
 
Index: code/trunk/src/modules/pickup/PickupCollectionIdentifier.cc
===================================================================
--- code/trunk/src/modules/pickup/PickupCollectionIdentifier.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupCollectionIdentifier.cc	(revision 7163)
@@ -38,5 +38,5 @@
 namespace orxonox
 {
-    
+
     /**
     @brief
@@ -47,5 +47,5 @@
         RegisterObject(PickupCollectionIdentifier);
     }
-    
+
     /**
     @brief
@@ -54,5 +54,5 @@
     PickupCollectionIdentifier::~PickupCollectionIdentifier()
     {
-        
+
     }
 
@@ -67,23 +67,23 @@
     int PickupCollectionIdentifier::compare(const PickupIdentifier* identifier) const
     {
-        //! Slight un-niceity to cast the PickupIdentifier to a PickupCollectionIdentifier.
+        // Slight un-niceity to cast the PickupIdentifier to a PickupCollectionIdentifier.
         PickupIdentifier* temp = const_cast<PickupIdentifier*>(identifier);
         const PickupCollectionIdentifier* collectionIdentifier = dynamic_cast<PickupCollectionIdentifier*>(temp);
-        
-        //! If the input PickupIdentifier 'identifier' is no PickupCollectionIdentifier then just the two PickupIdentifiers are compared.
+
+        // If the input PickupIdentifier 'identifier' is no PickupCollectionIdentifier then just the two PickupIdentifiers are compared.
         if(collectionIdentifier == NULL)
         {
             return this->PickupIdentifier::compare(identifier);
         }
-        
-        //! If the number of Pickupables each of the two PickupCollectionIdentifiers contain differ, the one with less is considered smaller.
+
+        // If the number of Pickupables each of the two PickupCollectionIdentifiers contain differ, the one with less is considered smaller.
         if(this->identifiers_.size() != collectionIdentifier->identifiers_.size())
             return this->identifiers_.size()-collectionIdentifier->identifiers_.size();
-        
-        //! Compare the Pickupables of the two PickupCollectionIdentifiers one after the other. the one with the first 'smaller' one is considered smaller.
+
+        // Compare the Pickupables of the two PickupCollectionIdentifiers one after the other. the one with the first 'smaller' one is considered smaller.
         std::set<const PickupIdentifier*, PickupIdentifierCompare>::const_iterator it2 = collectionIdentifier->identifiers_.begin();
         for(std::set<const PickupIdentifier*, PickupIdentifierCompare>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); it++)
         {
-            
+
             if((*it)->compare(*it2) < 0)
                 return -1;
@@ -91,9 +91,9 @@
                 return 1;
         }
-        
+
         //! Means they are equal.
         return 0;
     }
-    
+
     /**
     @brief
@@ -106,5 +106,5 @@
         this->identifiers_.insert(identifier);
     }
-    
+
 }
 
Index: code/trunk/src/modules/pickup/PickupCollectionIdentifier.h
===================================================================
--- code/trunk/src/modules/pickup/PickupCollectionIdentifier.h	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupCollectionIdentifier.h	(revision 7163)
@@ -54,18 +54,18 @@
     class _PickupExport PickupCollectionIdentifier : public PickupIdentifier
     {
-        
+
         public:
             PickupCollectionIdentifier(Pickupable* pickup); //!< Constructor.
             ~PickupCollectionIdentifier(); //!< Destructor.
-            
+
             virtual int compare(const PickupIdentifier* identifier) const; //!< Compares a PickupCollectionIdentifier with a PickupIdentifier.
-            
+
             void addPickup(const PickupIdentifier* identifier); //!< Add a Pickupable to the PickupCollectionIdentifier.
-            
+
         private:
             std::set<const PickupIdentifier*, PickupIdentifierCompare> identifiers_; //!< The set of PickupIdentifiers of the Pickupables the PickupCollection with this PickupCollectionIdentifier consists of, ordered by the rule set by PickupIdentifierCompare.
-            
+
     };
-    
+
 }
 
Index: code/trunk/src/modules/pickup/PickupManager.cc
===================================================================
--- code/trunk/src/modules/pickup/PickupManager.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupManager.cc	(revision 7163)
@@ -39,7 +39,9 @@
 #include "core/ScopedSingletonManager.h"
 #include "core/Identifier.h"
+#include "util/Convert.h"
 #include "interfaces/PickupCarrier.h"
 #include "infos/PlayerInfo.h"
 #include "worldentities/pawns/Pawn.h"
+#include "CollectiblePickup.h"
 #include "PickupRepresentation.h"
 
@@ -50,9 +52,9 @@
     // Register tolua_open function when loading the library
     DeclareToluaInterface(Pickup);
-    
-    ManageScopedSingleton(PickupManager, ScopeID::Graphics, false);
-    
+
+    ManageScopedSingleton(PickupManager, ScopeID::Root, false);
+
     /*static*/ const std::string PickupManager::guiName_s = "PickupInventory";
-    
+
     /**
     @brief
@@ -62,10 +64,15 @@
     {
         RegisterRootObject(PickupManager);
-        
+
+        //TODO: This doesn't work, yet.
+        if( GameMode::showsGraphics() )
+        {
+            GUIManager::getInstance().loadGUI(PickupManager::guiName_s);
+        }
         this->defaultRepresentation_ = new PickupRepresentation();
-        
+
         COUT(3) << "PickupManager created." << std::endl;
     }
-    
+
     /**
     @brief
@@ -77,10 +84,10 @@
         if(this->defaultRepresentation_ != NULL)
             this->defaultRepresentation_->destroy();
-        
+
         this->representations_.clear();
-        
+
         COUT(3) << "PickupManager destroyed." << std::endl;
     }
-    
+
     /**
     @brief
@@ -95,14 +102,14 @@
     */
     bool PickupManager::registerRepresentation(const PickupIdentifier* identifier, PickupRepresentation* representation)
-    {       
+    {
         if(identifier == NULL || representation == NULL || this->representations_.find(identifier) != this->representations_.end()) //!< If the Pickupable already has a Representation registered.
             return false;
-        
+
         this->representations_[identifier] = representation;
-        
+
         COUT(4) << "PickupRepresentation " << representation << " registered with the PickupManager." << std::endl;
         return true;
     }
-    
+
     /**
     @brief
@@ -116,18 +123,18 @@
     */
     bool PickupManager::unregisterRepresentation(const PickupIdentifier* identifier, PickupRepresentation* representation)
-    {       
+    {
         if(identifier == NULL || representation == NULL)
             return false;
-        
+
         std::map<const PickupIdentifier*, PickupRepresentation*, PickupIdentifierCompare>::iterator it = this->representations_.find(identifier);
         if(it == this->representations_.end()) //!< If the Pickupable is not registered in the first place.
             return false;
-        
+
         this->representations_.erase(it);
-        
+
         COUT(4) << "PickupRepresentation " << representation << " unregistered with the PickupManager." << std::endl;
         return true;
     }
-    
+
     /**
     @brief
@@ -146,67 +153,84 @@
             return this->defaultRepresentation_;
         }
-        
+
         return it->second;
     }
-    
-    PickupCarrier* PickupManager::getPawn(void)
-    {
+
+    int PickupManager::getNumPickups(void)
+    {
+        this->pickupsList_.clear();
+
         PlayerInfo* player = GUIManager::getInstance().getPlayer(PickupManager::guiName_s);
+        PickupCarrier* carrier = NULL;
         if (player != NULL)
-            return dynamic_cast<PickupCarrier*>(player->getControllableEntity());
+            carrier =  dynamic_cast<PickupCarrier*>(player->getControllableEntity());
         else
-            return NULL;
-    }
-    
-    int PickupManager::getNumCarrierChildren(PickupCarrier* carrier)
-    {
-        if(carrier == NULL)
             return 0;
-        return carrier->getNumCarrierChildren();
-    }
-            
-    PickupCarrier* PickupManager::getCarrierChild(int index, PickupCarrier* carrier)
-    {
-        if(carrier == NULL)
-            return NULL;
-        return carrier->getCarrierChild(index);
-    }
-    
-    const std::string& PickupManager::getCarrierName(orxonox::PickupCarrier* carrier)
-    {
-        if(carrier == NULL)
-            return BLANKSTRING;
-        return carrier->getCarrierName();
-    }
-    
-    PickupRepresentation* PickupManager::getPickupRepresentation(int index, PickupCarrier* carrier)
-    {
-        Pickupable* pickup = carrier->getPickup(index);
-        if(pickup == NULL)
-            return NULL;
-        
-        return this->getRepresentation(pickup->getPickupIdentifier());
-    }
-    
-    int PickupManager::getNumPickups(PickupCarrier* carrier)
-    {
-        if(carrier == NULL)
-            return 0;
-        return carrier->getNumPickups();
-    }
-    
-    void PickupManager::dropPickup(int index, PickupCarrier* carrier)
-    {
-        Pickupable* pickup = carrier->getPickup(index);
-        if(pickup != NULL)
-            carrier->drop(pickup);
-    }
-    
-    void PickupManager::usePickup(int index, PickupCarrier* carrier, bool use)
-    {
-        Pickupable* pickup = carrier->getPickup(index);
-        if(pickup != NULL)
+
+        std::vector<PickupCarrier*>* carriers = this->getAllCarriers(carrier);
+        for(std::vector<PickupCarrier*>::iterator it = carriers->begin(); it != carriers->end(); it++)
+        {
+            std::set<Pickupable*> pickups = (*it)->getPickups();
+            for(std::set<Pickupable*>::iterator pickup = pickups.begin(); pickup != pickups.end(); pickup++)
+            {
+                CollectiblePickup* collectible = orxonox_cast<CollectiblePickup*>(*pickup);
+                if(collectible == NULL || !collectible->isInCollection())
+                    this->pickupsList_.insert(std::pair<Pickupable*, WeakPtr<Pickupable> >(*pickup, WeakPtr<Pickupable>(*pickup)));
+            }
+        }
+        delete carriers;
+
+        this->pickupsIterator_ = this->pickupsList_.begin();
+        return this->pickupsList_.size();
+    }
+
+    std::vector<PickupCarrier*>* PickupManager::getAllCarriers(PickupCarrier* carrier)
+    {
+        //TODO: More efficiently.
+        std::vector<PickupCarrier*>* carriers = new std::vector<PickupCarrier*>();
+        carriers->insert(carriers->end(), carrier);
+        std::vector<PickupCarrier*>* children = carrier->getCarrierChildren();
+        for(std::vector<PickupCarrier*>::iterator it = children->begin(); it != children->end(); it++)
+        {
+            std::vector<PickupCarrier*>* childrensChildren = this->getAllCarriers(*it);
+            for(std::vector<PickupCarrier*>::iterator it2 = childrensChildren->begin(); it2 != childrensChildren->end(); it2++)
+            {
+                carriers->insert(carriers->end(), *it2);
+            }
+            delete childrensChildren;
+        }
+        delete children;
+        return carriers;
+    }
+
+    void PickupManager::dropPickup(orxonox::Pickupable* pickup)
+    {
+        std::map<Pickupable*, WeakPtr<Pickupable> >::iterator it = this->pickupsList_.find(pickup);
+        if(pickup == NULL || it == this->pickupsList_.end() || it->second.get() == NULL)
+            return;
+
+        if(!pickup->isPickedUp())
+            return;
+
+        PickupCarrier* carrier = pickup->getCarrier();
+        if(pickup != NULL && carrier != NULL)
+        {
+            pickup->drop(carrier);
+        }
+    }
+
+    void PickupManager::usePickup(orxonox::Pickupable* pickup, bool use)
+    {
+        std::map<Pickupable*, WeakPtr<Pickupable> >::iterator it = this->pickupsList_.find(pickup);
+        if(pickup == NULL || it == this->pickupsList_.end() || it->second.get() == NULL)
+            return;
+
+        if(!pickup->isPickedUp())
+            return;
+
+        PickupCarrier* carrier = pickup->getCarrier();
+        if(pickup != NULL && carrier != NULL)
             pickup->setUsed(use);
     }
-    
+
 }
Index: code/trunk/src/modules/pickup/PickupManager.h
===================================================================
--- code/trunk/src/modules/pickup/PickupManager.h	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupManager.h	(revision 7163)
@@ -39,4 +39,5 @@
 #include <map>
 #include "util/Singleton.h"
+#include "core/WeakPtr.h"
 #include "pickup/PickupIdentifier.h"
 #include "PickupRepresentation.h"
@@ -59,38 +60,39 @@
     { // tolua_export
         friend class Singleton<PickupManager>;
-        
+
         public:
             PickupManager();
             virtual ~PickupManager();
-            
+
             static PickupManager& getInstance() { return Singleton<PickupManager>::getInstance(); } // tolua_export
-            
+
             bool registerRepresentation(const PickupIdentifier* identifier, PickupRepresentation* representation); //!< Registers a PickupRepresentation together with the PickupIdentifier of the Pickupable the PickupRepresentation represents.
             bool unregisterRepresentation(const PickupIdentifier* identifier, PickupRepresentation* representation); //!< Unegisters a PickupRepresentation together with the PickupIdentifier of the Pickupable the PickupRepresentation represents.
             PickupRepresentation* getRepresentation(const PickupIdentifier* identifier); //!< Get the PickupRepresentation representing the Pickupable with the input PickupIdentifier.
-            
+
             // tolua_begin
-            orxonox::PickupCarrier* getPawn(void);
-            
-            int getNumCarrierChildren(orxonox::PickupCarrier* carrier);
-            orxonox::PickupCarrier* getCarrierChild(int index, orxonox::PickupCarrier* carrier);
-            
-            const std::string& getCarrierName(orxonox::PickupCarrier* carrier);
-            
-            int getNumPickups(orxonox::PickupCarrier* carrier);
-            PickupRepresentation* getPickupRepresentation(int index, orxonox::PickupCarrier* carrier);
-            void dropPickup(int index, orxonox::PickupCarrier* carrier);
-            void usePickup(int index, orxonox::PickupCarrier* carrier, bool use);
+            int getNumPickups(void);
+            orxonox::Pickupable* popPickup(void) { return (this->pickupsIterator_++)->first; }
+            orxonox::PickupRepresentation* getPickupRepresentation(orxonox::Pickupable* pickup) { if(pickup != NULL) return this->getRepresentation(pickup->getPickupIdentifier()); return NULL; }
+
+            void dropPickup(orxonox::Pickupable* pickup);
+            void usePickup(orxonox::Pickupable* pickup, bool use);
+            bool isValidPickup(orxonox::Pickupable* pickup) { std::map<Pickupable*, WeakPtr<Pickupable> >::iterator it = this->pickupsList_.find(pickup); if(it == this->pickupsList_.end()) return false; return it->second.get() != NULL; }
             // tolua_end
-            
+
         private:
             static PickupManager* singletonPtr_s;
             static const std::string guiName_s;
-            
+
             PickupRepresentation* defaultRepresentation_; //!< The default PickupRepresentation.
             std::map<const PickupIdentifier*, PickupRepresentation*, PickupIdentifierCompare> representations_; //!< Map linking PickupIdentifiers (representing types if Pickupables) and PickupRepresentations.
-        
+
+            std::map<Pickupable*, WeakPtr<Pickupable> > pickupsList_;
+            std::map<Pickupable*, WeakPtr<Pickupable> >::iterator pickupsIterator_;
+
+            std::vector<PickupCarrier*>* getAllCarriers(PickupCarrier* carrier);
+
     }; // tolua_export
-    
+
 } // tolua_export
 
Index: code/trunk/src/modules/pickup/PickupPrereqs.h
===================================================================
--- code/trunk/src/modules/pickup/PickupPrereqs.h	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupPrereqs.h	(revision 7163)
@@ -43,5 +43,5 @@
 //-----------------------------------------------------------------------
 
-#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_STATIC_BUILD)
+#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(PICKUP_STATIC_BUILD)
 #  ifdef PICKUP_SHARED_BUILD
 #    define _PickupExport __declspec(dllexport)
@@ -65,5 +65,6 @@
 namespace orxonox
 {
-    
+
+    class CollectiblePickup;
     class DroppedPickup;
     class Pickup;
@@ -75,8 +76,10 @@
 
     //items
+    class DronePickup;
     class HealthPickup;
     class InvisiblePickup;
     class MetaPickup;
     class SpeedPickup;
+    class ShieldPickup;
 
 }
Index: code/trunk/src/modules/pickup/PickupRepresentation.cc
===================================================================
--- code/trunk/src/modules/pickup/PickupRepresentation.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupRepresentation.cc	(revision 7163)
@@ -41,7 +41,7 @@
 namespace orxonox
 {
-    
+
     CreateFactory(PickupRepresentation);
-    
+
     /**
     @brief
@@ -52,8 +52,8 @@
     {
         RegisterObject(PickupRepresentation);
-        
+
         this->initialize();
     }
-    
+
     /**
     @brief
@@ -63,8 +63,8 @@
     {
         RegisterObject(PickupRepresentation);
-        
+
         this->initialize();
     }
-    
+
     /**
     @brief
@@ -75,9 +75,9 @@
         if(this->spawnerRepresentation_ != NULL)
             this->spawnerRepresentation_->destroy();
-        
+
         if(this->pickup_ != NULL)
             PickupManager::getInstance().unregisterRepresentation(this->pickup_->getPickupIdentifier(), this);
     }
-    
+
     /**
     @brief
@@ -91,5 +91,5 @@
         this->inventoryRepresentation_ = "Default";
     }
-    
+
     /**
     @brief
@@ -99,5 +99,5 @@
     {
         SUPER(PickupRepresentation, XMLPort, xmlelement, mode);
-        
+
         XMLPortParam(PickupRepresentation, "pickupName", setPickupName, getPickupName, xmlelement, mode);
         XMLPortParam(PickupRepresentation, "pickupDescription", setPickupDescription, getPickupDescription, xmlelement, mode);
@@ -106,13 +106,13 @@
         XMLPortObject(PickupRepresentation, Pickupable, "pickup", setPickup, getPickup, xmlelement, mode);
         XMLPortObject(PickupRepresentation, StaticEntity, "spawner-representation", setSpawnerRepresentation, getSpawnerRepresentationIndex, xmlelement, mode);
-        
+
         PickupManager::getInstance().registerRepresentation(this->pickup_->getPickupIdentifier(), this); //!< Registers the PickupRepresentation with the PickupManager through the PickupIdentifier of the Pickupable it represents.
-        
+
         if(this->spawnerRepresentation_ != NULL)
             this->spawnerRepresentation_->setVisible(false);
-        
+
         COUT(4) << "PickupRepresentation created: name: '" << this->name_ << "', description: '" << this->description_ << "', spawnerTemplate: '" << this->spawnerTemplate_ << "'." << std::endl;
     }
-    
+
     /**
     @brief
@@ -136,14 +136,14 @@
             this->addTemplate(this->spawnerTemplate_);
         }
-        
+
         StaticEntity* representation = this->spawnerRepresentation_;
         representation->setVisible(true);
-        
+
         this->addTemplate(this->spawnerTemplate_);
         this->spawnerRepresentation_->setVisible(false);
-        
+
         return representation;
     }
-    
+
     /**
     @brief
@@ -171,4 +171,4 @@
         return representation;
     }
-    
+
 }
Index: code/trunk/src/modules/pickup/PickupRepresentation.h
===================================================================
--- code/trunk/src/modules/pickup/PickupRepresentation.h	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupRepresentation.h	(revision 7163)
@@ -56,12 +56,12 @@
         : public BaseObject
     { // tolua_export
-        
+
         public:
             PickupRepresentation(); //!< Constructor
             PickupRepresentation(BaseObject* creator); //!< Default constructor.
             virtual ~PickupRepresentation(); //!< Destructor.
-            
+
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            
+
             /**
             @brief Set the name of the Pickupable represented by this PickupRepresentation.
@@ -102,5 +102,5 @@
             inline void setPickup(Pickupable* pickup)
                 { this->pickup_ = pickup; }
-                
+
             /**
             @brief Get the name of the Pickupable represented by this PickupRepresentation.
@@ -138,22 +138,22 @@
             inline const Pickupable* getPickup(unsigned int index)
                 { if(index == 0) return this->pickup_; return NULL; }
-                
+
             StaticEntity* getSpawnerRepresentation(PickupSpawner* spawner); //!< Get a spawnerRepresentation for a specific PickupSpawner.
-        
+
         private:
             void initialize(void); //!< Initializes the member variables of this PickupRepresentation.
             StaticEntity* getDefaultSpawnerRepresentation(PickupSpawner* spawner); //!< Get the default spawnerRepresentation for a specific PickupSpawner.
-            
+
             std::string name_; //!< The name of the Pickupable represented by this PickupRepresentation.
             std::string description_; //!< The description of the Pickupable represented by this PickupRepresentation.
             std::string spawnerTemplate_; //!<  The name of the template of this PickupRepresentation.
             StaticEntity* spawnerRepresentation_; //!< The spawnerRepresentation of this PickupRepresentation.
-            std::string inventoryRepresentation_; //!< The name of an image representing the pickup in the PickupInventory. TODO: Exact format and placement of image?
-            
+            std::string inventoryRepresentation_; //!< The name of an image representing the pickup in the PickupInventory.
+
             Pickupable* pickup_; //!< The Pickupable that is represented by this PickupRepresentation.
-            
+
     }; // tolua_export
 
 } // tolua_export
-    
+
 #endif // _PickupRepresentation_H__
Index: code/trunk/src/modules/pickup/PickupSpawner.cc
===================================================================
--- code/trunk/src/modules/pickup/PickupSpawner.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupSpawner.cc	(revision 7163)
@@ -55,5 +55,5 @@
     {
         RegisterObject(PickupSpawner);
-        
+
         this->initialize();
     }
@@ -76,7 +76,7 @@
     {
         RegisterObject(PickupSpawner);
-        
+
         this->initialize();
-  
+
         this->pickup_ = pickup;
 
@@ -84,5 +84,5 @@
         this->respawnTime_ = respawnTime;
         this->setMaxSpawnedItems(maxSpawnedItems);
-        
+
         if(this->pickup_ == NULL)
         {
@@ -107,4 +107,5 @@
         this->maxSpawnedItems_ = INF;
         this->spawnsRemaining_ = INF;
+        this->selfDestruct_ = false;
     }
 
@@ -115,5 +116,5 @@
     PickupSpawner::~PickupSpawner()
     {
-        if(this->pickup_ != NULL)
+        if(this->selfDestruct_ && this->pickup_ != NULL)
             this->pickup_->destroy();
     }
@@ -132,9 +133,9 @@
 
         XMLPortObject(PickupSpawner, Pickupable, "pickup", setPickupable, getPickupable, xmlelement, mode);
-        
+
         XMLPortParam(PickupSpawner, "triggerDistance", setTriggerDistance, getTriggerDistance, xmlelement, mode);
         XMLPortParam(PickupSpawner, "respawnTime", setRespawnTime, getRespawnTime, xmlelement, mode);
         XMLPortParam(PickupSpawner, "maxSpawnedItems", setMaxSpawnedItems, getMaxSpawnedItems, xmlelement, mode);
-        
+
         if(this->pickup_ == NULL)
         {
@@ -150,5 +151,5 @@
         }
     }
-    
+
     /**
     @brief
@@ -161,5 +162,5 @@
         this->setVisible(this->isActive());
     }
-     
+
     /**
     @brief
@@ -172,8 +173,10 @@
     {
         SUPER(PickupSpawner, tick, dt);
-        
+
         //! If the PickupSpawner is active.
         if (this->isActive())
         {
+            SmartPtr<PickupSpawner> temp = this; //Create a smart pointer to keep the PickupSpawner alive until we iterated through all Pawns (in case a Pawn takes the last pickup)
+
             //! Iterate trough all Pawns.
             for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it != ObjectList<Pawn>::end(); ++it)
@@ -189,5 +192,5 @@
         }
     }
-    
+
     /**
     @brief
@@ -201,5 +204,5 @@
         this->spawnsRemaining_ = items;
     }
-    
+
     /**
     @brief
@@ -223,10 +226,10 @@
         else
         {
-            COUT(3) << "PickupSpawner empty, selfdestruct initialized." << std::endl;
+            COUT(4) << "PickupSpawner (&" << this << ") empty, selfdestruct initialized." << std::endl;
             this->setActive(false);
             this->destroy();
         }
     }
-    
+
     /**
     @brief
@@ -237,5 +240,5 @@
         this->respawnTimer_.setTimer(this->respawnTime_, false, createExecutor(createFunctor(&PickupSpawner::respawnTimerCallback, this)));
     }
-    
+
     /**
     @brief
@@ -248,16 +251,16 @@
         if(this->pickup_ != NULL)
         {
-            COUT(1) << "In PickupSpawner: setPickupable called, with this->pickup_ already set." << std::endl;
+            COUT(1) << "In PickupSpawner (&" << this << "): setPickupable called, with this->pickup_ already set." << std::endl;
             return;
         }
         if(pickup == NULL)
         {
-            COUT(1) << "In PickupSpawner: Argument of setPickupable is NULL." << std::endl;
+            COUT(1) << "In PickupSpawner (&" << this << "): Argument of setPickupable is NULL." << std::endl;
             return;
         }
-        
+
         this->pickup_ = pickup;
     }
-    
+
     /**
     @brief
@@ -282,6 +285,6 @@
         if (this->isActive()) //!< Checks whether PickupSpawner is active.
         {
-            COUT(3) << "PickupSpawner triggered and active." << std::endl;
-            
+            COUT(4) << "PickupSpawner (&" << this << ") triggered and active." << std::endl;
+
             PickupCarrier* carrier = dynamic_cast<PickupCarrier*>(pawn);
             if(carrier == NULL)
@@ -290,22 +293,21 @@
                 return;
             }
-            
+
             if(!carrier->isTarget(this->pickup_))
             {
-                COUT(4) << "PickupSpawner triggered but Pawn wasn't a target of the Pickupable." << std::endl;
+                COUT(4) << "PickupSpawner (&" << this << ") triggered but Pawn wasn't a target of the Pickupable." << std::endl;
                 return;
             }
-            
+
             PickupCarrier* target = carrier->getTarget(this->pickup_);
             Pickupable* pickup = this->getPickup();
-            
+
             if(target != NULL && pickup != NULL)
             {
-                if(target->pickup(pickup))
-                {
+                if(pickup->pickup(target))
                     this->decrementSpawnsRemaining();
-                }
                 else
                 {
+                    this->selfDestruct_ = true;
                     pickup->destroy();
                 }
@@ -314,12 +316,11 @@
             {
                 if(target == NULL)
-                    COUT(1) << "PickupSpawner: Pickupable has no target." << std::endl;
-                
+                    COUT(1) << "PickupSpawner (&" << this << "): Pickupable has no target." << std::endl;
+
                 if(pickup == NULL)
-                {
-                    COUT(1) << "PickupSpawner: getPickup produced an error, no Pickupable created." << std::endl;
-                }
+                    COUT(1) << "PickupSpawner (&" << this << "): getPickup produced an error, no Pickupable created." << std::endl;
                 else
                 {
+                    this->selfDestruct_ = true;
                     pickup->destroy();
                 }
@@ -333,5 +334,5 @@
     @return
         The Pickupable created.
-    */    
+    */
     Pickupable* PickupSpawner::getPickup(void)
     {
@@ -341,5 +342,5 @@
             return NULL;
         }
-        
+
         Pickupable* pickup = this->pickup_->clone();
         return pickup;
@@ -352,5 +353,5 @@
     void PickupSpawner::respawnTimerCallback()
     {
-        COUT(3) << "PickupSpawner reactivated." << std::endl;
+        COUT(4) << "PickupSpawner (&" << this << ") reactivated." << std::endl;
 
         this->setActive(true);
Index: code/trunk/src/modules/pickup/PickupSpawner.h
===================================================================
--- code/trunk/src/modules/pickup/PickupSpawner.h	(revision 6906)
+++ code/trunk/src/modules/pickup/PickupSpawner.h	(revision 7163)
@@ -101,17 +101,17 @@
         protected:
             void decrementSpawnsRemaining(void); //!< Decrements the number of remaining spawns.
-                        
+
             void startRespawnTimer(void);
-            
+
             virtual Pickupable* getPickup(void); //!< Creates a new Pickupable.
-            
+
             void setPickupable(Pickupable* pickup); //!< Sets a Pickupable for the PickupSpawner to spawn.
             const Pickupable* getPickupable(void); //!< Get the Pickupable that is spawned by this PickupSpawner.
-            
+
             Pickupable* pickup_; //!< The pickup to be spawned.
 
         private:
             void initialize(void);
-            
+
             void trigger(Pawn* pawn); //!< Method called when a Pawn is close enough.
             void respawnTimerCallback(); //!< Method called when the timer runs out.
@@ -125,4 +125,6 @@
             Timer respawnTimer_; //!< Timer used for re-activating.
 
+            bool selfDestruct_; //!< True if the PickupSpawner is selfdestructing.
+
             static const int INF = -1; //!< Constant for infinity.
     };
Index: code/trunk/src/modules/pickup/items/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/pickup/items/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/pickup/items/CMakeLists.txt	(revision 7163)
@@ -3,4 +3,6 @@
   InvisiblePickup.cc
   MetaPickup.cc
+  DronePickup.cc
   SpeedPickup.cc
+  ShieldPickup.cc
 )
Index: code/trunk/src/modules/pickup/items/DronePickup.cc
===================================================================
--- code/trunk/src/modules/pickup/items/DronePickup.cc	(revision 7163)
+++ code/trunk/src/modules/pickup/items/DronePickup.cc	(revision 7163)
@@ -0,0 +1,199 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Lukas Gasser
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+/**
+    @file DronePickup.cc
+    @brief Implementation of the DronePickup class.
+*/
+
+#include "DronePickup.h"
+#include "worldentities/Drone.h"
+#include "controllers/DroneController.h"
+
+#include "core/CoreIncludes.h"
+#include "core/XMLPort.h"
+#include "util/StringUtils.h"
+
+#include "worldentities/pawns/Pawn.h"
+#include "pickup/PickupIdentifier.h"
+
+#include <sstream>
+
+namespace orxonox
+{
+
+    CreateFactory(DronePickup);
+
+    /**
+    @brief
+        Constructor. Registers the object and initializes the member variables.
+    */
+    DronePickup::DronePickup(BaseObject* creator) : Pickup(creator)
+    {
+        RegisterObject(DronePickup);
+
+        this->initialize();
+    }
+
+    /**
+    @brief
+        Destructor.
+    */
+    DronePickup::~DronePickup()
+    {
+
+    }
+
+    /**
+    @brief
+        Initializes the member variables.
+    */
+    void DronePickup::initialize(void)
+    {
+        this->addTarget(ClassIdentifier<Pawn>::getIdentifier());
+        this->setDurationTypeDirect(pickupDurationType::once);
+        this->droneTemplate_ = "";
+    }
+
+    /**
+    @brief
+        Initializes the PickupIdentifier of this pickup.
+    */
+    void DronePickup::initializeIdentifier(void)
+    {
+        std::string val = this->getDroneTemplate();
+        std::string type = "droneTemplate";
+        this->pickupIdentifier_->addParameter(type, val);
+    }
+
+    /**
+    @brief
+        Method for creating a DronePickup object through XML.
+    */
+    void DronePickup::XMLPort(Element& xmlelement, orxonox::XMLPort::Mode mode)
+    {
+        SUPER(DronePickup, XMLPort, xmlelement, mode);
+        XMLPortParam(DronePickup, "droneTemplate", setDroneTemplate, getDroneTemplate, xmlelement, mode);
+
+        this->initializeIdentifier();
+    }
+
+    void DronePickup::setDroneTemplate(std::string templatename){
+        droneTemplate_ = templatename;
+    }
+
+    const std::string& DronePickup::getDroneTemplate() const
+    {
+        return droneTemplate_;
+    }
+
+    /**
+    @brief
+        Is called when the pickup has transited from used to unused or the other way around.
+    */
+    void DronePickup::changedUsed(void)
+    {
+        SUPER(DronePickup, changedUsed);
+
+        //! If the pickup is not picked up nothing must be done.
+        if(!this->isPickedUp())
+            return;
+
+        //! If the pickup has transited to used.
+        if(this->isUsed())
+        {
+
+                Pawn* pawn = this->carrierToPawnHelper();
+                if(pawn == NULL) //!< If the PickupCarrier is no Pawn, then this pickup is useless and therefore is destroyed.
+                    this->Pickupable::destroy();
+
+                //Attach to pawn
+                Drone* drone = new Drone(pawn->getCreator()); // this is neccessary because the projectiles fired need a valid creator for the particlespawner (when colliding against something)
+                drone->addTemplate(this->getDroneTemplate());
+
+                Controller* controller = drone->getController();
+                DroneController* droneController = dynamic_cast<DroneController*>(controller);
+                if(droneController != NULL)
+                {
+                    droneController->setOwner(pawn);
+                }
+
+                Vector3 spawnPosition = pawn->getWorldPosition() + Vector3(30,0,-30);
+                drone->setPosition(spawnPosition);
+
+                //! The pickup has been used up.
+                this->setUsed(false);
+        }
+        else
+        {
+            //! If either the pickup can only be used once or it is continuous and used up, it is destroyed upon setting it to unused.
+            if(this->isOnce() || (this->isContinuous() ))
+            {
+                this->Pickupable::destroy();
+            }
+        }
+    }
+
+    /**
+    @brief
+        Helper to transform the PickupCarrier to a Pawn, and throw an error message if the conversion fails.
+    @return
+        A pointer to the Pawn, or NULL if the conversion failed.
+    */
+    Pawn* DronePickup::carrierToPawnHelper(void)
+    {
+        PickupCarrier* carrier = this->getCarrier();
+        Pawn* pawn = dynamic_cast<Pawn*>(carrier);
+
+        if(pawn == NULL)
+        {
+            COUT(1) << "Invalid PickupCarrier in DronePickup." << std::endl;
+        }
+
+        return pawn;
+    }
+
+    /**
+    @brief
+        Creates a duplicate of the input OrxonoxClass.
+    @param item
+        A pointer to the Orxonox class.
+    */
+    void DronePickup::clone(OrxonoxClass*& item)
+    {
+        if(item == NULL)
+            item = new DronePickup(this);
+
+        SUPER(DronePickup, clone, item);
+
+        DronePickup* pickup = dynamic_cast<DronePickup*>(item);
+        pickup->setDroneTemplate(this->getDroneTemplate());
+
+        pickup->initializeIdentifier();
+    }
+}
Index: code/trunk/src/modules/pickup/items/DronePickup.h
===================================================================
--- code/trunk/src/modules/pickup/items/DronePickup.h	(revision 7163)
+++ code/trunk/src/modules/pickup/items/DronePickup.h	(revision 7163)
@@ -0,0 +1,79 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Lukas Gasser
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+/**
+    @file DronePickup.h
+    @brief Declaration of the DronePickup class.
+*/
+
+#ifndef _DronePickup_H__
+#define _DronePickup_H__
+
+#include "pickup/PickupPrereqs.h"
+
+#include <string>
+#include <worldentities/pawns/Pawn.h>
+#include <worldentities/Drone.h>
+
+#include "worldentities/StaticEntity.h"
+
+#include "pickup/Pickup.h"
+#include "tools/interfaces/Tickable.h"
+
+namespace orxonox {
+
+
+    class _PickupExport DronePickup : public Pickup, public Tickable
+    {
+        public:
+
+            DronePickup(BaseObject* creator); //!< Constructor.
+            virtual ~DronePickup(); //!< Destructor.
+
+            virtual void XMLPort(Element& xmlelement, orxonox::XMLPort::Mode mode); //!< Method for creating a DronePickup object through XML.
+
+            virtual void changedUsed(void); //!< Is called when the pickup has transited from used to unused or the other way around.
+            virtual void clone(OrxonoxClass*& item); //!< Creates a duplicate of the input OrxonoxClass.
+
+            void setDroneTemplate(std::string templatename);
+            const std::string& getDroneTemplate() const;
+
+        protected:
+            void initializeIdentifier(void); //!< Initializes the PickupIdentifier of this pickup.
+
+        private:
+            void initialize(void); //!< Initializes the member variables.
+            std::string droneTemplate_;
+            Pawn* carrierToPawnHelper(void); //!< Helper to transform the PickupCarrier to a Pawn, and throw an error message if the conversion fails.
+
+
+
+    };
+}
+
+#endif // _DronePickup_H__
Index: code/trunk/src/modules/pickup/items/HealthPickup.cc
===================================================================
--- code/trunk/src/modules/pickup/items/HealthPickup.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/items/HealthPickup.cc	(revision 7163)
@@ -45,11 +45,11 @@
 namespace orxonox
 {
-    
+
     /*static*/ const std::string HealthPickup::healthTypeLimited_s = "limited";
     /*static*/ const std::string HealthPickup::healthTypeTemporary_s = "temporary";
     /*static*/ const std::string HealthPickup::healthTypePermanent_s = "permanent";
-    
+
     CreateFactory(HealthPickup);
-    
+
     /**
     @brief
@@ -59,8 +59,8 @@
     {
         RegisterObject(HealthPickup);
-        
+
         this->initialize();
     }
-    
+
     /**
     @brief
@@ -69,13 +69,13 @@
     HealthPickup::~HealthPickup()
     {
-        
-    }
-    
-    /**
-    @brief 
+
+    }
+
+    /**
+    @brief
         Initializes the member variables.
     */
     void HealthPickup::initialize(void)
-    {        
+    {
         this->health_ = 0;
         this->healthRate_ = 0;
@@ -83,8 +83,8 @@
         this->maxHealthSave_ = 0;
         this->maxHealthOverwrite_ = 0;
-        
+
         this->addTarget(ClassIdentifier<Pawn>::getIdentifier());
     }
-    
+
     /**
     @brief
@@ -98,9 +98,9 @@
         std::string val1 = stream.str();
         this->pickupIdentifier_->addParameter(type1, val1);
-        
+
         std::string val2 = this->getHealthType();
         std::string type2 = "healthType";
         this->pickupIdentifier_->addParameter(type2, val2);
-        
+
         stream.clear();
         stream << this->getHealthRate();
@@ -109,5 +109,5 @@
         this->pickupIdentifier_->addParameter(type3, val3);
     }
-    
+
     /**
     @brief
@@ -117,15 +117,15 @@
     {
         SUPER(HealthPickup, XMLPort, xmlelement, mode);
-        
+
         XMLPortParam(HealthPickup, "health", setHealth, getHealth, xmlelement, mode);
         XMLPortParam(HealthPickup, "healthRate", setHealthRate, getHealthRate, xmlelement, mode);
         XMLPortParam(HealthPickup, "healthType", setHealthType, getHealthType, xmlelement, mode);
-        
+
         if(!this->isContinuous())
             this->healthRate_ = 0.0;
-        
+
         this->initializeIdentifier();
     }
-    
+
     /**
     @brief
@@ -138,11 +138,11 @@
     {
         SUPER(HealthPickup, tick, dt);
-        
+
         if(this->isContinuous() && this->isUsed())
         {
             Pawn* pawn = this->carrierToPawnHelper();
             if(pawn == NULL) //!< If the PickupCarrier is no Pawn, then this pickup is useless and therefore is destroyed.
-                this->destroy();
-            
+                this->Pickupable::destroy();
+
             //! Calculate the health that is added this tick.
             float health = dt*this->getHealthRate();
@@ -152,5 +152,5 @@
             float fullHealth = pawn->getHealth() + health;
             this->setHealth(this->getHealth()-health);
-                    
+
             switch(this->getHealthTypeDirect())
             {
@@ -173,5 +173,5 @@
                     COUT(1) << "Invalid healthType in HealthPickup." << std::endl;
             }
-            
+
             //! If all health has been transfered.
             if(this->getHealth() == 0)
@@ -181,5 +181,5 @@
         }
     }
-    
+
     /**
     @brief
@@ -189,9 +189,9 @@
     {
         SUPER(HealthPickup, changedUsed);
-        
+
         //! If the pickup is not picked up nothing must be done.
-        if(!this->isPickedUp())
+        if(!this->isPickedUp()) //TODO: Needed?
             return;
-        
+
         //! If the pickup has transited to used.
         if(this->isUsed())
@@ -201,6 +201,6 @@
                 Pawn* pawn = this->carrierToPawnHelper();
                 if(pawn == NULL) //!< If the PickupCarrier is no Pawn, then this pickup is useless and therefore is destroyed.
-                    this->destroy();
-                
+                    this->Pickupable::destroy();
+
                 float health = 0;
                 switch(this->getHealthTypeDirect())
@@ -226,5 +226,5 @@
                         COUT(1) << "Invalid healthType in HealthPickup." << std::endl;
                 }
-                
+
                 //! The pickup has been used up.
                 this->setUsed(false);
@@ -237,12 +237,12 @@
                 PickupCarrier* carrier = this->getCarrier();
                 Pawn* pawn = dynamic_cast<Pawn*>(carrier);
-                
+
                 if(pawn == NULL)
                 {
                     COUT(1) << "Something went horribly wrong in Health Pickup. PickupCarrier is no Pawn." << std::endl;
-                    this->destroy();
+                    this->Pickupable::destroy();
                     return;
                 }
-                
+
                 if(pawn->getMaxHealth() == this->maxHealthOverwrite_)
                 {
@@ -252,13 +252,13 @@
                 }
             }
-            
+
             //! If either the pickup can only be used once or it is continuous and used up, it is destroyed upon setting it to unused.
             if(this->isOnce() || (this->isContinuous() && this->getHealth() == 0))
             {
-                this->destroy();
-            }
-        }
-    }
-    
+                this->Pickupable::destroy();
+            }
+        }
+    }
+
     /**
     @brief
@@ -271,13 +271,13 @@
         PickupCarrier* carrier = this->getCarrier();
         Pawn* pawn = dynamic_cast<Pawn*>(carrier);
-        
+
         if(pawn == NULL)
         {
             COUT(1) << "Invalid PickupCarrier in HealthPickup." << std::endl;
         }
-        
+
         return pawn;
     }
-    
+
     /**
     @brief
@@ -290,15 +290,15 @@
         if(item == NULL)
             item = new HealthPickup(this);
-        
+
         SUPER(HealthPickup, clone, item);
-        
+
         HealthPickup* pickup = dynamic_cast<HealthPickup*>(item);
         pickup->setHealth(this->getHealth());
         pickup->setHealthRate(this->getHealthRate());
         pickup->setHealthTypeDirect(this->getHealthTypeDirect());
-        
+
         pickup->initializeIdentifier();
     }
-    
+
     /**
     @brief
@@ -322,5 +322,5 @@
         }
     }
-    
+
     /**
     @brief
@@ -341,5 +341,5 @@
         }
     }
-    
+
     /**
     @brief
@@ -356,8 +356,8 @@
         else
         {
-            COUT(1) << "Invalid healthSpeed in HealthPickup." << std::endl; 
-        }
-    }
-    
+            COUT(1) << "Invalid healthSpeed in HealthPickup." << std::endl;
+        }
+    }
+
     /**
     @brief
Index: code/trunk/src/modules/pickup/items/HealthPickup.h
===================================================================
--- code/trunk/src/modules/pickup/items/HealthPickup.h	(revision 6906)
+++ code/trunk/src/modules/pickup/items/HealthPickup.h	(revision 7163)
@@ -45,5 +45,5 @@
 
 namespace orxonox {
-    
+
     //! Enum for the type of the HealthPickup
     namespace pickupHealthType
@@ -56,5 +56,5 @@
         };
     }
-    
+
     /**
     @brief
@@ -71,14 +71,14 @@
     {
         public:
-        
+
             HealthPickup(BaseObject* creator); //!< Constructor.
             virtual ~HealthPickup(); //!< Destructor.
-            
+
             virtual void XMLPort(Element& xmlelement, orxonox::XMLPort::Mode mode); //!< Method for creating a HealthPickup object through XML.
             virtual void tick(float dt); //!< Is called every tick.
-            
+
             virtual void changedUsed(void); //!< Is called when the pickup has transited from used to unused or the other way around.
             virtual void clone(OrxonoxClass*& item); //!< Creates a duplicate of the input OrxonoxClass.
-            
+
             /**
             @brief Get the health that is transfered to the Pawn upon usage of this pickup.
@@ -93,13 +93,13 @@
             inline float getHealthRate(void)
                 { return this->healthRate_; }
-                
+
             /**
             @brief Get the type of HealthPickup, this pickup is.
-            @return Returns the health type as an enum. 
+            @return Returns the health type as an enum.
             */
             inline pickupHealthType::Value getHealthTypeDirect(void)
                 { return this->healthType_; }
             const std::string& getHealthType(void); //!< Get the health type of this pickup.
-            
+
         protected:
             void initializeIdentifier(void); //!< Initializes the PickupIdentifier of this pickup.
@@ -107,5 +107,5 @@
             void setHealth(float health); //!< Sets the health.
             void setHealthRate(float speed); //!< Set the rate at which health is transferred if the pickup is continuous.
-            
+
             /**
             @brief Set the health type of this pickup.
@@ -115,9 +115,9 @@
                 { this->healthType_ = type; }
             void setHealthType(std::string type); //!< Set the type of the HealthPickup.
-        
+
         private:
             void initialize(void); //!< Initializes the member variables.
             Pawn* carrierToPawnHelper(void); //!< Helper to transform the PickupCarrier to a Pawn, and throw an error message if the conversion fails.
-            
+
             float health_; //!< The health that is transferred to the Pawn.
             float healthRate_; //!< The rate at which the health is transferred.
@@ -125,10 +125,10 @@
             float maxHealthOverwrite_; //!< Helper to remember with which value we overwrote the maxHealh, to detect if someone else changed it as well.
             pickupHealthType::Value healthType_; //!< The type of the HealthPickup.
-            
+
             //! Strings for the health types.
             static const std::string healthTypeLimited_s;
             static const std::string healthTypeTemporary_s;
             static const std::string healthTypePermanent_s;
-        
+
     };
 }
Index: code/trunk/src/modules/pickup/items/InvisiblePickup.cc
===================================================================
--- code/trunk/src/modules/pickup/items/InvisiblePickup.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/items/InvisiblePickup.cc	(revision 7163)
@@ -34,18 +34,20 @@
 #include "InvisiblePickup.h"
 
+#include <sstream>
+#include <OgreEntity.h>
+#include <OgreAnimationState.h>
+
+#include "util/StringUtils.h"
 #include "core/CoreIncludes.h"
 #include "core/XMLPort.h"
-#include "util/StringUtils.h"
 
 #include "worldentities/pawns/Pawn.h"
 #include "pickup/PickupIdentifier.h"
 
-#include <sstream>
-
 namespace orxonox
 {
 
     CreateFactory(InvisiblePickup);
-    
+
     /**
     @brief
@@ -56,7 +58,7 @@
         RegisterObject(InvisiblePickup);
         //! Defines who is allowed to pick up the pickup.
-        this->initialize(); 
-    }
-    
+        this->initialize();
+    }
+
     /**
     @brief
@@ -64,8 +66,8 @@
     */
     InvisiblePickup::~InvisiblePickup()
-    {        
-    }
-    
-    
+    {
+    }
+
+
     void InvisiblePickup::initializeIdentifier(void)
     {
@@ -76,5 +78,5 @@
         this->pickupIdentifier_->addParameter(type1, val1);
     }
-    
+
     /**
     @brief
@@ -93,10 +95,10 @@
     void InvisiblePickup::XMLPort(Element& xmlelement, orxonox::XMLPort::Mode mode)
     {
-        SUPER(InvisiblePickup, XMLPort, xmlelement, mode);    
+        SUPER(InvisiblePickup, XMLPort, xmlelement, mode);
         XMLPortParam(InvisiblePickup, "duration", setDuration, getDuration, xmlelement, mode);
-        
+
         this->initializeIdentifier();
     }
-    
+
     /**
     @brief
@@ -106,9 +108,9 @@
     {
         SUPER(InvisiblePickup, changedUsed);
-        
+
         //! If the pickup is not picked up nothing must be done.
         if(!this->isPickedUp())
             return;
-        
+
         if (this->isUsed())
         {
@@ -121,13 +123,15 @@
                 this->startPickupTimer(this->getDuration());
             }
+
             this->setInvisible(true);
+
         }
         else
         {
             this->setInvisible(false);
-        
+
             if(!this->getTimer()->isActive() && this->getTimer()->getRemainingTime() == this->getDuration())
             {
-                this->destroy();
+                this->Pickupable::destroy();
             }
             else
@@ -136,7 +140,7 @@
             }
         }
-        
-    }
-    
+
+    }
+
     /**
     @brief
@@ -149,5 +153,5 @@
         PickupCarrier* carrier = this->getCarrier();
         Pawn* pawn = dynamic_cast<Pawn*>(carrier);
-        
+
         if(pawn == NULL)
         {
@@ -156,5 +160,5 @@
         return pawn;
     }
-    
+
     /**
     @brief
@@ -167,12 +171,12 @@
         if(item == NULL)
             item = new InvisiblePickup(this);
-        
+
         SUPER(InvisiblePickup, clone, item);
-        
+
         InvisiblePickup* pickup = dynamic_cast<InvisiblePickup*>(item);
         pickup->setDuration(this->getDuration());
         pickup->initializeIdentifier();
     }
-    
+
     /**
     @brief
@@ -186,9 +190,21 @@
         if(pawn == NULL)
             return false;
-        
+
         pawn->setVisible(!invisibility);
+        pawn->setRadarVisibility(!invisibility);
+
+// Test to change Material at runtime!
+
+//      Ogre::MaterialPtr mat = this->mesh_.getEntity()->getSubEntity(0)->getMaterial();
+//      mat->setDiffuse(0.4, 0.3, 0.1, 0.1);
+//      mat->setAmbient(0.3, 0.7, 0.8);
+//      mat->setSpecular(0.5, 0.5, 0.5, 0.1);
+//      Ogre::SceneBlendType sbt = Ogre::SBT_ADD;
+//
+//      mat->setSceneBlending(sbt);
+
         return true;
     }
-    
+
     /**
     @brief
@@ -209,5 +225,5 @@
         }
     }
-    
+
     void InvisiblePickup::pickupTimerCallback(void)
     {
Index: code/trunk/src/modules/pickup/items/InvisiblePickup.h
===================================================================
--- code/trunk/src/modules/pickup/items/InvisiblePickup.h	(revision 6906)
+++ code/trunk/src/modules/pickup/items/InvisiblePickup.h	(revision 7163)
@@ -38,11 +38,11 @@
 
 #include <string>
+
 #include <worldentities/pawns/Pawn.h>
 #include "worldentities/StaticEntity.h"
-
 #include "pickup/Pickup.h"
 
 namespace orxonox {
-        
+
     /**
     @brief
@@ -57,5 +57,5 @@
     {
         public:
-        
+
             InvisiblePickup(BaseObject* creator); //!< Constructor.
             virtual ~InvisiblePickup(); //!< Destructor.
@@ -63,5 +63,5 @@
             virtual void changedUsed(void); //!< Is called when the pickup has transited from used to unused or the other way around.
             virtual void clone(OrxonoxClass*& item); //!< Creates a duplicate of the input OrxonoxClass.
-            
+
             /**
             @brief Checks whether the Pawn is invisible.
@@ -72,5 +72,5 @@
             inline float getDuration()
                 { return this->duration_; }
- 
+
         protected:
             bool setInvisible(bool invisibility); //!< Set the Pawn to be invisible or visible again.
@@ -78,5 +78,5 @@
             void initializeIdentifier(void);
             virtual void pickupTimerCallback(void); //!< Function that gets called when the timer ends.
-        
+
         private:
             void initialize(void); //!< Initializes the member variables.
Index: code/trunk/src/modules/pickup/items/MetaPickup.cc
===================================================================
--- code/trunk/src/modules/pickup/items/MetaPickup.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/items/MetaPickup.cc	(revision 7163)
@@ -34,4 +34,5 @@
 #include "core/CoreIncludes.h"
 #include "core/XMLPort.h"
+#include "worldentities/pawns/Pawn.h"
 #include "interfaces/PickupCarrier.h"
 #include "pickup/PickupIdentifier.h"
@@ -40,12 +41,14 @@
 
 namespace orxonox {
- 
+
     CreateFactory(MetaPickup);
-    
+
     //! Setting the static variables to their values.
     /*static*/ const std::string MetaPickup::metaTypeNone_s = "none";
     /*static*/ const std::string MetaPickup::metaTypeUse_s = "use";
     /*static*/ const std::string MetaPickup::metaTypeDrop_s = "drop";
-    
+    /*static*/ const std::string MetaPickup::metaTypeDestroy_s = "destroy";
+    /*static*/ const std::string MetaPickup::metaTypeDestroyCarrier_s = "destroyCarrier";
+
     /**
     @brief
@@ -55,8 +58,8 @@
     {
         RegisterObject(MetaPickup);
-        
+
         this->initialize();
     }
-    
+
     /**
     @brief
@@ -65,7 +68,7 @@
     MetaPickup::~MetaPickup()
     {
-        
-    }
-    
+
+    }
+
     /**
     @brief
@@ -75,10 +78,10 @@
     {
         this->addTarget(ClassIdentifier<PickupCarrier>::getIdentifier());
-        
+
         this->setActivationTypeDirect(pickupActivationType::immediate);
         this->setDurationTypeDirect(pickupDurationType::once);
         this->metaType_ = pickupMetaType::none;
     }
-    
+
     /**
     @brief
@@ -91,5 +94,5 @@
         this->pickupIdentifier_->addParameter(type, val);
     }
-    
+
     /**
     @brief
@@ -99,10 +102,10 @@
     {
         SUPER(MetaPickup, XMLPort, xmlelement, mode);
-        
+
         XMLPortParam(MetaPickup, "metaType", setMetaType, getMetaType, xmlelement, mode);
-        
+
         this->initializeIdentifier();
     }
-    
+
     /**
     @brief
@@ -113,5 +116,5 @@
     {
         SUPER(MetaPickup, changedUsed);
-        
+
         //! If the MetaPickup transited to used.
         if(this->isUsed())
@@ -120,6 +123,12 @@
             if(this->getMetaTypeDirect() != pickupMetaType::none && carrier != NULL)
             {
+                if(this->getMetaTypeDirect() == pickupMetaType::destroyCarrier)
+                {
+                    Pawn* pawn = orxonox_cast<Pawn*>(carrier);
+                    pawn->kill();
+                    return;
+                }
                 std::set<Pickupable*> pickups = carrier->getPickups();
-                //! Set all Pickupables carried by the PickupCarrier either to used or drop them, depending o the meta type.
+                //! Set all Pickupables carried by the PickupCarrier either to used or drop them, depending on the meta type.
                 for(std::set<Pickupable*>::iterator it = pickups.begin(); it != pickups.end(); it++)
                 {
@@ -136,13 +145,20 @@
                         if(pickup != NULL && pickup != this)
                         {
-                            carrier->drop(pickup);
+                            pickup->drop();
+                        }
+                    }
+                    if(this->getMetaTypeDirect() == pickupMetaType::destroy)
+                    {
+                        if(pickup != NULL && pickup != this)
+                        {
+                            pickup->Pickupable::destroy();
                         }
                     }
                 }
             }
-            this->destroy();
-        }
-    }
-        
+            this->Pickupable::destroy();
+        }
+    }
+
     /**
     @brief
@@ -155,13 +171,13 @@
         if(item == NULL)
             item = new MetaPickup(this);
-        
+
         SUPER(MetaPickup, clone, item);
-        
+
         MetaPickup* pickup = dynamic_cast<MetaPickup*>(item);
         pickup->setMetaTypeDirect(this->getMetaTypeDirect());
-        
+
         pickup->initializeIdentifier();
     }
-    
+
     /**
     @brief
@@ -180,9 +196,13 @@
             case pickupMetaType::drop:
                 return MetaPickup::metaTypeDrop_s;
+            case pickupMetaType::destroy:
+                return MetaPickup::metaTypeDestroy_s;
+            case pickupMetaType::destroyCarrier:
+                return MetaPickup::metaTypeDestroyCarrier_s;
             default:
                 return BLANKSTRING;
         }
     }
-    
+
     /**
     @brief
@@ -205,5 +225,15 @@
             this->setMetaTypeDirect(pickupMetaType::drop);
         }
-    }
-    
+        else if(type == MetaPickup::metaTypeDestroy_s)
+        {
+            this->setMetaTypeDirect(pickupMetaType::destroy);
+        }
+        else if(type == MetaPickup::metaTypeDestroyCarrier_s)
+        {
+            this->setMetaTypeDirect(pickupMetaType::destroyCarrier);
+        }
+        else
+            COUT(2) << "Invalid metaType '" << type << "' in MetaPickup." << std::endl;
+    }
+
 }
Index: code/trunk/src/modules/pickup/items/MetaPickup.h
===================================================================
--- code/trunk/src/modules/pickup/items/MetaPickup.h	(revision 6906)
+++ code/trunk/src/modules/pickup/items/MetaPickup.h	(revision 7163)
@@ -48,11 +48,17 @@
             none,
             use,
-            drop
+            drop,
+            destroy,
+            destroyCarrier
         };
     }
-    
+
     /**
     @brief
-        The MetaPickup is a pickup that can, depending on the parameters, either drop all pickups of the PickupCarrier that picks it up, or use all the unused pickups of the PickupCarrier, that picks it up. The parameter to set for this is the metaType and it can be used with the values 'none', 'drop' and 'use'.
+        The MetaPickup is a pickup that can, depending on the parameter 'metaType', do different things. If the 'metaType' is set to
+        1) 'use', all the pickups, the PickupCarrier has, are immediately set to used upon pickup of the MetaPickup.
+        2) 'drop', all the pickups, the PickupCarrier has, are immediately dropped upon pickup of the MetaPickup.
+        3) 'destroy', all the pickups, the PickupCarrier has, are immediately destroyed upon pickup of the MetaPickup.
+        4) 'destroyCarrier', the PickupCarrier is immediately destroyed upon pickup of the MetaPickup.
     @author
         Damian 'Mozork' Frick
@@ -60,14 +66,14 @@
     class _PickupExport MetaPickup : public Pickup
     {
-        
+
         public:
             MetaPickup(BaseObject* creator); //!< Constructor. Registers and initializes the object.
             virtual ~MetaPickup(); //!< Destructor.
-            
+
             virtual void XMLPort(Element& xmlelement, orxonox::XMLPort::Mode mode); //!< Method for creating a MetaPickup object through XML.
-            
+
             virtual void changedUsed(void); //!< Is called when the pickup has transited from used to unused or the other way around.
             virtual void clone(OrxonoxClass*& item); //!< Creates a duplicate of the input OrxonoxClass.
-            
+
             /**
             @brief Returns the meta type of the MetaPickup.
@@ -77,8 +83,8 @@
                 { return this->metaType_; }
             const std::string& getMetaType(void); //!< Get the meta type of this MetaPickup.
-            
+
         protected:
             void initializeIdentifier(void); //!< Initializes the PickupIdentifier of this pickup.
-            
+
             /**
             @brief Set the meta type of the MetaPickup.
@@ -88,16 +94,18 @@
                 { this->metaType_ =  type; }
             void setMetaType(const std::string& type); //!< Set the meta type of this MetaPickup.
-            
+
         private:
             void initialize(void); //!< Initializes the member variables.
-            
+
             pickupMetaType::Value metaType_; //!< The meta type of the MetaPickup, determines which actions are taken.
-            
+
             //! Static strings for the meta types.
             static const std::string metaTypeNone_s;
             static const std::string metaTypeUse_s;
             static const std::string metaTypeDrop_s;
-            
-        
+            static const std::string metaTypeDestroy_s;
+            static const std::string metaTypeDestroyCarrier_s;
+
+
     };
 
Index: code/trunk/src/modules/pickup/items/ShieldPickup.cc
===================================================================
--- code/trunk/src/modules/pickup/items/ShieldPickup.cc	(revision 7163)
+++ code/trunk/src/modules/pickup/items/ShieldPickup.cc	(revision 7163)
@@ -0,0 +1,274 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Eric Beier
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+/**
+    @file ShieldPickup.cc
+    @brief Implementation of the ShieldPickup class.
+*/
+
+#include "ShieldPickup.h"
+
+#include "core/CoreIncludes.h"
+#include "core/XMLPort.h"
+#include "util/StringUtils.h"
+
+#include "worldentities/pawns/SpaceShip.h"
+#include "items/Engine.h"
+#include "pickup/PickupIdentifier.h"
+
+#include <sstream>
+
+
+namespace orxonox
+{
+    CreateFactory(ShieldPickup);
+
+    /**
+    @brief
+        Constructor. Registers the object and initializes the member variables.
+    */
+    ShieldPickup::ShieldPickup(BaseObject* creator) : Pickup(creator)
+    {
+        RegisterObject(ShieldPickup);
+
+        this->initialize();
+    }
+
+    /**
+    @brief
+        Destructor.
+    */
+    ShieldPickup::~ShieldPickup()
+    {
+
+    }
+
+    /**
+    @brief
+    Helper to transform the PickupCarrier to a Pawn, and throw an error message if the conversion fails.
+    @return
+    A pointer to the Pawn, or NULL if the conversion failed.
+    */
+    Pawn* ShieldPickup::carrierToPawnHelper(void)
+    {
+        PickupCarrier* carrier = this->getCarrier();
+        Pawn* pawn = dynamic_cast<Pawn*>(carrier);
+
+        if(pawn == NULL)
+        {
+            COUT(1) << "Invalid PickupCarrier in ShieldPickup." << std::endl;
+        }
+        return pawn;
+    }
+
+    /**
+    @brief
+        Initializes the member variables.
+    */
+    void ShieldPickup::initialize(void)
+    {
+        this->duration_ = 0.0f;
+        this->shieldAbsorption_ = 0.0f;
+        this->shieldHealth_ = 0.0f;
+
+        this->addTarget(ClassIdentifier<Pawn>::getIdentifier());
+    }
+
+    /**
+    @brief
+        Initializes the PickupIdentifier of this pickup.
+    */
+    void ShieldPickup::initializeIdentifier(void)
+    {
+        std::stringstream stream;
+        stream << this->getDuration();
+        std::string type1 = "duration";
+        std::string val1 = stream.str();
+        this->pickupIdentifier_->addParameter(type1, val1);
+
+        stream.clear();
+        stream << this->getShieldHealth();
+        std::string type2 = "ShieldHealth";
+        std::string val2 = stream.str();
+        this->pickupIdentifier_->addParameter(type2, val2);
+
+        stream.clear();
+        stream << this->getShieldAbsorption();
+        std::string type3 = "ShieldAbsorption";
+        std::string val3 = stream.str();
+        this->pickupIdentifier_->addParameter(type3, val3);
+
+    }
+
+    /**
+    @brief
+        Method for creating a ShieldPickup object through XML.
+    */
+    void ShieldPickup::XMLPort(Element& xmlelement, orxonox::XMLPort::Mode mode)
+    {
+        SUPER(ShieldPickup, XMLPort, xmlelement, mode);
+
+        XMLPortParam(ShieldPickup, "duration", setDuration, getDuration, xmlelement, mode);
+        XMLPortParam(ShieldPickup, "shieldhealth", setShieldHealth, getShieldHealth, xmlelement, mode);
+        XMLPortParam(ShieldPickup, "shieldabsorption", setShieldAbsorption, getShieldAbsorption, xmlelement, mode);
+
+        this->initializeIdentifier();
+    }
+
+    /**
+    @brief
+        Is called when the pickup has transited from used to unused or the other way around.
+    */
+    void ShieldPickup::changedUsed(void)
+    {
+        SUPER(ShieldPickup, changedUsed);
+
+        //! If the pickup is not picked up nothing must be done.
+        if(!this->isPickedUp())
+            return;
+
+        Pawn* pawn = this->carrierToPawnHelper();
+        if(pawn == NULL)
+            this->Pickupable::destroy();
+
+        //! If the pickup has transited to used.
+        if(this->isUsed())
+        {
+            if(!this->getTimer()->isActive() && this->getTimer()->getRemainingTime() > 0.0f)
+            {
+                this->getTimer()->unpauseTimer();
+            }
+            else
+            {
+                this->startPickupTimer(this->getDuration());
+            }
+            pawn->setShieldAbsorption(this->getShieldAbsorption());
+            pawn->setShieldHealth(this->getShieldHealth());
+        }
+        else
+        {
+            pawn->setShieldAbsorption(0.0f);
+            this->setShieldHealth(pawn->getShieldHealth());
+            pawn->setShieldHealth(0.0f);
+
+            if(this->isOnce())
+            {
+                if(!this->getTimer()->isActive() && this->getTimer()->getRemainingTime() == this->getDuration())
+                {
+                    this->Pickupable::destroy();
+                }
+                else
+                {
+                    this->getTimer()->pauseTimer();
+                }
+            }
+        }
+    }
+
+    /**
+    @brief
+        Creates a duplicate of the input OrxonoxClass.
+    @param item
+        A pointer to the Orxonox class.
+    */
+    void ShieldPickup::clone(OrxonoxClass*& item)
+    {
+        if(item == NULL)
+            item = new ShieldPickup(this);
+
+        SUPER(ShieldPickup, clone, item);
+
+        ShieldPickup* pickup = dynamic_cast<ShieldPickup*>(item);
+        pickup->setDuration(this->getDuration());
+        pickup->setShieldAbsorption(this->getShieldAbsorption());
+        pickup->setShieldHealth(this->getShieldHealth());
+        pickup->initializeIdentifier();
+    }
+
+    /**
+    @brief
+    Sets the percentage the shield absorbs of the dealt damage.
+    @param shieldAbsorption
+    The shieldAbsorption. Has to be between 0 and 1
+    */
+    void ShieldPickup::setShieldAbsorption(float shieldAbsorption)
+    {
+        if (shieldAbsorption>=0 && shieldAbsorption<=1)
+        {
+            this->shieldAbsorption_=shieldAbsorption;
+        }
+        else
+        {
+            COUT(1) << "Invalid Absorption in ShieldPickup." << std::endl;
+            this->shieldAbsorption_=0;
+        }
+    }
+
+    /**
+    @brief
+    Sets the health of the shield.
+    @param shieldHealth
+    The shieldHealth
+    */
+    void ShieldPickup::setShieldHealth(float shieldHealth)
+    {
+        if (shieldHealth>=0)
+        {
+            this->shieldHealth_=shieldHealth;
+        }
+        else
+        {
+            COUT(1) << "Invalid Shieldhealth in ShieldPickup." << std::endl;
+            this->shieldHealth_=0;
+        }
+    }
+
+    /**
+    @brief
+        Sets the duration.
+    @param duration
+        The duration
+    */
+    void ShieldPickup::setDuration(float duration)
+    {
+        if(duration >= 0.0f)
+        {
+            this->duration_ = duration;
+        }
+        else
+        {
+            COUT(1) << "Invalid duration in ShieldPickup." << std::endl;
+            this->duration_ = 0.0f;
+        }
+    }
+
+    void ShieldPickup::pickupTimerCallback(void)
+    {
+        this->setUsed(false);
+    }
+}
Index: code/trunk/src/modules/pickup/items/ShieldPickup.h
===================================================================
--- code/trunk/src/modules/pickup/items/ShieldPickup.h	(revision 7163)
+++ code/trunk/src/modules/pickup/items/ShieldPickup.h	(revision 7163)
@@ -0,0 +1,99 @@
+
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Eric Beier
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+/**
+    @file ShieldPickup.h
+    @brief Declaration of the ShieldPickup class.
+*/
+
+#ifndef _ShieldPickup_H__
+#define _ShieldPickup_H__
+
+#include "pickup/PickupPrereqs.h"
+
+#include <string>
+#include "worldentities/pawns/Pawn.h"
+#include "worldentities/StaticEntity.h"
+
+#include "pickup/Pickup.h"
+
+namespace orxonox {
+
+    /**
+    @brief
+        A Pickup which can add a Shield to the Pawn.
+
+        1) The percentage: The percentage the shield takes from the damage dealt to a Pawn
+        2) The hit points: The amount of damage points a shield can teake before collapsing
+        3) The activation type: 'immediate' or 'onUse'. defines if the item is used when it's picked up or only after the player chooses to use it.
+        4) The duration: the activation time of the pickup.
+
+    @author
+        Eric Beier
+    */
+    class _PickupExport ShieldPickup : public Pickup
+    {
+        public:
+
+            ShieldPickup(BaseObject* creator); //!< Constructor.
+            virtual ~ShieldPickup(); //!< Destructor.
+
+            virtual void XMLPort(Element& xmlelement, orxonox::XMLPort::Mode mode); //!< Method for creating a HealthPickup object through XML.
+
+            virtual void changedUsed(void); //!< Is called when the pickup has transited from used to unused or the other way around.
+            virtual void clone(OrxonoxClass*& item); //!< Creates a duplicate of the input OrxonoxClass.
+
+            inline float getDuration(void)
+                { return this->duration_; }
+            inline float getShieldHealth()
+                { return this->shieldHealth_; }
+            inline float getShieldAbsorption()
+                { return this->shieldAbsorption_; }
+
+        protected:
+            void initializeIdentifier(void); //!< Initializes the PickupIdentifier of this pickup.
+
+            virtual void pickupTimerCallback(void); //!< Function that gets called when timer ends.
+
+            void setDuration(float duration);
+            void setShieldHealth(float shieldHealth);
+            void setShieldAbsorption(float shieldAbsorption);
+
+        private:
+            void initialize(void); //!< Initializes the member variables.
+            Pawn* carrierToPawnHelper(void); //!< Helper to transform the PickupCarrier to a Pawn, and throw an error message if the conversion fails.
+
+            float duration_; //!< The health that is transferred to the Pawn.
+            float shieldHealth_;
+            float shieldAbsorption_; // Has to be between 0 and 1
+
+    };
+}
+
+#endif // _ShieldPickup_H__
Index: code/trunk/src/modules/pickup/items/SpeedPickup.cc
===================================================================
--- code/trunk/src/modules/pickup/items/SpeedPickup.cc	(revision 6906)
+++ code/trunk/src/modules/pickup/items/SpeedPickup.cc	(revision 7163)
@@ -136,6 +136,6 @@
         Engine* engine = this->carrierToEngineHelper();
         if(engine == NULL) //!< If the PickupCarrier is no Engine, then this pickup is useless and therefore is destroyed.
-            this->destroy();
-        
+            this->Pickupable::destroy();
+
         //! If the pickup has transited to used.
         if(this->isUsed())
@@ -156,10 +156,10 @@
             engine->setSpeedAdd(0.0f);
             engine->setSpeedMultiply(1.0f);
-            
+
             if(this->isOnce())
             {
                 if(!this->getTimer()->isActive() && this->getTimer()->getRemainingTime() == this->getDuration())
                 {
-                    this->destroy();
+                    this->Pickupable::destroy();
                 }
                 else
@@ -186,5 +186,5 @@
             COUT(1) << "Invalid PickupCarrier in SpeedPickup." << std::endl;
         }
-        
+
         return engine;
     }
@@ -269,5 +269,5 @@
 
     void SpeedPickup::pickupTimerCallback(void)
-    {       
+    {
         this->setUsed(false);
     }
Index: code/trunk/src/modules/pickup/items/SpeedPickup.h
===================================================================
--- code/trunk/src/modules/pickup/items/SpeedPickup.h	(revision 6906)
+++ code/trunk/src/modules/pickup/items/SpeedPickup.h	(revision 7163)
@@ -78,5 +78,5 @@
         protected:
             void initializeIdentifier(void); //!< Initializes the PickupIdentifier of this pickup.
-            
+
             virtual void pickupTimerCallback(void); //!< Function that gets called when timer ends.
 
Index: code/trunk/src/modules/pong/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/pong/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/pong/CMakeLists.txt	(revision 7163)
@@ -14,6 +14,4 @@
   MODULE
   FIND_HEADER_FILES
-  DEFINE_SYMBOL
-    "PONG_SHARED_BUILD"
   LINK_LIBRARIES
     orxonox
Index: code/trunk/src/modules/pong/PongBall.h
===================================================================
--- code/trunk/src/modules/pong/PongBall.h	(revision 6906)
+++ code/trunk/src/modules/pong/PongBall.h	(revision 7163)
@@ -45,6 +45,4 @@
             virtual void tick(float dt);
 
-            void registerVariables();
-
             void setFieldDimension(float width, float height)
                 { this->fieldWidth_ = width; this->fieldHeight_ = height; }
@@ -74,4 +72,6 @@
 
         private:
+            void registerVariables();
+
             float fieldWidth_;
             float fieldHeight_;
Index: code/trunk/src/modules/pong/PongBat.h
===================================================================
--- code/trunk/src/modules/pong/PongBat.h	(revision 6906)
+++ code/trunk/src/modules/pong/PongBat.h	(revision 7163)
@@ -41,5 +41,4 @@
             virtual ~PongBat() {}
 
-            void registerVariables();
             virtual void tick(float dt);
 
@@ -65,4 +64,6 @@
 
         private:
+            void registerVariables();
+
             float movement_;
             bool bMoveLocal_;
Index: code/trunk/src/modules/pong/PongPrereqs.h
===================================================================
--- code/trunk/src/modules/pong/PongPrereqs.h	(revision 6906)
+++ code/trunk/src/modules/pong/PongPrereqs.h	(revision 7163)
@@ -43,5 +43,5 @@
 //-----------------------------------------------------------------------
 
-#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_STATIC_BUILD)
+#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(PONG_STATIC_BUILD)
 #  ifdef PONG_SHARED_BUILD
 #    define _PongExport __declspec(dllexport)
Index: code/trunk/src/modules/questsystem/AddQuest.cc
===================================================================
--- code/trunk/src/modules/questsystem/AddQuest.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/AddQuest.cc	(revision 7163)
@@ -68,5 +68,5 @@
         SUPER(AddQuest, XMLPort, xmlelement, mode);
 
-        COUT(3) << "New AddQuest, with target Quest {" << this->getQuestId() << "}, created." << std::endl;
+        COUT(4) << "New AddQuest, with target Quest {" << this->getQuestId() << "}, created." << std::endl;
     }
 
@@ -87,5 +87,5 @@
         }
 
-        COUT(3) << "AddQuest on player: " << player << " ." << std::endl;
+        COUT(5) << "AddQuest on player: " << player << " ." << std::endl;
 
         try
@@ -103,5 +103,5 @@
         }
 
-        COUT(3) << "Quest {" << this->getQuestId() << "} successfully added to player: " << player << " ." << std::endl;
+        COUT(4) << "Quest {" << this->getQuestId() << "} successfully added to player: " << player << " ." << std::endl;
         return true;
     }
Index: code/trunk/src/modules/questsystem/AddQuestHint.cc
===================================================================
--- code/trunk/src/modules/questsystem/AddQuestHint.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/AddQuestHint.cc	(revision 7163)
@@ -72,5 +72,5 @@
         XMLPortParam(AddQuestHint, "hintId", setHintId, getHintId, xmlelement, mode);
 
-        COUT(3) << "New AddQuestHint, with target QuestHint {" << this->getHintId() << "}, created." << std::endl;
+        COUT(4) << "New AddQuestHint, with target QuestHint {" << this->getHintId() << "}, created." << std::endl;
     }
 
@@ -85,5 +85,5 @@
     bool AddQuestHint::setHintId(const std::string & id)
     {
-        if(!QuestItem::isId(id))
+        if(id.compare(BLANKSTRING) == 0)
         {
             COUT(2) << "Invalid id. QuestItem id {" << id << "} could not be set." << std::endl;
@@ -111,5 +111,5 @@
         }
 
-        COUT(3) << "AddQuestHint on player: " << player << " ." << std::endl;
+        COUT(5) << "AddQuestHint on player: " << player << " ." << std::endl;
 
         try
@@ -127,5 +127,5 @@
         }
 
-        COUT(3) << "QuestHint {" << this->getHintId() << "} successfully added to player: " << player << " ." << std::endl;
+        COUT(4) << "QuestHint {" << this->getHintId() << "} successfully added to player: " << player << " ." << std::endl;
         return true;
 
Index: code/trunk/src/modules/questsystem/AddReward.cc
===================================================================
--- code/trunk/src/modules/questsystem/AddReward.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/AddReward.cc	(revision 7163)
@@ -68,5 +68,5 @@
         XMLPortObject(AddReward, Rewardable, "", addRewardable, getRewardables, xmlelement, mode);
 
-        COUT(3) << "New AddReward, with " << this->rewards_.size() << " Rewardables created." << std::endl;
+        COUT(4) << "New AddReward, with " << this->rewards_.size() << " Rewardables created." << std::endl;
     }
 
@@ -103,5 +103,5 @@
     bool AddReward::invoke(PlayerInfo* player)
     {
-        COUT(3) << "AddReward on player: " << player << " ." << std::endl;
+        COUT(5) << "AddReward on player: " << player << " ." << std::endl;
 
         bool check = true;
@@ -111,5 +111,5 @@
         }
 
-        COUT(3) << "Rewardable successfully added to player." << player << " ." << std::endl;
+        COUT(4) << "Rewardable successfully added to player." << player << " ." << std::endl;
 
         return check;
Index: code/trunk/src/modules/questsystem/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/questsystem/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/questsystem/CMakeLists.txt	(revision 7163)
@@ -12,6 +12,4 @@
   QuestEffect.cc
   QuestEffectBeacon.cc
-  QuestGUINode.cc
-  QuestGUI.cc
   QuestHint.cc
   QuestItem.cc
@@ -28,6 +26,7 @@
   TOLUA_FILES
     QuestManager.h
-  DEFINE_SYMBOL
-    "QUESTSYSTEM_SHARED_BUILD"
+    QuestDescription.h
+    Quest.h
+    QuestHint.h
   PCH_FILE
     QuestsystemPrecompiledHeaders.h
Index: code/trunk/src/modules/questsystem/ChangeQuestStatus.cc
===================================================================
--- code/trunk/src/modules/questsystem/ChangeQuestStatus.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/ChangeQuestStatus.cc	(revision 7163)
@@ -78,5 +78,5 @@
     bool ChangeQuestStatus::setQuestId(const std::string & id)
     {
-        if(!QuestItem::isId(id))
+        if(id.compare(BLANKSTRING) == 0)
         {
             COUT(2) << "Invalid id. QuestItem id {" << id << "} could not be set." << std::endl;
Index: code/trunk/src/modules/questsystem/CompleteQuest.cc
===================================================================
--- code/trunk/src/modules/questsystem/CompleteQuest.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/CompleteQuest.cc	(revision 7163)
@@ -68,5 +68,5 @@
         SUPER(CompleteQuest, XMLPort, xmlelement, mode);
 
-        COUT(3) << "New CompleteQuest, with target Quest {" << this->getQuestId() << "}, created." << std::endl;
+        COUT(4) << "New CompleteQuest, with target Quest {" << this->getQuestId() << "}, created." << std::endl;
     }
 
@@ -87,5 +87,5 @@
         }
 
-        COUT(3) << "CompleteQuest on player: " << player << " ." << std::endl;
+        COUT(5) << "CompleteQuest on player: " << player << " ." << std::endl;
 
         Quest* quest;
@@ -105,5 +105,5 @@
         }
 
-        COUT(3) << "Quest {" << quest->getId() << "} successfully completed by player: " << player << " ." << std::endl;
+        COUT(4) << "Quest {" << quest->getId() << "} successfully completed by player: " << player << " ." << std::endl;
         return true;
     }
Index: code/trunk/src/modules/questsystem/FailQuest.cc
===================================================================
--- code/trunk/src/modules/questsystem/FailQuest.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/FailQuest.cc	(revision 7163)
@@ -68,5 +68,5 @@
         SUPER(FailQuest, XMLPort, xmlelement, mode);
 
-        COUT(3) << "New FailQUest, with target Quest {" << this->getQuestId() << "}, created." << std::endl;
+        COUT(4) << "New FailQUest, with target Quest {" << this->getQuestId() << "}, created." << std::endl;
     }
 
@@ -87,5 +87,5 @@
         }
 
-        COUT(3) << "FailQuest on player: " << player << " ." << std::endl;
+        COUT(4) << "FailQuest on player: " << player << " ." << std::endl;
 
         Quest* quest;
@@ -104,5 +104,5 @@
         }
 
-        COUT(3) << "Quest {" << quest->getId() << "} failed by player: " << player << " ." << std::endl;
+        COUT(4) << "Quest {" << quest->getId() << "} failed by player: " << player << " ." << std::endl;
         return true;
     }
Index: code/trunk/src/modules/questsystem/GlobalQuest.cc
===================================================================
--- code/trunk/src/modules/questsystem/GlobalQuest.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/GlobalQuest.cc	(revision 7163)
@@ -70,5 +70,5 @@
         XMLPortObject(GlobalQuest, QuestEffect, "reward-effects", addRewardEffect, getRewardEffects, xmlelement, mode);
 
-        COUT(3) << "New GlobalQuest {" << this->getId() << "} created." << std::endl;
+        COUT(4) << "New GlobalQuest {" << this->getId() << "} created." << std::endl;
     }
 
@@ -253,5 +253,5 @@
         this->rewards_.push_back(effect); //!< Add the QuestEffect to the list.
 
-        COUT(3) << "Reward effect was added to Quest {" << this->getId() << "}." << std::endl;
+        COUT(4) << "Reward effect was added to Quest {" << this->getId() << "}." << std::endl;
         return true;
     }
Index: code/trunk/src/modules/questsystem/LocalQuest.cc
===================================================================
--- code/trunk/src/modules/questsystem/LocalQuest.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/LocalQuest.cc	(revision 7163)
@@ -68,5 +68,5 @@
         SUPER(LocalQuest, XMLPort, xmlelement, mode);
 
-        COUT(3) << "New LocalQuest {" << this->getId() << "} created." << std::endl;
+        COUT(4) << "New LocalQuest {" << this->getId() << "} created." << std::endl;
     }
 
Index: code/trunk/src/modules/questsystem/Quest.cc
===================================================================
--- code/trunk/src/modules/questsystem/Quest.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/Quest.cc	(revision 7163)
@@ -61,5 +61,6 @@
     Quest::~Quest()
     {
-
+        if(this->isRegistered())
+            QuestManager::getInstance().unregisterQuest(this);
     }
 
@@ -98,5 +99,5 @@
         this->parentQuest_ = quest;
 
-        COUT(3) << "Parent Quest {" << quest->getId() << "} was added to Quest {" << this->getId() << "}." << std::endl;
+        COUT(4) << "Parent Quest {" << quest->getId() << "} was added to Quest {" << this->getId() << "}." << std::endl;
         return true;
     }
@@ -121,5 +122,5 @@
         this->subQuests_.push_back(quest); //!< Adds the Quest to the end of the list of subquests.
 
-        COUT(3) << "Sub Quest {" << quest->getId() << "} was added to Quest {" << this->getId() << "}." << std::endl;
+        COUT(4) << "Sub Quest {" << quest->getId() << "} was added to Quest {" << this->getId() << "}." << std::endl;
         return true;
     }
@@ -145,5 +146,5 @@
         this->hints_.push_back(hint); //!< Adds the QuestHint to the end of the list of QuestHints.
 
-        COUT(3) << "QuestHint {" << hint->getId() << "} was added to Quest {" << this->getId() << "}." << std::endl;
+        COUT(4) << "QuestHint {" << hint->getId() << "} was added to Quest {" << this->getId() << "}." << std::endl;
         return true;
     }
@@ -167,5 +168,5 @@
         this->failEffects_.push_back(effect); //!< Adds the QuestEffect to the end of the list of fail QuestEffects.
 
-        COUT(3) << "A FailEffect was added to Quest {" << this->getId() << "}." << std::endl;
+        COUT(4) << "A FailEffect was added to Quest {" << this->getId() << "}." << std::endl;
         return true;
     }
@@ -189,5 +190,5 @@
         this->completeEffects_.push_back(effect); //!< Adds the QuestEffect to the end of the list of complete QuestEffects.
 
-        COUT(3) << "A CompleteEffect was added to Quest {" << this->getId() << "}." << std::endl;
+        COUT(4) << "A CompleteEffect was added to Quest {" << this->getId() << "}." << std::endl;
         return true;
     }
Index: code/trunk/src/modules/questsystem/Quest.h
===================================================================
--- code/trunk/src/modules/questsystem/Quest.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/Quest.h	(revision 7163)
@@ -41,6 +41,6 @@
 #include "QuestItem.h"
 
-namespace orxonox
-{
+namespace orxonox // tolua_export
+{ // tolua_export
     namespace QuestStatus
     {
@@ -67,6 +67,7 @@
         Damian 'Mozork' Frick
     */
-    class _QuestsystemExport Quest : public QuestItem
-    {
+    class _QuestsystemExport Quest // tolua_export
+        : public QuestItem
+    { // tolua_export
         public:
             Quest(BaseObject* creator);
@@ -97,7 +98,7 @@
 
             bool isInactive(const PlayerInfo* player) const; //!< Returns true if the quest status for the specific player is 'inactive'.
-            bool isActive(const PlayerInfo* player) const; //!< Returns true if the quest status for the specific player is 'active'.
-            bool isFailed(const PlayerInfo* player) const; //!< Returns true if the quest status for the specific player is 'failed'.
-            bool isCompleted(const PlayerInfo* player) const; //!< Returns true if the quest status for the specific player is 'completed'.
+            bool isActive(const orxonox::PlayerInfo* player) const; // tolua_export //!< Returns true if the quest status for the specific player is 'active'.
+            bool isFailed(const orxonox::PlayerInfo* player) const; // tolua_export //!< Returns true if the quest status for the specific player is 'failed'.
+            bool isCompleted(const orxonox::PlayerInfo* player) const; // tolua_export //!< Returns true if the quest status for the specific player is 'completed'.
 
             bool start(PlayerInfo* player); //!< Sets a Quest to active.
@@ -151,7 +152,7 @@
             bool addCompleteEffect(QuestEffect* effect); //!< Adds an QuestEffect to the list of complete QuestEffects.
 
-    };
+    }; // tolua_export
 
-}
+} // tolua_export
 
 #endif /* _Quest_H__ */
Index: code/trunk/src/modules/questsystem/QuestDescription.cc
===================================================================
--- code/trunk/src/modules/questsystem/QuestDescription.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestDescription.cc	(revision 7163)
@@ -74,5 +74,5 @@
         XMLPortParam(QuestDescription, "completeMessage", setCompleteMessage, getCompleteMessage, xmlelement, mode);
 
-        COUT(3) << "New QuestDescription with title '" << this->getTitle() << "' created." << std::endl;
+        COUT(4) << "New QuestDescription with title '" << this->getTitle() << "' created." << std::endl;
     }
 
@@ -89,5 +89,5 @@
         Make sure the messages meet the conditions.
     */
-    bool QuestDescription::notificationHelper(const std::string & item, const std::string & status) const
+    bool QuestDescription::notificationHelper(const std::string & item, const std::string & status)
     {
         std::string message;
@@ -122,5 +122,5 @@
         }
 
-        QuestNotification* notification = new QuestNotification(message);
+        QuestNotification* notification = new QuestNotification(this, message);
         notification->send();
         return true;
Index: code/trunk/src/modules/questsystem/QuestDescription.h
===================================================================
--- code/trunk/src/modules/questsystem/QuestDescription.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestDescription.h	(revision 7163)
@@ -83,5 +83,5 @@
             @return Returns a string containing the fail message of the QuestDescription.
             */
-            inline const std::string & getFailMessage(void) const
+            inline const std::string & getFailMessage(void)
                 { return this->failMessage_; }
 
@@ -90,5 +90,5 @@
             @return Returns a string containing the complete message of the QuestDescription.
             */
-            inline const std::string & getCompleteMessage(void) const
+            inline const std::string & getCompleteMessage(void)
                 { return this->completeMessage_; }
 
@@ -97,5 +97,5 @@
             @return Returns true if successful.
             */
-            inline bool sendAddHintNotification(void) const
+            inline bool sendAddHintNotification(void)
                 { return notificationHelper("hint", ""); }
 
@@ -104,5 +104,5 @@
             @return Returns true if successful.
             */
-            inline bool sendAddQuestNotification(void) const
+            inline bool sendAddQuestNotification(void)
                 { return notificationHelper("quest", "start"); }
 
@@ -111,5 +111,5 @@
             @return Returns true if successful.
             */
-            inline bool sendFailQuestNotification(void) const
+            inline bool sendFailQuestNotification(void)
                 { return notificationHelper("quest", "fail"); }
 
@@ -118,5 +118,5 @@
             @return Returns true if successful.
             */
-            inline bool sendCompleteQuestNotification(void) const
+            inline bool sendCompleteQuestNotification(void)
                 { return notificationHelper("quest", "complete"); }
 
@@ -127,5 +127,5 @@
             std::string completeMessage_; //!< The message displayed when the Quest is completed.
 
-            bool notificationHelper(const std::string & item, const std::string & status) const; //!< Helper for sending QuestDescriptions as Notifications.
+            bool notificationHelper(const std::string & item, const std::string & status); //!< Helper for sending QuestDescriptions as Notifications.
 
             /**
Index: code/trunk/src/modules/questsystem/QuestEffectBeacon.cc
===================================================================
--- code/trunk/src/modules/questsystem/QuestEffectBeacon.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestEffectBeacon.cc	(revision 7163)
@@ -78,5 +78,5 @@
         XMLPortEventSink(QuestEffectBeacon, BaseObject, "execute", execute, xmlelement, mode); //TODO: Change BaseObject to MultiTrigger as soon as MultiTrigger is the base of all triggers.
 
-        COUT(3) << "New QuestEffectBeacon created." << std::endl;
+        COUT(4) << "New QuestEffectBeacon created." << std::endl;
     }
 
@@ -112,10 +112,10 @@
         MultiTriggerContainer* mTrigger = orxonox_cast<MultiTriggerContainer*>(trigger);
         Pawn* pawn = NULL;
-        
+
         //! If the trigger is neither a Playertrigger nor a MultiTrigger (i.e. a MultitriggerContainer) we can do anything with it.
         if(pTrigger == NULL && mTrigger == NULL)
             return false;
-        
-        // If the trigger is a PlayerTrigger.        
+
+        // If the trigger is a PlayerTrigger.
         if(pTrigger != NULL)
         {
@@ -125,5 +125,5 @@
                 pawn = pTrigger->getTriggeringPlayer();
         }
-        
+
         // If the trigger is a MultiTrigger (i.e. a MultiTriggerContainer)
         if(mTrigger != NULL)
@@ -134,5 +134,5 @@
         if(pawn == NULL)
         {
-            COUT(2) << "The QuestEffectBeacon was triggered by an entity other than a Pawn." << std::endl;
+            COUT(4) << "The QuestEffectBeacon was triggered by an entity other than a Pawn. (" << trigger->getIdentifier()->getName() << ")" << std::endl;
             return false;
         }
@@ -147,5 +147,5 @@
         }
 
-        COUT(3) << "QuestEffectBeacon executed on player: " << player << " ." << std::endl;
+        COUT(4) << "QuestEffectBeacon executed on player: " << player << " ." << std::endl;
 
         bool check = QuestEffect::invokeEffects(player, this->effects_); //!< Invoke the QuestEffects on the PlayerInfo.
@@ -249,5 +249,5 @@
         this->effects_.push_back(effect);
 
-        COUT(3) << "A QuestEffect was added to a QuestEffectBeacon." << std::endl;
+        COUT(4) << "A QuestEffect was added to a QuestEffectBeacon." << std::endl;
         return true;
     }
Index: code/trunk/src/modules/questsystem/QuestGUI.cc
===================================================================
--- code/trunk/src/modules/questsystem/QuestGUI.cc	(revision 6906)
+++ 	(revision )
@@ -1,274 +1,0 @@
-/*
- *   ORXONOX - the hottest 3D action shooter ever to exist
- *                    > www.orxonox.net <
- *
- *
- *   License notice:
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation; either version 2
- *   of the License, or (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- *   Author:
- *      Damian 'Mozork' Frick
- *   Co-authors:
- *      ...
- *
- */
-
-#include "QuestGUI.h"
-
-#include <sstream>
-#include <CEGUIWindow.h>
-#include <CEGUIWindowManager.h>
-
-#include "core/CoreIncludes.h"
-#include "Quest.h"
-#include "QuestHint.h"
-#include "QuestItem.h"
-#include "QuestGUINode.h"
-#include "QuestManager.h"
-
-namespace orxonox {
-
-    /**
-    @brief
-        Constructor. Registers and initializes the object.
-    @param
-        The player the GUI is for.
-    */
-    QuestGUI::QuestGUI(PlayerInfo* player)
-    {
-        RegisterRootObject(QuestGUI);
-
-        this->player_ = player;
-        this->windowManager_ = CEGUI::WindowManager::getSingletonPtr(); //!< Get CEGUI WindowManager.
-        this->rootWindow_ = NULL;
-        this->root_ = new QuestGUINode(); //!< Create empty root node.
-
-        COUT(3) << "New QuestGUI created." << std::endl;
-    }
-
-    /**
-    @brief
-        Destructor.
-    */
-    QuestGUI::~QuestGUI()
-    {
-        COUT(3) << "Destroying QuestGUI..." << std::endl;
-
-        this->clear(); //!< Clearing the GUI and in the process destroying all QuestGUINodes.
-
-        //! Destroying the windows in the this->windows_ list.
-        for(std::list<CEGUI::Window*>::iterator it = this->windows_.begin(); it != this->windows_.end(); it++)
-        {
-            if(*it != NULL)
-                (*it)->destroy();
-        }
-        this->windows_.clear();
-
-        if(this->root_ != NULL)
-            this->root_->destroy();
-    }
-
-    /**
-    @brief
-        Get the root CEGUI Window of the GUI.
-    @return
-        Returns the root CEGUI Window of the GUI.
-    */
-    CEGUI::Window* QuestGUI::getGUI(void)
-    {
-        this->update(); //!< Update the GUI.
-
-        return this->rootWindow_;
-    }
-
-    /**
-    @brief
-        Update the GUI.
-    */
-    void QuestGUI::update(void)
-    {
-        COUT(3) << "Updating QuestGUI..." << std::endl;
-
-        this->clear(); //!< Clear the GUI.
-
-        int depth = 0;
-        int index = 0;
-
-        //! Create root window.
-        this->rootWindow_ = this->windowManager_->createWindow("MenuWidgets/ScrollablePane", "QuestGUI/Quests");
-        this->rootWindow_->setSize(CEGUI::UVector2(CEGUI::UDim(1, 0),CEGUI::UDim(1, 0)));
-
-        //! Iterate through all Quests.
-        std::map<std::string, Quest*> quests = QuestManager::getInstance().getQuests();
-        for(std::map<std::string, Quest*>::iterator it = quests.begin(); it != quests.end(); it++)
-        {
-            Quest* quest = it->second;
-            if(quest->getParentQuest() == NULL && !quest->isInactive(this->player_)) //!< If the Quest isn't inactive and a root Quest (meaning it has no parent.), create a Node.
-            {
-                index = createNode(this->root_, quest, depth, index);
-            }
-        }
-        COUT(3) << "Updating QuestGUI done." << std::endl;
-    }
-
-    /**
-    @brief
-        Clear the QuestGUI.
-    */
-    void QuestGUI::clear(void)
-    {
-        COUT(3) << "Clearing QuestGUI..." << std::endl;
-
-        //! Clear all nodes.
-        for(std::map<CEGUI::Window*, QuestGUINode*>::iterator it = this->nodes_.begin(); it != this->nodes_.end(); it++)
-        {
-            QuestGUINode* node = it->second;
-            if(node == NULL)
-            {
-                COUT(1) << "Node is NULL!";
-                continue;
-            }
-            std::string* str = new std::string();
-            node->getName(*str);
-            COUT(3) << "Clearing Node '" << *str << "' ..." << std::endl;
-            delete str;
-            node->destroy();
-        }
-        this->nodes_.clear();
-
-        //! Clear root window.
-        if(this->rootWindow_ != NULL)
-            this->rootWindow_->destroy();
-
-        COUT(3) << "Clearing QuestGUI done." << std::endl;
-    }
-
-    /**
-    @brief
-        Get a CEGUI Window to use.
-        Windows that are no longer used are collected with giveWindow, and are given out again with getWindow, so save some time recreating new windows everytime.
-        The retreived window is of type "MenuWidgets/TabButton".
-    @return
-        Returns a CEGUI Window of type "MenuWidgets/TabButton".
-    */
-    CEGUI::Window* QuestGUI::getWindow(void)
-    {
-        if(!this->windows_.empty()) //!< If there are windows in the list.
-        {
-            CEGUI::Window* window = this->windows_.back();
-            this->windows_.pop_back();
-            return window;
-        }
-
-        //!< Else create a new one.
-        std::ostringstream stream;
-        stream << "QuestGUI/Quests/EmptyWindows/" << this->windows_.size()+1;
-        return this->windowManager_->createWindow("MenuWidgets/TabButton", stream.str());
-    }
-
-    /**
-    @brief
-        Return a no longer needed CEGUI Window for reuse.
-    @param window
-        The CEGUI window ot be returned.
-    */
-    void QuestGUI::giveWindow(CEGUI::Window* window)
-    {
-        if(window == NULL)
-            return;
-        this->windows_.push_back(window);
-        this->rootWindow_->removeChildWindow(window); //!< Remove the window as child of the rootWindow.
-        std::ostringstream stream;
-        stream << "QuestGUI/Quests/EmptyWindows/" << this->windows_.size();
-        window->rename(stream.str());
-    }
-
-    /**
-    @brief
-        Finde the QuestGUINode belonging to the input CEGUI Window.
-    @param window
-        A pointer to a CEGUI Window.
-    @return
-        A pointer to the QuestGUI Node belonging to the input CEGUI Window.
-    */
-    /*static*/ QuestGUINode* QuestGUI::findNode(CEGUI::Window* window)
-    {
-        for(std::map<PlayerInfo*, QuestGUI*>::iterator it = QuestManager::getInstance().questGUIs_.begin(); it != QuestManager::getInstance().questGUIs_.end(); it++)
-        {
-            QuestGUI* gui = it->second;
-            std::map<CEGUI::Window*, QuestGUINode*>::iterator node = gui->nodes_.find(window);
-            if(node != gui->nodes_.end()) return node->second;
-        }
-        return NULL;
-    }
-
-    /**
-    @brief
-        Recursive method to create Nodes for all Quests an Hints the given Quest is a parent to.
-    @param parent
-        Pointer to the parent QuestGUINode.
-    @param item
-        The QuestItem the QuestGUINode is created for.
-    @param depth
-        Parameter to define how much the list item has to be indented.
-    @param index
-        "Counter" for Quests and Hints.
-    @return
-        Returns the index.
-    */
-    int QuestGUI::createNode(QuestGUINode* parent, QuestItem* item, int depth, int index)
-    {
-        QuestGUINode* node = new QuestGUINode(this, parent, item, depth, index); //!< Create a new QuestGUINode.
-
-        this->nodes_.insert(std::pair<CEGUI::Window*, QuestGUINode*>(node->getWindow(),node)); //!< Insert the node and its window in the nodes_ map.
-
-        index++;
-
-        //! Check if the QuestItem is a Quest, if not (it's a QuestHint) it just returns.
-        Quest* quest = dynamic_cast<Quest*>(item);
-        if(quest == NULL)
-          return index;
-
-        //! Iterate through all subQuests.
-        std::list<Quest*> quests = quest->getSubQuestList();
-        for(std::list<Quest*>::iterator it = quests.begin(); it != quests.end(); it++)
-        {
-            Quest* quest = *it;
-            if(!quest->isInactive(this->player_)) //!< Add node if the subQuest is not inactive.
-            {
-                index = createNode(node, quest, depth+1, index);
-            }
-        }
-
-        //! Iterate through all hints.
-        std::list<QuestHint*> hints = quest->getHintsList();
-        int tempIndex = index; //!< Preserve the index, since for the hints we start anew with index 0.
-        index = 0;
-        for(std::list<QuestHint*>::iterator it = hints.begin(); it != hints.end(); it++)
-        {
-            QuestHint* hint = *it;
-            if(hint->isActive(this->player_)) //!< Add node if the hint is active.
-            {
-                index = createNode(node, hint, depth+1, index);
-            }
-        }
-        index = tempIndex; //!< Reset the index to the original level.
-
-        return index;
-    }
-
-}
-
Index: code/trunk/src/modules/questsystem/QuestGUI.h
===================================================================
--- code/trunk/src/modules/questsystem/QuestGUI.h	(revision 6906)
+++ 	(revision )
@@ -1,109 +1,0 @@
-/*
- *   ORXONOX - the hottest 3D action shooter ever to exist
- *                    > www.orxonox.net <
- *
- *
- *   License notice:
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation; either version 2
- *   of the License, or (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- *   Author:
- *      Damian 'Mozork' Frick
- *   Co-authors:
- *      ...
- *
- */
-
-/**
-    @file
-    @brief Definition of the QuestGIU class.
-*/
-
-#ifndef _QuestGUI_H__
-#define _QuestGUI_H__
-
-#include "questsystem/QuestsystemPrereqs.h"
-
-#include <list>
-#include <map>
-#include <string>
-#include <CEGUIForwardRefs.h>
-
-#include "core/OrxonoxClass.h"
-
-namespace orxonox {
-
-    /**
-    @brief
-        Handles the GUI for the Questsystem.
-    @author
-        Damian 'Mozork' Frick
-    */
-    class _QuestsystemExport QuestGUI : public OrxonoxClass
-    {
-
-        public:
-
-            QuestGUI(PlayerInfo* player);
-            virtual ~QuestGUI();
-
-            void update(void); //!< Update the GUI.
-            CEGUI::Window* getGUI(void); //!< Get the root CEGUI Window of the GUI.
-
-            CEGUI::Window* getWindow(void); //!< Get a CEGUI Window to use.
-            void giveWindow(CEGUI::Window* window); //!< Return a no longer needed CEGUI Window for reuse.
-
-            static QuestGUINode* findNode(CEGUI::Window* window); //!< Finde the QuestGUINode belonging to the input CEGUI Window.
-
-            /**
-            @brief Retreive the CEGUI WindowManager.
-            @return Returns the CEGUI WindoWManager.
-            */
-            inline CEGUI::WindowManager* getWindowManager(void)
-                { return this->windowManager_; }
-            /**
-            @brief Retrieve the root window.
-            @return Returns the root window.
-            */
-            inline CEGUI::Window* getRootWindow(void)
-                { return this->rootWindow_; }
-            /**
-            @brief Retreive the player.
-            @return Returns the player.
-            */
-            inline PlayerInfo* getPlayer(void)
-                { return this->player_; }
-
-        private:
-
-            int createNode(QuestGUINode* parent, QuestItem* item, int depth, int index); //!< Recursive method to create Nodes for all Quests an Hints the given Quest is a parent to.
-
-            void clear(void); //!< Clear the QuestGUI.
-
-            QuestGUINode* root_; //!< An empty QuestGUINode being the parent of all otherwise parent-less nodes.
-
-            CEGUI::WindowManager* windowManager_; //!< The CEGUI WindowManager.
-            CEGUI::Window* rootWindow_; //!< The root CEGUI Window of the GUI.
-            PlayerInfo* player_; //!< The player that owns the GUI.
-
-            std::map<CEGUI::Window*, QuestGUINode*> nodes_; //!< A list of all QuestGUINodes, ordered by their respective CEGUI Windows.
-            std::list<CEGUI::Window*> windows_; //!< A list of windows to be used.
-
-    };
-
-}
-
-#endif /* _QuestGUI_H__ */
-
Index: code/trunk/src/modules/questsystem/QuestGUINode.cc
===================================================================
--- code/trunk/src/modules/questsystem/QuestGUINode.cc	(revision 6906)
+++ 	(revision )
@@ -1,399 +1,0 @@
-/*
- *   ORXONOX - the hottest 3D action shooter ever to exist
- *                    > www.orxonox.net <
- *
- *
- *   License notice:
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation; either version 2
- *   of the License, or (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- *   Author:
- *      Damian 'Mozork' Frick
- *   Co-authors:
- *      ...
- *
- */
-
-#include "QuestGUINode.h"
-
-#include <sstream>
-
-#include <CEGUIWindowManager.h>
-#include <elements/CEGUIFrameWindow.h>
-#include <elements/CEGUIPushButton.h>
-#include <falagard/CEGUIFalWidgetLookFeel.h>
-#include <falagard/CEGUIFalWidgetLookManager.h>
-
-#include "core/CoreIncludes.h"
-#include "Quest.h"
-#include "QuestHint.h"
-#include "QuestItem.h"
-#include "QuestDescription.h"
-#include "QuestGUI.h"
-
-namespace orxonox {
-
-    /**
-    @brief
-        Default Constructor. Registers and initializes the object.
-    */
-    QuestGUINode::QuestGUINode(void)
-    {
-        this->initialize();
-    }
-
-    /**
-    @brief
-        Constructor. Registers and initializes the object.
-    @param gui
-        The QuestGUi the node beongs to.
-    @param parent
-        The parent node of the newly created node.
-    @param item
-        The QuestItem the  newly created node is for.
-    @param depth
-        Parameter to define how much the list item has to be indented.
-    @param index
-        "Counter" for Quests and Hints.
-    */
-    QuestGUINode::QuestGUINode(QuestGUI* gui, QuestGUINode* parent, QuestItem* item, int depth, int index)
-    {
-        this->initialize();
-
-        this->gui_ = gui;
-        this->parent_ = parent;
-        this->item_ = item;
-        this->depth_ = depth;
-        this->index_ = index;
-
-        this->createWindow();
-
-        COUT(3) << "New QuestGUINode '" << this->window_->getName() << "' created." << std::endl;
-    }
-
-    /**
-    @brief
-        Destructor.
-    @todo
-        Destroying everything?
-    */
-    QuestGUINode::~QuestGUINode(void)
-    {
-        if(this->window_ != NULL)
-            this->window_->destroy();
-        if(this->details_ != NULL)
-        {
-            this->details_->destroy();
-        }
-    }
-
-    /**
-    @brief
-        Initialize the object.
-    */
-    void QuestGUINode::initialize(void)
-    {
-        RegisterRootObject(QuestGUINode);
-
-        this->parent_ = NULL;
-        this->item_ = NULL;
-        this->window_ = NULL;
-        this->details_ = NULL;
-        this->depth_ = 0;
-        this->index_ = 0;
-        this->visible_ = true;
-    }
-
-    void QuestGUINode::toggleVisibility(void)
-    {
-
-    }
-
-    /**
-    @brief
-        Sets the input buffer to the name of the node.
-    @param buffer
-        The buffer that is set to the name of the node.
-    @todo
-        Needed?
-    */
-    void QuestGUINode::getName(std::string & buffer)
-    {
-        if(this->window_ != NULL)
-        {
-            buffer = this->window_->getName().c_str();
-        }
-        else
-        {
-            buffer.erase();
-        }
-    }
-
-    /**
-    @brief
-        Creates the details window.
-    @return
-        Returns the details window.
-    @todo
-        Return necessary?
-    */
-    CEGUI::Window* QuestGUINode::getDetails(void)
-    {
-
-        if(this->details_ == NULL) //!< If the details window was not already created.
-        {
-            std::ostringstream stream;
-
-            //! Create the main window for the details.
-            stream << this->window_->getName() << "/Details";
-            const QuestDescription* description = this->item_->getDescription();
-            this->details_ = this->gui_->getWindowManager()->createWindow("MenuWidgets/FrameWindow", stream.str());
-            this->details_->setSize(CEGUI::UVector2(CEGUI::UDim(0.7f, 0),CEGUI::UDim(0.7f, 0)));
-            this->details_->setPosition(CEGUI::UVector2(CEGUI::UDim(0.1f, 0),CEGUI::UDim(0.1f, 0)));
-            this->details_->setText(description->getTitle());
-            this->details_->setAlpha(1.0);
-            this->details_->setInheritsAlpha(false);
-            this->details_->setProperty("CloseButtonEnabled", "True");
-            this->details_->subscribeEvent(CEGUI::FrameWindow::EventCloseClicked, CEGUI::Event::Subscriber(&QuestGUINode::closeDetails, this));
-
-            //! Create a ScrollablePane.
-            stream << "/Scrollable";
-            CEGUI::Window* window = this->gui_->getWindowManager()->createWindow("MenuWidgets/ScrollablePane", stream.str());
-            window->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, -2*QuestGUINode::BORDER_WIDTH),CEGUI::UDim(1.0, -QuestGUINode::TITLE_HEIGHT)));
-            window->setPosition(CEGUI::UVector2(CEGUI::UDim(0, (float)QuestGUINode::BORDER_WIDTH),CEGUI::UDim(0, (float)QuestGUINode::TITLE_HEIGHT)));
-            this->details_->addChildWindow(window);
-
-            int height;
-            int offset = 0;
-
-            //! Display the status of the QuestItem if it is a Quest.
-            Quest* quest = dynamic_cast<Quest*>(this->item_);
-            if(quest != NULL) //!< If the QuestItem is a Quest
-            {
-                stream.str("");
-                stream << this->details_->getName() << "/Status";
-                CEGUI::Window* statusWindow = this->gui_->getWindowManager()->createWindow("MenuWidgets/StaticText", stream.str());
-                window->addChildWindow(statusWindow);
-                std::string status;
-                if(quest->isActive(this->gui_->getPlayer()))
-                {
-                    status = "This quest is active.";
-                }
-                else if(quest->isCompleted(this->gui_->getPlayer()))
-                {
-                    status = "This quest was completed.";
-                }
-                else if(quest->isFailed(this->gui_->getPlayer()))
-                {
-                    status = "This quest was failed.";
-                }
-                statusWindow->setProperty("HorzFormatting", "WordWrapLeftAligned");
-                statusWindow->setProperty("VertFormatting", "TopAligned");
-                statusWindow->setText(status);
-                statusWindow->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0),CEGUI::UDim(0, (float)offset)));
-                statusWindow->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, (float)-QuestGUINode::SCROLLBAR_WIDTH),CEGUI::UDim(1.0f, 0)));
-                height = setHeight(statusWindow);
-
-                offset += height;
-            }
-
-            //! Create title pane for the description.
-            stream.str("");
-            stream << this->details_->getName() << "/Description";
-            stream << "/Title";
-            CEGUI::Window* descriptionWindowTitle = this->gui_->getWindowManager()->createWindow("MenuWidgets/StaticText", stream.str());
-            window->addChildWindow(descriptionWindowTitle);
-            descriptionWindowTitle->setProperty("HorzFormatting", "HorzCentred");
-            descriptionWindowTitle->setProperty("VertFormatting", "TopAligned");
-            descriptionWindowTitle->setText("Description:");
-            descriptionWindowTitle->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0),CEGUI::UDim(0, (float)offset)));
-            descriptionWindowTitle->setSize(CEGUI::UVector2(CEGUI::UDim(1.0f, -QuestGUINode::SCROLLBAR_WIDTH),CEGUI::UDim(1.0f, 0)));
-
-            offset += setHeight(descriptionWindowTitle);
-
-            //! Display the Description of the QuestItem.
-            stream.str("");
-            stream << this->details_->getName() << "/Description";
-            CEGUI::Window* descriptionWindow = this->gui_->getWindowManager()->createWindow("MenuWidgets/StaticText", stream.str());
-            window->addChildWindow(descriptionWindow);
-            descriptionWindow->setProperty("HorzFormatting", "WordWrapLeftAligned");
-            descriptionWindow->setProperty("VertFormatting", "TopAligned");
-            descriptionWindow->setText(description->getDescription());
-            descriptionWindow->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0),CEGUI::UDim(0, (float)offset)));
-            descriptionWindow->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, (float)-QuestGUINode::SCROLLBAR_WIDTH),CEGUI::UDim(1.0f, 0)));
-            height = setHeight(descriptionWindow);
-
-            offset += height;
-
-            //! Display a list of hints if the QuestItem is a Quest.
-            bool title = true;
-            if(quest != NULL)
-            {
-                for(std::list<QuestGUINode*>::iterator it = this->subNodes_.begin(); it != this->subNodes_.end(); it++)
-                {
-                    if(dynamic_cast<QuestHint*>((*it)->item_) != NULL) //!< If the subNode belongs to a QuestHint.
-                    {
-                        if(title) //!< If no title pane for the QuestHints has been created, create one.
-                        {
-                            stream.str("");
-                            stream << this->details_->getName() << "/Hints/Title";
-                            CEGUI::Window* hintsTitle = this->gui_->getWindowManager()->createWindow("MenuWidgets/StaticText", stream.str());
-                            window->addChildWindow(hintsTitle);
-                            hintsTitle->setProperty("HorzFormatting", "HorzCentred");
-                            hintsTitle->setProperty("VertFormatting", "TopAligned");
-                            hintsTitle->setText("Hints:");
-                            hintsTitle->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0),CEGUI::UDim(0, (float)offset)));
-                            hintsTitle->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, -QuestGUINode::SCROLLBAR_WIDTH),CEGUI::UDim(1.0, 0)));
-                            offset += setHeight(hintsTitle);;
-                            title = false;
-                        }
-                        QuestGUINode* node = *it;
-                        node->window_->setSize(CEGUI::UVector2(CEGUI::UDim(1.0f, (float)-QuestGUINode::SCROLLBAR_WIDTH),CEGUI::UDim(0, (float)QuestGUINode::BUTTON_HEIGHT)));
-                        node->window_->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0),CEGUI::UDim(0, (float)offset)));
-                        window->addChildWindow(node->window_);
-                        offset += QuestGUINode::BUTTON_HEIGHT;
-                    }
-                }
-            }
-
-            COUT(3) << "Show Details: " << this->details_->getName() << std::endl;
-        }
-
-        return this->details_;
-    }
-
-    /**
-    @brief
-        Opens the details window for the Quest/QuestHint clicked on.
-    */
-    bool QuestGUINode::openDetails(const CEGUI::EventArgs& e)
-    {
-        COUT(3) << "Open QuestItem..." << std::endl;
-
-        //CEGUI::Window* window = this->gui_->getRootWindow();
-        CEGUI::Window* window = this->gui_->getWindowManager()->getWindow("orxonox/QuestGUI/Background");
-
-        if(window != NULL)
-            window->addChildWindow(this->getDetails());
-
-        return true;
-    }
-
-    /**
-    @brief
-        Close the details window.
-    */
-    bool QuestGUINode::closeDetails(const CEGUI::EventArgs& e)
-    {
-        //CEGUI::Window* window = this->gui_->getRootWindow();
-        CEGUI::Window* window = this->gui_->getWindowManager()->getWindow("orxonox/QuestGUI/Background");
-        window->removeChildWindow(this->details_);
-
-        return true;
-    }
-
-    /**
-    @brief
-        Helper method for setHeight(). Gets the StaticTextArea for an input CEGUI Window.
-    @param window
-        The CEGUI window.
-    @return
-        Returns a CEGUI Rect.
-    */
-    /*static*/ CEGUI::Rect QuestGUINode::getStaticTextArea(const CEGUI::Window* window)
-    {
-        const CEGUI::WidgetLookFeel& lookAndFeel = CEGUI::WidgetLookManager::getSingleton().getWidgetLook(window->getLookNFeel());
-
-        return lookAndFeel.getNamedArea("WithFrameTextRenderArea").getArea().getPixelRect(*window);
-    }
-
-    /**
-    @brief
-        Helper method to adjust the height of an input Window (of type StaticText) to the text it holds.
-    @param window
-        The  CEGUI Window (of type StaticText) for which the height is to be adjusted to the text.
-    @return
-        Returns the set height.
-    */
-    /*static*/ int QuestGUINode::setHeight(CEGUI::Window* window)
-    {
-        //! Get the area the text is formatted and drawn into.
-        const CEGUI::Rect formattedArea = getStaticTextArea(window);
-
-        //! Calculate the pixel height of the frame by subtracting the height of the area above from the total height of the window.
-        const float frameHeight = window->getUnclippedPixelRect().getHeight() - formattedArea.getHeight();
-
-        //! Get the formatted line count - using the formatting area obtained above.
-        const float lines = (float)(window->getFont()->getFormattedLineCount(window->getText(), formattedArea, CEGUI::WordWrapLeftAligned));
-
-        //! Calculate pixel height of window, which is the number of formatted lines multiplied by the spacing of the font, plus the pixel height of the frame.
-        const float height = lines * window->getFont()->getLineSpacing() + frameHeight;
-
-        //! Set the height to the window.
-        window->setHeight(CEGUI::UDim(0, height));
-
-        //Debug
-        const CEGUI::Rect newArea = getStaticTextArea(window);
-
-        return static_cast<int>(height);
-    }
-
-    /**
-    @brief
-        Update the position list item.
-    */
-    void QuestGUINode::updatePosition(void)
-    {
-        this->window_->setPosition(CEGUI::UVector2(CEGUI::UDim(0, (float)(QuestGUINode::INDENT_WIDTH*this->depth_)),CEGUI::UDim(0, (float)(QuestGUINode::BUTTON_HEIGHT*this->index_))));
-        this->window_->setSize(CEGUI::UVector2(CEGUI::UDim(1, (float)(-QuestGUINode::INDENT_WIDTH*this->depth_-QuestGUINode::SCROLLBAR_WIDTH)),CEGUI::UDim(0, (float)QuestGUINode::BUTTON_HEIGHT)));
-    }
-
-    /**
-    @brief
-        Helper method to create the CEGUI Window the node.
-    */
-    void QuestGUINode::createWindow(void)
-    {
-        Quest* quest = dynamic_cast<Quest*>(this->item_);
-
-        this->window_ = this->gui_->getWindow();
-        std::ostringstream stream;
-        stream << "QuestGUI/Quests/";
-        if(quest == NULL)
-        {
-            stream << this->parent_->index_ << "/Hints/";
-        }
-        stream << this->index_;
-
-        this->window_->rename(stream.str());
-        this->window_->setText(this->item_->getDescription()->getTitle());
-
-        this->parent_->subNodes_.push_back(this);
-
-        if(dynamic_cast<Quest*>(this->item_) != NULL)
-        {
-            this->gui_->getRootWindow()->addChildWindow(this->window_);
-            this->updatePosition();
-        }
-        else
-        {
-            this->window_->setDestroyedByParent(false);
-        }
-
-        this->window_->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&QuestGUINode::openDetails, this));
-    }
-
-}
-
Index: code/trunk/src/modules/questsystem/QuestGUINode.h
===================================================================
--- code/trunk/src/modules/questsystem/QuestGUINode.h	(revision 6906)
+++ 	(revision )
@@ -1,98 +1,0 @@
-/*
- *   ORXONOX - the hottest 3D action shooter ever to exist
- *                    > www.orxonox.net <
- *
- *
- *   License notice:
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation; either version 2
- *   of the License, or (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- *   Author:
- *      Damian 'Mozork' Frick
- *   Co-authors:
- *      ...
- *
- */
-
-#ifndef _QuestGUINode_H__
-#define _QuestGUINode_H__
-
-#include "questsystem/QuestsystemPrereqs.h"
-
-#include <list>
-#include <string>
-#include <CEGUIForwardRefs.h>
-#include "core/OrxonoxClass.h"
-
-
-namespace orxonox {
-
-    class _QuestsystemExport QuestGUINode : public OrxonoxClass
-    {
-
-        public:
-
-            QuestGUINode(void);
-            QuestGUINode(QuestGUI* gui, QuestGUINode* parent, QuestItem* item, int depth, int index);
-            virtual ~QuestGUINode(void);
-
-            void toggleVisibility(void);
-
-            void getName(std::string & buffer); //!< Sets the input buffer to the name of the node.
-            /**
-            @brief Retreive the window of this node.
-            @return The CEGUI Window of this node.
-            */
-            inline CEGUI::Window* getWindow(void)
-                { return this->window_; }
-
-            bool openDetails(const CEGUI::EventArgs& e); //!< Opens the details window for the Quest/QuestHint clicked on.
-            bool closeDetails(const CEGUI::EventArgs& e); //!< Close the details window.
-
-        private:
-            CEGUI::Window* getDetails(void); //!< Creates the details window.
-
-            void initialize(void); //!< Initialize the object.
-            void updatePosition(void); //!< Update the position list item.
-            void createWindow(void); //!< Helper method to create the CEGUI Window the node.
-            static CEGUI::Rect getStaticTextArea(const CEGUI::Window* window); //Helper method for setHeight(). Gets the StaticTextArea for an input CEGUI Window.
-            static int setHeight(CEGUI::Window* window); //Helper method to adjust the height of an input Window (of type StaticText) to the text it holds.
-
-            bool visible_; //!< Boolean determining the visibility of the node.
-
-            QuestGUI* gui_; //!< The QuestGUI this node belongs to.
-            QuestGUINode* parent_; //!< The parent node.
-            std::list<QuestGUINode*> subNodes_; //!< A list of all subnodes.
-            QuestItem* item_; //!< QuestItem belonging to this node.
-
-            int depth_; //!< The depth (resp. indentation) of this node in the list of Quests. (Irrelevant for QuestHints)
-            int index_; //!< The index of this node in the list of Quests, resp. in the list of QuestHints, if the node belongs to a QuestHint, rather than a Quest.
-
-            CEGUI::Window* window_; //!< The list window of this node.
-            CEGUI::Window* details_; //!< The details window of this node.
-
-            //! Some magic numbers
-            static const int TITLE_HEIGHT = 26;
-            static const int BORDER_WIDTH = 5;
-            static const int SCROLLBAR_WIDTH = 13;
-            static const int BUTTON_HEIGHT = 30;
-            static const int INDENT_WIDTH = 20;
-
-    };
-
-}
-
-#endif /* _QuestGUINode_H__ */
-
Index: code/trunk/src/modules/questsystem/QuestHint.cc
===================================================================
--- code/trunk/src/modules/questsystem/QuestHint.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestHint.cc	(revision 7163)
@@ -59,5 +59,6 @@
     QuestHint::~QuestHint()
     {
-
+        if(this->isRegistered())
+            QuestManager::getInstance().unregisterHint(this);
     }
 
@@ -72,5 +73,5 @@
         QuestManager::getInstance().registerHint(this); //!< Registers the QuestHint with the QuestManager.
 
-        COUT(3) << "New QuestHint {" << this->getId() << "} created." << std::endl;
+        COUT(4) << "New QuestHint {" << this->getId() << "} created." << std::endl;
     }
 
@@ -125,10 +126,10 @@
             else
             {
-                COUT(2) << "An already active questHint was trying to get activated." << std::endl;
+                COUT(4) << "An already active questHint was trying to get activated." << std::endl;
                 return false;
             }
         }
 
-        COUT(2) << "A hint of a non-active quest was trying to get activated." << std::endl;
+        COUT(4) << "A hint of a non-active quest was trying to get activated." << std::endl;
         return false;
     }
Index: code/trunk/src/modules/questsystem/QuestHint.h
===================================================================
--- code/trunk/src/modules/questsystem/QuestHint.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestHint.h	(revision 7163)
@@ -40,6 +40,6 @@
 #include "QuestItem.h"
 
-namespace orxonox
-{
+namespace orxonox // tolua_export
+{ // tolua_export
     namespace QuestHintStatus
     {
@@ -66,6 +66,7 @@
         Damian 'Mozork' Frick
     */
-    class _QuestsystemExport QuestHint : public QuestItem
-    {
+    class _QuestsystemExport QuestHint // tolua_export
+        : public QuestItem
+    { // tolua_export
 
         public:
@@ -91,7 +92,7 @@
             std::map<const PlayerInfo*, QuestHintStatus::Value> playerStatus_; //!< List of the states for each player, with the Player-pointer as key.
 
-    };
+    }; // tolua_export
 
-}
+} // tolua_export
 
 #endif /* _QuestHint_H__ */
Index: code/trunk/src/modules/questsystem/QuestItem.cc
===================================================================
--- code/trunk/src/modules/questsystem/QuestItem.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestItem.cc	(revision 7163)
@@ -40,4 +40,7 @@
 namespace orxonox
 {
+
+    CreateUnloadableFactory(QuestItem);
+
     /**
     @brief
@@ -46,4 +49,6 @@
     QuestItem::QuestItem(BaseObject* creator) : BaseObject(creator)
     {
+        this->registered_ = false;
+
         RegisterObject(QuestItem);
     }
@@ -79,5 +84,5 @@
     void QuestItem::setId(const std::string & id)
     {
-        if(!isId(id)) //!< Checks whether the id is a valid id.
+        if(id.compare(BLANKSTRING) == 0) //!< Checks whether the id is a valid id.
         {
             COUT(2) << "Invalid id. QuestItem id {" << id << "} could not be set." << std::endl;
@@ -88,16 +93,3 @@
     }
 
-    /**
-    @brief
-        Checks whether an input id is of the required form.
-    @param id
-        The id to be checked.
-    @return
-        Returns true if the string is likely to be of the required form.
-    */
-    /*static*/ bool QuestItem::isId(const std::string & id)
-    {
-        return id.size() >= 32;
-    }
-
 }
Index: code/trunk/src/modules/questsystem/QuestItem.h
===================================================================
--- code/trunk/src/modules/questsystem/QuestItem.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestItem.h	(revision 7163)
@@ -41,4 +41,5 @@
 #include <string>
 #include "core/BaseObject.h"
+#include "QuestManager.h"
 
 namespace orxonox
@@ -71,8 +72,18 @@
             @return Returns a pointer to the QuestDescription object of the QuestItem.
             */
-            inline const QuestDescription* getDescription(void) const
+            inline QuestDescription* getDescription(void) const
                 { return this->description_; }
 
-            static bool isId(const std::string & id); //!< Checks whether a given id is valid.
+            /**
+            @brief Check whether the QuestItem is registered with the QuestManager.
+            @return Returns true if the QuestItem is registered with the QuestManager.
+            */
+            inline bool isRegistered(void)
+                { return this->registered_; }
+            /**
+            @brief Set the QuestItem as being registered with the QuestManager.
+            */
+            inline void setRegistered(void)
+                { this->registered_ = true; }
 
         protected:
@@ -90,4 +101,6 @@
             QuestDescription* description_; //!< The QuestDescription of the QuestItem.
 
+            bool registered_;
+
     };
 
Index: code/trunk/src/modules/questsystem/QuestListener.cc
===================================================================
--- code/trunk/src/modules/questsystem/QuestListener.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestListener.cc	(revision 7163)
@@ -74,7 +74,8 @@
         XMLPortParam(QuestListener, "mode", setMode, getMode, xmlelement, mode);
 
-        this->quest_->addListener(this); //!< Adds the QuestListener to the Quests list of listeners.
-
-        COUT(3) << "QuestListener created for quest: {" << this->quest_->getId() << "} with mode '" << this->getMode() << "'." << std::endl;
+        if(this->quest_ != NULL)
+            this->quest_->addListener(this); //!< Adds the QuestListener to the Quests list of listeners.
+
+        COUT(4) << "QuestListener created for quest: {" << this->quest_->getId() << "} with mode '" << this->getMode() << "'." << std::endl;
     }
 
Index: code/trunk/src/modules/questsystem/QuestManager.cc
===================================================================
--- code/trunk/src/modules/questsystem/QuestManager.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestManager.cc	(revision 7163)
@@ -74,9 +74,5 @@
     QuestManager::~QuestManager()
     {
-        for(std::map<PlayerInfo*, QuestGUI*>::iterator it = this->questGUIs_.begin(); it != this->questGUIs_.end(); it++)
-        {
-            it->second->destroy();
-        }
-        this->questGUIs_.clear();
+
     }
 
@@ -114,5 +110,6 @@
         if(result.second) //!< If inserting was a success.
         {
-            COUT(3) << "Quest with questId {" << quest->getId() << "} successfully inserted." << std::endl;
+            quest->setRegistered();
+            COUT(4) << "Quest with questId {" << quest->getId() << "} successfully inserted." << std::endl;
             return true;
         }
@@ -122,4 +119,13 @@
            return false;
         }
+    }
+
+    /**
+    @brief
+        Unregisters a Quest in the QuestManager.
+    */
+    bool QuestManager::unregisterQuest(Quest* quest)
+    {
+        return this->questMap_.erase(quest->getId()) == 1;
     }
 
@@ -146,5 +152,6 @@
         if(result.second) //!< If inserting was a success.
         {
-            COUT(3) << "QuestHint with hintId {" << hint->getId() << "} successfully inserted." << std::endl;
+            hint->setRegistered();
+            COUT(4) << "QuestHint with hintId {" << hint->getId() << "} successfully inserted." << std::endl;
             return true;
         }
@@ -154,4 +161,13 @@
            return false;
         }
+    }
+
+    /**
+    @brief
+        Unregisters a QuestHint in the QuestManager.
+    */
+    bool QuestManager::unregisterHint(QuestHint* hint)
+    {
+        return this->hintMap_.erase(hint->getId()) == 1;
     }
 
@@ -169,5 +185,5 @@
     Quest* QuestManager::findQuest(const std::string & questId)
     {
-        if(!QuestItem::isId(questId)) //!< Check vor validity of the given id.
+        if(questId.compare(BLANKSTRING) == 1) //!< Check vor validity of the given id.
         {
             ThrowException(Argument, "Invalid questId.");
@@ -203,5 +219,5 @@
     QuestHint* QuestManager::findHint(const std::string & hintId)
     {
-        if(!QuestItem::isId(hintId)) //!< Check vor validity of the given id.
+        if(hintId.compare(BLANKSTRING) == 1) //!< Check vor validity of the given id.
         {
             ThrowException(Argument, "Invalid hintId.");
@@ -224,21 +240,79 @@
     }
 
-    /**
-    @brief
-        Retreive the main window for the GUI.
-        This is for the use in the lua script tu start the QuestGUI.
-    @param guiName
-        The name of the GUI.
-    @return
-        Returns a CEGUI Window.
-    */
-    CEGUI::Window* QuestManager::getQuestGUI(const std::string & guiName)
-    {
-        PlayerInfo* player = this->retrievePlayer(guiName);
-
-        if(this->questGUIs_.find(player) == this->questGUIs_.end()) //!< Create a new GUI, if there is none, yet.
-            this->questGUIs_[player] = new QuestGUI(player);
-
-        return this->questGUIs_[player]->getGUI();
+    int QuestManager::getNumParentQuests(PlayerInfo* player)
+    {
+        int numQuests = 0;
+        for(std::map<std::string, Quest*>::iterator it = this->questMap_.begin(); it != this->questMap_.end(); it++)
+        {
+            if(it->second->getParentQuest() == NULL && !it->second->isInactive(player))
+                numQuests++;
+        }
+        return numQuests;
+    }
+
+    Quest* QuestManager::getParentQuest(PlayerInfo* player, int index)
+    {
+        for(std::map<std::string, Quest*>::iterator it = this->questMap_.begin(); it != this->questMap_.end(); it++)
+        {
+            if(it->second->getParentQuest() == NULL && !it->second->isInactive(player) && index-- == 0)
+                return it->second;
+        }
+        return NULL;
+    }
+
+    int QuestManager::getNumSubQuests(Quest* quest, PlayerInfo* player)
+    {
+        std::list<Quest*> quests = quest->getSubQuestList();
+        int numQuests = 0;
+        for(std::list<Quest*>::iterator it = quests.begin(); it != quests.end(); it++)
+        {
+            if(!(*it)->isInactive(player))
+                numQuests++;
+        }
+        return numQuests;
+    }
+
+    Quest* QuestManager::getSubQuest(Quest* quest, PlayerInfo* player, int index)
+    {
+        std::list<Quest*> quests = quest->getSubQuestList();
+        for(std::list<Quest*>::iterator it = quests.begin(); it != quests.end(); it++)
+        {
+            if(!(*it)->isInactive(player) && index-- == 0)
+                return *it;
+        }
+        return NULL;
+    }
+
+    int QuestManager::getNumHints(Quest* quest, PlayerInfo* player)
+    {
+        std::list<QuestHint*> hints = quest->getHintsList();
+        int numHints = 0;
+        for(std::list<QuestHint*>::iterator it = hints.begin(); it != hints.end(); it++)
+        {
+            if((*it)->isActive(player))
+                numHints++;
+        }
+        return numHints;
+    }
+
+    QuestHint* QuestManager::getHints(Quest* quest, PlayerInfo* player, int index)
+    {
+        std::list<QuestHint*> hints = quest->getHintsList();
+        for(std::list<QuestHint*>::iterator it = hints.begin(); it != hints.end(); it++)
+        {
+            if((*it)->isActive(player) && index-- == 0)
+                return *it;
+        }
+        return NULL;
+    }
+
+    QuestDescription* QuestManager::getDescription(Quest* item)
+    {
+        return item->getDescription();
+    }
+
+    QuestDescription* QuestManager::getDescription(QuestHint* item)
+    {
+        return item->getDescription();
     }
 
Index: code/trunk/src/modules/questsystem/QuestManager.h
===================================================================
--- code/trunk/src/modules/questsystem/QuestManager.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestManager.h	(revision 7163)
@@ -36,5 +36,4 @@
 
 #include "questsystem/QuestsystemPrereqs.h"
-#include <CEGUIForwardRefs.h>
 
 #include <list>
@@ -44,6 +43,4 @@
 #include "util/Singleton.h"
 #include "core/OrxonoxClass.h"
-
-#include "QuestGUI.h"
 
 // tolua_begin
@@ -63,5 +60,4 @@
 
             friend class Singleton<QuestManager>;
-            friend class QuestGUI;
 
         public:
@@ -72,9 +68,22 @@
             static QuestManager& getInstance() { return Singleton<QuestManager>::getInstance(); } // tolua_export
 
-            //! Retrieve the main window for the GUI.
-            CEGUI::Window* getQuestGUI(const std::string & guiName); // tolua_export
+            // tolua_begin
+            int getNumParentQuests(orxonox::PlayerInfo* player);
+            Quest* getParentQuest(orxonox::PlayerInfo* player, int index);
+
+            int getNumSubQuests(Quest* quest, orxonox::PlayerInfo* player);
+            Quest* getSubQuest(Quest* quest, orxonox::PlayerInfo* player, int index);
+
+            int getNumHints(Quest* quest, orxonox::PlayerInfo* player);
+            QuestHint* getHints(Quest* quest, orxonox::PlayerInfo* player, int index);
+
+            QuestDescription* getDescription(Quest* item);
+            QuestDescription* getDescription(QuestHint* item);
+            // tolua_end
 
             bool registerQuest(Quest* quest); //!< Registers a Quest in the QuestManager.
-            bool registerHint(QuestHint* quest); //!< Registers a QuestHint in the QuestManager.
+            bool unregisterQuest(Quest* quest); //!< Unregisters a Quest in the QuestManager.
+            bool registerHint(QuestHint* hint); //!< Registers a QuestHint in the QuestManager.
+            bool unregisterHint(QuestHint* hint); //!< Unregisters a QuestHint in the QuestManager.
 
             Quest* findQuest(const std::string & questId); //!< Returns the Quest with the input id.
@@ -91,6 +100,4 @@
             std::map<std::string, QuestHint*> hintMap_; //!< All QuestHints registered by their id's.
 
-            std::map<PlayerInfo*, QuestGUI*> questGUIs_; //!< All GUI's registered by the players.
-
     }; // tolua_export
 
Index: code/trunk/src/modules/questsystem/QuestNotification.cc
===================================================================
--- code/trunk/src/modules/questsystem/QuestNotification.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestNotification.cc	(revision 7163)
@@ -32,16 +32,32 @@
 namespace orxonox {
 
-    const std::string QuestNotification::SENDER("questsystem");
+    /*static*/ const std::string QuestNotification::SENDER("questsystem");
 
+    CreateUnloadableFactory(QuestNotification);
+
+    /**
+    @brief
+        Default Constructor. Creates a useless QuestNotification.
+    */
     QuestNotification::QuestNotification(BaseObject* creator) : Notification(creator)
     {
-        this->initialize();
+        RegisterObject(QuestNotification);
     }
 
-    QuestNotification::QuestNotification(const std::string & message) : Notification(message)
+    /**
+    @brief
+        Creates a QuestNotification with the input message.
+    @param message
+        The message to be sent.
+    */
+    QuestNotification::QuestNotification(BaseObject* creator, const std::string & message) : Notification(creator, message)
     {
-        this->initialize();
+        RegisterObject(QuestNotification);
     }
 
+    /**
+    @brief
+        Destructor.
+    */
     QuestNotification::~QuestNotification()
     {
@@ -49,4 +65,10 @@
     }
 
+    /**
+    @brief
+        Send the QuestNotification.
+    @return
+        Returns true if successful.
+    */
     bool QuestNotification::send(void)
     {
@@ -54,9 +76,4 @@
     }
 
-    void QuestNotification::initialize(void)
-    {
-        RegisterObject(QuestNotification);
-    }
-
 
 }
Index: code/trunk/src/modules/questsystem/QuestNotification.h
===================================================================
--- code/trunk/src/modules/questsystem/QuestNotification.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestNotification.h	(revision 7163)
@@ -39,5 +39,5 @@
     /**
     @brief
-
+        The QuestNotification is a special Notification that has the single property that it is only sent by the questsystem.
     @author
         Damian 'Mozork' Frick
@@ -46,14 +46,12 @@
     {
         public:
-            QuestNotification(BaseObject* creator);
-            QuestNotification(const std::string & message);
-            virtual ~QuestNotification();
+            QuestNotification(BaseObject* creator); //!< Default Constructor.
+            QuestNotification(BaseObject* creator, const std::string & message); //!< Constructor.
+            virtual ~QuestNotification(); //!< Destructor.
 
-            bool send(void);
+            bool send(void); //!< Send the QuestNotification.
 
         private:
-            static const std::string SENDER;
-
-            void initialize(void);
+            static const std::string SENDER; //!< A string identifying the questsystem as the sender.
 
     };
Index: code/trunk/src/modules/questsystem/QuestsystemPrereqs.h
===================================================================
--- code/trunk/src/modules/questsystem/QuestsystemPrereqs.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/QuestsystemPrereqs.h	(revision 7163)
@@ -43,5 +43,5 @@
 //-----------------------------------------------------------------------
 
-#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_STATIC_BUILD)
+#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(QUESTSYSTEM_STATIC_BUILD)
 #  ifdef QUESTSYSTEM_SHARED_BUILD
 #    define _QuestsystemExport __declspec(dllexport)
@@ -77,6 +77,4 @@
     class QuestEffect;
     class QuestEffectBeacon;
-    class QuestGUI;
-    class QuestGUINode;
     class QuestHint;
     class QuestItem;
Index: code/trunk/src/modules/questsystem/notifications/Notification.cc
===================================================================
--- code/trunk/src/modules/questsystem/notifications/Notification.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/notifications/Notification.cc	(revision 7163)
@@ -40,4 +40,6 @@
 {
 
+    CreateUnloadableFactory(Notification);
+
     /**
     @brief
@@ -56,5 +58,5 @@
         The message of the Notification.
     */
-    Notification::Notification(const std::string & message) : BaseObject(NULL)
+    Notification::Notification(BaseObject* creator, const std::string & message) : BaseObject(creator)
     {
         this->message_ = message;
@@ -67,4 +69,5 @@
     Notification::~Notification()
     {
+
     }
 
Index: code/trunk/src/modules/questsystem/notifications/Notification.h
===================================================================
--- code/trunk/src/modules/questsystem/notifications/Notification.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/notifications/Notification.h	(revision 7163)
@@ -53,5 +53,5 @@
         public:
             Notification(BaseObject* creator);
-            Notification(const std::string & message);
+            Notification(BaseObject* creator, const std::string & message);
             virtual ~Notification();
 
Index: code/trunk/src/modules/questsystem/notifications/NotificationManager.cc
===================================================================
--- code/trunk/src/modules/questsystem/notifications/NotificationManager.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/notifications/NotificationManager.cc	(revision 7163)
@@ -66,4 +66,5 @@
     NotificationManager::~NotificationManager()
     {
+
     }
 
@@ -101,10 +102,68 @@
                 this->notificationLists_[it->second]->insert(std::pair<std::time_t,Notification*>(time,notification)); //!< Insert the Notification in the Notifications list of the current NotificationListener.
                 it->first->update(notification, time); //!< Update the listener.
+                std::map<Notification*, unsigned int>::iterator counterIt = this->listenerCounter_.find(notification);
+                if(counterIt == this->listenerCounter_.end())
+                    this->listenerCounter_[notification] = 1;
+                else
+                    this->listenerCounter_[notification] = counterIt->second + 1;
             }
         }
 
-        COUT(3) << "Notification registered with the NotificationManager." << std::endl;
+        COUT(4) << "Notification registered with the NotificationManager." << std::endl;
 
         return true;
+    }
+
+    /**
+    @brief
+        Unregisters a Notification within the NotificationManager.
+    @param notification
+        A pointer to the Notification to be unregistered.
+    @param listener
+        A pointer to the NotificationListener the Notification is unregistered for.
+    */
+    void NotificationManager::unregisterNotification(Notification* notification, NotificationListener* listener)
+    {
+        assert(notification);
+        assert(listener);
+
+        // If the Notification was removed from the list of Notifications of the input NotificationListener, the counter for the Notification of the number of NotificationListeners it is present in is decremented.
+        if(this->removeNotification(notification, *(this->notificationLists_.find(this->listenerList_.find(listener)->second)->second)))
+            this->listenerCounter_[notification] = this->listenerCounter_[notification] - 1;
+
+        // If the Notification is no longer present in any of the NotificationListeners it can be removed from the map of all Notifications and be destroyed.
+        if(this->listenerCounter_[notification] == (unsigned int) 0)
+        {
+            this->removeNotification(notification, this->allNotificationsList_);
+            this->listenerCounter_.erase(notification);
+            notification->destroy();
+        }
+
+        COUT(4) << "Notification unregistered with the NotificationManager." << std::endl;
+    }
+
+    /**
+    @brief
+        Helper method that removes an input notification form an input map.
+    @param notification
+        A pointer to the notification to be removed.
+    @param map
+        The map the notification should be removed from.
+    @return
+        Returns true if successful.
+    */
+    bool NotificationManager::removeNotification(Notification* notification, std::multimap<std::time_t, Notification*>& map)
+    {
+        // Iterates through all items in the map until the Notification is found.
+        //TODO: Do more efficiently?
+        for(std::multimap<std::time_t, Notification*>::iterator it = map.begin(); it != map.end(); it++)
+        {
+            if(it->second == notification)
+            {
+                map.erase(it);
+                return true;
+            }
+        }
+        return false;
     }
 
@@ -130,5 +189,5 @@
         {
             this->notificationLists_[index] = &this->allNotificationsList_;
-            COUT(3) << "NotificationListener registered with the NotificationManager." << std::endl;
+            COUT(4) << "NotificationListener registered with the NotificationManager." << std::endl;
             return true;
         }
@@ -142,5 +201,10 @@
             if(set.find(it->second->getSender()) != set.end()) //!< Checks whether the overlay has the sender of the current notification as target.
             {
-                map.insert(std::pair<std::time_t,Notification*>(it->first, it->second));
+                map.insert(std::pair<std::time_t, Notification*>(it->first, it->second));
+                std::map<Notification*, unsigned int>::iterator counterIt = this->listenerCounter_.find(it->second);
+                if(counterIt == this->listenerCounter_.end())
+                    this->listenerCounter_[it->second] = 1;
+                else
+                    this->listenerCounter_[it->second] = counterIt->second + 1;
             }
         }
@@ -148,7 +212,36 @@
         listener->update(); //!< Update the listener.
 
-        COUT(3) << "NotificationListener registered with the NotificationManager." << std::endl;
+        COUT(4) << "NotificationListener registered with the NotificationManager." << std::endl;
 
         return true;
+    }
+
+    /**
+    @brief
+        Unregisters a NotificationListener withing the NotificationManager.
+    */
+    void NotificationManager::unregisterListener(NotificationListener* listener)
+    {
+        assert(listener);
+
+        int identifier = this->listenerList_.find(listener)->second;
+        std::multimap<std::time_t, Notification*>* map = this->notificationLists_.find(identifier)->second;
+
+        // Make sure all Notifications are removed.
+        std::multimap<std::time_t, Notification*>::iterator it = map->begin();
+        while(it != map->end())
+        {
+            this->unregisterNotification(it->second, listener);
+            it = map->begin();
+        }
+
+        this->listenerList_.erase(listener);
+        this->notificationLists_.erase(identifier);
+
+        // If the map is not the map of all notifications, delete it.
+        if(map != &this->allNotificationsList_)
+            delete map;
+
+        COUT(4) << "NotificationListener unregistered with the NotificationManager." << std::endl;
     }
 
Index: code/trunk/src/modules/questsystem/notifications/NotificationManager.h
===================================================================
--- code/trunk/src/modules/questsystem/notifications/NotificationManager.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/notifications/NotificationManager.h	(revision 7163)
@@ -60,9 +60,11 @@
             virtual ~NotificationManager();
 
-            static const std::string ALL;
-            static const std::string NONE;
+            static const std::string ALL; //!< Static string to indicate a sender that sends to all NotificationListeners.
+            static const std::string NONE; //!< Static string to indicare a sender that sends to no specific NotificationListener.
 
             bool registerNotification(Notification* notification); //!< Registers a Notification within the NotificationManager.
+            void unregisterNotification(Notification* notification, NotificationListener* listener); //!< Unregisters a Notification within the NotificationManager.
             bool registerListener(NotificationListener* listener); //!< Registers a NotificationListener within the NotificationManager.
+            void unregisterListener(NotificationListener* listener); //!< Unregisters a NotificationListener withing the NotificationManager.
 
             bool getNotifications(NotificationListener* listener, std::multimap<std::time_t,Notification*>* map, const std::time_t & timeFrameStart, const std::time_t & timeFrameEnd); //!< Returns the Notifications for a specific NotificationListener in a specified timeframe.
@@ -90,10 +92,12 @@
             static NotificationManager* singletonPtr_s;
 
-            int highestIndex_; //!< This variable holds the highest index (resp. key) in notificationLists_s, to secure that  no key appears twice.
+            int highestIndex_; //!< This variable holds the highest index (resp. key) in notificationLists_s, to secure that no key appears twice.
 
-            std::multimap<std::time_t,Notification*> allNotificationsList_; //!< Container where all notifications are stored (together with their respecive timestamps).
+            std::multimap<std::time_t,Notification*> allNotificationsList_; //!< Container where all notifications are stored.
             std::map<NotificationListener*,int> listenerList_; //!< Container where all NotificationListeners are stored with a number as identifier.
             std::map<int,std::multimap<std::time_t,Notification*>*> notificationLists_; //!< Container where all Notifications, for each identifier (associated with a NotificationListener), are stored.
+            std::map<Notification*, unsigned int> listenerCounter_; //!< A container to store the number of NotificationListeners a Notification is registered with.
 
+            bool removeNotification(Notification* notification, std::multimap<std::time_t, Notification*>& map); //!< Helper method that removes an input notification form an input map.
 
     };
Index: code/trunk/src/modules/questsystem/notifications/NotificationQueue.cc
===================================================================
--- code/trunk/src/modules/questsystem/notifications/NotificationQueue.cc	(revision 6906)
+++ code/trunk/src/modules/questsystem/notifications/NotificationQueue.cc	(revision 7163)
@@ -34,6 +34,5 @@
 #include "NotificationQueue.h"
 
-#include <sstream>
-
+#include "util/Convert.h"
 #include "core/CoreIncludes.h"
 #include "core/XMLPort.h"
@@ -56,4 +55,6 @@
     NotificationQueue::NotificationQueue(BaseObject* creator) : OverlayGroup(creator)
     {
+        this->registered_ = false;
+
         RegisterObject(NotificationQueue);
         this->initialize();
@@ -68,4 +69,7 @@
         this->targets_.clear();
         this->clear();
+
+        if(this->registered_)
+            NotificationManager::getInstance().unregisterListener(this);
     }
 
@@ -81,4 +85,5 @@
 
         NotificationManager::getInstance().registerListener(this);
+        this->registered_ = true;
     }
 
@@ -118,5 +123,5 @@
         XMLPortParam(NotificationQueue, "position", setPosition, getPosition, xmlElement, mode);
 
-        COUT(3) << "NotificationQueue created." << std::endl;
+        COUT(3) << "NotificationQueue '" << this->getName() << "' created." << std::endl;
     }
 
@@ -173,5 +178,5 @@
         delete notifications;
 
-        COUT(3) << "NotificationQueue updated." << std::endl;
+        COUT(4) << "NotificationQueue '" << this->getName() << "' updated." << std::endl;
     }
 
@@ -196,5 +201,5 @@
         }
 
-        COUT(3) << "NotificationQueue updated. A new Notifications has been added." << std::endl;
+        COUT(4) << "NotificationQueue '" << this->getName() << "' updated. A new Notifications has been added." << std::endl;
     }
 
@@ -397,7 +402,5 @@
         std::string timeString = std::ctime(&time);
         timeString.erase(timeString.length()-1);
-        std::ostringstream stream;
-        stream << reinterpret_cast<unsigned long>(notification);
-        const std::string& addressString = stream.str();
+        const std::string& addressString = multi_cast<std::string>(reinterpret_cast<unsigned long>(notification));
         container->name = "NotificationOverlay(" + timeString + ")&" + addressString;
 
@@ -422,4 +425,7 @@
         if(this->size_ == 0) //!< You cannot remove anything if the queue is empty.
             return false;
+
+        // Unregister the NotificationQueue with the NotificationManager.
+        NotificationManager::getInstance().unregisterNotification(container->notification, this);
 
         this->removeElement(container->overlay);
@@ -443,5 +449,5 @@
         {
             this->removeContainer(*it);
-            it = this->containers_.begin(); //TODO: Needed?
+            it = this->containers_.begin();
         }
     }
Index: code/trunk/src/modules/questsystem/notifications/NotificationQueue.h
===================================================================
--- code/trunk/src/modules/questsystem/notifications/NotificationQueue.h	(revision 6906)
+++ code/trunk/src/modules/questsystem/notifications/NotificationQueue.h	(revision 7163)
@@ -71,4 +71,5 @@
 
         Creating a NotificationQueue through XML goes as follows:
+        Be aware that the NotificationQueue must be inside the <Level></Level> tags or bad things will happen.
         <NotificationQueue
             name = "SuperQueue" //Name of your OverlayQueue.
@@ -185,4 +186,6 @@
             NotificationOverlayContainer timeLimit_; //!< Helper object to check against to determine whether Notifications have expired.
 
+            bool registered_; //!< Helper variable to remember whether the NotificationQueue is registered already.
+
             void initialize(void); //!< Initializes the object.
             void setDefaults(void); //!< Helper method to set the default values.
Index: code/trunk/src/modules/weapons/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/weapons/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/weapons/CMakeLists.txt	(revision 7163)
@@ -1,4 +1,5 @@
 SET_SOURCE_FILES(WEAPONS_SRC_FILES
   MuzzleFlash.cc
+  RocketController.cc
 )
 
@@ -12,6 +13,4 @@
   PCH_FILE
     WeaponsPrecompiledHeaders.h
-  DEFINE_SYMBOL
-    "WEAPONS_SHARED_BUILD"
   LINK_LIBRARIES
     orxonox
Index: code/trunk/src/modules/weapons/RocketController.cc
===================================================================
--- code/trunk/src/modules/weapons/RocketController.cc	(revision 7163)
+++ code/trunk/src/modules/weapons/RocketController.cc	(revision 7163)
@@ -0,0 +1,115 @@
+/*
+*   ORXONOX - the hottest 3D action shooter ever to exist
+*                    > www.orxonox.net <
+*
+*
+*   License notice:
+*
+*   This program is free software; you can redistribute it and/or
+*   modify it under the terms of the GNU General Public License
+*   as published by the Free Software Foundation; either version 2
+*   of the License, or (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*   along with this program; if not, write to the Free Software
+*   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*
+*   Author:
+*     Gabriel Nadler, Originalfile: Oli Scheuss
+*   Co-authors:
+*      ...
+*
+*/
+
+#include "RocketController.h"
+#include "projectiles/SimpleRocket.h"
+#include "util/Math.h"
+#include "weapons/projectiles/SimpleRocket.h"
+#include "util/Debug.h"
+#include "weapons/weaponmodes/SimpleRocketFire.h"
+#include "worldentities/pawns/Pawn.h"
+
+namespace orxonox
+{
+    /**
+    @brief
+    Constructor.
+    */
+    RocketController::RocketController(BaseObject* creator) : Controller(creator)
+    {
+        RegisterObject(RocketController);
+        COUT(5)<< "RocketController constructed\n";
+
+
+        this->rocket_ = new SimpleRocket(this);
+        this->rocket_->setController(this);
+        this->setControllableEntity(dynamic_cast<ControllableEntity*> (this->rocket_));
+    }
+
+
+    /**
+    @brief
+    The controlling happens here. This method defines what the controller has to do each tick.
+    @param dt
+    The duration of the tick.
+    */
+    void RocketController::tick(float dt)
+    {
+
+        if (this->target_ && this->rocket_->hasFuel()) {
+            this->setTargetPosition();
+            this->moveToTargetPosition();
+        }
+
+
+    }
+
+
+    RocketController::~RocketController()
+    {
+        COUT(5)<< "RocketController destroyed\n";
+    }
+
+    void RocketController::setTargetPosition()
+    {
+        this->targetPosition_=this->target_->getWorldPosition(); //don't really note a difference in the rocket behaviour xD
+        //this->targetPosition_ = getPredictedPosition(this->getControllableEntity()->getWorldPosition(),this->getControllableEntity()->getVelocity().length() , this->target_->getWorldPosition(), this->target_->getVelocity());
+    }
+    void RocketController::moveToTargetPosition()
+    {
+        this->moveToPosition(this->targetPosition_);
+    }
+
+
+
+    void RocketController::setTarget(WorldEntity* target)
+    {
+        this->target_ = target;
+    }
+
+    void RocketController::moveToPosition(const Vector3& target)
+    {
+        if (!this->getControllableEntity())
+            return;
+
+        Vector2 coord = get2DViewdirection(this->rocket_->getPosition(), this->rocket_->getOrientation() * WorldEntity::FRONT, this->rocket_->getOrientation() * WorldEntity::UP, target);
+        float distance = (target - this->rocket_->getWorldPosition()).length();
+
+
+        if (distance > 1000 && this->rocket_->getVelocity().squaredLength()<160000)
+            this->rocket_->setAcceleration(this->rocket_->getOrientation()*Vector3(-20,-20,-20));
+        if (distance <1000) this->rocket_->setAcceleration(0,0,0);
+
+        this->rocket_->rotateYaw(-sgn(coord.x)*coord.x*coord.x);
+        this->rocket_->rotatePitch(sgn(coord.y)*coord.y*coord.y);
+    }
+
+
+
+
+}
Index: code/trunk/src/modules/weapons/RocketController.h
===================================================================
--- code/trunk/src/modules/weapons/RocketController.h	(revision 7163)
+++ code/trunk/src/modules/weapons/RocketController.h	(revision 7163)
@@ -0,0 +1,73 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Gabriel Nadler, Originalfile: Oli Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _RocketController_H__
+#define _RocketController_H__
+
+#include "weapons/WeaponsPrereqs.h"
+
+#include "controllers/Controller.h"
+#include "tools/interfaces/Tickable.h"
+#include "weapons/projectiles/SimpleRocket.h"
+#include "weapons/weaponmodes/SimpleRocketFire.h"
+
+namespace orxonox
+{
+    /**
+    @brief
+        Controller for the Rocket (targetseeking)
+    @author
+        Gabriel Nadler, Originalfile: Oli Scheuss
+    */
+    class _WeaponsExport RocketController : public Controller, public Tickable
+    {
+        public:
+            RocketController(BaseObject* creator);
+            virtual ~RocketController();
+
+            virtual void tick(float dt);
+            SimpleRocket* getRocket() const
+             {  return this->rocket_;  };
+            void setTarget(WorldEntity* target);
+        protected:
+            void moveToPosition(const Vector3& target);
+            void setTargetPosition();
+            void moveToTargetPosition();
+
+        private:
+            SimpleRocket* rocket_; //!<The Rocket it controlls
+            Vector3 targetPosition_;
+            WeakPtr<PlayerInfo> player_;
+
+            WeakPtr<WorldEntity> target_;
+
+
+    };
+}
+
+#endif /* _RocketController_H__ */
Index: code/trunk/src/modules/weapons/WeaponsPrereqs.h
===================================================================
--- code/trunk/src/modules/weapons/WeaponsPrereqs.h	(revision 6906)
+++ code/trunk/src/modules/weapons/WeaponsPrereqs.h	(revision 7163)
@@ -43,5 +43,5 @@
 //-----------------------------------------------------------------------
 
-#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(ORXONOX_STATIC_BUILD)
+#if defined(ORXONOX_PLATFORM_WINDOWS) && !defined(WEAPONS_STATIC_BUILD)
 #  ifdef WEAPONS_SHARED_BUILD
 #    define _WeaponsExport __declspec(dllexport)
Index: code/trunk/src/modules/weapons/projectiles/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/weapons/projectiles/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/weapons/projectiles/CMakeLists.txt	(revision 7163)
@@ -5,3 +5,4 @@
   LightningGunProjectile.cc
   Rocket.cc
+  SimpleRocket.cc
 )
Index: code/trunk/src/modules/weapons/projectiles/Rocket.cc
===================================================================
--- code/trunk/src/modules/weapons/projectiles/Rocket.cc	(revision 6906)
+++ code/trunk/src/modules/weapons/projectiles/Rocket.cc	(revision 7163)
@@ -41,4 +41,5 @@
 #include "controllers/Controller.h"
 #include "sound/WorldSound.h"
+#include "Scene.h"
 
 namespace orxonox
@@ -87,4 +88,5 @@
             this->defSndWpnEngine_->setLooping(true);
             this->defSndWpnEngine_->setSource("sounds/Rocket_engine.ogg");
+            this->defSndWpnEngine_->setVolume(100);
             this->attach(defSndWpnEngine_);
 
@@ -92,4 +94,5 @@
             this->defSndWpnLaunch_->setLooping(false);
             this->defSndWpnLaunch_->setSource("sounds/Rocket_launch.ogg");
+            this->defSndWpnLaunch_->setVolume(100);
             this->attach(defSndWpnLaunch_);
         }
@@ -114,6 +117,11 @@
         if(this->isInitialized())
         {
-            if (GameMode::isMaster() && this->player_)
-                this->player_->stopTemporaryControl();
+            if (GameMode::isMaster())
+            {
+                this->destructionEffect();
+
+                if (this->getPlayer() && this->getController())
+                    this->player_->stopTemporaryControl();
+            }
 
             if ( this->defSndWpnEngine_ )
@@ -138,5 +146,4 @@
     {
         this->owner_ = owner;
-        this->originalControllableEntity_ = this->owner_->getPlayer()->getControllableEntity();
         this->player_ = this->owner_->getPlayer();
         this->owner_->getPlayer()->startTemporaryControl(this);
@@ -164,7 +171,11 @@
             this->setVelocity( this->getOrientation()*WorldEntity::FRONT*this->getVelocity().length() );
             this->localAngularVelocity_ = 0;
-
+        }
+
+        if( GameMode::isMaster() )
+        {
             if( this->bDestroy_ )
                 this->destroy();
+
         }
     }
@@ -222,25 +233,35 @@
     void Rocket::fired(unsigned int firemode)
     {
-        if (this->owner_)
-        {
-            {
-                ParticleSpawner* effect = new ParticleSpawner(this->owner_->getCreator());
-                effect->setPosition(this->getPosition());
-                effect->setOrientation(this->getOrientation());
-                effect->setDestroyAfterLife(true);
-                effect->setSource("Orxonox/explosion4");
-                effect->setLifetime(2.0f);
-            }
-
-            {
-                ParticleSpawner* effect = new ParticleSpawner(this->owner_->getCreator());
-                effect->setPosition(this->getPosition());
-                effect->setOrientation(this->getOrientation());
-                effect->setDestroyAfterLife(true);
-                effect->setSource("Orxonox/smoke4");
-                effect->setLifetime(3.0f);
-            }
+//         if (this->owner_)
+//         {
             this->destroy();
-        }
+//         }
+    }
+    
+    void Rocket::destructionEffect()
+    {
+        ParticleSpawner *effect1, *effect2;
+        if( this->owner_ )
+        {
+            effect1 = new ParticleSpawner(this->owner_->getCreator());
+            effect2 = new ParticleSpawner(this->owner_->getCreator());
+        }
+        else
+        {
+            effect1 = new ParticleSpawner(static_cast<BaseObject*>(this->getScene().get()));
+            effect2 = new ParticleSpawner(static_cast<BaseObject*>(this->getScene().get()));
+        }
+        
+        effect1->setPosition(this->getPosition());
+        effect1->setOrientation(this->getOrientation());
+        effect1->setDestroyAfterLife(true);
+        effect1->setSource("Orxonox/explosion4");
+        effect1->setLifetime(2.0f);
+        
+        effect2->setPosition(this->getPosition());
+        effect2->setOrientation(this->getOrientation());
+        effect2->setDestroyAfterLife(true);
+        effect2->setSource("Orxonox/smoke4");
+        effect2->setLifetime(3.0f);
     }
 
Index: code/trunk/src/modules/weapons/projectiles/Rocket.h
===================================================================
--- code/trunk/src/modules/weapons/projectiles/Rocket.h	(revision 6906)
+++ code/trunk/src/modules/weapons/projectiles/Rocket.h	(revision 7163)
@@ -57,4 +57,5 @@
             virtual bool collidesAgainst(WorldEntity* otherObject, btManifoldPoint& contactPoint);
             void destroyObject();
+            void destructionEffect();
 
             virtual void moveFrontBack(const Vector2& value){}
@@ -119,5 +120,4 @@
             float damage_;
             bool bDestroy_;
-            ControllableEntity* originalControllableEntity_;
 
             WeakPtr<PlayerInfo> player_;
Index: code/trunk/src/modules/weapons/projectiles/SimpleRocket.cc
===================================================================
--- code/trunk/src/modules/weapons/projectiles/SimpleRocket.cc	(revision 7163)
+++ code/trunk/src/modules/weapons/projectiles/SimpleRocket.cc	(revision 7163)
@@ -0,0 +1,258 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oliver Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "SimpleRocket.h"
+
+#include <BulletDynamics/Dynamics/btRigidBody.h>
+
+#include "core/CoreIncludes.h"
+#include "core/XMLPort.h"
+#include "worldentities/pawns/Pawn.h"
+#include "graphics/ParticleSpawner.h"
+#include "graphics/Model.h"
+#include "objects/collisionshapes/ConeCollisionShape.h"
+#include "infos/PlayerInfo.h"
+#include "controllers/Controller.h"
+#include "weapons/RocketController.h"
+#include "sound/WorldSound.h"
+#include "util/Debug.h"
+
+namespace orxonox
+{
+
+    CreateFactory(SimpleRocket);
+
+    SimpleRocket::SimpleRocket(BaseObject* creator) : ControllableEntity(creator)
+    {
+        RegisterObject(SimpleRocket);// - register the SimpleRocket class to the core
+
+        this->localAngularVelocity_ = 0;
+        this->bDestroy_ = false;
+        this->lifetime_ = 120;
+
+        this->setMass(15);
+        COUT(4) << "simplerocket constructed\n";
+
+        if (GameMode::isMaster())
+        {
+            this->setCollisionType(WorldEntity::Kinematic);
+            this->fuel_=true;
+
+            Model* model = new Model(this);
+            model->setMeshSource("rocket.mesh");
+            model->scale(0.7f);
+            this->attach(model);
+
+            this->fire_ = new ParticleEmitter(this);
+            this->attach(this->fire_);
+
+            this->fire_->setOrientation(this->getOrientation());
+            this->fire_->setSource("Orxonox/simplerocketfire");
+            this->enableCollisionCallback();
+            this->setCollisionResponse(false);
+            this->setCollisionType(Kinematic);
+
+            // TODO: fix the orientation and size of this collision shape to match the rocket
+            ConeCollisionShape* collisionShape = new ConeCollisionShape(this);
+            collisionShape->setOrientation(this->getOrientation());
+            collisionShape->setRadius(1.5f);
+            collisionShape->setHeight(5);
+            this->attachCollisionShape(collisionShape);
+            this->destroyTimer_.setTimer(this->lifetime_, false, createExecutor(createFunctor(&SimpleRocket::destroyObject, this)));
+        }
+
+    }
+
+
+
+    /**
+    * @brief updates state of rocket, disables fire if no fuel
+    * @param dt tick-length
+    */
+    void SimpleRocket::tick(float dt)
+    {
+
+        SUPER(SimpleRocket, tick, dt);
+        if ( GameMode::isMaster() )
+        {
+
+
+            this->setAngularVelocity(this->getOrientation() * this->localAngularVelocity_);
+            this->setVelocity( this->getOrientation()*WorldEntity::FRONT*this->getVelocity().length() );
+            this->localAngularVelocity_ = 0;
+
+
+            if (this->fuel_)
+            {
+                if (this->destroyTimer_.getRemainingTime()<  (static_cast<float>(this->FUEL_PERCENTAGE)/100) *this->lifetime_ )
+                    this->fuel_=false;
+            } else
+                this->disableFire();
+
+            if( this->bDestroy_ )
+                this->destroy();
+        }
+
+    }
+
+    /**
+    * @brief Sets the Acceleration to 0 and detaches the fire
+    * @return void
+    */
+    void SimpleRocket::disableFire()
+    {
+        this->setAcceleration(0,0,0);
+        this->fire_->detachFromParent();
+    }
+
+    /**s
+    @brief
+        Destructor. Destroys controller, if present and kills sounds, if playing.
+    */
+    SimpleRocket::~SimpleRocket()
+    {
+        if (this->isInitialized())
+        {
+            if( GameMode::isMaster() )
+            {
+                this->getController()->destroy();
+            }
+        }
+    }
+
+    /**
+    @brief
+        Method for creating a SimpleRocket through XML.
+    */
+    void SimpleRocket::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        // this calls the XMLPort function of the parent class
+        SUPER(SimpleRocket, XMLPort, xmlelement, mode);
+    }
+
+    void SimpleRocket::setOwner(Pawn* owner)
+    {
+        this->owner_ = owner;
+        this->player_ = this->owner_->getPlayer();
+    }
+
+
+
+
+    bool SimpleRocket::collidesAgainst(WorldEntity* otherObject, btManifoldPoint& contactPoint)
+    {
+        if (!this->bDestroy_ && GameMode::isMaster())
+        {
+            if (otherObject == this->owner_)
+                return false;
+
+            this->bDestroy_ = true;
+
+            if (this->owner_)
+            {
+                {
+                    ParticleSpawner* effect = new ParticleSpawner(this->owner_->getCreator());
+                    effect->setPosition(this->getPosition());
+                    effect->setOrientation(this->getOrientation());
+                    effect->setDestroyAfterLife(true);
+                    effect->setSource("Orxonox/explosion4");
+                    effect->setLifetime(2.0f);
+                }
+
+                {
+                    ParticleSpawner* effect = new ParticleSpawner(this->owner_->getCreator());
+                    effect->setPosition(this->getPosition());
+                    effect->setOrientation(this->getOrientation());
+                    effect->setDestroyAfterLife(true);
+                    effect->setSource("Orxonox/smoke4");
+                    effect->setLifetime(3.0f);
+                }
+            }
+
+            float dmg = this->damage_;
+//             if (this->owner_)
+//                 dmg = this->owner_->getPickups().processModifiers(ModifierType::Damage, dmg, false);
+
+            Pawn* victim = orxonox_cast<Pawn*>(otherObject);
+            if (victim)
+                victim->hit(this->owner_, contactPoint, dmg);
+        }
+        return false;
+    }
+
+    void SimpleRocket::destroyObject()
+    {
+        if (GameMode::isMaster())
+        {
+            this->destroy();
+        }
+    }
+
+    /**
+    @brief
+        Rotates the SimpleRocket around the y-axis by the amount specified by the first component of the input 2-dim vector.
+    @param value
+        The vector determining the amount of the angular movement.
+    */
+    void SimpleRocket::rotateYaw(const Vector2& value)
+    {
+        ControllableEntity::rotateYaw(value);
+
+        if( !this->isInMouseLook() )
+            this->localAngularVelocity_.y += value.x;
+    }
+
+    /**
+    @brief
+        Rotates the SimpleRocket around the x-axis by the amount specified by the first component of the input 2-dim vector.
+    @param value
+        The vector determining the amount of the angular movement.
+    */
+    void SimpleRocket::rotatePitch(const Vector2& value)
+    {
+        ControllableEntity::rotatePitch(value);
+
+        if( !this->isInMouseLook() )
+            this->localAngularVelocity_.x += value.x;
+    }
+
+    /**
+    @brief
+        Rotates the SimpleRocket around the z-axis by the amount specified by the first component of the input 2-dim vector.
+    @param value
+        The vector determining the amount of the angular movement.
+    */
+    void SimpleRocket::rotateRoll(const Vector2& value)
+    {
+        ControllableEntity::rotateRoll(value);
+
+        if( !this->isInMouseLook() )
+            this->localAngularVelocity_.z += value.x;
+    }
+
+}
Index: code/trunk/src/modules/weapons/projectiles/SimpleRocket.h
===================================================================
--- code/trunk/src/modules/weapons/projectiles/SimpleRocket.h	(revision 7163)
+++ code/trunk/src/modules/weapons/projectiles/SimpleRocket.h	(revision 7163)
@@ -0,0 +1,143 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oliver Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _SimpleRocket_H__
+#define _SimpleRocket_H__
+
+#include "weapons/WeaponsPrereqs.h"
+
+#include "tools/Timer.h"
+#include "worldentities/ControllableEntity.h"
+#include "graphics/ParticleSpawner.h"
+
+namespace orxonox
+{
+    class ConeCollisionShape;
+
+    /**
+    @brief
+        SimpleRocket, follows direction from a Rocketcontroller, has fuel for 80% of its lifetime, afterwards it's fire disappears.
+    @author
+       Gabriel Nadler (Original file: Oli Scheuss)
+    */
+    class _WeaponsExport SimpleRocket : public ControllableEntity
+    {
+        public:
+            SimpleRocket(BaseObject* creator);
+            virtual ~SimpleRocket();
+            virtual void tick(float dt);
+            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); //!< Method for creating a SimpleRocket through XML.
+
+            virtual bool collidesAgainst(WorldEntity* otherObject, btManifoldPoint& contactPoint);
+            void destroyObject();
+
+            void disableFire(); //!< Method to disable the fire and stop all acceleration
+
+            virtual void moveFrontBack(const Vector2& value){}
+            virtual void moveRightLeft(const Vector2& value){}
+            virtual void moveUpDown(const Vector2& value){}
+
+            virtual void rotateYaw(const Vector2& value);
+            virtual void rotatePitch(const Vector2& value);
+            virtual void rotateRoll(const Vector2& value);
+            void setDestroy();
+
+            /**
+            @brief Moves the SimpleRocket in the Front/Back-direction by the specifed amount.
+            @param value  The amount by which the SimpleRocket is to be moved.
+            */
+            inline void moveFrontBack(float value)
+            { this->moveFrontBack(Vector2(value, 0)); }
+            /**
+            @brief Moves the SimpleRocket in the Right/Left-direction by the specifed amount.
+            @param value  The amount by which the SimpleRocket is to be moved.
+            */
+            inline void moveRightLeft(float value)
+            { this->moveRightLeft(Vector2(value, 0)); }
+            /**
+            @brief Moves the SimpleRocket in the Up/Down-direction by the specifed amount.
+            @param value  The amount by which the SimpleRocket is to be moved.
+            */
+            inline void moveUpDown(float value)
+            { this->moveUpDown(Vector2(value, 0)); }
+
+            /**
+            @brief Rotates the SimpleRocket around the y-axis by the specifed amount.
+            @param value  The amount by which the SimpleRocket is to be rotated.
+            */
+            inline void rotateYaw(float value)
+            { this->rotateYaw(Vector2(value, 0)); }
+            /**
+            @brief Rotates the SimpleRocket around the x-axis by the specifed amount.
+            @param value  The amount by which the SimpleRocket is to be rotated.
+            */
+            inline void rotatePitch(float value)
+            {
+                this->rotatePitch(Vector2(value, 0)); }
+            /**
+            @brief Rotates the SimpleRocket around the z-axis by the specifed amount.
+            @param value  The amount by which the SimpleRocket is to be rotated.
+            */
+            inline void rotateRoll(float value)
+            {
+                this->rotateRoll(Vector2(value, 0)); }
+
+            void setOwner(Pawn* owner);
+            inline Pawn* getOwner() const
+                { return this->owner_; }
+            inline bool hasFuel() const
+            { return this->fuel_; }
+
+            inline void setDamage(float damage)
+                { this->damage_ = damage; }
+            inline float getDamage() const
+                { return this->damage_; }
+
+
+        private:
+            WeakPtr<Pawn> owner_;
+            Vector3 localAngularVelocity_;
+            float damage_;
+            bool bDestroy_;
+            bool fuel_; //!< Bool is true while the rocket "has fuel"
+
+
+            WeakPtr<PlayerInfo> player_;
+            Timer destroyTimer_;
+            float lifetime_;
+            static const int FUEL_PERCENTAGE=80; //!<Percentage of Lifetime the rocket has fuel
+
+            ParticleEmitter* fire_; //!< Fire-Emittor
+
+
+
+    };
+
+}
+
+#endif /* _SimpleRocket_H__ */
Index: code/trunk/src/modules/weapons/weaponmodes/CMakeLists.txt
===================================================================
--- code/trunk/src/modules/weapons/weaponmodes/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/modules/weapons/weaponmodes/CMakeLists.txt	(revision 7163)
@@ -6,3 +6,4 @@
   LightningGun.cc
   RocketFire.cc
+  SimpleRocketFire.cc
 )
Index: code/trunk/src/modules/weapons/weaponmodes/SimpleRocketFire.cc
===================================================================
--- code/trunk/src/modules/weapons/weaponmodes/SimpleRocketFire.cc	(revision 7163)
+++ code/trunk/src/modules/weapons/weaponmodes/SimpleRocketFire.cc	(revision 7163)
@@ -0,0 +1,77 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oliver Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "SimpleRocketFire.h"
+
+#include "util/Math.h"
+#include "core/CoreIncludes.h"
+#include "weapons/RocketController.h"
+
+#include "weaponsystem/Weapon.h"
+#include "weaponsystem/WeaponPack.h"
+#include "weaponsystem/WeaponSystem.h"
+#include "worldentities/pawns/Pawn.h"
+#include "sound/WorldSound.h"
+
+namespace orxonox
+{
+
+    CreateFactory(SimpleRocketFire);
+
+    SimpleRocketFire::SimpleRocketFire(BaseObject* creator) : WeaponMode(creator)
+    {
+        RegisterObject(SimpleRocketFire);
+
+        this->reloadTime_ = 1;
+        this->bParallelReload_ = false;
+        this->damage_ = 100;
+        this->speed_ = 500;
+
+            this->setMunitionName("TargetSeeking Rockets");
+            this->setDefaultSoundWithVolume("sounds/Rocket_launch.ogg",0.4);
+        // The firing sound of the Rocket is played in Rocket.cc (because of OpenAl sound positioning)
+    }
+
+    SimpleRocketFire::~SimpleRocketFire()
+    {
+    }
+
+    void SimpleRocketFire::fire()
+    {
+        RocketController* con = new RocketController(this);
+        SimpleRocket* rocket = con->getRocket();
+        this->computeMuzzleParameters(this->getWeapon()->getWeaponPack()->getWeaponSystem()->getPawn()->getAimPosition());
+        rocket->setOrientation(this->getWeapon()->getWeaponPack()->getWeaponSystem()->getPawn()->getWorldOrientation());
+        rocket->setPosition(this->getMuzzlePosition());
+        rocket->setVelocity(this->getMuzzleDirection()*this->speed_);
+        rocket->setOwner(this->getWeapon()->getWeaponPack()->getWeaponSystem()->getPawn());
+        rocket->setDamage(this->damage_);
+        WorldEntity* pawnn=static_cast<ControllableEntity*>(this->getWeapon()->getWeaponPack()->getWeaponSystem()->getPawn())->getTarget();
+        if (pawnn) con->setTarget(pawnn);
+    }
+}
Index: code/trunk/src/modules/weapons/weaponmodes/SimpleRocketFire.h
===================================================================
--- code/trunk/src/modules/weapons/weaponmodes/SimpleRocketFire.h	(revision 7163)
+++ code/trunk/src/modules/weapons/weaponmodes/SimpleRocketFire.h	(revision 7163)
@@ -0,0 +1,57 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oliver Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _SimpleRocketFire_H__
+#define _SimpleRocketFire_H__
+
+#include "weapons/WeaponsPrereqs.h"
+#include "weaponsystem/WeaponMode.h"
+
+namespace orxonox
+{
+    /**
+    @brief
+        FireMode for target-seeking Rocket
+    @author
+        Gabriel Nadler (Original file: Oli Scheuss)
+    */
+    class _WeaponsExport SimpleRocketFire : public WeaponMode
+    {
+        public:
+            SimpleRocketFire(BaseObject* creator);
+            virtual ~SimpleRocketFire();
+            void deactivateFire();
+            virtual void fire();
+
+        private:
+            float speed_;
+
+    };
+}
+
+#endif /* _SimpleRocketFire_H__ */
Index: code/trunk/src/orxonox/CMakeLists.txt
===================================================================
--- code/trunk/src/orxonox/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/orxonox/CMakeLists.txt	(revision 7163)
@@ -32,4 +32,7 @@
   PlayerManager.cc
   Radar.cc
+  ChatHistory.cc
+  ChatInputHandler.cc
+#  Test.cc
 COMPILATION_BEGIN SceneCompilation.cc
   CameraManager.cc
@@ -55,11 +58,11 @@
   FIND_HEADER_FILES
   TOLUA_FILES
+    ChatInputHandler.h
     LevelManager.h
     MoodManager.h
     controllers/HumanController.h
-    interfaces/PickupCarrier.h
+    interfaces/Pickupable.h
+    infos/PlayerInfo.h
     sound/SoundManager.h
-  DEFINE_SYMBOL
-    "ORXONOX_SHARED_BUILD"
   PCH_FILE
     OrxonoxPrecompiledHeaders.h
@@ -75,6 +78,6 @@
     ${VORBIS_LIBRARY}
     ${OGG_LIBRARY}
-    tinyxml++_orxonox
-    tolua++_orxonox
+    tinyxml_orxonox
+    tolua_orxonox
     bullet_orxonox
     util
Index: code/trunk/src/orxonox/ChatHistory.cc
===================================================================
--- code/trunk/src/orxonox/ChatHistory.cc	(revision 7163)
+++ code/trunk/src/orxonox/ChatHistory.cc	(revision 7163)
@@ -0,0 +1,195 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Sandro 'smerkli' Merkli
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "ChatHistory.h"
+#include <core/ScopedSingletonManager.h>
+
+#ifndef CHATTEST
+namespace orxonox
+{
+  /* singleton */
+  ManageScopedSingleton( ChatHistory, ScopeID::Root, false );
+#endif
+
+  /* constructor */
+#ifndef CHATTEST
+  //ChatHistory::ChatHistory( BaseObject* creator ) : BaseObject(creator)
+  ChatHistory::ChatHistory()
+#else
+  ChatHistory::ChatHistory()
+#endif
+  {
+    /* register the object */
+#ifndef CHATTEST
+    RegisterObject(ChatHistory);
+#endif
+
+    this->hist_log_enabled = true;
+
+    /* Read setting for logfiles */
+    if( hist_log_enabled ) /* NOTE Make this a check for the logfile setting */
+    { this->chat_hist_openlog();
+
+      /* push starting line */
+      this->chat_hist_logline( "--- Logfile opened ---" );
+    }
+
+    /* Read setting for maximum number of lines and set limit */
+    this->hist_maxlines = 200; /* NOTE to be changed, 200 is just for testing */
+  }
+
+  /* destructor */
+  ChatHistory::~ChatHistory()
+  {
+    chat_hist_closelog();
+
+    /* clear list */
+    this->hist_buffer.clear();
+  }
+
+  /* react to incoming chat */
+  void ChatHistory::incomingChat(const std::string& message,
+    unsigned int senderID)
+  {
+    /* --> a) look up the actual name of the sender */
+    std::string text;
+
+#ifndef CHATTEST
+    /* get sender ID and prepend it to the message */
+    if (senderID != CLIENTID_UNKNOWN)
+    {
+      /* if we can't find anything, use "unknown" as default */
+      std::string name = "unknown";
+
+      PlayerInfo* player = PlayerManager::getInstance().getClient(senderID);
+      if (player)
+        name = player->getName();
+
+      text = name + ": " + message;
+    }
+    else
+      text = message;
+#else
+    text = message;
+#endif
+
+    /* add the line to the history */
+    this->chat_hist_addline( text );
+
+    /* add the line to the log */
+    this->chat_hist_logline( text );
+  }
+
+  /* Synchronize logfile onto the hard drive */ /* MARK MARK */
+  int ChatHistory::syncLog()
+  {
+    //if( this->hist_logfile )
+      //this->hist_logfile.sync();
+    return 0;
+  }
+
+  /* add a line to this history */
+  int ChatHistory::chat_hist_addline( const std::string& toadd )
+  {
+    /* crop history at the end if it's too large */
+    while( this->hist_buffer.size() > this->hist_maxlines+1 )
+      this->hist_buffer.pop_front();
+
+    /* push to the front of the history */
+    this->hist_buffer.push_back( toadd );
+    return 0;
+  }
+
+  /* log a line to a logfile */
+  int ChatHistory::chat_hist_logline( const std::string& toadd )
+  {
+    /* output the line to the file if logging is enabled */
+    if( this->hist_log_enabled )
+      this->hist_logfile << toadd << std::endl;
+    return 0;
+  }
+
+  /* open logfile */
+  int ChatHistory::chat_hist_openlog()
+  {
+    /* TODO: find out the name of the file to log to via settings
+     *       and set the this->hist_logfile_path variable to it
+     */
+#ifndef CHATTEST
+    this->hist_logfile.open( (PathConfig::getInstance().getLogPathString() +
+      "chatlog.log").c_str(),
+      std::fstream::out | std::fstream::app );
+#else
+    this->hist_logfile.open( "/tmp/chatlog.log",
+      std::fstream::out | std::fstream::app );
+#endif
+
+    /* TODO check whether this works (not sure how you'd like it?) */
+    if( !this->hist_logfile )
+    { this->hist_log_enabled = false;
+#ifndef CHATTEST
+      COUT(2) << "Warning: Could not open logfile." << std::endl;
+#endif
+    }
+
+    /* if it worked */
+    return 0;
+  }
+
+  /* close logfile */
+  void ChatHistory::chat_hist_closelog()
+  {
+    /* see if we've actually got a logfile */
+    if( this->hist_logfile )
+    {
+      /* yes, we've got one, add a line that shows we're closing it */
+      this->chat_hist_logline( "--- Logfile closed ---" );
+
+      /* actually close down the file */
+      this->hist_logfile.close();
+    }
+  }
+
+  /* output history for debugging */
+  void ChatHistory::debug_printhist()
+  {
+    /* create deque iterator */
+    std::deque<std::string>::iterator it;
+
+    /* output all the strings */
+    for( it = this->hist_buffer.begin(); it != this->hist_buffer.end();
+      ++it )
+      std::cout << *it << std::endl;
+
+    /* output size */
+    std::cout << "Size: " << hist_buffer.size() << std::endl;
+  }
+
+#ifndef CHATTEST
+}
+#endif
Index: code/trunk/src/orxonox/ChatHistory.h
===================================================================
--- code/trunk/src/orxonox/ChatHistory.h	(revision 7163)
+++ code/trunk/src/orxonox/ChatHistory.h	(revision 7163)
@@ -0,0 +1,149 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Sandro 'smerkli' Merkli
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include <deque>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <cassert>
+
+/* define this if you're unit testing */
+//#define CHATTEST
+
+#ifndef CHATTEST
+#include <OrxonoxPrereqs.h>
+#include <PlayerManager.h>
+#include <infos/PlayerInfo.h>
+#include <core/BaseObject.h>
+#include <network/ChatListener.h>
+#include <core/PathConfig.h>
+#include <util/Singleton.h>
+#endif
+
+#ifndef _ChatHistory_H__
+#define _ChatHistory_H__
+
+
+/* Class to implement chat history */
+#ifndef CHATTEST
+namespace orxonox
+{
+#endif
+
+  /* constructor */
+#ifndef CHATTEST
+  class _OrxonoxExport ChatHistory : public ChatListener,
+    public Singleton<ChatHistory>
+
+#else
+  class ChatHistory
+#endif
+  {
+    public:
+      /* constructors, destructors */
+#ifndef CHATTEST
+      ChatHistory();
+      friend class Singleton<ChatHistory>;
+#else
+      ChatHistory();
+#endif
+      virtual ~ChatHistory();
+
+
+    //protected:
+      /** what to do with incoming chat
+       *
+       * \param message The incoming message
+       * \param senderID Identification number of the sender
+       */
+      virtual void incomingChat(const std::string& message,
+        unsigned int senderID);
+
+      /** Synchronize logfile onto the hard drive
+       *
+       * \return 0 for success, other for error
+       */
+      int syncLog();
+
+      /** debug-print: output the whole history to stdout */
+      void debug_printhist();
+
+    private:
+      /* FIELDS */
+      /** Vector to store the history in */
+      std::deque<std::string> hist_buffer;
+
+      /** Maximum number of lines stored in this history */
+      unsigned int hist_maxlines;
+
+      /** is logging enabled? */
+      bool hist_log_enabled;
+
+      /** path of logfile on the file system */
+      std::string hist_logfile_path;
+
+      /** Output file stream for logfile */
+      std::ofstream hist_logfile;
+
+#ifndef CHATTEST
+      static ChatHistory* singletonPtr_s;
+#endif
+
+
+
+      /* METHODS */
+      /** Append line to chat history
+       *
+       * \param toadd The line to add to the history
+       * \return 0 for success, other for error TODO: Throw exception
+       */
+      int chat_hist_addline( const std::string& toadd );
+
+      /** Append line to logfile
+       *
+       * \param toadd The line to add to the logfile
+       * \return 0 for success, other for error TODO: Throw exception
+       */
+      int chat_hist_logline( const std::string& toadd );
+
+      /** open logfile to log to
+       *
+       * \return 0 for success,s other for error
+       */
+      int chat_hist_openlog();
+
+
+      /** close logfile */
+      void chat_hist_closelog();
+  };
+
+#ifndef CHATTEST
+}
+#endif
+
+#endif /* _ChatHistory_H__ */
Index: code/trunk/src/orxonox/ChatInputHandler.cc
===================================================================
--- code/trunk/src/orxonox/ChatInputHandler.cc	(revision 7163)
+++ code/trunk/src/orxonox/ChatInputHandler.cc	(revision 7163)
@@ -0,0 +1,345 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Sandro 'smerkli' Merkli
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "ChatInputHandler.h"
+#include <core/ScopedSingletonManager.h>
+#include "core/ConsoleCommand.h"
+#include "core/CoreIncludes.h"
+#include "core/GUIManager.h"
+#include "core/CorePrereqs.h"
+#include <CEGUIWindow.h>
+#include <elements/CEGUIListbox.h>
+#include <elements/CEGUIListboxItem.h>
+#include <elements/CEGUIListboxTextItem.h>
+#include <CEGUIWindowManager.h>
+#include <string>
+
+namespace orxonox
+{
+  /* singleton */
+  ManageScopedSingleton( ChatInputHandler, ScopeID::Graphics, false );
+
+  /* add commands to console */
+  SetConsoleCommandAlias( ChatInputHandler, activate_static, "startchat",
+    true );
+  SetConsoleCommandAlias( ChatInputHandler, activate_small_static,
+    "startchat_small", true );
+
+  /* constructor */
+  ChatInputHandler::ChatInputHandler()
+  {
+    /* register the object  */
+    RegisterObject(ChatInputHandler);
+
+    /* create necessary objects */
+    this->inpbuf = new InputBuffer();
+    this->disp_offset = 0;
+    assert( this->inpbuf != NULL );
+
+    /* generate chatbox ui and chatbox-inputonly ui */
+    GUIManager::getInstance().loadGUI( "ChatBox" );
+    GUIManager::getInstance().loadGUI( "ChatBox-inputonly" );
+
+    /* setup colors */
+    setupColors();
+
+    /* configure the input buffer */
+    configureInputBuffer();
+
+    this->inputState = InputManager::getInstance().createInputState( "chatinput", false, false, InputStatePriority::Dynamic );
+    this->inputState->setKeyHandler(this->inpbuf);
+  }
+
+  /* configure input buffer, sub for the constructor */
+  void ChatInputHandler::configureInputBuffer()
+  {
+    /* INSTALL CALLBACKS */
+    /* input has changed */
+    this->inpbuf->registerListener(this, &ChatInputHandler::inputChanged, true);
+
+    /* add a line */
+    this->inpbuf->registerListener(this, &ChatInputHandler::addline,         '\r',   false);
+    this->inpbuf->registerListener(this, &ChatInputHandler::addline,         '\n',   false);
+
+    /* backspace */
+    this->inpbuf->registerListener(this, &ChatInputHandler::backspace,       '\b',   true);
+    //this->inpbuf->registerListener(this, &ChatInputHandler::backspace,       '\177', true);
+
+    /* exit the chatinputhandler thingy (tbd) */
+    this->inpbuf->registerListener(this, &ChatInputHandler::exit,            '\033', true); // escape
+
+    /* delete character */
+    this->inpbuf->registerListener(this, &ChatInputHandler::deleteChar,      KeyCode::Delete);
+
+    /* cursor movement */
+    this->inpbuf->registerListener(this, &ChatInputHandler::cursorRight,     KeyCode::Right);
+    this->inpbuf->registerListener(this, &ChatInputHandler::cursorLeft,      KeyCode::Left);
+    this->inpbuf->registerListener(this, &ChatInputHandler::cursorEnd,       KeyCode::End);
+    this->inpbuf->registerListener(this, &ChatInputHandler::cursorHome,      KeyCode::Home);
+
+    /* GET WINDOW POINTERS */
+    input = CEGUI::WindowManager::getSingleton().getWindow( "orxonox/ChatBox/input" );
+    inputonly = CEGUI::WindowManager::getSingleton().getWindow( "orxonox/ChatBox-inputonly/input" );
+
+    /* get pointer to the history window */
+    CEGUI::Window *history = CEGUI::WindowManager::getSingleton().getWindow( "orxonox/ChatBox/history" );
+
+    /* cast it to a listbox */
+    lb_history = dynamic_cast<CEGUI::Listbox*>(history);
+
+    /* assert wee */
+    assert( lb_history );
+  }
+
+  /* setup the colors, sub for the constructor */
+  void ChatInputHandler::setupColors()
+  {
+    /* auto variables */
+    float red = 1.0, green = 0.5, blue = 0.5;
+    int i = 0;
+
+    // three loops: red tones, blue tones and green tones
+    // reds
+    for( i = 0; i < NumberOfColors/3; ++i )
+    { this->text_colors[ i ] = new CEGUI::colour( red, green, blue );
+      assert( this->text_colors[ i ] );
+      green += 0.2, blue += 0.2;
+    }
+
+    // greens
+    red = 0.5, green = 1, blue = 0.5;
+    for( ; i < NumberOfColors*2/3; ++i )
+    { this->text_colors[ i ] = new CEGUI::colour( red, green, blue );
+      assert( this->text_colors[ i ] );
+      red += 0.2, blue += 0.2;
+    }
+
+    // blues
+    red = 0.5, green = 0.5, blue = 1;
+    for( ; i < NumberOfColors; ++i )
+    { this->text_colors[ i ] = new CEGUI::colour( red, green, blue );
+      assert( this->text_colors[ i ] );
+      red += 0.2, green += 0.2;
+    }
+  }
+
+
+  /* activate, deactivate */
+  void ChatInputHandler::activate_static()
+  { ChatInputHandler::getInstance().activate( true ); }
+
+  void ChatInputHandler::activate_small_static()
+  { ChatInputHandler::getInstance().activate( false ); }
+
+  void ChatInputHandler::activate( bool full )
+  {
+    /* start listening */
+    InputManager::getInstance().enterState("chatinput");
+
+    /* MARK add spawning of chat widget stuff here.*/
+    if( full )
+      GUIManager::getInstance().showGUI( "ChatBox" );
+    else
+      GUIManager::getInstance().showGUI( "ChatBox-inputonly" );
+
+    this->fullchat = full;
+  }
+
+  void ChatInputHandler::deactivate()
+  {
+    /* stop listening */
+    InputManager::getInstance().leaveState("chatinput");
+
+    /* un-spawning of chat widget stuff */
+    GUIManager::getInstance().hideGUI( "ChatBox" );
+    GUIManager::getInstance().hideGUI( "ChatBox-inputonly" );
+  }
+
+
+  /* subs for incomingChat */
+  void ChatInputHandler::sub_setcolor( CEGUI::ListboxTextItem *tocolor,
+    std::string name )
+  {
+    /* sanity checks */
+    if( !tocolor )
+      COUT(2) << "Empty ListBoxTextItem given to "
+        "ChatInputhandler::sub_setcolor().\n";
+
+    /* "hash" the name */
+    int hash = 0;
+    for( int i = name.length(); i > 0; --i )
+      hash += name[i-1];
+    hash = hash % this->NumberOfColors;
+
+    /* set the color according to the hash */
+    tocolor->setTextColours( *(this->text_colors[ hash ]) );
+  }
+
+  /* handle incoming chat */
+  void ChatInputHandler::incomingChat(const std::string& message,
+    unsigned int senderID)
+  {
+    /* look up the actual name of the sender */
+    std::string text, name = "unknown";
+
+    /* setup player name info */
+    if (senderID != CLIENTID_UNKNOWN)
+    {
+       PlayerInfo* player = PlayerManager::getInstance().getClient(senderID);
+       if (player)
+         name = player->getName();
+    }
+
+    /* assemble the text */
+    text = name + ": " + message;
+
+    /* create item */
+    CEGUI::ListboxTextItem *toadd = new CEGUI::ListboxTextItem( text );
+
+    /* setup colors */
+    sub_setcolor( toadd, name );
+
+    /* now add */
+    this->lb_history->addItem( dynamic_cast<CEGUI::ListboxItem*>(toadd) );
+    this->lb_history->ensureItemIsVisible(
+      dynamic_cast<CEGUI::ListboxItem*>(toadd) );
+
+    /* make sure the history handles it */
+    this->lb_history->handleUpdatedItemData();
+  }
+
+
+  /* sub for inputchanged */
+  void ChatInputHandler::sub_adjust_dispoffset( int maxlen,
+    int cursorpos,
+    int inplen )
+  {
+    /* already start offsetting 5 characters before end */
+    if( cursorpos+5 > maxlen )
+    {
+      /* always stay 5 characters ahead of end, looks better */
+      ((disp_offset = cursorpos-maxlen+5) >= 0) ? 1 : disp_offset = 0;
+
+      /* enforce visibility of cursor */
+      (disp_offset > cursorpos ) ? disp_offset = 0 : 1;
+    }
+
+    /* make sure we don't die at substr */
+    if( inplen <= disp_offset ) disp_offset = 0;
+  }
+
+  /* callbacks for InputBuffer */
+  void ChatInputHandler::inputChanged()
+  {
+    /* update the cursor and the window */
+    std::string raw = this->inpbuf->get();
+    int cursorpos = this->inpbuf->getCursorPosition();
+
+    /* get string before cursor */
+    std::string left = raw.substr( 0, cursorpos );
+
+    /* see if there's a string after the cursor */
+    std::string right = "";
+    if( raw.length() >= left.length()+1 )
+      right = raw.substr( cursorpos );
+
+    /* set the text */
+    std::string assembled = "$ " + left + "|" + right;
+
+    if( this->fullchat )
+    {
+      /* adjust curser position - magic number 5 for font width */
+      sub_adjust_dispoffset( (this->input->getUnclippedInnerRect().getWidth()/6),
+        cursorpos, assembled.length() );
+      this->input->setProperty( "Text", assembled.substr( disp_offset ) );
+    }
+    else
+    {
+      /* adjust curser position - magic number 5 for font width */
+      sub_adjust_dispoffset( (this->inputonly->getUnclippedInnerRect().getWidth()/6),
+        cursorpos, assembled.length() );
+      this->inputonly->setProperty( "Text", assembled.substr( disp_offset) );
+    }
+
+    /* reset display offset */
+    disp_offset = 0;
+  }
+
+  void ChatInputHandler::addline()
+  {
+    /* actually do send what was input */
+    /* a) get the string out of the inputbuffer */
+    std::string msgtosend = this->inpbuf->get();
+
+    if( msgtosend.length() == 0 )
+    { this->deactivate();
+      return;
+    }
+
+    /* b) clear the input buffer */
+    if (this->inpbuf->getSize() > 0)
+      this->inpbuf->clear();
+
+    /* c) send the chat via some call */
+    Host::Chat( msgtosend );
+
+    /* d) stop listening to input - only if this is not fullchat */
+    if( !this->fullchat )
+      this->deactivate();
+
+  }
+
+  void ChatInputHandler::backspace()
+  { this->inpbuf->removeBehindCursor(); }
+
+  void ChatInputHandler::deleteChar()
+  { this->inpbuf->removeAtCursor(); }
+
+  void ChatInputHandler::cursorRight()
+  { this->inpbuf->increaseCursor(); }
+
+  void ChatInputHandler::cursorLeft()
+  { this->inpbuf->decreaseCursor(); }
+
+  void ChatInputHandler::cursorEnd()
+  { this->inpbuf->setCursorToEnd(); }
+
+  void ChatInputHandler::cursorHome()
+  { this->inpbuf->setCursorToBegin(); }
+
+  void ChatInputHandler::exit()
+  {
+    /* b) clear the input buffer */
+    if (this->inpbuf->getSize() > 0)
+      this->inpbuf->clear();
+
+    /* d) stop listening to input  */
+    this->deactivate();
+  }
+
+}
Index: code/trunk/src/orxonox/ChatInputHandler.h
===================================================================
--- code/trunk/src/orxonox/ChatInputHandler.h	(revision 7163)
+++ code/trunk/src/orxonox/ChatInputHandler.h	(revision 7163)
@@ -0,0 +1,148 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Sandro 'smerkli' Merkli
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _ChatInputHandler_H__
+#define _ChatInputHandler_H__
+
+/* std includes */
+#include <deque>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <cassert>
+#include <CEGUIForwardRefs.h>
+
+/* project includes */
+#include <OrxonoxPrereqs.h>
+#include <core/BaseObject.h>
+#include <core/PathConfig.h>
+
+#include "core/input/InputBuffer.h"
+#include "core/input/InputManager.h"
+#include "core/input/InputState.h"
+
+#include <network/ChatListener.h>
+#include <PlayerManager.h>
+#include <infos/PlayerInfo.h>
+
+#include "../libraries/network/Host.h"
+#include <util/Singleton.h>
+
+namespace orxonox // tolua_export
+{ // tolua_export
+  /* class to handle chat using an InputBuffer */
+  class _OrxonoxExport ChatInputHandler  // tolua_export
+    : public Singleton<ChatInputHandler>, public ChatListener
+  { // tolua_export
+    private:
+      /** Input buffer, to be used to catch input from the
+       * keyboard
+       */
+      InputBuffer *inpbuf;
+      int disp_offset, width;
+      bool fullchat;
+
+      /* colors for nickname coloring */
+      static const int NumberOfColors = 10;
+      CEGUI::colour *text_colors[ NumberOfColors ];
+
+      /** input state */
+      InputState *inputState;
+
+      /** setup input buffer, the constructor calls this */
+      void configureInputBuffer();
+
+      /** adjust display offset depending on cursor position */
+      void sub_adjust_dispoffset( int maxlen, int cursorpos, int inplen );
+
+      /** singleton pointer */
+      static ChatInputHandler* singletonPtr_s;
+
+      /** cegui window handles */
+      CEGUI::Window *input, *inputonly;
+
+      /** cegui handle for the history window */
+      CEGUI::Listbox *lb_history;
+
+      /* methods to deal with colors */
+      void sub_setcolor( CEGUI::ListboxTextItem *tocolor,
+        std::string name );
+
+      void setupColors();
+
+      /* callbacks for input handler */
+      void inputChanged();
+      void addline();
+      void backspace();
+      void deleteChar();
+      void cursorRight();
+      void cursorLeft();
+      void cursorEnd();
+      void cursorHome();
+      void exit();
+
+    public:
+      /** constructor */
+      ChatInputHandler();
+      friend class Singleton<ChatInputHandler>;
+
+      static ChatInputHandler& getInstance(void) { return Singleton<ChatInputHandler>::getInstance(); }  // tolua_export
+
+      /** start listening */
+      static void activate_static();
+
+      /** stop listening */
+      static void activate_small_static();
+
+      /** \param message the message text
+       * \param senderID ID of the player who sent the message
+       *
+       * Deal with incoming chat (which means in our case: Add it to the
+       * history window of the full chat window)
+       */
+      void incomingChat( const std::string& message,
+        unsigned int senderID );
+
+      /** \param full true means show full chat window with history,
+            false means show only an input line
+       *
+       * Show the chat window and redirect the game's keyboard input
+       * into it.
+       */
+      void activate( bool full );
+
+      /** Deactivate the chat window, meaning: hide it. */
+      void deactivate();  // tolua_export
+
+  };  // tolua_export
+
+
+}  // tolua_export
+
+
+#endif /*_ChatInputHandler_H__*/
Index: code/trunk/src/orxonox/Level.cc
===================================================================
--- code/trunk/src/orxonox/Level.cc	(revision 6906)
+++ code/trunk/src/orxonox/Level.cc	(revision 7163)
@@ -49,4 +49,5 @@
         RegisterObject(Level);
 
+
         this->registerVariables();
         this->xmlfilename_ = this->getFilename();
@@ -73,12 +74,14 @@
         XMLPortParam(Level, "gametype", setGametypeString, getGametypeString, xmlelement, mode).defaultValues("Gametype");
 
+        XMLPortObject(Level, MeshLodInformation, "lodinformation", addLodInfo, getLodInfo, xmlelement, mode);
         XMLPortObjectExtended(Level, BaseObject, "", addObject, getObject, xmlelement, mode, true, false);
-    }
+}
 
     void Level::registerVariables()
     {
-        registerVariable(this->xmlfilename_, VariableDirection::ToClient, new NetworkCallback<Level>(this, &Level::networkcallback_applyXMLFile));
-        registerVariable(this->name_,        VariableDirection::ToClient, new NetworkCallback<Level>(this, &Level::changedName));
-        registerVariable(this->description_, VariableDirection::ToClient);
+        registerVariable(this->xmlfilename_,            VariableDirection::ToClient, new NetworkCallback<Level>(this, &Level::networkcallback_applyXMLFile));
+        registerVariable(this->name_,                   VariableDirection::ToClient, new NetworkCallback<Level>(this, &Level::changedName));
+        registerVariable(this->description_,            VariableDirection::ToClient);
+        registerVariable(this->networkTemplateNames_,   VariableDirection::ToClient, new NetworkCallback<Level>(this, &Level::networkCallbackTemplatesChanged));
     }
 
@@ -95,4 +98,13 @@
 
         Loader::open(this->xmlfile_);
+    }
+
+    void Level::networkCallbackTemplatesChanged()
+    {
+        for( std::set<std::string>::iterator it = this->networkTemplateNames_.begin(); it!=this->networkTemplateNames_.end(); ++it )
+        {
+            assert(Template::getTemplate(*it));
+            Template::getTemplate(*it)->applyOn(this);
+        }
     }
 
@@ -125,4 +137,5 @@
         this->objects_.push_back(object);
         object->setGametype(this->getGametype());
+        object->setLevel(this);
     }
 
@@ -136,4 +149,21 @@
             ++i;
         }
+        return 0;
+    }
+
+    void Level::addLodInfo(MeshLodInformation* lodInformation)
+    {
+        std::string meshName = lodInformation->getMeshName();
+//         this->lodInformation_.insert(std::make_pair(meshName,lodInformation));
+        if( this->lodInformation_.find(meshName) != this->lodInformation_.end())
+          CCOUT(4) << "replacing lod information for " << meshName << endl;
+        this->lodInformation_[meshName] = lodInformation;
+    }
+
+    MeshLodInformation* Level::getLodInfo(std::string meshName) const
+    {
+        if(this->lodInformation_.find(meshName)!=this->lodInformation_.end())
+            return this->lodInformation_.find(meshName)->second;
+
         return 0;
     }
Index: code/trunk/src/orxonox/Level.h
===================================================================
--- code/trunk/src/orxonox/Level.h	(revision 6906)
+++ code/trunk/src/orxonox/Level.h	(revision 7163)
@@ -34,6 +34,8 @@
 #include <list>
 #include <string>
+#include <map>
 #include "core/BaseObject.h"
 #include "network/synchronisable/Synchronisable.h"
+#include "graphics/MeshLodInformation.h"
 
 namespace orxonox
@@ -46,5 +48,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             inline void setDescription(const std::string& description)
@@ -56,7 +57,16 @@
             void playerLeft(PlayerInfo* player);
 
+            MeshLodInformation* getLodInfo(std::string meshName) const;
+
+
         private:
+            void registerVariables();
             void addObject(BaseObject* object);
             BaseObject* getObject(unsigned int index) const;
+
+            void addLodInfo(MeshLodInformation* object);
+            void networkCallbackTemplatesChanged();
+//            const MeshLodInformation* getLodInfo(std::string meshName) const;
+//            MeshLodInformation* getLodInfo(unsigned int index) const;
 
             void setGametypeString(const std::string& gametype);
@@ -66,9 +76,10 @@
             void networkcallback_applyXMLFile();
 
-            std::string            description_;
-            std::string            gametype_;
-            std::string            xmlfilename_;
-            XMLFile*               xmlfile_;
-            std::list<BaseObject*> objects_;
+            std::string                    description_;
+            std::string                    gametype_;
+            std::string                    xmlfilename_;
+            XMLFile*                       xmlfile_;
+            std::list<BaseObject*>         objects_;
+            std::map<std::string,MeshLodInformation*>  lodInformation_;
     };
 }
Index: code/trunk/src/orxonox/LevelManager.cc
===================================================================
--- code/trunk/src/orxonox/LevelManager.cc	(revision 6906)
+++ code/trunk/src/orxonox/LevelManager.cc	(revision 7163)
@@ -70,4 +70,7 @@
     void LevelManager::requestActivity(Level* level)
     {
+        assert( std::find(this->levels_s.begin(), this->levels_s.end(), level)==this->levels_s.end() );
+        if( std::find(this->levels_s.begin(), this->levels_s.end(), level)!=this->levels_s.end() )
+            return; // level is already in list
         this->levels_s.push_back(level);
         if (this->levels_s.size() == 1)
Index: code/trunk/src/orxonox/Main.cc
===================================================================
--- code/trunk/src/orxonox/Main.cc	(revision 6906)
+++ code/trunk/src/orxonox/Main.cc	(revision 7163)
@@ -40,4 +40,5 @@
 #include "core/LuaState.h"
 #include "ToluaBindOrxonox.h"
+#include "ToluaBindNetwork.h"
 #include "Main.h"
 
@@ -51,4 +52,5 @@
 
 DeclareToluaInterface(Orxonox);
+DeclareToluaInterface(Network);
 
 namespace orxonox
Index: code/trunk/src/orxonox/MoodManager.cc
===================================================================
--- code/trunk/src/orxonox/MoodManager.cc	(revision 6906)
+++ code/trunk/src/orxonox/MoodManager.cc	(revision 7163)
@@ -32,4 +32,5 @@
 #include "core/CoreIncludes.h"
 #include "core/ScopedSingletonManager.h"
+#include "core/Resource.h"
 
 namespace orxonox
@@ -37,23 +38,36 @@
     ManageScopedSingleton(MoodManager, ScopeID::Root, false);
 
+    // Note: I'm (Kevin Young) not entirely sure whether that's good code style:
+    const std::string MoodManager::defaultMood_ = "default";
+
     MoodManager::MoodManager()
     {
         RegisterRootObject(MoodManager);
         this->setConfigValues();
+
+        // Need to use a variable to store old data because ResetConfigValues() doesn't seem to work.
+        oldMood_ = MoodManager::defaultMood_;
+        
+        // Checking for the existence of the folder for the default mood
+        const std::string& path = "ambient/" + MoodManager::defaultMood_ + "/.";
+        if (!Resource::exists(path))
+        {
+            // TODO: Non-fatal error handling (non-critical resource missing)
+            COUT(2) << "Mood Warning: Folder for default mood (" << MoodManager::defaultMood_ << ") does not exist!" << std::endl;
+        }
     }
 
     void MoodManager::setConfigValues()
     {
-        SetConfigValue(mood_, "default")
+        SetConfigValue(mood_, MoodManager::defaultMood_)
             .description("Sets the mood for the current level.")
             .callback(this, &MoodManager::checkMoodValidity);
     }
 
-    /** Sets the mood
-    @note
-        TODO: Inform dependent classes of mood change
-    */
+    /** Set a new mood
+     */
     void MoodManager::setMood(const std::string& mood)
     {
+        oldMood_ = mood_;
         ModifyConfigValue(mood_, set, mood);
     }
@@ -61,8 +75,10 @@
     void MoodManager::checkMoodValidity()
     {
-        // TODO: Insert new moods here & make this generic
-        if (mood_ != "default" && mood_ != "dnb")
+        //  Generic mood validation
+        const std::string& path = "ambient/" + mood_ + "/.";
+        if (!Resource::exists(path))
         {
-            ResetConfigValue(mood_);
+            COUT(3) << "Mood " << mood_ << " does not exist. Will not change." << std::endl;
+            this->setMood(oldMood_);
         }
         else
Index: code/trunk/src/orxonox/MoodManager.h
===================================================================
--- code/trunk/src/orxonox/MoodManager.h	(revision 6906)
+++ code/trunk/src/orxonox/MoodManager.h	(revision 7163)
@@ -38,4 +38,8 @@
 namespace orxonox
 {
+    /*
+    @brief
+        The MoodListener class is aware of a change in themes and directs that info to dependent classes.
+    */
     class _OrxonoxExport MoodListener : virtual public OrxonoxClass
     {
@@ -55,4 +59,8 @@
     };
 
+    /*
+    @brief
+        The MoodManager class serves to allow for different musical themes in the game.
+    */
     class _OrxonoxExport MoodManager : public Singleton<MoodManager>, public OrxonoxClass
     {
@@ -74,4 +82,6 @@
             // config values
             std::string mood_;
+            std::string oldMood_;
+            static const std::string defaultMood_;
 
             static MoodManager* singletonPtr_s;
Index: code/trunk/src/orxonox/OrxonoxPrereqs.h
===================================================================
--- code/trunk/src/orxonox/OrxonoxPrereqs.h	(revision 6906)
+++ code/trunk/src/orxonox/OrxonoxPrereqs.h	(revision 7163)
@@ -82,4 +82,5 @@
     class ArtificialController;
     class Controller;
+    class DroneController;
     class HumanController;
     class ScriptController;
@@ -90,4 +91,5 @@
     class Asteroids;
     class Deathmatch;
+    class Dynamicmatch;
     class Gametype;
     class TeamBaseMatch;
@@ -135,5 +137,5 @@
     class OrxonoxOverlay;
     class OverlayGroup;
-    
+
     // pickup
     class PickupIdentifier;
@@ -161,4 +163,5 @@
     class CameraPosition;
     class ControllableEntity;
+    class Drone;
     class EffectContainer;
     class ExplosionChunk;
Index: code/trunk/src/orxonox/Radar.cc
===================================================================
--- code/trunk/src/orxonox/Radar.cc	(revision 6906)
+++ code/trunk/src/orxonox/Radar.cc	(revision 7163)
@@ -77,4 +77,26 @@
     }
 
+    void Radar::addRadarObject(RadarViewable* rv)
+    {
+        assert( this->radarObjects_.find(rv) == this->radarObjects_.end() );
+        this->radarObjects_.insert(rv);
+        // iterate through all radarlisteners and notify them
+        for (ObjectList<RadarListener>::iterator itListener = ObjectList<RadarListener>::begin(); itListener; ++itListener)
+        {
+            (*itListener)->addObject(rv);
+        }
+    }
+
+    void Radar::removeRadarObject(RadarViewable* rv)
+    {
+        assert( this->radarObjects_.find(rv) != this->radarObjects_.end() );
+        this->radarObjects_.erase(rv);
+        // iterate through all radarlisteners and notify them
+        for (ObjectList<RadarListener>::iterator itListener = ObjectList<RadarListener>::begin(); itListener; ++itListener)
+        {
+            (*itListener)->removeObject(rv);
+        }
+    }
+
     const RadarViewable* Radar::getFocus()
     {
@@ -109,11 +131,4 @@
         {
             (*itListener)->radarTick(dt);
-
-            for (ObjectList<RadarViewable>::iterator itElement = ObjectList<RadarViewable>::begin(); itElement; ++itElement)
-            {
-                if ((*itElement)->getRadarVisibility())
-                    if ((*itListener)->getRadarSensitivity() > (*itElement)->getRadarObjectCamouflage())
-                        (*itListener)->displayObject(*itElement, *itElement == this->focus_);
-            }
         }
     }
@@ -188,3 +203,11 @@
         }
     }
+
+    void Radar::radarObjectChanged(RadarViewable* rv)
+    {
+        for (ObjectList<RadarListener>::iterator itListener = ObjectList<RadarListener>::begin(); itListener; ++itListener)
+        {
+          (*itListener)->objectChanged(rv);
+        }
+    }
 }
Index: code/trunk/src/orxonox/Radar.h
===================================================================
--- code/trunk/src/orxonox/Radar.h	(revision 6906)
+++ code/trunk/src/orxonox/Radar.h	(revision 7163)
@@ -38,4 +38,5 @@
 
 #include <map>
+#include <set>
 #include <string>
 
@@ -48,4 +49,5 @@
     class _OrxonoxExport Radar : public Tickable
     {
+        friend class RadarViewable;
     public:
         Radar();
@@ -58,4 +60,6 @@
 
         void listObjects() const;
+        const std::set<RadarViewable*>& getRadarObjects() const
+            { return this->radarObjects_; }
 
         void releaseFocus();
@@ -66,8 +70,12 @@
 
         void updateFocus();
+        void addRadarObject(RadarViewable* rv);
+        void removeRadarObject(RadarViewable* rv);
+        void radarObjectChanged(RadarViewable* rv);
 
         ObjectListIterator<RadarViewable> itFocus_;
         RadarViewable* focus_;
         std::map<std::string, RadarViewable::Shape> objectTypes_;
+        std::set<RadarViewable*> radarObjects_;
         int objectTypeCounter_;
     };
Index: code/trunk/src/orxonox/Scene.cc
===================================================================
--- code/trunk/src/orxonox/Scene.cc	(revision 6906)
+++ code/trunk/src/orxonox/Scene.cc	(revision 7163)
@@ -47,4 +47,5 @@
 #include "Radar.h"
 #include "worldentities/WorldEntity.h"
+#include "Level.h"
 
 namespace orxonox
@@ -133,4 +134,5 @@
         registerVariable(this->bHasPhysics_,        VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_hasPhysics));
         registerVariable(this->bShadows_,           VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::networkcallback_applyShadows));
+        registerVariable(this->getLevel(),          VariableDirection::ToClient, new NetworkCallback<Scene>(this, &Scene::changedLevel));
     }
 
Index: code/trunk/src/orxonox/Test.cc
===================================================================
--- code/trunk/src/orxonox/Test.cc	(revision 6906)
+++ code/trunk/src/orxonox/Test.cc	(revision 7163)
@@ -88,15 +88,17 @@
     void Test::registerVariables()
     {
-        registerVariable ( u1, VariableDirection::ToClient, new NetworkCallback<Test> ( this, &Test::checkU1 ));
-        registerVariable ( u2, VariableDirection::ToServer, new NetworkCallback<Test> ( this, &Test::checkU2 ));
-        registerVariable ( u3, Bidirectionality::ServerMaster, new NetworkCallback<Test> ( this, &Test::checkU3 ), true );
-        registerVariable ( u4, Bidirectionality::ClientMaster, new NetworkCallback<Test> ( this, &Test::checkU4 ), true );
+        registerVariable ( this->mySet_, VariableDirection::ToClient );
+      
+//         registerVariable ( u1, VariableDirection::ToClient, new NetworkCallback<Test> ( this, &Test::checkU1 ));
+//         registerVariable ( u2, VariableDirection::ToServer, new NetworkCallback<Test> ( this, &Test::checkU2 ));
+//         registerVariable ( u3, Bidirectionality::ServerMaster, new NetworkCallback<Test> ( this, &Test::checkU3 ), true );
+//         registerVariable ( u4, Bidirectionality::ClientMaster, new NetworkCallback<Test> ( this, &Test::checkU4 ), true );
     
-        registerVariable ( s1, VariableDirection::ToClient, new NetworkCallback<Test> ( this, &Test::checkS1 ));
-        registerVariable ( s2, VariableDirection::ToServer, new NetworkCallback<Test> ( this, &Test::checkS2 ));
-        registerVariable ( s3, Bidirectionality::ServerMaster, new NetworkCallback<Test> ( this, &Test::checkS3 ), true );
-        registerVariable ( s4, Bidirectionality::ClientMaster, new NetworkCallback<Test> ( this, &Test::checkS4 ), true );
+//         registerVariable ( s1, VariableDirection::ToClient, new NetworkCallback<Test> ( this, &Test::checkS1 ));
+//         registerVariable ( s2, VariableDirection::ToServer, new NetworkCallback<Test> ( this, &Test::checkS2 ));
+//         registerVariable ( s3, Bidirectionality::ServerMaster, new NetworkCallback<Test> ( this, &Test::checkS3 ), true );
+//         registerVariable ( s4, Bidirectionality::ClientMaster, new NetworkCallback<Test> ( this, &Test::checkS4 ), true );
     
-        registerVariable ( pointer_, VariableDirection::ToClient, new NetworkCallback<Test> ( this, &Test::printPointer ) );
+//         registerVariable ( pointer_, VariableDirection::ToClient, new NetworkCallback<Test> ( this, &Test::printPointer ) );
     }
   
Index: code/trunk/src/orxonox/Test.h
===================================================================
--- code/trunk/src/orxonox/Test.h	(revision 6906)
+++ code/trunk/src/orxonox/Test.h	(revision 7163)
@@ -35,4 +35,5 @@
 #include "tools/interfaces/Tickable.h"
 
+#include <set>
 
 typedef int TYPE;
@@ -49,5 +50,4 @@
 
       void setConfigValues();
-      void registerVariables();
 
       static void call(unsigned int clientID);
@@ -78,6 +78,6 @@
       void printPointer();
 
-      static void printV1(){ instance_->checkU1(); }
-      static void printV2(){ instance_->checkU2(); }
+      static void printV1(){ instance_->blub(); }
+      static void printV2(){ instance_->blub2(); }
       static void printV3(){ instance_->checkU3(); }
       static void printV4(){ instance_->checkU4(); }
@@ -86,4 +86,6 @@
 
     private:
+      void registerVariables();
+
       UTYPE u1;
       UTYPE u2;
@@ -97,6 +99,14 @@
 
       Test* pointer_;
+      
+      std::set<uint32_t> mySet_;
 
       static Test* instance_;
+      
+      void blub()
+      { mySet_.insert(2); }
+      
+      void blub2()
+      { for( std::set<uint32_t>::iterator it=mySet_.begin(); it!=mySet_.end(); ++it ) COUT(0) << *it << endl; }
   };
 }
Index: code/trunk/src/orxonox/collisionshapes/CollisionShape.h
===================================================================
--- code/trunk/src/orxonox/collisionshapes/CollisionShape.h	(revision 6906)
+++ code/trunk/src/orxonox/collisionshapes/CollisionShape.h	(revision 7163)
@@ -45,5 +45,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             inline void setPosition(const Vector3& position)
@@ -88,4 +87,6 @@
 
         private:
+            void registerVariables();
+
             Vector3                 position_;
             Quaternion              orientation_;
Index: code/trunk/src/orxonox/controllers/AIController.cc
===================================================================
--- code/trunk/src/orxonox/controllers/AIController.cc	(revision 6906)
+++ code/trunk/src/orxonox/controllers/AIController.cc	(revision 7163)
@@ -23,5 +23,5 @@
  *      Fabian 'x3n' Landau
  *   Co-authors:
- *      ...
+ *      Dominik Solenicki
  *
  */
@@ -33,4 +33,5 @@
 #include "core/Executor.h"
 #include "worldentities/ControllableEntity.h"
+#include "worldentities/pawns/Pawn.h"
 
 namespace orxonox
@@ -56,43 +57,146 @@
         float maxrand = 100.0f / ACTION_INTERVAL;
 
-        // search enemy
-        random = rnd(maxrand);
-        if (random < 15 && (!this->target_))
-            this->searchNewTarget();
-
-        // forget enemy
-        random = rnd(maxrand);
-        if (random < 5 && (this->target_))
-            this->forgetTarget();
-
-        // next enemy
-        random = rnd(maxrand);
-        if (random < 10 && (this->target_))
-            this->searchNewTarget();
-
-        // fly somewhere
-        random = rnd(maxrand);
-        if (random < 50 && (!this->bHasTargetPosition_ && !this->target_))
-            this->searchRandomTargetPosition();
-
-        // stop flying
-        random = rnd(maxrand);
-        if (random < 10 && (this->bHasTargetPosition_ && !this->target_))
-            this->bHasTargetPosition_ = false;
-
-        // fly somewhere else
-        random = rnd(maxrand);
-        if (random < 30 && (this->bHasTargetPosition_ && !this->target_))
-            this->searchRandomTargetPosition();
-
-        // shoot
-        random = rnd(maxrand);
-        if (random < 75 && (this->target_ && !this->bShooting_))
-            this->bShooting_ = true;
-
-        // stop shooting
-        random = rnd(maxrand);
-        if (random < 25 && (this->bShooting_))
-            this->bShooting_ = false;
+        if (this->state_ == FREE)
+        {
+
+            if (this->formationFlight_)
+            {
+                // return to Master after being forced free
+                if (this->freedomCount_ == 1)
+                {
+                this->state_ = SLAVE;
+                this->freedomCount_ = 0;
+                }
+
+                random = rnd(maxrand);
+                if (random < 90 && (((!this->target_) || (random < 50 && this->target_)) && !this->forcedFree()))
+                    this->searchNewMaster();
+            }
+
+            // search enemy
+            random = rnd(maxrand);
+            if (random < 15 && (!this->target_))
+                this->searchNewTarget();
+
+            // forget enemy
+            random = rnd(maxrand);
+            if (random < 5 && (this->target_))
+                this->forgetTarget();
+
+            // next enemy
+            random = rnd(maxrand);
+            if (random < 10 && (this->target_))
+                this->searchNewTarget();
+
+            // fly somewhere
+            random = rnd(maxrand);
+            if (random < 50 && (!this->bHasTargetPosition_ && !this->target_))
+                this->searchRandomTargetPosition();
+
+            // stop flying
+            random = rnd(maxrand);
+            if (random < 10 && (this->bHasTargetPosition_ && !this->target_))
+                this->bHasTargetPosition_ = false;
+
+            // fly somewhere else
+            random = rnd(maxrand);
+            if (random < 30 && (this->bHasTargetPosition_ && !this->target_))
+                this->searchRandomTargetPosition();
+
+            // shoot
+            random = rnd(maxrand);
+            if (!(this->passive_) && random < 75 && (this->target_ && !this->bShooting_))
+                this->bShooting_ = true;
+
+            // stop shooting
+            random = rnd(maxrand);
+            if (random < 25 && (this->bShooting_))
+                this->bShooting_ = false;
+
+        }
+
+        if (this->state_ == SLAVE)
+        {
+
+        }
+
+        if (this->state_ == MASTER)
+        {
+
+
+            this->commandSlaves();
+
+            if  (this->specificMasterAction_ != NONE)
+                    this->specificMasterActionHold();
+
+            else {
+
+                 // make 180 degree turn - a specific Master Action
+                random = rnd(1000.0f);
+                if (random < 5)
+                   this->turn180Init();
+
+                // spin around - a specific Master Action
+                random = rnd(1000.0f);
+                if (random < 5)
+                   this->spinInit();
+
+                // follow a randomly chosen human - a specific Master Action
+                random = rnd(1000.0f);
+                if (random < 1)
+                   this->followRandomHumanInit();
+
+                 // lose master status (only if less than 4 slaves in formation)
+                random = rnd(maxrand);
+                if(random < 15/(this->slaves_.size()+1) && this->slaves_.size() < 4 )
+                   this->loseMasterState();
+
+                // look out for outher masters if formation is small
+                random = rnd(maxrand);
+                if(this->slaves_.size() < 3 && random < 20)
+                    this->searchNewMaster();
+
+                // search enemy
+                random = rnd(maxrand);
+                if (random < 15 && (!this->target_))
+                    this->searchNewTarget();
+
+                // forget enemy
+                random = rnd(maxrand);
+                if (random < 5 && (this->target_))
+                    this->forgetTarget();
+
+                // next enemy
+                random = rnd(maxrand);
+                if (random < 10 && (this->target_))
+                    this->searchNewTarget();
+
+                // fly somewhere
+                random = rnd(maxrand);
+                if (random < 50 && (!this->bHasTargetPosition_ && !this->target_))
+                    this->searchRandomTargetPosition();
+
+
+                // fly somewhere else
+                random = rnd(maxrand);
+                if (random < 30 && (this->bHasTargetPosition_ && !this->target_))
+                    this->searchRandomTargetPosition();
+
+                // shoot
+                random = rnd(maxrand);
+                if (!(this->passive_) && random < 9 && (this->target_ && !this->bShooting_))
+                {
+                this->bShooting_ = true;
+                this->forceFreeSlaves();
+                }
+
+                // stop shooting
+                random = rnd(maxrand);
+                if (random < 25 && (this->bShooting_))
+                    this->bShooting_ = false;
+
+            }
+        }
+
     }
 
@@ -102,12 +206,54 @@
             return;
 
-        if (this->target_)
-            this->aimAtTarget();
-
-        if (this->bHasTargetPosition_)
-            this->moveToTargetPosition();
-
-        if (this->getControllableEntity() && this->bShooting_ && this->isCloseAtTarget(1000) && this->isLookingAtTarget(Ogre::Math::PI / 20.0f))
-            this->getControllableEntity()->fire(0);
+        if (this->state_ == MASTER)
+        {
+            if (this->specificMasterAction_ ==  NONE)
+            {
+                if (this->target_)
+                {
+				if (!this->target_->getRadarVisibility()) /* So AI won't shoot invisible Spaceships */
+                	this->forgetTarget();
+                else this->aimAtTarget();
+            }
+
+                if (this->bHasTargetPosition_)
+                    this->moveToTargetPosition();
+
+                if (this->getControllableEntity() && this->bShooting_ && this->isCloseAtTarget(1000) && this->isLookingAtTarget(Ogre::Math::PI / 20.0f))
+                    this->getControllableEntity()->fire(0);
+            }
+
+            if (this->specificMasterAction_  == TURN180)
+                    this->turn180();
+
+            if (this->specificMasterAction_ == SPIN)
+                    this->spin();
+            if (this->specificMasterAction_ == FOLLOW)
+                    this->follow();
+        }
+
+        if (this->state_ == SLAVE)
+        {
+
+            if (this->bHasTargetPosition_)
+                this->moveToTargetPosition();
+
+        }
+
+         if (this->state_ == FREE)
+        {
+            if (this->target_)
+            {
+				if (!this->target_->getRadarVisibility()) /* So AI won't shoot invisible Spaceships */
+                	this->forgetTarget();
+                else this->aimAtTarget();
+            }
+
+            if (this->bHasTargetPosition_)
+                this->moveToTargetPosition();
+
+            if (this->getControllableEntity() && this->bShooting_ && this->isCloseAtTarget(1000) && this->isLookingAtTarget(Ogre::Math::PI / 20.0f))
+                this->getControllableEntity()->fire(0);
+        }
 
         SUPER(AIController, tick, dt);
Index: code/trunk/src/orxonox/controllers/ArtificialController.cc
===================================================================
--- code/trunk/src/orxonox/controllers/ArtificialController.cc	(revision 6906)
+++ code/trunk/src/orxonox/controllers/ArtificialController.cc	(revision 7163)
@@ -23,5 +23,5 @@
  *      Fabian 'x3n' Landau
  *   Co-authors:
- *      ...
+ *      Dominik Solenicki
  *
  */
@@ -29,13 +29,39 @@
 #include "ArtificialController.h"
 
+#include <vector>
+#include <climits>
+
+#include "util/Math.h"
+#include "core/ConsoleCommand.h"
 #include "core/CoreIncludes.h"
+#include "core/XMLPort.h"
 #include "worldentities/ControllableEntity.h"
 #include "worldentities/pawns/Pawn.h"
 #include "worldentities/pawns/TeamBaseMatchBase.h"
 #include "gametypes/TeamDeathmatch.h"
+#include "gametypes/Dynamicmatch.h"
 #include "controllers/WaypointPatrolController.h"
+#include "controllers/NewHumanController.h"
+#include "controllers/DroneController.h"
 
 namespace orxonox
 {
+    SetConsoleCommand(ArtificialController, formationflight, true);
+    SetConsoleCommand(ArtificialController, masteraction, true);
+    SetConsoleCommand(ArtificialController, followme, true);
+    SetConsoleCommand(ArtificialController, passivebehaviour, true);
+    SetConsoleCommand(ArtificialController, formationsize, true);
+
+    static const unsigned int STANDARD_MAX_FORMATION_SIZE = 7;
+    static const int RADIUS_TO_SEARCH_FOR_MASTERS = 5000;
+    static const int FORMATION_LENGTH =  130;
+    static const int FORMATION_WIDTH =  110;
+    static const int FREEDOM_COUNT = 4; //seconds the slaves in a formation will be set free when master attacks an enemy
+    static const float SPEED_MASTER = 0.6f;
+    static const float ROTATEFACTOR_MASTER = 0.2f;
+    static const float SPEED_FREE = 0.8f;
+    static const float ROTATEFACTOR_FREE = 0.8f;
+
+
     ArtificialController::ArtificialController(BaseObject* creator) : Controller(creator)
     {
@@ -43,6 +69,16 @@
 
         this->target_ = 0;
+        this->formationFlight_ = true;
+        this->passive_ = false;
+        this->maxFormationSize_ = STANDARD_MAX_FORMATION_SIZE;
+        this->myMaster_ = 0;
+        this->freedomCount_ = 0;
+        this->team_ = -1;
+        this->state_ = FREE;
+        this->specificMasterAction_ = NONE;
+        this->specificMasterActionHoldCount_  = 0;
         this->bShooting_ = false;
         this->bHasTargetPosition_ = false;
+        this->speedCounter_ = 0.2f;
         this->targetPosition_ = Vector3::ZERO;
 
@@ -52,4 +88,229 @@
     ArtificialController::~ArtificialController()
     {
+        if (this->isInitialized())
+        {
+            this->removeFromFormation();
+
+            for (ObjectList<ArtificialController>::iterator it = ObjectList<ArtificialController>::begin(); it; ++it)
+            {
+                if (*it != this)
+                {
+                    if (it->myMaster_ == this)
+                    {
+                        COUT(1) << "error: " << this << " is still master in " << (*it) << std::endl;
+                        it->myMaster_ = 0;
+                    }
+
+                    while (true)
+                    {
+                        std::vector<ArtificialController*>::iterator it2 = std::find(it->slaves_.begin(), it->slaves_.end(), this);
+                        if (it2 != it->slaves_.end())
+                        {
+                            COUT(1) << "error: " << this << " is still slave in " << (*it) << std::endl;
+                            it->slaves_.erase(it2);
+                        }
+                        else
+                            break;
+                    }
+                }
+            }
+        }
+    }
+
+    void ArtificialController::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(ArtificialController, XMLPort, xmlelement, mode);
+
+        XMLPortParam(ArtificialController, "team", setTeam, getTeam, xmlelement, mode).defaultValues(-1);
+        XMLPortParam(ArtificialController, "formationFlight", setFormationFlight, getFormationFlight, xmlelement, mode).defaultValues(false);
+        XMLPortParam(ArtificialController, "formationSize", setFormationSize, getFormationSize, xmlelement, mode).defaultValues(STANDARD_MAX_FORMATION_SIZE);
+        XMLPortParam(ArtificialController, "passive", setPassive, getPassive, xmlelement, mode).defaultValues(false);
+    }
+
+// Documentation only here to get a faster overview for creating a useful documentation...
+
+    /**
+        @brief Activates / deactivates formationflight behaviour
+        @param form activate formflight if form is true
+    */
+    void ArtificialController::formationflight(const bool form)
+    {
+        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
+        {
+            Controller* controller = 0;
+
+            if (it->getController())
+                controller = it->getController();
+            else if (it->getXMLController())
+                controller = it->getXMLController();
+
+            if (!controller)
+                continue;
+
+            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
+
+            if (aiController)
+            {
+                aiController->formationFlight_ = form;
+                if (!form)
+                {
+                    aiController->removeFromFormation();
+                }
+            }
+        }
+    }
+
+    /**
+        @brief Get all masters to do a "specific master action"
+        @param action which action to perform (integer, so it can be called with a console command (tmp solution))
+    */
+    void ArtificialController::masteraction(const int action)
+    {
+        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
+        {
+            Controller* controller = 0;
+
+            if (it->getController())
+                controller = it->getController();
+            else if (it->getXMLController())
+                controller = it->getXMLController();
+
+            if (!controller)
+                continue;
+
+            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
+
+            if(aiController && aiController->state_ == MASTER)
+            {
+                if (action == 1)
+                    aiController->spinInit();
+                if (action == 2)
+                    aiController->turn180Init();
+            }
+        }
+    }
+
+    /**
+        @brief A human player gets followed by its nearest master. Initiated by console command, so far intended for demonstration puproses (possible future pickup).
+    */
+    void ArtificialController::followme()
+    {
+
+        Pawn *humanPawn = NULL;
+        NewHumanController *currentHumanController = NULL;
+        std::vector<ArtificialController*> allMasters;
+
+        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
+        {
+            Controller* controller = 0;
+
+            if (it->getController())
+                controller = it->getController();
+            else if (it->getXMLController())
+                controller = it->getXMLController();
+
+            if (!controller)
+                continue;
+
+            currentHumanController = orxonox_cast<NewHumanController*>(controller);
+
+            if(currentHumanController) humanPawn = *it;
+
+            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
+
+            if(aiController && aiController->state_ == MASTER)
+                allMasters.push_back(aiController);
+
+        }
+
+        if((humanPawn != NULL) && (allMasters.size() != 0))
+        {
+                float posHuman = humanPawn->getPosition().length();
+                float distance = 0.0f;
+                float minDistance = FLT_MAX;
+                int index = 0;
+                int i = 0;
+
+                for(std::vector<ArtificialController*>::iterator it = allMasters.begin(); it != allMasters.end(); it++, i++)
+                    {
+                        if (!ArtificialController::sameTeam((*it)->getControllableEntity(), humanPawn, (*it)->getGametype())) continue;
+                        distance = posHuman - (*it)->getControllableEntity()->getPosition().length();
+                        if(distance < minDistance) index = i;
+                    }
+                allMasters[index]->followInit(humanPawn);
+            }
+
+    }
+
+    /**
+        @brief Sets shooting behaviour of pawns.
+        @param passive if true, bots won't shoot.
+    */
+    void ArtificialController::passivebehaviour(const bool passive)
+    {
+        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
+        {
+            Controller* controller = 0;
+
+            if (it->getController())
+                controller = it->getController();
+            else if (it->getXMLController())
+                controller = it->getXMLController();
+
+            if (!controller)
+                continue;
+
+            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
+
+            if(aiController)
+            {
+                aiController->passive_ = passive;
+            }
+        }
+    }
+
+
+    /**
+        @brief Sets maximal formation size
+        @param size maximal formation size.
+    */
+    void ArtificialController::formationsize(const int size)
+    {
+        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
+        {
+            Controller* controller = 0;
+
+            if (it->getController())
+                controller = it->getController();
+            else if (it->getXMLController())
+                controller = it->getXMLController();
+
+            if (!controller)
+                continue;
+
+            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
+
+            if(aiController)
+            {
+                aiController->maxFormationSize_ = size;
+            }
+        }
+    }
+
+    /**
+        @brief Gets called when ControllableEntity is being changed. Resets the bot when it dies.
+    */
+    void ArtificialController::changedControllableEntity()
+    {
+        if (!this->getControllableEntity())
+            this->removeFromFormation();
+    }
+
+    void ArtificialController::removeFromFormation()
+    {
+        if (this->state_ == SLAVE || this->myMaster_) // slaves can also be temporary free, so check if myMaster_ is set
+            this->unregisterSlave();
+        else if (this->state_ == MASTER)
+            this->setNewMasterWithinFormation();
     }
 
@@ -59,24 +320,488 @@
             return;
 
+        // Slave uses special movement if its master is in FOLLOW mode
+        if(this->state_ == SLAVE && this->myMaster_ && this->myMaster_->specificMasterAction_ == FOLLOW)
+        {
+//             this->followForSlaves(target);
+//             return;
+        }
+
         Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, target);
         float distance = (target - this->getControllableEntity()->getPosition()).length();
 
-        if (this->target_ || distance > 10)
-        {
-            // Multiply with 0.8 to make them a bit slower
-            this->getControllableEntity()->rotateYaw(-0.8f * sgn(coord.x) * coord.x*coord.x);
-            this->getControllableEntity()->rotatePitch(0.8f * sgn(coord.y) * coord.y*coord.y);
-        }
-
-        if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength())
-            this->getControllableEntity()->moveFrontBack(-0.5f); // They don't brake with full power to give the player a chance
+
+        if(this->state_ == FREE)
+        {
+            if (this->target_ || distance > 10)
+            {
+                // Multiply with ROTATEFACTOR_FREE to make them a bit slower
+                this->getControllableEntity()->rotateYaw(-1.0f * ROTATEFACTOR_FREE * sgn(coord.x) * coord.x*coord.x);
+                this->getControllableEntity()->rotatePitch(ROTATEFACTOR_FREE * sgn(coord.y) * coord.y*coord.y);
+            }
+
+            if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength())
+            {
+              this->getControllableEntity()->moveFrontBack(-0.05f); // They don't brake with full power to give the player a chance
+            } else this->getControllableEntity()->moveFrontBack(SPEED_FREE);
+        }
+
+
+
+        if(this->state_ == MASTER)
+        {
+            if (this->target_ || distance > 10)
+            {
+                this->getControllableEntity()->rotateYaw(-1.0f * ROTATEFACTOR_MASTER * sgn(coord.x) * coord.x*coord.x);
+                this->getControllableEntity()->rotatePitch(ROTATEFACTOR_MASTER * sgn(coord.y) * coord.y*coord.y);
+            }
+
+            if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength())
+            {
+                this->getControllableEntity()->moveFrontBack(-0.05f);
+            } else this->getControllableEntity()->moveFrontBack(SPEED_MASTER);
+        }
+
+
+
+        if(this->state_ == SLAVE)
+        {
+
+           this->getControllableEntity()->rotateYaw(-2.0f * ROTATEFACTOR_MASTER * sgn(coord.x) * coord.x*coord.x);
+           this->getControllableEntity()->rotatePitch(2.0f * ROTATEFACTOR_MASTER * sgn(coord.y) * coord.y*coord.y);
+
+            if (distance < 300)
+            {
+                if (distance < 40)
+                {
+                    this->getControllableEntity()->moveFrontBack(0.8f*SPEED_MASTER);
+                } else this->getControllableEntity()->moveFrontBack(1.2f*SPEED_MASTER);
+
+            } else {
+                this->getControllableEntity()->moveFrontBack(1.2f*SPEED_MASTER + distance/300.0f);
+            }
+        }
+    }
+
+    void ArtificialController::moveToTargetPosition()
+    {
+        this->moveToPosition(this->targetPosition_);
+    }
+
+
+    /**
+        @brief Unregisters a slave from its master. Initiated by a slave.
+    */
+    void ArtificialController::unregisterSlave()
+    {
+        if (this->myMaster_)
+        {
+            std::vector<ArtificialController*>::iterator it = std::find(this->myMaster_->slaves_.begin(), this->myMaster_->slaves_.end(), this);
+            if (it != this->myMaster_->slaves_.end())
+                this->myMaster_->slaves_.erase(it);
+        }
+
+        this->myMaster_ = 0;
+        this->state_ = FREE;
+    }
+
+    void ArtificialController::searchNewMaster()
+    {
+
+        if (!this->getControllableEntity())
+            return;
+
+        this->targetPosition_ = this->getControllableEntity()->getPosition();
+        this->forgetTarget();
+        int teamSize = 0;
+        //go through all pawns
+        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
+        {
+            //same team?
+            if (!ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
+                continue;
+
+            //has it an ArtificialController?
+            Controller* controller = 0;
+
+            if (it->getController())
+                controller = it->getController();
+            else if (it->getXMLController())
+                controller = it->getXMLController();
+
+            if (!controller)
+                continue;
+
+            //is pawn oneself?
+            if (orxonox_cast<ControllableEntity*>(*it) == this->getControllableEntity())
+                continue;
+
+            teamSize++;
+
+            ArtificialController *newMaster = orxonox_cast<ArtificialController*>(controller);
+
+            //is it a master?
+            if (!newMaster || newMaster->state_ != MASTER)
+                continue;
+
+            float distance = (it->getPosition() - this->getControllableEntity()->getPosition()).length();
+
+            // is pawn in range?
+            if (distance < RADIUS_TO_SEARCH_FOR_MASTERS)
+            {
+                if(newMaster->slaves_.size() > this->maxFormationSize_) continue;
+
+                for(std::vector<ArtificialController*>::iterator itSlave = this->slaves_.begin(); itSlave != this->slaves_.end(); itSlave++)
+                {
+                    (*itSlave)->myMaster_ = newMaster;
+                    newMaster->slaves_.push_back(*itSlave);
+                }
+                this->slaves_.clear();
+                this->state_ = SLAVE;
+
+                this->myMaster_ = newMaster;
+                newMaster->slaves_.push_back(this);
+
+                break;
+            }
+        }
+
+        if (this->state_ != SLAVE  && teamSize != 0)
+        {
+            this->state_ = MASTER;
+            this->myMaster_ = 0;
+        }
+    }
+
+    /**
+        @brief Commands the slaves of a master into a formation. Sufficiently fast not to be called within tick. Initiated by a master.
+    */
+    void ArtificialController::commandSlaves()
+    {
+        if(this->state_ != MASTER) return;
+
+        Quaternion orient = this->getControllableEntity()->getOrientation();
+        Vector3 dest = this->getControllableEntity()->getPosition();
+
+        // 1 slave: follow
+        if (this->slaves_.size() == 1)
+        {
+            dest += 4*orient*WorldEntity::BACK;
+            this->slaves_.front()->setTargetPosition(dest);
+        }
         else
-            this->getControllableEntity()->moveFrontBack(0.8f);
-    }
-
-    void ArtificialController::moveToTargetPosition()
-    {
-        this->moveToPosition(this->targetPosition_);
-    }
+        {
+            dest += 1.0f*orient*WorldEntity::BACK;
+            Vector3 pos = Vector3::ZERO;
+            int i = 1;
+
+            for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
+            {
+                pos = Vector3::ZERO;
+                if (i <= 1) pos += dest  + FORMATION_WIDTH*(orient*WorldEntity::LEFT);
+                if (i == 2) pos += dest  + FORMATION_WIDTH*(orient*WorldEntity::RIGHT);
+                if (i == 3) pos += dest  + FORMATION_WIDTH*(orient*WorldEntity::UP);
+                if (i >= 4)
+                {
+                    pos += dest  + FORMATION_WIDTH*(orient*WorldEntity::DOWN);
+                    i = 1;
+                    dest += FORMATION_LENGTH*(orient*WorldEntity::BACK);
+                    (*it)->setTargetPosition(pos);
+                    continue;
+                }
+                i++;
+                (*it)->setTargetPosition(pos);
+            }
+        }
+    }
+
+    /**
+        @brief Sets a new master within the formation. Called by a master.
+    */
+    void ArtificialController::setNewMasterWithinFormation()
+    {
+        if(this->state_ != MASTER) return;
+
+        if (!this->slaves_.empty())
+        {
+            ArtificialController *newMaster = this->slaves_.back();
+            this->slaves_.pop_back();
+
+            newMaster->state_ = MASTER;
+            newMaster->slaves_ = this->slaves_;
+            newMaster->myMaster_ = 0;
+
+            for(std::vector<ArtificialController*>::iterator it = newMaster->slaves_.begin(); it != newMaster->slaves_.end(); it++)
+            {
+                (*it)->myMaster_ = newMaster;
+            }
+        }
+
+        this->slaves_.clear();
+        this->specificMasterAction_ = NONE;
+        this->state_ = FREE;
+    }
+
+    /**
+        @brief Frees all slaves form a master. Initiated by a master.
+    */
+    void ArtificialController::freeSlaves()
+    {
+        if(this->state_ != MASTER) return;
+
+        for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
+        {
+            (*it)->state_ = FREE;
+            (*it)->myMaster_ = 0;
+        }
+        this->slaves_.clear();
+    }
+
+    /**
+        @brief Master sets its slaves free for @var FREEDOM_COUNT seconds.
+    */
+    void ArtificialController::forceFreeSlaves()
+    {
+        if(this->state_ != MASTER) return;
+
+        for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
+        {
+            (*it)->state_ = FREE;
+            (*it)->forceFreedom();
+            (*it)->targetPosition_ = this->targetPosition_;
+            (*it)->bShooting_ = true;
+//             (*it)->getControllableEntity()->fire(0);// fire once for fun
+        }
+    }
+
+    void ArtificialController::loseMasterState()
+    {
+        this->freeSlaves();
+        this->state_ = FREE;
+    }
+
+
+    void ArtificialController::forceFreedom()
+    {
+        this->freedomCount_ = FREEDOM_COUNT;
+    }
+
+    /**
+        @brief Checks wether caller has been forced free, decrements time to stay forced free.
+        @return true if forced free.
+    */
+    bool ArtificialController::forcedFree()
+    {
+        if(this->freedomCount_ > 0)
+        {
+            this->freedomCount_--;
+            return true;
+        } else return false;
+    }
+
+    /**
+        @brief Used to continue a "specific master action" for a certain time and resuming normal behaviour after.
+    */
+    void ArtificialController::specificMasterActionHold()
+    {
+        if(this->state_ != MASTER) return;
+
+        if (specificMasterActionHoldCount_ == 0)
+         {
+            this->specificMasterAction_ = NONE;
+            this->searchNewTarget();
+         }
+        else specificMasterActionHoldCount_--;
+    }
+
+    /**
+        @brief Master initializes a 180 degree turn. Leads to a "specific master action".
+    */
+    void ArtificialController::turn180Init()
+    {
+        if(this->state_ != MASTER) return;
+
+        Quaternion orient = this->getControllableEntity()->getOrientation();
+
+        this->setTargetPosition(this->getControllableEntity()->getPosition() + 1000.0f*orient*WorldEntity::BACK);
+
+        this->specificMasterActionHoldCount_ = 4;
+
+        this->specificMasterAction_ = TURN180;
+    }
+
+    /**
+        @brief Execute the 180 degree turn. Called within tick.
+    */
+    void ArtificialController::turn180()
+    {
+            Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, this->targetPosition_);
+
+            this->getControllableEntity()->rotateYaw(-2.0f * sgn(coord.x) * coord.x*coord.x);
+            this->getControllableEntity()->rotatePitch(2.0f * sgn(coord.y) * coord.y*coord.y);
+
+            this->getControllableEntity()->moveFrontBack(SPEED_MASTER);
+    }
+
+    /**
+        @brief Master initializes a spin around its looking direction axis. Leads to a "specific master action".
+    */
+    void ArtificialController::spinInit()
+    {
+        if(this->state_ != MASTER) return;
+        this->specificMasterAction_ = SPIN;
+        this->specificMasterActionHoldCount_ = 10;
+    }
+
+    /**
+        @brief Execute the spin. Called within tick.
+    */
+    void ArtificialController::spin()
+    {
+            this->moveToTargetPosition();
+            this->getControllableEntity()->rotateRoll(0.8f);
+    }
+
+    /**
+        @brief Master begins to follow a pawn. Is a "specific master action".
+        @param pawn pawn to follow.
+        @param alaways follows pawn forever if true (false if omitted).
+        @param secondsToFollow seconds to follow the pawn if always is false. Will follow pawn 100 seconds if omitted (set in header).
+    */
+    void ArtificialController::followInit(Pawn* pawn, const bool always, const int secondsToFollow)
+    {
+        if (pawn == NULL || this->state_ != MASTER)
+            return;
+        this->specificMasterAction_  =  FOLLOW;
+
+        this->setTarget(pawn);
+        if (!always)
+            this->specificMasterActionHoldCount_ = secondsToFollow;
+        else
+            this->specificMasterActionHoldCount_ = INT_MAX; //for now...
+
+    }
+
+
+    /**
+        @brief Master begins to follow a randomly chosen human player of the same team. Is a "specific master action".
+    */
+    void ArtificialController::followRandomHumanInit()
+    {
+
+        Pawn *humanPawn = NULL;
+        NewHumanController *currentHumanController = NULL;
+
+        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
+        {
+            if (!it->getController())
+                continue;
+
+            currentHumanController = orxonox_cast<NewHumanController*>(it->getController());
+            if(currentHumanController)
+            {
+                if (!ArtificialController::sameTeam(this->getControllableEntity(), *it, this->getGametype())) continue;
+                humanPawn = *it;
+                break;
+            }
+        }
+
+        if((humanPawn != NULL))
+                this->followInit(humanPawn);
+    }
+
+    /**
+        @brief Master follows target with adjusted speed. Called within tick.
+    */
+    void ArtificialController::follow()
+    {
+        if (this->target_)
+            this->moveToPosition(this->target_->getPosition());
+        else
+            this->specificMasterActionHoldCount_ = 0;
+/*
+        if (!this->getControllableEntity())
+            return;
+
+        float distance = (this->target_->getPosition() - this->getControllableEntity()->getPosition()).length();
+
+        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, this->target_->getPosition());
+
+
+        this->getControllableEntity()->rotateYaw(-0.8f * sgn(coord.x) * coord.x*coord.x);
+        this->getControllableEntity()->rotatePitch(0.8f * sgn(coord.y) * coord.y*coord.y);
+
+        float speedDiv = this->getControllableEntity()->getVelocity().squaredLength() - this->target_->getVelocity().squaredLength();
+
+COUT(0) << "~follow distance: " << distance << "SpeedCounter: " << this->speedCounter_ << "~speedDiv: " << speedDiv << std::endl;
+        if (distance < 800)
+        {
+            if (distance < 200)
+            {
+                this->speedCounter_ -= 0.5f;
+                if(this->speedCounter_ < 0) this->speedCounter_ = 0.0f;
+                this->getControllableEntity()->moveFrontBack(speedCounter_);
+            } else {
+                if(speedDiv < 0)
+                    this->speedCounter_ +=  0.01f;
+                else
+                    this->speedCounter_ -= 0.05f;
+                this->getControllableEntity()->moveFrontBack(speedCounter_);
+            }
+
+        } else {
+            this->speedCounter_ += 0.05f;
+            this->getControllableEntity()->moveFrontBack(speedCounter_ + distance/300.0f);
+        }
+//         if (this->getControllableEntity()->getVelocity().squaredLength() > 50.0f) this->speedCounter_ = 0;
+
+*/
+    }
+
+
+    /**
+        @brief Slave moving behaviour when master is following a pawn, gets redirected from moveToPosition(const Vector3& target)). Called within tick.
+    */
+    void ArtificialController::followForSlaves(const Vector3& target)
+    {
+
+/*
+        if (!this->getControllableEntity() && !this->myMaster_ && this->myMaster_->state_ != FOLLOW && !this->myMaster_->target_)
+            return;
+
+        float distance = (target - this->getControllableEntity()->getPosition()).length();
+
+        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, target);
+
+
+        this->getControllableEntity()->rotateYaw(-0.8f * sgn(coord.x) * coord.x*coord.x);
+        this->getControllableEntity()->rotatePitch(0.8f * sgn(coord.y) * coord.y*coord.y);
+
+
+        float speedDiv = this->getControllableEntity()->getVelocity().squaredLength() - this->myMaster_->target_->getVelocity().squaredLength();
+
+
+         if (distance < 800)
+        {
+            if (distance < 200)
+            {
+                this->speedCounter_ -= 5.0f;
+                if(this->speedCounter_ < 0) this->speedCounter_ = 0.0f;
+                this->getControllableEntity()->moveFrontBack(speedCounter_);
+            } else {
+                if(speedDiv < 0)
+                    this->speedCounter_ +=  0.01f;
+                else
+                    this->speedCounter_ -= 0.05f;
+                this->getControllableEntity()->moveFrontBack(speedCounter_);
+            }
+
+        } else {
+            this->speedCounter_ += 0.05f;
+            this->getControllableEntity()->moveFrontBack(speedCounter_ + distance/300.0f);
+        }
+//         if (this->getControllableEntity()->getVelocity().squaredLength() > 50.0f) this->speedCounter_ = 0;
+*/
+    }
+
 
     void ArtificialController::setTargetPosition(const Vector3& target)
@@ -111,4 +836,8 @@
         {
             if (ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
+                continue;
+
+            /* So AI won't choose invisible Spaceships as target */
+            if (!it->getRadarVisibility())
                 continue;
 
@@ -144,5 +873,5 @@
         this->bHasTargetPosition_ = (this->targetPosition_ != Vector3::ZERO);
 
-        Pawn* pawn = dynamic_cast<Pawn*>(this->getControllableEntity());
+        Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
         if (pawn)
             pawn->setAimPosition(this->targetPosition_);
@@ -188,15 +917,25 @@
         int team2 = -1;
 
-        if (entity1->getXMLController())
-        {
-            WaypointPatrolController* wpc = orxonox_cast<WaypointPatrolController*>(entity1->getXMLController());
-            if (wpc)
-                team1 = wpc->getTeam();
-        }
-        if (entity2->getXMLController())
-        {
-            WaypointPatrolController* wpc = orxonox_cast<WaypointPatrolController*>(entity2->getXMLController());
-            if (wpc)
-                team2 = wpc->getTeam();
+        Controller* controller = 0;
+        if (entity1->getController())
+            controller = entity1->getController();
+        else
+            controller = entity1->getXMLController();
+        if (controller)
+        {
+            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
+            if (ac)
+                team1 = ac->getTeam();
+        }
+
+        if (entity2->getController())
+            controller = entity2->getController();
+        else
+            controller = entity2->getXMLController();
+        if (controller)
+        {
+            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
+            if (ac)
+                team2 = ac->getTeam();
         }
 
@@ -245,4 +984,34 @@
         }
 
+        DroneController* droneController = 0;
+        droneController = orxonox_cast<DroneController*>(entity1->getController());
+        if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity2)
+            return true;
+        droneController = orxonox_cast<DroneController*>(entity2->getController());
+        if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity1)
+            return true;
+        DroneController* droneController1 = orxonox_cast<DroneController*>(entity1->getController());
+        DroneController* droneController2 = orxonox_cast<DroneController*>(entity2->getController());
+        if (droneController1 && droneController2 && droneController1->getOwner() == droneController2->getOwner())
+            return true;
+
+        Dynamicmatch* dynamic = orxonox_cast<Dynamicmatch*>(gametype);
+        if (dynamic)
+        {
+            if (dynamic->notEnoughPigs||dynamic->notEnoughKillers||dynamic->notEnoughChasers) {return false;}
+
+            if (entity1->getPlayer())
+                team1 = dynamic->getParty(entity1->getPlayer());
+
+            if (entity2->getPlayer())
+                team2 = dynamic->getParty(entity2->getPlayer());
+
+            if (team1 ==-1 ||team2 ==-1 ) {return false;}
+            else if (team1 == dynamic->chaser && team2 != dynamic->chaser) {return false;}
+            else if (team1 == dynamic->piggy && team2 == dynamic->chaser) {return false;}
+            else if (team1 == dynamic->killer && team2 == dynamic->chaser) {return false;}
+            else return true;
+        }
+
         return (team1 == team2 && team1 != -1);
     }
Index: code/trunk/src/orxonox/controllers/ArtificialController.h
===================================================================
--- code/trunk/src/orxonox/controllers/ArtificialController.h	(revision 6906)
+++ code/trunk/src/orxonox/controllers/ArtificialController.h	(revision 7163)
@@ -23,5 +23,5 @@
  *      Fabian 'x3n' Landau
  *   Co-authors:
- *      ...
+ *      Dominik Solenicki
  *
  */
@@ -32,6 +32,9 @@
 #include "OrxonoxPrereqs.h"
 
+#include <vector>
+
 #include "util/Math.h"
 #include "Controller.h"
+#include "controllers/NewHumanController.h"
 
 namespace orxonox
@@ -43,11 +46,76 @@
             virtual ~ArtificialController();
 
+            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
+
             void abandonTarget(Pawn* target);
 
+            inline void setTeam(int team)
+                { this->team_ = team; }
+            inline int getTeam() const
+                { return this->team_; }
+
+            inline void setFormationFlight(bool formation)
+                { this->formationFlight_ = formation; }
+            inline bool getFormationFlight() const
+                { return this->formationFlight_; }
+
+            inline void setFormationSize(int size)
+                { this->maxFormationSize_ = size; }
+            inline int getFormationSize() const
+                { return this->maxFormationSize_; }
+
+            inline void setPassive(bool passive)
+                { this->passive_ = passive; }
+            inline bool getPassive() const
+                { return this->passive_; }
+
+            virtual void changedControllableEntity();
+
+            static void formationflight(const bool form);
+            static void masteraction(const int action);
+            static void followme();
+            static void passivebehaviour(const bool passive);
+            static void formationsize(const int size);
+
         protected:
-            void targetDied();
+
+            int team_;
+            bool formationFlight_;
+            bool passive_;
+            unsigned int maxFormationSize_;
+            int freedomCount_;
+            enum State {SLAVE, MASTER, FREE};
+            State state_;
+            std::vector<ArtificialController*> slaves_;
+            ArtificialController *myMaster_;
+            enum SpecificMasterAction {NONE, HOLD, SPIN, TURN180, FOLLOW};
+            SpecificMasterAction specificMasterAction_;
+            int specificMasterActionHoldCount_;
+            float speedCounter_; //for speed adjustment when following
 
             void moveToPosition(const Vector3& target);
             void moveToTargetPosition();
+
+            void removeFromFormation();
+            void unregisterSlave();
+            void searchNewMaster();
+            void commandSlaves();
+            void setNewMasterWithinFormation();
+
+            void freeSlaves();
+            void forceFreeSlaves();
+            void loseMasterState();
+            void forceFreedom();
+            bool forcedFree();
+
+            void specificMasterActionHold();
+            void turn180Init();
+            void turn180();
+            void spinInit();
+            void spin();
+            void followInit(Pawn* pawn, const bool always = false, const int secondsToFollow = 100);
+            void followRandomHumanInit();
+            void follow();
+            void followForSlaves(const Vector3& target);
 
             void setTargetPosition(const Vector3& target);
@@ -61,4 +129,6 @@
             bool isCloseAtTarget(float distance) const;
             bool isLookingAtTarget(float angle) const;
+
+            void targetDied();
 
             static bool sameTeam(ControllableEntity* entity1, ControllableEntity* entity2, Gametype* gametype); // hack
Index: code/trunk/src/orxonox/controllers/CMakeLists.txt
===================================================================
--- code/trunk/src/orxonox/controllers/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/orxonox/controllers/CMakeLists.txt	(revision 7163)
@@ -8,3 +8,4 @@
   WaypointController.cc
   WaypointPatrolController.cc
+  DroneController.cc
 )
Index: code/trunk/src/orxonox/controllers/DroneController.cc
===================================================================
--- code/trunk/src/orxonox/controllers/DroneController.cc	(revision 7163)
+++ code/trunk/src/orxonox/controllers/DroneController.cc	(revision 7163)
@@ -0,0 +1,149 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oli Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "DroneController.h"
+#include "worldentities/Drone.h"
+#include "util/Math.h"
+
+#include "core/CoreIncludes.h"
+#include "core/Executor.h"
+#include "worldentities/ControllableEntity.h"
+
+namespace orxonox
+{
+    /**
+    @brief
+        Constructor.
+    */
+    CreateFactory(DroneController);
+
+    static const float ACTION_INTERVAL = 1.0f;
+
+    DroneController::DroneController(BaseObject* creator) : ArtificialController(creator)
+    {
+        RegisterObject(DroneController);
+
+        this->owner_ = 0;
+        this->drone_ = 0;
+        this->isShooting_ = false;
+
+        this->actionTimer_.setTimer(ACTION_INTERVAL, true, createExecutor(createFunctor(&DroneController::action, this)));
+
+        this->owner_.setCallback(createFunctor(&DroneController::ownerDied, this));
+    }
+
+    DroneController::~DroneController()
+    {
+    }
+
+    void DroneController::setOwner(Pawn* owner){
+        this->owner_ = owner;
+    }
+
+    void DroneController::setDrone(Drone* drone)
+    {
+        this->drone_ = drone;
+        this->setControllableEntity(drone);
+    }
+
+    void DroneController::action()
+    {
+        float random;
+        float maxrand = 100.0f / ACTION_INTERVAL;
+        float distanceToTargetSquared = 0;
+
+        if (this->target_)
+            distanceToTargetSquared = (getDrone()->getWorldPosition() - this->target_->getWorldPosition()).squaredLength();
+
+        random = rnd(maxrand);
+        if ( random < 30 || (!this->target_) || distanceToTargetSquared > (this->getDrone()->getMaxShootingRange()*this->getDrone()->getMaxShootingRange()))
+            this->searchNewTarget();
+    }
+
+    /**
+    @brief
+        The controlling happens here. This method defines what the controller has to do each tick.
+    @param dt
+        The duration of the tick.
+    */
+    void DroneController::tick(float dt)
+    {
+        if (this->getDrone() && this->getOwner())
+        {
+            if (this->target_)
+            {
+                float distanceToTargetSquared = (this->getDrone()->getWorldPosition() - this->target_->getWorldPosition()).squaredLength();
+                if (distanceToTargetSquared < (this->getDrone()->getMaxShootingRange()*this->getDrone()->getMaxShootingRange()))
+                {
+                    this->isShooting_ = true;
+                    this->aimAtTarget();
+                    this->getDrone()->fire(0);
+                }
+            }
+
+            float maxDistanceSquared = this->getDrone()->getMaxDistanceToOwner()*this->getDrone()->getMaxDistanceToOwner();
+            float minDistanceSquared = this->getDrone()->getMinDistanceToOwner()*this->getDrone()->getMinDistanceToOwner();
+            if ((this->getDrone()->getWorldPosition() - this->getOwner()->getWorldPosition()).squaredLength()  > maxDistanceSquared)
+            {
+                this->moveToPosition(this->getOwner()->getWorldPosition()); //fly towards owner
+            }
+            else if((this->getDrone()->getWorldPosition() - this->getOwner()->getWorldPosition()).squaredLength() < minDistanceSquared)
+            {
+                this->moveToPosition(-this->getOwner()->getWorldPosition()); //fly away from owner
+            }
+            else if (!this->isShooting_)
+            {
+                float random = rnd(2.0f);
+                float randomSelection = rnd(6.0f);
+                if((int)randomSelection==0) drone_->moveUpDown(random);
+                else if((int)randomSelection==1) drone_->moveRightLeft(random);
+                else if((int)randomSelection==2) drone_->moveFrontBack(random);
+                else if((int)randomSelection==3) drone_->rotateYaw(random);
+                else if((int)randomSelection==4) drone_->rotatePitch(random);
+                else if((int)randomSelection==5) drone_->rotateRoll(random);
+            }
+
+            this->isShooting_ = false;
+        }
+
+        SUPER(AIController, tick, dt);
+
+    }
+
+    void DroneController::ownerDied()
+    {
+//         if (this->target_) {            //Drone has some kind of Stockholm-Syndrom --> gets attached to Owners Killer
+//             this->setOwner(target_);
+//             this->searchNewTarget();
+//         }
+        if (this->drone_)
+            this->drone_->destroy();
+        else
+            this->destroy();
+    }
+}
Index: code/trunk/src/orxonox/controllers/DroneController.h
===================================================================
--- code/trunk/src/orxonox/controllers/DroneController.h	(revision 7163)
+++ code/trunk/src/orxonox/controllers/DroneController.h	(revision 7163)
@@ -0,0 +1,77 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oli Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _DroneController_H__
+#define _DroneController_H__
+
+#include "OrxonoxPrereqs.h"
+
+#include "AIController.h"
+#include "core/WeakPtr.h"
+#include "tools/interfaces/Tickable.h"
+
+#include "tools/Timer.h"
+
+
+namespace orxonox
+{
+    /**
+    @brief
+        Controller for the Drone of the PPS tutorial.
+    @author
+        Oli Scheuss
+    */
+    class _OrxonoxExport DroneController : public ArtificialController, public Tickable
+    {
+        public:
+            DroneController(BaseObject* creator);
+            virtual ~DroneController();
+
+            virtual void tick(float dt); //!< The controlling happens here. This method defines what the controller has to do each tick.
+
+            void setOwner(Pawn* owner);
+            inline Pawn* getOwner() const
+                { return this->owner_; }
+
+            void setDrone(Drone*  drone);
+            inline Drone* getDrone() const
+                { return this->drone_; }
+
+        protected:
+            virtual void action();
+            void ownerDied();
+            bool isShooting_;
+
+        private:
+            Timer actionTimer_;
+            WeakPtr<Pawn> owner_;
+            Drone* drone_;
+    };
+}
+
+#endif /* _DroneController_H__ */
Index: code/trunk/src/orxonox/controllers/HumanController.cc
===================================================================
--- code/trunk/src/orxonox/controllers/HumanController.cc	(revision 6906)
+++ code/trunk/src/orxonox/controllers/HumanController.cc	(revision 7163)
@@ -35,5 +35,4 @@
 #include "gametypes/Gametype.h"
 #include "infos/PlayerInfo.h"
-#include "overlays/Map.h"
 #include "Radar.h"
 #include "Scene.h"
@@ -116,10 +115,4 @@
     void HumanController::yaw(const Vector2& value)
     {
-        //Hack to enable mouselook in map
-        if ( Map::getSingletonPtr() && Map::getSingletonPtr()->getVisibility() && HumanController::localController_s->controllableEntity_->isInMouseLook() )
-        {
-            Map::getSingletonPtr()->rotateYaw(value);
-            return;
-        }
         if (HumanController::localController_s && HumanController::localController_s->controllableEntity_)
             HumanController::localController_s->controllableEntity_->rotateYaw(value);
@@ -128,10 +121,4 @@
     void HumanController::pitch(const Vector2& value)
     {
-        //Hack to enable mouselook in map
-        if ( Map::getSingletonPtr() && Map::getSingletonPtr()->getVisibility() && HumanController::localController_s->controllableEntity_->isInMouseLook() )
-        {
-            Map::getSingletonPtr()->rotatePitch(value);
-            return;
-        }
         if (HumanController::localController_s && HumanController::localController_s->controllableEntity_)
             HumanController::localController_s->controllableEntity_->rotatePitch(value);
Index: code/trunk/src/orxonox/controllers/NewHumanController.cc
===================================================================
--- code/trunk/src/orxonox/controllers/NewHumanController.cc	(revision 6906)
+++ code/trunk/src/orxonox/controllers/NewHumanController.cc	(revision 7163)
@@ -217,4 +217,9 @@
                     if (this->getControllableEntity() && (this->getControllableEntity()->isExactlyA(ClassByString("SpaceShip")) || this->getControllableEntity()->isExactlyA(ClassByString("Rocket"))))
                         this->showOverlays();
+                    else if (this->getControllableEntity() &&  this->getControllableEntity()->isExactlyA(ClassByString("FpsPlayer")))
+                    {
+                        this->showOverlays();
+                        this->hideArrows();
+                    }
 
                     this->crossHairOverlay_->setPosition(Vector2(static_cast<float>(this->currentYaw_)/2*-1+.5f-overlaySize_/2, static_cast<float>(this->currentPitch_)/2*-1+.5f-overlaySize_/2));
@@ -364,12 +369,27 @@
         Ogre::RaySceneQueryResult& result = rsq->execute();
         Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
+        WorldEntity* myWe = static_cast<WorldEntity*>(this->getControllableEntity());
 
         Ogre::RaySceneQueryResult::iterator itr;
         for (itr = result.begin(); itr != result.end(); ++itr)
         {
-            if (itr->movable->isInScene() && itr->movable->getMovableType() == "Entity" && itr->distance > 500)
+//             CCOUT(0) << "testing object as target" << endl;
+            if (itr->movable->isInScene() && itr->movable->getMovableType() == "Entity" /*&& itr->distance > 500*/)
             {
                 // Try to cast the user pointer
-                WorldEntity* wePtr = dynamic_cast<WorldEntity*>(Ogre::any_cast<OrxonoxClass*>(itr->movable->getUserAny()));
+                WorldEntity* wePtr;
+                try
+                {
+                    wePtr = dynamic_cast<WorldEntity*>(Ogre::any_cast<OrxonoxClass*>(itr->movable->getUserAny()));
+                }
+                catch (...)
+                {
+                    continue;
+                }
+
+                // make sure we don't shoot ourselves
+                if( wePtr==myWe )
+                    continue;
+
                 if (wePtr)
                 {
@@ -379,5 +399,5 @@
                     while (parent)
                     {
-                        if (this->targetMask_.isExcluded(parent->getIdentifier()))
+                        if (this->targetMask_.isExcluded(parent->getIdentifier()) || parent==myWe)
                         {
                             parent = parent->getParent();
@@ -430,5 +450,6 @@
             HumanController::yaw(value);
 
-        this->currentYaw_ = value.x;
+        if (this->getControllableEntity() && !this->getControllableEntity()->isExactlyA(ClassByString("FpsPlayer")))
+            this->currentYaw_ = value.x;
     }
 
@@ -439,5 +460,6 @@
             HumanController::pitch(value);
 
-        this->currentPitch_ = value.x;
+        if (this->getControllableEntity() && !this->getControllableEntity()->isExactlyA(ClassByString("FpsPlayer")))
+            this->currentPitch_ = value.x;
     }
 
@@ -579,3 +601,8 @@
         }
     }
+
+
+
+
+
 }
Index: code/trunk/src/orxonox/controllers/NewHumanController.h
===================================================================
--- code/trunk/src/orxonox/controllers/NewHumanController.h	(revision 6906)
+++ code/trunk/src/orxonox/controllers/NewHumanController.h	(revision 7163)
@@ -67,4 +67,5 @@
             virtual void doResumeControl();
 
+
         protected:
             void updateTarget();
Index: code/trunk/src/orxonox/controllers/WaypointPatrolController.cc
===================================================================
--- code/trunk/src/orxonox/controllers/WaypointPatrolController.cc	(revision 6906)
+++ code/trunk/src/orxonox/controllers/WaypointPatrolController.cc	(revision 7163)
@@ -42,5 +42,5 @@
         RegisterObject(WaypointPatrolController);
 
-        this->team_ = 0;
+        //this->team_ = 0;
         this->alertnessradius_ = 500;
 
@@ -53,5 +53,5 @@
 
         XMLPortParam(WaypointPatrolController, "alertnessradius", setAlertnessRadius, getAlertnessRadius, xmlelement, mode).defaultValues(500.0f);
-        XMLPortParam(WaypointPatrolController, "team", setTeam, getTeam, xmlelement, mode).defaultValues(0);
+//        XMLPortParam(WaypointPatrolController, "team", setTeam, getTeam, xmlelement, mode).defaultValues(0);
     }
 
Index: code/trunk/src/orxonox/controllers/WaypointPatrolController.h
===================================================================
--- code/trunk/src/orxonox/controllers/WaypointPatrolController.h	(revision 6906)
+++ code/trunk/src/orxonox/controllers/WaypointPatrolController.h	(revision 7163)
@@ -46,8 +46,8 @@
             virtual void tick(float dt);
 
-            inline void setTeam(int team)
+           /* inline void setTeam(int team)
                 { this->team_ = team; }
             inline int getTeam() const
-                { return this->team_; }
+                { return this->team_; } */
 
             inline void setAlertnessRadius(float radius)
@@ -59,5 +59,5 @@
             void searchEnemy();
 
-            int team_;
+            //int team_;
             float alertnessradius_;
             Timer patrolTimer_;
Index: code/trunk/src/orxonox/gamestates/GSClient.cc
===================================================================
--- code/trunk/src/orxonox/gamestates/GSClient.cc	(revision 6906)
+++ code/trunk/src/orxonox/gamestates/GSClient.cc	(revision 7163)
@@ -40,9 +40,8 @@
     DeclareGameState(GSClient, "client", false, false);
 
-    SetCommandLineArgument(ip, "127.0.0.1").information("Sever IP as string in the form #.#.#.#");
+    SetCommandLineArgument(dest, "127.0.0.1").information("Server hostname/IP (IP in the form of #.#.#.#)");
 
     GSClient::GSClient(const GameStateInfo& info)
         : GameState(info)
-        , client_(0)
     {
     }
@@ -56,21 +55,21 @@
         GameMode::setIsClient(true);
 
-        this->client_ = new Client(CommandLineParser::getValue("ip").getString(), CommandLineParser::getValue("port"));
+//         this->client_ = new Client();
+//         this->client_->setDestination(CommandLineParser::getValue("dest").getString(), CommandLineParser::getValue("port") );
 
-        if(!client_->establishConnection())
+        if( !Client::getInstance()->establishConnection() )
         {
-            delete this->client_;
             ThrowException(InitialisationFailed, "Could not establish connection with server.");
         }
 
-        client_->update(Game::getInstance().getGameClock());
+        Client::getInstance()->update(Game::getInstance().getGameClock());
     }
 
     void GSClient::deactivate()
     {
-        client_->closeConnection();
+        Client::getInstance()->closeConnection();
 
         // destroy client
-        delete this->client_;
+//         delete this->client_;
 
         GameMode::setIsClient(false);
@@ -79,5 +78,5 @@
     void GSClient::update(const Clock& time)
     {
-        client_->update(time);
+        Client::getInstance()->update(time);
     }
 }
Index: code/trunk/src/orxonox/gamestates/GSClient.h
===================================================================
--- code/trunk/src/orxonox/gamestates/GSClient.h	(revision 6906)
+++ code/trunk/src/orxonox/gamestates/GSClient.h	(revision 7163)
@@ -46,7 +46,4 @@
         void deactivate();
         void update(const Clock& time);
-
-    private:
-        Client* client_;
     };
 }
Index: code/trunk/src/orxonox/gamestates/GSGraphics.cc
===================================================================
--- code/trunk/src/orxonox/gamestates/GSGraphics.cc	(revision 6906)
+++ code/trunk/src/orxonox/gamestates/GSGraphics.cc	(revision 7163)
@@ -39,6 +39,4 @@
 #include "core/Game.h"
 #include "core/GUIManager.h"
-// HACK:
-#include "overlays/Map.h"
 
 namespace orxonox
@@ -73,6 +71,5 @@
     void GSGraphics::deactivate()
     {
-        // HACK: (destroys a resource smart pointer)
-        Map::hackDestroyMap();
+
     }
 
Index: code/trunk/src/orxonox/gametypes/CMakeLists.txt
===================================================================
--- code/trunk/src/orxonox/gametypes/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/orxonox/gametypes/CMakeLists.txt	(revision 7163)
@@ -6,3 +6,4 @@
   UnderAttack.cc
   Asteroids.cc
+  Dynamicmatch.cc
 )
Index: code/trunk/src/orxonox/gametypes/Dynamicmatch.cc
===================================================================
--- code/trunk/src/orxonox/gametypes/Dynamicmatch.cc	(revision 7163)
+++ code/trunk/src/orxonox/gametypes/Dynamicmatch.cc	(revision 7163)
@@ -0,0 +1,699 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Johannes Ritz
+ *   Co-authors:
+ *      ...
+ *
+ */
+//TODO:
+//pig punkte vergeben pro Zeit!
+//killerfarbe schwarz; evtl. eigenes Raumfahrzeug;
+//Low; Codeoptimierung und Dokumentation
+
+/*
+short gaming manual:
+There are three different parties a player can belong to: victim, chaser or killer
+Every player starts as chaser. As long as there are not enough victims and killers, you can change your and other player's parties by shooting them.
+In order to win you have to earn as much points as possible:
+- as victim by escaping the chasers
+- as chaser by shooting the victim
+- as killer by killing the chasers
+
+
+What you shouldn't do is shooting at players of your own party. By doing so your score will decrease.
+P.S: If you don't want to be a victim: Get rid of your part by shooting a chaser.
+*/
+#include "Dynamicmatch.h"
+
+#include "util/Convert.h"
+#include "core/CoreIncludes.h"
+#include "network/Host.h"
+#include "infos/PlayerInfo.h"
+#include "worldentities/pawns/Pawn.h"
+#include "worldentities/pawns/SpaceShip.h"
+#include "core/ConfigValueIncludes.h"
+#include "interfaces/TeamColourable.h"
+#include "items/Engine.h"
+#include "tools/Timer.h"
+#include "worldentities/TeamSpawnPoint.h"
+
+namespace orxonox
+{
+    CreateUnloadableFactory(Dynamicmatch);
+
+    Dynamicmatch::Dynamicmatch(BaseObject* creator) : Gametype(creator)
+    {
+        RegisterObject(Dynamicmatch);
+        this->gameTime_ = 180;
+        this->setConfigValues();
+        this->chaser=0;
+        this->piggy=1;
+        this->killer=2;
+        this->notEnoughPigs=false;
+        this->notEnoughKillers=false;
+        this->notEnoughChasers=false;
+        this->gameEnded_ =false;
+        this->timesequence_ = static_cast<int>(this->gameTime_);
+        this->friendlyfire=true;
+        this->numberOf[chaser]=0;
+        this->numberOf[piggy]=0;
+        this->numberOf[killer]=0;
+        this->tutorial=true;
+        this->pointsPerTime=0.0f;
+        this->setHUDTemplate("DynamicmatchHUD");
+    }
+
+    void Dynamicmatch::setConfigValues()
+    {
+        SetConfigValue(gameTime_, 180);
+        SetConfigValue(friendlyfire, true);
+        SetConfigValue(tutorial, true);
+        static ColourValue colours[] =
+        {
+            ColourValue(1.0f, 0.3f, 0.3f),  //chasercolour
+            ColourValue(0.3f, 0.3f, 1.0f),  //piggycolour
+            ColourValue(0.3f, 1.0f, 0.3f)   //killercolour  what about black: 0.0f, 0.0f, 0.0f
+
+        };
+        static std::vector<ColourValue> defaultcolours(colours, colours + sizeof(colours) / sizeof(ColourValue));
+
+        SetConfigValue(partyColours_, defaultcolours);
+    }
+
+    bool Dynamicmatch::allowPawnDamage(Pawn* victim, Pawn* originator)
+    {
+        //TODO: static and fading message for the "human" player's
+        if (!originator||!victim)
+            return false;
+        if (!originator->getPlayer()||!victim->getPlayer())
+            return false;
+        if (victim && victim->getPlayer()) //&& originator && originator->getPlayer() ??
+        {
+        int target= playerParty_[victim->getPlayer()];
+        int source= playerParty_[originator->getPlayer()];
+
+            //Case: Not Enough Pigs: party change (= party management)
+            if (notEnoughPigs)
+            {
+                numberOf[target]--; //decrease numberof victims's party
+                playerParty_[victim->getPlayer()]=piggy; //victim's new party: pig
+                setPlayerColour(victim->getPlayer()); //victim's new colour
+                numberOf[piggy]++; //party switch: number of players is not affected (decrease and increase)
+
+                    if(tutorial) //announce party switch
+                    {
+                         std::map<PlayerInfo*, Player>::iterator it2 = this->players_.find(victim->getPlayer());
+                         if (it2 != this->players_.end())
+                         {
+                              this->gtinfo_->sendStaticMessage("Either hide or shoot a chaser.",it2->first->getClientID(), partyColours_[chaser]);
+                              this->gtinfo_->sendFadingMessage("You're now a victim.",it2->first->getClientID());
+                         }
+                    }
+                    if (notEnoughKillers) //reward the originator
+                    {
+                        numberOf[source]--; //decrease numberof originator's party
+                        playerParty_[originator->getPlayer()]=killer; //originator's new party: killer
+                        setPlayerColour(originator->getPlayer()); //originator's new colour
+                        numberOf[killer]++;
+
+                        if(tutorial) //announce party switch
+                        {
+                             std::map<PlayerInfo*, Player>::iterator it3 = this->players_.find(originator->getPlayer());
+                             if (it3 != this->players_.end())
+                             {
+                                  this->gtinfo_->sendStaticMessage("Take the chasers down.",it3->first->getClientID(), partyColours_[chaser]);
+                                  this->gtinfo_->sendFadingMessage("You're now a killer.",it3->first->getClientID());
+                             }
+                        }
+                    }
+                evaluatePlayerParties(); //check if the party change has to trigger futher party changes
+
+                //Give new pig boost
+                SpaceShip* spaceship = dynamic_cast<SpaceShip*>(victim);
+                if (spaceship && spaceship->getEngine())
+                {
+                    spaceship->getEngine()->setSpeedFactor(5);
+                    WeakPtr<Engine>* ptr = new WeakPtr<Engine>(spaceship->getEngine());
+                    new Timer(10, false, &createExecutor(createFunctor(&Dynamicmatch::resetSpeedFactor, this))->setDefaultValue(0, ptr), true);
+                }
+            }
+
+            //Case: notEnoughKillers: party change
+            else if (notEnoughKillers)
+            {
+                numberOf[source]--; //decrease numberof originator's party
+                playerParty_[originator->getPlayer()]=killer; //originator's new party: killer
+                setPlayerColour(originator->getPlayer()); //originator colour
+                numberOf[killer]++; //party switch: number of players is not affected (decrease and increase)
+
+
+                if(tutorial) //announce party switch
+                {
+                     std::map<PlayerInfo*, Player>::iterator it3 = this->players_.find(originator->getPlayer());
+                     if (it3 != this->players_.end())
+                     {
+                          this->gtinfo_->sendStaticMessage("Take the chasers down.",it3->first->getClientID(),partyColours_[chaser]);
+                          this->gtinfo_->sendFadingMessage("You're now a killer.",it3->first->getClientID());
+                     }
+                }
+                evaluatePlayerParties(); //check if the party change has to trigger futher party changes
+            }
+            //Case: notEnoughChasers: party change
+            else if (notEnoughChasers)
+            {
+                numberOf[target]--; //decrease numberof victims's party
+                playerParty_[victim->getPlayer()]=chaser; //victim's new party: chaser
+                setPlayerColour(victim->getPlayer()); //victim colour
+                numberOf[chaser]++; //party switch: number of players is not affected (decrease and increase)
+
+                if(tutorial) //announce party switch
+                {
+                     std::map<PlayerInfo*, Player>::iterator it3 = this->players_.find(originator->getPlayer());
+                     if (it3 != this->players_.end())
+                     {
+                          if (numberOf[killer]>0)
+                              this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible. Defend yourself against the killers.",it3->first->getClientID(),partyColours_[piggy]);
+
+                          else
+                              this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible.",it3->first->getClientID(),partyColours_[piggy]);
+                          this->gtinfo_->sendFadingMessage("You're now a chaser.",it3->first->getClientID());
+                     }
+                }
+                evaluatePlayerParties(); //check if the party change has to trigger futher party changes
+            }
+
+            //Case: chaser vs. killer
+            else if ((source == killer && target == chaser)||(target == killer && source == chaser ))
+            {
+                return true;
+            }
+
+            //Case: a chaser hits piggy
+            else if ((source==chaser)&&(target==piggy))
+            {
+                std::map<PlayerInfo*, Player>::iterator it = this->players_.find(originator->getPlayer());
+                if (it != this->players_.end())
+                    {
+                        it->second.frags_++;
+                    }
+            }
+            //Case: piggy hits chaser
+            else if (source==piggy&&target==chaser)
+            {
+                //partyswitch: victim bcomes piggy and the originator(piggy) becomes chaser
+                playerParty_[victim->getPlayer()]=piggy;
+                playerParty_[originator->getPlayer()]=chaser;
+
+                //party switch -> colour switch
+                setPlayerColour(victim->getPlayer()); //victim colour
+                setPlayerColour(originator->getPlayer());//originator colour
+
+                //Announce pary switch
+                if(tutorial)
+                {
+                     std::map<PlayerInfo*, Player>::iterator it = this->players_.find(originator->getPlayer());
+                     if (it != this->players_.end())
+                     {
+                          if (numberOf[killer]>0)
+                              this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible. Defend yourself against the killers.",it->first->getClientID(), partyColours_[piggy]);
+                          else
+                              this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible.",it->first->getClientID(),partyColours_[piggy]);
+                          this->gtinfo_->sendFadingMessage("You're now a chaser.",it->first->getClientID());
+                     }
+                     std::map<PlayerInfo*, Player>::iterator it2 = this->players_.find(victim->getPlayer());
+                     if (it2 != this->players_.end())
+                     {
+                          this->gtinfo_->sendStaticMessage("Either hide or shoot a chaser.",it2->first->getClientID(),partyColours_[chaser]);
+                          this->gtinfo_->sendFadingMessage("You're now a victim.",it2->first->getClientID());
+                     }
+                }
+                //Give new pig boost
+                SpaceShip* spaceship = dynamic_cast<SpaceShip*>(victim);
+                if (spaceship && spaceship->getEngine())
+                {
+                    spaceship->getEngine()->setSpeedFactor(5);
+                    WeakPtr<Engine>* ptr = new WeakPtr<Engine>(spaceship->getEngine());
+                    new Timer(10, false, &createExecutor(createFunctor(&Dynamicmatch::resetSpeedFactor, this))->setDefaultValue(0, ptr), true);
+                }
+
+            }
+            // killer vs piggy
+            else if (source==killer &&target==piggy) //party and colour switch
+            {
+            playerParty_[victim->getPlayer()]=killer;
+            playerParty_[originator->getPlayer()]=piggy;
+
+            setPlayerColour(victim->getPlayer()); //victim colour
+            setPlayerColour(originator->getPlayer()); //originator colour
+
+            if(tutorial) //Announce pary switch
+            {
+                 std::map<PlayerInfo*, Player>::iterator it = this->players_.find(originator->getPlayer());
+                 if (it != this->players_.end())
+                 {
+                      this->gtinfo_->sendStaticMessage("Either hide or shoot a chaser.",it->first->getClientID(),partyColours_[chaser]);
+                      this->gtinfo_->sendFadingMessage("You're now a victim.",it->first->getClientID());
+                 }
+                 std::map<PlayerInfo*, Player>::iterator it2 = this->players_.find(victim->getPlayer());
+                 if (it2 != this->players_.end())
+                 {
+                      this->gtinfo_->sendStaticMessage("Take the chasers down.",it2->first->getClientID(),partyColours_[chaser]);
+                      this->gtinfo_->sendFadingMessage("You're now a killer.",it2->first->getClientID());
+                 }
+                }
+            }
+            //Case: friendly fire
+            else if (friendlyfire && (source == target))
+            {
+                std::map<PlayerInfo*, Player>::iterator it = this->players_.find(originator->getPlayer());
+                if (it != this->players_.end())
+                    {
+                        it->second.frags_--;
+                    }
+            }
+        }// from far far away not to be removed!
+        return false; //default: no damage
+    }
+
+
+
+    bool Dynamicmatch::allowPawnDeath(Pawn* victim, Pawn* originator)
+    {
+        //killers can kill chasers and killers can be killed by chasers
+        if ((playerParty_[originator->getPlayer()] == killer && playerParty_[victim->getPlayer()] == chaser)||(playerParty_[victim->getPlayer()] == killer &&
+        playerParty_[originator->getPlayer()] == chaser ))
+        {
+            if (playerParty_[originator->getPlayer()] == killer) //reward the killer
+            {
+                std::map<PlayerInfo*, Player>::iterator it = this->players_.find(originator->getPlayer());
+                if (it != this->players_.end())
+                {
+                    it->second.frags_+=20; //value must be tested
+                }
+            }
+        return true;
+        }
+        else return false;
+    }
+
+    void Dynamicmatch::playerStartsControllingPawn(PlayerInfo* player, Pawn* pawn) //set party + colouring
+    {
+        if (!player)
+            return;
+
+        Dynamicmatch::setPlayerColour(player); //Set playercolour
+        evaluatePlayerParties();
+    }
+
+    void Dynamicmatch::playerEntered(PlayerInfo* player) //standardfunction
+    {
+        if (!player)// only for safety
+            return;
+        playerParty_[player]=chaser; //Set playerparty
+        numberOf[chaser]++;
+        Gametype::playerEntered(player);
+        const std::string& message6 = player->getName() + " entered the game";
+        COUT(0) << message6 << std::endl;
+        Host::Broadcast(message6);
+    }
+
+    bool Dynamicmatch::playerLeft(PlayerInfo* player) //standardfunction
+    {
+        bool valid_player = Gametype::playerLeft(player);
+        if (valid_player)
+        {
+            switch (playerParty_[player])
+            {
+            case 0: numberOf[chaser]--; break;
+            case 1: numberOf[piggy]--; break;
+            case 2: numberOf[killer]--; break;
+            }
+            const std::string& message = player->getName() + " left the game";
+            COUT(0) << message << std::endl;
+            Host::Broadcast(message);
+            //remove player from map
+            playerParty_.erase (player);
+            //adjust player parties
+            evaluatePlayerParties();
+        }
+
+        return valid_player;
+    }
+
+
+    void Dynamicmatch::tick(float dt)
+    {
+        SUPER(Dynamicmatch, tick, dt);
+
+        if (this->hasStarted() && !gameEnded_)
+        {   pointsPerTime =pointsPerTime + dt;
+            gameTime_ = gameTime_ - dt;
+            if (pointsPerTime > 2.0f)//hard coded!! should be changed
+            {
+                pointsPerTime=0.0f;
+                rewardPig();
+            }
+            if (gameTime_<= 0)
+            {
+                this->gameEnded_ = true;
+                this->end();
+            }
+            if ( gameTime_ <= timesequence_ && gameTime_ > 0)
+            {
+                const std::string& message = multi_cast<std::string>(timesequence_) + " seconds left!";
+
+                this->gtinfo_->sendAnnounceMessage(message);
+
+                if (timesequence_ >= 30 && timesequence_ <= 60)
+                {
+                    timesequence_ = timesequence_ - 10;
+                }
+                else if (timesequence_ <= 30)
+                {
+                    timesequence_ = timesequence_ - 5;
+                }
+                else
+                {
+                    timesequence_ = timesequence_ - 30;
+                }
+            }
+        }
+    }
+
+    void Dynamicmatch::rewardPig()
+    {
+        for (std::map< PlayerInfo*, int >::iterator it = this->playerParty_.begin(); it != this->playerParty_.end(); ++it) //durch alle Spieler iterieren und alle piggys finden
+        {
+            if (it->second==piggy)
+            {
+                 //Spieler mit der Pig-party frags++
+                 std::map<PlayerInfo*, Player>::iterator it2 = this->players_.find(it->first);// still not sure if right syntax
+                 if (it2 != this->players_.end())
+                 {
+                     it2->second.frags_++;
+                 }
+            }
+        }
+    }
+    void Dynamicmatch::setPlayerColour(PlayerInfo* player) // sets a player's colour
+    {
+        std::map<PlayerInfo*, int>::const_iterator it_player = this->playerParty_.find(player);
+        Pawn* pawn = dynamic_cast<Pawn*>(player->getControllableEntity());
+            if (pawn)
+            {
+                pawn->setRadarObjectColour(this->partyColours_[it_player->second]);
+
+                std::set<WorldEntity*> pawnAttachments = pawn->getAttachedObjects();
+                for (std::set<WorldEntity*>::iterator it = pawnAttachments.begin(); it != pawnAttachments.end(); ++it)
+                {
+                    if ((*it)->isA(Class(TeamColourable)))
+                    {
+                        TeamColourable* tc = orxonox_cast<TeamColourable*>(*it);
+                        tc->setTeamColour(this->partyColours_[it_player->second]);
+                    }
+                }
+            }
+    }
+
+    void Dynamicmatch::evaluatePlayerParties() //manages the notEnough booleans (here the percentage of special players is implemented)
+    {
+        //pigs: 1 + every 6th player is a pig
+        if ( (1+this->getNumberOfPlayers()/6) > numberOf[piggy])
+        {
+            notEnoughPigs=true;
+            if (tutorial) // Announce selectionphase
+            {
+             for (std::map<PlayerInfo*, int>::iterator it = this->playerParty_.begin(); it != this->playerParty_.end(); ++it)
+                {
+                    if (!it->first)//in order to catch nullpointer
+                        continue;
+                    if (it->first->getClientID() == CLIENTID_UNKNOWN)
+                        continue;
+                    this->gtinfo_->sendStaticMessage("Selection phase: Shoot at everything that moves.",it->first->getClientID(),ColourValue(1.0f, 1.0f, 0.5f));
+                }
+            }
+        }
+        else
+        {
+             notEnoughPigs=false;
+             if(tutorial&&(!notEnoughKillers)&&(!notEnoughChasers)) //Selection phase over
+             {
+                  for (std::map<PlayerInfo*, int>::iterator it = this->playerParty_.begin(); it != this->playerParty_.end(); ++it)
+                  {
+                       if (!it->first)//in order to catch nullpointer
+                           continue;
+                       if (it->first->getClientID() == CLIENTID_UNKNOWN)
+                           continue;
+                       else if (it->second==chaser)
+                       {
+                           if (numberOf[killer]>0)
+                               this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible. Defend yourself against the killers.",it->first->getClientID(),partyColours_[piggy]);
+                           else
+                               this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible.",it->first->getClientID(),partyColours_[piggy]);
+                           //this->gtinfo_->sendFadingMessage("You're now a chaser.",it->first->getClientID());
+                       }
+                       else if (it->second==piggy)
+                       {
+                           this->gtinfo_->sendStaticMessage("Either hide or shoot a chaser.",it->first->getClientID(),partyColours_[chaser]);
+                           //this->gtinfo_->sendFadingMessage("You're now a victim.",it->first->getClientID());
+                       }
+                       else if (it->second==killer)
+                       {
+                           this->gtinfo_->sendStaticMessage("Take the chasers down.",it->first->getClientID(),partyColours_[chaser]);
+                           //this->gtinfo_->sendFadingMessage("You're now a killer.",it->first->getClientID());
+                       }
+                  }
+
+             }
+        }
+        //killers: every 4th player is a killer
+        if (getNumberOfPlayers()/4 > numberOf[killer])
+        {
+            notEnoughKillers=true;
+            if (tutorial) // Announce selectionphase
+            {
+             for (std::map<PlayerInfo*, int>::iterator it = this->playerParty_.begin(); it != this->playerParty_.end(); ++it)
+                {
+                    if (!it->first)//in order to catch nullpointer
+                        continue;
+                    if (it->first->getClientID() == CLIENTID_UNKNOWN)
+                        continue;
+                    this->gtinfo_->sendStaticMessage("Selection phase: Shoot at everything that moves.",it->first->getClientID(),ColourValue(1.0f, 1.0f, 0.5f));
+                }
+            }
+        }
+        else
+        {
+            notEnoughKillers=false;
+            if(tutorial&&(!notEnoughPigs)&&(!notEnoughChasers)) //Selection phase over
+             {
+                  for (std::map<PlayerInfo*, int>::iterator it = this->playerParty_.begin(); it != this->playerParty_.end(); ++it)
+                  {
+                       if (!it->first)
+                           continue;
+                       if (it->first->getClientID() == CLIENTID_UNKNOWN)
+                           continue;
+                       else if (it->second==chaser)
+                       {
+                           if (numberOf[killer]>0)
+                               this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible. Defend yourself against the killers.",it->first->getClientID(),partyColours_[piggy]);
+                           else
+                               this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible.",it->first->getClientID(),partyColours_[piggy]);
+                           //this->gtinfo_->sendFadingMessage("You're now a chaser.",it->first->getClientID());
+                       }
+                       else if (it->second==piggy)
+                       {
+                           this->gtinfo_->sendStaticMessage("Either hide or shoot a chaser.",it->first->getClientID(),partyColours_[piggy]);
+                           //this->gtinfo_->sendFadingMessage("You're now a victim.",it->first->getClientID());
+                       }
+                       else if (it->second==killer)
+                       {
+                           this->gtinfo_->sendStaticMessage("Take the chasers down.",it->first->getClientID(),partyColours_[piggy]);
+                           //this->gtinfo_->sendFadingMessage("You're now a killer.",it->first->getClientID());
+                       }
+                  }
+
+             }
+
+        }
+        //chasers: there are more chasers than killers + pigs
+        if (numberOf[piggy]+numberOf[killer] > numberOf[chaser])
+        {
+            notEnoughChasers=true;
+            if (tutorial) // Announce selectionphase
+            {
+             for (std::map<PlayerInfo*, int>::iterator it = this->playerParty_.begin(); it != this->playerParty_.end(); ++it)
+                {
+                    if (!it->first)//in order to catch nullpointer
+                        continue;
+                    if (it->first->getClientID() == CLIENTID_UNKNOWN)
+                        continue;
+                    this->gtinfo_->sendStaticMessage("Selection phase: Shoot at everything that moves.",it->first->getClientID(),ColourValue(1.0f, 1.0f, 0.5f));
+                }
+            }
+        }
+        else
+        {
+             notEnoughChasers=false;
+             if(tutorial&&(!notEnoughPigs)&&(!notEnoughKillers)) //Selection phase over
+             {
+                  for (std::map<PlayerInfo*, int>::iterator it = this->playerParty_.begin(); it != this->playerParty_.end(); ++it)
+                  {
+                       if (!it->first)
+                           continue;
+                       if (it->first->getClientID() == CLIENTID_UNKNOWN)
+                           continue;
+                       else if (it->second==chaser)
+                       {
+                           if (numberOf[killer]>0)
+                               this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible. Defend yourself against the killers.",it->first->getClientID(),partyColours_[piggy]);
+                           else
+                               this->gtinfo_->sendStaticMessage("Shoot at the victim as often as possible.",it->first->getClientID(),partyColours_[piggy]);
+                           //this->gtinfo_->sendFadingMessage("You're now a chaser.",it->first->getClientID());
+                       }
+                       else if (it->second==piggy)
+                       {
+                           this->gtinfo_->sendStaticMessage("Either hide or shoot a chaser.",it->first->getClientID(),partyColours_[chaser]);
+                           //this->gtinfo_->sendFadingMessage("You're now a victim.",it->first->getClientID());
+                       }
+                       else if (it->second==killer)
+                       {
+                           this->gtinfo_->sendStaticMessage("Take the chasers down.",it->first->getClientID(),partyColours_[chaser]);
+                           //this->gtinfo_->sendFadingMessage("You're now a killer.",it->first->getClientID());
+                       }
+                  }
+
+             }
+        }
+    }
+
+    int Dynamicmatch::getParty(PlayerInfo* player) // helper function for ArtificialController
+    {
+        return this->playerParty_[player];
+    }
+
+    void Dynamicmatch::resetSpeedFactor(WeakPtr<Engine>* ptr)// helper function
+    {
+        if (*ptr)
+        {
+            (*ptr)->setSpeedFactor(1.0f);
+        }
+        delete ptr;
+    }
+
+    bool Dynamicmatch::playerChangedName(PlayerInfo* player) //standardfunction
+    {
+        bool valid_player = Gametype::playerChangedName(player);
+        if (valid_player)
+        {
+            const std::string& message = player->getOldName() + " changed name to " + player->getName();
+            COUT(0) << message << std::endl;
+            Host::Broadcast(message);
+        }
+
+        return valid_player;
+    }
+
+    void Dynamicmatch::start()
+    {
+        Gametype::start();
+        if(!tutorial)
+        {
+            std::string message("Dynamicmatch started!");
+            COUT(0) << message << std::endl;
+            Host::Broadcast(message);
+        }
+        else if(tutorial) // Announce selectionphase
+        {
+            for (std::map<PlayerInfo*, int>::iterator it = this->playerParty_.begin(); it != this->playerParty_.end(); ++it)
+            {
+                if (it->first->getClientID() == CLIENTID_UNKNOWN)
+                    continue;
+                this->gtinfo_->sendStaticMessage("Selection phase: Shoot at everything that moves.",it->first->getClientID(),ColourValue(1.0f, 1.0f, 0.5f));
+            }
+        }
+    }
+
+    /*void Dynamicmatch::instructions()
+    {
+        std::string message("Earn points:\n\n\n\tIf you're red: Chase the blue player!\n\n\tIf you're blue shoot at a red player or hide.\n\n\tIf you're green: You've got the licence to kill red players!");
+        COUT(0) << message << std::endl;
+        Host::Broadcast(message);
+        callInstructions_.setTimer(10, false, createExecutor(createFunctor(&Dynamicmatch::furtherInstructions, this)));
+    }
+
+    void Dynamicmatch::furtherInstructions()
+    {
+        std::string message("After 3 Minutes the game is over.");
+        COUT(0) << message << std::endl;
+        Host::Broadcast(message);
+    }*/
+    void Dynamicmatch::end()
+    {
+        Gametype::end();
+
+        std::string message("Time out. Press F2 to see the points you scored.");
+        COUT(0) << message << std::endl;
+        Host::Broadcast(message);
+    }
+    SpawnPoint* Dynamicmatch::getBestSpawnPoint(PlayerInfo* player) const
+    {
+        int desiredTeamNr = -1;
+        std::map<PlayerInfo*, int>::const_iterator it_player = this->playerParty_.find(player);
+        if (it_player != this->playerParty_.end())
+            desiredTeamNr = it_player->second;
+
+        // Only use spawnpoints of the own team (or non-team-spawnpoints)
+        std::set<SpawnPoint*> teamSpawnPoints = this->spawnpoints_;
+        for (std::set<SpawnPoint*>::iterator it = teamSpawnPoints.begin(); it != teamSpawnPoints.end(); )
+        {
+            if ((*it)->isA(Class(TeamSpawnPoint)))
+            {
+                TeamSpawnPoint* tsp = orxonox_cast<TeamSpawnPoint*>(*it);
+                if (tsp && static_cast<int>(tsp->getTeamNumber()) != desiredTeamNr)//getTeamNumber!!
+                {
+                    teamSpawnPoints.erase(it++);
+                    continue;
+                }
+            }
+
+            ++it;
+        }
+
+        if (teamSpawnPoints.size() > 0)
+        {
+            unsigned int randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(teamSpawnPoints.size())));
+            unsigned int index = 0;
+            for (std::set<SpawnPoint*>::const_iterator it = teamSpawnPoints.begin(); it != teamSpawnPoints.end(); ++it)
+            {
+                if (index == randomspawn)
+                    return (*it);
+
+                ++index;
+            }
+        }
+
+        return 0;
+    }
+
+}
Index: code/trunk/src/orxonox/gametypes/Dynamicmatch.h
===================================================================
--- code/trunk/src/orxonox/gametypes/Dynamicmatch.h	(revision 7163)
+++ code/trunk/src/orxonox/gametypes/Dynamicmatch.h	(revision 7163)
@@ -0,0 +1,92 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Johannes Ritz
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _Dynamicmatch_H__
+#define _Dynamicmatch_H__
+
+#include <map>
+#include <vector>
+#include "OrxonoxPrereqs.h"
+#include "Gametype.h"
+#include "tools/Timer.h"
+
+namespace orxonox
+{
+    class _OrxonoxExport Dynamicmatch : public Gametype
+    {
+        public:
+            Dynamicmatch(BaseObject* creator);
+            virtual ~Dynamicmatch() {}
+
+            bool notEnoughPigs;
+            bool notEnoughKillers;
+            bool notEnoughChasers;
+
+            //three different parties
+            int chaser;
+            int piggy;
+            int killer;
+
+            virtual void evaluatePlayerParties();
+            int getParty(PlayerInfo* player);
+            void setPlayerColour(PlayerInfo* player);//own function
+            void setConfigValues();//done
+
+            bool friendlyfire; //goal: player can switch it on/off
+            bool tutorial; //goal: new players receive messages how the new gametype works - later it can be switched off.
+
+            virtual bool allowPawnDamage(Pawn* victim, Pawn* originator = 0); //ok - score function and management of parties
+            virtual bool allowPawnDeath(Pawn* victim, Pawn* originator = 0); //ok - simple
+            virtual void start();
+            virtual void end(); //Wie geht das mit der Punkteausgabe aendern? Z.B: Persoenliche Nachricht?
+            virtual void playerEntered(PlayerInfo* player);
+            virtual void playerStartsControllingPawn(PlayerInfo* player, Pawn* pawn);//is used to initialize the player's party and colour
+            virtual bool playerLeft(PlayerInfo* player);
+            virtual bool playerChangedName(PlayerInfo* player);//unchanged
+
+            /*virtual void instructions();
+            virtual void furtherInstructions();*/
+            virtual void rewardPig();
+            void resetSpeedFactor(WeakPtr<Engine>* ptr);
+            void tick (float dt);// used to end the game
+            SpawnPoint* getBestSpawnPoint(PlayerInfo* player) const;
+
+        protected:
+
+            std::map< PlayerInfo*, int > playerParty_; //player's parties are recorded here
+            std::vector<ColourValue> partyColours_; //aus TeamDeathmatch
+            unsigned int numberOf[3]; //array to count number of chasers, pigs, killers
+            float pointsPerTime;
+            float gameTime_;   // from UnderAttack
+            bool gameEnded_; // true if game is over
+            int timesequence_; //used for countdown
+            //Timer callInstructions_;
+    };
+}
+
+#endif /* _Dynamicmatch_H__ */
Index: code/trunk/src/orxonox/gametypes/Gametype.cc
===================================================================
--- code/trunk/src/orxonox/gametypes/Gametype.cc	(revision 6906)
+++ code/trunk/src/orxonox/gametypes/Gametype.cc	(revision 7163)
@@ -309,7 +309,22 @@
         if (this->spawnpoints_.size() > 0)
         {
+            SpawnPoint* fallbackSpawnPoint = NULL;
             unsigned int randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(this->spawnpoints_.size())));
             unsigned int index = 0;
+            std::set<SpawnPoint*> activeSpawnPoints = this->spawnpoints_;
             for (std::set<SpawnPoint*>::const_iterator it = this->spawnpoints_.begin(); it != this->spawnpoints_.end(); ++it)
+            {
+                if (index == randomspawn)
+                    fallbackSpawnPoint = (*it);
+
+                if (!(*it)->isActive())
+                    activeSpawnPoints.erase(*it);
+
+                ++index;
+            }
+
+            randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(this->spawnpoints_.size())));
+            index = 0;
+            for (std::set<SpawnPoint*>::const_iterator it = activeSpawnPoints.begin(); it != activeSpawnPoints.end(); ++it)
             {
                 if (index == randomspawn)
@@ -318,4 +333,6 @@
                 ++index;
             }
+
+            return fallbackSpawnPoint;
         }
         return 0;
Index: code/trunk/src/orxonox/gametypes/TeamDeathmatch.cc
===================================================================
--- code/trunk/src/orxonox/gametypes/TeamDeathmatch.cc	(revision 6906)
+++ code/trunk/src/orxonox/gametypes/TeamDeathmatch.cc	(revision 7163)
@@ -137,8 +137,35 @@
         }
 
+        SpawnPoint* fallbackSpawnPoint = NULL;
         if (teamSpawnPoints.size() > 0)
         {
             unsigned int randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(teamSpawnPoints.size())));
             unsigned int index = 0;
+            // Get random fallback spawnpoint in case there is no active SpawnPoint.
+            for (std::set<SpawnPoint*>::const_iterator it = teamSpawnPoints.begin(); it != teamSpawnPoints.end(); ++it)
+            {
+                if (index == randomspawn)
+                {
+                    fallbackSpawnPoint = (*it);
+                    break;
+                }
+
+                ++index;
+            }
+
+            // Remove all inactive SpawnPoints from the list.
+            for (std::set<SpawnPoint*>::const_iterator it = teamSpawnPoints.begin(); it != teamSpawnPoints.end(); )
+            {
+                if(!(*it)->isActive())
+                {
+                    teamSpawnPoints.erase(it++);
+                    continue;
+                }
+
+                ++it;
+            }
+
+            randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(teamSpawnPoints.size())));
+            index = 0;
             for (std::set<SpawnPoint*>::const_iterator it = teamSpawnPoints.begin(); it != teamSpawnPoints.end(); ++it)
             {
@@ -148,4 +175,6 @@
                 ++index;
             }
+
+            return fallbackSpawnPoint;
         }
 
Index: code/trunk/src/orxonox/graphics/AnimatedModel.cc
===================================================================
--- code/trunk/src/orxonox/graphics/AnimatedModel.cc	(revision 7163)
+++ code/trunk/src/orxonox/graphics/AnimatedModel.cc	(revision 7163)
@@ -0,0 +1,126 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Benjamin de Capitani
+ *
+ *
+ */
+
+#include "AnimatedModel.h"
+
+#include <OgreEntity.h>
+#include <OgreAnimationState.h>
+
+#include "core/CoreIncludes.h"
+#include "core/GameMode.h"
+#include "core/XMLPort.h"
+#include "Scene.h"
+
+namespace orxonox
+{
+    CreateFactory(AnimatedModel);
+
+    AnimatedModel::AnimatedModel(BaseObject* creator) : Model(creator)
+    {
+        RegisterObject(AnimatedModel);
+    }
+
+
+    AnimatedModel::~AnimatedModel()
+    {
+        if (this->isInitialized() && this->mesh_.getEntity())
+            this->detachOgreObject(this->mesh_.getEntity());
+    }
+
+    void AnimatedModel::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(AnimatedModel, XMLPort, xmlelement, mode);
+        XMLPortParam(AnimatedModel,"anims",setAnims,getAnims, xmlelement,mode).defaultValues("");
+        XMLPortParam(AnimatedModel,"loop", setAnimLoop,getAnimLoop, xmlelement,mode).defaultValues(true);
+        XMLPortParam(AnimatedModel,"enabled", setAnimEnabled,getAnimEnabled, xmlelement,mode).defaultValues(true);
+    }
+
+
+    void AnimatedModel::changedMesh()
+    {
+        if (GameMode::showsGraphics())
+        {
+            if (this->mesh_.getEntity())
+                this->detachOgreObject(this->mesh_.getEntity());
+
+            this->mesh_.setMeshSource(this->getScene()->getSceneManager(), this->meshSrc_);
+
+            if (this->mesh_.getEntity())
+            {
+                this->attachOgreObject(this->mesh_.getEntity());
+                this->mesh_.getEntity()->setCastShadows(this->bCastShadows_);
+                this->setAnimationState(this->bAnimLoop_, this->bAnimEnabled_, this->anims_);
+                this->mesh_.setVisible(this->isVisible());
+            }
+        }
+    }
+
+    void AnimatedModel::changedAnimationState()
+    {
+        this->setAnimationState(this->bAnimLoop_, this->bAnimEnabled_, this->anims_);
+    }
+    void AnimatedModel::setAnimationState(bool loop, bool enabled, const std::string& state)
+    {
+        if(state!="")
+        {
+        if(this->mesh_.getEntity()->getAnimationState(state))
+        {
+        Ogre::AnimationState* as = this->mesh_.getEntity()->getAnimationState(state);
+        as->setLoop(loop);
+        as->setEnabled(enabled);
+        this->anims_ = state;
+        }
+        }
+    }
+
+    void AnimatedModel::setAnimLoop(bool loop)
+    {
+        this->bAnimLoop_ = loop;
+    }
+    void AnimatedModel::setAnimEnabled(bool enabled)
+    {
+        this->bAnimEnabled_ = enabled;
+    }
+    void AnimatedModel::tick(float dt)
+    {
+        if(this->mesh_.getEntity()->getAnimationState(anims_))
+        {
+// Test to change Material at runtime!
+
+//            Ogre::MaterialPtr mat = this->mesh_.getEntity()->getSubEntity(0)->getMaterial();
+//            mat->setDiffuse(0.4, 0.3, 0.1, 0.1);
+//            mat->setAmbient(0.3, 0.7, 0.8);
+//            mat->setSpecular(0.5, 0.5, 0.5, 0.1);
+//            Ogre::SceneBlendType sbt = Ogre::SBT_ADD;
+//
+//            mat->setSceneBlending(sbt);
+
+            Ogre::AnimationState* as = this->mesh_.getEntity()->getAnimationState(anims_);
+            as->addTime(dt);
+    }
+}
+}
Index: code/trunk/src/orxonox/graphics/AnimatedModel.h
===================================================================
--- code/trunk/src/orxonox/graphics/AnimatedModel.h	(revision 7163)
+++ code/trunk/src/orxonox/graphics/AnimatedModel.h	(revision 7163)
@@ -0,0 +1,76 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Fabian 'x3n' Landau
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _AnimatedModel_H__
+#define _AnimatedModel_H__
+
+#include "OrxonoxPrereqs.h"
+
+#include <string>
+#include "tools/interfaces/Tickable.h"
+#include "Model.h"
+
+namespace orxonox
+{
+    class _OrxonoxExport AnimatedModel : public Model, public Tickable
+    {
+        public:
+            AnimatedModel(BaseObject* creator);
+            virtual ~AnimatedModel();
+
+            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
+            void registerVariables();
+
+            virtual void changedAnimationState();
+            virtual void setAnimationState(bool loop, bool enabled, const std::string& state);
+            virtual void setAnimEnabled(bool enabled);
+            virtual void setAnimLoop(bool loop);
+            virtual void tick(float dt);
+            virtual void changedMesh();
+
+
+            inline void setAnims(const std::string& anims)
+                { this->anims_ = anims; this->changedAnimationState(); }
+            inline const std::string& getAnims() const
+                { return this->anims_; }
+
+            inline const std::string& getAnimationState() const
+                { return this->anims_; }
+            inline const bool&  getAnimLoop() const
+                { return this->bAnimLoop_; }
+            inline const bool&  getAnimEnabled() const
+                { return this->bAnimEnabled_; }
+
+        private:
+            std::string anims_;
+            bool bAnimEnabled_;
+            bool bAnimLoop_;
+    };
+}
+
+#endif /* _AnimatedModel_H__ */
Index: code/trunk/src/orxonox/graphics/Backlight.h
===================================================================
--- code/trunk/src/orxonox/graphics/Backlight.h	(revision 6906)
+++ code/trunk/src/orxonox/graphics/Backlight.h	(revision 7163)
@@ -45,5 +45,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             virtual void tick(float dt);
@@ -81,4 +80,5 @@
 
         private:
+            void registerVariables();
             virtual void startturnonoff();
             virtual void stopturnonoff();
Index: code/trunk/src/orxonox/graphics/Billboard.h
===================================================================
--- code/trunk/src/orxonox/graphics/Billboard.h	(revision 6906)
+++ code/trunk/src/orxonox/graphics/Billboard.h	(revision 7163)
@@ -46,5 +46,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             virtual void changedVisibility();
@@ -78,4 +77,5 @@
 
         private:
+            void registerVariables();
             void changedMaterial();
 //            void changedRotation();
Index: code/trunk/src/orxonox/graphics/BlinkingBillboard.cc
===================================================================
--- code/trunk/src/orxonox/graphics/BlinkingBillboard.cc	(revision 6906)
+++ code/trunk/src/orxonox/graphics/BlinkingBillboard.cc	(revision 7163)
@@ -66,7 +66,9 @@
     void BlinkingBillboard::registerVariables()
     {
-//        registerVariable(this->amplitude_, VariableDirection::ToClient);
-//        registerVariable(this->frequency_, VariableDirection::ToClient);
-//        registerVariable(this->phase_,     VariableDirection::ToClient);
+        unregisterVariable(this->getScale3D());
+        registerVariable(this->amplitude_,  VariableDirection::ToClient);
+        registerVariable(this->frequency_,  VariableDirection::ToClient);
+        registerVariable(this->phase_,      VariableDirection::ToClient);
+        registerVariable(this->bQuadratic_, VariableDirection::ToClient);
     }
 
@@ -75,5 +77,5 @@
         SUPER(BlinkingBillboard, tick, dt);
 
-        if (GameMode::isMaster() && this->isActive())
+        if (this->isActive())
         {
             this->time_ += dt;
Index: code/trunk/src/orxonox/graphics/BlinkingBillboard.h
===================================================================
--- code/trunk/src/orxonox/graphics/BlinkingBillboard.h	(revision 6906)
+++ code/trunk/src/orxonox/graphics/BlinkingBillboard.h	(revision 7163)
@@ -45,5 +45,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             virtual void tick(float dt);
@@ -70,4 +69,6 @@
 
         private:
+            void registerVariables();
+            
             float amplitude_;
             float frequency_;
Index: code/trunk/src/orxonox/graphics/CEGuiSample.cc
===================================================================
--- code/trunk/src/orxonox/graphics/CEGuiSample.cc	(revision 7163)
+++ code/trunk/src/orxonox/graphics/CEGuiSample.cc	(revision 7163)
@@ -0,0 +1,304 @@
+/***********************************************************************
+    filename:   CEGuiSample.cpp
+    created:    24/9/2004
+    author:     Paul D Turner
+*************************************************************************/
+/***************************************************************************
+ *   Copyright (C) 2004 - 2008 Paul D Turner & The CEGUI Development Team
+ *
+ *   Permission is hereby granted, free of charge, to any person obtaining
+ *   a copy of this software and associated documentation files (the
+ *   "Software"), to deal in the Software without restriction, including
+ *   without limitation the rights to use, copy, modify, merge, publish,
+ *   distribute, sublicense, and/or sell copies of the Software, and to
+ *   permit persons to whom the Software is furnished to do so, subject to
+ *   the following conditions:
+ *
+ *   The above copyright notice and this permission notice shall be
+ *   included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ ***************************************************************************/
+#include "CEGuiSample.h"
+
+#ifdef HAVE_CONFIG_H
+#   include "config.h"
+#endif
+#include "CEGUISamplesConfig.h"
+
+// includes for renderer selector classes
+#if defined( __WIN32__ ) || defined( _WIN32 )
+#   include "Win32CEGuiRendererSelector.h"
+#elif defined(__linux__)
+#   ifdef CEGUI_SAMPLES_USE_GTK2
+#       include "GTK2CEGuiRendererSelector.h"
+#   else
+#       include "CLICEGuiRendererSelector.h"
+#   endif
+#elif defined(__APPLE__)
+#   include "MacCEGuiRendererSelector.h"
+#endif
+
+// includes for application types
+#ifdef CEGUI_SAMPLES_USE_OGRE
+#   include "CEGuiOgreBaseApplication.h"
+#endif
+#ifdef CEGUI_SAMPLES_USE_OPENGL
+#   include "CEGuiOpenGLBaseApplication.h"
+#endif
+#ifdef CEGUI_SAMPLES_USE_IRRLICHT
+#   include "CEGuiIrrlichtBaseApplication.h"
+#endif
+#ifdef CEGUI_SAMPLES_USE_DIRECTFB
+#   include "CEGuiDirectFBBaseApplication.h"
+#endif
+#if defined( __WIN32__ ) || defined( _WIN32 )
+#   ifdef CEGUI_SAMPLES_USE_DIRECTX_8
+#       include "CEGuiD3D81BaseApplication.h"
+#   endif
+#   ifdef CEGUI_SAMPLES_USE_DIRECTX_9
+#       include "CEGuiD3D9BaseApplication.h"
+#   endif
+#   ifdef CEGUI_SAMPLES_USE_DIRECTX_10
+#       include "CEGuiD3D10BaseApplication.h"
+#   endif
+#endif
+// now we include the base CEGuiBaseApplication just in case someone has managed to
+// get this far without any of the renderers.  This ensures the framework will build,
+// although there will be no renderers available for selection in the samples.
+#include "CEGuiBaseApplication.h"
+
+#include "CEGUI.h"
+
+#ifdef CEGUI_WITH_XERCES
+#   include "CEGUIXercesParser.h"
+#endif
+
+// Include iostream if not on windows.
+#if defined( __WIN32__ ) || defined( _WIN32 )
+#else
+#    include <iostream>
+#endif
+
+
+/*************************************************************************
+    Constructor
+*************************************************************************/
+CEGuiSample::CEGuiSample() :
+        d_rendererSelector(0),
+        d_sampleApp(0)
+{}
+
+
+/*************************************************************************
+    Destructor
+*************************************************************************/
+CEGuiSample::~CEGuiSample()
+{
+    if (d_sampleApp)
+    {
+        d_sampleApp->cleanup();
+        delete d_sampleApp;
+    }
+
+    if (d_rendererSelector)
+    {
+        delete d_rendererSelector;
+    }
+
+}
+
+
+/*************************************************************************
+    Application entry point
+*************************************************************************/
+int CEGuiSample::run()
+{
+    try
+    {
+        if (initialise())
+            cleanup();
+    }
+    catch (CEGUI::Exception& exc)
+    {
+        outputExceptionMessage(exc.getMessage().c_str());
+    }
+    catch (std::exception& exc)
+    {
+        outputExceptionMessage(exc.what());
+    }
+    catch(...)
+    {
+        outputExceptionMessage("Unknown exception was caught!");
+    }
+
+    return 0;
+}
+
+
+/*************************************************************************
+    Initialise the sample application
+*************************************************************************/
+bool CEGuiSample::initialise()
+{
+    // Setup renderer selection dialog for Win32
+#if defined( __WIN32__ ) || defined( _WIN32 )
+    d_rendererSelector = new Win32CEGuiRendererSelector;
+
+    // enable renderer types supported for Win32
+#ifdef CEGUI_SAMPLES_USE_DIRECTX_8
+    d_rendererSelector->setRendererAvailability(Direct3D81GuiRendererType);
+#endif
+#ifdef CEGUI_SAMPLES_USE_DIRECTX_9
+    d_rendererSelector->setRendererAvailability(Direct3D9GuiRendererType);
+#endif
+#ifdef CEGUI_SAMPLES_USE_DIRECTX_10
+    d_rendererSelector->setRendererAvailability(Direct3D10GuiRendererType);
+#endif
+
+#elif defined(__linux__)
+    // decide which method to use for renderer selection
+#   ifdef CEGUI_SAMPLES_USE_GTK2
+        d_rendererSelector = new GTK2CEGuiRendererSelector();
+#   else
+        d_rendererSelector = new CLICEGuiRendererSelector();
+#   endif
+
+#elif defined(__APPLE__)
+     d_rendererSelector = new MacCEGuiRendererSelector();
+#endif
+
+    // enable available renderer types
+#ifdef CEGUI_SAMPLES_USE_OGRE
+    d_rendererSelector->setRendererAvailability(OgreGuiRendererType);
+#endif
+#ifdef CEGUI_SAMPLES_USE_OPENGL
+    d_rendererSelector->setRendererAvailability(OpenGLGuiRendererType);
+#endif
+#ifdef CEGUI_SAMPLES_USE_IRRLICHT
+    d_rendererSelector->setRendererAvailability(IrrlichtGuiRendererType);
+#endif
+#ifdef CEGUI_SAMPLES_USE_DIRECTFB
+    d_rendererSelector->setRendererAvailability(DirectFBGuiRendererType);
+#endif
+
+    // get selection from user
+    if (d_rendererSelector->invokeDialog())
+    {
+        // create appropriate application type based upon users selection
+        switch(d_rendererSelector->getSelectedRendererType())
+        {
+#ifdef CEGUI_SAMPLES_USE_OGRE
+        case OgreGuiRendererType:
+            d_sampleApp = new CEGuiOgreBaseApplication();
+            break;
+#endif
+#if defined( __WIN32__ ) || defined( _WIN32 )
+#ifdef CEGUI_SAMPLES_USE_DIRECTX_8
+        case Direct3D81GuiRendererType:
+            d_sampleApp = new CEGuiD3D81BaseApplication();
+            break;
+#endif
+#ifdef CEGUI_SAMPLES_USE_DIRECTX_9
+        case Direct3D9GuiRendererType:
+            d_sampleApp = new CEGuiD3D9BaseApplication();
+            break;
+#endif // DX9
+#ifdef CEGUI_SAMPLES_USE_DIRECTX_10
+        case Direct3D10GuiRendererType:
+            d_sampleApp = new CEGuiD3D10BaseApplication();
+            break;
+#endif // DX10
+#endif // Win32
+#ifdef CEGUI_SAMPLES_USE_OPENGL
+        case OpenGLGuiRendererType:
+            d_sampleApp = new CEGuiOpenGLBaseApplication();
+            break;
+#endif
+#ifdef CEGUI_SAMPLES_USE_IRRLICHT
+        case IrrlichtGuiRendererType:
+            d_sampleApp = new CEGuiIrrlichtBaseApplication();
+            break;
+#endif
+#ifdef CEGUI_SAMPLES_USE_DIRECTFB
+        case DirectFBGuiRendererType:
+            d_sampleApp = new CEGuiDirectFBBaseApplication();
+            break;
+#endif
+
+        default:
+            throw CEGUI::GenericException("No renderer was selected!");
+            break;
+        }
+
+        // set the default resource groups to be used
+        CEGUI::Imageset::setDefaultResourceGroup("imagesets");
+        CEGUI::Font::setDefaultResourceGroup("fonts");
+        CEGUI::Scheme::setDefaultResourceGroup("schemes");
+        CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
+        CEGUI::WindowManager::setDefaultResourceGroup("layouts");
+        CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");
+#ifdef CEGUI_WITH_XERCES
+        CEGUI::XercesParser::setSchemaDefaultResourceGroup("schemas");
+#endif
+
+        // execute the base application (which sets up the demo via 'this' and runs it.
+        if (d_sampleApp->execute(this))
+        {
+            // signal that app initialised and ran
+            return true;
+        }
+
+        // sample app did not initialise, delete the object.
+        delete d_sampleApp;
+        d_sampleApp = 0;
+    }
+
+    // delete renderer selector object
+    delete d_rendererSelector;
+    d_rendererSelector = 0;
+
+    // signal app did not initialise and run.
+    return false;
+}
+
+
+/*************************************************************************
+    Cleanup the sample application.
+*************************************************************************/
+void CEGuiSample::cleanup()
+{
+    if (d_sampleApp)
+    {
+        d_sampleApp->cleanup();
+        delete d_sampleApp;
+        d_sampleApp = 0;
+    }
+
+    if (d_rendererSelector)
+    {
+        delete d_rendererSelector;
+        d_rendererSelector = 0;
+    }
+
+}
+
+
+/*************************************************************************
+    Output a message to the user in some OS independant way.
+*************************************************************************/
+void CEGuiSample::outputExceptionMessage(const char* message) const
+{
+#if defined(__WIN32__) || defined(_WIN32)
+    MessageBoxA(0, message, "CEGUI - Exception", MB_OK|MB_ICONERROR);
+#else
+    std::cout << "An exception was thrown within the sample framework:" << std::endl;
+    std::cout << message << std::endl;
+#endif
+}
Index: code/trunk/src/orxonox/graphics/CEGuiSample.h
===================================================================
--- code/trunk/src/orxonox/graphics/CEGuiSample.h	(revision 7163)
+++ code/trunk/src/orxonox/graphics/CEGuiSample.h	(revision 7163)
@@ -0,0 +1,130 @@
+/***********************************************************************
+    filename:   CEGuiSample.h
+    created:    24/9/2004
+    author:     Paul D Turner
+*************************************************************************/
+/***************************************************************************
+ *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
+ *
+ *   Permission is hereby granted, free of charge, to any person obtaining
+ *   a copy of this software and associated documentation files (the
+ *   "Software"), to deal in the Software without restriction, including
+ *   without limitation the rights to use, copy, modify, merge, publish,
+ *   distribute, sublicense, and/or sell copies of the Software, and to
+ *   permit persons to whom the Software is furnished to do so, subject to
+ *   the following conditions:
+ *
+ *   The above copyright notice and this permission notice shall be
+ *   included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ ***************************************************************************/
+#ifndef _CEGuiSample_h_
+#define _CEGuiSample_h_
+
+#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined (CEGUI_STATIC)
+#   ifdef CEGUISAMPLE_EXPORTS
+#       define CEGUISAMPLE_API __declspec(dllexport)
+#   else
+#       define CEGUISAMPLE_API __declspec(dllimport)
+#   endif
+#else
+#       define CEGUISAMPLE_API
+#endif
+
+
+// forward declarations
+class CEGuiBaseApplication;
+class CEGuiRendererSelector;
+
+
+/*!
+\brief
+    This is a base class that is intended to be used for all sample applications.
+    Here we take care of common things such the renderer selection and application
+    startup.
+*/
+class CEGUISAMPLE_API CEGuiSample
+{
+public:
+    /*!
+    \brief
+        Constructor.
+    */
+    CEGuiSample();
+
+
+    /*!
+    \brief
+        Destructor.
+    */
+    virtual ~CEGuiSample();
+
+
+    /*!
+    \brief
+        Application entry point.
+
+    \return
+        code to be returned by the application.
+    */
+    int run();
+
+
+    /*!
+    \brief
+        Sample specific initialisation goes here.  This method is called by the application base object created
+        as part of the initialise call.
+
+    \return
+        false if something went wrong.
+    */
+    virtual bool initialiseSample()  = 0;
+
+
+    /*!
+    \brief
+        Cleans up resources allocated in the initialiseSample call.
+    */
+    virtual void cleanupSample() = 0;
+
+
+protected:
+    /*!
+    \brief
+        Initialises the sample system, this includes asking the user for a render to use and
+        the subsequent creation of the required systems to support that renderer.
+
+    \return
+        false if anything went wrong.
+    */
+    virtual bool initialise();
+
+
+    /*!
+    \brief
+        Cleans up all resources allocated by the initialise call.
+    */
+    virtual void cleanup();
+
+
+    /*!
+    \brief
+        Output a message to the user in some OS independant way.
+    */
+    void outputExceptionMessage(const char* message) const;
+
+    /*************************************************************************
+        Data fields
+    *************************************************************************/
+    CEGuiRendererSelector*  d_rendererSelector;     //!< Points to the renderer selector object.
+    CEGuiBaseApplication*   d_sampleApp;            //!< Pointer to the base application object.
+};
+
+#endif  // end of guard _CEGuiSample_h_
Index: code/trunk/src/orxonox/graphics/CMakeLists.txt
===================================================================
--- code/trunk/src/orxonox/graphics/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/orxonox/graphics/CMakeLists.txt	(revision 7163)
@@ -4,5 +4,7 @@
   FadingBillboard.cc
   GlobalShader.cc
+  MeshLodInformation.cc
   Model.cc
+  AnimatedModel.cc
   ParticleEmitter.cc
   ParticleSpawner.cc
Index: code/trunk/src/orxonox/graphics/Camera.cc
===================================================================
--- code/trunk/src/orxonox/graphics/Camera.cc	(revision 6906)
+++ code/trunk/src/orxonox/graphics/Camera.cc	(revision 7163)
@@ -111,5 +111,5 @@
         SUPER(Camera, tick, dt);
 
-        if (this->bDrag_)
+        if (this->bDrag_ && this->getTimeFactor() != 0)
         {
             // this stuff here may need some adjustments
Index: code/trunk/src/orxonox/graphics/FadingBillboard.h
===================================================================
--- code/trunk/src/orxonox/graphics/FadingBillboard.h	(revision 6906)
+++ code/trunk/src/orxonox/graphics/FadingBillboard.h	(revision 7163)
@@ -46,5 +46,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             virtual void tick(float dt);
@@ -66,4 +65,5 @@
 
         protected:
+            void registerVariables();
             virtual void startturnonoff();
             virtual void stopturnonoff();
Index: code/trunk/src/orxonox/graphics/GlobalShader.h
===================================================================
--- code/trunk/src/orxonox/graphics/GlobalShader.h	(revision 6906)
+++ code/trunk/src/orxonox/graphics/GlobalShader.h	(revision 7163)
@@ -45,5 +45,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             virtual void changedVisibility();
@@ -53,4 +52,5 @@
 
         private:
+            void registerVariables();
             void changedCompositor();
 
Index: code/trunk/src/orxonox/graphics/Light.h
===================================================================
--- code/trunk/src/orxonox/graphics/Light.h	(revision 6906)
+++ code/trunk/src/orxonox/graphics/Light.h	(revision 7163)
@@ -57,5 +57,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             virtual void changedVisibility();
@@ -132,4 +131,5 @@
 
         private:
+            void registerVariables();
             void setTypeString(const std::string& type);
             std::string getTypeString() const;
Index: code/trunk/src/orxonox/graphics/MeshLodInformation.cc
===================================================================
--- code/trunk/src/orxonox/graphics/MeshLodInformation.cc	(revision 7163)
+++ code/trunk/src/orxonox/graphics/MeshLodInformation.cc	(revision 7163)
@@ -0,0 +1,85 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Jan Bernegger
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "MeshLodInformation.h"
+
+#include <OgreEntity.h>
+
+#include "core/CoreIncludes.h"
+#include "core/GameMode.h"
+#include "core/XMLPort.h"
+#include "Scene.h"
+
+namespace orxonox
+{
+    CreateFactory(MeshLodInformation);
+
+    MeshLodInformation::MeshLodInformation(BaseObject* creator)
+    : BaseObject(creator), lodLevel_(5), bEnabled_(true), numLevels_(10), reductionRate_(0.15)
+    {
+        RegisterObject(MeshLodInformation);
+    }
+
+    MeshLodInformation::~MeshLodInformation()
+    {    }
+
+    void MeshLodInformation::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(MeshLodInformation, XMLPort, xmlelement, mode);
+
+        XMLPortParam(MeshLodInformation, "mesh", setMeshSource, getMeshSource, xmlelement, mode);
+        XMLPortParam(MeshLodInformation, "lodQuality", setLodLevel, getLodLevel, xmlelement, mode);
+        XMLPortParam(MeshLodInformation, "enabled", setEnabled, getEnabled, xmlelement, mode);
+        XMLPortParam(MeshLodInformation, "numLevels", setNumLevels, getNumLevels, xmlelement, mode);
+        XMLPortParam(MeshLodInformation, "reductionRate", setReductionRate, getReductionRate, xmlelement, mode);
+    }
+
+    std::string MeshLodInformation::getMeshName()
+    {
+        return MeshLodInformation::getMeshSource();
+    }
+
+    void MeshLodInformation::setLodLevel(float lodLevel)
+    {
+        if(lodLevel>=0)
+            lodLevel_=lodLevel;
+    }
+    float MeshLodInformation::getLodLevel()
+    {
+        return lodLevel_;
+    }
+    void MeshLodInformation::setMeshSource(std::string meshSource)
+    {
+        meshSource_ = meshSource;
+    }
+    std::string MeshLodInformation::getMeshSource()
+    {
+        return meshSource_;
+    }
+
+}
Index: code/trunk/src/orxonox/graphics/MeshLodInformation.h
===================================================================
--- code/trunk/src/orxonox/graphics/MeshLodInformation.h	(revision 7163)
+++ code/trunk/src/orxonox/graphics/MeshLodInformation.h	(revision 7163)
@@ -0,0 +1,70 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Jan Bernegger
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _MeshLodInformation_H__
+#define _MeshLodInformation_H__
+
+#include "OrxonoxPrereqs.h"
+
+#include <string>
+#include "tools/Mesh.h"
+#include "worldentities/StaticEntity.h"
+
+namespace orxonox
+{
+    class _OrxonoxExport MeshLodInformation : public BaseObject
+    {
+        public:
+            MeshLodInformation(BaseObject* creator);
+            virtual ~MeshLodInformation();
+
+            float getLodLevel();
+            std::string getMeshName();
+            bool getEnabled(){ return this->bEnabled_; }
+            unsigned int getNumLevels(){ return this->numLevels_; }
+            float getReductionRate(){ return this->reductionRate_; }
+
+            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
+
+        private:
+            void setLodLevel(float lodLevel);
+            void setMeshSource(std::string meshSource);
+            void setEnabled( bool enabled ){ this->bEnabled_ = enabled; }
+            void setNumLevels( unsigned int num ){ this->numLevels_ = num; }
+            void setReductionRate( float rate ){ this->reductionRate_ = rate; }
+            std::string getMeshSource();
+            std::string meshSource_;
+            float lodLevel_;
+            bool bEnabled_;
+            unsigned int numLevels_;
+            float reductionRate_;
+
+    };
+}
+
+#endif /* _MeshLodInformation_H__ */
Index: code/trunk/src/orxonox/graphics/Model.cc
===================================================================
--- code/trunk/src/orxonox/graphics/Model.cc	(revision 6906)
+++ code/trunk/src/orxonox/graphics/Model.cc	(revision 7163)
@@ -35,4 +35,6 @@
 #include "core/XMLPort.h"
 #include "Scene.h"
+#include "graphics/MeshLodInformation.h"
+#include "Level.h"
 
 namespace orxonox
@@ -40,9 +42,8 @@
     CreateFactory(Model);
 
-    Model::Model(BaseObject* creator) : StaticEntity(creator)
+    Model::Model(BaseObject* creator) :
+        StaticEntity(creator), bCastShadows_(true), lodLevel_(5), bLodEnabled_(true), numLodLevels_(10), lodReductionRate_(.15)
     {
         RegisterObject(Model);
-
-        this->bCastShadows_ = true;
 
         this->registerVariables();
@@ -59,4 +60,6 @@
         SUPER(Model, XMLPort, xmlelement, mode);
 
+        XMLPortParam(Model, "lodLevel", setLodLevel, getLodLevel, xmlelement, mode);
+
         XMLPortParam(Model, "mesh", setMeshSource, getMeshSource, xmlelement, mode);
         XMLPortParam(Model, "shadow", setCastShadows, getCastShadows, xmlelement, mode).defaultValues(true);
@@ -67,4 +70,14 @@
         registerVariable(this->meshSrc_,    VariableDirection::ToClient, new NetworkCallback<Model>(this, &Model::changedMesh));
         registerVariable(this->bCastShadows_, VariableDirection::ToClient, new NetworkCallback<Model>(this, &Model::changedShadows));
+    }
+
+    float Model::getBiggestScale(Vector3 scale3d)
+    {
+        float scaleFactor = scale3d.x;
+        if(scale3d.y>scaleFactor)
+            scaleFactor = scale3d.y;
+        if(scale3d.z>scaleFactor)
+            scaleFactor = scale3d.z;
+        return scaleFactor;
     }
 
@@ -83,4 +96,86 @@
                 this->mesh_.getEntity()->setCastShadows(this->bCastShadows_);
                 this->mesh_.setVisible(this->isVisible());
+
+
+                //LOD
+                if( this->mesh_.getEntity()->getMesh()->getNumLodLevels()==1 )
+                {
+                    Level* level = this->getLevel();
+
+                    assert( level != 0 );
+
+                    MeshLodInformation* lodInfo = level->getLodInfo(this->meshSrc_);
+                    if( lodInfo )
+                    {
+                        setLodLevel(lodInfo->getLodLevel());
+                        this->bLodEnabled_ = lodInfo->getEnabled();
+                        this->numLodLevels_ = lodInfo->getNumLevels();
+                        this->lodReductionRate_ = lodInfo->getReductionRate();
+                    }
+                    if( this->numLodLevels_>10 )
+                    {
+                        CCOUT(2) << "More than 10 LoD levels requested. Creating only 10." << endl;
+                        this->numLodLevels_ = 10;
+                    }
+                    if( this->bLodEnabled_ )
+                    {
+                        float volume = this->mesh_.getEntity()->getBoundingBox().volume();
+    //                     float scaleFactor = 1;
+
+    //                     BaseObject* creatorPtr = this;
+    //
+    //                     while(creatorPtr!=NULL&&orxonox_cast<WorldEntity*>(creatorPtr))
+    //                     {
+    //                         scaleFactor *= getBiggestScale(((WorldEntity*) creatorPtr)->getScale3D());
+    //                         creatorPtr = creatorPtr->getCreator();
+    //                     }
+    //                     COUT(0) << "name: " << this->meshSrc_ << "scaleFactor: " << scaleFactor << ", volume: " << volume << endl;
+
+                        COUT(4) << "Setting lodLevel for " << this->meshSrc_<< " with lodLevel_: " << this->lodLevel_ <<" and volume: "<< volume << ":" << std::endl;
+
+#if OGRE_VERSION >= 0x010700
+                        Ogre::Mesh::LodValueList distList;
+#else
+                        Ogre::Mesh::LodDistanceList distList;
+#endif
+
+                        if( lodLevel_>0 )
+                        {
+    //                         float factor = scaleFactor*5/lodLevel_;
+                            float factor = pow(volume, 2.0f / 3.0f) * 15.0f / lodLevel_;
+
+                            COUT(4) << "LodLevel set with factor: " << factor << endl;
+
+                            distList.push_back(70.0f*factor);
+                            distList.push_back(140.0f*factor);
+                            distList.push_back(170.0f*factor);
+                            distList.push_back(200.0f*factor);
+                            distList.push_back(230.0f*factor);
+                            distList.push_back(250.0f*factor);
+                            distList.push_back(270.0f*factor);
+                            distList.push_back(290.0f*factor);
+                            distList.push_back(310.0f*factor);
+                            distList.push_back(330.0f*factor);
+                            while(distList.size()>this->numLodLevels_)
+                                distList.pop_back();
+
+
+                            //Generiert LOD-Levels
+                            this->mesh_.getEntity()->getMesh()->generateLodLevels(distList, Ogre::ProgressiveMesh::VRQ_PROPORTIONAL, this->lodReductionRate_);
+                        }
+                        else
+                        {
+                            std::string what;
+                            if(lodLevel_>5)
+                                what = ">5";
+                            else
+                                what = "<0";
+
+                            COUT(4)<<"LodLevel not set because lodLevel("<<lodLevel_<<") was "<<what<<"." << endl;
+                        }
+                    }
+                    else
+                        COUT(4) << "LodLevel for " << this->meshSrc_ << " not set because is disabled." << endl;
+                }
             }
         }
Index: code/trunk/src/orxonox/graphics/Model.h
===================================================================
--- code/trunk/src/orxonox/graphics/Model.h	(revision 6906)
+++ code/trunk/src/orxonox/graphics/Model.h	(revision 7163)
@@ -45,5 +45,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             virtual void changedVisibility();
@@ -62,11 +61,26 @@
                 { return this->bCastShadows_; }
 
-        private:
+        protected:
+            void registerVariables();
             void changedMesh();
             void changedShadows();
+
+            //LoD
+            inline void setLodLevel(float lodLevel)
+                { this->lodLevel_ =  lodLevel; }
+            inline float getLodLevel() const
+                { return this->lodLevel_; }
+            float getBiggestScale(Vector3 scale3d);
 
             std::string meshSrc_;
             Mesh mesh_;
             bool bCastShadows_;
+
+            //LoD
+            float lodLevel_;
+            bool bLodEnabled_;
+            unsigned int numLodLevels_;
+            float lodReductionRate_;
+
     };
 }
Index: code/trunk/src/orxonox/graphics/ParticleEmitter.h
===================================================================
--- code/trunk/src/orxonox/graphics/ParticleEmitter.h	(revision 6906)
+++ code/trunk/src/orxonox/graphics/ParticleEmitter.h	(revision 7163)
@@ -44,5 +44,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             virtual void changedVisibility();
@@ -74,4 +73,7 @@
             std::string        source_;
             LODParticle::Value   LOD_;
+
+        private:
+            void registerVariables();
     };
 }
Index: code/trunk/src/orxonox/infos/GametypeInfo.cc
===================================================================
--- code/trunk/src/orxonox/infos/GametypeInfo.cc	(revision 6906)
+++ code/trunk/src/orxonox/infos/GametypeInfo.cc	(revision 7163)
@@ -42,4 +42,6 @@
     registerMemberNetworkFunction(GametypeInfo, dispatchKillMessage);
     registerMemberNetworkFunction(GametypeInfo, dispatchDeathMessage);
+    registerMemberNetworkFunction(GametypeInfo, dispatchStaticMessage);
+    registerMemberNetworkFunction(GametypeInfo, dispatchFadingMessage);
 
     GametypeInfo::GametypeInfo(BaseObject* creator) : Info(creator)
@@ -110,4 +112,26 @@
     }
 
+    void GametypeInfo::sendStaticMessage(const std::string& message, unsigned int clientID, const ColourValue& colour)
+    {
+        if (GameMode::isMaster())
+        {
+            if (clientID == CLIENTID_SERVER)
+                this->dispatchStaticMessage(message, colour);
+            else
+                callMemberNetworkFunction(GametypeInfo, dispatchStaticMessage, this->getObjectID(), clientID, message, colour);
+        }
+    }
+
+    void GametypeInfo::sendFadingMessage(const std::string& message, unsigned int clientID)
+    {
+        if (GameMode::isMaster())
+        {
+            if (clientID == CLIENTID_SERVER)
+                this->dispatchFadingMessage(message);
+            else
+                callMemberNetworkFunction(GametypeInfo, dispatchFadingMessage, this->getObjectID(), clientID, message);
+        }
+    }
+
     void GametypeInfo::dispatchAnnounceMessage(const std::string& message)
     {
@@ -127,3 +151,15 @@
             it->deathmessage(this, message);
     }
+
+     void GametypeInfo::dispatchStaticMessage(const std::string& message, const ColourValue& colour)
+    {
+        for (ObjectList<GametypeMessageListener>::iterator it = ObjectList<GametypeMessageListener>::begin(); it != ObjectList<GametypeMessageListener>::end(); ++it)
+            it->staticmessage(this, message, colour);
+    }
+
+     void GametypeInfo::dispatchFadingMessage(const std::string& message)
+    {
+        for (ObjectList<GametypeMessageListener>::iterator it = ObjectList<GametypeMessageListener>::begin(); it != ObjectList<GametypeMessageListener>::end(); ++it)
+            it->fadingmessage(this, message);
+    }
 }
Index: code/trunk/src/orxonox/infos/GametypeInfo.h
===================================================================
--- code/trunk/src/orxonox/infos/GametypeInfo.h	(revision 6906)
+++ code/trunk/src/orxonox/infos/GametypeInfo.h	(revision 7163)
@@ -45,6 +45,4 @@
             virtual ~GametypeInfo();
 
-            void registerVariables();
-
             inline bool hasStarted() const
                 { return this->bStarted_; }
@@ -64,10 +62,16 @@
             void sendKillMessage(const std::string& message, unsigned int clientID);
             void sendDeathMessage(const std::string& message, unsigned int clientID);
+            void sendStaticMessage(const std::string& message, unsigned int clientID, const ColourValue& colour);
+            void sendFadingMessage(const std::string& message, unsigned int clientID);
 
             void dispatchAnnounceMessage(const std::string& message);
             void dispatchKillMessage(const std::string& message);
             void dispatchDeathMessage(const std::string& message);
+            void dispatchStaticMessage(const std::string& message,const ColourValue& colour);
+            void dispatchFadingMessage(const std::string& message);
 
         private:
+            void registerVariables();
+
             bool bStarted_;
             bool bEnded_;
Index: code/trunk/src/orxonox/infos/HumanPlayer.h
===================================================================
--- code/trunk/src/orxonox/infos/HumanPlayer.h	(revision 6906)
+++ code/trunk/src/orxonox/infos/HumanPlayer.h	(revision 7163)
@@ -43,5 +43,4 @@
             virtual ~HumanPlayer();
 
-            void registerVariables();
             void setConfigValues();
 
@@ -101,4 +100,6 @@
             std::string gametypeHudTemplate_;
             OverlayGroup* gametypeHud_;
+        private:
+            void registerVariables();
     };
 }
Index: code/trunk/src/orxonox/infos/PlayerInfo.cc
===================================================================
--- code/trunk/src/orxonox/infos/PlayerInfo.cc	(revision 6906)
+++ code/trunk/src/orxonox/infos/PlayerInfo.cc	(revision 7163)
@@ -177,5 +177,5 @@
             return;
 
-//         assert( this->temporaryControllableEntity_==0 );
+        assert( this->oldControllableEntity_==0 );
 
         this->oldControllableEntity_ = this->controllableEntity_;
@@ -184,4 +184,5 @@
 
         entity->setPlayer(this);
+        entity->setController(this->controller_);
 
         if (this->controller_)
@@ -222,4 +223,6 @@
             return;
 
+        this->controllableEntity_->setController(0);
+        
         this->controllableEntity_ = this->oldControllableEntity_;
         this->controllableEntityID_ = this->controllableEntity_->getObjectID();
Index: code/trunk/src/orxonox/infos/PlayerInfo.h
===================================================================
--- code/trunk/src/orxonox/infos/PlayerInfo.h	(revision 6906)
+++ code/trunk/src/orxonox/infos/PlayerInfo.h	(revision 7163)
@@ -35,13 +35,12 @@
 #include "core/SubclassIdentifier.h"
 
-namespace orxonox
-{
-    class _OrxonoxExport PlayerInfo : public Info
-    {
+namespace orxonox // tolua_export
+{ // tolua_export
+    class _OrxonoxExport PlayerInfo // tolua_export
+        : public Info
+    { // tolua_export
         public:
             PlayerInfo(BaseObject* creator);
             virtual ~PlayerInfo();
-
-            void registerVariables();
 
             virtual void changedName();
@@ -91,4 +90,5 @@
 
         private:
+            void registerVariables();
             void networkcallback_changedcontrollableentityID();
             void networkcallback_changedgtinfoID();
@@ -103,6 +103,6 @@
             const GametypeInfo* gtinfo_;
             unsigned int gtinfoID_;
-    };
-}
+    }; // tolua_export
+} // tolua_export
 
 #endif /* _PlayerInfo_H__ */
Index: code/trunk/src/orxonox/interfaces/GametypeMessageListener.h
===================================================================
--- code/trunk/src/orxonox/interfaces/GametypeMessageListener.h	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/GametypeMessageListener.h	(revision 7163)
@@ -44,4 +44,6 @@
             virtual void killmessage(const GametypeInfo* gtinfo, const std::string& message) {}
             virtual void deathmessage(const GametypeInfo* gtinfo, const std::string& message) {}
+            virtual void staticmessage(const GametypeInfo* gtinfo, const std::string& message, const ColourValue& colour) {}
+            virtual void fadingmessage(const GametypeInfo* gtinfo, const std::string& message) {}
     };
 }
Index: code/trunk/src/orxonox/interfaces/InterfaceCompilation.cc
===================================================================
--- code/trunk/src/orxonox/interfaces/InterfaceCompilation.cc	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/InterfaceCompilation.cc	(revision 7163)
@@ -52,5 +52,5 @@
         RegisterRootObject(GametypeMessageListener);
     }
-    
+
     //----------------------------
     // PickupCarrier
@@ -59,14 +59,25 @@
     {
         RegisterRootObject(PickupCarrier);
-        
-        this->setCarrierName("PickupCarrier");
     }
-    
+
     PickupCarrier::~PickupCarrier()
     {
+
+    }
+
+    void PickupCarrier::preDestroy(void)
+    {
         std::set<Pickupable*>::iterator it = this->pickups_.begin();
+        std::set<Pickupable*>::iterator temp;
         while(it != this->pickups_.end())
         {
-            (*(it++))->destroy();
+            (*it)->carrierDestroyed();
+            temp = it;
+            it = this->pickups_.begin();
+            if(it == temp) // Infinite loop avoidance, in case the pickup wasn't removed from the carrier somewhere in the carrierDestroy() procedure.
+            {
+                COUT(2) << "Oops. In a PickupCarrier, while cleaning up, a Pickupable (&" << (*temp) << ") didn't unregister itself as it should have." << std::endl;;
+                it++;
+            }
         }
 
@@ -84,5 +95,5 @@
         this->isForPlayer_ = true;
     }
-    
+
     //----------------------------
     // RadarListener
Index: code/trunk/src/orxonox/interfaces/NotificationListener.h
===================================================================
--- code/trunk/src/orxonox/interfaces/NotificationListener.h	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/NotificationListener.h	(revision 7163)
@@ -47,4 +47,10 @@
     class Notification;
 
+    /**
+    @brief
+        NotificationListener interface.
+    @author
+        Fabian 'x3n' Landau
+    */
     class _OrxonoxExport NotificationListener : virtual public OrxonoxClass
     {
Index: code/trunk/src/orxonox/interfaces/PickupCarrier.h
===================================================================
--- code/trunk/src/orxonox/interfaces/PickupCarrier.h	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/PickupCarrier.h	(revision 7163)
@@ -45,6 +45,6 @@
 #include "core/OrxonoxClass.h"
 
-namespace orxonox // tolua_export
-{ // tolua_export
+namespace orxonox
+{
 
     //! Forward-declarations.
@@ -54,4 +54,5 @@
     class InvisiblePickup;
     class MetaPickup;
+    class DronePickup;
     class SpeedPickup;
 
@@ -62,15 +63,15 @@
         Damian 'Mozork' Frick
     */
-    class _OrxonoxExport PickupCarrier  // tolua_export
-        : virtual public OrxonoxClass
-    { // tolua_export
+    class _OrxonoxExport PickupCarrier : virtual public OrxonoxClass
+    {
         //! So that the different Pickupables have full access to their PickupCarrier.
         friend class Pickupable;
         friend class PickupManager;
-        //! Friends. 
+        //! Friends.
         friend class Pickup;
         friend class HealthPickup;
         friend class InvisiblePickup;
         friend class MetaPickup;
+        friend class DronePickup;
         friend class SpeedPickup;
 
@@ -78,37 +79,5 @@
             PickupCarrier(); //!< Constructor.
             virtual ~PickupCarrier(); //!< Destructor.
-
-            /**
-            @brief Can be called to pick up a Pickupable.
-            @param pickup A pointer to the Pickupable.
-            @return Returns true if the Pickupable was picked up, false if not.
-            */
-            bool pickup(Pickupable* pickup)
-                {
-                    bool pickedUp = this->pickups_.insert(pickup).second;
-                    if(pickedUp)
-                    {
-                        COUT(4) << "Picked up Pickupable " << pickup->getIdentifier()->getName() << "(&" << pickup << ")." << std::endl;
-                        pickup->pickedUp(this);
-                    }
-                    return pickedUp;
-                }
-
-            /**
-            @brief Can be called to drop a Pickupable.
-            @param pickup A pointer to the Pickupable.
-            @param drop If the Pickupable should just be removed from the PickupCarrier without further action, this can be set to false. true is default.
-            @return Returns true if the Pickupable has been dropped, false if not.
-            */
-            bool drop(Pickupable* pickup, bool drop = true)
-                {
-                    bool dropped = this->pickups_.erase(pickup) == 1;
-                    if(dropped && drop)
-                    {
-                        COUT(4) << "Dropping Pickupable " << pickup->getIdentifier()->getName() << "(&" << pickup << ")." << std::endl;
-                        pickup->dropped();
-                    }
-                    return dropped;
-                }
+            void preDestroy(void);
 
             /**
@@ -169,12 +138,6 @@
             */
             virtual const Vector3& getCarrierPosition(void) = 0;
-            
-            /**
-            @brief Get the name of this PickupCarrier.
-            @return Returns the name as a string.
-            */
-            const std::string& getCarrierName(void) { return this->carrierName_; } // tolua_export
-            
-        protected:        
+
+        protected:
             /**
             @brief Get all direct children of this PickupSpawner.
@@ -197,68 +160,32 @@
             std::set<Pickupable*>& getPickups(void)
                 { return this->pickups_; }
-                
-            /**
-            @brief Set the name of this PickupCarrier.
-                   The name needs to be set in the constructor of every class inheriting from PickupCarrier, by calling setCarrierName().
-            @param name The name to be set.
-            */
-            void setCarrierName(const std::string& name)
-                { this->carrierName_ = name; }
-        
+
         private:
             std::set<Pickupable*> pickups_; //!< The list of Pickupables carried by this PickupCarrier.
-            std::string carrierName_; //!< The name of the PickupCarrier, as displayed in the PickupInventory.
-            
+
             /**
-            @brief Get the number of carrier children this PickupCarrier has.
-            @return Returns the number of carrier children.
+            @brief Adds a Pickupable to the list of pickups that are carried by this PickupCarrier.
+            @param pickup A pointer to the pickup to be added.
+            @return Returns true if successfull, false if the Pickupable was already present.
             */
-            unsigned int getNumCarrierChildren(void)
+            bool addPickup(Pickupable* pickup)
                 {
-                    std::vector<PickupCarrier*>* list = this->getCarrierChildren();
-                    unsigned int size = list->size();
-                    delete list;
-                    return size;
+                    COUT(4) << "Adding Pickupable (&" << pickup << ") to PickupCarrier (&" << this << ")" << std::endl;
+                    return this->pickups_.insert(pickup).second;
                 }
-            
+
             /**
-            @brief Get the index-th child of this PickupCarrier.
-            @param index The index of the child to return.
-            @return Returns the index-th child.
+            @brief Removes a Pickupable from the list of pickups that are carried by thsi PickupCarrier.
+            @param pickup A pointer to the pickup to be removed.
+            @return Returns true if successfull, false if the Pickupable was not present in the list.
             */
-            PickupCarrier* getCarrierChild(unsigned int index)
+            bool removePickup(Pickupable* pickup)
                 {
-                    std::vector<PickupCarrier*>* list = this->getCarrierChildren();
-                    if(list->size() < index)
-                        return NULL;
-                    PickupCarrier* carrier = (*list)[index];
-                    delete list;
-                    return carrier;
+                    COUT(4) << "Removing Pickupable (&" << pickup << ") from PickupCarrier (&" << this << ")" << std::endl;
+                    return this->pickups_.erase(pickup) == 1;
                 }
-            
-            /**
-            @brief Get the number of Pickupables this PickupCarrier carries.
-            @return returns the number of pickups.
-            */
-            unsigned int getNumPickups(void)
-                { return this->pickups_.size(); }
-            
-            /**
-            @brief Get the index-th Pickupable of this PickupCarrier.
-            @param index The index of the Pickupable to return.
-            @return Returns the index-th pickup.
-            */
-            Pickupable* getPickup(unsigned int index)
-                {
-                    std::set<Pickupable*>::iterator it;
-                    for(it = this->pickups_.begin(); index != 0 && it != this->pickups_.end(); it++)
-                        index--;
-                    if(it == this->pickups_.end())
-                        return NULL;
-                    return *it;
-                }
-            
-    }; // tolua_export
-} // tolua_export
+
+    };
+}
 
 #endif /* _PickupCarrier_H__ */
Index: code/trunk/src/orxonox/interfaces/Pickupable.cc
===================================================================
--- code/trunk/src/orxonox/interfaces/Pickupable.cc	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/Pickupable.cc	(revision 7163)
@@ -34,12 +34,17 @@
 #include "Pickupable.h"
 
+#include "core/LuaState.h"
+#include "core/GUIManager.h"
 #include "core/Identifier.h"
 #include "core/CoreIncludes.h"
+#include "util/Convert.h"
+#include "infos/PlayerInfo.h"
 #include "pickup/PickupIdentifier.h"
+#include "worldentities/pawns/Pawn.h"
 #include "PickupCarrier.h"
 
 namespace orxonox
 {
-    
+
     /**
     @brief
@@ -47,31 +52,59 @@
     */
     Pickupable::Pickupable() : pickupIdentifier_(NULL), used_(false), pickedUp_(false)
-    {        
+    {
         RegisterRootObject(Pickupable);
-        
+
         this->carrier_ = NULL;
-        
+
         this->pickupIdentifier_ = new PickupIdentifier(this);
-    }
-    
-    /**
-    @brief
-        Destructor. 
+        this->beingDestroyed_ = false;
+        this->enabled_ = true;
+    }
+
+    /**
+    @brief
+        Destructor.
     */
     Pickupable::~Pickupable()
     {
-        if(this->isUsed())
-            this->setUsed(false);
-        
-        if(this->isPickedUp() && this->getCarrier() != NULL)
-        {
-            this->getCarrier()->drop(this, false);
-            this->setCarrier(NULL);
-        }
-        
+        COUT(4) << "Pickupable (" << this->getIdentifier()->getName() << ") (&" << this << ") destroyed." << std::endl;
         if(this->pickupIdentifier_ != NULL)
             this->pickupIdentifier_->destroy();
     }
-    
+
+    /**
+    @brief
+        A method that is called by OrxonoxClass::destroy() before the object is actually destroyed.
+    */
+    void Pickupable::preDestroy(void)
+    {
+        this->beingDestroyed_ = true;
+
+        if(this->isPickedUp())
+            this->drop(false); // Drops the pickup without creating a PickupSpawner.
+    }
+
+    /**
+    @brief
+        Is called internally within the pickup module to destroy pickups.
+    */
+    void Pickupable::destroy(void)
+    {
+        this->destroyPickup();
+    }
+
+    /**
+    @brief
+        Destroys a Pickupable.
+        If the Pickupable is already in the process of being destroyed a warning is displayed and this method is skipped.
+    */
+    void Pickupable::destroyPickup(void)
+    {
+        if(!this->beingDestroyed_)
+            this->OrxonoxClass::destroy();
+        else
+            COUT(2) << this->getIdentifier()->getName() << " may be unsafe. " << std::endl;
+    }
+
     /**
     @brief
@@ -84,14 +117,19 @@
     bool Pickupable::setUsed(bool used)
     {
-        if(this->used_ == used)
-            return false;
-        
+        if(this->used_ == used || !this->isPickedUp()) // If either the used status of the Pickupable doesn't change or it isn't picked up.
+            return false;
+
+        if((!this->isUsable() && used) || (!this->isUnusable() && !used)) // If either the Pickupable is requested to be used but it is not usable or the Pickupable is requested to be unused, while it is not unusable.
+            return false;
+
         COUT(4) << "Pickupable (&" << this << ") set to used " << used << "." << std::endl;
-        
+
         this->used_ = used;
         this->changedUsed();
-        return true;
-    }
-    
+
+        GUIManager::getInstance().getLuaState()->doString("PickupInventory.update()");
+        return true;
+    }
+
     /**
     @brief
@@ -106,7 +144,8 @@
         if(carrier == NULL)
             return false;
+
         return this->isTarget(carrier->getIdentifier());
     }
-    
+
     /**
     @brief
@@ -125,7 +164,8 @@
                 return true;
         }
+
         return false;
     }
-        
+
     /**
     @brief
@@ -140,5 +180,5 @@
         return this->addTarget(target->getIdentifier());
     }
-    
+
     /**
     @brief
@@ -153,30 +193,67 @@
         if(this->isTarget(target)) //!< If the input target is already present in the list of targets.
             return false;
-        
+
         COUT(4) << "Target " << target->getName() << " added to Pickupable (&" << this << ")." << std::endl;
         this->targets_.push_back(target);
         return true;
     }
-    
-    /**
-    @brief  
-        Sets the Pickupable to picked up.
-        This method will be called by the PickupCarrier picking the Pickupable up.
+
+    /**
+    @brief
+        Can be called to pick up a Pickupable.
     @param carrier
-        The PickupCarrier that picked the Pickupable up.
-    @return
-        Returns false if, for some reason, the pickup could not be picked up, e.g. it was picked up already.
-    */
-    bool Pickupable::pickedUp(PickupCarrier* carrier)
-    {
-        if(this->isPickedUp()) //!< If the Pickupable is already picked up.
-            return false;
+        A pointer to the PickupCarrier that picks up the Pickupable.
+    @return
+        Returns true if the Pickupable was picked up, false if not.
+    */
+    bool Pickupable::pickup(PickupCarrier* carrier)
+    {
+        if(carrier == NULL || this->isPickedUp()) //!< If carrier is NULL or the Pickupable is already picked up.
+            return false;
+
+        if(!this->setCarrier(carrier))
+        {
+            COUT(3) << "A Pickupable (&" << this << ") was trying to be added to a PickupCarrier, but was already present." << std::endl;
+            return false;
+        }
         
+        this->setPickedUp(true);
         COUT(4) << "Pickupable (&" << this << ") got picked up by a PickupCarrier (&" << carrier << ")." << std::endl;
-        this->setCarrier(carrier);
-        this->setPickedUp(true);
-        return true;
-    }
-    
+        return true;
+    }
+
+    /**
+    @brief
+        Can be called to drop a Pickupable.
+    @param createSpawner
+        If true a spawner is to be created for the dropped Pickupable. True is default.
+    @return
+        Returns true if the Pickupable has been dropped, false if not.
+    */
+    bool Pickupable::drop(bool createSpawner)
+    {
+        if(!this->isPickedUp()) // If the Pickupable is not picked up.
+            return false;
+
+        assert(this->getCarrier()); // The Carrier cannot be NULL at this point.
+        if(!this->getCarrier()->removePickup(this)) //TODO Shouldn't this be a little later?
+            COUT(2) << "Pickupable (&" << this << ", " << this->getIdentifier()->getName() << ") is being dropped, but it was not present in the PickupCarriers list of pickups." << std::endl;
+
+        COUT(4) << "Pickupable (&" << this << ") got dropped up by a PickupCarrier (&" << this->getCarrier() << ")." << std::endl;
+        this->setUsed(false);
+        this->setPickedUp(false);
+
+        bool created = false;
+        if(createSpawner)
+            created = this->createSpawner();
+
+        this->setCarrier(NULL);
+
+        if(!created && createSpawner) // If a PickupSpawner should have been created but wasn't.
+            this->destroy();
+
+        return true;
+    }
+
     /**
     @brief
@@ -189,14 +266,17 @@
     bool Pickupable::setPickedUp(bool pickedUp)
     {
-        if(this->pickedUp_ == pickedUp)
-            return false;
-        
+        if(this->pickedUp_ == pickedUp) // If the picked up status has not changed.
+            return false;
+
         COUT(4) << "Pickupable (&" << this << ") set to pickedUp " << pickedUp << "." << std::endl;
-        
+
         this->pickedUp_ = pickedUp;
+        if(!pickedUp) // if the Pickupable has been dropped it unregisters itself with its PickupCarrier.
+            this->getCarrier()->removePickup(this);
         this->changedPickedUp();
-        return true;
-    }
-        
+        GUIManager::getInstance().getLuaState()->doString("PickupInventory.update()");
+        return true;
+    }
+
     /**
     @brief
@@ -204,11 +284,21 @@
     @param carrier
         Sets the input PickupCarrier as the carrier of the pickup.
-    */
-    inline bool Pickupable::setCarrier(PickupCarrier* carrier)
-    {
-        if(this->carrier_ == carrier)
-            return false;
-        
+    @param tell
+        If true (default) the pickup is added to the list of pickups in the PickupCarrier.
+    @return
+        Returns true if successful, false if not.
+    */
+    bool Pickupable::setCarrier(orxonox::PickupCarrier* carrier, bool tell)
+    {
+        if(this->carrier_ == carrier) // If the PickupCarrier doesn't change.
+            return false;
+
         COUT(4) << "Pickupable (&" << this << ") changed Carrier (& " << carrier << ")." << std::endl;
+
+        if(carrier != NULL && tell)
+        {
+            if(!carrier->addPickup(this))
+                return false;
+        }
         
         this->carrier_ = carrier;
@@ -216,33 +306,14 @@
         return true;
     }
-    
-    /**
-    @brief 
-        Sets the Pickupable to not picked up or dropped.
-        This method will be called by the PickupCarrier dropping the Pickupable.
-    @return
-        Returns false if the pickup could not be dropped.
-    */
-    bool Pickupable::dropped(void)
-    {
-        if(!this->isPickedUp()) //!< If the Pickupable is not picked up.
-            return false;
-        
-        COUT(4) << "Pickupable (&" << this << ") got dropped up by a PickupCarrier (&" << this->getCarrier() << ")." << std::endl;
-        this->setUsed(false);
-        this->setPickedUp(false);
-        
-        bool created = this->createSpawner();
-        
-        this->setCarrier(NULL);
-        
-        if(!created)
-        {
-            this->destroy();
-        }
-        
-        return true;
-    }
-    
+
+    /**
+    @brief
+        Is called by the PickupCarrier when it is being destroyed.
+    */
+    void Pickupable::carrierDestroyed(void)
+    {
+        this->destroy();
+    }
+
     /**
     @brief
@@ -255,11 +326,11 @@
         OrxonoxClass* item = NULL;
         this->clone(item);
-        
+
         Pickupable* pickup = dynamic_cast<Pickupable*>(item);
-        
+
         COUT(4) << "Pickupable (&" << this << ") cloned. Clone is new Pickupable (&" << pickup << ")." << std::endl;
         return pickup;
     }
-    
+
     /**
     @brief
@@ -273,4 +344,20 @@
         SUPER(Pickupable, clone, item);
     }
-    
+
+    /**
+    @brief
+        Method to transcribe a Pickupable as a Rewardable to the player.
+    @param player
+        A pointer to the PlayerInfo, do whatever you want with it.
+    @return
+        Return true if successful.
+    */
+    bool Pickupable::reward(PlayerInfo* player)
+    {
+        ControllableEntity* entity = player->getControllableEntity();
+        Pawn* pawn = static_cast<Pawn*>(entity);
+        PickupCarrier* carrier = static_cast<PickupCarrier*>(pawn);
+        return this->pickup(carrier);
+    }
+
 }
Index: code/trunk/src/orxonox/interfaces/Pickupable.h
===================================================================
--- code/trunk/src/orxonox/interfaces/Pickupable.h	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/Pickupable.h	(revision 7163)
@@ -41,8 +41,9 @@
 
 #include "core/OrxonoxClass.h"
+#include "Rewardable.h"
 
-namespace orxonox
-{
-    
+namespace orxonox // tolua_export
+{ // tolua_export
+
     /**
     @brief
@@ -51,18 +52,18 @@
         Damian 'Mozork' Frick
     */
-    class _OrxonoxExport Pickupable : virtual public OrxonoxClass
-    {
+    class _OrxonoxExport Pickupable  // tolua_export
+        : virtual public OrxonoxClass, public Rewardable
+    {  // tolua_export
         protected:
             Pickupable(); //!< Default constructor.
-        
+
         public:
             virtual ~Pickupable(); //!< Default destructor.
-            
+
             /**
             @brief Get whether the pickup is currently in use or not.
             @return Returns true if the pickup is currently in use.
             */
-            inline bool isUsed(void)
-                { return this->used_; }
+            inline bool isUsed(void) { return this->used_; }  // tolua_export
             /**
             @brief  Should be called when the pickup has transited from used to unused or the other way around.
@@ -70,5 +71,5 @@
             */
             virtual void changedUsed(void) {}
-            
+
             /**
             @brief Get the carrier of the pickup.
@@ -82,11 +83,10 @@
             */
             virtual void changedCarrier(void) {}
-            
+
             /**
             @brief Returns whether the Pickupable is currently picked up.
             @return Returns true if the Pickupable is currently picked up, false if not.
             */
-            inline bool isPickedUp(void)
-                { return this->pickedUp_; }
+            inline bool isPickedUp(void) { return this->pickedUp_; }  // tolua_export
             /**
             @brief  Should be called when the pickup has transited from picked up to dropped or the other way around.
@@ -94,16 +94,36 @@
             */
             virtual void changedPickedUp(void) {}
+
+            /**
+            @brief Returns whether the Pickupable can be used.
+            @return Returns true if it can be used.
+            */
+            inline bool isUsable(void) { return this->enabled_; } // tolua_export
             
-            bool pickedUp(PickupCarrier* carrier); //!< Sets the Pickupable to picked up.
-            bool dropped(void); //!< Sets the Pickupable to not picked up or dropped.
-            
+            /**
+            @brief Returns whether the Pickupable can be unused.
+            @return Returns true if it can be unused.
+            */
+            inline bool isUnusable(void) { return this->enabled_; } // tolua_export
+
+            /**
+            @brief Returns whether the Pickupable is enabled.
+                   Once a Pickupable is disabled it cannot be enabled again. A Pickupable that is disabled can neither be used nor unused.
+            @return Returns true if the Pickupable is enabled.
+            */
+            inline bool isEnabled(void)
+                { return this->enabled_; }
+
+            bool pickup(PickupCarrier* carrier); //!< Can be called to pick up a Pickupable.
+            bool drop(bool createSpawner = true); //!< Can be called to drop a Pickupable.
+
             virtual bool isTarget(PickupCarrier* carrier) const; //!< Get whether the given PickupCarrier is a target of this pickup.
             bool isTarget(const Identifier* identifier) const; //!< Get whether a given class, represented by the input Identifier, is a target of this Pickupable.
             bool addTarget(PickupCarrier* target); //!< Add a PickupCarrier as target of this pickup.
             bool addTarget(Identifier* identifier); //!< Add a class, representetd by the input Identifier, as target of this pickup.
-            
+
             Pickupable* clone(void); //!< Creates a duplicate of the Pickupable.
             virtual void clone(OrxonoxClass*& item); //!< Creates a duplicate of the input OrxonoxClass.
-            
+
             /**
             @brief Get the PickupIdentifier of this Pickupable.
@@ -112,9 +132,15 @@
             virtual const PickupIdentifier* getPickupIdentifier(void)
                 { return this->pickupIdentifier_; }
-                
+
             bool setUsed(bool used); //!< Sets the Pickupable to used or unused, depending on the input.
             bool setPickedUp(bool pickedUp); //!< Helper method to set the Pickupable to either picked up or not picked up.
-            bool setCarrier(PickupCarrier* carrier); //!< Sets the carrier of the pickup.
-            
+            //TODO: private?
+            bool setCarrier(PickupCarrier* carrier, bool tell = true); //!< Sets the carrier of the pickup.
+
+            //TODO: private?
+            virtual void carrierDestroyed(void); //!< Is called by the PickupCarrier when it is being destroyed.
+
+            void destroy(void); //!< Is called internally within the pickup module to destroy pickups.
+
         protected:
             /**
@@ -122,5 +148,14 @@
             */
             void initializeIdentifier(void) {}
-            
+
+            virtual void preDestroy(void); //!< A method that is called by OrxonoxClass::destroy() before the object is actually destroyed.
+            virtual void destroyPickup(void); //!< Destroys a Pickupable.
+
+            /**
+            @brief Sets the Pickuapble to disabled.
+            */
+            inline void setDisabled(void)
+                { this->enabled_ = false; }
+
             /**
             @brief Facilitates the creation of a PickupSpawner upon dropping of the Pickupable.
@@ -131,21 +166,29 @@
             */
             virtual bool createSpawner(void) = 0;
-            
+
             PickupIdentifier* pickupIdentifier_; //!< The PickupIdentifier of this Pickupable.
-            
+
         private:
-            
-            bool used_; //!< Whether the pickup is currently in use or not.
-            bool pickedUp_; //!< Whether the pickup is currently picked up or not.
-            
-            PickupCarrier* carrier_; //!< The carrier of the pickup.
-            std::list<Identifier*> targets_; //!< The possible targets of this pickup.
 
-    };
-    
+            bool used_; //!< Whether the Pickupable is currently in use or not.
+            bool pickedUp_; //!< Whether the Pickupable is currently picked up or not.
+
+            bool enabled_; //!< Whether the Pickupable is enabled or not.
+
+            PickupCarrier* carrier_; //!< The PickupCarrier of the Pickupable.
+            std::list<Identifier*> targets_; //!< The possible targets of this Pickupable.
+
+            bool beingDestroyed_; //!< Is true if the Pickupable is in the process of being destroyed.
+
+        // For implementing the Rewardable interface:
+        public:
+            virtual bool reward(PlayerInfo* player); //!< Method to transcribe a Pickupable as a Rewardable to the player.
+
+    };  // tolua_export
+
     SUPER_FUNCTION(10, Pickupable, changedUsed, false);
     SUPER_FUNCTION(12, Pickupable, changedCarrier, false);
     SUPER_FUNCTION(13, Pickupable, changedPickedUp, false);
-}
+}  // tolua_export
 
 #endif /* _Pickupable_H__ */
Index: code/trunk/src/orxonox/interfaces/RadarListener.h
===================================================================
--- code/trunk/src/orxonox/interfaces/RadarListener.h	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/RadarListener.h	(revision 7163)
@@ -41,5 +41,7 @@
         virtual ~RadarListener() { }
 
-        virtual void displayObject(RadarViewable* viewable, bool bIsMarked) = 0;
+        virtual void addObject(RadarViewable* viewable) = 0;
+        virtual void removeObject(RadarViewable* viewable) = 0;
+        virtual void objectChanged(RadarViewable* viewable) = 0;
         virtual float getRadarSensitivity() const = 0;
         virtual void radarTick(float dt) = 0;
Index: code/trunk/src/orxonox/interfaces/RadarViewable.cc
===================================================================
--- code/trunk/src/orxonox/interfaces/RadarViewable.cc	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/RadarViewable.cc	(revision 7163)
@@ -29,15 +29,10 @@
 #include "RadarViewable.h"
 
-#include <OgreSceneManager.h>
-#include <OgreSceneNode.h>
-#include <OgreEntity.h>
-
 #include "util/StringUtils.h"
 #include "core/CoreIncludes.h"
-#include "tools/DynamicLines.h"
+#include "core/GameMode.h"
 #include "worldentities/WorldEntity.h"
 #include "Radar.h"
 #include "Scene.h"
-#include "overlays/Map.h"
 
 namespace orxonox
@@ -46,11 +41,10 @@
         @brief Constructor.
     */
-    RadarViewable::RadarViewable()
-        : MapNode_(NULL)
-        , MapEntity_(NULL)
-        , line_(NULL)
-        , LineNode_(NULL)
-        , isHumanShip_(false)
+    RadarViewable::RadarViewable(BaseObject* creator, const WorldEntity* wePtr)
+        : isHumanShip_(false)
         , bVisibility_(true)
+        , bInitialized_(false)
+        , creator_(creator)
+        , wePtr_(wePtr)
         , radarObjectCamouflage_(0.0f)
         , radarObjectShape_(Dot)
@@ -60,11 +54,10 @@
 
         this->uniqueId_=getUniqueNumberString();
-/*
-        if(Map::getSingletonPtr() && Map::getSingletonPtr()->getMapSceneManagerPtr())
+        if( GameMode::showsGraphics() )
         {
-            this->addEntity();
+            this->radar_ = this->creator_->getScene()->getRadar();
+            this->radar_->addRadarObject(this);
         }
-
-        */
+        this->bInitialized_ = true;
     }
 
@@ -72,76 +65,25 @@
     RadarViewable::~RadarViewable()
     {
-        if (this->isHumanShip_ && MapNode_)
-            MapNode_->removeAllChildren();
 
-        if (MapNode_)
-            delete MapNode_;
-
-        if (MapEntity_)
-            delete MapEntity_;
-
-        if (line_)
-            delete line_;
-
-        if (LineNode_)
-            delete LineNode_;
-    }
-
-    void RadarViewable::addMapEntity()
-    { //TODO Check shape and add accordantly
-        if( this->MapNode_ && !this->MapEntity_ && Map::getSingletonPtr() && Map::getSingletonPtr()->getMapSceneManagerPtr() )
+        if( this->bInitialized_ )
         {
-            COUT(0) << "Adding " << this->uniqueId_ << " to Map.\n";
-            this->MapEntity_ = Map::getSingletonPtr()->getMapSceneManagerPtr()->createEntity( this->uniqueId_, "drone.mesh");
-            /*this->line_ =  Map::getSingletonPtr()->getMapSceneManagerPtr()->createManualObject(this->uniqueId_ + "_l");
-            this->line_->begin("Map/line_", Ogre::RenderOperation::OT_LINE_STRIP);
-            //line_->position(0, -it->getRVWorldPosition().y, 0);
-            //this->line_->position(0, -20, 0);
-            this->line_->position(0, 0, -10); //Front Arrow
-            this->line_->position(0, 0, 0);
-
-            this->line_->end(); */
-            this->line_ = new Ogre::DynamicLines(Ogre::RenderOperation::OT_LINE_LIST);
-            this->line_->addPoint( Vector3(0,0,0) );
-            this->line_->addPoint( Vector3(0,0,0) );
-
-            this->MapNode_->attachObject( this->MapEntity_ );
-
-            this->LineNode_ = this->MapNode_->createChildSceneNode();
-            this->LineNode_->attachObject( this->line_ );
-        }
-        else
-        {
-            COUT(0) << "Unable to load " << this->uniqueId_ << " to Map.\n";
+            if( GameMode::showsGraphics() )
+            {
+                this->radar_->removeRadarObject(this);
+            }
         }
     }
 
-    void RadarViewable::updateMapPosition()
-    {
-        if( this->MapNode_ )
-        {
-            this->MapNode_->setPosition( this->getRVWorldPosition() );
-            this->MapNode_->translate( this->getRVOrientedVelocity(), static_cast<Ogre::Node::TransformSpace>(3) );
-            this->MapNode_->setOrientation( this->getWorldEntity()->getOrientation() );
-//Vector3 v = this->getRVWorldPosition();
-            //this->line_->setPoint(1, Vector3(0,v.y,0) );
-            this->line_->setPoint(1, Vector3( 0, static_cast<float>(static_cast<int>( -Map::getSingletonPtr()->movablePlane_->getDistance( this->getRVWorldPosition() ) ) ) ,0 ));
-            this->line_->update();
-            if( Map::getSingletonPtr()->playerShipNode_ )
-                this->LineNode_->setDirection( Map::getSingletonPtr()->playerShipNode_->getLocalAxes().GetColumn(1) ,Ogre::Node::TS_WORLD,Vector3::UNIT_Y);
-        }
-    }
-
-    void RadarViewable::setRadarObjectDescription(const std::string& str)
-    {
-        Radar* radar = this->getWorldEntity()->getScene()->getRadar();
-        if (radar)
-            this->radarObjectShape_ = radar->addObjectDescription(str);
-        else
-        {
-            CCOUT(2) << "Attempting to access the radar, but the radar is non existent." << std::endl;
-        }
-        this->radarObjectDescription_ = str;
-    }
+//     void RadarViewable::setRadarObjectDescription(const std::string& str)
+//     {
+//         Radar* radar = this->getWorldEntity()->getScene()->getRadar();
+//         if (radar)
+//             this->radarObjectShape_ = radar->addObjectDescription(str);
+//         else
+//         {
+//             CCOUT(2) << "Attempting to access the radar, but the radar is non existent." << std::endl;
+//         }
+//         this->radarObjectDescription_ = str;
+//     }
 
     const Vector3& RadarViewable::getRVWorldPosition() const
@@ -167,3 +109,11 @@
         }
     }
+
+    void RadarViewable::settingsChanged()
+    {
+        if( GameMode::showsGraphics() )
+        {
+            this->radar_->radarObjectChanged(this);
+        }
+    }
 }
Index: code/trunk/src/orxonox/interfaces/RadarViewable.h
===================================================================
--- code/trunk/src/orxonox/interfaces/RadarViewable.h	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/RadarViewable.h	(revision 7163)
@@ -36,9 +36,11 @@
 
 #include "util/Math.h"
-#include "util/OgreForwardRefs.h"
 #include "core/OrxonoxClass.h"
+#include "core/SmartPtr.h"
 
 namespace orxonox
 {
+    class BaseObject;
+
     /**
     @brief Interface for receiving window events.
@@ -56,27 +58,45 @@
 
     public:
-        RadarViewable();
+        RadarViewable(BaseObject* creator, const WorldEntity* wePtr);
         virtual ~RadarViewable();
 
         inline void setRadarObjectCamouflage(float camouflage)
-            { this->radarObjectCamouflage_ = camouflage; }
+            {
+                if( this->radarObjectCamouflage_ != camouflage )
+                {
+                    this->radarObjectCamouflage_ = camouflage;
+                    this->settingsChanged();
+                }
+            }
         inline float getRadarObjectCamouflage() const
             { return this->radarObjectCamouflage_; }
 
         inline void setRadarObjectColour(const ColourValue& colour)
-            { this->radarObjectColour_ = colour; }
+            {
+                if(this->radarObjectColour_ != colour)
+                {
+                    this->radarObjectColour_ = colour;
+                    this->settingsChanged();
+                }
+            }
         inline const ColourValue& getRadarObjectColour() const
             { return this->radarObjectColour_; }
 
-        void setRadarObjectDescription(const std::string& str);
-        inline const std::string& getRadarObjectDescription() const
-            { return this->radarObjectDescription_; }
+//         void setRadarObjectDescription(const std::string& str);
+//         inline const std::string& getRadarObjectDescription() const
+//             { return this->radarObjectDescription_; }
 
         inline void setRadarVisibility(bool b)
-            { this->bVisibility_ = b; }
+            {
+                if(b!=this->bVisibility_)
+                {
+                    this->bVisibility_ = b;
+                    this->settingsChanged();
+                }
+            }
         inline bool getRadarVisibility() const
             { return this->bVisibility_; }
 
-        virtual const WorldEntity* getWorldEntity() const = 0;
+        virtual const WorldEntity* getWorldEntity() const{ return this->wePtr_; }
 
         const Vector3& getRVWorldPosition() const;
@@ -84,25 +104,16 @@
 
         inline void setRadarObjectShape(Shape shape)
-            { this->radarObjectShape_ = shape; }
+            {
+                if( this->radarObjectShape_ != shape )
+                {
+                    this->radarObjectShape_ = shape;
+                    this->settingsChanged();
+                }
+            }
         inline Shape getRadarObjectShape() const
             { return this->radarObjectShape_; }
+        void settingsChanged();
 
-/*
-        inline void setMapNode(Ogre::SceneNode * node)
-            { this->MapNode_ = node; }
-        inline Ogre::SceneNode * getMapNode() const
-            { return this->MapNode_; }
-        inline void setMapEntity(Ogre::Entity * ent)
-            { this->MapEntity_ = ent; }
-        inline Ogre::Entity * getMapEntity() const
-            { return this->MapEntity_; }
-*/
-        //Used for Map
-        Ogre::SceneNode * MapNode_;
-        Ogre::Entity * MapEntity_;
-        Ogre::DynamicLines* line_;
-        Ogre::SceneNode * LineNode_;
-        void addMapEntity();
-        void updateMapPosition();
+
         bool isHumanShip_;
         inline const std::string& getUniqueId()
@@ -115,9 +126,13 @@
         void validate(const WorldEntity* object) const;
         bool bVisibility_;
+        bool bInitialized_;
         //Map
         std::string uniqueId_;
+        BaseObject* creator_;
 
 
         //Radar
+        const WorldEntity* wePtr_;
+        SmartPtr<Radar> radar_;
         float radarObjectCamouflage_;
         Shape radarObjectShape_;
Index: code/trunk/src/orxonox/interfaces/Rewardable.h
===================================================================
--- code/trunk/src/orxonox/interfaces/Rewardable.h	(revision 6906)
+++ code/trunk/src/orxonox/interfaces/Rewardable.h	(revision 7163)
@@ -48,5 +48,5 @@
         Damian 'Mozork' Frick
     */
-    class _OrxonoxExport Rewardable : public OrxonoxClass
+    class _OrxonoxExport Rewardable : virtual public OrxonoxClass
     {
         public:
@@ -59,5 +59,5 @@
                 Must be implemented by every class inheriting from Rewardable.
             @param player
-                A pointer to the ControllableEntity, do whatever you want with it.
+                A pointer to the PlayerInfo, do whatever you want with it.
             @return
                 Return true if successful.
Index: code/trunk/src/orxonox/items/Engine.cc
===================================================================
--- code/trunk/src/orxonox/items/Engine.cc	(revision 6906)
+++ code/trunk/src/orxonox/items/Engine.cc	(revision 7163)
@@ -64,5 +64,4 @@
         this->boostBlur_ = 0;
 
-        this->setCarrierName("Engine");
         this->speedAdd_ = 0.0;
         this->speedMultiply_ = 1.0;
Index: code/trunk/src/orxonox/items/Engine.h
===================================================================
--- code/trunk/src/orxonox/items/Engine.h	(revision 6906)
+++ code/trunk/src/orxonox/items/Engine.h	(revision 7163)
@@ -46,5 +46,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
             void setConfigValues();
 
@@ -127,4 +126,5 @@
 
         private:
+            void registerVariables();
             void networkcallback_shipID();
 
Index: code/trunk/src/orxonox/items/MultiStateEngine.h
===================================================================
--- code/trunk/src/orxonox/items/MultiStateEngine.h	(revision 6906)
+++ code/trunk/src/orxonox/items/MultiStateEngine.h	(revision 7163)
@@ -53,5 +53,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             virtual void tick(float dt);
@@ -68,4 +67,6 @@
 
         private:
+            void registerVariables();
+
             int state_;
             int oldState_;
Index: code/trunk/src/orxonox/overlays/CMakeLists.txt
===================================================================
--- code/trunk/src/orxonox/overlays/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/orxonox/overlays/CMakeLists.txt	(revision 7163)
@@ -4,7 +4,6 @@
   OverlayGroup.cc
 
-COMPILATION_BEGIN OverlayCompilation.cc
+#COMPILATION_BEGIN OverlayCompilation.cc
   InGameConsole.cc
-  Map.cc
-COMPILATION_END
+#COMPILATION_END
 )
Index: code/trunk/src/orxonox/overlays/GUISheet.cc
===================================================================
--- code/trunk/src/orxonox/overlays/GUISheet.cc	(revision 6906)
+++ code/trunk/src/orxonox/overlays/GUISheet.cc	(revision 7163)
@@ -32,4 +32,5 @@
 #include "core/GUIManager.h"
 #include "core/XMLPort.h"
+#include "core/GameMode.h"
 
 namespace orxonox
Index: code/trunk/src/orxonox/overlays/Map.cc
===================================================================
--- code/trunk/src/orxonox/overlays/Map.cc	(revision 6906)
+++ 	(revision )
@@ -1,454 +1,0 @@
-/*
- *   ORXONOX - the hottest 3D action shooter ever to exist
- *                    > www.orxonox.net <
- *
- *
- *   License notice:
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation; either version 2
- *   of the License, or (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- *   Author:
- *      Si Sun
- *
- */
-
-#include "Map.h"
-
-#include <string>
-
-#include <OgreBorderPanelOverlayElement.h>
-#include <OgreCamera.h>
-#include <OgreEntity.h>
-#include <OgreHardwarePixelBuffer.h>
-#include <OgreMaterialManager.h>
-#include <OgreMovablePlane.h>
-#include <OgreOverlay.h>
-#include <OgreOverlayContainer.h>
-#include <OgreOverlayManager.h>
-#include <OgrePass.h>
-#include <OgreRenderTexture.h>
-#include <OgreResourceGroupManager.h>
-#include <OgreRoot.h>
-#include <OgreSceneManager.h>
-#include <OgreSceneNode.h>
-#include <OgreTechnique.h>
-#include <OgreTexture.h>
-#include <OgreTextureManager.h>
-#include <OgreViewport.h>
-
-#include "util/StringUtils.h"
-#include "core/ConsoleCommand.h"
-#include "core/CoreIncludes.h"
-#include "core/XMLPort.h"
-#include "interfaces/RadarViewable.h"
-#include "Scene.h"
-#include "controllers/HumanController.h"
-#include "worldentities/CameraPosition.h"
-#include "worldentities/ControllableEntity.h"
-
- namespace orxonox
- {
-    CreateFactory(Map);
-    SetConsoleCommand(Map, openMap, true);
-    //SetConsoleCommand(Map, rotateYaw, true).setAsInputCommand();
-    //SetConsoleCommand(Map, rotatePitch, true).setAsInputCommand();
-    SetConsoleCommand(Map, Zoom, true).setAsInputCommand();
-
-
-    Map* Map::singletonMap_s = 0;
-    Ogre::SceneManager* Map::mapSceneM_s = 0;
-    Ogre::Camera* Map::Cam_ = 0;
-    Ogre::SceneNode* Map::CamNode_ = 0;
-    Ogre::MaterialPtr Map::OverlayMaterial_;// = init();
-    Ogre::Overlay* Map::overlay_ = 0;
-/*
-Ogre::MaterialPtr Map::init()
-{
-    Ogre::MaterialPtr tmp;
-    tmp.setNull();
-    return tmp;
-}
-*/
-
-    //int Map::mouseLookSpeed_ = 200;
-    //Ogre::SceneNode* Map::playerShipNode_ = 0;
-
-    const int PITCH=-30;
-    const int DISTANCE=200;
-
-    Map::Map(BaseObject* creator) : OrxonoxOverlay(creator)
-    {
-        RegisterObject(Map);
-        Map::singletonMap_s=this;
-
-        //Getting Scene Manager (Hack)
-        ObjectList<Scene>::iterator it = ObjectList<Scene>::begin();
-        this->sManager_ = it->getSceneManager();
-        if( !Map::getMapSceneManager() )
-        {
-            Map::setMapSceneManager( Ogre::Root::getSingletonPtr()->createSceneManager( Ogre::ST_GENERIC,"MapScene" ) );
-        }
-
-        this->playerShipNode_ = 0;
-        //this->sNode_ = new Ogre::SceneNode(sManager_);
-        //oManager_ = Ogre::OverlayManager::getSingletonPtr();
-        //overlay_ = oManager_->create("Map");
-        //overlay_ is member of OrxonoxOverlay
-
-        //Not Showing the map as default
-        //this->isVisible_=false;
-        //overlay_->hide();
-        this->mouseLookSpeed_ = 200;
-
-        //TestEntity
-        //Ogre::Entity * ent = mapSceneM_s->createEntity("ent", "drone.mesh");
-
-        //Map::getMapSceneManager()->getRootSceneNode()->attachObject( ent );
-        /*sNode_->setPosition(0,0,-50);
-        overlay_->add3D(sNode_);
-        */
-
-
-
-
-
-        // Alter the camera aspect ratio to match the viewport
-        //mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
-        if(!Map::Cam_)
-            Cam_ = Map::getMapSceneManager()->createCamera("ReflectCam");
-        //Cam_->setPosition(200,170, -160);
-        //Cam_->lookAt(0,0,0);
-        Cam_->setAspectRatio(1);
-        //Cam_->setRenderingDistance(0);
-        if(!Map::CamNode_)
-            CamNode_ = Map::getMapSceneManager()->getRootSceneNode()->createChildSceneNode();
-
-
-        //Create overlay material
-        if(Map::OverlayMaterial_.isNull())
-            Map::OverlayMaterial_ = this->createRenderCamera(Cam_, "RttMat");
-/*
-        Ogre::TexturePtr rttTex = Ogre::TextureManager::getSingleton().createManual("RttTex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
-
-        Ogre::RenderTexture *renderTexture = rttTex->getBuffer()->getRenderTarget();
-
-        renderTexture->addViewport(Cam_);
-        renderTexture->getViewport(0)->setClearEveryFrame(true);
-        renderTexture->getViewport(0)->setBackgroundColour(ColourValue::Black);
-        renderTexture->getViewport(0)->setOverlaysEnabled(false);
-
-        Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create("RttMat", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
-        Ogre::Technique *technique = material->createTechnique();
-        technique->createPass();
-        material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
-        material->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex");
-*/
-
-
-        // create overlay
-/*
-        Ogre::Overlay* pOverlay = Ogre::OverlayManager::getSingleton().create("Overlay1");
-
-        // Create a panel with RenderToTexture texture
-        Ogre::OverlayContainer* m_pOverlayPanel = static_cast<Ogre::OverlayContainer*>(Ogre::OverlayManager::getSingleton().createOverlayElement("Panel","OverlayPanelName%d"));
-        m_pOverlayPanel->setMetricsMode(Ogre::GMM_PIXELS);
-        m_pOverlayPanel->setPosition(10, 10);
-        m_pOverlayPanel->setDimensions(500, 300);
-        // Give overlay a texture
-        m_pOverlayPanel->setMaterialName(camMat_id);
-        pOverlay->add2D(m_pOverlayPanel);
-        pOverlay->show();
-*/
-        if(!this->overlay_)
-        {
-            this->overlay_ = Ogre::OverlayManager::getSingletonPtr()->create("MapOverlay");
-            Ogre::OverlayContainer* m_pOverlayPanel = static_cast<Ogre::OverlayContainer*>(Ogre::OverlayManager::getSingleton().createOverlayElement("Panel","OverlayPanelName%d"));
-            //m_pOverlayPanel->setMetricsMode(Ogre::GMM_PIXELS);
-            //m_pOverlayPanel->setPosition(10, 10);
-            //m_pOverlayPanel->setDimensions(600, 400);
-            m_pOverlayPanel->setPosition(0.01f, 0.003f);
-            m_pOverlayPanel->setDimensions(0.5f, 0.4f);
-            // Give overlay a texture
-            m_pOverlayPanel->setMaterialName("RttMat");
-            overlay_->add2D(m_pOverlayPanel);
-
-            //Add Borders
-            Ogre::BorderPanelOverlayElement* oBorder = static_cast<Ogre::BorderPanelOverlayElement*>(Ogre::OverlayManager::getSingletonPtr()->createOverlayElement("BorderPanel", "MapBorderPanel" + getUniqueNumberString()));
-            oBorder->setBorderSize( 0.003f, 0.003f );
-            oBorder->setDimensions(0.5f, 0.4f);
-            oBorder->setBorderMaterialName("StatsBorder");
-            oBorder->setTopBorderUV(0.49f, 0.0f, 0.51f, 0.5f);
-            oBorder->setTopLeftBorderUV(0.0f, 0.0f, 0.5f, 0.5f);
-            oBorder->setTopRightBorderUV(0.5f, 0.0f, 1.0f, 0.5f);
-            oBorder->setLeftBorderUV(0.0f, 0.49f, 0.5f, 0.51f);
-            oBorder->setRightBorderUV(0.5f, 0.49f, 1.0f, 0.5f);
-            oBorder->setBottomBorderUV(0.49f, 0.5f, 0.51f, 1.0f);
-            oBorder->setBottomLeftBorderUV(0.0f, 0.5f, 0.5f, 1.0f);
-            oBorder->setBottomRightBorderUV(0.5f, 0.5f, 1.0f, 1.0f);
-            //overlay_->add2D(oBorder);
-            m_pOverlayPanel->addChild(oBorder);
-        }
-
-
-        //Not Showing the map as default
-        this->isVisible_=false;
-        overlay_->hide();
-
-        //Create plane to show gridTypeError: blimport() takes no keyword arguments
-/*        Ogre::Entity* plane_ent;
-        if(Map::getMapSceneManager()->hasEntity("MapPlane"))
-            plane_ent = Map::getMapSceneManager()->getEntity("MapPlane");
-        else
-            plane_ent = Map::getMapSceneManager()->createEntity( "MapPlane", "plane.mesh");
-*/
-        this->movablePlane_ = new Ogre::MovablePlane( Vector3::UNIT_Y, 0 );
-        this->movablePlane_->normalise();
-
-        if(!Map::getMapSceneManager()->hasEntity("MapPlane"))
-        {
-            Ogre::Entity* plane_ent = Map::getMapSceneManager()->createEntity( "MapPlane", "plane.mesh");
-            planeNode_ = Map::getMapSceneManager()->createSceneNode();
-        //Create plane for calculations
-
-
-        //Ogre::MaterialPtr plane_mat = Ogre::MaterialManager::getSingleton().create("mapgrid", "General");
-        //plane_mat->getTechnique(0)->getPass(0)->createTextureUnitState("mapgrid.tga");
-        //plane_ent->setMaterialName("mapgrid");
-            plane_ent->setMaterialName("Map/Grid");
-            planeNode_->attachObject(plane_ent);
-
-            planeNode_->scale(160,1,160);
-//        planeNode_->attachObject(movablePlane_);
-        //Ogre::Material plane_mat = Ogre::MaterialManager::getSingletonPtr()->getByName("rock");
-
-
-        //ToDo create material script
-            Ogre::MaterialPtr myManualObjectMaterial = Ogre::MaterialManager::getSingleton().create("Map/Line","General");
-            myManualObjectMaterial->setReceiveShadows(false);
-            myManualObjectMaterial->getTechnique(0)->setLightingEnabled(true);
-            myManualObjectMaterial->getTechnique(0)->getPass(0)->setDiffuse(1,1,0,0);
-            myManualObjectMaterial->getTechnique(0)->getPass(0)->setAmbient(1,1,0);
-            myManualObjectMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1,1,0);
-        }
-    }
-
-    Map::~Map()
-    {
-        this->singletonMap_s = 0;
-        //delete this->overlay_;
-        /*if (this->isInitialized())
-        {
-        //delete sManager_;
-        //delete Map::getMapSceneManager()->getRootSceneNode();
-        //delete oManager_;
-        //delete CamNode_;
-        //delete Cam_;
-        //delete mapSceneM_s;
-        //Map::getMapSceneManager()->destroyAllEntities();
-        //Map::getMapSceneManager()->destroyAllCameras();
-        delete Map::getMapSceneManager();
-        }*/
-    }
-
-    Ogre::MaterialPtr Map::createRenderCamera(Ogre::Camera * cam, const std::string& matName)
-    {
-        Ogre::TexturePtr rttTex = Ogre::TextureManager::getSingleton().createManual(matName+"_tex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
-
-        Ogre::RenderTexture *renderTexture = rttTex->getBuffer()->getRenderTarget();
-
-        renderTexture->addViewport(cam);
-        renderTexture->getViewport(0)->setClearEveryFrame(true);
-        renderTexture->getViewport(0)->setBackgroundColour(ColourValue::Black);
-        renderTexture->getViewport(0)->setOverlaysEnabled(false);
-
-        Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create(matName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
-        Ogre::Technique *technique = material->createTechnique();
-        technique->createPass();
-        material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
-        material->getTechnique(0)->getPass(0)->createTextureUnitState(matName+"_tex");
-        return material;
-    }
-
-    void Map::updatePositions()
-    {
-
-//Ogre::Entity * ent;// = mapSceneM_s->createEntity("ent1", "drone.mesh");
-       for(ObjectList<orxonox::RadarViewable>::iterator it = ObjectList<orxonox::RadarViewable>::begin();
-            it!=ObjectList<orxonox::RadarViewable>::end();
-            ++it)
-        {
-            //COUT(0) << "Radar_Position: " << it->getRVWorldPosition() << std::endl;
-            //Ogre::SceneNode node = it->getMapNode();
-            //Ogre::Entity ent = it->getMapEntity();
-            if( !(it->MapNode_) )
-            {
-                it->MapNode_ = Map::getMapSceneManager()->getRootSceneNode()->createChildSceneNode( it->getRVWorldPosition() );
-                //it->MapNode_->translate( it->getRVOrientedVelocity(), Ogre::TS_WORLD );
-                /*if(it->getRadarObjectShape() == RadarViewable::Dot)
-                {
-                    //if( !(it->MapEntity_) )//check wether the entity is already attached
-                    //{
-                        //it->MapEntity_ = Map::getMapSceneManager()->createEntity( getUniqueNumberString(), "drone.mesh");
-                        //it->addEntity();
-                        //it->MapNode_->attachObject( it->MapEntity_ );
-                        //it->MapNode_->attachObject( it->line_ );
-                   // }
-                }*/
-                it->addMapEntity();
-            }
-            if(it->isHumanShip_)
-            {
-                this->movablePlane_->redefine(it->MapNode_->getLocalAxes().GetColumn(1) , it->MapNode_->getPosition());
-                if(it->isHumanShip_ && it->MapNode_ != this->playerShipNode_)
-                {
-                    this->playerShipNode_ = it->MapNode_;
-                    if(planeNode_ && this->planeNode_->getParent())
-                        this->planeNode_->getParent()->removeChild(this->planeNode_);
-                    this->playerShipNode_->addChild(this->planeNode_);
-                //Movable Plane needs to be attached direcly for calculations
-                //this->movablePlane_->detatchFromParent();
-                //this->movablePlane_->getParentSceneNode()->detachObject(this->movablePlane_);
-                //this->movablePlane_->redefine(it->MapNode_->getLocalAxes().GetColumn(1) , it->MapNode_->getPosition());
-                //it->MapNode_->attachObject(this->movablePlane_);
-                    if(planeNode_ && this->CamNode_->getParent())
-                        this->CamNode_->getParent()->removeChild(this->CamNode_);
-                    this->playerShipNode_->addChild(this->CamNode_);
-                    this->CamNode_->attachObject(this->Cam_);
-                //this->CamNodeHelper_ = this->CamNode_->createChildSceneNode();
-                //this->CamNodeHelper_->attachObject(this->Cam_);
-                    this->Cam_->setPosition(0, 0, (float)DISTANCE);
-                    this->Cam_->pitch( static_cast<Degree>((float)PITCH) );
-                    this->Cam_->lookAt(this->playerShipNode_->getPosition());
-                //this->Cam_->setAutoTracking(true, this->playerShipNode_);
-                }
-            }
-            it->updateMapPosition();
-
-
-
-
-
-
-        }
-    }
-
-
-
-    void Map::XMLPort(Element& xmlElement, XMLPort::Mode mode)
-    {
-        SUPER(Map, XMLPort, xmlElement, mode);
-    }
-
-    void Map::changedOwner()
-    {
-        SUPER(Map, changedOwner);
-        //COUT(0) << "shipptr" << this->getOwner()->getReverseCamera() << std::endl;
-
-        ControllableEntity* entity = orxonox_cast<ControllableEntity*>(this->getOwner());
-        if(entity && entity->getReverseCamera())
-        {
-            //COUT(0) << "foo";
-            entity->getReverseCamera()->attachCamera(this->Cam_);
-        }
-    }
-
-
-    void Map::toggleVisibility()
-    {
-        if (!(this->isVisible_))
-        {
-            this->overlay_->show();
-            this->isVisible_=1;
-            //set mouselook when showing map
-            if (HumanController::localController_s && HumanController::localController_s->controllableEntity_ && !HumanController::localController_s->controllableEntity_->isInMouseLook())
-            HumanController::localController_s->controllableEntity_->mouseLook();
-        }
-        else
-        {
-            this->overlay_->hide();
-            this->isVisible_=0;
-            if (HumanController::localController_s && HumanController::localController_s->controllableEntity_ && HumanController::localController_s->controllableEntity_->isInMouseLook())
-            HumanController::localController_s->controllableEntity_->mouseLook();
-        }
-    }
-
-    //Static function to toggle visibility of the map
-    void Map::openMap()
-    {
-        for(ObjectList<orxonox::Map>::iterator it = ObjectList<orxonox::Map>::begin();
-            it!=ObjectList<orxonox::Map>::end();
-            ++it)
-        {
-        //Map * m = it->getMap();
-        //COUT(0) << it->isVisible_ << std::endl;
-        it->toggleVisibility();
-        //it->updatePositions();
-        }
-    }
-
-    // HACK!
-    void Map::hackDestroyMap()
-    {
-        Map::OverlayMaterial_.setNull();
-    }
-
-    void Map::tick(float dt)
-    {
-        //Debug
-        //COUT(0) << "MovablePlane Position: " << this->movablePlane_->getParentSceneNode()->getName() << this->movablePlane_->getParentSceneNode()->getPosition() << std::endl;
-        //COUT(0) << "planeNode_ Position: " << this->planeNode_ ->getName() << this->planeNode_->getPosition() << std::endl;
-        //COUT(0) <<  "planeNode_ Parrent Position" << this->planeNode_->getParent()->getName() << this->planeNode_->getParent()->getPosition() << std::endl;
-        if( this->isVisible_ )
-            updatePositions();
-        //Cam_->roll(Degree(1));
-
-    }
-
-    void Map::rotateYaw(const Vector2& value)
-    {
-        if(!( Map::singletonMap_s && Map::singletonMap_s->CamNode_ ))
-            return;
-
-/*
-        singletonMap_s->CamNode_->setOrientation(singletonMap_s->CamNode_->getOrientation() * Quaternion( static_cast<Degree>(-value.y * singletonMap_s->mouseLookSpeed_) , singletonMap_s->playerShipNode_->getLocalAxes().GetColumn(1) ));
-
-        Map::singletonMap_s->CamNodeHelper_->setDirection(Vector3::UNIT_Y, Ogre::Node::TS_PARENT, Vector3::UNIT_Y);
-        Map::singletonMap_s->CamNodeHelper_->lookAt(Vector3(0,0,0), Ogre::Node::TS_PARENT);
-*/
-        singletonMap_s->CamNode_->yaw( static_cast<Degree>(-value.y * singletonMap_s->mouseLookSpeed_), Ogre::Node::TS_PARENT);
-    }
-
-    void Map::rotatePitch(const Vector2& value)
-    {
-        if(!( Map::singletonMap_s && Map::singletonMap_s->CamNode_ ))
-            return;
-            //singletonMap_s->Cam_->setOrientation(singletonMap_s->Cam_->getOrientation() * Quaternion( static_cast<Degree>(-value.y * singletonMap_s->mouseLookSpeed_) , Vector3::UNIT_X));
-/*        singletonMap_s->CamNode_->setOrientation(singletonMap_s->CamNode_->getOrientation() * Quaternion( static_cast<Degree>(-value.y * singletonMap_s->mouseLookSpeed_) , singletonMap_s->playerShipNode_->getLocalAxes().GetColumn(0) ));
-
-        Map::singletonMap_s->CamNodeHelper_->setDirection(Vector3::UNIT_Y, Ogre::Node::TS_PARENT, Vector3::UNIT_Y);
-        Map::singletonMap_s->CamNodeHelper_->lookAt(Vector3(0,0,0), Ogre::Node::TS_PARENT);
-*/
-        singletonMap_s->CamNode_->pitch( static_cast<Degree>(value.y * singletonMap_s->mouseLookSpeed_), Ogre::Node::TS_LOCAL);
-
-    }
-
-    void Map::Zoom(const Vector2& value)
-    {
-        if(!( Map::singletonMap_s && Map::singletonMap_s->CamNode_ ))
-            return;
-        //COUT(0) << value.y << std::endl;
-        Map::singletonMap_s->Cam_->setPosition(0,0, Map::singletonMap_s->Cam_->getPosition().z + value.y * Map::singletonMap_s->mouseLookSpeed_ );
-    }
- }
Index: code/trunk/src/orxonox/overlays/Map.h
===================================================================
--- code/trunk/src/orxonox/overlays/Map.h	(revision 6906)
+++ 	(revision )
@@ -1,118 +1,0 @@
-/*
- *   ORXONOX - the hottest 3D action shooter ever to exist
- *                    > www.orxonox.net <
- *
- *
- *   License notice:
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation; either version 2
- *   of the License, or (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- *   Author:
- *      Si Sun
- *
- */
-
-#ifndef _Map_H__
-#define _Map_H__
-
-#include "OrxonoxPrereqs.h"
-
-#include <OgreMaterial.h>
-
-#include "util/UtilPrereqs.h"
-#include "tools/interfaces/Tickable.h"
-#include "overlays/OrxonoxOverlay.h"
-
-namespace orxonox
-{
-    class _OrxonoxExport Map : public OrxonoxOverlay, public Tickable
-    {
-
-    public: // functions
-        Map(BaseObject* creator);
-        virtual ~Map();
-
-        virtual void XMLPort(Element& xmlElement, XMLPort::Mode mode);
-        virtual void tick(float dt);
-        virtual void changedOwner();
-
-        static Ogre::MaterialPtr createRenderCamera(Ogre::Camera * cam, const std::string& matName);
-
-        static void openMap();
-        // HACK!
-        static void hackDestroyMap();
-
-//Not yet implemented
-        static const int maxRange_s=1000;
-
-        static void rotateYaw(const Vector2& value);
-        static void rotatePitch(const Vector2& value);
-        static void Zoom(const Vector2& value);
-        // variables
-
-
-        bool inline getVisibility()
-            { return this->isVisible_; };
-
-        static inline Ogre::SceneManager* getMapSceneManagerPtr()
-        {
-            return Map::singletonMap_s->mapSceneM_s;
-        }
-        static inline Map* getSingletonPtr()
-        {
-            return Map::singletonMap_s;
-        }
-
-        static inline Ogre::SceneManager* getMapSceneManager()
-        {
-            return Map::mapSceneM_s;
-        }
-
-
-
-    private: // functions
-
-        void toggleVisibility();
-        void updatePositions();
-//        void changedPlayerNode();
-        static inline void setMapSceneManager( Ogre::SceneManager * sm)
-        {
-            Map::mapSceneM_s = sm;
-        }
-        //static Ogre::MaterialPtr init();
-
-    private: // variables
-        static Map* singletonMap_s;
-
-        Ogre::SceneManager* sManager_;
-        Ogre::OverlayManager * oManager_;
-
-        static Ogre::SceneManager* mapSceneM_s;
-        static Ogre::SceneNode* CamNode_;
-        static Ogre::Camera* Cam_;
-        static Ogre::MaterialPtr OverlayMaterial_;
-        static Ogre::Overlay* overlay_;
-        //Ogre::SceneNode* CamNodeHelper_;
-        Ogre::SceneNode* playerShipNode_;
-        Ogre::SceneNode* planeNode_;
-        Ogre::MovablePlane* movablePlane_;
-        int mouseLookSpeed_;
-        bool isVisible_;
-
-    friend class RadarViewable;
-    };
-}
-
-#endif /* _Map_H__ */
Index: code/trunk/src/orxonox/pickup/PickupIdentifier.cc
===================================================================
--- code/trunk/src/orxonox/pickup/PickupIdentifier.cc	(revision 6906)
+++ code/trunk/src/orxonox/pickup/PickupIdentifier.cc	(revision 7163)
@@ -39,5 +39,5 @@
 namespace orxonox
 {
-    
+
     /**
     @brief
@@ -47,16 +47,16 @@
     {
         RegisterRootObject(PickupIdentifier);
-        
+
         if(pickup == NULL)
             COUT(1) << "Error, PickupIdentifier was created without a valid Pickupable." << std::endl;
-        
+
         this->pickup_ = pickup;
     }
-    
+
     PickupIdentifier::~PickupIdentifier()
     {
 
     }
-    
+
     /**
     @brief
@@ -74,5 +74,5 @@
             COUT(1) << "Error in PickupIdentifier::compare: Input Identifier is NULL." << std::endl;
         }
-        
+
         if(identifier->pickup_ == NULL && this->pickup_ == NULL)
         {
@@ -80,5 +80,5 @@
             COUT(1) << "Error in PickupIdentifier::compare: Pickup stored by Identifier is NULL." << std::endl;
         }
-        
+
         if(identifier->pickup_ == NULL)
         {
@@ -86,5 +86,5 @@
             COUT(1) << "Error in PickupIdentifier::compare: Pickup stored by Identifier is NULL." << std::endl;
         }
-        
+
         if(this->pickup_ == NULL)
         {
@@ -92,9 +92,9 @@
             COUT(1) << "Error in PickupIdentifier::compare: Pickup stored by Identifier is NULL." << std::endl;
         }
-        
+
         //! If the classIdentifiers are not the same (meaning the PickupIdentifiers identify different classes), the obviously the two Pickupables identified by the PickupIdentifiers cannot be the same. An ordering is established through the alphabetical ordering of the respective classnames.
         if(!identifier->pickup_->getIdentifier()->isExactlyA(this->pickup_->getIdentifier()))
             return this->pickup_->getIdentifier()->getName().compare(identifier->pickup_->getIdentifier()->getName());
-        
+
         //! If the class is the same for both PickupIdentifiers we go on to check the parameters of the class.
         //! If the two have a different number of parameters then obviusly something is very wrong.
@@ -104,6 +104,6 @@
             return this->parameters_.size()-identifier->parameters_.size();
         }
-        
-        //! We iterate through all parameters and compar their values (which are strings). The first parameter is the most significant. The ordering is once again established by the alphabetical comparison of the two value strings.
+
+        //! We iterate through all parameters and compare their values (which are strings). The first parameter is the most significant. The ordering is once again established by the alphabetical comparison of the two value strings.
         for(std::map<std::string, std::string>::const_iterator it = this->parameters_.begin(); it != this->parameters_.end(); it++)
         {
@@ -117,8 +117,8 @@
                 return it->second.compare(identifier->parameters_.find(it->first)->second);
         }
-            
+
         return 0;
     }
-    
+
     /**
     @brief
@@ -134,5 +134,5 @@
     {
         COUT(4) << "PickupIdentifier " << name << ", " << value << std::endl;
-        
+
         if(!(this->parameters_.find(name) == this->parameters_.end()))
         {
@@ -140,9 +140,9 @@
             return false;
         }
-        
+
         this->parameters_[name] = value;
-        
+
         return true;
     }
-    
+
 }
Index: code/trunk/src/orxonox/pickup/PickupIdentifier.h
===================================================================
--- code/trunk/src/orxonox/pickup/PickupIdentifier.h	(revision 6906)
+++ code/trunk/src/orxonox/pickup/PickupIdentifier.h	(revision 7163)
@@ -41,9 +41,9 @@
 #include "core/Identifier.h"
 
-#include "core/OrxonoxClass.h" 
+#include "core/OrxonoxClass.h"
 
 namespace orxonox
 {
-    
+
     /**
     @brief
@@ -57,19 +57,19 @@
     class _OrxonoxExport PickupIdentifier : virtual public OrxonoxClass
     {
-        
+
         public:
             PickupIdentifier(Pickupable* pickup); //!< Constructor.
             ~PickupIdentifier(); //!< Destructor.
-            
+
             virtual int compare(const PickupIdentifier* identifier) const; //!< Compares two PickupIdentifiers and returns 0 if a == b, <0 if a < b and >0 if a > b for a.compare(b).
-            
+
             bool addParameter(std::string & name, std::string & value); //!< Add a parameter to the PickupIdentifier.
-            
+
         private:
             Pickupable* pickup_; //!< The Pickupable the PickupIdentififer is for.
             std::map<std::string, std::string> parameters_; //!< The parameters identifying the type of the pickup beyond the class.
-            
+
     };
-    
+
     /**
     @brief
@@ -81,5 +81,5 @@
             { return lhs->compare(rhs) < 0; }
     };
-    
+
 }
 
Index: code/trunk/src/orxonox/sound/BaseSound.cc
===================================================================
--- code/trunk/src/orxonox/sound/BaseSound.cc	(revision 6906)
+++ code/trunk/src/orxonox/sound/BaseSound.cc	(revision 7163)
@@ -33,4 +33,5 @@
 #include <al.h>
 
+#include "util/Math.h"
 #include "core/CoreIncludes.h"
 #include "core/GameMode.h"
@@ -248,5 +249,5 @@
         else // No source acquired so far, but might be set to playing or paused
         {
-            State state = this->state_; // save
+            State state = static_cast<State>(this->state_); // save
             if (this->isPlaying() || this->isPaused())
                 doPlay();
Index: code/trunk/src/orxonox/sound/BaseSound.h
===================================================================
--- code/trunk/src/orxonox/sound/BaseSound.h	(revision 6906)
+++ code/trunk/src/orxonox/sound/BaseSound.h	(revision 7163)
@@ -112,5 +112,5 @@
         float           volume_;
         bool            bLooping_;
-        State           state_;
+        uint8_t         state_;       // This Variable is actually of type State
         float           pitch_;
 
Index: code/trunk/src/orxonox/sound/WorldSound.cc
===================================================================
--- code/trunk/src/orxonox/sound/WorldSound.cc	(revision 6906)
+++ code/trunk/src/orxonox/sound/WorldSound.cc	(revision 7163)
@@ -58,5 +58,5 @@
         registerVariable(bLooping_, ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::loopingChanged));
         registerVariable(pitch_,    ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::pitchChanged));
-        registerVariable((int&)(BaseSound::state_), ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::stateChanged));
+        registerVariable((uint8_t&)(BaseSound::state_), ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::stateChanged));
     }
 
Index: code/trunk/src/orxonox/weaponsystem/WeaponMode.cc
===================================================================
--- code/trunk/src/orxonox/weaponsystem/WeaponMode.cc	(revision 6906)
+++ code/trunk/src/orxonox/weaponsystem/WeaponMode.cc	(revision 7163)
@@ -274,3 +274,11 @@
             return BLANKSTRING;
     }
+
+    void WeaponMode::setDefaultSoundWithVolume(const std::string& soundPath, const float soundVolume){
+        if (this->defSndWpnFire_) {
+            this->defSndWpnFire_->setSource(soundPath);
+            this->defSndWpnFire_->setVolume(soundVolume);
+        }
+    }
+
 }
Index: code/trunk/src/orxonox/weaponsystem/WeaponMode.h
===================================================================
--- code/trunk/src/orxonox/weaponsystem/WeaponMode.h	(revision 6906)
+++ code/trunk/src/orxonox/weaponsystem/WeaponMode.h	(revision 7163)
@@ -55,5 +55,5 @@
             void setDefaultSound(const std::string& soundPath);
             const std::string& getDefaultSound();
-
+            void setDefaultSoundWithVolume(const std::string& soundPath, const float soundVolume);
 
             // Munition
Index: code/trunk/src/orxonox/weaponsystem/WeaponSystem.cc
===================================================================
--- code/trunk/src/orxonox/weaponsystem/WeaponSystem.cc	(revision 6906)
+++ code/trunk/src/orxonox/weaponsystem/WeaponSystem.cc	(revision 7163)
@@ -214,5 +214,6 @@
         Weapon* weapon = 0;
         while ((weapon = wPack->getWeapon(i++)))
-            weapon->getWeaponSlot()->removeWeapon();
+            if (weapon->getWeaponSlot())
+                weapon->getWeaponSlot()->removeWeapon();
 
         // Remove all added links from the WeaponSets
Index: code/trunk/src/orxonox/worldentities/BigExplosion.cc
===================================================================
--- code/trunk/src/orxonox/worldentities/BigExplosion.cc	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/BigExplosion.cc	(revision 7163)
@@ -101,4 +101,9 @@
         this->debrisEntity3_ = new MovableEntity(this);
         this->debrisEntity4_ = new MovableEntity(this);
+        
+        this->debrisEntity1_->setSyncMode(0);
+        this->debrisEntity2_->setSyncMode(0);
+        this->debrisEntity3_->setSyncMode(0);
+        this->debrisEntity4_->setSyncMode(0);
 
         this->debris1_ = new Model(this);
@@ -106,6 +111,12 @@
         this->debris3_ = new Model(this);
         this->debris4_ = new Model(this);
+        
+        this->debris1_->setSyncMode(0);
+        this->debris2_->setSyncMode(0);
+        this->debris3_->setSyncMode(0);
+        this->debris4_->setSyncMode(0);
 
         this->explosion_ = new StaticEntity(this);
+        this->explosion_->setSyncMode(0);
 
         this->debrisSmoke1_ = new ParticleInterface(this->getScene()->getSceneManager(), "Orxonox/smoke7", this->LOD_);
@@ -158,4 +169,5 @@
         effect->setSource("Orxonox/explosion2b");
         effect->setLifetime(4.0f);
+        effect->setSyncMode(0);
 
         ParticleSpawner* effect2 = new ParticleSpawner(this->getCreator());
@@ -163,4 +175,5 @@
         effect2->setSource("Orxonox/smoke6");
         effect2->setLifetime(4.0f);
+        effect2->setSyncMode(0);
 
         this->explosion_->attach(effect);
@@ -181,4 +194,9 @@
             MovableEntity* partEntity1 = new MovableEntity(this);
             MovableEntity* partEntity2 = new MovableEntity(this);
+            
+            part1->setSyncMode(0);
+            part2->setSyncMode(0);
+            partEntity1->setSyncMode(0);
+            partEntity2->setSyncMode(0);
 
             partEntity1->setVelocity(Vector3(rnd(-1, 1), rnd(-1, 1), rnd(-1, 1))*rnd(10,100));
Index: code/trunk/src/orxonox/worldentities/BigExplosion.h
===================================================================
--- code/trunk/src/orxonox/worldentities/BigExplosion.h	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/BigExplosion.h	(revision 7163)
@@ -45,5 +45,4 @@
 
             virtual void tick(float dt);
-            void registerVariables();
 
             inline void setLOD(LODParticle::Value level)
@@ -53,4 +52,5 @@
 
         private:
+            void registerVariables();
 
             void LODchanged();
Index: code/trunk/src/orxonox/worldentities/CMakeLists.txt
===================================================================
--- code/trunk/src/orxonox/worldentities/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/CMakeLists.txt	(revision 7163)
@@ -5,5 +5,5 @@
   MobileEntity.cc
   ControllableEntity.cc
-
+  Drone.cc
   BigExplosion.cc
   EffectContainer.cc
Index: code/trunk/src/orxonox/worldentities/ControllableEntity.h
===================================================================
--- code/trunk/src/orxonox/worldentities/ControllableEntity.h	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/ControllableEntity.h	(revision 7163)
@@ -49,5 +49,4 @@
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
             virtual void tick(float dt);
-            void registerVariables();
             void setConfigValues();
 
@@ -137,4 +136,6 @@
             inline float getMouseLookSpeed() const
                 { return this->mouseLookSpeed_; }
+            inline CameraPosition* getCurrentCameraPosition()
+                { return this->currentCameraPosition_; }
 
             inline Controller* getXMLController() const
@@ -162,5 +163,8 @@
                 { this->hudtemplate_ = name; }
 
+            Ogre::SceneNode* cameraPositionRootNode_;
+
         private:
+            void registerVariables();
             void setXMLController(Controller* controller);
 
@@ -208,5 +212,4 @@
             bool bMouseLook_;
             float mouseLookSpeed_;
-            Ogre::SceneNode* cameraPositionRootNode_;
             std::list<SmartPtr<CameraPosition> > cameraPositions_;
             CameraPosition* currentCameraPosition_;
Index: code/trunk/src/orxonox/worldentities/Drone.cc
===================================================================
--- code/trunk/src/orxonox/worldentities/Drone.cc	(revision 7163)
+++ code/trunk/src/orxonox/worldentities/Drone.cc	(revision 7163)
@@ -0,0 +1,178 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oli Scheuss
+ *   Co-authors:
+ *      ...
+ */
+
+
+#include "Drone.h"
+
+#include "core/XMLPort.h"
+#include "BulletDynamics/Dynamics/btRigidBody.h"
+
+namespace orxonox
+{
+    CreateFactory(Drone);
+    /**
+    @brief
+        Constructor. Registers the object and initializes some default values.
+    */
+    Drone::Drone(BaseObject* creator) : Pawn(creator)
+    {
+        RegisterObject(Drone);
+
+        this->myController_ = 0;
+
+        this->localLinearAcceleration_.setValue(0, 0, 0);
+        this->localAngularAcceleration_.setValue(0, 0, 0);
+        this->setRadarVisibility(false);
+        this->setCollisionType(WorldEntity::Dynamic);
+
+        myController_ = new DroneController(static_cast<BaseObject*>(this)); //!< Creates a new controller and passes our this pointer to it as creator.
+        myController_->setDrone(this);
+
+        this->setController(myController_);
+    }
+
+    /**
+    @brief
+        Destructor. Destroys controller, if present.
+    */
+    Drone::~Drone()
+    {
+        if( this->isInitialized() && this->myController_ )
+            this->myController_->destroy();
+    }
+
+    /**
+    @brief
+        Method for creating a Drone through XML.
+    */
+    void Drone::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(Drone, XMLPort, xmlelement, mode);
+
+        XMLPortParam(Drone, "primaryThrust_", setPrimaryThrust, getPrimaryThrust, xmlelement, mode);
+        XMLPortParam(Drone, "auxilaryThrust_", setAuxilaryThrust, getAuxilaryThrust, xmlelement, mode);
+        XMLPortParam(Drone, "rotationThrust_", setRotationThrust, getRotationThrust, xmlelement, mode);
+        XMLPortParam(Drone, "maxDistanceToOwner_", setMaxDistanceToOwner, getMaxDistanceToOwner, xmlelement, mode);
+        XMLPortParam(Drone, "minDistanceToOwner_", setMinDistanceToOwner, getMinDistanceToOwner, xmlelement, mode);
+        XMLPortParam(Drone, "maxShootingRange_", setMaxShootingRange, getMaxShootingRange, xmlelement, mode);
+    }
+
+
+    /**
+    @brief
+        Defines which actions the Drone has to take in each tick.
+    @param dt
+        The length of the tick.
+    */
+    void Drone::tick(float dt)
+    {
+        SUPER(Drone, tick, dt);
+
+        //if (this->hasLocalController())
+        //{
+            this->localLinearAcceleration_.setX(this->localLinearAcceleration_.x() * getMass() * this->auxilaryThrust_);
+            this->localLinearAcceleration_.setY(this->localLinearAcceleration_.y() * getMass() * this->auxilaryThrust_);
+            if (this->localLinearAcceleration_.z() > 0)
+              this->localLinearAcceleration_.setZ(this->localLinearAcceleration_.z() * getMass() * this->auxilaryThrust_);
+            else
+              this->localLinearAcceleration_.setZ(this->localLinearAcceleration_.z() * getMass() * this->primaryThrust_);
+            this->physicalBody_->applyCentralForce(physicalBody_->getWorldTransform().getBasis() * this->localLinearAcceleration_);
+            this->localLinearAcceleration_.setValue(0, 0, 0);
+
+            this->localAngularAcceleration_ *= this->getLocalInertia() * this->rotationThrust_;
+            this->physicalBody_->applyTorque(physicalBody_->getWorldTransform().getBasis() * this->localAngularAcceleration_);
+            this->localAngularAcceleration_.setValue(0, 0, 0);
+        //}
+    }
+
+    /**
+    @brief
+        Moves the Drone in the negative z-direction (Front/Back) by an amount specified by the first component of the input 2-dim vector.
+    @param value
+        The vector determining the amount of the movement.
+    */
+    void Drone::moveFrontBack(const Vector2& value)
+    {
+        this->localLinearAcceleration_.setZ(this->localLinearAcceleration_.z() - value.x);
+    }
+
+    /**
+    @brief
+        Moves the Drone in the x-direction (Right/Left) by an amount specified by the first component of the input 2-dim vector.
+    @param value
+        The vector determining the amount of the movement.
+    */
+    void Drone::moveRightLeft(const Vector2& value)
+    {
+        this->localLinearAcceleration_.setX(this->localLinearAcceleration_.x() + value.x);
+    }
+
+    /**
+    @brief
+        Moves the Drone in the y-direction (Up/Down) by an amount specified by the first component of the input 2-dim vector.
+    @param value
+        The vector determining the amount of the movement.
+    */
+    void Drone::moveUpDown(const Vector2& value)
+    {
+        this->localLinearAcceleration_.setY(this->localLinearAcceleration_.y() + value.x);
+    }
+
+    /**
+    @brief
+        Rotates the Drone around the y-axis by the amount specified by the first component of the input 2-dim vector.
+    @param value
+        The vector determining the amount of the angular movement.
+    */
+    void Drone::rotateYaw(const Vector2& value)
+    {
+        this->localAngularAcceleration_.setY(this->localAngularAcceleration_.y() + value.x);
+    }
+
+    /**
+    @brief
+        Rotates the Drone around the x-axis by the amount specified by the first component of the input 2-dim vector.
+    @param value
+        The vector determining the amount of the angular movement.
+    */
+    void Drone::rotatePitch(const Vector2& value)
+    {
+        this->localAngularAcceleration_.setX(this->localAngularAcceleration_.x() + value.x);
+    }
+
+    /**
+    @brief
+        Rotates the Drone around the z-axis by the amount specified by the first component of the input 2-dim vector.
+    @param value
+        The vector determining the amount of the angular movement.
+    */
+    void Drone::rotateRoll(const Vector2& value)
+    {
+        this->localAngularAcceleration_.setZ(this->localAngularAcceleration_.z() + value.x);
+    }
+
+}
Index: code/trunk/src/orxonox/worldentities/Drone.h
===================================================================
--- code/trunk/src/orxonox/worldentities/Drone.h	(revision 7163)
+++ code/trunk/src/orxonox/worldentities/Drone.h	(revision 7163)
@@ -0,0 +1,152 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oli Scheuss
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _Drone_H__
+#define _Drone_H__
+
+#include "OrxonoxPrereqs.h"
+#include "worldentities/pawns/Pawn.h"
+#include "controllers/DroneController.h"
+
+namespace orxonox
+{
+
+    /**
+    @brief
+        Drone, that is made to move upon a specified pattern.
+        This class was constructed for the PPS tutorial.
+    @author
+        Oli Scheuss
+    */
+    class _OrxonoxExport Drone : public Pawn
+    {
+        public:
+            Drone(BaseObject* creator);
+            virtual ~Drone();
+
+            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); //!< Method for creating a Drone through XML.
+            virtual void tick(float dt); //!< Defines which actions the Drone has to take in each tick.
+
+
+            virtual void moveFrontBack(const Vector2& value);
+            virtual void moveRightLeft(const Vector2& value);
+            virtual void moveUpDown(const Vector2& value);
+
+            virtual void rotateYaw(const Vector2& value);
+            virtual void rotatePitch(const Vector2& value);
+            virtual void rotateRoll(const Vector2& value);
+
+            /**
+            @brief Moves the Drone in the Front/Back-direction by the specifed amount.
+            @param value  The amount by which the drone is to be moved.
+            */
+            inline void moveFrontBack(float value)
+            { this->moveFrontBack(Vector2(value, 0)); }
+            /**
+            @brief Moves the Drone in the Right/Left-direction by the specifed amount.
+            @param value  The amount by which the drone is to be moved.
+            */
+            inline void moveRightLeft(float value)
+            { this->moveRightLeft(Vector2(value, 0)); }
+            /**
+            @brief Moves the Drone in the Up/Down-direction by the specifed amount.
+            @param value  The amount by which the drone is to be moved.
+            */
+            inline void moveUpDown(float value)
+            { this->moveUpDown(Vector2(value, 0)); }
+
+            /**
+            @brief Rotates the Drone around the y-axis by the specifed amount.
+            @param value  The amount by which the drone is to be rotated.
+            */
+            inline void rotateYaw(float value)
+            { this->rotateYaw(Vector2(value, 0)); }
+            /**
+            @brief Rotates the Drone around the x-axis by the specifed amount.
+            @param value  The amount by which the drone is to be rotated.
+            */
+            inline void rotatePitch(float value)
+            { this->rotatePitch(Vector2(value, 0)); }
+            /**
+            @brief Rotates the Drone around the z-axis by the specifed amount.
+            @param value  The amount by which the drone is to be rotated.
+            */
+            inline void rotateRoll(float value)
+            { this->rotateRoll(Vector2(value, 0)); }
+
+            /**
+            @brief Sets the primary thrust to the input amount.
+            @param thrust The amount of thrust.
+            */
+            inline void setPrimaryThrust( float thrust )
+                { this->primaryThrust_=thrust; }
+            inline void setAuxilaryThrust( float thrust )
+                { this->auxilaryThrust_=thrust; }
+            inline void setRotationThrust( float thrust )
+                { this->rotationThrust_=thrust; }
+            inline void setMaxDistanceToOwner( float distance)
+                { this->maxDistanceToOwner_=distance; }
+            inline void setMinDistanceToOwner( float distance)
+                { this->minDistanceToOwner_=distance; }
+            inline void setMaxShootingRange( float distance)
+                { this->maxShootingRange_=distance; }
+
+
+            /**
+            @brief Gets the primary thrust to the input amount.
+            @return The amount of thrust.
+            */
+            inline float getPrimaryThrust()
+                { return this->primaryThrust_; }
+            inline float getAuxilaryThrust()
+                { return this->auxilaryThrust_; }
+            inline float getRotationThrust()
+                { return this->rotationThrust_; }
+            inline float getMaxDistanceToOwner()
+                { return this->maxDistanceToOwner_; }
+            inline float getMinDistanceToOwner()
+                { return this->minDistanceToOwner_; }
+            inline float getMaxShootingRange()
+                { return this->maxShootingRange_; }
+
+        private:
+            DroneController *myController_; //!< The controller of the Drone.
+
+            btVector3 localLinearAcceleration_; //!< The linear acceleration that is used to move the Drone the next tick.
+            btVector3 localAngularAcceleration_; //!< The linear angular acceleration that is used to move the Drone the next tick.
+            float primaryThrust_; //!< The amount of primary thrust. This is just used, when moving forward.
+            float auxilaryThrust_; //!< The amount of auxilary thrust. Used for all other movements (except for rotations).
+            float rotationThrust_; //!< The amount of rotation thrust. Used for rotations only.
+            float maxDistanceToOwner_; //Maximum Distance to owner
+            float minDistanceToOwner_; //Minimum Distance to owner
+            float maxShootingRange_;
+    };
+
+}
+
+#endif /* _Drone_H__ */
Index: code/trunk/src/orxonox/worldentities/ExplosionChunk.h
===================================================================
--- code/trunk/src/orxonox/worldentities/ExplosionChunk.h	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/ExplosionChunk.h	(revision 7163)
@@ -44,5 +44,4 @@
 
             virtual void tick(float dt);
-            void registerVariables();
 
             inline void setLOD(LODParticle::Value level)
@@ -52,4 +51,5 @@
 
         private:
+            void registerVariables();
             void LODchanged();
             void checkStop();
Index: code/trunk/src/orxonox/worldentities/MobileEntity.cc
===================================================================
--- code/trunk/src/orxonox/worldentities/MobileEntity.cc	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/MobileEntity.cc	(revision 7163)
@@ -46,6 +46,4 @@
         this->angularAcceleration_ = Vector3::ZERO;
         this->angularVelocity_     = Vector3::ZERO;
-
-        this->registerVariables();
     }
 
Index: code/trunk/src/orxonox/worldentities/MovableEntity.h
===================================================================
--- code/trunk/src/orxonox/worldentities/MovableEntity.h	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/MovableEntity.h	(revision 7163)
@@ -48,5 +48,4 @@
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
             virtual bool collidesAgainst(WorldEntity* otherObject, btManifoldPoint& contactPoint);
-            void registerVariables();
 
             using WorldEntity::setPosition;
@@ -79,4 +78,5 @@
 
         private:
+            void registerVariables();
             void clientConnected(unsigned int clientID);
             void clientDisconnected(unsigned int clientID);
Index: code/trunk/src/orxonox/worldentities/StaticEntity.h
===================================================================
--- code/trunk/src/orxonox/worldentities/StaticEntity.h	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/StaticEntity.h	(revision 7163)
@@ -42,6 +42,4 @@
             virtual ~StaticEntity();
 
-            void registerVariables();
-
             using WorldEntity::setPosition;
             using WorldEntity::setOrientation;
@@ -51,4 +49,5 @@
 
         private:
+            void registerVariables();
             bool isCollisionTypeLegal(CollisionType type) const;
 
Index: code/trunk/src/orxonox/worldentities/WorldEntity.cc
===================================================================
--- code/trunk/src/orxonox/worldentities/WorldEntity.cc	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/WorldEntity.cc	(revision 7163)
@@ -81,5 +81,5 @@
         this->node_->setPosition(Vector3::ZERO);
         this->node_->setOrientation(Quaternion::IDENTITY);
-        
+
         // Activity and visibility memory.
         this->bActiveMem_ = true;
@@ -205,5 +205,5 @@
         registerVariable(this->parentID_,       VariableDirection::ToClient, new NetworkCallback<WorldEntity>(this, &WorldEntity::networkcallback_parentChanged));
     }
-    
+
     /**
     @brief
@@ -213,5 +213,5 @@
     {
         SUPER(WorldEntity, changedActivity);
-        
+
         for (std::set<WorldEntity*>::const_iterator it = this->getAttachedObjects().begin(); it != this->getAttachedObjects().end(); it++)
         {
@@ -227,5 +227,5 @@
         }
     }
-    
+
     /**
     @brief
@@ -235,5 +235,5 @@
     {
         SUPER(WorldEntity, changedVisibility);
-        
+
         for (std::set<WorldEntity*>::const_iterator it = this->getAttachedObjects().begin(); it != this->getAttachedObjects().end(); it++)
         {
Index: code/trunk/src/orxonox/worldentities/WorldEntity.h
===================================================================
--- code/trunk/src/orxonox/worldentities/WorldEntity.h	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/WorldEntity.h	(revision 7163)
@@ -94,5 +94,4 @@
 
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
-            void registerVariables();
 
             inline const Ogre::SceneNode* getNode() const
@@ -105,5 +104,5 @@
             static const Vector3 DOWN;
             static const Vector3 UP;
-            
+
             virtual void changedActivity(void);
             virtual void changedVisibility(void);
@@ -214,4 +213,6 @@
 
         private:
+            void registerVariables();
+            
             inline void lookAt_xmlport(const Vector3& target)
                 { this->lookAt(target); }
@@ -234,5 +235,5 @@
             std::set<WorldEntity*> children_;
             bool bDeleteWithParent_;
-            
+
             bool bActiveMem_;
             bool bVisibleMem_;
Index: code/trunk/src/orxonox/worldentities/pawns/CMakeLists.txt
===================================================================
--- code/trunk/src/orxonox/worldentities/pawns/CMakeLists.txt	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/pawns/CMakeLists.txt	(revision 7163)
@@ -1,3 +1,4 @@
 ADD_SOURCE_FILES(ORXONOX_SRC_FILES
+  FpsPlayer.cc
   Spectator.cc
   Pawn.cc
Index: code/trunk/src/orxonox/worldentities/pawns/FpsPlayer.cc
===================================================================
--- code/trunk/src/orxonox/worldentities/pawns/FpsPlayer.cc	(revision 7163)
+++ code/trunk/src/orxonox/worldentities/pawns/FpsPlayer.cc	(revision 7163)
@@ -0,0 +1,307 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Cyrill Frei
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "FpsPlayer.h"
+
+#include <OgreSceneNode.h>
+#include <BulletDynamics/Dynamics/btRigidBody.h>
+#include <LinearMath/btVector3.h>
+#include <BulletCollision/NarrowPhaseCollision/btManifoldPoint.h>
+#include <OgreSceneManager.h>
+#include <OgreSceneNode.h>
+#include <OgreEntity.h>
+
+#include "core/CoreIncludes.h"
+#include "core/ConfigValueIncludes.h"
+#include "core/Template.h"
+#include "core/XMLPort.h"
+#include "items/Engine.h"
+#include "Scene.h"
+#include "weaponsystem/WeaponPack.h"
+#include "weaponsystem/WeaponSlot.h"
+#include "weaponsystem/Weapon.h"
+
+#include <cmath>
+
+namespace orxonox
+{
+    const float orientationGain_ = 100;
+    const float jumpValue_ = 300;
+    CreateFactory(FpsPlayer);
+
+    FpsPlayer::FpsPlayer(BaseObject* creator) : Pawn(creator)
+    {
+        RegisterObject(FpsPlayer);
+        this->speed_ = 200;
+        this->localVelocity_ = Vector3::ZERO;
+/*
+ *        this->primaryThrust_  = 100;
+ *        this->auxilaryThrust_ =  30;
+ *        this->rotationThrust_ =  10;
+ *
+ *        this->localLinearAcceleration_.setValue(0, 0, 0);
+ *        this->localAngularAcceleration_.setValue(0, 0, 0);
+ *        this->bBoost_ = false;
+ *        this->bPermanentBoost_ = false;
+ *        this->steering_ = Vector3::ZERO;
+*/
+
+
+        this->bInvertYAxis_ = false;
+
+        this->setDestroyWhenPlayerLeft(true);
+
+        // FpsPlayer is always a physical object per default
+        // Be aware of this call: The collision type legality check will not reach derived classes!
+        this->setCollisionType(WorldEntity::Dynamic);
+        // Get notification about collisions
+        this->enableCollisionCallback();
+
+        this->setConfigValues();
+        this->registerVariables();
+
+        //this->weaponNode = this->cameraPositionRootNode_;
+        this->weaponNode_ = this->getScene()->getRootSceneNode()->createChildSceneNode();
+        this->attachNode(this->weaponNode_);
+    }
+
+    FpsPlayer::~FpsPlayer()
+    {
+        if (this->isInitialized())
+        {
+            if (this->mesh_.getEntity())
+                this->detachOgreObject(this->mesh_.getEntity());
+
+            if (this->weaponNode_ && this->getScene()->getSceneManager())
+                this->getScene()->getSceneManager()->destroySceneNode(this->weaponNode_->getName());
+        }
+    }
+
+    void FpsPlayer::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(FpsPlayer, XMLPort, xmlelement, mode);
+
+        XMLPortParamVariable(FpsPlayer, "primaryThrust",  primaryThrust_,  xmlelement, mode);
+        XMLPortParamVariable(FpsPlayer, "auxilaryThrust", auxilaryThrust_, xmlelement, mode);
+        XMLPortParamVariable(FpsPlayer, "rotationThrust", rotationThrust_, xmlelement, mode);
+        XMLPortParam(FpsPlayer, "weapon", setMeshSource, getMeshSource, xmlelement, mode);
+    }
+
+    void FpsPlayer::registerVariables()
+    {
+        registerVariable(this->primaryThrust_,  VariableDirection::ToClient);
+        registerVariable(this->auxilaryThrust_, VariableDirection::ToClient);
+        registerVariable(this->rotationThrust_, VariableDirection::ToClient);
+        registerVariable(this->weaponMashName_, VariableDirection::ToClient);
+    }
+
+
+
+    void FpsPlayer::setConfigValues()
+    {
+        SetConfigValue(bInvertYAxis_, false).description("Set this to true for joystick-like mouse behaviour (mouse up = targetting down).");
+    }
+
+    bool FpsPlayer::isCollisionTypeLegal(WorldEntity::CollisionType type) const
+    {
+        if (type != WorldEntity::Dynamic)
+        {
+            CCOUT(1) << "Error: Cannot tell a FpsPlayer not to be dynamic! Ignoring." << std::endl;
+            assert(false); // Only in debug mode
+            return false;
+        }
+        else
+            return true;
+    }
+
+    void FpsPlayer::tick(float dt)
+    {
+        if (this->hasLocalController())
+        {
+            this->setOrientation(savedOrientation_);
+
+            this->thisTickBoost_ = false;
+
+            float localSpeedSquared = this->localVelocity_.squaredLength();
+            float localSpeed;
+            if (localSpeedSquared > 1.0)
+                localSpeed = this->speed_ / sqrtf(localSpeedSquared);
+            else
+                localSpeed = this->speed_;
+
+            this->localVelocity_.x *= localSpeed;
+            this->localVelocity_.z *= localSpeed;
+            Vector3 temp = this->getOrientation() * this->localVelocity_;
+            if (localVelocity_.y == jumpValue_)
+                this->setVelocity(Vector3(temp.x, temp.y + this->getVelocity().y, temp.z));
+            else
+                this->setVelocity(Vector3(temp.x, this->getVelocity().y, temp.z));
+            this->localVelocity_.x = 0;
+            this->localVelocity_.y = 0;
+            this->localVelocity_.z = 0;
+
+            if (!this->isInMouseLook())
+            {
+                this->yaw(Radian(this->yaw_ * this->getMouseLookSpeed()), WorldEntity::Parent);
+
+                Radian pitch = this->cameraPositionRootNode_->getOrientation().getPitch();
+                if (pitch < Radian(1.5707) && pitch > Radian(-1.5707))
+                {
+                    this->cameraPositionRootNode_->pitch(Radian(this->pitch_ * this->getMouseLookSpeed()));
+                }
+                else if (pitch < Radian(-1.5707))
+                {
+                    if (this->pitch_ > 0.0)
+                        this->cameraPositionRootNode_->pitch(Radian(this->pitch_ * this->getMouseLookSpeed()));
+                    else if (pitch < Radian(-1.571))
+                        this->cameraPositionRootNode_->pitch(-pitch + Radian(-1.570796));
+                }
+                else if (pitch > Radian(1.5707))
+                {
+                    if (this->pitch_ < 0.0)
+                        this->cameraPositionRootNode_->pitch(Radian(this->pitch_ * this->getMouseLookSpeed()));
+                    else if (pitch > Radian(1.571))
+                        this->cameraPositionRootNode_->pitch(-pitch + Radian(1.570796));
+                }
+                this->weaponNode_->setOrientation(this->cameraPositionRootNode_->getOrientation());
+            }
+
+            this->yaw_ = this->pitch_ = this->roll_ = 0;
+
+            this->setAngularVelocity(0.0, 0.0, 0.0);
+            this->savedOrientation_ = this->getOrientation();
+        }
+
+        SUPER(FpsPlayer, tick, dt);
+    }
+
+    void FpsPlayer::changedMesh()
+    {
+        if (GameMode::showsGraphics())
+        {
+            if (this->mesh_.getEntity())
+                this->weaponNode_->detachObject(this->mesh_.getEntity());
+
+            this->mesh_.setMeshSource(this->getScene()->getSceneManager(), this->meshSrc_);
+
+            if (this->mesh_.getEntity())
+            {
+                this->weaponNode_->attachObject(this->mesh_.getEntity());
+            }
+        }
+    }
+
+    void FpsPlayer::setPlayer(PlayerInfo* player)
+    {
+        ControllableEntity::setPlayer(player);
+
+//        this->setSyncMode(ObjectDirection::ToClient);
+    }
+
+    void FpsPlayer::startLocalHumanControl()
+    {
+        ControllableEntity::startLocalHumanControl();
+    }
+
+    void FpsPlayer::moveFrontBack(const Vector2& value)
+    {
+        this->localVelocity_.z -= value.x;
+    }
+
+
+    void FpsPlayer::moveRightLeft(const Vector2& value)
+    {
+        this->localVelocity_.x += value.x;
+    }
+
+    void FpsPlayer::moveUpDown(const Vector2& value)
+    {
+        //this->localVelocity_.y += value.x;
+    }
+
+    void FpsPlayer::rotateYaw(const Vector2& value)
+    {
+        this->yaw_ += value.y;
+
+        ControllableEntity::rotateYaw(value);
+    }
+
+    void FpsPlayer::rotatePitch(const Vector2& value)
+    {
+        this->pitch_ += value.y;
+
+        ControllableEntity::rotatePitch(value);
+    }
+
+    void FpsPlayer::rotateRoll(const Vector2& value)
+    {
+        this->roll_ += value.y;
+
+        ControllableEntity::rotateRoll(value);
+    }
+
+    void FpsPlayer::fire()
+    {
+    }
+
+    void FpsPlayer::boost() //acctually jump
+    {
+        if (this->isFloor_)
+        {
+            if (!this->thisTickBoost_)
+                this->localVelocity_.y = jumpValue_;
+            //this->physicalBody_->applyCentralImpulse(btVector3(0, jumpvalue, 0));
+            this->thisTickBoost_ = true;
+            this->isFloor_ = false;
+        }
+    }
+
+    bool FpsPlayer::collidesAgainst(WorldEntity* otherObject, btManifoldPoint& contactPoint)
+    {
+        if (contactPoint.m_normalWorldOnB.y() > 0.6)
+            this->isFloor_ = true;
+        else
+            this->isFloor_ = false;
+
+        return false;
+    }
+
+    void FpsPlayer::addedWeaponPack(WeaponPack* wPack)
+    {
+        for (size_t i = 0; i < wPack->getNumWeapons(); ++i)
+        {
+            Weapon* weapon = wPack->getWeapon(i);
+            if (weapon->getWeaponSlot())
+            {
+                weapon->getWeaponSlot()->removeWeapon();
+                weapon->detachFromParent();
+                weapon->attachToNode(this->weaponNode_);
+            }
+        }
+    }
+}
Index: code/trunk/src/orxonox/worldentities/pawns/FpsPlayer.h
===================================================================
--- code/trunk/src/orxonox/worldentities/pawns/FpsPlayer.h	(revision 7163)
+++ code/trunk/src/orxonox/worldentities/pawns/FpsPlayer.h	(revision 7163)
@@ -0,0 +1,108 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Cyrill Frei
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _FpsPlayer_H__
+#define _FpsPlayer_H__
+
+#include "OrxonoxPrereqs.h"
+
+#include <string>
+#include <LinearMath/btVector3.h>
+#include "util/Math.h"
+#include "tools/Mesh.h"
+#include "Pawn.h"
+
+namespace orxonox
+{
+    class _OrxonoxExport FpsPlayer : public Pawn
+    {
+        public:
+            FpsPlayer(BaseObject* creator);
+            virtual ~FpsPlayer();
+
+            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
+            virtual void tick(float dt);
+            void registerVariables();
+            void setConfigValues();
+
+            virtual void moveFrontBack(const Vector2& value);
+            virtual void moveRightLeft(const Vector2& value);
+            virtual void moveUpDown(const Vector2& value);
+
+            virtual void rotateYaw(const Vector2& value);
+            virtual void rotatePitch(const Vector2& value);
+            virtual void rotateRoll(const Vector2& value);
+
+
+            inline void setMeshSource(const std::string& meshname)
+                { this->meshSrc_ = meshname; this->changedMesh(); }
+            inline const std::string& getMeshSource() const
+                { return this->meshSrc_; }
+
+            void boost(); //acctually jump
+
+            virtual void fire();
+
+            bool collidesAgainst(WorldEntity* otherObject, btManifoldPoint& contactPoint);
+
+            virtual void addedWeaponPack(WeaponPack* wPack);
+
+        protected:
+            virtual void setPlayer(PlayerInfo* player);
+            virtual void startLocalHumanControl();
+            bool bInvertYAxis_;
+
+            bool bBoost_;
+            bool bPermanentBoost_;
+            Vector3 steering_;
+            float primaryThrust_;
+            float auxilaryThrust_;
+            float rotationThrust_;
+            std::string weaponMashName_;
+            btVector3 localLinearAcceleration_;
+            btVector3 localAngularAcceleration_;
+
+        private:
+            virtual bool isCollisionTypeLegal(WorldEntity::CollisionType type) const;
+            float speed_;
+
+            void changedMesh();
+            Mesh mesh_;
+            std::string meshSrc_;
+            float yaw_;
+            float pitch_;
+            float roll_;
+            Vector3 localVelocity_;
+            bool isFloor_;
+            bool thisTickBoost_;
+            Quaternion savedOrientation_;
+            Ogre::SceneNode* weaponNode_;
+    };
+}
+
+#endif /* _FpsPlayer_H__ */
Index: code/trunk/src/orxonox/worldentities/pawns/Pawn.cc
===================================================================
--- code/trunk/src/orxonox/worldentities/pawns/Pawn.cc	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/pawns/Pawn.cc	(revision 7163)
@@ -53,5 +53,7 @@
     CreateFactory(Pawn);
 
-    Pawn::Pawn(BaseObject* creator) : ControllableEntity(creator)
+    Pawn::Pawn(BaseObject* creator)
+        : ControllableEntity(creator)
+        , RadarViewable(creator, static_cast<WorldEntity*>(this))
     {
         RegisterObject(Pawn);
@@ -64,4 +66,6 @@
         this->maxHealth_ = 0;
         this->initialHealth_ = 0;
+        this->shieldHealth_ = 0;
+        this->shieldAbsorption_ = 0.5;
 
         this->lastHitOriginator_ = 0;
@@ -78,6 +82,4 @@
         else
             this->weaponSystem_ = 0;
-        
-        this->setCarrierName("Pawn");
 
         this->setRadarObjectColour(ColourValue::Red);
@@ -105,4 +107,8 @@
         XMLPortParam(Pawn, "maxhealth", setMaxHealth, getMaxHealth, xmlelement, mode).defaultValues(200);
         XMLPortParam(Pawn, "initialhealth", setInitialHealth, getInitialHealth, xmlelement, mode).defaultValues(100);
+
+        XMLPortParam(Pawn, "shieldhealth", setShieldHealth, getShieldHealth, xmlelement, mode).defaultValues(0);
+        XMLPortParam(Pawn, "shieldabsorption", setShieldAbsorption, getShieldAbsorption, xmlelement, mode).defaultValues(0);
+
         XMLPortParam(Pawn, "spawnparticlesource", setSpawnParticleSource, getSpawnParticleSource, xmlelement, mode);
         XMLPortParam(Pawn, "spawnparticleduration", setSpawnParticleDuration, getSpawnParticleDuration, xmlelement, mode).defaultValues(3.0f);
@@ -116,9 +122,11 @@
     void Pawn::registerVariables()
     {
-        registerVariable(this->bAlive_,        VariableDirection::ToClient);
-        registerVariable(this->health_,        VariableDirection::ToClient);
-        registerVariable(this->initialHealth_, VariableDirection::ToClient);
-        registerVariable(this->bReload_,       VariableDirection::ToServer);
-        registerVariable(this->aimPosition_,   Bidirectionality::ServerMaster, 0, true);
+        registerVariable(this->bAlive_,           VariableDirection::ToClient);
+        registerVariable(this->health_,           VariableDirection::ToClient);
+        registerVariable(this->initialHealth_,    VariableDirection::ToClient);
+        registerVariable(this->shieldHealth_,     VariableDirection::ToClient);
+        registerVariable(this->shieldAbsorption_, VariableDirection::ToClient);
+        registerVariable(this->bReload_,          VariableDirection::ToServer);
+        registerVariable(this->aimPosition_,      VariableDirection::ToServer);  // For the moment this variable gets only transfered to the server
     }
 
@@ -162,5 +170,22 @@
         if (this->getGametype() && this->getGametype()->allowPawnDamage(this, originator))
         {
-            this->setHealth(this->health_ - damage);
+            //share the dealt damage to the shield and the Pawn.
+            float shielddamage = damage*this->shieldAbsorption_;
+            float healthdamage = damage*(1-this->shieldAbsorption_);
+
+            // In case the shield can not take all the shield damage.
+            if (shielddamage > this->getShieldHealth())
+            {
+                healthdamage += shielddamage-this->getShieldHealth();
+                this->setShieldHealth(0);
+            }
+
+            this->setHealth(this->health_ - healthdamage);
+
+            if (this->getShieldHealth() > 0)
+            {
+                this->setShieldHealth(this->shieldHealth_ - shielddamage);
+            }
+
             this->lastHitOriginator_ = originator;
 
@@ -336,5 +361,8 @@
     {
         if (this->weaponSystem_)
+        {
             this->weaponSystem_->addWeaponPack(wPack);
+            this->addedWeaponPack(wPack);
+        }
     }
 
@@ -342,6 +370,10 @@
     {
         if (this->weaponSystem_)
+        {
             if (!this->weaponSystem_->addWeaponPack(wPack))
                 wPack->destroy();
+            else
+                this->addedWeaponPack(wPack);
+        }
     }
 
Index: code/trunk/src/orxonox/worldentities/pawns/Pawn.h
===================================================================
--- code/trunk/src/orxonox/worldentities/pawns/Pawn.h	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/pawns/Pawn.h	(revision 7163)
@@ -50,5 +50,4 @@
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
             virtual void tick(float dt);
-            void registerVariables();
 
             inline bool isAlive() const
@@ -73,4 +72,14 @@
                 { return this->initialHealth_; }
 
+            inline void setShieldHealth(float shieldHealth)
+            { this->shieldHealth_ = shieldHealth; }
+            inline float getShieldHealth()
+            { return this->shieldHealth_; }
+
+            inline void setShieldAbsorption(float shieldAbsorption)
+            { this->shieldAbsorption_ = shieldAbsorption; }
+            inline float getShieldAbsorption()
+            { return this->shieldAbsorption_; }
+
             inline ControllableEntity* getLastHitOriginator() const
                 { return this->lastHitOriginator_; }
@@ -91,4 +100,6 @@
             void addWeaponPackXML(WeaponPack * wPack);
             WeaponPack * getWeaponPack(unsigned int index) const;
+
+            virtual void addedWeaponPack(WeaponPack* wPack) {}
 
             inline const WorldEntity* getWorldEntity() const
@@ -116,5 +127,5 @@
             Vector3 getAimPosition()
                 { return this->aimPosition_; }
-                
+
             virtual const Vector3& getCarrierPosition(void)
                 { return this->getWorldPosition(); };
@@ -141,4 +152,6 @@
             float maxHealth_;
             float initialHealth_;
+            float shieldHealth_;
+            float shieldAbsorption_; // Has to be between 0 and 1
 
             Pawn* lastHitOriginator_;
@@ -152,4 +165,5 @@
 
         private:
+            void registerVariables();
             inline void setWeaponSystem(WeaponSystem* weaponsystem)
                 { this->weaponSystem_ = weaponsystem; }
Index: code/trunk/src/orxonox/worldentities/pawns/SpaceShip.h
===================================================================
--- code/trunk/src/orxonox/worldentities/pawns/SpaceShip.h	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/pawns/SpaceShip.h	(revision 7163)
@@ -47,5 +47,4 @@
             virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
             virtual void tick(float dt);
-            void registerVariables();
             void setConfigValues();
 
@@ -99,7 +98,7 @@
 
         private:
+            void registerVariables();
             virtual bool isCollisionTypeLegal(WorldEntity::CollisionType type) const;
 
-        private:
             void loadEngineTemplate();
 
Index: code/trunk/src/orxonox/worldentities/pawns/Spectator.h
===================================================================
--- code/trunk/src/orxonox/worldentities/pawns/Spectator.h	(revision 6906)
+++ code/trunk/src/orxonox/worldentities/pawns/Spectator.h	(revision 7163)
@@ -44,5 +44,4 @@
 
             void setConfigValues();
-            void registerVariables();
             virtual void tick(float dt);
 
@@ -63,4 +62,5 @@
 
         private:
+            void registerVariables();
             void changedGreeting();
             void changedFlareVisibility();
