? CMakeCache.txt
? CMakeFiles
? Makefile
? cmake_install.cmake
? forest20080223.diff
? examples/CMakeFiles
? examples/Makefile
? examples/cmake_install.cmake
? examples/bin/release/Example1
? examples/bin/release/Example2
? examples/bin/release/Example3
? examples/bin/release/Example4
? examples/bin/release/Example5
? examples/bin/release/Example6
? examples/bin/release/Example7
? examples/bin/release/Impostor.HKSHDSOJOKUYFPGCRGIKVPHHWDUCIZTF.128.png
? examples/bin/release/Ogre.log
? examples/bin/release/ogre.cfg
? examples/source/CMakeFiles
? examples/source/Makefile
? examples/source/bin
? examples/source/cmake_install.cmake
? source/CMakeFiles
? source/Makefile
? source/cmake_install.cmake
Index: examples/source/Example1.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/examples/source/Example1.cpp,v
retrieving revision 1.5
diff -b -U3 -r1.5 Example1.cpp
--- examples/source/Example1.cpp	3 Feb 2008 00:02:44 -0000	1.5
+++ examples/source/Example1.cpp	23 Feb 2008 12:20:48 -0000
@@ -30,6 +30,7 @@
 //height easy. You can use it in your games/applications if you want, although if you're using a
 //collision/physics library with a faster alternate, you may use that instead.
 
+using namespace PagedGeometry;
 
 //Demo world class
 //[NOTE] The main PagedGeometry-related sections of this class are load() and
@@ -66,7 +67,7 @@
 	Radian camPitch, camYaw;
 
 	//Pointers to PagedGeometry class instances:
-	PagedGeometry *trees;
+	::PagedGeometry::PagedGeometry *trees;
 };
 
 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
@@ -193,7 +194,7 @@
 
 	//-------------------------------------- LOAD TREES --------------------------------------
 	//Create and configure a new PagedGeometry instance
-	trees = new PagedGeometry();
+	trees = new ::PagedGeometry::PagedGeometry();
 	trees->setCamera(camera);	//Set the camera so PagedGeometry knows how to calculate LODs
 	trees->setPageSize(80);	//Set the size of each page of geometry
 	trees->setInfinite();		//Use infinite paging mode
Index: examples/source/Example2.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/examples/source/Example2.cpp,v
retrieving revision 1.6
diff -b -U3 -r1.6 Example2.cpp
--- examples/source/Example2.cpp	3 Feb 2008 00:02:44 -0000	1.6
+++ examples/source/Example2.cpp	23 Feb 2008 12:20:48 -0000
@@ -30,6 +30,8 @@
 //height easy. You can use it in your games/applications if you want, although if you're using a
 //collision/physics library with a faster alternate, you may use that instead.
 
+using namespace PagedGeometry;
+
 
 //Demo world class
 //[NOTE] The main PagedGeometry-related sections of this class are load() and
@@ -66,7 +68,7 @@
 	Radian camPitch, camYaw;
 
 	//Pointers to PagedGeometry class instances:
-	PagedGeometry *trees;
+	::PagedGeometry::PagedGeometry *trees;
 };
 
 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
@@ -193,7 +195,7 @@
 
 	//-------------------------------------- LOAD TREES --------------------------------------
 	//Create and configure a new PagedGeometry instance
-	trees = new PagedGeometry();
+	trees = new ::PagedGeometry::PagedGeometry();
 	trees->setCamera(camera);	//Set the camera so PagedGeometry knows how to calculate LODs
 	trees->setPageSize(80);	//Set the size of each page of geometry
 	trees->setInfinite();		//Use infinite paging mode
Index: examples/source/Example3.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/examples/source/Example3.cpp,v
retrieving revision 1.6
diff -b -U3 -r1.6 Example3.cpp
--- examples/source/Example3.cpp	3 Feb 2008 00:02:45 -0000	1.6
+++ examples/source/Example3.cpp	23 Feb 2008 12:20:48 -0000
@@ -30,6 +30,7 @@
 //height easy. You can use it in your games/applications if you want, although if you're using a
 //collision/physics library with a faster alternate, you may use that instead.
 
+using namespace PagedGeometry;
 
 //Demo world class
 //[NOTE] The main PagedGeometry-related sections of this class are load() and
@@ -66,7 +67,7 @@
 	Radian camPitch, camYaw;
 
 	//Pointers to PagedGeometry class instances:
-	PagedGeometry *trees, *bushes;
+	::PagedGeometry::PagedGeometry *trees, *bushes;
 };
 
 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
@@ -193,7 +194,7 @@
 	
 	//-------------------------------------- LOAD TREES --------------------------------------
 	//Create and configure a new PagedGeometry instance for trees
-	trees = new PagedGeometry(camera, 80);
+	trees = new ::PagedGeometry::PagedGeometry(camera, 80);
 	trees->addDetailLevel<BatchPage>(150, 50);
 	trees->addDetailLevel<ImpostorPage>(500, 50);
 
@@ -223,7 +224,7 @@
 
 	//-------------------------------------- LOAD BUSHES --------------------------------------
 	//Create and configure a new PagedGeometry instance for bushes
-	bushes = new PagedGeometry(camera, 50);
+	bushes = new ::PagedGeometry::PagedGeometry(camera, 50);
 	bushes->addDetailLevel<BatchPage>(80, 50);
 
 	//Create a new TreeLoader2D object for the bushes
Index: examples/source/Example4.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/examples/source/Example4.cpp,v
retrieving revision 1.8
diff -b -U3 -r1.8 Example4.cpp
--- examples/source/Example4.cpp	3 Feb 2008 00:36:20 -0000	1.8
+++ examples/source/Example4.cpp	23 Feb 2008 12:20:48 -0000
@@ -28,6 +28,7 @@
 //height easy. You can use it in your games/applications if you want, although if you're using a
 //collision/physics library with a faster alternate, you may use that instead.
 
+using namespace PagedGeometry;
 
 //Demo world class
 //[NOTE] The main PagedGeometry-related sections of this class are load() and
@@ -64,8 +65,8 @@
 	Radian camPitch, camYaw;
 
 	//Pointers to PagedGeometry class instances:
-	PagedGeometry *grass;
-	GrassLoader *grassLoader;
+	::PagedGeometry::PagedGeometry *grass;
+	GrassLoader<GrassLayer> *grassLoader;
 };
 
 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
@@ -192,11 +193,11 @@
 
 	//-------------------------------------- LOAD GRASS --------------------------------------
 	//Create and configure a new PagedGeometry instance for grass
-	grass = new PagedGeometry(camera, 50);
+	grass = new ::PagedGeometry::PagedGeometry(camera, 50);
 	grass->addDetailLevel<GrassPage>(150);
 
 	//Create a GrassLoader object
-	grassLoader = new GrassLoader(grass);
+	grassLoader = new GrassLoader<GrassLayer>(grass);
 	grass->setPageLoader(grassLoader);	//Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance
 
 	//Supply a height function to GrassLoader so it can calculate grass Y values
Index: examples/source/Example5.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/examples/source/Example5.cpp,v
retrieving revision 1.7
diff -b -U3 -r1.7 Example5.cpp
--- examples/source/Example5.cpp	3 Feb 2008 00:02:45 -0000	1.7
+++ examples/source/Example5.cpp	23 Feb 2008 12:20:48 -0000
@@ -30,6 +30,7 @@
 //height easy. You can use it in your games/applications if you want, although if you're using a
 //collision/physics library with a faster alternate, you may use that instead.
 
+using namespace PagedGeometry;
 
 //Demo world class
 //[NOTE] The main PagedGeometry-related sections of this class are load() and
@@ -66,7 +67,7 @@
 	Radian camPitch, camYaw;
 
 	//Pointers to PagedGeometry class instances:
-	PagedGeometry *trees;
+	::PagedGeometry::PagedGeometry *trees;
 	TreeLoader2D *treeLoader;
 
 	//The tree entity being used in this demo (stored for later use when dynamically adding trees)
@@ -197,7 +198,7 @@
 
 	//-------------------------------------- LOAD TREES --------------------------------------
 	//Create and configure a new PagedGeometry instance
-	trees = new PagedGeometry();
+	trees = new ::PagedGeometry::PagedGeometry();
 	trees->setCamera(camera);	//Set the camera so PagedGeometry knows how to calculate LODs
 	trees->setPageSize(80);	//Set the size of each page of geometry
 	trees->setInfinite();		//Use infinite paging mode
Index: examples/source/Example6.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/examples/source/Example6.cpp,v
retrieving revision 1.5
diff -b -U3 -r1.5 Example6.cpp
--- examples/source/Example6.cpp	3 Feb 2008 00:02:45 -0000	1.5
+++ examples/source/Example6.cpp	23 Feb 2008 12:20:49 -0000
@@ -30,6 +30,7 @@
 //height easy. You can use it in your games/applications if you want, although if you're using a
 //collision/physics library with a faster alternate, you may use that instead.
 
+using namespace PagedGeometry;
 
 //Demo world class
 //[NOTE] The main PagedGeometry-related sections of this class are load() and
@@ -66,7 +67,7 @@
 	Radian camPitch, camYaw;
 
 	//Pointers to PagedGeometry class instances:
-	PagedGeometry *trees;
+	::PagedGeometry::PagedGeometry *trees;
 };
 
 
@@ -272,7 +273,7 @@
 
 	//-------------------------------------- LOAD TREES --------------------------------------
 	//Create and configure a new PagedGeometry instance
-	trees = new PagedGeometry();
+	trees = new ::PagedGeometry::PagedGeometry();
 	trees->setCamera(camera);	//Set the camera so PagedGeometry knows how to calculate LODs
 	trees->setPageSize(100);	//Set the size of each page of geometry
 	trees->setBounds(TBounds(0, 0, 1500, 1500));	//Force a boundary on the trees, since ProceduralLoader is infinite
Index: examples/source/Example7.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/examples/source/Example7.cpp,v
retrieving revision 1.8
diff -b -U3 -r1.8 Example7.cpp
--- examples/source/Example7.cpp	3 Feb 2008 00:02:45 -0000	1.8
+++ examples/source/Example7.cpp	23 Feb 2008 12:20:49 -0000
@@ -31,6 +31,7 @@
 //height easy. You can use it in your games/applications if you want, although if you're using a
 //collision/physics library with a faster alternate, you may use that instead.
 
+using namespace PagedGeometry;
 
 //Demo world class
 //[NOTE] The main PagedGeometry-related sections of this class are load() and
@@ -67,8 +68,8 @@
 	Radian camPitch, camYaw;
 
 	//Pointers to PagedGeometry class instances:
-	PagedGeometry *trees, *grass;
-	GrassLoader *grassLoader;
+	::PagedGeometry::PagedGeometry *trees, *grass;
+	GrassLoader<GrassLayer> *grassLoader;
 };
 
 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
@@ -194,11 +195,11 @@
 
 	//-------------------------------------- LOAD GRASS --------------------------------------
 	//Create and configure a new PagedGeometry instance for grass
-	grass = new PagedGeometry(camera, 50);
+	grass = new ::PagedGeometry::PagedGeometry(camera, 50);
 	grass->addDetailLevel<GrassPage>(100);
 
 	//Create a GrassLoader object
-	grassLoader = new GrassLoader(grass);
+	grassLoader = new GrassLoader<GrassLayer>(grass);
 	grass->setPageLoader(grassLoader);	//Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance
 
 	//Supply a height function to GrassLoader so it can calculate grass Y values
@@ -235,7 +236,7 @@
 
 	//-------------------------------------- LOAD TREES --------------------------------------
 	//Create and configure a new PagedGeometry instance
-	trees = new PagedGeometry();
+	trees = new ::PagedGeometry::PagedGeometry();
 	trees->setCamera(camera);	//Set the camera so PagedGeometry knows how to calculate LODs
 	trees->setPageSize(80);	//Set the size of each page of geometry
 	trees->setInfinite();		//Use infinite paging mode
Index: examples/source/HeightFunction.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/examples/source/HeightFunction.h,v
retrieving revision 1.4
diff -b -U3 -r1.4 HeightFunction.h
Index: include/BatchPage.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/include/BatchPage.h,v
retrieving revision 1.12
diff -b -U3 -r1.12 BatchPage.h
--- include/BatchPage.h	4 Oct 2007 17:11:53 -0000	1.12
+++ include/BatchPage.h	23 Feb 2008 12:20:49 -0000
@@ -18,9 +18,10 @@
 #include "PagedGeometry.h"
 #include "BatchedGeometry.h"
 
-#include "OgrePrerequisites.h"
-#include "OgreStringConverter.h"
+#include <OgrePrerequisites.h>
+#include <OgreStringConverter.h>
 
