File stuntrally-master.patch of Package stuntrally

diff --git a/.travis.yml b/.travis.yml
index 9242cf0e..6d1408b7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,14 +14,15 @@ branches:
 
 before_install:
  - pwd
- - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
- - sudo apt-get update -qq
+ - sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
+ - sudo apt-get update -y -qq
  - sudo apt-get install -qq libboost-wave-dev libboost-system-dev libboost-filesystem-dev libboost-thread-dev
  - sudo apt-get install -qq libbullet-dev libbullet-extras-dev
  - sudo apt-get install -qq libopenal-dev
  - sudo apt-get install -qq libenet-dev libvorbisfile3 libogg-dev libvorbis-dev
  - sudo apt-get install -qq libogre-1.9-dev
  - sudo apt-get install -qq libmygui-dev
+ - sudo apt-get install -qq libegl1-mesa-dev libgles2-mesa-dev  # workaround https://github.com/travis-ci/travis-ci/issues/9065
  - sudo apt-get install -qq libsdl2-dev
 
 before_script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 684e34f4..7b3915fd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -83,7 +83,15 @@ list(APPEND LIBS ${Boost_LIBRARIES})
 
 # We can significantly reduce deps if only building master server
 if(BUILD_GAME OR BUILD_EDITOR)
-	find_package(OGRE REQUIRED QUIET)
+    find_package(OGRE QUIET CONFIG) # first try 1.10+ style
+    if(${OGRE_FOUND})
+        # 1.10+ puts everything in OGRE_INCLUDE_DIRS & OGRE_LIBRARIES
+        include_directories(${OGRE_INCLUDE_DIRS})
+        list(APPEND LIBS ${OGRE_LIBRARIES})
+        add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR}")
+        add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR}")
+    else()
+        find_package(OGRE REQUIRED QUIET)
         include_directories(${OGRE_INCLUDE_DIRS} ${OGRE_Terrain_INCLUDE_DIRS} ${OGRE_Paging_INCLUDE_DIRS})
         # Overlay moved to separate component in 1.9
         if (OGRE_VERSION_MAJOR GREATER 1 OR OGRE_VERSION_MINOR GREATER 8)
@@ -97,6 +105,7 @@ if(BUILD_GAME OR BUILD_EDITOR)
         endif()
         add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}")
         add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}")
+    endif()
 
 	find_package(Bullet REQUIRED QUIET)
 	include_directories(${BULLET_INCLUDE_DIRS})
diff --git a/Readme.txt b/Readme.txt
index c650bf50..6352630d 100644
--- a/Readme.txt
+++ b/Readme.txt
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------------
 
     Stunt Rally - game based on VDrift and OGRE, with Track Editor
-    Copyright (C) 2017  Crystal Hammer and contributors
+    Copyright (C) 2010-2021  Crystal Hammer and contributors
 
     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
@@ -45,7 +45,7 @@ Videos:  (gameplay and editor)
 
     Description
 
-The game features 172 tracks in 34 sceneries and 25 vehicles.
+The game features 173 tracks in 34 sceneries and 25 vehicles.
 Game modes include: Single Race, Tutorials, Championships, Challenges,
 Multiplayer and Split Screen. Also Replays and Ghost drive are present.
 
diff --git a/config/editor-default.cfg b/config/editor-default.cfg
index 71759260..d76ab4e7 100644
--- a/config/editor-default.cfg
+++ b/config/editor-default.cfg
@@ -135,6 +135,6 @@ limit_fps = off
 limit_fps_val = 60.000000
 limit_sleep = -1
 rendersystem = Default
-vsync = off
+vsync = on
 windowx = 1024
 windowy = 768
diff --git a/config/game-default.cfg b/config/game-default.cfg
index fbf02c9f..eda3992a 100644
--- a/config/game-default.cfg
+++ b/config/game-default.cfg
@@ -295,7 +295,7 @@ limit_fps = off
 limit_fps_val = 60.000000
 limit_sleep = -1
 rendersystem = Default
-vsync = off
+vsync = on
 windowx = 1024
 windowy = 768
 
diff --git a/config/tracks.ini b/config/tracks.ini
index 08ca2f62..58ca8cb8 100644
--- a/config/tracks.ini
+++ b/config/tracks.ini
@@ -276,3 +276,6 @@
 
 181,Mud5-Mudflats      v2.6 08/03/15 18/03/15 :Mud          |o3 c0 w4 ~2 J0 L0 P1 /3 s4 l5 !4 *3  T=300  a:rubberduck
 182,Cry3-BlueHell      v2.6 11/03/15 18/03/15 :Crystals     |o0 c3 w1 ~1 J2 L3 P3 /3 s3 l6 !6 *5  T=310  a:rubberduck,CryHam
+
+    #168 2.6.2 ?
+183,Grc9-Oasis         v2.7 28/11/20 29/11/20 :Greece       |o1 c3 w1 ~1 J3 L4 P4 /3 s3 l8 !5 *5  T=241  a:CryHam
diff --git a/data/compositor/softparticles/softparticles.material b/data/compositor/softparticles/softparticles.material
index 6c499188..14ec9b45 100644
--- a/data/compositor/softparticles/softparticles.material
+++ b/data/compositor/softparticles/softparticles.material
@@ -66,30 +66,6 @@ fragment_program ShowDepth_ps unified
     delegate ShowDepth_ps_hlsl
 }
 
-
-material RenderScene
-{
-	technique
-    {
-        pass
-        {
-			vertex_program_ref Ogre/Compositor/StdQuad_vp
-			{
-			}
-        
-			fragment_program_ref Ogre/Compositor/StdQuad_fp
-			{
-			}
-
-			texture_unit tex1
-			{
-				//scenebuffer
-				texture white.png
-				filtering bilinear
-			}
-		}
-	}
-}
 material SceneRenderNoDepth
 {
 	technique
diff --git a/data/gui/stuntrally.png b/data/gui/stuntrally.png
index 614e706c..f8d3ce16 100644
Binary files a/data/gui/stuntrally.png and b/data/gui/stuntrally.png differ
diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt
index 3b4cb45b..bed44879 100644
--- a/dist/CMakeLists.txt
+++ b/dist/CMakeLists.txt
@@ -1,6 +1,7 @@
 
 if(UNIX)
 	install(FILES stuntrally.desktop sr-editor.desktop DESTINATION "share/applications/")
-	install(FILES ../data/gui/stuntrally.png ../data/gui/sr-editor.png DESTINATION "share/icons/hicolor/64x64/apps/")
+	install(FILES ../data/gui/stuntrally.png DESTINATION "share/icons/hicolor/256x256/apps/")
+	install(FILES ../data/gui/sr-editor.png DESTINATION "share/icons/hicolor/64x64/apps/")
 endif()
 
diff --git a/dist/linux-archive/stuntrally b/dist/linux-archive/stuntrally
index 9145e6b3..f9bdcc5c 100755
--- a/dist/linux-archive/stuntrally
+++ b/dist/linux-archive/stuntrally
@@ -26,6 +26,18 @@ export OGRE_PLUGIN_DIR="$LIBPATH"
 
 if [ "$(uname -m)" = "x86_64" ]; then
 	"$BINPATH/stuntrally_x86_64" $*
+	ret=$?
+	if [ $ret -eq 139 ]; then
+		cat - <<EOHELP
+----------------------------
+This might be a known crash!
+You can try to rename (disable) libstdc++.so.6 with the command:
+
+mv $LIBPATH/libstdc++.so.6 $LIBPATH/libstdc++.so.6.disabled
+
+and call $0 again
+EOHELP
+	fi
 else
 	"$BINPATH/stuntrally_x86" $*
 fi
diff --git a/source/btOgre/BtOgreDebug.cpp b/source/btOgre/BtOgreDebug.cpp
index d78cff73..bc4f6589 100644
--- a/source/btOgre/BtOgreDebug.cpp
+++ b/source/btOgre/BtOgreDebug.cpp
@@ -11,6 +11,7 @@
 
 #include <math.h>
 
+#include <OgrePrerequisites.h>
 #include <OgreSceneNode.h>
 #include <OgreResourceGroupManager.h>
 #include <OgreMaterial.h>
@@ -38,7 +39,11 @@ DebugDrawer::DebugDrawer(Ogre::SceneNode *node, btDynamicsWorld *world) :
 	mat->setReceiveShadows(false);
 	mat->setLightingEnabled(false);
 	//mat->setSelfIllumination(1,1,1);
+#if defined(OGRE_VERSION) && OGRE_VERSION < 0x10A00
 	mLineDrawer->setMaterial("BtOgre/DebugLines");/**/  //crash debug..
+#else
+	mLineDrawer->setMaterial(mat);/**/  //crash debug..
+#endif
 	mLineDrawer->setVisibilityFlags(2/*RV_Hud*/);  // not in reflection
 }
 
diff --git a/source/editor/BaseApp_Create.cpp b/source/editor/BaseApp_Create.cpp
index e49cb40a..dcec7cba 100644
--- a/source/editor/BaseApp_Create.cpp
+++ b/source/editor/BaseApp_Create.cpp
@@ -27,6 +27,7 @@
 #include <MyGUI_FactoryManager.h>
 #include <MyGUI_ImageBox.h>
 #include <MyGUI_TextBox.h>
+#include <OgreWindowEventUtilities.h>
 
 namespace
 {
@@ -286,6 +287,9 @@ bool BaseApp::setup()
 	}
 
 	mRoot->loadPlugin(PATHMANAGER::OgrePluginDir() + "/Plugin_ParticleFX" + D_SUFFIX);
+#if defined(OGRE_VERSION) && OGRE_VERSION >= 0x10B00
+    mRoot->loadPlugin(PATHMANAGER::OgrePluginDir() + "/Codec_STBI" + D_SUFFIX);
+#endif
 
 	setupResources();
 
@@ -304,6 +308,7 @@ bool BaseApp::setup()
 	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
 	mSceneMgr->setFog(Ogre::FOG_NONE);
 
+    postInit();
 	loadResources();
 
 	baseInitGui();
@@ -344,6 +349,16 @@ void BaseApp::setupResources()
 				PATHMANAGER::Data() + "/" + archName, typeName, secName);
 		}
 	}
+
+#if defined(OGRE_VERSION) && OGRE_VERSION >= 0x10C00
+	using namespace Ogre;
+    // create stubs for Ogre 1.12 core shaders (unused by stuntrally)
+    auto& gpm = HighLevelGpuProgramManager::getSingleton();
+    for(auto name : {"PointLight", "DirLight", "PointLightFinite", "DirLightFinite"})
+        gpm.createProgram("Ogre/ShadowExtrude"+String(name), "OgreInternal", "unified", GPT_VERTEX_PROGRAM);
+    gpm.createProgram("Ogre/ShadowBlendVP", "OgreInternal", "unified", GPT_VERTEX_PROGRAM);
+    gpm.createProgram("Ogre/ShadowBlendFP", "OgreInternal", "unified", GPT_FRAGMENT_PROGRAM);
+#endif
 }
 
 void BaseApp::loadResources()
diff --git a/source/editor/CApp.h b/source/editor/CApp.h
index f1976b72..93a8936a 100644
--- a/source/editor/CApp.h
+++ b/source/editor/CApp.h
@@ -137,7 +137,8 @@ public:
 		float Size,Intens,Pow,Fq,NOf;
 		int Oct;  EBrShape shape;
 		float Filter,HSet;
-		char newLine;  Ogre::String name;
+		signed char newLine;
+		Ogre::String name;
 	};
 
 	const static int brSetsNum = 87;
diff --git a/source/editor/Render2tex.cpp b/source/editor/Render2tex.cpp
index 37dfdcca..bfdd02f5 100644
--- a/source/editor/Render2tex.cpp
+++ b/source/editor/Render2tex.cpp
@@ -13,6 +13,7 @@
 #include <btBulletDynamicsCommon.h>
 #include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
 
+#include <OgrePrerequisites.h>
 #include <OgreTimer.h>
 #include <OgreTerrain.h>
 #include <OgreRenderWindow.h>
@@ -25,6 +26,8 @@
 #include <OgreViewport.h>
 #include <OgreMaterialManager.h>
 #include <OgreSceneNode.h>
+#include <OgreTechnique.h>
+#include <OgrePass.h>
 using namespace Ogre;
 
 
@@ -43,6 +46,7 @@ void App::Rnd2TexSetup()
 	xm1 = 1-sz/asp, ym1 = -1+sz, xm2 = 1.0, ym2 = -1.0;
 	AxisAlignedBox aab;  aab.setInfinite();
 	
+	TexturePtr texture[RTs];
 	for (int i=0; i < RTs+RTsAdd; ++i)
 	{
 		SRndTrg& r = rt[i];  bool full = i==3;
@@ -56,7 +60,7 @@ void App::Rnd2TexSetup()
 			
 			///  rnd to tex - same dim as Hmap	// after track load
 			Real fDim = scn->sc->td.fTerWorldSize;  // world dim  ..vdr
-			TexturePtr texture = TextureManager::getSingleton().createManual(
+			texture[i] = TextureManager::getSingleton().createManual(
 				sTex, rgDef, TEX_TYPE_2D,
 				dim[i], dim[i], 0, PF_R8G8B8A8, TU_RENDERTARGET);
 				  
@@ -66,7 +70,7 @@ void App::Rnd2TexSetup()
 			r.cam->setAspectRatio(1.0);			if (!full)  r.cam->setProjectionType(PT_ORTHOGRAPHIC);
 			r.cam->setOrthoWindow(fDim,fDim);	//rt[i].rndCam->setPolygonMode(PM_WIREFRAME);
 
-			r.tex = texture->getBuffer()->getRenderTarget();
+			r.tex = texture[i]->getBuffer()->getRenderTarget();
 			r.tex->setAutoUpdated(false);	r.tex->addListener(this);
 			Viewport* rvp = r.tex->addViewport(r.cam);
 			rvp->setClearEveryFrame(true);   rvp->setBackgroundColour(ColourValue(0,0,0,0));
@@ -78,7 +82,16 @@ void App::Rnd2TexSetup()
 		}
 		///  minimap  . . . . . . . . . . . . . . . . . . . . . . . . . . . 
 		if (r.ndMini)  mSceneMgr->destroySceneNode(r.ndMini);
-		ResourcePtr mt = MaterialManager::getSingleton().getByName(sMtr);
+		MaterialPtr mt = MaterialManager::getSingleton().getByName(sMtr);
+	#if defined(OGRE_VERSION) && OGRE_VERSION >= 0x10A00
+		if (i == 3)
+		{	mt->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTexture(texture[0]);
+			mt->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTexture(texture[2]);
+		}else if (i < RTs)
+			mt->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTexture(texture[i]);
+		else if (i == RTs)
+			mt->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTexture(texture[3]);
+	#endif
 		if (!mt.isNull())  mt->reload();
 
 		r.mini = new Rectangle2D(true);  // screen rect preview
@@ -88,7 +101,12 @@ void App::Rnd2TexSetup()
 		r.mini->setBoundingBox(aab);
 		r.ndMini = mSceneMgr->getRootSceneNode()->createChildSceneNode("Minimap"+si);
 		r.ndMini->attachObject(r.mini);	r.mini->setCastShadows(false);
+#if defined(OGRE_VERSION) && OGRE_VERSION < 0x10A00
 		r.mini->setMaterial(i == RTs+1 ? "BrushPrvMtr" : sMtr);
+#else
+		MaterialPtr brush_mt = MaterialManager::getSingleton().getByName("BrushPrvMtr");
+		r.mini->setMaterial(i == RTs+1 ? brush_mt : mt);
+#endif
 		r.mini->setRenderQueueGroup(RQG_Hud2);
 		r.mini->setVisibilityFlags(i == RTs ? RV_MaskPrvCam : RV_Hud);
 	}
diff --git a/source/editor/SceneInit.cpp b/source/editor/SceneInit.cpp
index 9b3f9ce8..0fbe4b76 100644
--- a/source/editor/SceneInit.cpp
+++ b/source/editor/SceneInit.cpp
@@ -29,6 +29,7 @@
 #include <OgreViewport.h>
 #include <OgreMaterialManager.h>
 #include <OgreTextureManager.h>
+#include <OgreResourceGroupManager.h>
 #include <OgreSceneNode.h>
 #include "../ogre/common/MessageBox/MessageBox.h"
 #include "../ogre/common/Instancing.h"
