diff --git a/Makefile b/Makefile
index 51571c7c89..5a4e348ff9 100644
--- a/Makefile
+++ b/Makefile
@@ -33,8 +33,8 @@ mygui_cpp=mygui console
 
 # Ditto for the landscape engine, in terrain/cpp_X.cpp
 terrain_cpp=baseland esm framelistener generator index landdata\
-materialgen mwheightmap palette point2\
-quad quaddata terraincls terrain terrainmesh
+materialgen heightmap palette point2\
+quad quaddata terrain terrainmesh terrainmesh2 heightmap2
 
 # FFmpeg files, in the form sound/cpp_X.cpp.
 avcodec_cpp=avcodec
diff --git a/terrain/cpp_framelistener.cpp b/terrain/cpp_framelistener.cpp
index 75c417c4ec..9323fb97b7 100644
--- a/terrain/cpp_framelistener.cpp
+++ b/terrain/cpp_framelistener.cpp
@@ -6,7 +6,7 @@ protected:
    */
   bool frameEnded(const FrameEvent& evt)
   {
-    g_Terrain->update(evt.timeSinceLastFrame);
+    g_heightMap->update(evt.timeSinceLastFrame);
     return true;
   }
 
@@ -16,19 +16,20 @@ public:
     // Add the frame listener
     mRoot->addFrameListener(this);
 
-    //our derived heightmap
-    g_heightMap = new MWHeightmap();
+    // Create a root scene node first
+    Ogre::SceneNode *node = mSceneMgr->getRootSceneNode()
+      ->createChildSceneNode("TERRAIN_ROOT");
+
+    // The main terrain object
+    g_heightMap = new HeightMap(node);
     g_heightMap->load(TERRAIN_OUTPUT);
 
-    //setup terrain
-    g_Terrain = new Terrain(mSceneMgr->getRootSceneNode()->createChildSceneNode("TERRAIN_ROOT"));  //root scene node
-
     //fix settings
-    g_Terrain->setMorphingEnabled(false);
-    g_Terrain->setTextureFadingEnabled(false);
+    g_heightMap->setMorphingEnabled(false);
+    g_heightMap->setTextureFadingEnabled(false);
 
     //create the quad node
-    g_Terrain->create();
+    g_heightMap->create();
   }
 
   /* KILLME
diff --git a/terrain/cpp_mwheightmap.cpp b/terrain/cpp_heightmap.cpp
similarity index 57%
rename from terrain/cpp_mwheightmap.cpp
rename to terrain/cpp_heightmap.cpp
index 8b74488b90..2bc5844e45 100644
--- a/terrain/cpp_mwheightmap.cpp
+++ b/terrain/cpp_heightmap.cpp
@@ -1,11 +1,10 @@
-/**
- * @brief the class that deals with loading quads from the disk @todo a
- * major improvment would be to store the data as a quad tree. It might
- * improve lookup times. Then again. Might not
- */
-class MWHeightmap
+class HeightMap
 {
 public:
+  HeightMap(Ogre::SceneNode* r);
+
+  ~HeightMap();
+
   /**
    * loads the quad data from the disk
    */
@@ -55,12 +54,41 @@ public:
     return true;
   }
 
-private:
+  void create();
+
+  inline Ogre::SceneNode* getTerrainSceneNode(){return mTerrainSceneNode;}
+
+  void update(Ogre::Real t);
+
+  inline Ogre::Real getMorphSpeed(){return 1.0f;}
+  inline Ogre::Real getTextureFadeSpeed(){ return 2.0f;}
+  inline void setMorphingEnabled(bool enabled){
+    mMorphingEnabled = enabled;
+  }
+  inline bool isMorphingEnabled() const{
+    return mMorphingEnabled;
+  }
+  inline void setTextureFadingEnabled(bool enabled){
+    if ( enabled && !mMorphingEnabled )
+      OGRE_EXCEPT(Ogre::Exception::ERR_NOT_IMPLEMENTED, "Cannot have fading but not morphing active", "Terrain::setTextureFadingEnabled");
+    mTextureFadingEnabled = enabled;
+  }
+
+  inline bool isTextureFadingEnabled() const{
+    return mTextureFadingEnabled;
+  }
+
+  private:
+  Ogre::SceneNode* mTerrainSceneNode;
+  Quad* mQuadRoot;
+  bool mMorphingEnabled;
+  bool mTextureFadingEnabled;
+
+  BaseLand mBaseLand;
 
   ///ifs for the data file. Opned on load
   std::ifstream mDataIFS;
   ///holds the offsets of the quads
   Index mIndex;
   TexturePalette mPalette;
-
 };