+namespace PagedGeometry {
 
 /**
 \brief The BatchPage class renders entities as StaticGeometry.
@@ -74,5 +75,6 @@
 	}
 };
 
+}
 
 #endif
Index: include/BatchedGeometry.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/include/BatchedGeometry.h,v
retrieving revision 1.7
diff -b -U3 -r1.7 BatchedGeometry.h
--- include/BatchedGeometry.h	17 Jan 2008 02:35:32 -0000	1.7
+++ include/BatchedGeometry.h	23 Feb 2008 12:20:49 -0000
@@ -16,11 +16,12 @@
 #ifndef __BatchedGeometry_H__
 #define __BatchedGeometry_H__
 
-#include "OgrePrerequisites.h"
-#include "OgreMovableObject.h"
-#include "OgreSceneNode.h"
-#include "OgreMaterialManager.h"
+#include <OgrePrerequisites.h>
+#include <OgreMovableObject.h>
+#include <OgreSceneNode.h>
+#include <OgreMaterialManager.h>
 
+namespace PagedGeometry {
 
 class BatchedGeometry: public Ogre::MovableObject
 {
@@ -129,6 +130,6 @@
 };
 
 
-
+}
 
 #endif
\ No newline at end of file
Index: include/GrassLoader.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/include/GrassLoader.h,v
retrieving revision 1.24
diff -b -U3 -r1.24 GrassLoader.h
--- include/GrassLoader.h	17 Jan 2008 02:35:32 -0000	1.24
+++ include/GrassLoader.h	23 Feb 2008 12:20:50 -0000
@@ -1,5 +1,6 @@
 /*-------------------------------------------------------------------------------------
 Copyright (c) 2006 John Judnich
+Modified 2008 by Erik Hjortsberg (erik.hjortsberg@iteam.se)
 
 This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
 Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
@@ -14,22 +15,57 @@
 #include "PagedGeometry.h"
 #include "PropertyMaps.h"
 
-#include "OgrePrerequisites.h"
-#include "OgreMaterial.h"
-#include "OgrePixelFormat.h"
-#include "OgreStringConverter.h"
+#include <OgrePrerequisites.h>
+#include <OgreMaterial.h>
+#include <OgrePixelFormat.h>
+#include <OgreStringConverter.h>
+#include <OgreMeshManager.h>
+
+
+#include <OgreRoot.h>
+#include <OgreTimer.h>
+#include <OgreCamera.h>
+#include <OgreVector3.h>
+#include <OgreQuaternion.h>
+#include <OgreEntity.h>
+#include <OgreString.h>
+#include <OgreStringConverter.h>
+#include <OgreMaterialManager.h>
+#include <OgreMaterial.h>
+#include <OgreHardwareBufferManager.h>
+#include <OgreHardwareBuffer.h>
+#include <OgreMeshManager.h>
+#include <OgreMesh.h>
+#include <OgreSubMesh.h>
+#include <OgreLogManager.h>
+#include <OgreTextureManager.h>
+#include <OgreHardwarePixelBuffer.h>
+#include <OgreRenderSystem.h>
+#include <OgreRenderSystemCapabilities.h>
+#include <OgreHighLevelGpuProgram.h>
+#include <OgreHighLevelGpuProgramManager.h>
 
+namespace PagedGeometry {
 
 class GrassLayer;
+class GrassLayerBase;
 
 /** \brief A PageLoader-derived object you can use with PagedGeometry to produce realistic grass. 
 
 Using a GrassLoader is simple - simply create an instance, attach it to your PagedGeometry object
 with PagedGeometry::setPageLoader(), and add your grass. Important: For best performance, it is
 recommended that you use GrassPage (included in GrassLoader.h) to display geometry loaded by GrassLoader.
+
 This page type is designed for best performance with this grass system. BatchPage
 will work, although performance will be reduced slightly, and ImpostorPage will run extremely slow.
 
+When creating a GrassLoader you must specify the class which will be used for creating layers. By default a GrassLayer class is provided, which can be used as this:
+\code
+	::PagedGeometry::GrassLoader<GrassLayer> loader = new ::PagedGeometry::GrassLoader<GrassLayer>(grass);
+\endcode
+It's also possible for you to provide your own GrassLayer implementation by overriding the class GrassLayerBase. This will allow you to have much more control over how the grass is placed.
+
+
 To add grass, just call addLayer(). addLayer() returns a GrassLayer object pointer, which you should
 use to further configure your newly added grass. Properties like size, density, color, animation, etc.
 can be controlled through the GrassLayer class.
@@ -43,12 +79,13 @@
 keep in mind that calculating the height of Ogre's built-in terrain this way can
 be VERY slow if not done properly, and may cause stuttering due to long paging delays.
 */
+template <typename TGrassLayer>
 class GrassLoader: public PageLoader
 {
 public:
 	/** \brief Creates a new GrassLoader object. 
 	\param geom The PagedGeometry object that this GrassLoader will be assigned to.*/
-	GrassLoader(PagedGeometry *geom);
+	inline GrassLoader(PagedGeometry *geom);
 	~GrassLoader();
 
 	/** \brief Adds a grass layer to the scene.
@@ -64,18 +101,18 @@
 	functions to vary grass size and density levels as desired.
 
 	\see GrassLayer class for more information. */
-	GrassLayer *addLayer(const Ogre::String &material);
+	TGrassLayer *addLayer(const Ogre::String &material);
 
 	/** \brief Removes and deletes a grass layer from the scene
 
 	This function simply deletes a GrassLayer previously created with addLayer(). */
-	void deleteLayer(GrassLayer *layer);
+	void deleteLayer(TGrassLayer *layer);
 
 	/** \brief Returns a list of added grass layers.
 	
 	This function returns a std::list<GrassLayer*> reference, which contains all grass
 	layers which have been added to this GrassLoader. */
-	inline std::list<GrassLayer*> &getLayerList() { return layerList; }
+	inline std::list<TGrassLayer*> &getLayerList() { return layerList; }
 
 	/** \brief Sets the global wind direction for this GrassLoader.
 
@@ -179,12 +216,12 @@
 	friend class GrassLayer;
 
 	//Helper functions
-	Ogre::Mesh *GrassLoader::generateGrass_QUAD(PageInfo &page, GrassLayer *layer, float *grassPositions, unsigned int grassCount);
-	Ogre::Mesh *GrassLoader::generateGrass_CROSSQUADS(PageInfo &page, GrassLayer *layer, float *grassPositions, unsigned int grassCount);
-	Ogre::Mesh *GrassLoader::generateGrass_SPRITE(PageInfo &page, GrassLayer *layer, float *grassPositions, unsigned int grassCount);
+	Ogre::Mesh *generateGrass_QUAD(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount);
+	Ogre::Mesh *generateGrass_CROSSQUADS(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount);
+	Ogre::Mesh *generateGrass_SPRITE(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount);
 
 	//List of grass types
-	std::list<GrassLayer*> layerList;
+	std::list<TGrassLayer*> layerList;
 
 	//Height data
 	Ogre::Real (*heightFunction)(Ogre::Real x, Ogre::Real z, void *userData);	//Pointer to height function
@@ -208,6 +245,9 @@
 };
 
 
+
+
+
 /** \brief A technique used to render grass. Passed to GrassLayer::setRenderTechnique(). */
 enum GrassTechnique
 {
@@ -230,6 +270,127 @@
 	FADETECH_ALPHAGROW
 };
 
+class GrassLayerBase
+{
+public:
+	/** \brief Sets the material that is applied to all grass billboards/quads */
+	void setMaterialName(const Ogre::String &matName);
+
+	/** \brief Sets the minimum size that grass quads/billboards will be */
+	void setMinimumSize(float width, float height);
+
+	/** \brief Sets the maximum size that grass quads/billboards will be */
+	void setMaximumSize(float width, float height);
+	
+	/** \brief Sets the technique used to render this grass layer
+	\param style The GrassTechnique style used to display grass.
+	\param blendBase Whether or not grass base blending is enabled.
+	
+	The "style" setting allows you to choose from various construction methods, such as
+	sprite-style grass quads, plain 3D quads, etc. See the GrassTechnique documentation
+	for more information about this option. GRASSTECH_QUAD is used by default.
+
+	Setting "blendBase" to true will enable grass base blending, a technique which helps
+	reduce the unnatural flat appearance of grass quads near the camera. Since the flatness
+	is most obvious where the grass intersects the terrain, this technique attempts to
+	smoothly blend the base of near-by grass into the terrain.
+
+	\note Base blending does not work well with alpha-rejected textures.
+	*/
+	void setRenderTechnique(GrassTechnique style, bool blendBase = false);
+
+	/** \brief Sets the technique used when fading out distant grass
+	\param style The FadeTechnique style used to fade grass.
+	
+	This "style" setting allows you to choose from various fade techniques. Depending on
+	your scene, certain techniques may look better than others. The most compatible method
+	is FADETECH_ALPHA (used by default), although better results can usually be achieved
+	with other methods. See the FadeTechnique documentation for more information.
+	*/
+	void setFadeTechnique(FadeTechnique style);
+
+	/** \brief Enables/disables animation on this layer
+	
+	Always use this function to disable animation, rather than setting SwayLength or SwaySpeed
+	to 0. This function will use a different vertex shader which means improved performance
+	when animation is disabled.
+	*/
+	void setAnimationEnabled(bool enabled);
+
+	/** \brief Sets how far grass should sway back and forth
+
+	\note Since this is measured in world units, you may have to adjust this depending on
+	the size of your grass as set by setMinimumSize() and setMaximumSize().*/
+	void setSwayLength(float mag) { animMag = mag; }
+
+	/** \brief Sets the sway speed of the grass (measured in "sways-per-second") */
+	void setSwaySpeed(float speed) { animSpeed = speed; }
+
+	/** \brief Sets the smooth distribution (positional phase shift) of the grass swaying animation
+
+	If you set this to 0, grass animation will look very unnatural, since all the grass sway motions
+	will be in perfect synchronization (everything sways to the right, then everything sways to the
+	left, etc.) This sets the "positional phase shift", which gives the grass a "wave" like phase
+	distribution. The higher this value is, the more "chaotic" the wind will appear. Lower values give
+	a smoother breeze appearance, but values too high can look unrealistic.
+	*/
+	void setSwayDistribution(float freq) { animFreq = freq; }
+	
+	/** \brief Sets the boundaries of the density/color maps
+	\param bounds The map boundary
+
+	By default, the GrassLayer has no knowledge of your terrain/world boundaries, so you must
+	use this function to specify a rectangular/square area of your world, otherwise density/color maps
+	won't work properly. The boundary given to this function defines the area where density/color
+	maps take effect. Normally this is set to your terrain's bounds so the density/color map is aligned
+	to your heightmap, but you could apply it anywhere you want.
+	
+	\note The grass system is infinite, so there's no need to worry about using too expansive
+	boundaries. This setting simply configures the behavior of density and color maps. */
+	virtual void setMapBounds(const Ogre::TRect<Ogre::Real> &bounds)
+	{
+		mapBounds = bounds;
+	}
+	
+	
+	/**
+	 *    Calculates the max number of grass instances for this layer.
+	 * @param densityFactor The density factor set on the grass loader
+	 * @param volume The volume, in world units, to fill
+	 * @return The max number of grass instances to create.
+	 */
+	virtual unsigned int calculateMaxGrassCount(float densityFactor, float volume) = 0;
+	
+protected: 
+
+	//Used by GrassLoader::loadPage() - populates an array with grass.
+	//Returns the final number of grasses, which will always be <= grassCount
+	virtual unsigned int _populateGrassList(PageInfo page, float *posBuff, unsigned int grassCount) = 0;
+
+	//Updates the vertex shader used by this layer based on the animate enable status
+	void _updateShaders();
+	
+	//Grass material/shape properties
+	Ogre::MaterialPtr material;
+	float minWidth, maxWidth;
+	float minHeight, maxHeight;
+	
+	FadeTechnique fadeTechnique;
+	GrassTechnique renderTechnique;
+
+	//Property maps
+	Ogre::TRect<Ogre::Real> mapBounds;
+	
+	//Grass shader properties
+	bool animate, blend, shaderNeedsUpdate;
+	float animMag, animSpeed, animFreq;
+
+	//Current frame of animation for this layer
+	float waveCount;
+
+	PagedGeometry *geom;
+	
+};
 
 
 /** \brief A data structure giving you full control over grass properties.
@@ -242,17 +403,9 @@
 with GrassLoader::addLayer(), and may not be deleted manually (they will be deleted when
 the associated GrassLoader is deleted).
 */
-class GrassLayer
+class GrassLayer : public GrassLayerBase
 {
 public:
-	/** \brief Sets the material that is applied to all grass billboards/quads */
-	void setMaterialName(const Ogre::String &matName);
-
-	/** \brief Sets the minimum size that grass quads/billboards will be */
-	void setMinimumSize(float width, float height);
-
-	/** \brief Sets the maximum size that grass quads/billboards will be */
-	void setMaximumSize(float width, float height);
 
 	/** \brief Sets the maximum density (measured in grass quads/billboards per square unit) of grass */
 	void setDensity(float density) { this->density = density; }
@@ -359,26 +512,6 @@
 	*/
 	void setColorMapFilter(MapFilter filter);
 
-	/** \brief Sets the boundaries of the density/color maps
-	\param bounds The map boundary
-
-	By default, the GrassLayer has no knowledge of your terrain/world boundaries, so you must
-	use this function to specify a rectangular/square area of your world, otherwise density/color maps
-	won't work properly. The boundary given to this function defines the area where density/color
-	maps take effect. Normally this is set to your terrain's bounds so the density/color map is aligned
-	to your heightmap, but you could apply it anywhere you want.
-	
-	\note The grass system is infinite, so there's no need to worry about using too expansive
-	boundaries. This setting simply configures the behavior of density and color maps. */
-	void setMapBounds(const Ogre::TRect<Ogre::Real> &bounds)
-	{
-		mapBounds = bounds;
-		if (densityMap)
-			densityMap->setMapBounds(mapBounds);
-		if (colorMap)
-			colorMap->setMapBounds(mapBounds);
-	}
-
 	/** \brief Gets a pointer to the density map being used
 
 	You can use this function to access the internal density map object used by the GrassLoader.
@@ -401,71 +534,62 @@
 	don't, the grass you see will remain unchanged. */
 	ColorMap *getColorMap() { return colorMap; }
 
-	/** \brief Sets the technique used to render this grass layer
-	\param style The GrassTechnique style used to display grass.
-	\param blendBase Whether or not grass base blending is enabled.
-	
-	The "style" setting allows you to choose from various construction methods, such as
-	sprite-style grass quads, plain 3D quads, etc. See the GrassTechnique documentation
-	for more information about this option. GRASSTECH_QUAD is used by default.
-
-	Setting "blendBase" to true will enable grass base blending, a technique which helps
-	reduce the unnatural flat appearance of grass quads near the camera. Since the flatness
-	is most obvious where the grass intersects the terrain, this technique attempts to
-	smoothly blend the base of near-by grass into the terrain.
-
-	\note Base blending does not work well with alpha-rejected textures.
-	*/
-	void setRenderTechnique(GrassTechnique style, bool blendBase = false);
 
-	/** \brief Sets the technique used when fading out distant grass
-	\param style The FadeTechnique style used to fade grass.
+	/** \brief Sets the boundaries of the density/color maps
+	\param bounds The map boundary
 	
-	This "style" setting allows you to choose from various fade techniques. Depending on
-	your scene, certain techniques may look better than others. The most compatible method
-	is FADETECH_ALPHA (used by default), although better results can usually be achieved
-	with other methods. See the FadeTechnique documentation for more information.
-	*/
-	void setFadeTechnique(FadeTechnique style);
+	By default, the GrassLayer has no knowledge of your terrain/world boundaries, so you must
+	use this function to specify a rectangular/square area of your world, otherwise density/color maps
+	won't work properly. The boundary given to this function defines the area where density/color
+	maps take effect. Normally this is set to your terrain's bounds so the density/color map is aligned
+	to your heightmap, but you could apply it anywhere you want.
 
-	/** \brief Enables/disables animation on this layer
+	\note The grass system is infinite, so there's no need to worry about using too expansive
+	boundaries. This setting simply configures the behavior of density and color maps. */
+	virtual void setMapBounds(const Ogre::TRect<Ogre::Real> &bounds)
+	{
+		GrassLayerBase::setMapBounds(bounds);
+		if (densityMap)
+			densityMap->setMapBounds(mapBounds);
+		if (colorMap)
+			colorMap->setMapBounds(mapBounds);
+	}
 	
-	Always use this function to disable animation, rather than setting SwayLength or SwaySpeed
-	to 0. This function will use a different vertex shader which means improved performance
-	when animation is disabled.
+	/**
+	 *    Calculates the max number of grass instances for this layer.
+	 * @param densityFactor The density factor set on the grass loader
+	 * @param volume The volume, in world units, to fill
+	 * @return The max number of grass instances to create.
 	*/
-	void setAnimationEnabled(bool enabled);
+	virtual unsigned int calculateMaxGrassCount(float densityFactor, float volume);
 
-	/** \brief Sets how far grass should sway back and forth
-
-	\note Since this is measured in world units, you may have to adjust this depending on
-	the size of your grass as set by setMinimumSize() and setMaximumSize().*/
-	void setSwayLength(float mag) { animMag = mag; }
-
-	/** \brief Sets the sway speed of the grass (measured in "sways-per-second") */
-	void setSwaySpeed(float speed) { animSpeed = speed; }
-
-	/** \brief Sets the smooth distribution (positional phase shift) of the grass swaying animation
 
-	If you set this to 0, grass animation will look very unnatural, since all the grass sway motions
-	will be in perfect synchronization (everything sways to the right, then everything sways to the
-	left, etc.) This sets the "positional phase shift", which gives the grass a "wave" like phase
-	distribution. The higher this value is, the more "chaotic" the wind will appear. Lower values give
-	a smoother breeze appearance, but values too high can look unrealistic.
+	/**
+	 *    If there's a colormap registered use that for lookup, else return fullbright.
+	 * @param x 
+	 * @param z 
+	 * @return 
 	*/
-	void setSwayDistribution(float freq) { animFreq = freq; }
+	inline Ogre::uint32 getColorAt(float x, float z)
+	{
+		if (colorMap)
+			return colorMap->getColorAt(x, z);
+		else
+			return 0xFFFFFFFF;
+	}
 
 private:
-	friend class GrassLoader;
+	friend class GrassLoader<GrassLayer>;
 
 	/** \brief Do not create a GrassLayer directly - use GrassLoader->addLayer() */
-	GrassLayer(PagedGeometry *geom, GrassLoader *ldr);
+	GrassLayer(PagedGeometry *geom, GrassLoader<GrassLayer> *ldr);
 
 	/** \brief Do not delete a GrassLayer yourself - the GrassLoader will do this automatically when it's deleted */
 	~GrassLayer();
 
-	//Updates the vertex shader used by this layer based on the animate enable status
-	void _updateShaders();
+	//Used by GrassLoader::loadPage() - populates an array with grass.
+	//Returns the final number of grasses, which will always be <= grassCount
+	virtual unsigned int _populateGrassList(PageInfo page, float *posBuff, unsigned int grassCount);
 
 	//Used by GrassLoader::loadPage() - populates an array with a uniform distribution of grass
 	//Returns the final number of grasses, which will always be <= grassCount
@@ -480,21 +604,13 @@
 	unsigned int _populateGrassList_BilinearDM(PageInfo page, float *posBuff, unsigned int grassCount);
 
 
-	GrassLoader *parent;
+	GrassLoader<GrassLayer> *parent;
 
 	//Grass material/shape properties
-	Ogre::MaterialPtr material;
 	float density;
-	float minWidth, maxWidth;
-	float minHeight, maxHeight;
 
 	float minY, maxY;
 
-	FadeTechnique fadeTechnique;
-	GrassTechnique renderTechnique;
-
-	//Property maps
-	Ogre::TRect<Ogre::Real> mapBounds;
 
 	DensityMap *densityMap;
 	MapFilter densityMapFilter;
@@ -502,14 +618,6 @@
 	ColorMap *colorMap;
 	MapFilter colorMapFilter;
 
-	//Grass shader properties
-	bool animate, blend, shaderNeedsUpdate;
-	float animMag, animSpeed, animFreq;
-
-	//Current frame of animation for this layer
-	float waveCount;
-
-	PagedGeometry *geom;
 };
 
 
@@ -544,4 +652,605 @@
 	}
 };
 