@@ -82,9 +83,6 @@ void App::createScene()  // once, init
 	
 	LogO(String("::: Time load xmls: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");
 
-
-	postInit();  // material factory
-
 	//  gui  * * *
 	if (pSet->startInMain)
 		pSet->isMain = true;
@@ -174,10 +172,10 @@ void App::NewCommon(bool onlyTerVeget)
 	//world.Clear();
 	if (track)  track->Clear();
 
-	if (resTrk != "")  mRoot->removeResourceLocation(resTrk);
+	if (resTrk != "")  ResourceGroupManager::getSingleton().removeResourceLocation(resTrk);
 	LogO("------  Loading track: "+pSet->gui.track);
 	resTrk = gcom->TrkDir() + "objects";
-	mRoot->addResourceLocation(resTrk, "FileSystem");
+	ResourceGroupManager::getSingleton().addResourceLocation(resTrk, "FileSystem");
 
 	MeshManager::getSingleton().unloadUnreferencedResources();
 	sh::Factory::getInstance().unloadUnreferencedMaterials();
diff --git a/source/editor/TerrainBrushes.cpp b/source/editor/TerrainBrushes.cpp
index 585aba3e..dcdc2ee2 100644
--- a/source/editor/TerrainBrushes.cpp
+++ b/source/editor/TerrainBrushes.cpp
@@ -5,7 +5,7 @@
 //  Brush Presets data
 //---------------------------------------------------------------------------------------------------------------
 const App::BrushSet App::brSets[App::brSetsNum] = {
-//ED_MODE,curBr,  Size, Intens,  Pow, Freq,  Ofs, Oct, EBrShape, Filter, HSet,  Name
+	//ED_MODE,curBr,Size,Intens, Pow,  Freq,  Ofs, Oct, EBrShape,  Filter,HSet, newLine, Name
 //------  easy sinus
 	{ED_Deform,0,  16.f, 10.f,   2.f,  1.f,   0.f, 5,   BRS_Sinus,  -1.f,-0.01f, 0, "Small"},
 	{ED_Deform,0,  32.f, 20.f,   2.f,  1.f,   0.f, 5,   BRS_Sinus,  -1.f,-0.01f, 0, "Medium"},
diff --git a/source/ogre/BaseApp.cpp b/source/ogre/BaseApp.cpp
index 6cc753b7..60c4892b 100644
--- a/source/ogre/BaseApp.cpp
+++ b/source/ogre/BaseApp.cpp
@@ -86,8 +86,9 @@ void BaseApp::updateStats()
 				{
 					std::string textureName = c->getTechnique()->getTargetPass(j)->getOutputName();
 					rt = c->getRenderTarget(textureName);
-					tris += rt->getTriangleCount();
-					batch += rt->getBatchCount();
+					const RenderTarget::FrameStats& rt_stats = rt->getStatistics();
+					tris += rt_stats.triangleCount;
+					batch += rt_stats.batchCount;
 			}	}
 		}else
 		{
diff --git a/source/ogre/BaseApp_Create.cpp b/source/ogre/BaseApp_Create.cpp
index ca9cef75..66505ce9 100644
--- a/source/ogre/BaseApp_Create.cpp
+++ b/source/ogre/BaseApp_Create.cpp
@@ -353,6 +353,9 @@ bool BaseApp::setup()
 	}
 
 	mRoot->loadPlugin(PATHMANAGER::OgrePluginDir() + "/Plugin_ParticleFX" + D_SUFFIX);
+#if defined(OGRE_VERSION) && OGRE_VERSION >= 0x10B00
+    mRoot->loadPlugin(PATHMANAGER::OgrePluginDir() + "/Codec_STBI" + D_SUFFIX);
+#endif
 
 	#ifdef _DEBUG
 	LogManager::getSingleton().setLogDetail(LL_BOREME);//
@@ -386,9 +389,7 @@ bool BaseApp::setup()
 		LogO(String(":::: Time setup gui: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");  ti.reset();
 
 	createResourceListener();
-	loadResources();
 
-		LogO(String(":::: Time resources: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");  ti.reset();
 
 	LogO("*** createFrameListener ***");
 	createFrameListener();
@@ -416,6 +417,10 @@ bool BaseApp::setup()
 
 		LogO(String(":::: Time post, mat factory: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");  ti.reset();
 
+	loadResources();
+
+		LogO(String(":::: Time resources: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");  ti.reset();  
+
 	LogO(String(":::: Time setup total: ") + fToStr(ti2.getMilliseconds(),0,3) + " ms");
 	
 	return true;
@@ -451,6 +456,15 @@ void BaseApp::setupResources()
 			ResourceGroupManager::getSingleton().addResourceLocation(
 				PATHMANAGER::Data() + "/" + archName, typeName, secName);
 	}	}
+
+#if defined(OGRE_VERSION) && OGRE_VERSION >= 0x10C00
+	// create stubs for Ogre 1.12 core shaders (unused by stuntrally)
+	auto& gpm = HighLevelGpuProgramManager::getSingleton();
+	for(auto name : {"PointLight", "DirLight", "PointLightFinite", "DirLightFinite"})
+	    gpm.createProgram("Ogre/ShadowExtrude"+String(name), "OgreInternal", "unified", GPT_VERTEX_PROGRAM);
+	gpm.createProgram("Ogre/ShadowBlendVP", "OgreInternal", "unified", GPT_VERTEX_PROGRAM);
+	gpm.createProgram("Ogre/ShadowBlendFP", "OgreInternal", "unified", GPT_FRAGMENT_PROGRAM);
+#endif
 }
 
 void BaseApp::createResourceListener()
diff --git a/source/ogre/BaseApp_Effects.cpp b/source/ogre/BaseApp_Effects.cpp
index 77cdc6c8..06d85e0d 100644
--- a/source/ogre/BaseApp_Effects.cpp
+++ b/source/ogre/BaseApp_Effects.cpp
@@ -9,12 +9,13 @@
 #include "SplitScreen.h"
 //#include "HDRCompositor.h"
 
-#include <OgreRoot.h>
 #include <OgreCompositorManager.h>
 #include <OgreCompositionTargetPass.h>
 #include <OgreCompositionPass.h>
 #include <OgreTechnique.h>
 #include <OgreCompositor.h>
+#include <OgreResourceGroupManager.h>
+
 using namespace Ogre;
 
 
@@ -135,16 +136,16 @@ void BaseApp::recreateCompositor()
 	if (!ResourceGroupManager::getSingleton().resourceGroupExists("Effects"))
 	{
 		std::string sPath = PATHMANAGER::Data() + "/compositor";
-		mRoot->addResourceLocation(sPath, "FileSystem", "Effects");
-		mRoot->addResourceLocation(sPath + "/gbuffer", "FileSystem", "Effects");
-		mRoot->addResourceLocation(sPath + "/bloom", "FileSystem", "Effects");
-		mRoot->addResourceLocation(sPath + "/hdr", "FileSystem", "Effects");
-		mRoot->addResourceLocation(sPath + "/motionblur", "FileSystem", "Effects");
-		mRoot->addResourceLocation(sPath + "/ssao", "FileSystem", "Effects");
-		mRoot->addResourceLocation(sPath + "/softparticles", "FileSystem", "Effects");
-		mRoot->addResourceLocation(sPath + "/dof", "FileSystem", "Effects");
-		mRoot->addResourceLocation(sPath + "/godrays", "FileSystem", "Effects");
-		mRoot->addResourceLocation(sPath + "/filmgrain", "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath, "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath + "/gbuffer", "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath + "/bloom", "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath + "/hdr", "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath + "/motionblur", "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath + "/ssao", "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath + "/softparticles", "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath + "/dof", "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath + "/godrays", "FileSystem", "Effects");
+		ResourceGroupManager::getSingleton().addResourceLocation(sPath + "/filmgrain", "FileSystem", "Effects");
 		ResourceGroupManager::getSingleton().initialiseResourceGroup("Effects");
 	}
 
diff --git a/source/ogre/CarModel_Create.cpp b/source/ogre/CarModel_Create.cpp
index f53d88f8..084b89ce 100644
--- a/source/ogre/CarModel_Create.cpp
+++ b/source/ogre/CarModel_Create.cpp
@@ -16,12 +16,12 @@
 #include "../road/Road.h"
 #include "../shiny/Main/Factory.hpp"
 #include "../network/gameclient.hpp"
-#include <OgreRoot.h>
 #include <OgreTerrain.h>
 #include <OgreEntity.h>
 #include <OgreManualObject.h>
 #include <OgreSubMesh.h>
 #include <OgreMaterialManager.h>
+#include <OgreResourceGroupManager.h>
 #include <OgreParticleSystem.h>
 #include <OgreParticleEmitter.h>
 #include <OgreParticleAffector.h>
@@ -401,8 +401,8 @@ void CarModel::Create()
 	//  Resource locations -----------------------------------------
 	/// Add a resource group for this car
 	ResourceGroupManager::getSingleton().createResourceGroup(resGrpId);
-	Root::getSingletonPtr()->addResourceLocation(sCars, "FileSystem", resGrpId);
-	Root::getSingletonPtr()->addResourceLocation(sCars + "/textures", "FileSystem", resGrpId);
+	ResourceGroupManager::getSingleton().addResourceLocation(sCars, "FileSystem", resGrpId);
+	ResourceGroupManager::getSingleton().addResourceLocation(sCars + "/textures", "FileSystem", resGrpId);
 		
 	SceneNode* ndRoot = mSceneMgr->getRootSceneNode();
 	pMainNode = ndRoot->createChildSceneNode();  ToDel(pMainNode);
@@ -645,8 +645,10 @@ void CarModel::Create()
 	//  this snippet makes sure the brake texture is pre-loaded.
 	//  since it is not used until you actually brake, we have to explicitely declare it
 	ResourceGroupManager& resMgr = ResourceGroupManager::getSingleton();
-	if (FileExists(rCar + "_body00_brake.png")) resMgr.declareResource(sDirname + "_body00_brake.png", "Texture", resGrpId);
-	if (FileExists(rCar + "_body00_add.png"))   resMgr.declareResource(sDirname + "_body00_add.png", "Texture", resGrpId);
+	if (FileExists(rCar + "_body00_brake.png") && !resMgr.resourceExists(resGrpId, sDirname + "_body00_brake.png"))
+		resMgr.declareResource(sDirname + "_body00_brake.png", "Texture", resGrpId);
+	if (FileExists(rCar + "_body00_add.png") && !resMgr.resourceExists(resGrpId, sDirname + "_body00_add.png"))
+		resMgr.declareResource(sDirname + "_body00_add.png", "Texture", resGrpId);
 	
 	//  now just preload the whole resource group
 	resMgr.initialiseResourceGroup(resGrpId);
diff --git a/source/ogre/SceneInit.cpp b/source/ogre/SceneInit.cpp
index dacc9b9b..738a88df 100644
--- a/source/ogre/SceneInit.cpp
+++ b/source/ogre/SceneInit.cpp
@@ -26,6 +26,8 @@
 #include <MyGUI_PointerManager.h>
 #include <OgreTerrainGroup.h>
 #include <OgreParticleSystem.h>
+#include <OgreResourceGroupManager.h>
+
 using namespace MyGUI;
 using namespace Ogre;
 
@@ -255,10 +257,10 @@ void App::LoadCleanUp()  // 1 first
 	// rem old track
 	if (dstTrk)
 	{
-		if (resTrk != "")  mRoot->removeResourceLocation(resTrk);
+		if (resTrk != "")  ResourceGroupManager::getSingleton().removeResourceLocation(resTrk);
 		LogO("------  Loading track: "+pSet->game.track);
 		resTrk = gcom->TrkDir() + "objects";
-		mRoot->addResourceLocation(resTrk, "FileSystem");
+		ResourceGroupManager::getSingleton().addResourceLocation(resTrk, "FileSystem");
 	}
 	
 	//  Delete all cars
diff --git a/source/ogre/SplitScreen.cpp b/source/ogre/SplitScreen.cpp
index 80455f39..8627b3e5 100644
--- a/source/ogre/SplitScreen.cpp
+++ b/source/ogre/SplitScreen.cpp
@@ -204,7 +204,7 @@ void SplitScr::preViewportUpdate(const RenderTargetViewportEvent& evt)
 
 		//  Update HUD for this car
 		pApp->hud->ShowVp(true);
-		pApp->hud->Update(carId, 1.f / mWindow->getLastFPS());
+		pApp->hud->Update(carId, 1.f / mWindow->getStatistics().lastFPS);
 
 		///  Set sky pos to camera  - TODO: fix, sky is center only for last player ...
 		//  idea: with compositor this needs separate sky nodes (own sky for each player) and showing 1 sky for 1 player
@@ -266,7 +266,7 @@ void SplitScr::preViewportUpdate(const RenderTargetViewportEvent& evt)
 	else
 	{
 		//  Gui viewport - hide stuff we don't want
-		pApp->hud->Update(-1, 1.f / mWindow->getLastFPS());
+		pApp->hud->Update(-1, 1.f / mWindow->getStatistics().lastFPS);
 		pApp->hud->ShowVp(false);
 		
 		// no mouse in key capture mode
diff --git a/source/ogre/common/GuiCom_Screen.cpp b/source/ogre/common/GuiCom_Screen.cpp
index 0b1ddbff..d8976c61 100644
--- a/source/ogre/common/GuiCom_Screen.cpp
+++ b/source/ogre/common/GuiCom_Screen.cpp
@@ -102,7 +102,7 @@ void CGuiCom::InitGuiScreenRes()
 		String modeSel = "";
 		std::vector<ScrRes> vRes;
 
-		const StringVector& videoModes = app->mRoot->getRenderSystem()->getConfigOptions()["Video Mode"].possibleValues;
+		const StringVector& videoModes = app->mRoot->getRenderSystem()->getConfigOptions().find("Video Mode")->second.possibleValues;
 		for (int i=0; i < videoModes.size(); ++i)
 		{
 			String mode = videoModes[i];
diff --git a/source/ogre/common/SceneTrees.cpp b/source/ogre/common/SceneTrees.cpp
index 41703878..7bd7be93 100644
--- a/source/ogre/common/SceneTrees.cpp
+++ b/source/ogre/common/SceneTrees.cpp
@@ -256,10 +256,8 @@ void CScene::CreateTrees()
 					ImpostorTexture* it = new ImpostorTexture(&group, ent, true);  // only to renderTextures()
 					delete it;
 				}
-				if (resMgr.resourceExistsInAnyGroup(fpng))
 				try
 				{	TextureManager::getSingleton().load(fpng, "BinFolder", TEX_TYPE_2D, MIP_UNLIMITED);  ///T png first
-					resMgr.declareResource(fpng, "Texture", "BinFolder");  // preload
 				}catch (Ogre::Exception&)
 				{	}
 			}
@@ -437,15 +435,6 @@ void CScene::CreateTrees()
 				#endif
 			}
 		}
-		if (imp)
-		{
-			resMgr.initialiseResourceGroup("BinFolder");
-			try  {
-				resMgr.loadResourceGroup("BinFolder");
-			}catch (Ogre::Exception& e)  {  // does throw not found impostors png sometimes, why?
-				LogO(e.getFullDescription());
-			}
-		}
 		trees->update();
 		
 		LogO(String("***** Vegetation objects count: ") + toStr(cntr) + "  shapes: " + toStr(cntshp));
diff --git a/source/ogre/common/Shadows.cpp b/source/ogre/common/Shadows.cpp
index 2354ddb5..1db3da2e 100644
--- a/source/ogre/common/Shadows.cpp
+++ b/source/ogre/common/Shadows.cpp
@@ -17,6 +17,7 @@
 #include "../../paged-geom/PagedGeometry.h"
 #include "../../paged-geom/GrassLoader.h"
 
+#include <OgrePrerequisites.h>
 #include <OgreTimer.h>
 #include <OgreTerrain.h>
 #include <OgreShadowCameraSetupLiSPSM.h>
@@ -163,8 +164,12 @@ void CScene::changeShadows()
 		
 		mSceneMgr->setShadowTextureSelfShadow(bDepth ? true : false);  //-?
 		mSceneMgr->setShadowCasterRenderBackFaces((bDepth && !bSoft) ? true : false);
-
+#if defined(OGRE_VERSION) && OGRE_VERSION < 0x10A00
 		mSceneMgr->setShadowTextureCasterMaterial(bDepth ? "shadowcaster_default" : "");