diff --git a/terrain/cpp_heightmap2.cpp b/terrain/cpp_heightmap2.cpp
new file mode 100644
index 0000000000..bae9809a1d
--- /dev/null
+++ b/terrain/cpp_heightmap2.cpp
@@ -0,0 +1,24 @@
+HeightMap::HeightMap(Ogre::SceneNode* r)
+  :  mTerrainSceneNode(r),
+     mQuadRoot(0),
+     mMorphingEnabled(true),
+     mTextureFadingEnabled(true),
+     mBaseLand(r)
+{
+
+}
+//----------------------------------------------
+HeightMap::~HeightMap(){
+  delete mQuadRoot;
+}
+//----------------------------------------------
+void HeightMap::create(){
+  mQuadRoot = new Quad(Quad::QL_ROOT, 0);
+}
+//----------------------------------------------
+void HeightMap::update(Ogre::Real t){
+  assert(mQuadRoot);
+  mQuadRoot->update(t);
+  mBaseLand.update();
+}
+
diff --git a/terrain/cpp_quad.cpp b/terrain/cpp_quad.cpp
index 4f6ac19662..7bc514d919 100644
--- a/terrain/cpp_quad.cpp
+++ b/terrain/cpp_quad.cpp
@@ -19,7 +19,6 @@
  */
 class Quad
 {
-  enum SplitState { SS_NONE, SS_SPLIT, SS_UNSPLIT };
 
   /**
    * when each quad is split, the children can be one of 4 places,
@@ -226,11 +225,11 @@ public:
     const Ogre::Vector3 pos(qx - mSideLength/2,
                             0,qy - mSideLength/2);
 
-    mSceneNode = g_Terrain->getTerrainSceneNode()->createChildSceneNode(pos);
+    mSceneNode = g_heightMap->getTerrainSceneNode()->createChildSceneNode(pos);
 
     // This was in create()
 
-    if ( mDepth == g_Terrain->getMaxDepth() )
+    if ( mDepth == g_heightMap->getMaxDepth() )
       for ( int y = 0; y < 4; ++y )
         for ( int x = 0; x < 4; ++x )
           {
@@ -265,7 +264,7 @@ public:
     mSceneNode->removeAndDestroyAllChildren();
     mSceneMgr->destroySceneNode(mSceneNode);
 
-    g_Terrain->getTerrainSceneNode()->detachAllObjects();
+    g_heightMap->getTerrainSceneNode()->detachAllObjects();
 
     delete mQuadData;
     mQuadData = NULL;
diff --git a/terrain/cpp_quaddata.cpp b/terrain/cpp_quaddata.cpp
index 18d37d9064..15741f060e 100644
--- a/terrain/cpp_quaddata.cpp
+++ b/terrain/cpp_quaddata.cpp
@@ -5,6 +5,8 @@
  * a set of verts Normals and indicies to allow us to pass optimized
  * meshes
  */
+enum SplitState { SS_NONE, SS_SPLIT, SS_UNSPLIT };
+
 class QuadData
 {
   typedef std::list<Ogre::ResourcePtr> ResourceList;
diff --git a/terrain/cpp_terrain.cpp b/terrain/cpp_terrain.cpp
index d0e3e9c339..0bb8fd668b 100644
--- a/terrain/cpp_terrain.cpp
+++ b/terrain/cpp_terrain.cpp
@@ -54,13 +54,11 @@ const float UNSPLIT_FACTOR = 2.0;
 
 class Quad;
 class QuadData;
-class Terrain;
 class MaterialGenerator;
-class MWHeightmap;
+class HeightMap;
 
-MWHeightmap *g_heightMap;
+HeightMap *g_heightMap;
 MaterialGenerator *g_materialGen;
-Terrain *g_Terrain;
 
 #undef TRACE
 #define TRACE(x)
@@ -91,17 +89,14 @@ Terrain *g_Terrain;
 
 // For rendering
 #include "cpp_baseland.cpp"
-#include "cpp_mwheightmap.cpp"
 
 // These depend on each other, so our usual hackery won't work. We
 // need the header files first.
-#include "cpp_terrainmesh.h"
-#include "cpp_terraincls.h"
-
-#include "cpp_quad.cpp"
-
-#include "cpp_terraincls.cpp"
+#include "cpp_heightmap.cpp"
 #include "cpp_terrainmesh.cpp"
+#include "cpp_quad.cpp"
+#include "cpp_heightmap2.cpp"
+#include "cpp_terrainmesh2.cpp"
 
 #include "cpp_framelistener.cpp"
 
diff --git a/terrain/cpp_terraincls.cpp b/terrain/cpp_terraincls.cpp
deleted file mode 100644
index ab033b3ddb..0000000000
--- a/terrain/cpp_terraincls.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-Terrain::Terrain(Ogre::SceneNode* r)
-  :  mTerrainSceneNode(r),
-     mQuadRoot(0),
-     mMorphingEnabled(true),
-     mTextureFadingEnabled(true),
-     mBaseLand(r)
-{
-
-}
-//----------------------------------------------
-Terrain::~Terrain(){
-  delete mQuadRoot;
-}
-//----------------------------------------------
-void Terrain::create(){
-  mQuadRoot = new Quad(Quad::QL_ROOT, 0);
-}
-//----------------------------------------------
-void Terrain::update(Ogre::Real t){
-  assert(mQuadRoot);
-  mQuadRoot->update(t);
-  mBaseLand.update();
-}
-//----------------------------------------------
-int Terrain::getMaxDepth(){
-  return g_heightMap->getMaxDepth();
-}
-/*
-//----------------------------------------------
-void Terrain::reload(){
-  delete mQuadRoot;
-  mQuadRoot = new Quad(Quad::QL_ROOT, 0);
-}
-//----------------------------------------------
-*/
diff --git a/terrain/cpp_terraincls.h b/terrain/cpp_terraincls.h
deleted file mode 100644
index 0a9df4f741..0000000000
--- a/terrain/cpp_terraincls.h
+++ /dev/null
@@ -1,145 +0,0 @@
-class Terrain
-{
-public:
-  /**
-   * @brief inits vars and creates quad tree
-   * @param d the heightmap that contains the data
-   * @param s the current scne manager
-   * @param r the root scene node that all terrain nodes are barsed off
-   * @param c the camera that the poistion data is taken from
-   *
-   * The terrain is create in the constructor.
-   * @todo change quad root creation to create/destroy funcs?
-   */
-  explicit Terrain(Ogre::SceneNode* r);
-  /**
-   * @brief deletes the quad tree
-   */
-  ~Terrain();
-
-  /**
-   * @brief creates the quad tree
-   * @remarks This must be called before any call to upate(). We cannot call it from the constructor as options
-   *   may not have been set yet
-   */
-  void create();
-
-  /**
-   * @brief recreates the quad tree by destroying everything and starting again.
-   * @remarks this is very slow, as it drops all created alpha maps and meshes.
-   * @todo check this works
-   */
-  //void reload();
-
-  /**
-   * @brief sets the scene node that all of the terrain nodes are based off
-   * @param r the scene node to use for terrain
-   */
-  inline void setTerrainSceneNode(Ogre::SceneNode* r){ mTerrainSceneNode = r; }
-
-  /**
-   * @return the scene node that should be used as the root of the terrain
-   *
-   * This is mainly used by the quad tree
-   */
-  inline Ogre::SceneNode* getTerrainSceneNode(){return mTerrainSceneNode;}
-
-  /**
-   * @brief updates the quad tree, splittig and unsplitting where needed.
-   *
-   * There is no requirement for this to be called every frame
-   */
-  void update(Ogre::Real t);
-
-  /**
-   * @brief handles the actions to take on the creation of a terrain mesh
-   * @param qd the quad data. It is valid until the same variable is passed to _quadDestroyed
-  void _quadCreated(QuadData* qd);
-
-  /**
-   * @brief The quad as defined by the quad data qd has been destroyed
-   * @param qd the quad that has been destroyed. This is only valid for this function. Is is deleted just after
-  void _quadDestroyed(QuadData* qd);
-
-  /**
-   * @brief sets the function to be used in the callback when a quad is created
-   * @param f the function to use. Set to null to disable callbacks
-
-  inline void setQuadCreateFunction(void (*f)(QuadData*)){
-    mQuadCreateFunction = f;
-  }
-  /**
-   * @brief sets the function to be used in the callback when a quad is destroyed
-   * @param f the function to use. Set to null to disable callbacks
-  inline void setQuadDestroyFunction(void (*f)(QuadData*)){
-    mQuadDestroyFunction = f;
-  }
-   */
-
-  /**
-   * @brief time in seconds to morph to full detail after an unsplit.
-   */
-  inline Ogre::Real getMorphSpeed(){return 1.0f;}
-  /**
-   * @brief the time in seconds it takes for the texture to fade to the higher detail
-   */
-  inline Ogre::Real getTextureFadeSpeed(){ return 2.0f;}
-
-  /**
-   * @return the maximum depth of the quad tree
-   * @remarks this is used by the terrain renderable for adding morhping to textures. It doesn't want to happen
-   *   on the lowest detail
-   */
-  int getMaxDepth();
-
-  /**
-   * @brief disables/enables morphing
-   * @remarks This will not happen instantly unless reload() is called
-   */
-
-  inline void setMorphingEnabled(bool enabled){
-    mMorphingEnabled = enabled;
-
-  }
-  /**
-   * @return true if morphing is enabled
-   */
-  inline bool isMorhpingEnabled() const{
-    return mMorphingEnabled;
-  }
-
-  /**
-   * @brief disables/enables texture fading.
-   * @remarks This will not happen instantly unless reload() is called. Morphing is required atm
-   */
-  inline void setTextureFadingEnabled(bool enabled){
-    if ( enabled && !mMorphingEnabled )
-      OGRE_EXCEPT(Ogre::Exception::ERR_NOT_IMPLEMENTED, "Cannot have fading but not morphing active", "Terrain::setTextureFadingEnabled");
-    mTextureFadingEnabled = enabled;
-  }
-  /**
-   * @return true if texture fading is enabled
-   */
-  inline bool isTextureFadingEnabled() const{
-    return mTextureFadingEnabled;
-  }
-protected:
-  /// the scenenode that every other node is decended from. This
-  /// should be surplied by the user
-  Ogre::SceneNode* mTerrainSceneNode;
-
-  ///the root node for all the quads.
-  Quad* mQuadRoot;
-
-  /*
-  ///quad callback function
-  void (*mQuadCreateFunction)(QuadData*);
-  ///quad callback function
-  void (*mQuadDestroyFunction)(QuadData*);
-  */
-
-  bool mMorphingEnabled;
-  bool mTextureFadingEnabled;
-
-  BaseLand mBaseLand;
-};
diff --git a/terrain/cpp_terrainmesh.cpp b/terrain/cpp_terrainmesh.cpp
index 1368228ccd..03ec0610fc 100644
--- a/terrain/cpp_terrainmesh.cpp
+++ b/terrain/cpp_terrainmesh.cpp
@@ -1,495 +1,343 @@
-TerrainMesh::TerrainMesh(QuadData* qd, float segSize, float startX, float startY,
-                         const Ogre::Vector3 &pos,
-                         int width, int depth, bool skirts,
-                         Ogre::SceneNode *parent)
-  : Ogre::Renderable(),
-    Ogre::MovableObject(),
-    mWidth(width),
-    mUseSkirts(skirts),
-    mBuilt(false),
-    mDepth(depth),
-    mVertexes(0),
-    mIndices(0),
-    mLODMorphFactor(0),
-    mTextureFadeFactor(0),
-    mMin(30000),
-    mMax(-30000),
-    mExtraMorphAmount(0),
-    mHasFadePass(false),
-    mQuadData(qd),
-    mSegmentSize(segSize),
-    mX(startX),
-    mY(startY)
+/**
+ * @brief Terrain for one cell. Handles building, destroying and LOD morphing
+ */
+#define QSDEBUG
+class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject
 {
-  // From QuadSegment()
-  assert(qd);
-  assert(segSize>0&&segSize<=1);
-  assert(mY>=0&&mY<=1);
-  assert(mX>=0&&mY<=1);
+ public:
 
+  TerrainMesh(QuadData* qd, float segSize, float startX, float startY,
+              const Ogre::Vector3 &pos,
+              int width, int depth, bool skirts,
+              Ogre::SceneNode *parent);
+
+  ~TerrainMesh()
+    {
+      destroy();
+
+      assert(node);
+
+      node->detachAllObjects();
+      node->getCreator()->destroySceneNode(node);
+    }
+
+  /**
+   * Can be called manually and can be called from the destuctor. This
+   * destroyes the mesh
+   */
+  // FIXME: We don't need this as a separate function.
+  void destroy();
+
+  /**
+   * @brief Checks if it needs to be split or unsplit and deals with
+   * the morph factor. time seconds since last frame
+   */
+  void update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist);
+
+  /**
+   * @todo Needs to work out what this does (if it does what it is meant to)
+   */
+  void visitRenderables(Renderable::Visitor* visitor,
+                        bool debugRenderables = false) {
+    visitor->visit(this, 0, false);
+  }
+
+  virtual const Ogre::MaterialPtr& getMaterial( void ) const {
+    return mMaterial;
+  }
+  //-----------------------------------------------------------------------
+  void getRenderOperation( Ogre::RenderOperation& op ) {
+    op.useIndexes = true;
+    op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
+    op.vertexData = mVertexes;
+    op.indexData = mIndices;
+  }
+
+  //-----------------------------------------------------------------------
+  void getWorldTransforms( Ogre::Matrix4* xform ) const {
+    *xform = mParentNode->_getFullTransform();
+  }
+  //-----------------------------------------------------------------------
+  const Ogre::Quaternion& getWorldOrientation(void) const {
+    return mParentNode->_getDerivedOrientation();
+  }
+  //-----------------------------------------------------------------------
+  const Ogre::Vector3& getWorldPosition(void) const {
+    return mParentNode->_getDerivedPosition();
+  }
+  //-----------------------------------------------------------------------
+
+  Ogre::Real getSquaredViewDepth(const Ogre::Camera *cam) const {
+    Ogre::Vector3 diff = mCenter - cam->getDerivedPosition();
+    // Use squared length to avoid square root
+    return diff.squaredLength();
+  }
+  //-----------------------------------------------------------------------
+
+  const Ogre::LightList& getLights(void) const {
+    if (mLightListDirty) {
+      getParentSceneNode()->getCreator()->_populateLightList(
+                                                             mCenter, this->getBoundingRadius(), mLightList);
+      mLightListDirty = false;
+    }
+    return mLightList;
+  }
+  //-----------------------------------------------------------------------
+  virtual const Ogre::String& getMovableType( void ) const {
+    static Ogre::String t = "MW_TERRAIN";
+    return t;
+  }
+  //-----------------------------------------------------------------------
+  void _updateRenderQueue( Ogre::RenderQueue* queue ) {
+    mLightListDirty = true;
+    queue->addRenderable(this, mRenderQueueID);
+  }
+
+  const Ogre::AxisAlignedBox& getBoundingBox( void ) const {
+    return mBounds;
+  };
+  //-----------------------------------------------------------------------
+  Ogre::Real getBoundingRadius(void) const {
+    return mBoundingRadius;
+  }
+  //-----------------------------------------------------------------------
+
+  /**
+   * @brief passes the morph factor to the custom vertex program
+   */
+  void _updateCustomGpuParameter(const Ogre::GpuProgramParameters::AutoConstantEntry& constantEntry,
+                                 Ogre::GpuProgramParameters* params) const;
+
+  /**
+   * @brief sets the mExtraMorphAmount so it slowly regains detail from the lowest morph factor
+   */
+  void justSplit();
+  /**
+   * @brief Does nothing
+   */
+  inline void justUnsplit(){
+  }
+
+  inline float getMax(){
+    return mMax;
+  }
+  inline float getMin(){
+    return mMin;
+  }
+
+
+  /**
+   * Gets how many vertexes wide this quad segment is. Should always be 2^n+1
+   * @return the vertex width of this quad segment
+   */
+  int getVertexWidth()
+  {
+    return (mQuadData->getVertexWidth()-1)*mSegmentSize+1;
+  }
+
+  /**
+   * @brief gets a vertex assuming that x = 0, y = 0 addresses the start of the quad
+   */
+  float getVertex(int x, int y)
+  {
 #ifdef QSDEBUG
-  {
-    //check sizes
-    const float qw = mQuadData->getVertexWidth()-1;
-    const float fsw = qw*segSize;
-    const int isw = (int)fsw;
-    assert(fsw==isw);
-  }
+    {
+      const int vw = getVertexWidth();
+      assert(x<vw);
+    }
 #endif
-
-  //precalc offsets, as getVertex/getNormal get called a lot (1000s of times)
-  computeOffsets();
-
-  // From Quad
-  node = parent->createChildSceneNode(pos);
-
-  // From create()
-  createVertexBuffer();
-  calculateVetexValues();
-  calculateIndexValues();
-  setBounds();
-
-  node->attachObject(this);
-
-  createMaterial();
-
-  if ( g_Terrain->isMorhpingEnabled() && mDepth != g_Terrain->getMaxDepth() ) {
-    Ogre::Technique* tech = getMaterial()->getTechnique(0);
-    for ( size_t i = 0; i < tech->getNumPasses(); ++i ) {
-      assert(g_Terrain->isMorhpingEnabled());
-      tech->getPass(i)->setVertexProgram(MORPH_VERTEX_PROGRAM);
-    }
+    return mQuadData->getVertex((mYOffset + y)*mQuadData->getVertexWidth()+(mXOffset+x));
   }
 
-  if ( g_Terrain->isMorhpingEnabled() )
-    calculateDeltaValues();
-
-  mBuilt = true;
-}
-
-void TerrainMesh::destroy() {
-  if ( !mBuilt ) return;
-
-  //deleting null values is fine iirc
-  delete mIndices;
-
-#   if ENABLED_CRASHING == 1
+  float getNormal(int x, int y, int z)
   {
-    delete mVertexes;
+    assert(z>=0&&z<3);
+    return mQuadData->getNormal(((mYOffset + y)*mQuadData->getVertexWidth()+(mXOffset+x))*3+z);
   }
-#   else
+
+ private:
+
+  void createMaterial()
   {
-    if ( mDepth != g_Terrain->getMaxDepth() ){
-      delete mVertexes;
+    assert(mSegmentSize>0);
+    if ( mSegmentSize == 1 ) //we can use the top level material
+      {
+        mMaterial = mQuadData->getMaterial();
+        return;
+      }
+
+    if ( mQuadData->getTexture().length() )
+      assert(0&&"NOT IMPLEMENTED");
+
+    const std::vector<int>& tref = mQuadData->getTextureIndexRef();
+    const int indexSize = sqrt(tref.size());
+    const int cellIndexSize = indexSize - 2;
+
+    //plus 1 to take into account border
+    const int xoff = float(cellIndexSize) * mX;
+    const int yoff = float(cellIndexSize) * mY;
+    const int size = float(cellIndexSize) * mSegmentSize;
+
+    std::vector<int> ti;
+
+    ti.resize((size+2)*(size+2), -1);
+
+    for ( int y = 0; y < size+2; ++y ){
+      for ( int x = 0; x < size+2; ++x ){
+        ti[(y)*(size+2)+(x)] = tref.at((y+yoff)*(indexSize)+(x+xoff));
+      }
     }
-  }
-#   endif
 
-  mBuilt = false;
-}
-//----------------------------------------------
-void TerrainMesh::update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist)
-{
-  TRACE("TerrainMesh::update");
-  //if ( USE_MORPH ){
-
-  //as aprocesh mUnsplitDistance, lower detail
-  if ( camDist > morphDist && mDepth > 1 ) {
-    mLODMorphFactor = 1 - (usplitDist - camDist)/(usplitDist-morphDist);
-  } else
-    mLODMorphFactor = 0;
-  mTextureFadeFactor = mLODMorphFactor;
-
-
-  //on an split, it sets the extra morph amount to 1, we then ensure this ends up at 0... slowly
-  if ( mExtraMorphAmount > 0 ) {
-    mLODMorphFactor += mExtraMorphAmount;
-    mExtraMorphAmount -= (time/g_Terrain->getMorphSpeed()); //decrease slowly
-  }
-  if ( mExtraFadeAmount > 0 ) {
-    mTextureFadeFactor += mExtraFadeAmount;
-    mExtraFadeAmount -= (time/g_Terrain->getTextureFadeSpeed());
+    mMaterial = g_materialGen->getAlphaMat
+      (ti,size,
+       1, 1.0f/size,
+       mQuadData->getUsedResourcesRef());
   }
 
-  //Ensure within valid bounds
-  if ( mLODMorphFactor > 1 )
-    mLODMorphFactor = 1;
-  else if ( mLODMorphFactor < 0 )
-    mLODMorphFactor = 0;
-
-  if ( mTextureFadeFactor > 1 )
-    mTextureFadeFactor = 1;
-  else if ( mTextureFadeFactor < 0 )
-    mTextureFadeFactor = 0;
-
-  //}
-
-  //remove pass. Keep outside in case terrain fading is removed while it is active
-  if ( mHasFadePass && mTextureFadeFactor == 0 ) {
-    removeFadePass();
-  } else if ( g_Terrain->isTextureFadingEnabled() &&
-              !mHasFadePass &&
-              mTextureFadeFactor > 0 &&
-              hasParentTexture() ) {
-    addFadePass();
+  inline bool hasParentTexture() const{
+    return mQuadData->hasParentTexture();
+  }
+  inline const std::string& getParentTexture() const{
+    return mQuadData->getParentTexture();
+  }
+  inline int getVertexSeperation(){
+    return mQuadData->getVertexSeperation();
   }
 
-}
-//----------------------------------------------
-void TerrainMesh::addFadePass() {
-  assert(mHasFadePass==false);
-
-  if ( mDepth == g_Terrain->getMaxDepth() ) return;
-
-
-  mHasFadePass = true;
-  Ogre::MaterialPtr mat = getMaterial();
-  Ogre::Pass* newPass = mat->getTechnique(0)->createPass();
-  newPass->setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA);
-
-  //set fragment program
-  assert(g_Terrain->isTextureFadingEnabled());
-  newPass->setFragmentProgram(FADE_FRAGMENT_PROGRAM);
-
-  if ( g_Terrain->isMorhpingEnabled() && mDepth != g_Terrain->getMaxDepth() ) {
-    assert(g_Terrain->isMorhpingEnabled());
-    newPass->setVertexProgram(MORPH_VERTEX_PROGRAM);
+  inline float getSegmentSize(){
+    return mSegmentSize;
+  }
+  inline float getStartX(){
+    return mX;
+  }
+  inline float getStartY(){
+    return mY;
   }
 
+  /**
+   * @brief Adds another pass to the material to fade in/out the material from a higher level
+   */
+  void addFadePass();
+  /**
+   * @brief removes the last pass from the material. Assumed to be the fade pass
+   */
+  void removeFadePass();
 
-  //set texture to be used
-  newPass->createTextureUnitState(getParentTexture(), 1);
-}
-//----------------------------------------------
-void TerrainMesh::removeFadePass() {
-  assert(mHasFadePass==true);
-  mHasFadePass = false;
-  Ogre::MaterialPtr mat = getMaterial();
-  Ogre::Technique* tech = mat->getTechnique(0);
+  /**
+   * @return the height at the given vertex
+   */
+  float getVertexHeight(int x, int y);
 
-  tech->removePass(tech->getNumPasses()-1);
-}
-//----------------------------------------------
-void TerrainMesh::justSplit() {
-  mExtraMorphAmount = 1;
-  mLODMorphFactor = 1;
-  mTextureFadeFactor = 1;
-  mExtraFadeAmount = 1;
+  /**
+   * Inits the vertex stuff
+   */
+  void createVertexBuffer();
 
-  if ( g_Terrain->isTextureFadingEnabled() && hasParentTexture() )
-    addFadePass();
-}
+  /**
+   * @brief fills the vertex buffer with data
+   * @todo I don't think tex co-ords are right
+   */
+  void calculateVetexValues();
 
-//----------------------------------------------
-void TerrainMesh::_updateCustomGpuParameter(
-                                            const GpuProgramParameters::AutoConstantEntry& constantEntry,
-                                            GpuProgramParameters* params) const {
-  using namespace Ogre;
-  if (constantEntry.data == MORPH_CUSTOM_PARAM_ID)
-    params->_writeRawConstant(constantEntry.physicalIndex, mLODMorphFactor);
-  else if ( constantEntry.data == FADE_CUSTOM_PARAM_ID )
-    params->_writeRawConstant(constantEntry.physicalIndex, mTextureFadeFactor);
-  else
-    Renderable::_updateCustomGpuParameter(constantEntry, params);
+  /**
+   * @brief returns a a new Vertex Buffer ready for input
+   * @remarks Unlike other terrain libs, this isn't 0s when it is returend
+   */
+  Ogre::HardwareVertexBufferSharedPtr createDeltaBuffer( );
 
+  /**
+   * @brief DOESN'T WORK FULLY
+   * @todo fix
+   */
+  void calculateDeltaValues();
+  /**
+   * @brief gets the position of a vertex. It will not interpolate
+   */
+  Ogre::Vector3 getVertexPosition(int x, int y);
 
-}
-//----------------------------------------------
-float TerrainMesh::getVertexHeight(int x, int y) {
-  return getVertex(x,y);
-}
-//----------------------------------------------
-Ogre::Vector3 TerrainMesh::getVertexPosition(int x, int y) {
-  return Ogre::Vector3(x*getVertexSeperation(), getVertexHeight(x,y) , y*getVertexSeperation());
-}
-//----------------------------------------------
-void TerrainMesh::calculateVetexValues() {
-  using namespace Ogre;
+  /**
+   * @brief gets the indicies for the vertex data.
+   */
+  void calculateIndexValues();
 
-  //get the texture offsets for the higher uv
-  float xUVOffset = 0;
-  float yUVOffset = 0;
-
-  if ( g_Terrain->isTextureFadingEnabled() ) {
-    assert(0);
-  }
   /*
-    switch (mInterface->getLocation()) {
-    case Quad::QL_NW :
-    yUVOffset = 32.0f/64.0f;
-    break;
-    case Quad::QL_NE:
-    yUVOffset = 32.0f/64.0f;
-    xUVOffset = 32.0f/64.0f;
-    break;
-    case Quad::QL_SE:
-    xUVOffset = 32.0f/64.0f;
-    break;
-    default:
-    break;
+   * Sets the bounds on the renderable. This requires that mMin/mMax
+   * have been set. They are set in createVertexData. This may look
+   * as though it is done twice, as it is also done in MeshInterface,
+   * however, there is no guarentee that the mesh sizes are the same
+   */
+  void setBounds();
+
+  Ogre::SceneNode* node;
+
+  const int mWidth;
+  const bool mUseSkirts;
+
+  ///true if the land has been built
+  bool mBuilt;
+
+  int mDepth;
+
+  Ogre::MaterialPtr mMaterial;
+  Ogre::ManualObject* mObject;
+
+  Ogre::VertexData* mVertexes;
+  Ogre::IndexData* mIndices;
+  Ogre::HardwareVertexBufferSharedPtr mMainBuffer;
+  Ogre::HardwareVertexBufferSharedPtr mDeltaBuffer;
+
+  mutable bool mLightListDirty;
+
+  Ogre::Real mBoundingRadius;
+  Ogre::AxisAlignedBox mBounds;
+  Ogre::Vector3 mCenter;
+
+  Ogre::Real mLODMorphFactor, mTextureFadeFactor;
+
+  /** Max and min heights of the mesh */
+  float mMin, mMax;
+
+  int computeOffset(float x)
+  {
+#ifdef QSDEBUG
+    {
+      //check it is a valid position
+      const int start = (mQuadData->getVertexWidth()-1)*x;
+      const int vw = getVertexWidth()-1;
+      assert(vw>0);
+      assert((start%vw)==0);
     }
-  */
-
-  int start = 0;
-  int end = mWidth;
-
-  if ( mUseSkirts ) {
-    --start;
-    ++end;
+#endif
+    return float((mQuadData->getVertexWidth()-1))*x;
   }
 
-  float* verts = static_cast<float*>(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD));
-  for ( int y = start; y < end; y++ ) {
-    for ( int x = start; x < end; x++ ) {
-
-      //the skirts
-      if ( y < 0 || y > (mWidth-1) || x < 0 || x > (mWidth-1) ) {
-
-        if ( x < 0 )		*verts++ = 0;
-        else if ( x > (mWidth-1) )	*verts++ = (mWidth-1)*getVertexSeperation();
-        else				*verts++ = x*getVertexSeperation();
-
-        *verts++ = -4096; //2048 below base sea floor height
-
-        if ( y < 0 )		        *verts++ = 0;
-        else if ( y > (mWidth-1) )	*verts++ = (mWidth-1)*getVertexSeperation();
-        else        				*verts++ = y*getVertexSeperation();
-
-
-        for ( Ogre::uint i = 0; i < 3; i++ )
-          *verts++ = 0;
-
-        float u = (float)(x) / (mWidth-1);
-        float v = (float)(y) / (mWidth-1);
-
-        //clamped, so shouldn't matter if > 1
-
-        *verts++ = u;
-        *verts++ = v;
-
-        if ( g_Terrain->isTextureFadingEnabled() ) {
-          *verts++ = u;
-          *verts++ = v;
-        }
-      } else {
-
-        assert(y*mWidth+x>=0&&y*mWidth+x<mWidth*mWidth);
-
-        //verts
-        *verts++ = x*getVertexSeperation();
-        *verts++ = getVertexHeight(x,y);
-        *verts++ = y*getVertexSeperation();
-
-        mMax = std::max(mMax, getVertexHeight(x,y));
-        mMin = std::min(mMin, getVertexHeight(x,y));
-
-        //normals
-        for ( Ogre::uint i = 0; i < 3; i++ )
-          *verts++ = getNormal(x,y,i);
-        //*verts++ = mInterface->getNormal((y*mWidth+x)*3+i);
-
-        const float u = (float)(x) / (mWidth-1);
-        const float v = (float)(y) / (mWidth-1);
-        assert(u>=0&&v>=0);
-        assert(u<=1&&v<=1);
-
-        *verts++ = u;
-        *verts++ = v;
-
-        if ( g_Terrain->isTextureFadingEnabled() ) {
-          *verts++ = u/2.0f + xUVOffset;
-          *verts++ = v/2.0f + yUVOffset;
-        }
-      }
-    }
-  }
-  mMainBuffer->unlock();
-}
-//----------------------------------------------
-void TerrainMesh::setBounds() {
-  mBounds.setExtents(0,mMin,0,
-                     (mWidth - 1) * getVertexSeperation(),
-                     mMax,
-                     (mWidth - 1) * getVertexSeperation());
-
-  mCenter = Ogre::Vector3( ( (mWidth  - 1) * getVertexSeperation() ) / 2,
-                           ( mMin + mMax ) / 2,
-                           ( (mWidth - 1) * getVertexSeperation() ) / 2);
-
-  mBoundingRadius = (mBounds.getMaximum() - mBounds.getMinimum()).length() / 2;
-}
-//----------------------------------------------
-void TerrainMesh::createVertexBuffer() {
-  using namespace Ogre;
-
-  size_t vw = mWidth;
-  if ( mUseSkirts ) vw += 2;
-
-  mVertexes = new VertexData();
-  mVertexes->vertexStart = 0;
-  mVertexes->vertexCount = vw*vw;// VERTEX_WIDTH;
-
-  VertexDeclaration* vertexDecl = mVertexes->vertexDeclaration;
-  size_t currOffset = 0;
-
-  vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_POSITION);
-  currOffset += VertexElement::getTypeSize(VET_FLOAT3);
-
-  vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_NORMAL);
-  currOffset += VertexElement::getTypeSize(VET_FLOAT3);
-
-
-  vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
-  currOffset += VertexElement::getTypeSize(VET_FLOAT2);
-
-  if ( g_Terrain->isTextureFadingEnabled() ) {
-    vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 1);
-    currOffset += VertexElement::getTypeSize(VET_FLOAT2);
+  void computeOffsets()
+  {
+    mXOffset = computeOffset(mX);
+    mYOffset = computeOffset(mY);
   }
 
-  mMainBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
-                                                                         vertexDecl->getVertexSize(0), // size of one whole vertex
-                                                                         mVertexes->vertexCount, // number of vertices
-                                                                         HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
-                                                                         false); // no shadow buffer
+  QuadData* mQuadData;
+  float mSegmentSize;
+  float mX, mY;
+  int mXOffset, mYOffset;
 
-  mVertexes->vertexBufferBinding->setBinding(MAIN_BINDING, mMainBuffer); //bind the data
+  /**
+   * @brief holds the amount to morph by, this decreases to 0 over a periord of time
+   * It is changed and used in the update() function
+   */
+  Ogre::Real mExtraMorphAmount, mExtraFadeAmount;
 
-  if ( g_Terrain->isMorhpingEnabled() )
-    vertexDecl->addElement(DELTA_BINDING, 0, VET_FLOAT1, VES_BLEND_WEIGHTS);
+  /**
+   * True if the fade pass has been added to the material.
+   */
+  bool mHasFadePass;
 
+  //Custom params used in terrian shaders.
+  static const size_t MORPH_CUSTOM_PARAM_ID = 77;
+  static const size_t FADE_CUSTOM_PARAM_ID = 78;
 
-}
-
-Ogre::HardwareVertexBufferSharedPtr TerrainMesh::createDeltaBuffer( ) {
-  size_t vw = mWidth;
-  if ( mUseSkirts ) vw += 2;
-
-  const size_t totalVerts = (vw * vw);
-  return Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
-                                                                        Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT1),
-                                                                        totalVerts,
-                                                                        Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
-                                                                        false); //no shadow buff
-
-}
-
-
-
-
-//----------------------------------------------
-#define SET_DELTA_AT(x, y, v)                       \
-if ( mUseSkirts )   pDeltas[( y + 1)*vw+ x + 1] = v; \
-else                pDeltas[( y)*vw+ x] = v;
-void TerrainMesh::calculateDeltaValues() {
-
-  using namespace Ogre;
-  size_t vw = mWidth;
-  if ( mUseSkirts ) vw += 2;
-
-  //must be using morphing to use this function
-  assert(g_Terrain->isMorhpingEnabled());
-
-  const size_t step = 2;
-
-  // Create a set of delta values
-  mDeltaBuffer = createDeltaBuffer();
-  float* pDeltas = static_cast<float*>(mDeltaBuffer->lock(HardwareBuffer::HBL_DISCARD));
-  memset(pDeltas, 0, (vw)*(vw) * sizeof(float));
-
-  return;
-
-  bool flag=false;
-  for ( size_t y = 0; y < mWidth-step; y += step ) {
-    for ( size_t x = 0; x < mWidth-step; x += step ) {
-      //create the diffrence between the full vertex if the vertex wasn't their
-
-      float bottom_left = getVertexHeight(x,y);
-      float bottom_right = getVertexHeight(x+step,y);
-
-      float top_left = getVertexHeight(x,y+step);
-      float top_right = getVertexHeight(x+step,y+step);
-
-      //const int vw = mWidth+2;
-      SET_DELTA_AT(x, y+1, (bottom_left+top_left)/2 - getVertexHeight(x, y+1)) //left
-        SET_DELTA_AT(x+2, y+1, (bottom_right+top_right)/2 - getVertexHeight(x+2, y+1)) //right
-
-        SET_DELTA_AT(x+1, y+2, (top_right+top_left)/2 - getVertexHeight(x+1, y+2)) //top
-        SET_DELTA_AT(x+1, y, (bottom_right+bottom_left)/2 - getVertexHeight(x+1, y)) //bottom
-
-        //this might not be correct
-        if ( !flag )
-          SET_DELTA_AT(x+1, y+1, (bottom_left+top_right)/2 - getVertexHeight(x+1, y+1)) //center
-            else
-              SET_DELTA_AT(x+1, y+1, (bottom_right+top_left)/2 - getVertexHeight(x+1, y+1)) //center
-
-                flag = !flag;
-    }
-    flag = !flag; //flip tries for next row
-  }
-
-  mDeltaBuffer->unlock();
-  mVertexes->vertexBufferBinding->setBinding(DELTA_BINDING,mDeltaBuffer);
-
-}
-#undef SET_DELTA_AT
-
-//----------------------------------------------
-void TerrainMesh::calculateIndexValues() {
-  using namespace Ogre;
-
-
-
-  size_t vw = mWidth-1;
-  if ( mUseSkirts ) vw += 2;
-
-  const size_t indexCount = (vw)*(vw)*6;
-
-  //need to manage allocation if not null
-  assert(mIndices==0);
-
-  mIndices = new IndexData();
-  mIndices->indexCount = indexCount;
-  mIndices->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
-                                                                                  HardwareIndexBuffer::IT_16BIT,
-                                                                                  indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
-
-  unsigned short* indices = static_cast<unsigned short*>(mIndices->indexBuffer->lock(0,
-                                                                                     mIndices->indexBuffer->getSizeInBytes(),
-                                                                                     HardwareBuffer::HBL_DISCARD));
-
-  bool flag = false;
-  Ogre::uint indNum = 0;
-  for ( Ogre::uint y = 0; y < (vw); y+=1 ) {
-    for ( Ogre::uint x = 0; x < (vw); x+=1 ) {
-
-      const int line1 = y * (vw+1) + x;
-      const int line2 = (y + 1) * (vw+1) + x;
-
-      if ( flag ) {
-        *indices++ = line1;
-        *indices++ = line2;
-        *indices++ = line1 + 1;
-
-        *indices++ = line1 + 1;
-        *indices++ = line2;
-        *indices++ = line2 + 1;
-      } else {
-        *indices++ = line1;
-        *indices++ = line2;
-        *indices++ = line2 + 1;
-
-        *indices++ = line1;
-        *indices++ = line2 + 1;
-        *indices++ = line1 + 1;
-      }
-      flag = !flag; //flip tris for next time
-
-      indNum+=6;
-    }
-    flag = !flag; //flip tries for next row
-  }
-  assert(indNum==indexCount);
-  mIndices->indexBuffer->unlock();
-  //return mIndices;
-}
+  //Terrain bindings
+  static const int MAIN_BINDING = 0;
+  static const int DELTA_BINDING = 1;
+};
diff --git a/terrain/cpp_terrainmesh.h b/terrain/cpp_terrainmesh.h
deleted file mode 100644
index 03ec0610fc..0000000000
--- a/terrain/cpp_terrainmesh.h
+++ /dev/null
@@ -1,343 +0,0 @@
-/**
- * @brief Terrain for one cell. Handles building, destroying and LOD morphing
- */
-#define QSDEBUG
-class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject
-{
- public:
-
-  TerrainMesh(QuadData* qd, float segSize, float startX, float startY,
-              const Ogre::Vector3 &pos,
-              int width, int depth, bool skirts,
-              Ogre::SceneNode *parent);
-
-  ~TerrainMesh()
-    {
-      destroy();
-
-      assert(node);
-
-      node->detachAllObjects();
-      node->getCreator()->destroySceneNode(node);
-    }
-
-  /**
-   * Can be called manually and can be called from the destuctor. This
-   * destroyes the mesh
-   */
-  // FIXME: We don't need this as a separate function.
-  void destroy();
-
-  /**
-   * @brief Checks if it needs to be split or unsplit and deals with
-   * the morph factor. time seconds since last frame
-   */
-  void update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist);
-
-  /**
-   * @todo Needs to work out what this does (if it does what it is meant to)
-   */
-  void visitRenderables(Renderable::Visitor* visitor,
-                        bool debugRenderables = false) {
-    visitor->visit(this, 0, false);
-  }
-
-  virtual const Ogre::MaterialPtr& getMaterial( void ) const {
-    return mMaterial;
-  }
-  //-----------------------------------------------------------------------
-  void getRenderOperation( Ogre::RenderOperation& op ) {
-    op.useIndexes = true;
-    op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
-    op.vertexData = mVertexes;
-    op.indexData = mIndices;
-  }
-
-  //-----------------------------------------------------------------------
-  void getWorldTransforms( Ogre::Matrix4* xform ) const {
-    *xform = mParentNode->_getFullTransform();
-  }
-  //-----------------------------------------------------------------------
-  const Ogre::Quaternion& getWorldOrientation(void) const {
-    return mParentNode->_getDerivedOrientation();
-  }
-  //-----------------------------------------------------------------------
-  const Ogre::Vector3& getWorldPosition(void) const {
-    return mParentNode->_getDerivedPosition();
-  }
-  //-----------------------------------------------------------------------
-
-  Ogre::Real getSquaredViewDepth(const Ogre::Camera *cam) const {
-    Ogre::Vector3 diff = mCenter - cam->getDerivedPosition();
-    // Use squared length to avoid square root
-    return diff.squaredLength();
-  }
-  //-----------------------------------------------------------------------
-
-  const Ogre::LightList& getLights(void) const {
-    if (mLightListDirty) {
-      getParentSceneNode()->getCreator()->_populateLightList(
-                                                             mCenter, this->getBoundingRadius(), mLightList);
-      mLightListDirty = false;
-    }
-    return mLightList;
-  }
-  //-----------------------------------------------------------------------
-  virtual const Ogre::String& getMovableType( void ) const {
-    static Ogre::String t = "MW_TERRAIN";
-    return t;
-  }
-  //-----------------------------------------------------------------------
-  void _updateRenderQueue( Ogre::RenderQueue* queue ) {
-    mLightListDirty = true;
-    queue->addRenderable(this, mRenderQueueID);
-  }
-
-  const Ogre::AxisAlignedBox& getBoundingBox( void ) const {
-    return mBounds;
-  };
-  //-----------------------------------------------------------------------
-  Ogre::Real getBoundingRadius(void) const {
-    return mBoundingRadius;
-  }
-  //-----------------------------------------------------------------------
-
-  /**
-   * @brief passes the morph factor to the custom vertex program
-   */
-  void _updateCustomGpuParameter(const Ogre::GpuProgramParameters::AutoConstantEntry& constantEntry,
-                                 Ogre::GpuProgramParameters* params) const;
-
-  /**
-   * @brief sets the mExtraMorphAmount so it slowly regains detail from the lowest morph factor
-   */
-  void justSplit();
-  /**
-   * @brief Does nothing
-   */
-  inline void justUnsplit(){
-  }
-
-  inline float getMax(){
-    return mMax;
-  }
-  inline float getMin(){
-    return mMin;
-  }
-
-
-  /**
-   * Gets how many vertexes wide this quad segment is. Should always be 2^n+1
-   * @return the vertex width of this quad segment
-   */
-  int getVertexWidth()
-  {
-    return (mQuadData->getVertexWidth()-1)*mSegmentSize+1;
-  }
-
-  /**
-   * @brief gets a vertex assuming that x = 0, y = 0 addresses the start of the quad
-   */
-  float getVertex(int x, int y)
-  {
-#ifdef QSDEBUG
-    {
-      const int vw = getVertexWidth();
-      assert(x<vw);
-    }
-#endif
-    return mQuadData->getVertex((mYOffset + y)*mQuadData->getVertexWidth()+(mXOffset+x));
-  }
-
-  float getNormal(int x, int y, int z)
-  {
-    assert(z>=0&&z<3);
-    return mQuadData->getNormal(((mYOffset + y)*mQuadData->getVertexWidth()+(mXOffset+x))*3+z);
-  }
-
- private:
-
-  void createMaterial()
-  {
-    assert(mSegmentSize>0);
-    if ( mSegmentSize == 1 ) //we can use the top level material
-      {
-        mMaterial = mQuadData->getMaterial();
-        return;
-      }
-
-    if ( mQuadData->getTexture().length() )
-      assert(0&&"NOT IMPLEMENTED");
-
-    const std::vector<int>& tref = mQuadData->getTextureIndexRef();
-    const int indexSize = sqrt(tref.size());
-    const int cellIndexSize = indexSize - 2;
-
-    //plus 1 to take into account border
-    const int xoff = float(cellIndexSize) * mX;
-    const int yoff = float(cellIndexSize) * mY;
-    const int size = float(cellIndexSize) * mSegmentSize;
-
-    std::vector<int> ti;
-
-    ti.resize((size+2)*(size+2), -1);
-
-    for ( int y = 0; y < size+2; ++y ){
-      for ( int x = 0; x < size+2; ++x ){
-        ti[(y)*(size+2)+(x)] = tref.at((y+yoff)*(indexSize)+(x+xoff));
-      }
-    }
-
-    mMaterial = g_materialGen->getAlphaMat
-      (ti,size,
-       1, 1.0f/size,
-       mQuadData->getUsedResourcesRef());
-  }
-
-  inline bool hasParentTexture() const{
-    return mQuadData->hasParentTexture();
-  }
-  inline const std::string& getParentTexture() const{
-    return mQuadData->getParentTexture();
-  }
-  inline int getVertexSeperation(){
-    return mQuadData->getVertexSeperation();
-  }
-
-  inline float getSegmentSize(){
-    return mSegmentSize;
-  }
-  inline float getStartX(){
-    return mX;
-  }
-  inline float getStartY(){
-    return mY;
-  }
-
-  /**
-   * @brief Adds another pass to the material to fade in/out the material from a higher level
-   */
-  void addFadePass();
-  /**
-   * @brief removes the last pass from the material. Assumed to be the fade pass
-   */
-  void removeFadePass();
-
-  /**
-   * @return the height at the given vertex
-   */
-  float getVertexHeight(int x, int y);
-
-  /**
-   * Inits the vertex stuff
-   */
-  void createVertexBuffer();
-
-  /**
-   * @brief fills the vertex buffer with data
-   * @todo I don't think tex co-ords are right
-   */
-  void calculateVetexValues();
-
-  /**
-   * @brief returns a a new Vertex Buffer ready for input
-   * @remarks Unlike other terrain libs, this isn't 0s when it is returend
-   */
-  Ogre::HardwareVertexBufferSharedPtr createDeltaBuffer( );
-
-  /**
-   * @brief DOESN'T WORK FULLY
-   * @todo fix
-   */
-  void calculateDeltaValues();
-  /**
-   * @brief gets the position of a vertex. It will not interpolate
-   */
-  Ogre::Vector3 getVertexPosition(int x, int y);
-
-  /**
-   * @brief gets the indicies for the vertex data.
-   */
-  void calculateIndexValues();
-
-  /*
-   * Sets the bounds on the renderable. This requires that mMin/mMax
-   * have been set. They are set in createVertexData. This may look
-   * as though it is done twice, as it is also done in MeshInterface,
-   * however, there is no guarentee that the mesh sizes are the same
-   */
-  void setBounds();
-
-  Ogre::SceneNode* node;
-
-  const int mWidth;
-  const bool mUseSkirts;
-
-  ///true if the land has been built
-  bool mBuilt;
-
-  int mDepth;
-
-  Ogre::MaterialPtr mMaterial;
-  Ogre::ManualObject* mObject;
-
-  Ogre::VertexData* mVertexes;
-  Ogre::IndexData* mIndices;
-  Ogre::HardwareVertexBufferSharedPtr mMainBuffer;
-  Ogre::HardwareVertexBufferSharedPtr mDeltaBuffer;
-
-  mutable bool mLightListDirty;
-
-  Ogre::Real mBoundingRadius;
-  Ogre::AxisAlignedBox mBounds;
-  Ogre::Vector3 mCenter;
-
-  Ogre::Real mLODMorphFactor, mTextureFadeFactor;
-
-  /** Max and min heights of the mesh */
-  float mMin, mMax;
-
-  int computeOffset(float x)
-  {
-#ifdef QSDEBUG
-    {
-      //check it is a valid position
-      const int start = (mQuadData->getVertexWidth()-1)*x;
-      const int vw = getVertexWidth()-1;
-      assert(vw>0);
-      assert((start%vw)==0);
-    }
-#endif
-    return float((mQuadData->getVertexWidth()-1))*x;
-  }
-
-  void computeOffsets()
-  {
-    mXOffset = computeOffset(mX);
-    mYOffset = computeOffset(mY);
-  }
-
-  QuadData* mQuadData;
-  float mSegmentSize;
-  float mX, mY;
-  int mXOffset, mYOffset;
-
-  /**
-   * @brief holds the amount to morph by, this decreases to 0 over a periord of time
-   * It is changed and used in the update() function
-   */
-  Ogre::Real mExtraMorphAmount, mExtraFadeAmount;
-
-  /**
-   * True if the fade pass has been added to the material.
-   */
-  bool mHasFadePass;
-
-  //Custom params used in terrian shaders.
-  static const size_t MORPH_CUSTOM_PARAM_ID = 77;
-  static const size_t FADE_CUSTOM_PARAM_ID = 78;
-
-  //Terrain bindings
-  static const int MAIN_BINDING = 0;
-  static const int DELTA_BINDING = 1;
-};
diff --git a/terrain/cpp_terrainmesh2.cpp b/terrain/cpp_terrainmesh2.cpp
new file mode 100644
index 0000000000..caa5f45581
--- /dev/null
+++ b/terrain/cpp_terrainmesh2.cpp
@@ -0,0 +1,495 @@
+TerrainMesh::TerrainMesh(QuadData* qd, float segSize, float startX, float startY,
+                         const Ogre::Vector3 &pos,
+                         int width, int depth, bool skirts,
+                         Ogre::SceneNode *parent)
+  : Ogre::Renderable(),
+    Ogre::MovableObject(),
+    mWidth(width),
+    mUseSkirts(skirts),
+    mBuilt(false),
+    mDepth(depth),
+    mVertexes(0),
+    mIndices(0),
+    mLODMorphFactor(0),
+    mTextureFadeFactor(0),
+    mMin(30000),
+    mMax(-30000),
+    mExtraMorphAmount(0),
+    mHasFadePass(false),
+    mQuadData(qd),
+    mSegmentSize(segSize),
+    mX(startX),
+    mY(startY)
+{
+  // From QuadSegment()
+  assert(qd);
+  assert(segSize>0&&segSize<=1);
+  assert(mY>=0&&mY<=1);
+  assert(mX>=0&&mY<=1);
+
+#ifdef QSDEBUG
+  {
+    //check sizes
+    const float qw = mQuadData->getVertexWidth()-1;
+    const float fsw = qw*segSize;
+    const int isw = (int)fsw;
+    assert(fsw==isw);
+  }
+#endif
+
+  //precalc offsets, as getVertex/getNormal get called a lot (1000s of times)
+  computeOffsets();
+
+  // From Quad
+  node = parent->createChildSceneNode(pos);
+
+  // From create()
+  createVertexBuffer();
+  calculateVetexValues();
+  calculateIndexValues();
+  setBounds();
+
+  node->attachObject(this);
+
+  createMaterial();
+
+  if ( g_heightMap->isMorphingEnabled() && mDepth != g_heightMap->getMaxDepth() ) {
+    Ogre::Technique* tech = getMaterial()->getTechnique(0);
+    for ( size_t i = 0; i < tech->getNumPasses(); ++i ) {
+      assert(g_heightMap->isMorphingEnabled());
+      tech->getPass(i)->setVertexProgram(MORPH_VERTEX_PROGRAM);
+    }
+  }
+
+  if ( g_heightMap->isMorphingEnabled() )
+    calculateDeltaValues();
+
+  mBuilt = true;
+}
+
+void TerrainMesh::destroy() {
+  if ( !mBuilt ) return;
+
+  //deleting null values is fine iirc
+  delete mIndices;
+
+#   if ENABLED_CRASHING == 1
+  {
+    delete mVertexes;
+  }
+#   else
+  {
+    if ( mDepth != g_heightMap->getMaxDepth() ){
+      delete mVertexes;
+    }
+  }
+#   endif
+
+  mBuilt = false;
+}
+//----------------------------------------------
+void TerrainMesh::update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist)
+{
+  TRACE("TerrainMesh::update");
+  //if ( USE_MORPH ){
+
+  //as aprocesh mUnsplitDistance, lower detail
+  if ( camDist > morphDist && mDepth > 1 ) {
+    mLODMorphFactor = 1 - (usplitDist - camDist)/(usplitDist-morphDist);
+  } else
+    mLODMorphFactor = 0;
+  mTextureFadeFactor = mLODMorphFactor;
+
+
+  //on an split, it sets the extra morph amount to 1, we then ensure this ends up at 0... slowly
+  if ( mExtraMorphAmount > 0 ) {
+    mLODMorphFactor += mExtraMorphAmount;
+    mExtraMorphAmount -= (time/g_heightMap->getMorphSpeed()); //decrease slowly
+  }
+  if ( mExtraFadeAmount > 0 ) {
+    mTextureFadeFactor += mExtraFadeAmount;
+    mExtraFadeAmount -= (time/g_heightMap->getTextureFadeSpeed());
+  }
+
+  //Ensure within valid bounds
+  if ( mLODMorphFactor > 1 )
+    mLODMorphFactor = 1;
+  else if ( mLODMorphFactor < 0 )
+    mLODMorphFactor = 0;
+
+  if ( mTextureFadeFactor > 1 )
+    mTextureFadeFactor = 1;
+  else if ( mTextureFadeFactor < 0 )
+    mTextureFadeFactor = 0;
+
+  //}
+
+  //remove pass. Keep outside in case terrain fading is removed while it is active
+  if ( mHasFadePass && mTextureFadeFactor == 0 ) {
+    removeFadePass();
+  } else if ( g_heightMap->isTextureFadingEnabled() &&
+              !mHasFadePass &&
+              mTextureFadeFactor > 0 &&
+              hasParentTexture() ) {
+    addFadePass();
+  }
+
+}
+//----------------------------------------------
+void TerrainMesh::addFadePass() {
+  assert(mHasFadePass==false);
+
+  if ( mDepth == g_heightMap->getMaxDepth() ) return;
+
+
+  mHasFadePass = true;
+  Ogre::MaterialPtr mat = getMaterial();
+  Ogre::Pass* newPass = mat->getTechnique(0)->createPass();
+  newPass->setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA);
+
+  //set fragment program
+  assert(g_heightMap->isTextureFadingEnabled());
+  newPass->setFragmentProgram(FADE_FRAGMENT_PROGRAM);
+
+  if ( g_heightMap->isMorphingEnabled() && mDepth != g_heightMap->getMaxDepth() ) {
+    assert(g_heightMap->isMorphingEnabled());
+    newPass->setVertexProgram(MORPH_VERTEX_PROGRAM);
+  }
+
+
+  //set texture to be used
+  newPass->createTextureUnitState(getParentTexture(), 1);
+}
+//----------------------------------------------
+void TerrainMesh::removeFadePass() {
+  assert(mHasFadePass==true);
+  mHasFadePass = false;
+  Ogre::MaterialPtr mat = getMaterial();
+  Ogre::Technique* tech = mat->getTechnique(0);
+
+  tech->removePass(tech->getNumPasses()-1);
+}
+//----------------------------------------------
+void TerrainMesh::justSplit() {
+  mExtraMorphAmount = 1;
+  mLODMorphFactor = 1;
+  mTextureFadeFactor = 1;
+  mExtraFadeAmount = 1;
+
+  if ( g_heightMap->isTextureFadingEnabled() && hasParentTexture() )
+    addFadePass();
+}
+
+//----------------------------------------------
+void TerrainMesh::_updateCustomGpuParameter(
+                                            const GpuProgramParameters::AutoConstantEntry& constantEntry,
+                                            GpuProgramParameters* params) const {
+  using namespace Ogre;
+  if (constantEntry.data == MORPH_CUSTOM_PARAM_ID)
+    params->_writeRawConstant(constantEntry.physicalIndex, mLODMorphFactor);
+  else if ( constantEntry.data == FADE_CUSTOM_PARAM_ID )
+    params->_writeRawConstant(constantEntry.physicalIndex, mTextureFadeFactor);
+  else
+    Renderable::_updateCustomGpuParameter(constantEntry, params);
+
+
+}
+//----------------------------------------------
+float TerrainMesh::getVertexHeight(int x, int y) {
+  return getVertex(x,y);
+}
+//----------------------------------------------
+Ogre::Vector3 TerrainMesh::getVertexPosition(int x, int y) {
+  return Ogre::Vector3(x*getVertexSeperation(), getVertexHeight(x,y) , y*getVertexSeperation());
+}
+//----------------------------------------------
+void TerrainMesh::calculateVetexValues() {
+  using namespace Ogre;
+
+  //get the texture offsets for the higher uv
+  float xUVOffset = 0;
+  float yUVOffset = 0;
+
+  if ( g_heightMap->isTextureFadingEnabled() ) {
+    assert(0);
+  }
+  /*
+    switch (mInterface->getLocation()) {
+    case Quad::QL_NW :
+    yUVOffset = 32.0f/64.0f;
+    break;
+    case Quad::QL_NE:
+    yUVOffset = 32.0f/64.0f;
+    xUVOffset = 32.0f/64.0f;
+    break;
+    case Quad::QL_SE:
+    xUVOffset = 32.0f/64.0f;
+    break;
+    default:
+    break;
+    }
+  */
+
+  int start = 0;
+  int end = mWidth;
+
+  if ( mUseSkirts ) {
+    --start;
+    ++end;
+  }
+
+  float* verts = static_cast<float*>(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD));
+  for ( int y = start; y < end; y++ ) {
+    for ( int x = start; x < end; x++ ) {
+
+      //the skirts
+      if ( y < 0 || y > (mWidth-1) || x < 0 || x > (mWidth-1) ) {
+
+        if ( x < 0 )		*verts++ = 0;
+        else if ( x > (mWidth-1) )	*verts++ = (mWidth-1)*getVertexSeperation();
+        else				*verts++ = x*getVertexSeperation();
+
+        *verts++ = -4096; //2048 below base sea floor height
+
+        if ( y < 0 )		        *verts++ = 0;
+        else if ( y > (mWidth-1) )	*verts++ = (mWidth-1)*getVertexSeperation();
+        else        				*verts++ = y*getVertexSeperation();
+
+
+        for ( Ogre::uint i = 0; i < 3; i++ )
+          *verts++ = 0;
+
+        float u = (float)(x) / (mWidth-1);
+        float v = (float)(y) / (mWidth-1);
+
+        //clamped, so shouldn't matter if > 1
+
+        *verts++ = u;
+        *verts++ = v;
+
+        if ( g_heightMap->isTextureFadingEnabled() ) {
+          *verts++ = u;
+          *verts++ = v;
+        }
+      } else {
+
+        assert(y*mWidth+x>=0&&y*mWidth+x<mWidth*mWidth);
+
+        //verts
+        *verts++ = x*getVertexSeperation();
+        *verts++ = getVertexHeight(x,y);
+        *verts++ = y*getVertexSeperation();
+
+        mMax = std::max(mMax, getVertexHeight(x,y));
+        mMin = std::min(mMin, getVertexHeight(x,y));
+
+        //normals
+        for ( Ogre::uint i = 0; i < 3; i++ )
+          *verts++ = getNormal(x,y,i);
+        //*verts++ = mInterface->getNormal((y*mWidth+x)*3+i);
+
+        const float u = (float)(x) / (mWidth-1);
+        const float v = (float)(y) / (mWidth-1);
+        assert(u>=0&&v>=0);
+        assert(u<=1&&v<=1);
+
+        *verts++ = u;
+        *verts++ = v;
+
+        if ( g_heightMap->isTextureFadingEnabled() ) {
+          *verts++ = u/2.0f + xUVOffset;
+          *verts++ = v/2.0f + yUVOffset;
+        }
+      }
+    }
+  }
+  mMainBuffer->unlock();
+}
+//----------------------------------------------
+void TerrainMesh::setBounds() {
+  mBounds.setExtents(0,mMin,0,
+                     (mWidth - 1) * getVertexSeperation(),
+                     mMax,
+                     (mWidth - 1) * getVertexSeperation());
+
+  mCenter = Ogre::Vector3( ( (mWidth  - 1) * getVertexSeperation() ) / 2,
+                           ( mMin + mMax ) / 2,
+                           ( (mWidth - 1) * getVertexSeperation() ) / 2);
+
+  mBoundingRadius = (mBounds.getMaximum() - mBounds.getMinimum()).length() / 2;
+}
+//----------------------------------------------
+void TerrainMesh::createVertexBuffer() {
+  using namespace Ogre;
+
+  size_t vw = mWidth;
+  if ( mUseSkirts ) vw += 2;
+
+  mVertexes = new VertexData();
+  mVertexes->vertexStart = 0;
+  mVertexes->vertexCount = vw*vw;// VERTEX_WIDTH;
+
+  VertexDeclaration* vertexDecl = mVertexes->vertexDeclaration;
+  size_t currOffset = 0;
+
+  vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_POSITION);
+  currOffset += VertexElement::getTypeSize(VET_FLOAT3);
+
+  vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_NORMAL);
+  currOffset += VertexElement::getTypeSize(VET_FLOAT3);
+
+
+  vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
+  currOffset += VertexElement::getTypeSize(VET_FLOAT2);
+
+  if ( g_heightMap->isTextureFadingEnabled() ) {
+    vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 1);
+    currOffset += VertexElement::getTypeSize(VET_FLOAT2);
+  }
+
+  mMainBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
+                                                                         vertexDecl->getVertexSize(0), // size of one whole vertex
+                                                                         mVertexes->vertexCount, // number of vertices
+                                                                         HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
+                                                                         false); // no shadow buffer
+
+  mVertexes->vertexBufferBinding->setBinding(MAIN_BINDING, mMainBuffer); //bind the data
+
+  if ( g_heightMap->isMorphingEnabled() )
+    vertexDecl->addElement(DELTA_BINDING, 0, VET_FLOAT1, VES_BLEND_WEIGHTS);
+
+
+}
+
+Ogre::HardwareVertexBufferSharedPtr TerrainMesh::createDeltaBuffer( ) {
+  size_t vw = mWidth;
+  if ( mUseSkirts ) vw += 2;
+
+  const size_t totalVerts = (vw * vw);
+  return Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
+                                                                        Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT1),
+                                                                        totalVerts,
+                                                                        Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
+                                                                        false); //no shadow buff
+
+}
+
+
+
+
+//----------------------------------------------
+#define SET_DELTA_AT(x, y, v)                       \
+if ( mUseSkirts )   pDeltas[( y + 1)*vw+ x + 1] = v; \
+else                pDeltas[( y)*vw+ x] = v;
+void TerrainMesh::calculateDeltaValues() {
+
+  using namespace Ogre;
+  size_t vw = mWidth;
+  if ( mUseSkirts ) vw += 2;
+
+  //must be using morphing to use this function
+  assert(g_heightMap->isMorphingEnabled());
+
+  const size_t step = 2;
+
+  // Create a set of delta values
+  mDeltaBuffer = createDeltaBuffer();
+  float* pDeltas = static_cast<float*>(mDeltaBuffer->lock(HardwareBuffer::HBL_DISCARD));
+  memset(pDeltas, 0, (vw)*(vw) * sizeof(float));
+
+  return;
+
+  bool flag=false;
+  for ( size_t y = 0; y < mWidth-step; y += step ) {
+    for ( size_t x = 0; x < mWidth-step; x += step ) {
+      //create the diffrence between the full vertex if the vertex wasn't their
+
+      float bottom_left = getVertexHeight(x,y);
+      float bottom_right = getVertexHeight(x+step,y);
+
+      float top_left = getVertexHeight(x,y+step);
+      float top_right = getVertexHeight(x+step,y+step);
+
+      //const int vw = mWidth+2;
+      SET_DELTA_AT(x, y+1, (bottom_left+top_left)/2 - getVertexHeight(x, y+1)) //left
+        SET_DELTA_AT(x+2, y+1, (bottom_right+top_right)/2 - getVertexHeight(x+2, y+1)) //right
+
+        SET_DELTA_AT(x+1, y+2, (top_right+top_left)/2 - getVertexHeight(x+1, y+2)) //top
+        SET_DELTA_AT(x+1, y, (bottom_right+bottom_left)/2 - getVertexHeight(x+1, y)) //bottom
+
+        //this might not be correct
+        if ( !flag )
+          SET_DELTA_AT(x+1, y+1, (bottom_left+top_right)/2 - getVertexHeight(x+1, y+1)) //center
+            else
+              SET_DELTA_AT(x+1, y+1, (bottom_right+top_left)/2 - getVertexHeight(x+1, y+1)) //center
+
+                flag = !flag;
+    }
+    flag = !flag; //flip tries for next row
+  }
+
+  mDeltaBuffer->unlock();
+  mVertexes->vertexBufferBinding->setBinding(DELTA_BINDING,mDeltaBuffer);
+
+}
+#undef SET_DELTA_AT
+
+//----------------------------------------------
+void TerrainMesh::calculateIndexValues() {
+  using namespace Ogre;
+
+
+
+  size_t vw = mWidth-1;
+  if ( mUseSkirts ) vw += 2;
+
+  const size_t indexCount = (vw)*(vw)*6;
+
+  //need to manage allocation if not null
+  assert(mIndices==0);
+
+  mIndices = new IndexData();
+  mIndices->indexCount = indexCount;
+  mIndices->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
+                                                                                  HardwareIndexBuffer::IT_16BIT,
+                                                                                  indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
+
+  unsigned short* indices = static_cast<unsigned short*>(mIndices->indexBuffer->lock(0,
+                                                                                     mIndices->indexBuffer->getSizeInBytes(),
+                                                                                     HardwareBuffer::HBL_DISCARD));
+
+  bool flag = false;
+  Ogre::uint indNum = 0;
+  for ( Ogre::uint y = 0; y < (vw); y+=1 ) {
+    for ( Ogre::uint x = 0; x < (vw); x+=1 ) {
+
+      const int line1 = y * (vw+1) + x;
+      const int line2 = (y + 1) * (vw+1) + x;
+
+      if ( flag ) {
+        *indices++ = line1;
+        *indices++ = line2;
+        *indices++ = line1 + 1;
+
+        *indices++ = line1 + 1;
+        *indices++ = line2;
+        *indices++ = line2 + 1;
+      } else {
+        *indices++ = line1;
+        *indices++ = line2;
+        *indices++ = line2 + 1;
+
+        *indices++ = line1;
+        *indices++ = line2 + 1;
+        *indices++ = line1 + 1;
+      }
+      flag = !flag; //flip tris for next time
+
+      indNum+=6;
+    }
+    flag = !flag; //flip tries for next row
+  }
+  assert(indNum==indexCount);
+  mIndices->indexBuffer->unlock();
+  //return mIndices;
+}