+template <class TGrassLayer>
+GrassLoader<TGrassLayer>::GrassLoader(PagedGeometry *geom)
+{
+	GrassLoader<TGrassLayer>::geom = geom;
+	
+	heightFunction = NULL;
+	heightFunctionUserData = NULL;
+
+	windDir = Ogre::Vector3::UNIT_X;
+	densityFactor = 1.0f;
+	renderQueue = Ogre::RENDER_QUEUE_6;
+
+	windTimer.reset();
+	lastTime = 0;
+}
+
+template <class TGrassLayer>
+GrassLoader<TGrassLayer>::~GrassLoader()
+{
+	typename std::list<TGrassLayer*>::iterator it;
+	for (it = layerList.begin(); it != layerList.end(); ++it){
+		delete *it;
+	}
+	layerList.clear();
+}
+
+template <class TGrassLayer>
+TGrassLayer *GrassLoader<TGrassLayer>::addLayer(const Ogre::String &material)
+{
+	TGrassLayer *layer = new TGrassLayer(geom, this);
+	layer->setMaterialName(material);
+	layerList.push_back(layer);
+
+	return layer;
+}
+
+template <class TGrassLayer>
+void GrassLoader<TGrassLayer>::deleteLayer(TGrassLayer *layer)
+{
+	layerList.remove(layer);
+	delete layer;
+}
+
+template <class TGrassLayer>
+void GrassLoader<TGrassLayer>::frameUpdate()
+{
+	unsigned long currentTime = windTimer.getMilliseconds();
+	unsigned long ellapsedTime = currentTime - lastTime;
+	lastTime = currentTime;
+
+	float ellapsed = ellapsedTime / 1000.0f;
+	
+	//Update the vertex shader parameters
+	typename std::list<TGrassLayer*>::iterator it;
+	for (it = layerList.begin(); it != layerList.end(); ++it){
+		TGrassLayer *layer = *it;
+
+		layer->_updateShaders();
+
+		Ogre::GpuProgramParametersSharedPtr params = layer->material->getTechnique(0)->getPass(0)->getVertexProgramParameters();
+		if (layer->animate){
+			//Increment animation frame
+			layer->waveCount += ellapsed * (layer->animSpeed * Ogre::Math::PI);
+			if (layer->waveCount > Ogre::Math::PI*2) layer->waveCount -= Ogre::Math::PI*2;
+
+			//Set vertex shader parameters
+			params->setNamedConstant("time", layer->waveCount);
+			params->setNamedConstant("frequency", layer->animFreq);
+
+			Ogre::Vector3 direction = windDir * layer->animMag;
+			params->setNamedConstant("direction", Ogre::Vector4(direction.x, direction.y, direction.z, 0));
+
+		}
+	}
+}
+
+template <class TGrassLayer>
+void GrassLoader<TGrassLayer>::loadPage(PageInfo &page)
+{
+	//Seed random number generator based on page indexes
+	Ogre::uint16 xSeed = static_cast<Ogre::uint16>(page.xIndex % 0xFFFF);
+	Ogre::uint16 zSeed = static_cast<Ogre::uint16>(page.zIndex % 0xFFFF);
+	Ogre::uint32 seed = (xSeed << 16) | zSeed;
+	srand(seed);
+
+	typename std::list<TGrassLayer*>::iterator it;
+	for (it = layerList.begin(); it != layerList.end(); ++it){
+		TGrassLayer *layer = *it;
+
+		//Calculate how much grass needs to be added
+		float volume = page.bounds.width() * page.bounds.height();
+		unsigned int grassCount = layer->calculateMaxGrassCount(densityFactor, volume);
+
+		//The vertex buffer can't be allocated until the exact number of polygons is known,
+		//so the locations of all grasses in this page must be precalculated.
+
+		//Precompute grass locations into an array of floats. A plain array is used for speed;
+		//there's no need to use a dynamic sized array since a maximum size is known.
+		float *position = new float[grassCount*2];
+		grassCount = layer->_populateGrassList(page, position, grassCount);
+
+		//Don't build a mesh unless it contains something
+		if (grassCount != 0){
+			Ogre::Mesh *mesh = NULL;
+			switch (layer->renderTechnique){
+				case GRASSTECH_QUAD:
+					mesh = generateGrass_QUAD(page, layer, position, grassCount);
+					break;
+				case GRASSTECH_CROSSQUADS:
+					mesh = generateGrass_CROSSQUADS(page, layer, position, grassCount);
+					break;
+				case GRASSTECH_SPRITE:
+					mesh = generateGrass_SPRITE(page, layer, position, grassCount);
+					break;
+			}
+			assert(mesh);
+
+			//Add the mesh to PagedGeometry
+			Ogre::Entity *entity = geom->getCamera()->getSceneManager()->createEntity(getUniqueID(), mesh->getName());
+			entity->setRenderQueueGroup(renderQueue);
+			entity->setCastShadows(false);
+			addEntity(entity, page.centerPoint, Ogre::Quaternion::IDENTITY, Ogre::Vector3::UNIT_SCALE);
+			geom->getSceneManager()->destroyEntity(entity);
+
+			//Store the mesh pointer
+			page.userData = mesh;
+		} else {
+			//No mesh
+			page.userData = NULL;
+		}
+
+		//Delete the position list
+		delete[] position;
+	}
+}
+
+template <class TGrassLayer>
+void GrassLoader<TGrassLayer>::unloadPage(const PageInfo &page)
+{
+	//Unload mesh
+	Ogre::Mesh *mesh = (Ogre::Mesh*)page.userData;
+	if (mesh)
+		Ogre::MeshManager::getSingleton().remove(mesh->getName());
+}
+template <class TGrassLayer>
+Ogre::Mesh *GrassLoader<TGrassLayer>::generateGrass_QUAD(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount)
+{
+	//Calculate the number of quads to be added
+	unsigned int quadCount;
+	quadCount = grassCount;
+
+	//Create manual mesh to store grass quads
+	Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(getUniqueID(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
+	Ogre::SubMesh *subMesh = mesh->createSubMesh();
+	subMesh->useSharedVertices = false;
+
+	//Setup vertex format information
+	subMesh->vertexData = new Ogre::VertexData;
+	subMesh->vertexData->vertexStart = 0;
+	subMesh->vertexData->vertexCount = 4 * quadCount;
+
+	Ogre::VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
+	size_t offset = 0;
+	dcl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
+	dcl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
+	dcl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
+
+	//Populate a new vertex buffer with grass
+	Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton()
+		.createVertexBuffer(offset, subMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
+	float* pReal = static_cast<float*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
+
+	//Calculate size variance
+	float rndWidth = layer->maxWidth - layer->minWidth;
+	float rndHeight = layer->maxHeight - layer->minHeight;
+
+	float minY = Ogre::Math::POS_INFINITY, maxY = Ogre::Math::NEG_INFINITY;
+	float *posPtr = grassPositions;	//Position array "iterator"
+	for (Ogre::uint16 i = 0; i < grassCount; ++i)
+	{
+		//Get the x and z positions from the position array
+		float x = *posPtr++;
+		float z = *posPtr++;
+
+		//Get the color at the grass position
+		Ogre::uint32 color(layer->getColorAt(x, z));
+
+		//Calculate size
+		float rnd = Ogre::Math::UnitRandom();	//The same rnd value is used for width and height to maintain aspect ratio
+		float halfScaleX = (layer->minWidth + rndWidth * rnd) * 0.5f;
+		float scaleY = (layer->minHeight + rndHeight * rnd);
+
+		//Calculate rotation
+		float angle = Ogre::Math::RangeRandom(0, Ogre::Math::TWO_PI);
+		float xTrans = Ogre::Math::Cos(angle) * halfScaleX;
+		float zTrans = Ogre::Math::Sin(angle) * halfScaleX;
+
+		//Calculate heights and edge positions
+		float x1 = x - xTrans, z1 = z - zTrans;
+		float x2 = x + xTrans, z2 = z + zTrans;
+
+		float y1, y2;
+		if (heightFunction){
+			y1 = heightFunction(x1, z1, heightFunctionUserData);
+			y2 = heightFunction(x2, z2, heightFunctionUserData);
+		} else {
+			y1 = 0;
+			y2 = 0;
+		}
+
+		//Add vertices
+		*pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1 + scaleY); *pReal++ = (z1 - page.centerPoint.z);	//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 0; *pReal++ = 0;								//uv
+
+		*pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2 + scaleY); *pReal++ = (z2 - page.centerPoint.z);	//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 1; *pReal++ = 0;								//uv
+
+		*pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1); *pReal++ = (z1 - page.centerPoint.z);			//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 0; *pReal++ = 1;								//uv
+
+		*pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2); *pReal++ = (z2 - page.centerPoint.z);			//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 1; *pReal++ = 1;								//uv
+
+		//Update bounds
+		if (y1 < minY) minY = y1;
+		if (y2 < minY) minY = y2;
+		if (y1 + scaleY > maxY) maxY = y1 + scaleY;
+		if (y2 + scaleY > maxY) maxY = y2 + scaleY;
+	}
+
+	vbuf->unlock();
+	subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
+
+	//Populate index buffer
+	subMesh->indexData->indexStart = 0;
+	subMesh->indexData->indexCount = 6 * quadCount;
+	subMesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton()
+		.createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
+	Ogre::uint16* pI = static_cast<Ogre::uint16*>(subMesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
+	for (Ogre::uint16 i = 0; i < quadCount; ++i)
+	{
+		Ogre::uint16 offset = i * 4;
+
+		*pI++ = 0 + offset;
+		*pI++ = 2 + offset;
+		*pI++ = 1 + offset;
+
+		*pI++ = 1 + offset;
+		*pI++ = 2 + offset;
+		*pI++ = 3 + offset;
+	}
+
+	subMesh->indexData->indexBuffer->unlock();
+
+	//Finish up mesh
+	Ogre::AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
+		page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
+	mesh->_setBounds(bounds);
+	Ogre::Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
+	mesh->_setBoundingSphereRadius(temp.length() * 0.5f);
+
+	Ogre::LogManager::getSingleton().setLogDetail(static_cast<Ogre::LoggingLevel>(0));
+	mesh->load();
+	Ogre::LogManager::getSingleton().setLogDetail(Ogre::LL_NORMAL);
+
+	//Apply grass material to mesh
+	subMesh->setMaterialName(layer->material->getName());
+
+	//Return the mesh
+	return mesh.getPointer();
+}
+
+template <class TGrassLayer>
+Ogre::Mesh *GrassLoader<TGrassLayer>::generateGrass_CROSSQUADS(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount)
+{
+	//Calculate the number of quads to be added
+	unsigned int quadCount;
+	quadCount = grassCount * 2;
+
+	//Create manual mesh to store grass quads
+	Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(getUniqueID(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
+	Ogre::SubMesh *subMesh = mesh->createSubMesh();
+	subMesh->useSharedVertices = false;
+
+	//Setup vertex format information
+	subMesh->vertexData = new Ogre::VertexData;
+	subMesh->vertexData->vertexStart = 0;
+	subMesh->vertexData->vertexCount = 4 * quadCount;
+
+	Ogre::VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
+	size_t offset = 0;
+	dcl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
+	dcl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
+	dcl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
+
+	//Populate a new vertex buffer with grass
+	Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton()
+		.createVertexBuffer(offset, subMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
+	float* pReal = static_cast<float*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
+
+	//Calculate size variance
+	float rndWidth = layer->maxWidth - layer->minWidth;
+	float rndHeight = layer->maxHeight - layer->minHeight;
+
+	float minY = Ogre::Math::POS_INFINITY, maxY = Ogre::Math::NEG_INFINITY;
+	float *posPtr = grassPositions;	//Position array "iterator"
+	for (Ogre::uint16 i = 0; i < grassCount; ++i)
+	{
+		//Get the x and z positions from the position array
+		float x = *posPtr++;
+		float z = *posPtr++;
+
+		//Get the color at the grass position
+		Ogre::uint32 color(layer->getColorAt(x, z));
+		
+// 		if (layer->colorMap)
+// 			color = layer->colorMap->getColorAt(x, z);
+// 		else
+// 			color = 0xFFFFFFFF;
+
+		//Calculate size
+		float rnd = Ogre::Math::UnitRandom();	//The same rnd value is used for width and height to maintain aspect ratio
+		float halfScaleX = (layer->minWidth + rndWidth * rnd) * 0.5f;
+		float scaleY = (layer->minHeight + rndHeight * rnd);
+
+		//Calculate rotation
+		float angle = Ogre::Math::RangeRandom(0, Ogre::Math::TWO_PI);
+		float xTrans = Ogre::Math::Cos(angle) * halfScaleX;
+		float zTrans = Ogre::Math::Sin(angle) * halfScaleX;
+
+		//Calculate heights and edge positions
+		float x1 = x - xTrans, z1 = z - zTrans;
+		float x2 = x + xTrans, z2 = z + zTrans;
+
+		float y1, y2;
+		if (heightFunction){
+			y1 = heightFunction(x1, z1, heightFunctionUserData);
+			y2 = heightFunction(x2, z2, heightFunctionUserData);
+		} else {
+			y1 = 0;
+			y2 = 0;
+		}
+
+		//Add vertices
+		*pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1 + scaleY); *pReal++ = (z1 - page.centerPoint.z);	//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 0; *pReal++ = 0;								//uv
+
+		*pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2 + scaleY); *pReal++ = (z2 - page.centerPoint.z);	//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 1; *pReal++ = 0;								//uv
+
+		*pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1); *pReal++ = (z1 - page.centerPoint.z);			//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 0; *pReal++ = 1;								//uv
+
+		*pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2); *pReal++ = (z2 - page.centerPoint.z);			//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 1; *pReal++ = 1;								//uv
+
+		//Update bounds
+		if (y1 < minY) minY = y1;
+		if (y2 < minY) minY = y2;
+		if (y1 + scaleY > maxY) maxY = y1 + scaleY;
+		if (y2 + scaleY > maxY) maxY = y2 + scaleY;
+
+		//Calculate heights and edge positions
+		float x3 = x + zTrans, z3 = z - xTrans;
+		float x4 = x - zTrans, z4 = z + xTrans;
+
+		float y3, y4;
+		if (heightFunction){
+			y3 = heightFunction(x3, z3, heightFunctionUserData);
+			y4 = heightFunction(x4, z4, heightFunctionUserData);
+		} else {
+			y3 = 0;
+			y4 = 0;
+		}
+
+		//Add vertices
+		*pReal++ = (x3 - page.centerPoint.x); *pReal++ = (y3 + scaleY); *pReal++ = (z3 - page.centerPoint.z);	//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 0; *pReal++ = 0;								//uv
+
+		*pReal++ = (x4 - page.centerPoint.x); *pReal++ = (y4 + scaleY); *pReal++ = (z4 - page.centerPoint.z);	//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 1; *pReal++ = 0;								//uv
+
+		*pReal++ = (x3 - page.centerPoint.x); *pReal++ = (y3); *pReal++ = (z3 - page.centerPoint.z);			//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 0; *pReal++ = 1;								//uv
+
+		*pReal++ = (x4 - page.centerPoint.x); *pReal++ = (y4); *pReal++ = (z4 - page.centerPoint.z);			//pos
+		*((Ogre::uint32*)pReal++) = color;							//color
+		*pReal++ = 1; *pReal++ = 1;								//uv
+
+		//Update bounds
+		if (y3 < minY) minY = y1;
+		if (y4 < minY) minY = y2;
+		if (y3 + scaleY > maxY) maxY = y3 + scaleY;
+		if (y4 + scaleY > maxY) maxY = y4 + scaleY;
+	}
+
+	vbuf->unlock();
+	subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
+
+	//Populate index buffer
+	subMesh->indexData->indexStart = 0;
+	subMesh->indexData->indexCount = 6 * quadCount;
+	subMesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton()
+		.createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
+	Ogre::uint16* pI = static_cast<Ogre::uint16*>(subMesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
+	for (Ogre::uint16 i = 0; i < quadCount; ++i)
+	{
+		Ogre::uint16 offset = i * 4;
+
+		*pI++ = 0 + offset;
+		*pI++ = 2 + offset;
+		*pI++ = 1 + offset;
+
+		*pI++ = 1 + offset;
+		*pI++ = 2 + offset;
+		*pI++ = 3 + offset;
+	}
+
+	subMesh->indexData->indexBuffer->unlock();
+
+	//Finish up mesh
+	Ogre::AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
+		page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
+	mesh->_setBounds(bounds);
+	Ogre::Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
+	mesh->_setBoundingSphereRadius(temp.length() * 0.5f);
+
+	Ogre::LogManager::getSingleton().setLogDetail(static_cast<Ogre::LoggingLevel>(0));
+	mesh->load();
+	Ogre::LogManager::getSingleton().setLogDetail(Ogre::LL_NORMAL);
+
+	//Apply grass material to mesh
+	subMesh->setMaterialName(layer->material->getName());
+
+	//Return the mesh
+	return mesh.getPointer();
+}
+
+template <class TGrassLayer>
+Ogre::Mesh *GrassLoader<TGrassLayer>::generateGrass_SPRITE(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount)
+{
+	//Calculate the number of quads to be added
+	unsigned int quadCount;
+	quadCount = grassCount;
+
+	//Create manual mesh to store grass quads
+	Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(getUniqueID(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
+	Ogre::SubMesh *subMesh = mesh->createSubMesh();
+	subMesh->useSharedVertices = false;
+
+	//Setup vertex format information
+	subMesh->vertexData = new Ogre::VertexData;
+	subMesh->vertexData->vertexStart = 0;
+	subMesh->vertexData->vertexCount = 4 * quadCount;
+
+	Ogre::VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
+	size_t offset = 0;
+	dcl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
+	dcl->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_NORMAL);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
+	dcl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
+	dcl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
+	offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
+
+	//Populate a new vertex buffer with grass
+	Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton()
+		.createVertexBuffer(offset, subMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
+	float* pReal = static_cast<float*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
+
+	//Calculate size variance
+	float rndWidth = layer->maxWidth - layer->minWidth;
+	float rndHeight = layer->maxHeight - layer->minHeight;
+
+	float minY = Ogre::Math::POS_INFINITY, maxY = Ogre::Math::NEG_INFINITY;
+	float *posPtr = grassPositions;	//Position array "iterator"
+	for (Ogre::uint16 i = 0; i < grassCount; ++i)
+	{
+		//Get the x and z positions from the position array
+		float x = *posPtr++;
+		float z = *posPtr++;
+
+		//Calculate height
+		float y;
+		if (heightFunction){
+			y = heightFunction(x, z, heightFunctionUserData);
+		} else {
+			y = 0;
+		}
+
+		float x1 = (x - page.centerPoint.x);
+		float z1 = (z - page.centerPoint.z);
+
+		//Get the color at the grass position
+		Ogre::uint32 color(layer->getColorAt(x, z));
+
+		//Calculate size
+		float rnd = Ogre::Math::UnitRandom();	//The same rnd value is used for width and height to maintain aspect ratio
+		float halfXScale = (layer->minWidth + rndWidth * rnd) * 0.5f;
+		float scaleY = (layer->minHeight + rndHeight * rnd);
+
+		//Randomly mirror grass textures
+		float uvLeft, uvRight;
+		if (Ogre::Math::UnitRandom() > 0.5f){
+			uvLeft = 0;
+			uvRight = 1;
+		} else {
+			uvLeft = 1;
+			uvRight = 0;
+		}
+
+		//Add vertices
+		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
+		*pReal++ = -halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0;	//normal (used to store relative corner positions)
+		*((Ogre::uint32*)pReal++) = color;								//color
+		*pReal++ = uvLeft; *pReal++ = 0;							//uv
+
+		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
+		*pReal++ = +halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0;	//normal (used to store relative corner positions)
+		*((Ogre::uint32*)pReal++) = color;								//color
+		*pReal++ = uvRight; *pReal++ = 0;							//uv
+
+		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
+		*pReal++ = -halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0;		//normal (used to store relative corner positions)
+		*((Ogre::uint32*)pReal++) = color;								//color
+		*pReal++ = uvLeft; *pReal++ = 1;							//uv
+
+		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
+		*pReal++ = +halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0;		//normal (used to store relative corner positions)
+		*((Ogre::uint32*)pReal++) = color;								//color
+		*pReal++ = uvRight; *pReal++ = 1;							//uv
+
+		//Update bounds
+		if (y < minY) minY = y;
+		if (y + scaleY > maxY) maxY = y + scaleY;
+	}
+
+	vbuf->unlock();
+	subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
+
+	//Populate index buffer
+	subMesh->indexData->indexStart = 0;
+	subMesh->indexData->indexCount = 6 * quadCount;
+	subMesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton()
+		.createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
+	Ogre::uint16* pI = static_cast<Ogre::uint16*>(subMesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
+	for (Ogre::uint16 i = 0; i < quadCount; ++i)
+	{
+		Ogre::uint16 offset = i * 4;
+
+		*pI++ = 0 + offset;
+		*pI++ = 2 + offset;
+		*pI++ = 1 + offset;
+
+		*pI++ = 1 + offset;
+		*pI++ = 2 + offset;
+		*pI++ = 3 + offset;
+	}
+
+	subMesh->indexData->indexBuffer->unlock();
+
+	//Finish up mesh
+	Ogre::AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
+		page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
+	mesh->_setBounds(bounds);
+	Ogre::Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
+	mesh->_setBoundingSphereRadius(temp.length() * 0.5f);
+
+	Ogre::LogManager::getSingleton().setLogDetail(static_cast<Ogre::LoggingLevel>(0));
+	mesh->load();
+	Ogre::LogManager::getSingleton().setLogDetail(Ogre::LL_NORMAL);
+
+	//Apply grass material to mesh
+	subMesh->setMaterialName(layer->material->getName());
+
+	//Return the mesh
+	return mesh.getPointer();
+}
+
+template <class TGrassLayer>
+unsigned long GrassLoader<TGrassLayer>::GUID = 0;
+
+}
 #endif
Index: include/ImpostorPage.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/include/ImpostorPage.h,v
retrieving revision 1.27
diff -b -U3 -r1.27 ImpostorPage.h
--- include/ImpostorPage.h	17 Jan 2008 02:35:32 -0000	1.27
+++ include/ImpostorPage.h	23 Feb 2008 12:20:51 -0000
@@ -1,5 +1,6 @@
 /*-------------------------------------------------------------------------------------
 Copyright (c) 2006 John Judnich
+Modified 2008 by Erik Hjortsberg (erik.hjortsberg@iteam.se)
 
 This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
 Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
@@ -18,13 +19,16 @@
 #include "PagedGeometry.h"
 #include "StaticBillboardSet.h"
 
-#include "OgrePrerequisites.h"
-#include "OgreTextureManager.h"
-#include "OgreRenderTexture.h"
+#include <OgrePrerequisites.h>
+#include <OgreTextureManager.h>
+#include <OgreRenderTexture.h>
 
 
 #define IMPOSTOR_YAW_ANGLES 8
 #define IMPOSTOR_PITCH_ANGLES 4
+//If set to 1, imposter textures will be read and saved to disc; if set to 0 they will stay in memory and need to be regenerated each time the application is run.
+#define IMPOSTOR_FILE_SAVE 1
+namespace PagedGeometry {
 
 class ImpostorBatch;
 class ImpostorTexture;
@@ -46,7 +50,8 @@
 To use this page type, use:
 \code
 PagedGeometry::addDetailLevel<ImpostorPage>(farRange);
-\endcode
+\endcode	TexturePtr renderTexture;
+
 
 Of all the page types included in the PagedGeometry engine, this one is the fastest. It
 uses impostors (billboards that look just like the real entity) to represent entities.
@@ -241,6 +246,27 @@
 	}
 };
 
+//-------------------------------------------------------------------------------------
+//Responsible for making sure that the texture is rerendered when the texture resource needs to //be reloaded.
+//
+class ImpostorTextureResourceLoader : public Ogre::ManualResourceLoader
+{
+public:
+	/**
+	 *    Ctor.
+	 * @param renderContext The ImpostorTexture to which this instance belongs.
+	 */
+	ImpostorTextureResourceLoader(ImpostorTexture& impostorTexture);
+	
+	
+	/**
+	 *    At load time the texture will be rerendered.
+	 * @param resource 
+	 */
+	virtual void loadResource (Ogre::Resource *resource);
+protected:
+	ImpostorTexture& texture;
+};
 
 //-------------------------------------------------------------------------------------
 //This is used internally by ImpostorPage. An ImpostorTexture is actually multiple
@@ -250,6 +276,7 @@
 class ImpostorTexture
 {
 	friend class ImpostorBatch;
+	friend class ImpostorTextureResourceLoader;
 
 public:
 	/** Returns a pointer to an ImpostorTexture for the specified entity. If one does not
@@ -294,6 +321,9 @@
 	{
 		return prefix + Ogre::StringConverter::toString(++GUID);
 	}
+	
+	//This will only be used when IMPOSTOR_FILE_SAVE is set to 0
+	std::auto_ptr<ImpostorTextureResourceLoader> loader;
 };
 
 
@@ -316,6 +346,6 @@
 							tex->entityDiameter * scale.y, color,
 							texCoordIndx);
 }
-
+}
 
 #endif
Index: include/PagedGeometry.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/include/PagedGeometry.h,v
retrieving revision 1.42
diff -b -U3 -r1.42 PagedGeometry.h
--- include/PagedGeometry.h	3 Feb 2008 00:02:53 -0000	1.42
+++ include/PagedGeometry.h	23 Feb 2008 12:20:56 -0000
@@ -93,15 +93,16 @@
 
 #include <limits> // numeric_limits<>
 
-#include "OgreRoot.h"
-#include "OgrePrerequisites.h"
-#include "OgreRenderSystem.h"
-#include "OgreEntity.h"
-#include "OgreCommon.h"
-#include "OgreCamera.h"
-#include "OgreVector3.h"
-#include "OgreTimer.h"
+#include <OgreRoot.h>
+#include <OgrePrerequisites.h>
+#include <OgreRenderSystem.h>
+#include <OgreEntity.h>
+#include <OgreCommon.h>
+#include <OgreCamera.h>
+#include <OgreVector3.h>
+#include <OgreTimer.h>
 
+namespace PagedGeometry {
 
 class GeometryPageManager;
 class PageLoader;
@@ -1383,4 +1384,5 @@
 		}
 	}
 }
+}
 #endif
Index: include/PropertyMaps.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/include/PropertyMaps.h,v
retrieving revision 1.3
diff -b -U3 -r1.3 PropertyMaps.h
--- include/PropertyMaps.h	15 Oct 2007 03:05:08 -0000	1.3
+++ include/PropertyMaps.h	23 Feb 2008 12:20:56 -0000
@@ -11,12 +11,13 @@
 #ifndef __PropertyMaps_H__
 #define __PropertyMaps_H__
 
-#include "OgrePrerequisites.h"
-#include "OgrePixelFormat.h"
-#include "OgreColourValue.h"
-#include "OgreRoot.h"
-#include "OgreRenderSystem.h"
+#include <OgrePrerequisites.h>
+#include <OgrePixelFormat.h>
+#include <OgreColourValue.h>
+#include <OgreRoot.h>
+#include <OgreRenderSystem.h>
 
+namespace PagedGeometry {
 
 /** \brief Specifies which color channel(s) to extract from an image */
 enum MapChannel {
@@ -239,6 +240,6 @@
 	Ogre::TRect<Ogre::Real> mapBounds;
 };
 
-
+}
 
 #endif
\ No newline at end of file
Index: include/StaticBillboardSet.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/include/StaticBillboardSet.h,v
retrieving revision 1.11
diff -b -U3 -r1.11 StaticBillboardSet.h
--- include/StaticBillboardSet.h	13 Dec 2007 23:33:30 -0000	1.11
+++ include/StaticBillboardSet.h	23 Feb 2008 12:20:57 -0000
@@ -18,18 +18,19 @@
 #ifndef __StaticBillboardSet_H__
 #define __StaticBillboardSet_H__
 
-#include "OgrePrerequisites.h"
-#include "OgreRoot.h"
-#include "OgreRenderSystem.h"
-#include "OgreVector3.h"
-#include "OgreMesh.h"
-#include "OgreMaterial.h"
-#include "OgreBillboard.h"
-#include "OgreBillboardSet.h"
-#include "OgreMaterialManager.h"
-#include "OgreSceneNode.h"
-#include "OgreStringConverter.h"
+#include <OgrePrerequisites.h>
+#include <OgreRoot.h>
+#include <OgreRenderSystem.h>
+#include <OgreVector3.h>
+#include <OgreMesh.h>
+#include <OgreMaterial.h>
+#include <OgreBillboard.h>
+#include <OgreBillboardSet.h>
+#include <OgreMaterialManager.h>
+#include <OgreSceneNode.h>
+#include <OgreStringConverter.h>
 
+namespace PagedGeometry {
 
 class SBMaterialRef;
 typedef std::map<Ogre::Material*, SBMaterialRef*> SBMaterialRefList;
@@ -303,6 +304,6 @@
 	Ogre::Material *material;
 	Ogre::BillboardOrigin origin;
 };
-
+}
 
 #endif