+#else
+		MaterialPtr shadowcast_mt = MaterialManager::getSingleton().getByName("shadowcaster_default");
+		if (bDepth)  mSceneMgr->setShadowTextureCasterMaterial(shadowcast_mt);
+#endif
 	}
 
 	mSceneMgr->setShadowColour(ColourValue(0,0,0,1));
diff --git a/source/ogre/common/Sky.cpp b/source/ogre/common/Sky.cpp
index 988ba858..2e7c6f1b 100644
--- a/source/ogre/common/Sky.cpp
+++ b/source/ogre/common/Sky.cpp
@@ -151,7 +151,7 @@ void CScene::UpdateWeather(Camera* cam, float mul)
 	const Vector3& pos = cam->getPosition(), dir = cam->getDirection();
 	static Vector3 oldPos = Vector3::ZERO;
 
-	Vector3 vel = (pos-oldPos) * app->mWindow->getLastFPS();  oldPos = pos;
+	Vector3 vel = (pos-oldPos) * app->mWindow->getStatistics().lastFPS;  oldPos = pos;
 	Vector3 par = pos + dir * 12.f + vel * 0.6f;
 
 	if (pr && sc->rainEmit > 0)
diff --git a/source/ogre/common/TerrainBlend.cpp b/source/ogre/common/TerrainBlend.cpp
index 2de87a8c..db8bc20e 100644
--- a/source/ogre/common/TerrainBlend.cpp
+++ b/source/ogre/common/TerrainBlend.cpp
@@ -9,6 +9,7 @@
 #else
 	#include "../CGame.h"
 #endif
+#include <OgrePrerequisites.h>
 #include <OgreRoot.h>
 #include <OgreTimer.h>
 #include <OgreTerrain.h>
@@ -17,6 +18,7 @@
 #include <OgreRectangle2D.h>
 #include <OgreViewport.h>
 #include <OgreSceneNode.h>
+#include <OgreMaterialManager.h>
 #include <OgreTextureManager.h>
 #include <OgreRenderTexture.h>
 #include "../../shiny/Main/Factory.hpp"
@@ -50,7 +52,12 @@ void CScene::RenderToTex::Setup(Root* rt, String sName, TexturePtr pTex, String
 	rect = new Rectangle2D(true);   rect->setCorners(-1,1,1,-1);
 	AxisAlignedBox aab;  aab.setInfinite();
 	rect->setBoundingBox(aab);  rect->setCastShadows(false);
-	rect->setMaterial( sMtr );
+#if defined(OGRE_VERSION) && OGRE_VERSION < 0x10A00
+	rect->setMaterial(sMtr);
+#else
+	MaterialPtr mtr = MaterialManager::getSingleton().getByName(sMtr);
+	rect->setMaterial(mtr);
+#endif
 
 	nd = scm->getRootSceneNode()->createChildSceneNode(sName+"N");
 	nd->attachObject(rect);
@@ -85,9 +92,9 @@ void CScene::CreateBlendTex()
 	
 	//  Blendmap rtt
 	blendRTex = texMgr.createManual( sBlend, rgDef, TEX_TYPE_2D,
-		size, size, 0, PF_R8G8B8A8, TU_RENDERTARGET);
+		size, size, 0, PF_BYTE_BGRA, TU_RENDERTARGET);
 	if (blendRTex.isNull())
-		LogO("Error: Can't create RGBA (Blendmap) RenderTarget!");
+		LogO("Error: Can't create BGRA (Blendmap) RenderTarget!");
 
 	//  rtt copy  (not needed)
 	//blMap = texMgr.createManual("blendmapT", rgDef, TEX_TYPE_2D,
@@ -124,8 +131,8 @@ void CScene::UpdBlendmap()
 	pt->lock(HardwareBuffer::HBL_DISCARD);
 
 	const PixelBox& pb = pt->getCurrentLock();
-	float* pD = static_cast<float*>(pb.data);
-	size_t aD = pb.getRowSkip() * PixelUtil::getNumElemBytes(pb.format);
+	float* pD = reinterpret_cast<float*>(pb.data);
+	size_t aD = pb.getRowSkip();
 	 
 	register size_t j,i,a=0;
 	for (j = 0; j < size; ++j)
diff --git a/source/paged-geom/BatchedGeometry.cpp b/source/paged-geom/BatchedGeometry.cpp
index 7ed4e504..7fce9244 100644
--- a/source/paged-geom/BatchedGeometry.cpp
+++ b/source/paged-geom/BatchedGeometry.cpp
@@ -176,9 +176,15 @@ uint32 CountUsedVertices(IndexData *id, std::map<uint32, uint32> &ibmap)
             uint16 *data = (uint16*)id->indexBuffer->lock(id->indexStart * sizeof(uint16), 
                id->indexCount * sizeof(uint16), HardwareBuffer::HBL_READ_ONLY);
 
-            for (i = 0; i < id->indexCount; ++i) {
+            for (i = 0; i < id->indexCount; i++) {
                uint16 index = data[i];
-               if (ibmap.find(index) == ibmap.end()) ibmap[index] = (uint32)(ibmap.size());
+               if (ibmap.find(index) == ibmap.end()) 
+	       {
+		    // use separate lines to avoid undefined compiler behavior.
+		    //   see: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r3.pdf?fbclid=IwAR2Wp4bQWvl0O9t7kBIXeiRsOxwxU8bttpes-gK71x_2j0ABtzGD5mcoF_c
+		    uint32 size = (uint32)(ibmap.size()); 
+		    ibmap[index] = size;
+	       }
             }
             count = (uint32)ibmap.size();
             id->indexBuffer->unlock();
@@ -190,9 +196,15 @@ uint32 CountUsedVertices(IndexData *id, std::map<uint32, uint32> &ibmap)
             uint32 *data = (uint32*)id->indexBuffer->lock(id->indexStart * sizeof(uint32), 
                id->indexCount * sizeof(uint32), HardwareBuffer::HBL_READ_ONLY);
 
-            for (i = 0; i < id->indexCount; ++i) {
+            for (i = 0; i < id->indexCount; i++) {
                uint32 index = data[i];
-               if (ibmap.find(index) == ibmap.end()) ibmap[index] = (uint32)(ibmap.size());
+               if (ibmap.find(index) == ibmap.end()) 
+	       {
+		    // use separate lines to avoid undefined compiler behavior.
+		    //   see: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r3.pdf?fbclid=IwAR2Wp4bQWvl0O9t7kBIXeiRsOxwxU8bttpes-gK71x_2j0ABtzGD5mcoF_c
+		    uint32 size = (uint32)(ibmap.size()); 
+		    ibmap[index] = size;
+	       }
             }
             count = (uint32)ibmap.size();
             id->indexBuffer->unlock();
@@ -200,7 +212,7 @@ uint32 CountUsedVertices(IndexData *id, std::map<uint32, uint32> &ibmap)
          break;
 
       default:
-         throw new Ogre::Exception(0, "Unknown index buffer type", "Converter.cpp::CountVertices");
+         throw new Ogre::Exception(Exception::ERR_INVALIDPARAMS, "Unknown index buffer type", "Converter.cpp::CountVertices");
          break;
    }
 
@@ -369,8 +381,8 @@ void BatchedGeometry::clear()
    {
       m_pSceneNode->removeAllChildren();
       if (m_pSceneNode->getParent())
-         m_pSceneNode->getParentSceneNode()->removeAndDestroyChild(m_pSceneNode->getName());
-      else
+         m_pSceneNode->getParentSceneNode()->removeChild(m_pSceneNode);
+
          m_pSceneMgr->destroySceneNode(m_pSceneNode);
 
       m_pSceneNode = 0;
@@ -545,7 +557,7 @@ void BatchedGeometry::SubBatch::addSubEntity(SubEntity *ent, const Vector3 &posi
       case VET_COLOUR_ABGR:
          break;
       default:
-         OGRE_EXCEPT(0, "Unknown RenderSystem color format", "BatchedGeometry::SubBatch::addSubMesh()");
+         OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unknown RenderSystem color format", "BatchedGeometry::SubBatch::addSubMesh()");
          break;
       }
    }
@@ -634,52 +646,42 @@ void BatchedGeometry::SubBatch::build()
 
       if (srcIndexType == HardwareIndexBuffer::IT_32BIT)
       {
-         //Lock the input buffer
-         uint32 *source = static_cast<uint32*>(sourceIndexData->indexBuffer->lock(
-            sourceIndexData->indexStart, sourceIndexData->indexCount, HardwareBuffer::HBL_READ_ONLY));
-         uint32 *sourceEnd = source + sourceIndexData->indexCount;
-
-         //And copy it to the output buffer
-         while (source != sourceEnd)
-            *indexBuffer32++ = static_cast<uint32>(*source++ + indexOffset);
-
-         sourceIndexData->indexBuffer->unlock();                     // Unlock the input buffer
-         indexOffset += queuedMesh.subMesh->vertexData->vertexCount; // Increment the index offset
+         sourceIndexData->indexBuffer->readData(
+               sourceIndexData->indexStart * sizeof(uint32),
+               sourceIndexData->indexCount * sizeof(uint32), indexBuffer32);
+         uint32 *updateEnd = indexBuffer32 + sourceIndexData->indexCount;
+
+         // add indexOffset
+         while (indexBuffer32 != updateEnd)
+            *indexBuffer32++ += indexOffset;
       }
       else
       {
          if (destIndexType == HardwareIndexBuffer::IT_32BIT)
          {
             //-- Convert 16 bit to 32 bit indices --
+            std::vector<uint16> tmp(sourceIndexData->indexCount);
             //Lock the input buffer
-            uint16 *source = static_cast<uint16*>(sourceIndexData->indexBuffer->lock(
-               sourceIndexData->indexStart, sourceIndexData->indexCount, HardwareBuffer::HBL_READ_ONLY));
+            sourceIndexData->indexBuffer->readData(sourceIndexData->indexStart*sizeof(uint16), tmp.size(), tmp.data());
+            uint16 *source = tmp.data();
             uint16 *sourceEnd = source + sourceIndexData->indexCount;
 
             //And copy it to the output buffer
             while (source != sourceEnd)
-            {
-               uint32 indx = *source++;
-               *indexBuffer32++ = (indx + indexOffset);
-            }
-
-            sourceIndexData->indexBuffer->unlock();                  // Unlock the input buffer
-            indexOffset += queuedMesh.subMesh->vertexData->vertexCount; // Increment the index offset
+               *indexBuffer32++ = (*source++ + indexOffset);
          }
          else
          {
-            //Lock the input buffer
-            uint16 *source = static_cast<uint16*>(sourceIndexData->indexBuffer->lock(
-               sourceIndexData->indexStart, sourceIndexData->indexCount, HardwareBuffer::HBL_READ_ONLY));
-            uint16 *sourceEnd = source + sourceIndexData->indexCount;
-
-            //And copy it to the output buffer
-            while (source != sourceEnd)
-               *indexBuffer16++ = static_cast<uint16>(*source++ + indexOffset);
-
-            sourceIndexData->indexBuffer->unlock();                  // Unlock the input buffer
-            indexOffset += queuedMesh.subMesh->vertexData->vertexCount; // Increment the index offset
+            sourceIndexData->indexBuffer->readData(
+                sourceIndexData->indexStart * sizeof(uint16),
+                sourceIndexData->indexCount * sizeof(uint16), indexBuffer16);
+            uint16 *updateEnd = indexBuffer16 + sourceIndexData->indexCount;
+
+            // add indexOffset
+            while (indexBuffer16 != updateEnd)
+               *indexBuffer16++ += indexOffset;
          }
+         indexOffset += queuedMesh.subMesh->vertexData->vertexCount; // Increment the index offset
       }
 
    }  // For each queued mesh