Index: include/TreeLoader2D.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/include/TreeLoader2D.h,v
retrieving revision 1.10
diff -b -U3 -r1.10 TreeLoader2D.h
--- include/TreeLoader2D.h	17 Jan 2008 02:35:32 -0000	1.10
+++ include/TreeLoader2D.h	23 Feb 2008 12:20:57 -0000
@@ -14,8 +14,9 @@
 #include "PagedGeometry.h"
 #include "PropertyMaps.h"
 
-#include "OgrePrerequisites.h"
+#include <OgrePrerequisites.h>
 
+namespace PagedGeometry {
 
 class TreeIterator3D;
 class TreeIterator2D;
@@ -364,6 +365,6 @@
 	bool hasMore;
 };
 
-
+}
 
 #endif
\ No newline at end of file
Index: include/TreeLoader3D.h
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/include/TreeLoader3D.h,v
retrieving revision 1.8
diff -b -U3 -r1.8 TreeLoader3D.h
--- include/TreeLoader3D.h	4 Dec 2007 00:42:13 -0000	1.8
+++ include/TreeLoader3D.h	23 Feb 2008 12:20:57 -0000
@@ -14,8 +14,9 @@
 #include "PagedGeometry.h"
 #include "PropertyMaps.h"
 
-#include "OgrePrerequisites.h"
+#include <OgrePrerequisites.h>
 
+namespace PagedGeometry {
 
 class TreeIterator3D;
 class TreeIterator2D;
@@ -304,6 +305,6 @@
 	bool hasMore;
 };
 
-
+}
 
 #endif
\ No newline at end of file
Index: source/BatchPage.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/source/BatchPage.cpp,v
retrieving revision 1.16
diff -b -U3 -r1.16 BatchPage.cpp
--- source/BatchPage.cpp	20 Jan 2008 01:40:27 -0000	1.16
+++ source/BatchPage.cpp	23 Feb 2008 12:20:57 -0000
@@ -15,17 +15,18 @@
 #include "BatchPage.h"
 #include "BatchedGeometry.h"
 
-#include "OgreRoot.h"
-#include "OgreCamera.h"
-#include "OgreVector3.h"
-#include "OgreQuaternion.h"
-#include "OgreEntity.h"
-#include "OgreRenderSystem.h"
-#include "OgreRenderSystemCapabilities.h"
-#include "OgreHighLevelGpuProgram.h"
-#include "OgreHighLevelGpuProgramManager.h"
+#include <OgreRoot.h>
+#include <OgreCamera.h>
+#include <OgreVector3.h>
+#include <OgreQuaternion.h>
+#include <OgreEntity.h>
+#include <OgreRenderSystem.h>
+#include <OgreRenderSystemCapabilities.h>
+#include <OgreHighLevelGpuProgram.h>
+#include <OgreHighLevelGpuProgramManager.h>
 using namespace Ogre;
 
+namespace PagedGeometry {
 
 //-------------------------------------------------------------------------------------
 
@@ -115,13 +116,13 @@
 	if (fadeEnabled != enabled){
 		fadeEnabled = enabled;
 
-		if (enabled) {
+// 		if (enabled) {
 			//Transparent batches should render after impostors
 			batch->setRenderQueueGroup(RENDER_QUEUE_6);
-		} else {
-			//Opaque batches should render in the normal render queue
-			batch->setRenderQueueGroup(RENDER_QUEUE_MAIN);
-		}
+// 		} else {
+// 			//Opaque batches should render in the normal render queue
+// 			batch->setRenderQueueGroup(RENDER_QUEUE_MAIN);
+// 		}
 
 		this->visibleDist = visibleDist;
 		this->invisibleDist = invisibleDist;
@@ -270,3 +271,4 @@
 	}
 
 }
+}
Index: source/BatchedGeometry.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/source/BatchedGeometry.cpp,v
retrieving revision 1.9
diff -b -U3 -r1.9 BatchedGeometry.cpp
--- source/BatchedGeometry.cpp	17 Jan 2008 02:35:32 -0000	1.9
+++ source/BatchedGeometry.cpp	23 Feb 2008 12:20:57 -0000
@@ -15,25 +15,26 @@
 
 #include "BatchedGeometry.h"
 
-#include "OgreRoot.h"
-#include "OgreRenderSystem.h"
-#include "OgreCamera.h"
-#include "OgreVector3.h"
-#include "OgreQuaternion.h"
-#include "OgreSceneNode.h"
-#include "OgreString.h"
-#include "OgreStringConverter.h"
-#include "OgreEntity.h"
-#include "OgreSubMesh.h"
-#include "OgreSubEntity.h"
-#include "OgreMesh.h"
-#include "OgreMeshManager.h"
-#include "OgreHardwareBufferManager.h"
-#include "OgreHardwareBuffer.h"
-#include "OgreMaterialManager.h"
-#include "OgreMaterial.h"
+#include <OgreRoot.h>
+#include <OgreRenderSystem.h>
+#include <OgreCamera.h>
+#include <OgreVector3.h>
+#include <OgreQuaternion.h>
+#include <OgreSceneNode.h>
+#include <OgreString.h>
+#include <OgreStringConverter.h>
+#include <OgreEntity.h>
+#include <OgreSubMesh.h>
+#include <OgreSubEntity.h>
+#include <OgreMesh.h>
+#include <OgreMeshManager.h>
+#include <OgreHardwareBufferManager.h>
+#include <OgreHardwareBuffer.h>
+#include <OgreMaterialManager.h>
+#include <OgreMaterial.h>
 using namespace Ogre;
 