@@ -709,6 +711,8 @@ void BatchedGeometry::SubBatch::_buildIdentiryOrientation(const QueuedMesh &queu
    VertexBufferBinding *sourceBinds = sourceVertexData->vertexBufferBinding;
    VertexBufferBinding *destBinds = dstVertexData->vertexBufferBinding;
 
+   std::vector<uchar> shadowBuf;
+
    // For each vertex buffer
    for (unsigned short ibuffer = 0, bufCnt = destBinds->getBufferCount(); ibuffer < bufCnt; ++ibuffer)
    {
@@ -716,7 +720,11 @@ void BatchedGeometry::SubBatch::_buildIdentiryOrientation(const QueuedMesh &queu
       {
          //Lock the input buffer
          const HardwareVertexBufferSharedPtr &sourceBuffer = sourceBinds->getBuffer(ibuffer);
-         uchar *sourceBase = static_cast<uchar*>(sourceBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
+
+         shadowBuf.resize(sourceBuffer->getSizeInBytes());
+         sourceBuffer->readData(0, sourceBuffer->getSizeInBytes(), shadowBuf.data());
+         uchar *sourceBase = shadowBuf.data();
+
          uchar *destBase = vertexBuffers[ibuffer]; //Get the locked output buffer
 
          const VertexDeclaration::VertexElementList &elems = vertexBufferElements[ibuffer];
@@ -786,7 +794,6 @@ void BatchedGeometry::SubBatch::_buildIdentiryOrientation(const QueuedMesh &queu
          }
 
          vertexBuffers[ibuffer] = destBase;
-         sourceBuffer->unlock(); // unlock the input buffer
       }
       else
       {
@@ -833,6 +840,8 @@ void BatchedGeometry::SubBatch::_buildFullTransform(const QueuedMesh &queuedMesh
    VertexBufferBinding *sourceBinds = sourceVertexData->vertexBufferBinding;
    VertexBufferBinding *destBinds = dstVertexData->vertexBufferBinding;
 
+   std::vector<uchar> shadowBuf;
+
    // For each vertex buffer
    for (unsigned short ibuffer = 0, bufCnt = destBinds->getBufferCount(); ibuffer < bufCnt; ++ibuffer)
    {
@@ -840,7 +849,9 @@ void BatchedGeometry::SubBatch::_buildFullTransform(const QueuedMesh &queuedMesh
       {
          //Lock the input buffer
          const HardwareVertexBufferSharedPtr &sourceBuffer = sourceBinds->getBuffer(ibuffer);
-         uchar *sourceBase = static_cast<uchar*>(sourceBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
+         shadowBuf.resize(sourceBuffer->getSizeInBytes());
+         sourceBuffer->readData(0, sourceBuffer->getSizeInBytes(), shadowBuf.data());
+         uchar *sourceBase = shadowBuf.data();
 
          //Get the locked output buffer
          uchar *destBase = vertexBuffers[ibuffer];
diff --git a/source/paged-geom/PagedGeometry.cpp b/source/paged-geom/PagedGeometry.cpp
index ba94f77b..24734882 100644
--- a/source/paged-geom/PagedGeometry.cpp
+++ b/source/paged-geom/PagedGeometry.cpp
@@ -164,7 +164,7 @@ Vector3 PagedGeometry::_convertToLocal(const Vector3 &globalVec) const
 void PagedGeometry::setPageSize(Real size)
 {
 	if (!managerList.empty())
-		OGRE_EXCEPT(0, "PagedGeometry::setPageSize() cannot be called after detail levels have been added. Call removeDetailLevels() first.", "PagedGeometry::setPageSize()");
+		OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "PagedGeometry::setPageSize() cannot be called after detail levels have been added. Call removeDetailLevels() first.", "PagedGeometry::setPageSize()");
 
 	pageSize = size;
 }
@@ -172,7 +172,7 @@ void PagedGeometry::setPageSize(Real size)
 void PagedGeometry::setInfinite()
 {
 	if (!managerList.empty())
-		OGRE_EXCEPT(0, "PagedGeometry::setInfinite() cannot be called after detail levels have been added. Call removeDetailLevels() first.", "PagedGeometry::setInfinite()");
+		OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "PagedGeometry::setInfinite() cannot be called after detail levels have been added. Call removeDetailLevels() first.", "PagedGeometry::setInfinite()");
 
 	m_bounds = TBounds(0, 0, 0, 0);
 }
@@ -180,7 +180,7 @@ void PagedGeometry::setInfinite()
 void PagedGeometry::setBounds(TBounds bounds)
 {
 	if (!managerList.empty())
-		OGRE_EXCEPT(0, "PagedGeometry::setBounds() cannot be called after detail levels have been added. Call removeDetailLevels() first.", "PagedGeometry::setBounds()");
+		OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "PagedGeometry::setBounds() cannot be called after detail levels have been added. Call removeDetailLevels() first.", "PagedGeometry::setBounds()");
 	if (!Math::RealEqual(bounds.width(), bounds.height(), 0.01f))
 		OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Bounds must be square", "PagedGeometry::setBounds()");
 	if (bounds.width() <= 0 || bounds.height() <=0)
@@ -364,7 +364,7 @@ void PagedGeometry::_addDetailLevel(GeometryPageManager *mgr, Real maxRange, Rea
 
 	//Error check
 	if (maxRange <= minRange){
-		OGRE_EXCEPT(1, "Closer detail levels must be added before farther ones", "PagedGeometry::addDetailLevel()");
+		OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Closer detail levels must be added before farther ones", "PagedGeometry::addDetailLevel()");
 	}
 
 	//Setup the new manager
diff --git a/source/paged-geom/PropertyMaps.cpp b/source/paged-geom/PropertyMaps.cpp
index c253e304..c123fdb0 100644
--- a/source/paged-geom/PropertyMaps.cpp
+++ b/source/paged-geom/PropertyMaps.cpp
@@ -112,7 +112,7 @@ DensityMap::DensityMap(TexturePtr map, MapChannel channel)
 			case CHANNEL_GREEN: channelOffset = 2; break;
 			case CHANNEL_BLUE: channelOffset = 1; break;
 			case CHANNEL_ALPHA: channelOffset = 0; break;
-			default: OGRE_EXCEPT(0, "Invalid channel", "GrassLayer::setDensityMap()"); break;
+			default: OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid channel", "GrassLayer::setDensityMap()"); break;
 		}
 
 		//And copy that channel into the density map
@@ -164,7 +164,7 @@ DensityMap::DensityMap(String map, MapChannel channel)
 				case CHANNEL_BLUE: colval = col.b; break;
 				case CHANNEL_ALPHA: colval = col.a; break;
 				case CHANNEL_COLOR: colval = col.r; break;
-				default: OGRE_EXCEPT(0, "Invalid channel", "GrassLayer::setDensityMap()"); break;
+				default: OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid channel", "GrassLayer::setDensityMap()"); break;
 			}
 			outputPtr[j*width+i] = colval * 255.0f;
 
@@ -321,7 +321,7 @@ ColorMap::ColorMap(TexturePtr map, MapChannel channel)
 				channel = CHANNEL_RED;
 			break;
 		default:
-			OGRE_EXCEPT(0, "Unknown RenderSystem color format", "GrassLayer::setColorMap()");
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unknown RenderSystem color format", "GrassLayer::setColorMap()");
 			break;
 	}
 
@@ -344,7 +344,7 @@ ColorMap::ColorMap(TexturePtr map, MapChannel channel)
 			case CHANNEL_GREEN: channelOffset = 2; break;
 			case CHANNEL_BLUE: channelOffset = 1; break;
 			case CHANNEL_ALPHA: channelOffset = 0; break;
-			default: OGRE_EXCEPT(0, "Invalid channel", "ColorMap::ColorMap()"); break;
+			default: OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid channel", "ColorMap::ColorMap()"); break;
 		}
 
 		//And copy that channel into the density map
diff --git a/source/paged-geom/StaticBillboardSet.cpp b/source/paged-geom/StaticBillboardSet.cpp
index 3371feae..57d51d16 100644
--- a/source/paged-geom/StaticBillboardSet.cpp
+++ b/source/paged-geom/StaticBillboardSet.cpp
@@ -121,10 +121,11 @@ StaticBillboardSet::~StaticBillboardSet()
       //Remove billboard set
       mpSceneMgr->destroyBillboardSet(mpFallbackBillboardSet);
 
+    mpSceneNode->removeAllChildren();
    //Delete scene node
    if (mpSceneNode->getParent())
-      mpSceneNode->getParentSceneNode()->removeAndDestroyChild(mpSceneNode->getName());
-   else
+      mpSceneNode->getParentSceneNode()->removeChild(mpSceneNode);
+
       mpSceneNode->getCreator()->destroySceneNode(mpSceneNode);
 }
 
diff --git a/source/paged-geom/TreeLoader2D.cpp b/source/paged-geom/TreeLoader2D.cpp
index ac906a5d..56d16ece 100644
--- a/source/paged-geom/TreeLoader2D.cpp
+++ b/source/paged-geom/TreeLoader2D.cpp
@@ -542,7 +542,7 @@ void TreeIterator2D::moveNext()
 {
 	//Out of bounds check
 	if (!hasMore)
-		OGRE_EXCEPT(1, "Cannot read past end of TreeIterator list", "TreeIterator::moveNext()");
+		OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot read past end of TreeIterator list", "TreeIterator::moveNext()");
 
 	//Preserve the last tree
 	prevTreeDat = currentTreeDat;
diff --git a/source/paged-geom/TreeLoader3D.cpp b/source/paged-geom/TreeLoader3D.cpp
index 48ed02ea..4dd838d4 100644
--- a/source/paged-geom/TreeLoader3D.cpp
+++ b/source/paged-geom/TreeLoader3D.cpp
@@ -529,7 +529,7 @@ void TreeIterator3D::moveNext()
 {
 	//Out of bounds check
 	if (!hasMore)
-		OGRE_EXCEPT(1, "Cannot read past end of TreeIterator list", "TreeIterator::moveNext()");
+		OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot read past end of TreeIterator list", "TreeIterator::moveNext()");
 
 	//Preserve the last tree
 	prevTreeDat = currentTreeDat;
diff --git a/source/paged-geom/WindBatchedGeometry.cpp b/source/paged-geom/WindBatchedGeometry.cpp
index a385d972..e340473b 100644
--- a/source/paged-geom/WindBatchedGeometry.cpp
+++ b/source/paged-geom/WindBatchedGeometry.cpp
@@ -198,7 +198,7 @@ void WindBatchedGeometry::WindSubBatch::build()
    }
 
 
-
+	std::vector<uchar> shadowBuf;
 	//For each queued mesh...
 	size_t indexOffset = 0;
    for (size_t iMesh = 0, meshCnt = m_queueMesh.size(); iMesh < meshCnt; ++iMesh)
@@ -232,7 +232,9 @@ void WindBatchedGeometry::WindSubBatch::build()
          {
 				//Lock the input buffer
 				const HardwareVertexBufferSharedPtr &sourceBuffer = sourceBinds->getBuffer(i);
-				uchar *sourceBase = static_cast<uchar*>(sourceBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
+				shadowBuf.resize(sourceBuffer->getSizeInBytes());
+         		sourceBuffer->readData(0, sourceBuffer->getSizeInBytes(), shadowBuf.data());
+         		uchar *sourceBase = shadowBuf.data();
 
             size_t sourceVertexSize = sourceBuffer->getVertexSize();
             size_t destVertexSize   = vertDecl->getVertexSize(i);
@@ -336,7 +338,6 @@ void WindBatchedGeometry::WindSubBatch::build()
 
 				//Unlock the input buffer
 				vertexBuffers[i] = destBase;
-				sourceBuffer->unlock();
          }
          else
          {
@@ -366,66 +367,44 @@ void WindBatchedGeometry::WindSubBatch::build()
 		//Copy mesh index data into the index buffer
 		if (srcIndexType == HardwareIndexBuffer::IT_32BIT)
       {
-			//Lock the input buffer
-			uint32 *source = static_cast<uint32*>(sourceIndexData->indexBuffer->lock(
-				sourceIndexData->indexStart, sourceIndexData->indexCount, HardwareBuffer::HBL_READ_ONLY));
-			uint32 *sourceEnd = source + sourceIndexData->indexCount;
-
-			//And copy it to the output buffer
-			while (source != sourceEnd) {
-				*indexBuffer32++ = static_cast<uint32>(*source++ + indexOffset);
-			}
-			
-			//Unlock the input buffer
-			sourceIndexData->indexBuffer->unlock();
-
-			//Increment the index offset
-			indexOffset += sourceVertexData->vertexCount;
+			sourceIndexData->indexBuffer->readData(
+				sourceIndexData->indexStart * sizeof(uint32),
+				sourceIndexData->indexCount * sizeof(uint32), indexBuffer32);
+			uint32 *updateEnd = indexBuffer32 + sourceIndexData->indexCount;
+
+			// add indexOffset
+			while (indexBuffer32 != updateEnd)
+				*indexBuffer32++ += indexOffset;
 		}
       else
       {
 			if (destIndexType == HardwareIndexBuffer::IT_32BIT)
          {
 				//-- Convert 16 bit to 32 bit indices --
+				std::vector<uint16> tmp(sourceIndexData->indexCount);
 				//Lock the input buffer
-				uint16 *source = static_cast<uint16*>(sourceIndexData->indexBuffer->lock(
-					sourceIndexData->indexStart, sourceIndexData->indexCount, HardwareBuffer::HBL_READ_ONLY
-					));
+				sourceIndexData->indexBuffer->readData(sourceIndexData->indexStart*sizeof(uint16), tmp.size(), tmp.data());
+				uint16 *source = tmp.data();
 				uint16 *sourceEnd = source + sourceIndexData->indexCount;
 
 				//And copy it to the output buffer
-				while (source != sourceEnd) {
-					uint32 indx = *source++;
-					*indexBuffer32++ = (indx + indexOffset);
+				while (source != sourceEnd)
+					*indexBuffer32++ = (*source++ + indexOffset);
 				}
-
-				//Unlock the input buffer
-				sourceIndexData->indexBuffer->unlock();
-
-				//Increment the index offset
-				indexOffset += sourceVertexData->vertexCount;
-			}
          else
          {
-				//Lock the input buffer
-				uint16 *source = static_cast<uint16*>(sourceIndexData->indexBuffer->lock(
-					sourceIndexData->indexStart, sourceIndexData->indexCount, HardwareBuffer::HBL_READ_ONLY
-					));
-				uint16 *sourceEnd = source + sourceIndexData->indexCount;
-
-				//And copy it to the output buffer
-				while (source != sourceEnd)
-            {
-					*indexBuffer16++ = static_cast<uint16>(*source++ + indexOffset);
-				}
-
-				//Unlock the input buffer
-				sourceIndexData->indexBuffer->unlock();
-
-				//Increment the index offset
-				indexOffset += sourceVertexData->vertexCount;
+			sourceIndexData->indexBuffer->readData(
+                sourceIndexData->indexStart * sizeof(uint16),
+                sourceIndexData->indexCount * sizeof(uint16), indexBuffer16);
+            uint16 *updateEnd = indexBuffer16 + sourceIndexData->indexCount;
+
+            // add indexOffset
+            while (indexBuffer16 != updateEnd)
+               *indexBuffer16++ += indexOffset;
 			}
 		}
+		//Increment the index offset
+		indexOffset += sourceVertexData->vertexCount;
 	}
 
 	//Unlock buffers
diff --git a/source/sdl4ogre/sdlcursormanager.cpp b/source/sdl4ogre/sdlcursormanager.cpp
index a7437208..34ac6efb 100644
--- a/source/sdl4ogre/sdlcursormanager.cpp
+++ b/source/sdl4ogre/sdlcursormanager.cpp
@@ -90,7 +90,7 @@ namespace SFO
         std::vector<Ogre::uint32> data;
         data.resize(size_x*size_y);
         Ogre::PixelBox destImage(size_x, size_y, 1, tex->getFormat(), &data[0]);
-        Ogre::Image::Box srcBox(left, top, left+size_x, top+size_y);
+        Ogre::Box srcBox(left, top, left+size_x, top+size_y);
         tex->getBuffer()->blitToMemory(srcBox, destImage);
 
         SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF);
diff --git a/source/sdl4ogre/sdlinputwrapper.cpp b/source/sdl4ogre/sdlinputwrapper.cpp
index c1195f9d..77bb197c 100644
--- a/source/sdl4ogre/sdlinputwrapper.cpp
+++ b/source/sdl4ogre/sdlinputwrapper.cpp
@@ -5,6 +5,7 @@
 #include <OgrePlatform.h>
 #include <OgreRoot.h>
 
+#include <iostream>
 
 namespace SFO
 {
@@ -108,11 +109,11 @@ namespace SFO
                         mJoyListener->buttonReleased(evt.jbutton, evt.jbutton.button);
                     break;
                 case SDL_JOYDEVICEADDED:
-                    //SDL_JoystickOpen(evt.jdevice.which);
-                    //std::cout << "Detected a new joystick: " << SDL_JoystickNameForIndex(evt.jdevice.which) << std::endl;
+                    SDL_JoystickOpen(evt.jdevice.which);
+                    std::cout << "Detected a new joystick: " << SDL_JoystickNameForIndex(evt.jdevice.which) << std::endl;
                     break;
                 case SDL_JOYDEVICEREMOVED:
-                    //std::cout << "A joystick has been removed" << std::endl;
+                    std::cout << "A joystick has been removed" << std::endl;
                     break;
                 case SDL_WINDOWEVENT:
                     handleWindowEvent(evt);
diff --git a/source/sdl4ogre/sdlwindowhelper.cpp b/source/sdl4ogre/sdlwindowhelper.cpp
index 0fa34605..ee19a90b 100644
--- a/source/sdl4ogre/sdlwindowhelper.cpp
+++ b/source/sdl4ogre/sdlwindowhelper.cpp
@@ -24,6 +24,7 @@ SDLWindowHelper::SDLWindowHelper (SDL_Window* window, int w, int h,
 	if (!SDL_GetWindowWMInfo(mSDLWindow, &wmInfo))
 		throw std::runtime_error("Couldn't get WM Info!");
 
+    Ogre::String param = "externalWindowHandle";
 	Ogre::String winHandle;
 
 	switch (wmInfo.subsystem)
@@ -43,6 +44,7 @@ SDLWindowHelper::SDLWindowHelper (SDL_Window* window, int w, int h,
 		break;
 #else
 	case SDL_SYSWM_X11:
+        param = "parentWindowHandle";
 		winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.x11.window);
 		break;
 #endif
@@ -51,9 +53,7 @@ SDLWindowHelper::SDLWindowHelper (SDL_Window* window, int w, int h,
 		break;
 	}
 
-	/// \todo externalWindowHandle is deprecated according to the source code. Figure out a way to get parentWindowHandle
-	/// to work properly. On Linux/X11 it causes an occasional GLXBadDrawable error.
-	params.insert(std::make_pair("externalWindowHandle",  winHandle));
+	params.insert(std::make_pair(param,  winHandle));
 
 	mWindow = Ogre::Root::getSingleton().createRenderWindow(title, w, h, fullscreen, &params);
 }
diff --git a/source/shiny/Platforms/Ogre/OgreGpuProgram.cpp b/source/shiny/Platforms/Ogre/OgreGpuProgram.cpp
index cce395d2..f27fbfe3 100644
--- a/source/shiny/Platforms/Ogre/OgreGpuProgram.cpp
+++ b/source/shiny/Platforms/Ogre/OgreGpuProgram.cpp
@@ -1,5 +1,6 @@
 #include "pch.h"
 #include <stdexcept>
+#include <iostream>
 
 #include "OgreGpuProgram.hpp"
 
diff --git a/source/shiny/Platforms/Ogre/OgreMaterial.cpp b/source/shiny/Platforms/Ogre/OgreMaterial.cpp
index a375e4b1..b1fdb29e 100644
--- a/source/shiny/Platforms/Ogre/OgreMaterial.cpp
+++ b/source/shiny/Platforms/Ogre/OgreMaterial.cpp
@@ -70,6 +70,10 @@ namespace sh
 
 	bool OgreMaterial::createConfiguration (const std::string& name, unsigned short lodIndex)
 	{
+		// drop dummy technique
+		if(mMaterial->getTechnique(0)->getNumPasses() == 0)
+			mMaterial->removeTechnique(0);
+
 		for (int i=0; i<mMaterial->getNumTechniques(); ++i)
 		{
 			if (mMaterial->getTechnique(i)->getSchemeName() == name && mMaterial->getTechnique(i)->getLodIndex() == lodIndex)
diff --git a/source/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/source/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp
index 7a5aa705..359a556e 100644
--- a/source/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp
+++ b/source/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp
@@ -4,36 +4,1902 @@
 #include <OgrePass.h>
 
 #include <OgreStringConverter.h>
+#include <OgreLodStrategyManager.h>
+#include <OgreDistanceLodStrategy.h>
+#include <OgreLogManager.h>
+
+namespace Ogre
+{
+    /** Struct for holding the script context while parsing. */
+    struct MaterialScriptContext 
+    {
+        MaterialPtr material;
+        Pass* pass;
+        TextureUnitState* textureUnit;
+        AliasTextureNamePairList textureAliases;
+    };
+}
+
+//-----------------------------------------------------------------------
+// Internal parser methods
+//-----------------------------------------------------------------------
+namespace 
+{
+    using namespace Ogre;
+
+    void logParseError(const String& error, const MaterialScriptContext& context)
+    {
+        // log material name only if filename not specified
+        if (context.material.get())
+        {
+            LogManager::getSingleton().logMessage(
+                "Error in material " + context.material->getName() +
+                " : " + error, LML_CRITICAL);
+        }
+        else
+        {
+            LogManager::getSingleton().logMessage("Error: "+error, LML_CRITICAL);
+        }
+    }
+    void trimAndUnquoteWord(String& val)
+    {
+        StringUtil::trim(val);
+        if(val.size() >= 2 && val[0] == '\"' && val[val.size() - 1] == '\"')
+            val = val.substr(1, val.size() - 2);
+    }
+    ColourValue _parseColourValue(StringVector& vecparams)
+    {
+        return ColourValue(
+            StringConverter::parseReal(vecparams[0]) ,
+            StringConverter::parseReal(vecparams[1]) ,
+            StringConverter::parseReal(vecparams[2]) ,
+            (vecparams.size()==4) ? StringConverter::parseReal(vecparams[3]) : 1.0f ) ;
+    }
+    //-----------------------------------------------------------------------
+    FilterOptions convertFiltering(const String& s)
+    {
+        if (s == "none")
+        {
+            return FO_NONE;
+        }
+        else if (s == "point")
+        {
+            return FO_POINT;
+        }
+        else if (s == "linear")
+        {
+            return FO_LINEAR;
+        }
+        else if (s == "anisotropic")
+        {
+            return FO_ANISOTROPIC;
+        }
+
+        return FO_POINT;
+    }
+    bool parseLodValues(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+
+        // iterate over the parameters and parse values out of them
+        Material::LodValueList lodList;
+        StringVector::iterator i, iend;
+        iend = vecparams.end();
+        for (i = vecparams.begin(); i != iend; ++i)
+        {
+            lodList.push_back(StringConverter::parseReal(*i));
+        }
+
+        context.material->setLodLevels(lodList);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseLodStrategy(String& params, MaterialScriptContext& context)
+    {
+        LodStrategy *strategy = LodStrategyManager::getSingleton().getStrategy(params);
+        
+        if (strategy == 0)
+            logParseError(
+            "Bad lod_strategy attribute, available LOD strategy name expected.",
+            context);
+
+        context.material->setLodStrategy(strategy);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseLodDistances(String& params, MaterialScriptContext& context)
+    {
+        // Set to distance strategy
+        context.material->setLodStrategy(DistanceLodSphereStrategy::getSingletonPtr());
+
+        StringVector vecparams = StringUtil::split(params, " \t");
+
+        // iterate over the parameters and parse values out of them
+        Material::LodValueList lodList;
+        StringVector::iterator i, iend;
+        iend = vecparams.end();
+        for (i = vecparams.begin(); i != iend; ++i)
+        {
+            lodList.push_back(StringConverter::parseReal(*i));
+        }
+
+        context.material->setLodLevels(lodList);
+
+        return false;
+    }
+    bool parseReceiveShadows(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.material->setReceiveShadows(true);
+        else if (params == "off")
+            context.material->setReceiveShadows(false);
+        else
+            logParseError(
+            "Bad receive_shadows attribute, valid parameters are 'on' or 'off'.",
+            context);
+
+        return false;
+
+    }
+    bool parseTransparencyCastsShadows(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.material->setTransparencyCastsShadows(true);
+        else if (params == "off")
+            context.material->setTransparencyCastsShadows(false);
+        else
+            logParseError(
+            "Bad transparency_casts_shadows attribute, valid parameters are 'on' or 'off'.",
+            context);
+
+        return false;
+    }
+    bool parseSetTextureAlias(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Wrong number of parameters for texture_alias, expected 2", context);
+            return false;
+        }
+        // first parameter is alias name and second parameter is texture name
+        context.textureAliases[vecparams[0]] = vecparams[1];
+
+        return false;
+    }
+    bool parseAmbient(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 1, 3 or 4 parameters
+        if (vecparams.size() == 1) {
+            if(vecparams[0] == "vertexcolour") {
+               context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_AMBIENT);
+            } else {
+                logParseError(
+                    "Bad ambient attribute, single parameter flag must be 'vertexcolour'",
+                    context);
+            }
+        }
+        else if (vecparams.size() == 3 || vecparams.size() == 4)
+        {
+            context.pass->setAmbient( _parseColourValue(vecparams) );
+            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_AMBIENT);
+        }
+        else
+        {
+            logParseError(
+                "Bad ambient attribute, wrong number of parameters (expected 1, 3 or 4)",
+                context);
+        }
+        return false;
+    }
+   //-----------------------------------------------------------------------
+    bool parseDiffuse(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 1, 3 or 4 parameters
+        if (vecparams.size() == 1) {
+            if(vecparams[0] == "vertexcolour") {
+               context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_DIFFUSE);
+            } else {
+                logParseError(
+                    "Bad diffuse attribute, single parameter flag must be 'vertexcolour'",
+                    context);
+            }
+        }
+        else if (vecparams.size() == 3 || vecparams.size() == 4)
+        {
+            context.pass->setDiffuse( _parseColourValue(vecparams) );
+            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_DIFFUSE);
+        }
+        else
+        {
+            logParseError(
+                "Bad diffuse attribute, wrong number of parameters (expected 1, 3 or 4)",
+                context);
+        }        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseSpecular(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 2, 4 or 5 parameters
+        if(vecparams.size() == 2)
+        {
+            if(vecparams[0] == "vertexcolour") {
+                context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_SPECULAR);
+                context.pass->setShininess(StringConverter::parseReal(vecparams[1]) );
+            }
+            else
+            {
+                logParseError(
+                    "Bad specular attribute, double parameter statement must be 'vertexcolour <shininess>'",
+                    context);
+            }
+        }
+        else if(vecparams.size() == 4 || vecparams.size() == 5)
+        {
+            context.pass->setSpecular(
+                StringConverter::parseReal(vecparams[0]),
+                StringConverter::parseReal(vecparams[1]),
+                StringConverter::parseReal(vecparams[2]),
+                vecparams.size() == 5?
+                    StringConverter::parseReal(vecparams[3]) : 1.0f);
+            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_SPECULAR);
+            context.pass->setShininess(
+                StringConverter::parseReal(vecparams[vecparams.size() - 1]) );
+        }
+        else
+        {
+            logParseError(
+                "Bad specular attribute, wrong number of parameters (expected 2, 4 or 5)",
+                context);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseEmissive(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 1, 3 or 4 parameters
+        if (vecparams.size() == 1) {
+            if(vecparams[0] == "vertexcolour") {
+               context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_EMISSIVE);
+            } else {
+                logParseError(
+                    "Bad emissive attribute, single parameter flag must be 'vertexcolour'",
+                    context);
+            }
+        }
+        else if (vecparams.size() == 3 || vecparams.size() == 4)
+        {
+            context.pass->setSelfIllumination( _parseColourValue(vecparams) );
+            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_EMISSIVE);
+        }
+        else
+        {
+            logParseError(
+                "Bad emissive attribute, wrong number of parameters (expected 1, 3 or 4)",
+                context);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    SceneBlendFactor convertBlendFactor(const String& param)
+    {
+        if (param == "one")
+            return SBF_ONE;
+        else if (param == "zero")
+            return SBF_ZERO;
+        else if (param == "dest_colour")
+            return SBF_DEST_COLOUR;
+        else if (param == "src_colour")
+            return SBF_SOURCE_COLOUR;
+        else if (param == "one_minus_dest_colour")
+            return SBF_ONE_MINUS_DEST_COLOUR;
+        else if (param == "one_minus_src_colour")
+            return SBF_ONE_MINUS_SOURCE_COLOUR;
+        else if (param == "dest_alpha")
+            return SBF_DEST_ALPHA;
+        else if (param == "src_alpha")
+            return SBF_SOURCE_ALPHA;
+        else if (param == "one_minus_dest_alpha")
+            return SBF_ONE_MINUS_DEST_ALPHA;
+        else if (param == "one_minus_src_alpha")
+            return SBF_ONE_MINUS_SOURCE_ALPHA;
+        else
+        {
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid blend factor.", "convertBlendFactor");
+        }
+
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseSceneBlend(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Should be 1 or 2 params
+        if (vecparams.size() == 1)
+        {
+            //simple
+            SceneBlendType stype;
+            if (vecparams[0] == "add")
+                stype = SBT_ADD;
+            else if (vecparams[0] == "modulate")
+                stype = SBT_MODULATE;
+            else if (vecparams[0] == "colour_blend")
+                stype = SBT_TRANSPARENT_COLOUR;
+            else if (vecparams[0] == "alpha_blend")
+                stype = SBT_TRANSPARENT_ALPHA;
+            else
+            {
+                logParseError(
+                    "Bad scene_blend attribute, unrecognised parameter '" + vecparams[0] + "'",
+                    context);
+                return false;
+            }
+            context.pass->setSceneBlending(stype);
+
+        }
+        else if (vecparams.size() == 2)
+        {
+            //src/dest
+            SceneBlendFactor src, dest;
+
+            try {
+                src = convertBlendFactor(vecparams[0]);
+                dest = convertBlendFactor(vecparams[1]);
+                context.pass->setSceneBlending(src,dest);
+            }
+            catch (Exception& e)
+            {
+                logParseError("Bad scene_blend attribute, " + e.getDescription(), context);
+            }
+
+        }
+        else
+        {
+            logParseError(
+                "Bad scene_blend attribute, wrong number of parameters (expected 1 or 2)",
+                context);
+        }
+
+        return false;
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseSeparateSceneBlend(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Should be 2 or 4 params
+        if (vecparams.size() == 2)
+        {
+            //simple
+            SceneBlendType stype;
+            if (vecparams[0] == "add")
+                stype = SBT_ADD;
+            else if (vecparams[0] == "modulate")
+                stype = SBT_MODULATE;
+            else if (vecparams[0] == "colour_blend")
+                stype = SBT_TRANSPARENT_COLOUR;
+            else if (vecparams[0] == "alpha_blend")
+                stype = SBT_TRANSPARENT_ALPHA;
+            else
+            {
+                logParseError(
+                    "Bad separate_scene_blend attribute, unrecognised parameter '" + vecparams[0] + "'",
+                    context);
+                return false;
+            }
+
+            SceneBlendType stypea;
+            if (vecparams[0] == "add")
+                stypea = SBT_ADD;
+            else if (vecparams[0] == "modulate")
+                stypea = SBT_MODULATE;
+            else if (vecparams[0] == "colour_blend")
+                stypea = SBT_TRANSPARENT_COLOUR;
+            else if (vecparams[0] == "alpha_blend")
+                stypea = SBT_TRANSPARENT_ALPHA;
+            else
+            {
+                logParseError(
+                    "Bad separate_scene_blend attribute, unrecognised parameter '" + vecparams[1] + "'",
+                    context);
+                return false;
+            }
+            
+            context.pass->setSeparateSceneBlending(stype, stypea);
+        }
+        else if (vecparams.size() == 4)
+        {
+            //src/dest
+            SceneBlendFactor src, dest;
+            SceneBlendFactor srca, desta;
+
+            try {
+                src = convertBlendFactor(vecparams[0]);
+                dest = convertBlendFactor(vecparams[1]);
+                srca = convertBlendFactor(vecparams[2]);
+                desta = convertBlendFactor(vecparams[3]);
+                context.pass->setSeparateSceneBlending(src,dest,srca,desta);
+            }
+            catch (Exception& e)
+            {
+                logParseError("Bad separate_scene_blend attribute, " + e.getDescription(), context);
+            }
+
+        }
+        else
+        {
+            logParseError(
+                "Bad separate_scene_blend attribute, wrong number of parameters (expected 2 or 4)",
+                context);
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    CompareFunction convertCompareFunction(const String& param)
+    {
+        if (param == "always_fail")
+            return CMPF_ALWAYS_FAIL;
+        else if (param == "always_pass")
+            return CMPF_ALWAYS_PASS;
+        else if (param == "less")
+            return CMPF_LESS;
+        else if (param == "less_equal")
+            return CMPF_LESS_EQUAL;
+        else if (param == "equal")
+            return CMPF_EQUAL;
+        else if (param == "not_equal")
+            return CMPF_NOT_EQUAL;
+        else if (param == "greater_equal")
+            return CMPF_GREATER_EQUAL;
+        else if (param == "greater")
+            return CMPF_GREATER;
+        else
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid compare function", "convertCompareFunction");
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseDepthCheck(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setDepthCheckEnabled(true);
+        else if (params == "off")
+            context.pass->setDepthCheckEnabled(false);
+        else
+            logParseError(
+            "Bad depth_check attribute, valid parameters are 'on' or 'off'.",
+            context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseDepthWrite(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setDepthWriteEnabled(true);
+        else if (params == "off")
+            context.pass->setDepthWriteEnabled(false);
+        else
+            logParseError(
+                "Bad depth_write attribute, valid parameters are 'on' or 'off'.",
+                context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseLightScissor(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setLightScissoringEnabled(true);
+        else if (params == "off")
+            context.pass->setLightScissoringEnabled(false);
+        else
+            logParseError(
+            "Bad light_scissor attribute, valid parameters are 'on' or 'off'.",
+            context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseLightClip(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setLightClipPlanesEnabled(true);
+        else if (params == "off")
+            context.pass->setLightClipPlanesEnabled(false);
+        else
+            logParseError(
+            "Bad light_clip_planes attribute, valid parameters are 'on' or 'off'.",
+            context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseDepthFunc(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        try {
+            CompareFunction func = convertCompareFunction(params);
+            context.pass->setDepthFunction(func);
+        }
+        catch (...)
+        {
+            logParseError("Bad depth_func attribute, invalid function parameter.", context);
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseNormaliseNormals(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setNormaliseNormals(true);
+        else if (params == "off")
+            context.pass->setNormaliseNormals(false);
+        else
+            logParseError(
+            "Bad normalise_normals attribute, valid parameters are 'on' or 'off'.",
+            context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseColourWrite(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setColourWriteEnabled(true);
+        else if (params == "off")
+            context.pass->setColourWriteEnabled(false);
+        else
+            logParseError(
+                "Bad colour_write attribute, valid parameters are 'on' or 'off'.",
+                context);
+        return false;
+    }
+
+    //-----------------------------------------------------------------------
+    bool parseCullHardware(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="none")
+            context.pass->setCullingMode(CULL_NONE);
+        else if (params=="anticlockwise")
+            context.pass->setCullingMode(CULL_ANTICLOCKWISE);
+        else if (params=="clockwise")
+            context.pass->setCullingMode(CULL_CLOCKWISE);
+        else
+            logParseError(
+                "Bad cull_hardware attribute, valid parameters are "
+                "'none', 'clockwise' or 'anticlockwise'.", context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseCullSoftware(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="none")
+            context.pass->setManualCullingMode(MANUAL_CULL_NONE);
+        else if (params=="back")
+            context.pass->setManualCullingMode(MANUAL_CULL_BACK);
+        else if (params=="front")
+            context.pass->setManualCullingMode(MANUAL_CULL_FRONT);
+        else
+            logParseError(
+                "Bad cull_software attribute, valid parameters are 'none', "
+                "'front' or 'back'.", context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseLighting(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="on")
+            context.pass->setLightingEnabled(true);
+        else if (params=="off")
+            context.pass->setLightingEnabled(false);
+        else
+            logParseError(
+                "Bad lighting attribute, valid parameters are 'on' or 'off'.", context);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseMaxLights(String& params, MaterialScriptContext& context)
+    {
+        context.pass->setMaxSimultaneousLights((ushort)StringConverter::parseInt(params));
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseStartLight(String& params, MaterialScriptContext& context)
+    {
+        context.pass->setStartLight((ushort)StringConverter::parseInt(params));
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    void parseIterationLightTypes(String& params, MaterialScriptContext& context)
+    {
+        // Parse light type
+        if (params == "directional")
+        {
+            context.pass->setIteratePerLight(true, true, Light::LT_DIRECTIONAL);
+        }
+        else if (params == "point")
+        {
+            context.pass->setIteratePerLight(true, true, Light::LT_POINT);
+        }
+        else if (params == "spot")
+        {
+            context.pass->setIteratePerLight(true, true, Light::LT_SPOTLIGHT);
+        }
+        else
+        {
+            logParseError("Bad iteration attribute, valid values for light type parameter "
+                "are 'point' or 'directional' or 'spot'.", context);
+        }
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseIteration(String& params, MaterialScriptContext& context)
+    {
+        // we could have more than one parameter
+        /** combinations could be:
+            iteration once
+            iteration once_per_light [light type]
+            iteration <number>
+            iteration <number> [per_light] [light type]
+            iteration <number> [per_n_lights] <num_lights> [light type]
+        */
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() < 1 || vecparams.size() > 4)
+        {
+            logParseError("Bad iteration attribute, expected 1 to 3 parameters.", context);
+            return false;
+        }
+
+        if (vecparams[0]=="once")
+            context.pass->setIteratePerLight(false, false);
+        else if (vecparams[0]=="once_per_light")
+        {
+            if (vecparams.size() == 2)
+            {
+                parseIterationLightTypes(vecparams[1], context);
+            }
+            else
+            {
+                context.pass->setIteratePerLight(true, false);
+            }
+
+        }
+        else // could be using form: <number> [per_light] [light type]
+        {
+            int passIterationCount = StringConverter::parseInt(vecparams[0]);
+            if (passIterationCount > 0)
+            {
+                context.pass->setPassIterationCount(passIterationCount);
+                if (vecparams.size() > 1)
+                {
+                    if (vecparams[1] == "per_light")
+                    {
+                        if (vecparams.size() == 3)
+                        {
+                            parseIterationLightTypes(vecparams[2], context);
+                        }
+                        else
+                        {
+                            context.pass->setIteratePerLight(true, false);
+                        }
+                    }
+                    else if (vecparams[1] == "per_n_lights")
+                    {
+                        if (vecparams.size() < 3)
+                        {
+                            logParseError(
+                                "Bad iteration attribute, expected number of lights.", 
+                                context);
+                        }
+                        else
+                        {
+                            // Parse num lights
+                            context.pass->setLightCountPerIteration(
+                                (ushort)StringConverter::parseInt(vecparams[2]));
+                            // Light type
+                            if (vecparams.size() == 4)
+                            {
+                                parseIterationLightTypes(vecparams[3], context);
+                            }
+                            else
+                            {
+                                context.pass->setIteratePerLight(true, false);
+                            }
+                        }
+                    }
+                    else
+                        logParseError(
+                            "Bad iteration attribute, valid parameters are <number> [per_light|per_n_lights <num_lights>] [light type].", context);
+                }
+            }
+            else
+                logParseError(
+                    "Bad iteration attribute, valid parameters are 'once' or 'once_per_light' or <number> [per_light|per_n_lights <num_lights>] [light type].", context);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePointSize(String& params, MaterialScriptContext& context)
+    {
+        context.pass->setPointSize(StringConverter::parseReal(params));
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePointSprites(String& params, MaterialScriptContext& context)
+    {
+        if (params=="on")
+            context.pass->setPointSpritesEnabled(true);
+        else if (params=="off")
+            context.pass->setPointSpritesEnabled(false);
+        else
+            logParseError(
+                "Bad point_sprites attribute, valid parameters are 'on' or 'off'.", context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePointAttenuation(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 1 && vecparams.size() != 4)
+        {
+            logParseError("Bad point_size_attenuation attribute, 1 or 4 parameters expected", context);
+            return false;
+        }
+        if (vecparams[0] == "off")
+        {
+            context.pass->setPointAttenuation(false);
+        }
+        else if (vecparams[0] == "on")
+        {
+            if (vecparams.size() == 4)
+            {
+                context.pass->setPointAttenuation(true,
+                    StringConverter::parseReal(vecparams[1]),
+                    StringConverter::parseReal(vecparams[2]),
+                    StringConverter::parseReal(vecparams[3]));
+            }
+            else
+            {
+                context.pass->setPointAttenuation(true);
+            }
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePointSizeMin(String& params, MaterialScriptContext& context)
+    {
+        context.pass->setPointMinSize(
+            StringConverter::parseReal(params));
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePointSizeMax(String& params, MaterialScriptContext& context)
+    {
+        context.pass->setPointMaxSize(
+            StringConverter::parseReal(params));
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseFogging(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams[0]=="true")
+        {
+            // if true, we need to see if they supplied all arguments, or just the 1... if just the one,
+            // Assume they want to disable the default fog from effecting this material.
+            if( vecparams.size() == 8 )
+            {
+                FogMode mFogtype;
+                if( vecparams[1] == "none" )
+                    mFogtype = FOG_NONE;
+                else if( vecparams[1] == "linear" )
+                    mFogtype = FOG_LINEAR;
+                else if( vecparams[1] == "exp" )
+                    mFogtype = FOG_EXP;
+                else if( vecparams[1] == "exp2" )
+                    mFogtype = FOG_EXP2;
+                else
+                {
+                    logParseError(
+                        "Bad fogging attribute, valid parameters are "
+                        "'none', 'linear', 'exp', or 'exp2'.", context);
+                    return false;
+                }
+
+                context.pass->setFog(
+                    true,
+                    mFogtype,
+                    ColourValue(
+                    StringConverter::parseReal(vecparams[2]),
+                    StringConverter::parseReal(vecparams[3]),
+                    StringConverter::parseReal(vecparams[4])),
+                    StringConverter::parseReal(vecparams[5]),
+                    StringConverter::parseReal(vecparams[6]),
+                    StringConverter::parseReal(vecparams[7])
+                    );
+            }
+            else
+            {
+                context.pass->setFog(true);
+            }
+        }
+        else if (vecparams[0]=="false")
+            context.pass->setFog(false);
+        else
+            logParseError(
+                "Bad fog_override attribute, valid parameters are 'true' or 'false'.",
+                context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseShading(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="flat")
+            context.pass->setShadingMode(SO_FLAT);
+        else if (params=="gouraud")
+            context.pass->setShadingMode(SO_GOURAUD);
+        else if (params=="phong")
+            context.pass->setShadingMode(SO_PHONG);
+        else
+            logParseError("Bad shading attribute, valid parameters are 'flat', "
+                "'gouraud' or 'phong'.", context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePolygonMode(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="solid")
+            context.pass->setPolygonMode(PM_SOLID);
+        else if (params=="wireframe")
+            context.pass->setPolygonMode(PM_WIREFRAME);
+        else if (params=="points")
+            context.pass->setPolygonMode(PM_POINTS);
+        else
+            logParseError("Bad polygon_mode attribute, valid parameters are 'solid', "
+            "'wireframe' or 'points'.", context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parsePolygonModeOverrideable(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+
+        context.pass->setPolygonModeOverrideable(
+            StringConverter::parseBool(params));
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseFiltering(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 1 or 3 parameters
+        if (vecparams.size() == 1)
+        {
+            // Simple format
+            if (vecparams[0]=="none")
+                context.textureUnit->setTextureFiltering(TFO_NONE);
+            else if (vecparams[0]=="bilinear")
+                context.textureUnit->setTextureFiltering(TFO_BILINEAR);
+            else if (vecparams[0]=="trilinear")
+                context.textureUnit->setTextureFiltering(TFO_TRILINEAR);
+            else if (vecparams[0]=="anisotropic")
+                context.textureUnit->setTextureFiltering(TFO_ANISOTROPIC);
+            else
+            {
+                logParseError("Bad filtering attribute, valid parameters for simple format are "
+                    "'none', 'bilinear', 'trilinear' or 'anisotropic'.", context);
+                return false;
+            }
+        }
+        else if (vecparams.size() == 3)
+        {
+            // Complex format
+            context.textureUnit->setTextureFiltering(
+                convertFiltering(vecparams[0]),
+                convertFiltering(vecparams[1]),
+                convertFiltering(vecparams[2]));
+
+
+        }
+        else
+        {
+            logParseError(
+                "Bad filtering attribute, wrong number of parameters (expected 1, 3 or 4)",
+                context);
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseCompareTest(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        try 
+        {
+            if(params == "on")
+            {
+                context.textureUnit->setTextureCompareEnabled(true);
+            }
+            else if(params == "off")
+            {
+                context.textureUnit->setTextureCompareEnabled(false);
+            }
+            else
+            {
+                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid compare setting", "parseCompareEnabled");
+            }
+        }
+        catch (...)
+        {
+            logParseError("Bad compare_test attribute, invalid function parameter.", context);
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseCompareFunction(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        try {
+            CompareFunction func = convertCompareFunction(params);
+            context.textureUnit->setTextureCompareFunction(func);
+        }
+        catch (...)
+        {
+            logParseError("Bad compare_func attribute, invalid function parameter.", context);
+        }
+
+        return false;
+    }
+    bool parseAlphaRejection(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError(
+                "Bad alpha_rejection attribute, wrong number of parameters (expected 2)",
+                context);
+            return false;
+        }
+
+        CompareFunction cmp;
+        try {
+            cmp = convertCompareFunction(vecparams[0]);
+        }
+        catch (...)
+        {
+            logParseError("Bad alpha_rejection attribute, invalid compare function.", context);
+            return false;
+        }
+
+        context.pass->setAlphaRejectSettings(cmp, (unsigned char)StringConverter::parseInt(vecparams[1]));
+
+        return false;
+    }
+    //---------------------------------------------------------------------
+    bool parseAlphaToCoverage(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setAlphaToCoverageEnabled(true);
+        else if (params == "off")
+            context.pass->setAlphaToCoverageEnabled(false);
+        else
+            logParseError(
+            "Bad alpha_to_coverage attribute, valid parameters are 'on' or 'off'.",
+            context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTransparentSorting(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params == "on")
+            context.pass->setTransparentSortingEnabled(true);
+        else if (params == "off")
+            context.pass->setTransparentSortingEnabled(false);
+        else if (params == "force")
+            context.pass->setTransparentSortingForced(true);
+        else
+            logParseError(
+            "Bad transparent_sorting attribute, valid parameters are 'on', 'off' or 'force'.",
+            context);
+
+        return false;
+    }
+    bool parseDepthBias(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+
+        float constantBias = static_cast<float>(StringConverter::parseReal(vecparams[0]));
+        float slopeScaleBias = 0.0f;
+        if (vecparams.size() > 1)
+        {
+            slopeScaleBias = static_cast<float>(StringConverter::parseReal(vecparams[1]));
+        }
+        context.pass->setDepthBias(constantBias, slopeScaleBias);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseIterationDepthBias(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+
+        float bias = static_cast<float>(StringConverter::parseReal(vecparams[0]));
+        context.pass->setIterationDepthBias(bias);
+
+        return false;
+    }
+    bool parseIlluminationStage(String& params, MaterialScriptContext& context)
+    {
+        if (params == "ambient")
+        {
+            context.pass->setIlluminationStage(IS_AMBIENT);
+        }
+        else if (params == "per_light")
+        {
+            context.pass->setIlluminationStage(IS_PER_LIGHT);
+        }
+        else if (params == "decal")
+        {
+            context.pass->setIlluminationStage(IS_DECAL);
+        }
+        else
+        {
+            logParseError("Invalid illumination_stage specified.", context);
+        }
+        return false;
+    }
+    // Texture layer attributes
+    bool parseTexture(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::tokenise(params, " \t");
+        const size_t numParams = vecparams.size();
+        if (numParams > 5)
+        {
+            logParseError("Invalid texture attribute - expected only up to 5 parameters.",
+                context);
+        }
+        TextureType tt = TEX_TYPE_2D;
+        int mipmaps = MIP_DEFAULT; // When passed to TextureManager::load, this means default to default number of mipmaps
+        bool isAlpha = false;
+        bool hwGamma = false;
+        PixelFormat desiredFormat = PF_UNKNOWN;
+        for (size_t p = 1; p < numParams; ++p)
+        {
+            StringUtil::toLowerCase(vecparams[p]);
+            if (vecparams[p] == "1d")
+            {
+                tt = TEX_TYPE_1D;
+            }
+            else if (vecparams[p] == "2d")
+            {
+                tt = TEX_TYPE_2D;
+            }
+            else if (vecparams[p] == "3d")
+            {
+                tt = TEX_TYPE_3D;
+            }
+            else if (vecparams[p] == "cubic")
+            {
+                tt = TEX_TYPE_CUBE_MAP;
+            }
+            else if (vecparams[p] == "unlimited")
+            {
+                mipmaps = MIP_UNLIMITED;
+            }
+            else if (StringConverter::isNumber(vecparams[p]))
+            {
+                mipmaps = StringConverter::parseInt(vecparams[p]);
+            }
+            else if (vecparams[p] == "alpha")
+            {
+                isAlpha = true;
+            }
+            else if (vecparams[p] == "gamma")
+            {
+                hwGamma = true;
+            }
+            else if ((desiredFormat = PixelUtil::getFormatFromName(vecparams[p], true)) != PF_UNKNOWN)
+            {
+                // nothing to do here
+            }
+            else
+            {
+                logParseError("Invalid texture option - "+vecparams[p]+".",
+                context);
+            }
+        }
+
+        context.textureUnit->setTextureName(vecparams[0], tt);
+        context.textureUnit->setNumMipmaps(mipmaps);
+        context.textureUnit->setIsAlpha(isAlpha);
+        context.textureUnit->setDesiredFormat(desiredFormat);
+        context.textureUnit->setHardwareGammaEnabled(hwGamma);
+        return false;
+    }
+    bool parseAnimTexture(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::tokenise(params, " \t");
+        size_t numParams = vecparams.size();
+        // Determine which form it is
+        // Must have at least 3 params though
+        if (numParams < 3)
+        {
+            logParseError("Bad anim_texture attribute, wrong number of parameters "
+                "(expected at least 3)", context);
+            return false;
+        }
+        if (numParams == 3 && StringConverter::parseInt(vecparams[1]) != 0 )
+        {
+            // First form using base name & number of frames
+            context.textureUnit->setAnimatedTextureName(
+                vecparams[0],
+                StringConverter::parseInt(vecparams[1]),
+                StringConverter::parseReal(vecparams[2]));
+        }
+        else
+        {
+            // Second form using individual names
+            context.textureUnit->setAnimatedTextureName(
+                (String*)&vecparams[0],
+                static_cast<unsigned int>(numParams-1),
+                StringConverter::parseReal(vecparams[numParams-1]));
+        }
+        return false;
+
+    }
+    //-----------------------------------------------------------------------
+    bool parseCubicTexture(String& params, MaterialScriptContext& context)
+    {
+
+        StringVector vecparams = StringUtil::tokenise(params, " \t");
+        size_t numParams = vecparams.size();
+
+        // Get final param
+        bool useUVW;
+        String& uvOpt = vecparams[numParams-1];
+        StringUtil::toLowerCase(uvOpt);
+        if (uvOpt == "combineduvw")
+            useUVW = true;
+        else if (uvOpt == "separateuv")
+            useUVW = false;
+        else
+        {
+            logParseError("Bad cubic_texture attribute, final parameter must be "
+                "'combinedUVW' or 'separateUV'.", context);
+            return false;
+        }
+        // Determine which form it is
+        if (numParams == 2)
+        {
+            // First form using base name
+            context.textureUnit->setCubicTextureName(vecparams[0], useUVW);
+        }
+        else if (numParams == 7)
+        {
+            // Second form using individual names
+            // Can use vecparams[0] as array start point
+            context.textureUnit->setCubicTextureName((String*)&vecparams[0], useUVW);
+        }
+        else
+        {
+            logParseError(
+                "Bad cubic_texture attribute, wrong number of parameters (expected 2 or 7)",
+                context);
+            return false;
+        }
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTexCoord(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setTextureCoordSet(
+            StringConverter::parseInt(params));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    TextureUnitState::TextureAddressingMode convTexAddressMode(const String& params, MaterialScriptContext& context)
+    {
+        if (params=="wrap")
+            return TextureUnitState::TAM_WRAP;
+        else if (params=="mirror")
+            return TextureUnitState::TAM_MIRROR;
+        else if (params=="clamp")
+            return TextureUnitState::TAM_CLAMP;
+        else if (params=="border")
+            return TextureUnitState::TAM_BORDER;
+        else
+            logParseError("Bad tex_address_mode attribute, valid parameters are "
+                "'wrap', 'mirror', 'clamp' or 'border'.", context);
+        // default
+        return TextureUnitState::TAM_WRAP;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTexAddressMode(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+
+        StringVector vecparams = StringUtil::split(params, " \t");
+        size_t numParams = vecparams.size();
+
+        if (numParams > 3 || numParams < 1)
+        {
+            logParseError("Invalid number of parameters to tex_address_mode"
+                    " - must be between 1 and 3", context);
+        }
+        if (numParams == 1)
+        {
+            // Single-parameter option
+            context.textureUnit->setTextureAddressingMode(
+                convTexAddressMode(vecparams[0], context));
+        }
+        else
+        {
+            // 2-3 parameter option
+            TextureUnitState::UVWAddressingMode uvw;
+            uvw.u = convTexAddressMode(vecparams[0], context);
+            uvw.v = convTexAddressMode(vecparams[1], context);
+            if (numParams == 3)
+            {
+                // w
+                uvw.w = convTexAddressMode(vecparams[2], context);
+            }
+            else
+            {
+                uvw.w = TextureUnitState::TAM_WRAP;
+            }
+            context.textureUnit->setTextureAddressingMode(uvw);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTexBorderColour(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        // Must be 3 or 4 parameters
+        if (vecparams.size() == 3 || vecparams.size() == 4)
+        {
+            context.textureUnit->setTextureBorderColour( _parseColourValue(vecparams) );
+        }
+        else
+        {
+            logParseError(
+                "Bad tex_border_colour attribute, wrong number of parameters (expected 3 or 4)",
+                context);
+        }
+        return false;
+    }
+    bool parseColourOp(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="replace")
+            context.textureUnit->setColourOperation(LBO_REPLACE);
+        else if (params=="add")
+            context.textureUnit->setColourOperation(LBO_ADD);
+        else if (params=="modulate")
+            context.textureUnit->setColourOperation(LBO_MODULATE);
+        else if (params=="alpha_blend")
+            context.textureUnit->setColourOperation(LBO_ALPHA_BLEND);
+        else
+            logParseError("Bad colour_op attribute, valid parameters are "
+                "'replace', 'add', 'modulate' or 'alpha_blend'.", context);
+
+        return false;
+    }
+    LayerBlendOperationEx convertBlendOpEx(const String& param)
+    {
+        if (param == "source1")
+            return LBX_SOURCE1;
+        else if (param == "source2")
+            return LBX_SOURCE2;
+        else if (param == "modulate")
+            return LBX_MODULATE;
+        else if (param == "modulate_x2")
+            return LBX_MODULATE_X2;
+        else if (param == "modulate_x4")
+            return LBX_MODULATE_X4;
+        else if (param == "add")
+            return LBX_ADD;
+        else if (param == "add_signed")
+            return LBX_ADD_SIGNED;
+        else if (param == "add_smooth")
+            return LBX_ADD_SMOOTH;
+        else if (param == "subtract")
+            return LBX_SUBTRACT;
+        else if (param == "blend_diffuse_colour")
+            return LBX_BLEND_DIFFUSE_COLOUR;
+        else if (param == "blend_diffuse_alpha")
+            return LBX_BLEND_DIFFUSE_ALPHA;
+        else if (param == "blend_texture_alpha")
+            return LBX_BLEND_TEXTURE_ALPHA;
+        else if (param == "blend_current_alpha")
+            return LBX_BLEND_CURRENT_ALPHA;
+        else if (param == "blend_manual")
+            return LBX_BLEND_MANUAL;
+        else if (param == "dotproduct")
+            return LBX_DOTPRODUCT;
+        else
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid blend function", "convertBlendOpEx");
+    }
+    //-----------------------------------------------------------------------
+    LayerBlendSource convertBlendSource(const String& param)
+    {
+        if (param == "src_current")
+            return LBS_CURRENT;
+        else if (param == "src_texture")
+            return LBS_TEXTURE;
+        else if (param == "src_diffuse")
+            return LBS_DIFFUSE;
+        else if (param == "src_specular")
+            return LBS_SPECULAR;
+        else if (param == "src_manual")
+            return LBS_MANUAL;
+        else
+            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid blend source", "convertBlendSource");
+    }
+    //-----------------------------------------------------------------------
+    bool parseColourOpEx(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        size_t numParams = vecparams.size();
+
+        if (numParams < 3 || numParams > 10)
+        {
+            logParseError(
+                "Bad colour_op_ex attribute, wrong number of parameters (expected 3 to 10)",
+                context);
+            return false;
+        }
+        LayerBlendOperationEx op;
+        LayerBlendSource src1, src2;
+        Real manual = 0.0;
+        ColourValue colSrc1 = ColourValue::White;
+        ColourValue colSrc2 = ColourValue::White;
+
+        try {
+            op = convertBlendOpEx(vecparams[0]);
+            src1 = convertBlendSource(vecparams[1]);
+            src2 = convertBlendSource(vecparams[2]);
+
+            if (op == LBX_BLEND_MANUAL)
+            {
+                if (numParams < 4)
+                {
+                    logParseError("Bad colour_op_ex attribute, wrong number of parameters "
+                        "(expected 4 for manual blend)", context);
+                    return false;
+                }
+                manual = StringConverter::parseReal(vecparams[3]);
+            }
+
+            if (src1 == LBS_MANUAL)
+            {
+                unsigned int parIndex = 3;
+                if (op == LBX_BLEND_MANUAL)
+                    parIndex++;
+
+                if (numParams < parIndex + 3)
+                {
+                    logParseError("Bad colour_op_ex attribute, wrong number of parameters "
+                        "(expected " + StringConverter::toString(parIndex + 3) + ")", context);
+                    return false;
+                }
+
+                colSrc1.r = StringConverter::parseReal(vecparams[parIndex++]);
+                colSrc1.g = StringConverter::parseReal(vecparams[parIndex++]);
+                colSrc1.b = StringConverter::parseReal(vecparams[parIndex++]);
+                if (numParams > parIndex)
+                {
+                    colSrc1.a = StringConverter::parseReal(vecparams[parIndex]);
+                }
+                else
+                {
+                    colSrc1.a = 1.0f;
+                }
+            }
+
+            if (src2 == LBS_MANUAL)
+            {
+                unsigned int parIndex = 3;
+                if (op == LBX_BLEND_MANUAL)
+                    parIndex++;
+                if (src1 == LBS_MANUAL)
+                    parIndex += 3;
+
+                if (numParams < parIndex + 3)
+                {
+                    logParseError("Bad colour_op_ex attribute, wrong number of parameters "
+                        "(expected " + StringConverter::toString(parIndex + 3) + ")", context);
+                    return false;
+                }
+
+                colSrc2.r = StringConverter::parseReal(vecparams[parIndex++]);
+                colSrc2.g = StringConverter::parseReal(vecparams[parIndex++]);
+                colSrc2.b = StringConverter::parseReal(vecparams[parIndex++]);
+                if (numParams > parIndex)
+                {
+                    colSrc2.a = StringConverter::parseReal(vecparams[parIndex]);
+                }
+                else
+                {
+                    colSrc2.a = 1.0f;
+                }
+            }
+        }
+        catch (Exception& e)
+        {
+            logParseError("Bad colour_op_ex attribute, " + e.getDescription(), context);
+            return false;
+        }
+
+        context.textureUnit->setColourOperationEx(op, src1, src2, colSrc1, colSrc2, manual);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseColourOpFallback(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Bad colour_op_multipass_fallback attribute, wrong number "
+                "of parameters (expected 2)", context);
+            return false;
+        }
+
+        //src/dest
+        SceneBlendFactor src, dest;
+
+        try {
+            src = convertBlendFactor(vecparams[0]);
+            dest = convertBlendFactor(vecparams[1]);
+            context.textureUnit->setColourOpMultipassFallback(src,dest);
+        }
+        catch (Exception& e)
+        {
+            logParseError("Bad colour_op_multipass_fallback attribute, "
+                + e.getDescription(), context);
+        }
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseAlphaOpEx(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+        size_t numParams = vecparams.size();
+        if (numParams < 3 || numParams > 6)
+        {
+            logParseError("Bad alpha_op_ex attribute, wrong number of parameters "
+                "(expected 3 to 6)", context);
+            return false;
+        }
+        LayerBlendOperationEx op;
+        LayerBlendSource src1, src2;
+        Real manual = 0.0;
+        Real arg1 = 1.0, arg2 = 1.0;
+
+        try {
+            op = convertBlendOpEx(vecparams[0]);
+            src1 = convertBlendSource(vecparams[1]);
+            src2 = convertBlendSource(vecparams[2]);
+            if (op == LBX_BLEND_MANUAL)
+            {
+                if (numParams != 4)
+                {
+                    logParseError("Bad alpha_op_ex attribute, wrong number of parameters "
+                        "(expected 4 for manual blend)", context);
+                    return false;
+                }
+                manual = StringConverter::parseReal(vecparams[3]);
+            }
+            if (src1 == LBS_MANUAL)
+            {
+                unsigned int parIndex = 3;
+                if (op == LBX_BLEND_MANUAL)
+                    parIndex++;
+
+                if (numParams < parIndex)
+                {
+                    logParseError(
+                        "Bad alpha_op_ex attribute, wrong number of parameters (expected " +
+                        StringConverter::toString(parIndex - 1) + ")", context);
+                    return false;
+                }
+
+                arg1 = StringConverter::parseReal(vecparams[parIndex]);
+            }
+
+            if (src2 == LBS_MANUAL)
+            {
+                unsigned int parIndex = 3;
+                if (op == LBX_BLEND_MANUAL)
+                    parIndex++;
+                if (src1 == LBS_MANUAL)
+                    parIndex++;
+
+                if (numParams < parIndex)
+                {
+                    logParseError(
+                        "Bad alpha_op_ex attribute, wrong number of parameters "
+                        "(expected " + StringConverter::toString(parIndex - 1) + ")", context);
+                    return false;
+                }
+
+                arg2 = StringConverter::parseReal(vecparams[parIndex]);
+            }
+        }
+        catch (Exception& e)
+        {
+            logParseError("Bad alpha_op_ex attribute, " + e.getDescription(), context);
+            return false;
+        }
+
+        context.textureUnit->setAlphaOperation(op, src1, src2, arg1, arg2, manual);
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseEnvMap(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        if (params=="off")
+            context.textureUnit->setEnvironmentMap(false);
+        else if (params=="spherical")
+            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_CURVED);
+        else if (params=="planar")
+            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_PLANAR);
+        else if (params=="cubic_reflection")
+            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_REFLECTION);
+        else if (params=="cubic_normal")
+            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_NORMAL);
+        else
+            logParseError("Bad env_map attribute, valid parameters are 'off', "
+                "'spherical', 'planar', 'cubic_reflection' and 'cubic_normal'.", context);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseScroll(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Bad scroll attribute, wrong number of parameters (expected 2)", context);
+            return false;
+        }
+        context.textureUnit->setTextureScroll(
+            StringConverter::parseReal(vecparams[0]),
+            StringConverter::parseReal(vecparams[1]));
+
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseScrollAnim(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Bad scroll_anim attribute, wrong number of "
+                "parameters (expected 2)", context);
+            return false;
+        }
+        context.textureUnit->setScrollAnimation(
+            StringConverter::parseReal(vecparams[0]),
+            StringConverter::parseReal(vecparams[1]));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseRotate(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setTextureRotate(
+            StringConverter::parseAngle(params));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseRotateAnim(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setRotateAnimation(
+            StringConverter::parseReal(params));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseScale(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 2)
+        {
+            logParseError("Bad scale attribute, wrong number of parameters (expected 2)", context);
+            return false;
+        }
+        context.textureUnit->setTextureScale(
+            StringConverter::parseReal(vecparams[0]),
+            StringConverter::parseReal(vecparams[1]));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseWaveXform(String& params, MaterialScriptContext& context)
+    {
+        StringUtil::toLowerCase(params);
+        StringVector vecparams = StringUtil::split(params, " \t");
+
+        if (vecparams.size() != 6)
+        {
+            logParseError("Bad wave_xform attribute, wrong number of parameters "
+                "(expected 6)", context);
+            return false;
+        }
+        TextureUnitState::TextureTransformType ttype;
+        WaveformType waveType;
+        // Check transform type
+        if (vecparams[0]=="scroll_x")
+            ttype = TextureUnitState::TT_TRANSLATE_U;
+        else if (vecparams[0]=="scroll_y")
+            ttype = TextureUnitState::TT_TRANSLATE_V;
+        else if (vecparams[0]=="rotate")
+            ttype = TextureUnitState::TT_ROTATE;
+        else if (vecparams[0]=="scale_x")
+            ttype = TextureUnitState::TT_SCALE_U;
+        else if (vecparams[0]=="scale_y")
+            ttype = TextureUnitState::TT_SCALE_V;
+        else
+        {
+            logParseError("Bad wave_xform attribute, parameter 1 must be 'scroll_x', "
+                "'scroll_y', 'rotate', 'scale_x' or 'scale_y'", context);
+            return false;
+        }
+        // Check wave type
+        if (vecparams[1]=="sine")
+            waveType = WFT_SINE;
+        else if (vecparams[1]=="triangle")
+            waveType = WFT_TRIANGLE;
+        else if (vecparams[1]=="square")
+            waveType = WFT_SQUARE;
+        else if (vecparams[1]=="sawtooth")
+            waveType = WFT_SAWTOOTH;
+        else if (vecparams[1]=="inverse_sawtooth")
+            waveType = WFT_INVERSE_SAWTOOTH;
+        else
+        {
+            logParseError("Bad wave_xform attribute, parameter 2 must be 'sine', "
+                "'triangle', 'square', 'sawtooth' or 'inverse_sawtooth'", context);
+            return false;
+        }
+
+        context.textureUnit->setTransformAnimation(
+            ttype,
+            waveType,
+            StringConverter::parseReal(vecparams[2]),
+            StringConverter::parseReal(vecparams[3]),
+            StringConverter::parseReal(vecparams[4]),
+            StringConverter::parseReal(vecparams[5]) );
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTransform(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::split(params, " \t");
+        if (vecparams.size() != 16)
+        {
+            logParseError("Bad transform attribute, wrong number of parameters (expected 16)", context);
+            return false;
+        }
+        Matrix4 xform(
+            StringConverter::parseReal(vecparams[0]),
+            StringConverter::parseReal(vecparams[1]),
+            StringConverter::parseReal(vecparams[2]),
+            StringConverter::parseReal(vecparams[3]),
+            StringConverter::parseReal(vecparams[4]),
+            StringConverter::parseReal(vecparams[5]),
+            StringConverter::parseReal(vecparams[6]),
+            StringConverter::parseReal(vecparams[7]),
+            StringConverter::parseReal(vecparams[8]),
+            StringConverter::parseReal(vecparams[9]),
+            StringConverter::parseReal(vecparams[10]),
+            StringConverter::parseReal(vecparams[11]),
+            StringConverter::parseReal(vecparams[12]),
+            StringConverter::parseReal(vecparams[13]),
+            StringConverter::parseReal(vecparams[14]),
+            StringConverter::parseReal(vecparams[15]) );
+        context.textureUnit->setTextureTransform(xform);
+
+
+        return false;
+    }
+    bool parseAnisotropy(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setTextureAnisotropy(
+            StringConverter::parseInt(params));
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseTextureAlias(String& params, MaterialScriptContext& context)
+    {
+        trimAndUnquoteWord(params);
+        context.textureUnit->setTextureNameAlias(params);
+
+        return false;
+    }
+    //-----------------------------------------------------------------------
+    bool parseMipmapBias(String& params, MaterialScriptContext& context)
+    {
+        context.textureUnit->setTextureMipmapBias(
+            (float)StringConverter::parseReal(params));
+
+        return false;
+    }
+    bool parseContentType(String& params, MaterialScriptContext& context)
+    {
+        StringVector vecparams = StringUtil::tokenise(params, " \t");
+        if (vecparams.empty())
+        {
+            logParseError("No content_type specified", context);
+            return false;
+        }
+        String& paramType = vecparams[0];
+        if (paramType == "named")
+        {
+            context.textureUnit->setContentType(TextureUnitState::CONTENT_NAMED);
+        }
+        else if (paramType == "shadow")
+        {
+            context.textureUnit->setContentType(TextureUnitState::CONTENT_SHADOW);
+        }
+        else if (paramType == "compositor")
+        {
+            context.textureUnit->setContentType(TextureUnitState::CONTENT_COMPOSITOR);
+            if (vecparams.size() == 3)
+            {
+                context.textureUnit->setCompositorReference(vecparams[1], vecparams[2]);
+            }
+            else if (vecparams.size() == 4)
+            {
+                context.textureUnit->setCompositorReference(vecparams[1], vecparams[2], 
+                    StringConverter::parseUnsignedInt(vecparams[3]));
+            }
+            else
+            {
+                logParseError("compositor content_type requires 2 or 3 extra params", context);
+            }
+        }
+        else
+        {
+            logParseError("Invalid content_type specified : " + paramType, context);
+        }
+        return false;
+    }
+}
 
 namespace sh
 {
-	void OgreMaterialSerializer::reset()
-	{
-		mScriptContext.section = Ogre::MSS_NONE;
-		mScriptContext.material.setNull();
-		mScriptContext.technique = 0;
-		mScriptContext.pass = 0;
-		mScriptContext.textureUnit = 0;
-		mScriptContext.program.setNull();
-		mScriptContext.lineNo = 0;
-		mScriptContext.filename.clear();
-		mScriptContext.techLev = -1;
-		mScriptContext.passLev = -1;
-		mScriptContext.stateLev = -1;
-	}
+    OgreMaterialSerializer::OgreMaterialSerializer()
+    {
+        // Set up material attribute parsers
+        mMaterialAttribParsers.insert(AttribParserList::value_type("lod_values", (ATTRIBUTE_PARSER)parseLodValues));
+        mMaterialAttribParsers.insert(AttribParserList::value_type("lod_strategy", (ATTRIBUTE_PARSER)parseLodStrategy));
+        mMaterialAttribParsers.insert(AttribParserList::value_type("lod_distances", (ATTRIBUTE_PARSER)parseLodDistances));
+        mMaterialAttribParsers.insert(AttribParserList::value_type("receive_shadows", (ATTRIBUTE_PARSER)parseReceiveShadows));
+        mMaterialAttribParsers.insert(AttribParserList::value_type("transparency_casts_shadows", (ATTRIBUTE_PARSER)parseTransparencyCastsShadows));
+        // mMaterialAttribParsers.insert(AttribParserList::value_type("technique", (ATTRIBUTE_PARSER)parseTechnique));
+        mMaterialAttribParsers.insert(AttribParserList::value_type("set_texture_alias", (ATTRIBUTE_PARSER)parseSetTextureAlias));
 
-	bool OgreMaterialSerializer::setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass)
-	{
-		// workaround https://ogre3d.atlassian.net/browse/OGRE-158
-		if (param == "transparent_sorting" && value == "force")
-		{
-			pass->setTransparentSortingForced(true);
-			return true;
-		}
+        // Set up pass attribute parsers
+        mPassAttribParsers.insert(AttribParserList::value_type("ambient", (ATTRIBUTE_PARSER)parseAmbient));
+        mPassAttribParsers.insert(AttribParserList::value_type("diffuse", (ATTRIBUTE_PARSER)parseDiffuse));
+        mPassAttribParsers.insert(AttribParserList::value_type("specular", (ATTRIBUTE_PARSER)parseSpecular));
+        mPassAttribParsers.insert(AttribParserList::value_type("emissive", (ATTRIBUTE_PARSER)parseEmissive));
+        mPassAttribParsers.insert(AttribParserList::value_type("scene_blend", (ATTRIBUTE_PARSER)parseSceneBlend));
+        mPassAttribParsers.insert(AttribParserList::value_type("separate_scene_blend", (ATTRIBUTE_PARSER)parseSeparateSceneBlend));
+        mPassAttribParsers.insert(AttribParserList::value_type("depth_check", (ATTRIBUTE_PARSER)parseDepthCheck));
+        mPassAttribParsers.insert(AttribParserList::value_type("depth_write", (ATTRIBUTE_PARSER)parseDepthWrite));
+        mPassAttribParsers.insert(AttribParserList::value_type("depth_func", (ATTRIBUTE_PARSER)parseDepthFunc));
+        mPassAttribParsers.insert(AttribParserList::value_type("normalise_normals", (ATTRIBUTE_PARSER)parseNormaliseNormals));
+        mPassAttribParsers.insert(AttribParserList::value_type("alpha_rejection", (ATTRIBUTE_PARSER)parseAlphaRejection));
+        mPassAttribParsers.insert(AttribParserList::value_type("alpha_to_coverage", (ATTRIBUTE_PARSER)parseAlphaToCoverage));
+        mPassAttribParsers.insert(AttribParserList::value_type("transparent_sorting", (ATTRIBUTE_PARSER)parseTransparentSorting));
+        mPassAttribParsers.insert(AttribParserList::value_type("colour_write", (ATTRIBUTE_PARSER)parseColourWrite));
+        mPassAttribParsers.insert(AttribParserList::value_type("light_scissor", (ATTRIBUTE_PARSER)parseLightScissor));
+        mPassAttribParsers.insert(AttribParserList::value_type("light_clip_planes", (ATTRIBUTE_PARSER)parseLightClip));
+        mPassAttribParsers.insert(AttribParserList::value_type("cull_hardware", (ATTRIBUTE_PARSER)parseCullHardware));
+        mPassAttribParsers.insert(AttribParserList::value_type("cull_software", (ATTRIBUTE_PARSER)parseCullSoftware));
+        mPassAttribParsers.insert(AttribParserList::value_type("lighting", (ATTRIBUTE_PARSER)parseLighting));
+        mPassAttribParsers.insert(AttribParserList::value_type("fog_override", (ATTRIBUTE_PARSER)parseFogging));
+        mPassAttribParsers.insert(AttribParserList::value_type("shading", (ATTRIBUTE_PARSER)parseShading));
+        mPassAttribParsers.insert(AttribParserList::value_type("polygon_mode", (ATTRIBUTE_PARSER)parsePolygonMode));
+        mPassAttribParsers.insert(AttribParserList::value_type("polygon_mode_overrideable", (ATTRIBUTE_PARSER)parsePolygonModeOverrideable));
+        mPassAttribParsers.insert(AttribParserList::value_type("depth_bias", (ATTRIBUTE_PARSER)parseDepthBias));
+        mPassAttribParsers.insert(AttribParserList::value_type("iteration_depth_bias", (ATTRIBUTE_PARSER)parseIterationDepthBias));
+        /*mPassAttribParsers.insert(AttribParserList::value_type("texture_unit", (ATTRIBUTE_PARSER)parseTextureUnit));
+        mPassAttribParsers.insert(AttribParserList::value_type("vertex_program_ref", (ATTRIBUTE_PARSER)parseVertexProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("geometry_program_ref", (ATTRIBUTE_PARSER)parseGeometryProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("shadow_caster_vertex_program_ref", (ATTRIBUTE_PARSER)parseShadowCasterVertexProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("shadow_caster_fragment_program_ref", (ATTRIBUTE_PARSER)parseShadowCasterFragmentProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("shadow_receiver_vertex_program_ref", (ATTRIBUTE_PARSER)parseShadowReceiverVertexProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("shadow_receiver_fragment_program_ref", (ATTRIBUTE_PARSER)parseShadowReceiverFragmentProgramRef));
+        mPassAttribParsers.insert(AttribParserList::value_type("fragment_program_ref", (ATTRIBUTE_PARSER)parseFragmentProgramRef));*/
+        mPassAttribParsers.insert(AttribParserList::value_type("max_lights", (ATTRIBUTE_PARSER)parseMaxLights));
+        mPassAttribParsers.insert(AttribParserList::value_type("start_light", (ATTRIBUTE_PARSER)parseStartLight));
+        mPassAttribParsers.insert(AttribParserList::value_type("iteration", (ATTRIBUTE_PARSER)parseIteration));
+        mPassAttribParsers.insert(AttribParserList::value_type("point_size", (ATTRIBUTE_PARSER)parsePointSize));
+        mPassAttribParsers.insert(AttribParserList::value_type("point_sprites", (ATTRIBUTE_PARSER)parsePointSprites));
+        mPassAttribParsers.insert(AttribParserList::value_type("point_size_attenuation", (ATTRIBUTE_PARSER)parsePointAttenuation));
+        mPassAttribParsers.insert(AttribParserList::value_type("point_size_min", (ATTRIBUTE_PARSER)parsePointSizeMin));
+        mPassAttribParsers.insert(AttribParserList::value_type("point_size_max", (ATTRIBUTE_PARSER)parsePointSizeMax));
+        mPassAttribParsers.insert(AttribParserList::value_type("illumination_stage", (ATTRIBUTE_PARSER)parseIlluminationStage));
 
-		reset();
+        // Set up texture unit attribute parsers
+        // mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture_source", (ATTRIBUTE_PARSER)parseTextureSource));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture", (ATTRIBUTE_PARSER)parseTexture));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("anim_texture", (ATTRIBUTE_PARSER)parseAnimTexture));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("cubic_texture", (ATTRIBUTE_PARSER)parseCubicTexture));
+        // mTextureUnitAttribParsers.insert(AttribParserList::value_type("binding_type", (ATTRIBUTE_PARSER)parseBindingType));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_coord_set", (ATTRIBUTE_PARSER)parseTexCoord));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_address_mode", (ATTRIBUTE_PARSER)parseTexAddressMode));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_border_colour", (ATTRIBUTE_PARSER)parseTexBorderColour));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op", (ATTRIBUTE_PARSER)parseColourOp));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op_ex", (ATTRIBUTE_PARSER)parseColourOpEx));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op_multipass_fallback", (ATTRIBUTE_PARSER)parseColourOpFallback));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("alpha_op_ex", (ATTRIBUTE_PARSER)parseAlphaOpEx));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("env_map", (ATTRIBUTE_PARSER)parseEnvMap));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("scroll", (ATTRIBUTE_PARSER)parseScroll));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("scroll_anim", (ATTRIBUTE_PARSER)parseScrollAnim));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("rotate", (ATTRIBUTE_PARSER)parseRotate));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("rotate_anim", (ATTRIBUTE_PARSER)parseRotateAnim));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("scale", (ATTRIBUTE_PARSER)parseScale));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("wave_xform", (ATTRIBUTE_PARSER)parseWaveXform));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("transform", (ATTRIBUTE_PARSER)parseTransform));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("filtering", (ATTRIBUTE_PARSER)parseFiltering));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("compare_test", (ATTRIBUTE_PARSER)parseCompareTest));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("compare_func", (ATTRIBUTE_PARSER)parseCompareFunction));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("max_anisotropy", (ATTRIBUTE_PARSER)parseAnisotropy));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture_alias", (ATTRIBUTE_PARSER)parseTextureAlias));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("mipmap_bias", (ATTRIBUTE_PARSER)parseMipmapBias));
+        mTextureUnitAttribParsers.insert(AttribParserList::value_type("content_type", (ATTRIBUTE_PARSER)parseContentType));
+    }
 
-		mScriptContext.section = Ogre::MSS_PASS;
+	bool OgreMaterialSerializer::setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass)
+	{
+		MaterialScriptContext mScriptContext;
 		mScriptContext.pass = pass;
 
 		if (mPassAttribParsers.find (param) == mPassAttribParsers.end())
@@ -54,9 +1920,7 @@ namespace sh
 			return true;
 		}
 		
-		reset();
-
-		mScriptContext.section = Ogre::MSS_TEXTUREUNIT;
+		MaterialScriptContext mScriptContext;
 		mScriptContext.textureUnit = t;
 
 		if (mTextureUnitAttribParsers.find (param) == mTextureUnitAttribParsers.end())
@@ -70,9 +1934,7 @@ namespace sh
 
 	bool OgreMaterialSerializer::setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m)
 	{
-		reset();
-
-		mScriptContext.section = Ogre::MSS_MATERIAL;
+        MaterialScriptContext mScriptContext;
 		mScriptContext.material = m;
 
 		if (mMaterialAttribParsers.find (param) == mMaterialAttribParsers.end())
diff --git a/source/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp b/source/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp
index acfc5a36..0b38f49d 100644
--- a/source/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp
+++ b/source/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp
@@ -1,27 +1,38 @@
 #ifndef SH_OGREMATERIALSERIALIZER_H
 #define SH_OGREMATERIALSERIALIZER_H
 
-#include <OgreMaterialSerializer.h>
+#include <OgrePrerequisites.h>
 
 namespace Ogre
 {
-	class Pass;
+    struct MaterialScriptContext;
+    /// Function def for material attribute parser; return value determines if the next line should be {
+    typedef bool (*ATTRIBUTE_PARSER)(String& params, MaterialScriptContext& context);
 }
 
 namespace sh
 {
 	/**
-	 * @brief This class allows me to let Ogre handle the pass & texture unit properties
+	 * @brief This class handles the pass & texture unit properties
 	 */
-	class OgreMaterialSerializer : public Ogre::MaterialSerializer
+	class OgreMaterialSerializer
 	{
 	public:
+        OgreMaterialSerializer();
+
 		bool setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass);
 		bool setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t);
 		bool setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m);
 
 	private:
-		void reset();
+        /// Keyword-mapped attribute parsers.
+        typedef std::map<Ogre::String, Ogre::ATTRIBUTE_PARSER> AttribParserList;
+        /// Parsers for the pass section of a script
+        AttribParserList mPassAttribParsers;
+        /// Parsers for the texture unit section of a script
+        AttribParserList mTextureUnitAttribParsers;
+        /// Parsers for the material section of a script
+        AttribParserList mMaterialAttribParsers;
 	};
 
 }
diff --git a/source/shiny/Platforms/Ogre/OgreTextureUnitState.cpp b/source/shiny/Platforms/Ogre/OgreTextureUnitState.cpp
index e1adbf33..c5caf22f 100644
--- a/source/shiny/Platforms/Ogre/OgreTextureUnitState.cpp
+++ b/source/shiny/Platforms/Ogre/OgreTextureUnitState.cpp
@@ -10,7 +10,7 @@ namespace sh
 	OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent, const std::string& name)
 		: TextureUnitState()
 	{
-		mTextureUnitState = parent->getOgrePass()->createTextureUnitState("");
+		mTextureUnitState = parent->getOgrePass()->createTextureUnitState();
 		mTextureUnitState->setName(name);
 	}
 
diff --git a/source/sound/SoundMgr.cpp b/source/sound/SoundMgr.cpp
index 6653a78e..67b288d4 100644
--- a/source/sound/SoundMgr.cpp
+++ b/source/sound/SoundMgr.cpp
@@ -4,6 +4,7 @@
 #include "SoundBase.h"
 #include "SoundBaseMgr.h"
 #include <OgreDataStream.h>
+#include <OgreException.h>
 using namespace Ogre;
 
 
diff --git a/source/vdrift/cartire.cpp b/source/vdrift/cartire.cpp
index 982f8807..8c1f00aa 100644
--- a/source/vdrift/cartire.cpp
+++ b/source/vdrift/cartire.cpp
@@ -280,7 +280,7 @@ Dbl CARTIRE::Pacejka_Fx (Dbl sigma, Dbl Fz, Dbl friction_coeff, Dbl & maxforce_o
 
 	maxforce_output = D;
 
-	assert(!std::isnan(Fx));
+	assert(!isnan(Fx));
 	return Fx;
 }
 
diff --git a/source/vdrift/collision_world.cpp b/source/vdrift/collision_world.cpp
index d907939a..55d90894 100644
--- a/source/vdrift/collision_world.cpp
+++ b/source/vdrift/collision_world.cpp
@@ -504,7 +504,7 @@ bool COLLISION_WORLD::CastRay(
 					int my = (pos[1] + 0.5*tws)/tws*t;  my = std::max(0,std::min(t-1, t-1-my));
 
 					int mtr = pApp->blendMtr[my*t + mx];
-
+                    assert(mtr < td.layers.size());
 					int id = td.layersAll[td.layers[mtr]].surfId;
 					surf = &pApp->pGame->surfaces[id];
 
openSUSE Build Service is sponsored by