+namespace PagedGeometry {
 
 //-------------------------------------------------------------------------------------
 
@@ -57,7 +58,7 @@
 void BatchedGeometry::addEntity(Entity *ent, const Vector3 &position, const Quaternion &orientation, const Vector3 &scale, const Ogre::ColourValue &color)
 {
 	//For each subentity
-	for (uint i = 0; i < ent->getNumSubEntities(); ++i){
+	for (Ogre::uint i = 0; i < ent->getNumSubEntities(); ++i){
 		//Get the subentity
 		SubEntity *subEntity = ent->getSubEntity(i);
 		SubMesh *subMesh = subEntity->getSubMesh();
@@ -234,7 +235,15 @@
 	built = false;
 
 	Material *origMat = ((MaterialPtr)MaterialManager::getSingleton().getByName(ent->getMaterialName())).getPointer();
+	if (origMat) {
 	material = MaterialManager::getSingleton().getByName(getMaterialClone(origMat)->getName());
+	} else {
+		MaterialManager::ResourceCreateOrRetrieveResult result = MaterialManager::getSingleton().createOrRetrieve("PagedGeometry_Batched_Material", "General");
+		if (result.first.isNull()) {
+			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "BatchedGeometry failed to create a material for entity with invalid material.", "BatchedGeometry::SubBatch::SubBatch(BatchedGeometry *parent, SubEntity *ent)");
+		}
+		material = result.first;
+	}
 
 	//Setup vertex/index data structure
 	vertexData = meshType->vertexData->clone(false);
@@ -651,4 +660,6 @@
 	return parent->queryLights();
 }
 
+}
+
 #endif
Index: source/GrassLoader.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/source/GrassLoader.cpp,v
retrieving revision 1.28
diff -b -U3 -r1.28 GrassLoader.cpp
--- source/GrassLoader.cpp	17 Jan 2008 02:35:32 -0000	1.28
+++ source/GrassLoader.cpp	23 Feb 2008 12:20:58 -0000
@@ -1,5 +1,6 @@
 /*-------------------------------------------------------------------------------------
 Copyright (c) 2006 John Judnich
+Modified 2008 by Erik Hjortsberg (erik.hjortsberg@iteam.se)
 
 This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
 Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
@@ -12,636 +13,33 @@
 #include "PagedGeometry.h"
 #include "PropertyMaps.h"
 
-#include "OgreRoot.h"
-#include "OgreTimer.h"
-#include "OgreCamera.h"
-#include "OgreVector3.h"
-#include "OgreQuaternion.h"
-#include "OgreEntity.h"
-#include "OgreString.h"
-#include "OgreStringConverter.h"
-#include "OgreMaterialManager.h"
-#include "OgreMaterial.h"
-#include "OgreHardwareBufferManager.h"
-#include "OgreHardwareBuffer.h"
-#include "OgreMeshManager.h"
-#include "OgreMesh.h"
-#include "OgreSubMesh.h"
-#include "OgreLogManager.h"
-#include "OgreTextureManager.h"
-#include "OgreHardwarePixelBuffer.h"
-#include "OgreRenderSystem.h"
-#include "OgreRenderSystemCapabilities.h"
-#include "OgreHighLevelGpuProgram.h"
-#include "OgreHighLevelGpuProgramManager.h"
+#include <OgreRoot.h>
+#include <OgreTimer.h>
+#include <OgreCamera.h>
+#include <OgreVector3.h>
+#include <OgreQuaternion.h>
+#include <OgreEntity.h>
+#include <OgreString.h>
+#include <OgreStringConverter.h>
+#include <OgreMaterialManager.h>
+#include <OgreMaterial.h>
+#include <OgreHardwareBufferManager.h>
+#include <OgreHardwareBuffer.h>
+#include <OgreMeshManager.h>
+#include <OgreMesh.h>
+#include <OgreSubMesh.h>
+#include <OgreLogManager.h>
+#include <OgreTextureManager.h>
+#include <OgreHardwarePixelBuffer.h>
+#include <OgreRenderSystem.h>
+#include <OgreRenderSystemCapabilities.h>
+#include <OgreHighLevelGpuProgram.h>
+#include <OgreHighLevelGpuProgramManager.h>
 using namespace Ogre;
 
+namespace PagedGeometry {
 
-unsigned long GrassLoader::GUID = 0;
-
-GrassLoader::GrassLoader(PagedGeometry *geom)
-{
-	GrassLoader::geom = geom;
-	
-	heightFunction = NULL;
-	heightFunctionUserData = NULL;
-
-	windDir = Vector3::UNIT_X;
-	densityFactor = 1.0f;
-	renderQueue = RENDER_QUEUE_6;
-
-	windTimer.reset();
-	lastTime = 0;
-}
-
-GrassLoader::~GrassLoader()
-{
-	std::list<GrassLayer*>::iterator it;
-	for (it = layerList.begin(); it != layerList.end(); ++it){
-		delete *it;
-	}
-	layerList.clear();
-}
-
-GrassLayer *GrassLoader::addLayer(const String &material)
-{
-	GrassLayer *layer = new GrassLayer(geom, this);
-	layer->setMaterialName(material);
-	layerList.push_back(layer);
-
-	return layer;
-}
-
-void GrassLoader::deleteLayer(GrassLayer *layer)
-{
-	layerList.remove(layer);
-	delete layer;
-}
-
-void GrassLoader::frameUpdate()
-{
-	unsigned long currentTime = windTimer.getMilliseconds();
-	unsigned long ellapsedTime = currentTime - lastTime;
-	lastTime = currentTime;
-
-	float ellapsed = ellapsedTime / 1000.0f;
-	
-	//Update the vertex shader parameters
-	std::list<GrassLayer*>::iterator it;
-	for (it = layerList.begin(); it != layerList.end(); ++it){
-		GrassLayer *layer = *it;
-
-		layer->_updateShaders();
-
-		GpuProgramParametersSharedPtr params = layer->material->getTechnique(0)->getPass(0)->getVertexProgramParameters();
-		if (layer->animate){
-			//Increment animation frame
-			layer->waveCount += ellapsed * (layer->animSpeed * Math::PI);
-			if (layer->waveCount > Math::PI*2) layer->waveCount -= Math::PI*2;
-
-			//Set vertex shader parameters
-			params->setNamedConstant("time", layer->waveCount);
-			params->setNamedConstant("frequency", layer->animFreq);
-
-			Vector3 direction = windDir * layer->animMag;
-			params->setNamedConstant("direction", Vector4(direction.x, direction.y, direction.z, 0));
-
-		}
-	}
-}
-
-void GrassLoader::loadPage(PageInfo &page)
-{
-	//Seed random number generator based on page indexes
-	uint16 xSeed = static_cast<uint16>(page.xIndex % 0xFFFF);
-	uint16 zSeed = static_cast<uint16>(page.zIndex % 0xFFFF);
-	uint32 seed = (xSeed << 16) | zSeed;
-	srand(seed);
-
-	std::list<GrassLayer*>::iterator it;
-	for (it = layerList.begin(); it != layerList.end(); ++it){
-		GrassLayer *layer = *it;
-
-		//Calculate how much grass needs to be added
-		float volume = page.bounds.width() * page.bounds.height();
-		unsigned int grassCount = layer->density * densityFactor * volume;
-
-		//The vertex buffer can't be allocated until the exact number of polygons is known,
-		//so the locations of all grasses in this page must be precalculated.
-
-		//Precompute grass locations into an array of floats. A plain array is used for speed;
-		//there's no need to use a dynamic sized array since a maximum size is known.
-		float *position = new float[grassCount*2];
-		if (layer->densityMap){
-			if (layer->densityMap->getFilter() == MAPFILTER_NONE)
-				grassCount = layer->_populateGrassList_UnfilteredDM(page, position, grassCount);
-			else if (layer->densityMap->getFilter() == MAPFILTER_BILINEAR)
-				grassCount = layer->_populateGrassList_BilinearDM(page, position, grassCount);
-		} else {
-			grassCount = layer->_populateGrassList_Uniform(page, position, grassCount);
-		}
-
-		//Don't build a mesh unless it contains something
-		if (grassCount != 0){
-			Mesh *mesh = NULL;
-			switch (layer->renderTechnique){
-				case GRASSTECH_QUAD:
-					mesh = generateGrass_QUAD(page, layer, position, grassCount);
-					break;
-				case GRASSTECH_CROSSQUADS:
-					mesh = generateGrass_CROSSQUADS(page, layer, position, grassCount);
-					break;
-				case GRASSTECH_SPRITE:
-					mesh = generateGrass_SPRITE(page, layer, position, grassCount);
-					break;
-			}
-			assert(mesh);
-
-			//Add the mesh to PagedGeometry
-			Entity *entity = geom->getCamera()->getSceneManager()->createEntity(getUniqueID(), mesh->getName());
-			entity->setRenderQueueGroup(renderQueue);
-			entity->setCastShadows(false);
-			addEntity(entity, page.centerPoint, Quaternion::IDENTITY, Vector3::UNIT_SCALE);
-			geom->getSceneManager()->destroyEntity(entity);
-
-			//Store the mesh pointer
-			page.userData = mesh;
-		} else {
-			//No mesh
-			page.userData = NULL;
-		}
-
-		//Delete the position list
-		delete[] position;
-	}
-}
-
-void GrassLoader::unloadPage(const PageInfo &page)
-{
-	//Unload mesh
-	Mesh *mesh = (Mesh*)page.userData;
-	if (mesh)
-		MeshManager::getSingleton().remove(mesh->getName());
-}
-
-Mesh *GrassLoader::generateGrass_QUAD(PageInfo &page, GrassLayer *layer, float *grassPositions, unsigned int grassCount)
-{
-	//Calculate the number of quads to be added
-	unsigned int quadCount;
-	quadCount = grassCount;
-
-	//Create manual mesh to store grass quads
-	MeshPtr mesh = MeshManager::getSingleton().createManual(getUniqueID(), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
-	SubMesh *subMesh = mesh->createSubMesh();
-	subMesh->useSharedVertices = false;
-
-	//Setup vertex format information
-	subMesh->vertexData = new VertexData;
-	subMesh->vertexData->vertexStart = 0;
-	subMesh->vertexData->vertexCount = 4 * quadCount;
-
-	VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
-	size_t offset = 0;
-	dcl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
-	offset += VertexElement::getTypeSize(VET_FLOAT3);
-	dcl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
-	offset += VertexElement::getTypeSize(VET_COLOUR);
-	dcl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
-	offset += VertexElement::getTypeSize(VET_FLOAT2);
-
-	//Populate a new vertex buffer with grass
-	HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton()
-		.createVertexBuffer(offset, subMesh->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
-	float* pReal = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
-
-	//Calculate size variance
-	float rndWidth = layer->maxWidth - layer->minWidth;
-	float rndHeight = layer->maxHeight - layer->minHeight;
-
-	float minY = Math::POS_INFINITY, maxY = Math::NEG_INFINITY;
-	float *posPtr = grassPositions;	//Position array "iterator"
-	for (uint16 i = 0; i < grassCount; ++i)
-	{
-		//Get the x and z positions from the position array
-		float x = *posPtr++;
-		float z = *posPtr++;
-
-		//Get the color at the grass position
-		uint32 color;
-		if (layer->colorMap)
-			color = layer->colorMap->getColorAt(x, z);
-		else
-			color = 0xFFFFFFFF;
-
-		//Calculate size
-		float rnd = Math::UnitRandom();	//The same rnd value is used for width and height to maintain aspect ratio
-		float halfScaleX = (layer->minWidth + rndWidth * rnd) * 0.5f;
-		float scaleY = (layer->minHeight + rndHeight * rnd);
-
-		//Calculate rotation
-		float angle = Math::RangeRandom(0, Math::TWO_PI);
-		float xTrans = Math::Cos(angle) * halfScaleX;
-		float zTrans = Math::Sin(angle) * halfScaleX;
-
-		//Calculate heights and edge positions
-		float x1 = x - xTrans, z1 = z - zTrans;
-		float x2 = x + xTrans, z2 = z + zTrans;
-
-		float y1, y2;
-		if (heightFunction){
-			y1 = heightFunction(x1, z1, heightFunctionUserData);
-			y2 = heightFunction(x2, z2, heightFunctionUserData);
-		} else {
-			y1 = 0;
-			y2 = 0;
-		}
-
-		//Add vertices
-		*pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1 + scaleY); *pReal++ = (z1 - page.centerPoint.z);	//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 0; *pReal++ = 0;								//uv
-
-		*pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2 + scaleY); *pReal++ = (z2 - page.centerPoint.z);	//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 1; *pReal++ = 0;								//uv
-
-		*pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1); *pReal++ = (z1 - page.centerPoint.z);			//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 0; *pReal++ = 1;								//uv
-
-		*pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2); *pReal++ = (z2 - page.centerPoint.z);			//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 1; *pReal++ = 1;								//uv
-
-		//Update bounds
-		if (y1 < minY) minY = y1;
-		if (y2 < minY) minY = y2;
-		if (y1 + scaleY > maxY) maxY = y1 + scaleY;
-		if (y2 + scaleY > maxY) maxY = y2 + scaleY;
-	}
-
-	vbuf->unlock();
-	subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
-
-	//Populate index buffer
-	subMesh->indexData->indexStart = 0;
-	subMesh->indexData->indexCount = 6 * quadCount;
-	subMesh->indexData->indexBuffer = HardwareBufferManager::getSingleton()
-		.createIndexBuffer(HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
-	uint16* pI = static_cast<uint16*>(subMesh->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
-	for (uint16 i = 0; i < quadCount; ++i)
-	{
-		uint16 offset = i * 4;
-
-		*pI++ = 0 + offset;
-		*pI++ = 2 + offset;
-		*pI++ = 1 + offset;
-
-		*pI++ = 1 + offset;
-		*pI++ = 2 + offset;
-		*pI++ = 3 + offset;
-	}
-
-	subMesh->indexData->indexBuffer->unlock();
-
-	//Finish up mesh
-	AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
-		page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
-	mesh->_setBounds(bounds);
-	Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
-	mesh->_setBoundingSphereRadius(temp.length() * 0.5f);
-
-	LogManager::getSingleton().setLogDetail(static_cast<LoggingLevel>(0));
-	mesh->load();
-	LogManager::getSingleton().setLogDetail(LL_NORMAL);
-
-	//Apply grass material to mesh
-	subMesh->setMaterialName(layer->material->getName());
-
-	//Return the mesh
-	return mesh.getPointer();
-}
-
-Mesh *GrassLoader::generateGrass_CROSSQUADS(PageInfo &page, GrassLayer *layer, float *grassPositions, unsigned int grassCount)
-{
-	//Calculate the number of quads to be added
-	unsigned int quadCount;
-	quadCount = grassCount * 2;
-
-	//Create manual mesh to store grass quads
-	MeshPtr mesh = MeshManager::getSingleton().createManual(getUniqueID(), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
-	SubMesh *subMesh = mesh->createSubMesh();
-	subMesh->useSharedVertices = false;
-
-	//Setup vertex format information
-	subMesh->vertexData = new VertexData;
-	subMesh->vertexData->vertexStart = 0;
-	subMesh->vertexData->vertexCount = 4 * quadCount;
-
-	VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
-	size_t offset = 0;
-	dcl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
-	offset += VertexElement::getTypeSize(VET_FLOAT3);
-	dcl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
-	offset += VertexElement::getTypeSize(VET_COLOUR);
-	dcl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
-	offset += VertexElement::getTypeSize(VET_FLOAT2);
-
-	//Populate a new vertex buffer with grass
-	HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton()
-		.createVertexBuffer(offset, subMesh->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
-	float* pReal = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
-
-	//Calculate size variance
-	float rndWidth = layer->maxWidth - layer->minWidth;
-	float rndHeight = layer->maxHeight - layer->minHeight;
-
-	float minY = Math::POS_INFINITY, maxY = Math::NEG_INFINITY;
-	float *posPtr = grassPositions;	//Position array "iterator"
-	for (uint16 i = 0; i < grassCount; ++i)
-	{
-		//Get the x and z positions from the position array
-		float x = *posPtr++;
-		float z = *posPtr++;
-
-		//Get the color at the grass position
-		uint32 color;
-		if (layer->colorMap)
-			color = layer->colorMap->getColorAt(x, z);
-		else
-			color = 0xFFFFFFFF;
-
-		//Calculate size
-		float rnd = Math::UnitRandom();	//The same rnd value is used for width and height to maintain aspect ratio
-		float halfScaleX = (layer->minWidth + rndWidth * rnd) * 0.5f;
-		float scaleY = (layer->minHeight + rndHeight * rnd);
-
-		//Calculate rotation
-		float angle = Math::RangeRandom(0, Math::TWO_PI);
-		float xTrans = Math::Cos(angle) * halfScaleX;
-		float zTrans = Math::Sin(angle) * halfScaleX;
-
-		//Calculate heights and edge positions
-		float x1 = x - xTrans, z1 = z - zTrans;
-		float x2 = x + xTrans, z2 = z + zTrans;
-
-		float y1, y2;
-		if (heightFunction){
-			y1 = heightFunction(x1, z1, heightFunctionUserData);
-			y2 = heightFunction(x2, z2, heightFunctionUserData);
-		} else {
-			y1 = 0;
-			y2 = 0;
-		}
-
-		//Add vertices
-		*pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1 + scaleY); *pReal++ = (z1 - page.centerPoint.z);	//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 0; *pReal++ = 0;								//uv
-
-		*pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2 + scaleY); *pReal++ = (z2 - page.centerPoint.z);	//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 1; *pReal++ = 0;								//uv
-
-		*pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1); *pReal++ = (z1 - page.centerPoint.z);			//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 0; *pReal++ = 1;								//uv
-
-		*pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2); *pReal++ = (z2 - page.centerPoint.z);			//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 1; *pReal++ = 1;								//uv
-
-		//Update bounds
-		if (y1 < minY) minY = y1;
-		if (y2 < minY) minY = y2;
-		if (y1 + scaleY > maxY) maxY = y1 + scaleY;
-		if (y2 + scaleY > maxY) maxY = y2 + scaleY;
-
-		//Calculate heights and edge positions
-		float x3 = x + zTrans, z3 = z - xTrans;
-		float x4 = x - zTrans, z4 = z + xTrans;
-
-		float y3, y4;
-		if (heightFunction){
-			y3 = heightFunction(x3, z3, heightFunctionUserData);
-			y4 = heightFunction(x4, z4, heightFunctionUserData);
-		} else {
-			y3 = 0;
-			y4 = 0;
-		}
-
-		//Add vertices
-		*pReal++ = (x3 - page.centerPoint.x); *pReal++ = (y3 + scaleY); *pReal++ = (z3 - page.centerPoint.z);	//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 0; *pReal++ = 0;								//uv
-
-		*pReal++ = (x4 - page.centerPoint.x); *pReal++ = (y4 + scaleY); *pReal++ = (z4 - page.centerPoint.z);	//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 1; *pReal++ = 0;								//uv
-
-		*pReal++ = (x3 - page.centerPoint.x); *pReal++ = (y3); *pReal++ = (z3 - page.centerPoint.z);			//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 0; *pReal++ = 1;								//uv
-
-		*pReal++ = (x4 - page.centerPoint.x); *pReal++ = (y4); *pReal++ = (z4 - page.centerPoint.z);			//pos
-		*((uint32*)pReal++) = color;							//color
-		*pReal++ = 1; *pReal++ = 1;								//uv
-
-		//Update bounds
-		if (y3 < minY) minY = y1;
-		if (y4 < minY) minY = y2;
-		if (y3 + scaleY > maxY) maxY = y3 + scaleY;
-		if (y4 + scaleY > maxY) maxY = y4 + scaleY;
-	}
-
-	vbuf->unlock();
-	subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
-
-	//Populate index buffer
-	subMesh->indexData->indexStart = 0;
-	subMesh->indexData->indexCount = 6 * quadCount;
-	subMesh->indexData->indexBuffer = HardwareBufferManager::getSingleton()
-		.createIndexBuffer(HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
-	uint16* pI = static_cast<uint16*>(subMesh->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
-	for (uint16 i = 0; i < quadCount; ++i)
-	{
-		uint16 offset = i * 4;
-
-		*pI++ = 0 + offset;
-		*pI++ = 2 + offset;
-		*pI++ = 1 + offset;
-
-		*pI++ = 1 + offset;
-		*pI++ = 2 + offset;
-		*pI++ = 3 + offset;
-	}
-
-	subMesh->indexData->indexBuffer->unlock();
-
-	//Finish up mesh
-	AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
-		page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
-	mesh->_setBounds(bounds);
-	Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
-	mesh->_setBoundingSphereRadius(temp.length() * 0.5f);
-
-	LogManager::getSingleton().setLogDetail(static_cast<LoggingLevel>(0));
-	mesh->load();
-	LogManager::getSingleton().setLogDetail(LL_NORMAL);
-
-	//Apply grass material to mesh
-	subMesh->setMaterialName(layer->material->getName());
-
-	//Return the mesh
-	return mesh.getPointer();
-}
-
-Mesh *GrassLoader::generateGrass_SPRITE(PageInfo &page, GrassLayer *layer, float *grassPositions, unsigned int grassCount)
-{
-	//Calculate the number of quads to be added
-	unsigned int quadCount;
-	quadCount = grassCount;
-
-	//Create manual mesh to store grass quads
-	MeshPtr mesh = MeshManager::getSingleton().createManual(getUniqueID(), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
-	SubMesh *subMesh = mesh->createSubMesh();
-	subMesh->useSharedVertices = false;
-
-	//Setup vertex format information
-	subMesh->vertexData = new VertexData;
-	subMesh->vertexData->vertexStart = 0;
-	subMesh->vertexData->vertexCount = 4 * quadCount;
-
-	VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
-	size_t offset = 0;
-	dcl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
-	offset += VertexElement::getTypeSize(VET_FLOAT3);
-	dcl->addElement(0, offset, VET_FLOAT4, VES_NORMAL);
-	offset += VertexElement::getTypeSize(VET_FLOAT4);
-	dcl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
-	offset += VertexElement::getTypeSize(VET_COLOUR);
-	dcl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
-	offset += VertexElement::getTypeSize(VET_FLOAT2);
-
-	//Populate a new vertex buffer with grass
-	HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton()
-		.createVertexBuffer(offset, subMesh->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
-	float* pReal = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
-
-	//Calculate size variance
-	float rndWidth = layer->maxWidth - layer->minWidth;
-	float rndHeight = layer->maxHeight - layer->minHeight;
-
-	float minY = Math::POS_INFINITY, maxY = Math::NEG_INFINITY;
-	float *posPtr = grassPositions;	//Position array "iterator"
-	for (uint16 i = 0; i < grassCount; ++i)
-	{
-		//Get the x and z positions from the position array
-		float x = *posPtr++;
-		float z = *posPtr++;
-
-		//Calculate height
-		float y;
-		if (heightFunction){
-			y = heightFunction(x, z, heightFunctionUserData);
-		} else {
-			y = 0;
-		}
-
-		float x1 = (x - page.centerPoint.x);
-		float z1 = (z - page.centerPoint.z);
-
-		//Get the color at the grass position
-		uint32 color;
-		if (layer->colorMap)
-			color = layer->colorMap->getColorAt(x, z);
-		else
-			color = 0xFFFFFFFF;
-
-		//Calculate size
-		float rnd = Math::UnitRandom();	//The same rnd value is used for width and height to maintain aspect ratio
-		float halfXScale = (layer->minWidth + rndWidth * rnd) * 0.5f;
-		float scaleY = (layer->minHeight + rndHeight * rnd);
-
-		//Randomly mirror grass textures
-		float uvLeft, uvRight;
-		if (Math::UnitRandom() > 0.5f){
-			uvLeft = 0;
-			uvRight = 1;
-		} else {
-			uvLeft = 1;
-			uvRight = 0;
-		}
-
-		//Add vertices
-		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
-		*pReal++ = -halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0;	//normal (used to store relative corner positions)
-		*((uint32*)pReal++) = color;								//color
-		*pReal++ = uvLeft; *pReal++ = 0;							//uv
-
-		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
-		*pReal++ = +halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0;	//normal (used to store relative corner positions)
-		*((uint32*)pReal++) = color;								//color
-		*pReal++ = uvRight; *pReal++ = 0;							//uv
-
-		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
-		*pReal++ = -halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0;		//normal (used to store relative corner positions)
-		*((uint32*)pReal++) = color;								//color
-		*pReal++ = uvLeft; *pReal++ = 1;							//uv
-
-		*pReal++ = x1; *pReal++ = y; *pReal++ = z1;					//center position
-		*pReal++ = +halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0;		//normal (used to store relative corner positions)
-		*((uint32*)pReal++) = color;								//color
-		*pReal++ = uvRight; *pReal++ = 1;							//uv
-
-		//Update bounds
-		if (y < minY) minY = y;
-		if (y + scaleY > maxY) maxY = y + scaleY;
-	}
-
-	vbuf->unlock();
-	subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
-
-	//Populate index buffer
-	subMesh->indexData->indexStart = 0;
-	subMesh->indexData->indexCount = 6 * quadCount;
-	subMesh->indexData->indexBuffer = HardwareBufferManager::getSingleton()
-		.createIndexBuffer(HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
-	uint16* pI = static_cast<uint16*>(subMesh->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
-	for (uint16 i = 0; i < quadCount; ++i)
-	{
-		uint16 offset = i * 4;
-
-		*pI++ = 0 + offset;
-		*pI++ = 2 + offset;
-		*pI++ = 1 + offset;
-
-		*pI++ = 1 + offset;
-		*pI++ = 2 + offset;
-		*pI++ = 3 + offset;
-	}
-
-	subMesh->indexData->indexBuffer->unlock();
-
-	//Finish up mesh
-	AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
-		page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
-	mesh->_setBounds(bounds);
-	Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
-	mesh->_setBoundingSphereRadius(temp.length() * 0.5f);
-
-	LogManager::getSingleton().setLogDetail(static_cast<LoggingLevel>(0));
-	mesh->load();
-	LogManager::getSingleton().setLogDetail(LL_NORMAL);
-
-	//Apply grass material to mesh
-	subMesh->setMaterialName(layer->material->getName());
-
-	//Return the mesh
-	return mesh.getPointer();
-}
-
-GrassLayer::GrassLayer(PagedGeometry *geom, GrassLoader *ldr)
+GrassLayer::GrassLayer(PagedGeometry *geom, GrassLoader<GrassLayer> *ldr)
 {
 	GrassLayer::geom = geom;
 	GrassLayer::parent = ldr;
@@ -674,7 +72,24 @@
 		colorMap->unload();
 }
 
-void GrassLayer::setMaterialName(const String &matName)
+unsigned int GrassLayer::calculateMaxGrassCount(float densityFactor, float volume)
+{
+	return density * densityFactor * volume;
+}
+
+unsigned int GrassLayer::_populateGrassList(PageInfo page, float *posBuff, unsigned int grassCount)
+{
+	if (densityMap){
+		if (densityMap->getFilter() == MAPFILTER_NONE)
+			return _populateGrassList_UnfilteredDM(page, posBuff, grassCount);
+		else if (densityMap->getFilter() == MAPFILTER_BILINEAR)
+			return _populateGrassList_BilinearDM(page, posBuff, grassCount);
+	}
+	return _populateGrassList_Uniform(page, posBuff, grassCount);
+	
+}
+
+void GrassLayerBase::setMaterialName(const String &matName)
 {
 	if (material.isNull() || matName != material->getName()){
 		material = MaterialManager::getSingleton().getByName(matName);
@@ -684,13 +99,13 @@
 	}
 }
 
-void GrassLayer::setMinimumSize(float width, float height)
+void GrassLayerBase::setMinimumSize(float width, float height)
 {
 	minWidth = width;
 	minHeight = height;
 }
 
-void GrassLayer::setMaximumSize(float width, float height)
+void GrassLayerBase::setMaximumSize(float width, float height)
 {
 	maxWidth = width;
 	if (maxHeight != height){
@@ -699,7 +114,7 @@
 	}
 }
 
-void GrassLayer::setRenderTechnique(GrassTechnique style, bool blendBase)
+void GrassLayerBase::setRenderTechnique(GrassTechnique style, bool blendBase)
 {
 	if (blend != blendBase || renderTechnique != style){
 		blend = blendBase;
@@ -708,7 +123,7 @@
 	}
 }
 
-void GrassLayer::setFadeTechnique(FadeTechnique style)
+void GrassLayerBase::setFadeTechnique(FadeTechnique style)
 {
 	if (fadeTechnique != style){
 		fadeTechnique = style;
@@ -716,7 +131,7 @@
 	}
 }
 
-void GrassLayer::setAnimationEnabled(bool enabled)
+void GrassLayerBase::setAnimationEnabled(bool enabled)
 {
 	if (animate != enabled){
 		animate = enabled;
@@ -943,7 +358,7 @@
 		colorMap->setFilter(colorMapFilter);
 }
 
-void GrassLayer::_updateShaders()
+void GrassLayerBase::_updateShaders()
 {
 	if (shaderNeedsUpdate){
 		shaderNeedsUpdate = false;
@@ -1149,3 +564,4 @@
 		node->setVisible(visible);
 	}
 }
+}
Index: source/ImpostorPage.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/source/ImpostorPage.cpp,v
retrieving revision 1.30
diff -b -U3 -r1.30 ImpostorPage.cpp
--- source/ImpostorPage.cpp	7 Feb 2008 03:51:51 -0000	1.30
+++ source/ImpostorPage.cpp	23 Feb 2008 12:20:58 -0000
@@ -1,5 +1,6 @@
 /*-------------------------------------------------------------------------------------
 Copyright (c) 2006 John Judnich
+Modified 2008 by Erik Hjortsberg (erik.hjortsberg@iteam.se)
 
 This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
 Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
@@ -15,16 +16,17 @@
 #include "ImpostorPage.h"
 #include "StaticBillboardSet.h"
 
-#include "OgreRoot.h"
-#include "OgreTimer.h"
-#include "OgreCamera.h"
-#include "OgreVector3.h"
-#include "OgreQuaternion.h"
-#include "OgreEntity.h"
-#include "OgreSubEntity.h"
-#include "OgreHardwarePixelBuffer.h"
+#include <OgreRoot.h>
+#include <OgreTimer.h>
+#include <OgreCamera.h>
+#include <OgreVector3.h>
+#include <OgreQuaternion.h>
+#include <OgreEntity.h>
+#include <OgreSubEntity.h>
+#include <OgreHardwarePixelBuffer.h>
 using namespace Ogre;
 
+namespace PagedGeometry {
 
 //-------------------------------------------------------------------------------------
 
@@ -285,21 +287,37 @@
 {
 	StringUtil::StrStreamType entityKey;
 	entityKey << entity->getMesh()->getName();
-	for (uint i = 0; i < entity->getNumSubEntities(); ++i){
+	for (Ogre::uint i = 0; i < entity->getNumSubEntities(); ++i){
 		entityKey << "-" << entity->getSubEntity(i)->getMaterialName();
 	}
-
 	return entityKey.str();
 }
 
 //-------------------------------------------------------------------------------------
 
+
+ImpostorTextureResourceLoader::ImpostorTextureResourceLoader(ImpostorTexture& impostorTexture)
+: texture(impostorTexture)
+{
+}
+
+void ImpostorTextureResourceLoader::loadResource (Ogre::Resource *resource)
+{
+	if (resource->getLoadingState() == Ogre::Resource::LOADSTATE_UNLOADED) {
+		texture.regenerate();
+	}
+}
+
+//-------------------------------------------------------------------------------------
+
+
 std::map<String, ImpostorTexture *> ImpostorTexture::selfList;
 unsigned long ImpostorTexture::GUID = 0;
 
 //Do not use this constructor yourself - instead, call getTexture()
 //to get/create an ImpostorTexture for an Entity.
 ImpostorTexture::ImpostorTexture(ImpostorPage *group, Entity *entity)
+: loader(0)
 {
 	//Store scene manager and entity
 	ImpostorTexture::sceneMgr = group->sceneMgr;
@@ -361,7 +379,7 @@
 			Material *m = material[i][o].getPointer();
 			Pass *p = m->getTechnique(0)->getPass(0);       
 
-			int x = p->getNumTextureUnitStates();
+// 			int x = p->getNumTextureUnitStates();
 			TextureUnitState *t = p->getTextureUnitState(0);
 
 			t->setTextureName(texture->getName());
@@ -417,15 +435,23 @@
 
 void ImpostorTexture::renderTextures(bool force)
 {
+#if IMPOSTOR_FILE_SAVE
 	TexturePtr renderTexture;
+#else
+	TexturePtr renderTexture(texture);
+	//if we're not using a file image we need to set up a resource loader, so that the texture is regenerated if it's ever unloaded (such as switching between fullscreen and the desktop in win32)
+	loader = std::auto_ptr<ImpostorTextureResourceLoader>(new ImpostorTextureResourceLoader(*this));
+#endif
 	RenderTexture *renderTarget;
 	Camera *renderCamera;
 	Viewport *renderViewport;
 
 	//Set up RTT texture
 	unsigned int textureSize = ImpostorPage::impostorResolution;
+	if (renderTexture.isNull()) {
 	renderTexture = TextureManager::getSingleton().createManual(getUniqueID("ImpostorTexture"), "Impostors",
-				TEX_TYPE_2D, textureSize * IMPOSTOR_YAW_ANGLES, textureSize * IMPOSTOR_PITCH_ANGLES, 0, PF_A8R8G8B8, TU_RENDERTARGET);
+				TEX_TYPE_2D, textureSize * IMPOSTOR_YAW_ANGLES, textureSize * IMPOSTOR_PITCH_ANGLES, 0, PF_A8R8G8B8, TU_RENDERTARGET, loader.get());
+	}
 	renderTexture->setNumMipmaps(MIP_UNLIMITED);
 	
 	//Set up render target
@@ -444,6 +470,10 @@
 	//Set up scene node
 	SceneNode* node = sceneMgr->getSceneNode("ImpostorPage::renderNode");
 	
+	Ogre::SceneNode* oldSceneNode = entity->getParentSceneNode();
+	if (oldSceneNode) {
+		oldSceneNode->detachObject(entity);
+	}
 	node->attachObject(entity);
 	node->setPosition(-entityCenter);
 	
@@ -476,9 +506,15 @@
 	sceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_INCLUDE); 
 	sceneMgr->addSpecialCaseRenderQueue(RENDER_QUEUE_6 + 1);
 
-	//uint8 oldRenderQueueGroup = entity->getRenderQueueGroup();
+	uint8 oldRenderQueueGroup = entity->getRenderQueueGroup();
 	entity->setRenderQueueGroup(RENDER_QUEUE_6 + 1);
+	bool oldVisible = entity->getVisible();
+	entity->setVisible(true);
+	float oldMaxDistance = entity->getRenderingDistance();
+	entity->setRenderingDistance(0);
 
+	bool needsRegen = true;
+#if IMPOSTOR_FILE_SAVE
 	//Calculate the filename used to uniquely identity this render
 	String strKey = entityKey;
 	char key[32] = {0};
@@ -495,7 +531,7 @@
 	String fileName = "Impostor." + String(key, sizeof(key)) + '.' + StringConverter::toString(textureSize) + ".png";
 
 	//Attempt to load the pre-render file if allowed
-	bool needsRegen = force;
+	needsRegen = force;
 	if (!needsRegen){
 		try{
 			texture = TextureManager::getSingleton().load(fileName, "BinFolder", TEX_TYPE_2D, MIP_UNLIMITED);
@@ -504,6 +540,7 @@
 			needsRegen = true;
 		}
 	}
+#endif
 
 	if (needsRegen){
 		//If this has not been pre-rendered, do so now
@@ -528,15 +565,21 @@
 			}
 		}
 		
+#if IMPOSTOR_FILE_SAVE
 		//Save RTT to file
 		renderTarget->writeContentsToFile(fileName);
 
 		//Load the render into the appropriate texture view
 		texture = TextureManager::getSingleton().load(fileName, "BinFolder", TEX_TYPE_2D, MIP_UNLIMITED);
+#else
+		texture = renderTexture;
+#endif
 	}
 	
 
-	//entity->setRenderQueueGroup(oldRenderQueueGroup);
+	entity->setVisible(oldVisible);
+	entity->setRenderQueueGroup(oldRenderQueueGroup);
+	entity->setRenderingDistance(oldMaxDistance);
 	sceneMgr->removeSpecialCaseRenderQueue(RENDER_QUEUE_6 + 1);
 	sceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); 
 
@@ -552,7 +595,10 @@
 	
 	//Delete scene node
 	node->detachAllObjects();
-
+	if (oldSceneNode) {
+		oldSceneNode->attachObject(entity);
+	}
+#if IMPOSTOR_FILE_SAVE
 	//Delete RTT texture
 	assert(!renderTexture.isNull());
 	String texName2(renderTexture->getName());
@@ -560,6 +606,7 @@
 	renderTexture.setNull();
 	if (TextureManager::getSingletonPtr())
 		TextureManager::getSingleton().remove(texName2);
+#endif
 }
 
 String ImpostorTexture::removeInvalidCharacters(String s)
@@ -614,3 +661,4 @@
 		}
 	}
 }
+}
Index: source/PagedGeometry.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/source/PagedGeometry.cpp,v
retrieving revision 1.28
diff -b -U3 -r1.28 PagedGeometry.cpp
--- source/PagedGeometry.cpp	13 Dec 2007 23:33:30 -0000	1.28
+++ source/PagedGeometry.cpp	23 Feb 2008 12:20:58 -0000
@@ -15,12 +15,13 @@
 #include "PagedGeometry.h"
 #include "StaticBillboardSet.h"
 
-#include "OgreRoot.h"
-#include "OgreTimer.h"
-#include "OgreCamera.h"
-#include "OgreVector3.h"
+#include <OgreRoot.h>
+#include <OgreTimer.h>
+#include <OgreCamera.h>
+#include <OgreVector3.h>
 using namespace Ogre;
 
+namespace PagedGeometry {
 
 //-------------------------------------------------------------------------------------
 PagedGeometry::PagedGeometry(Camera* cam, const Real pageSize)
@@ -807,3 +808,4 @@
 	_trueBounds = AxisAlignedBox(0, 0, 0, 0, 0, 0);
 	_trueBoundsUndefined = true;
 }
\ No newline at end of file
+}
Index: source/PropertyMaps.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/source/PropertyMaps.cpp,v
retrieving revision 1.4
diff -b -U3 -r1.4 PropertyMaps.cpp
--- source/PropertyMaps.cpp	15 Oct 2007 21:18:39 -0000	1.4
+++ source/PropertyMaps.cpp	23 Feb 2008 12:20:59 -0000
@@ -10,17 +10,18 @@
 
 #include "PropertyMaps.h"
 
-#include "OgreRoot.h"
-#include "OgrePrerequisites.h"
-#include "OgrePixelFormat.h"
-#include "OgreTexture.h"
-#include "OgreTextureManager.h"
-#include "OgreHardwarePixelBuffer.h"
-#include "OgreRenderSystem.h"
-#include "OgreString.h"
-#include "OgreStringConverter.h"
+#include <OgreRoot.h>
+#include <OgrePrerequisites.h>
+#include <OgrePixelFormat.h>
+#include <OgreTexture.h>
+#include <OgreTextureManager.h>
+#include <OgreHardwarePixelBuffer.h>
+#include <OgreRenderSystem.h>
+#include <OgreString.h>
+#include <OgreStringConverter.h>
 using namespace Ogre;
 
+namespace PagedGeometry {
 
 std::map<Ogre::String, DensityMap*> DensityMap::selfList;
 
@@ -60,7 +61,7 @@
 DensityMap::~DensityMap()
 {
 	assert(pixels);
-	delete[] pixels->data;
+	delete[] static_cast<uint8*>(pixels->data);
 	delete pixels;
 
 	//Remove self from selfList
@@ -114,7 +115,7 @@
 		}
 
 		//Finally, delete the temporary PF_R8G8B8A8 pixel buffer
-		delete[] tmpPixels.data;
+		delete[] static_cast<uint8*>(tmpPixels.data);
 	}
 }
 
@@ -222,7 +223,7 @@
 ColorMap::~ColorMap()
 {
 	assert(pixels);
-	delete[] pixels->data;
+	delete[] static_cast<uint8*>(pixels->data);
 	delete pixels;
 
 	//Remove self from selfList
@@ -296,7 +297,7 @@
 		}
 
 		//Finally, delete the temporary PF_R8G8B8A8 pixel buffer
-		delete[] tmpPixels.data;
+		delete[] static_cast<uint8*>(tmpPixels.data);
 	}
 }
 
@@ -379,3 +380,4 @@
 
 	return val;
 }
+}
Index: source/StaticBillboardSet.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/source/StaticBillboardSet.cpp,v
retrieving revision 1.21
diff -b -U3 -r1.21 StaticBillboardSet.cpp
--- source/StaticBillboardSet.cpp	13 Dec 2007 23:33:30 -0000	1.21
+++ source/StaticBillboardSet.cpp	23 Feb 2008 12:21:00 -0000
@@ -16,29 +16,30 @@
 
 #include "StaticBillboardSet.h"
 
-#include "OgreRoot.h"
-#include "OgreCamera.h"
-#include "OgreVector3.h"
-#include "OgreMeshManager.h"
-#include "OgreMesh.h"
-#include "OgreSubMesh.h"
-#include "OgreMaterialManager.h"
-#include "OgreMaterial.h"
-#include "OgreBillboardSet.h"
-#include "OgreBillboard.h"
-#include "OgreSceneNode.h"
-#include "OgreString.h"
-#include "OgreStringConverter.h"
-#include "OgreRenderSystem.h"
-#include "OgreRenderSystemCapabilities.h"
-#include "OgreHighLevelGpuProgramManager.h"
-#include "OgreHighLevelGpuProgram.h"
-#include "OgreHardwareBufferManager.h"
-#include "OgreHardwareBuffer.h"
-#include "OgreLogManager.h"
-#include "OgreEntity.h"
+#include <OgreRoot.h>
+#include <OgreCamera.h>
+#include <OgreVector3.h>
+#include <OgreMeshManager.h>
+#include <OgreMesh.h>
+#include <OgreSubMesh.h>
+#include <OgreMaterialManager.h>
+#include <OgreMaterial.h>
+#include <OgreBillboardSet.h>
+#include <OgreBillboard.h>
+#include <OgreSceneNode.h>
+#include <OgreString.h>
+#include <OgreStringConverter.h>
+#include <OgreRenderSystem.h>
+#include <OgreRenderSystemCapabilities.h>
+#include <OgreHighLevelGpuProgramManager.h>
+#include <OgreHighLevelGpuProgram.h>
+#include <OgreHardwareBufferManager.h>
+#include <OgreHardwareBuffer.h>
+#include <OgreLogManager.h>
+#include <OgreEntity.h>
 using namespace Ogre;
 
+namespace PagedGeometry {
 
 //-------------------------------------------------------------------------------------
 
@@ -704,3 +705,4 @@
 	origin = o;
 	refCount = 1;
 }
+}
Index: source/TreeLoader2D.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/source/TreeLoader2D.cpp,v
retrieving revision 1.14
diff -b -U3 -r1.14 TreeLoader2D.cpp
--- source/TreeLoader2D.cpp	6 Feb 2008 21:40:33 -0000	1.14
+++ source/TreeLoader2D.cpp	23 Feb 2008 12:21:01 -0000
@@ -12,14 +12,15 @@
 #include "PagedGeometry.h"
 #include "PropertyMaps.h"
 
-#include "OgreRoot.h"
-#include "OgreException.h"
-#include "OgreVector3.h"
-#include "OgreQuaternion.h"
-#include "OgreLogManager.h"
-#include "OgreStringConverter.h"
+#include <OgreRoot.h>
+#include <OgreException.h>
+#include <OgreVector3.h>
+#include <OgreQuaternion.h>
+#include <OgreLogManager.h>
+#include <OgreStringConverter.h>
 using namespace Ogre;
 
+namespace PagedGeometry {
 
 TreeLoader2D::TreeLoader2D(PagedGeometry *geom, const TRect<Real> &bounds)
 {
@@ -397,3 +398,4 @@
 	//Get entity
 	currentTreeDat.entity = currentGrid->first;
 }
\ No newline at end of file
+}
Index: source/TreeLoader3D.cpp
===================================================================
RCS file: /cvsroot/ogre/ogreaddons/forests/source/TreeLoader3D.cpp,v
retrieving revision 1.12
diff -b -U3 -r1.12 TreeLoader3D.cpp
--- source/TreeLoader3D.cpp	6 Feb 2008 21:40:33 -0000	1.12
+++ source/TreeLoader3D.cpp	23 Feb 2008 12:21:01 -0000
@@ -12,12 +12,13 @@
 #include "PagedGeometry.h"
 #include "PropertyMaps.h"
 
-#include "OgreRoot.h"
-#include "OgreException.h"
-#include "OgreVector3.h"
-#include "OgreQuaternion.h"
+#include <OgreRoot.h>
+#include <OgreException.h>
+#include <OgreVector3.h>
+#include <OgreQuaternion.h>
 using namespace Ogre;
 
+namespace PagedGeometry {
 
 TreeLoader3D::TreeLoader3D(PagedGeometry *geom, const TRect<Real> &bounds)
 {
@@ -376,3 +377,4 @@
 	//Get entity
 	currentTreeDat.entity = currentGrid->first;
 }
\ No newline at end of file
+}

