~ubuntu-branches/debian/sid/ember/sid

« back to all changes in this revision

Viewing changes to src/components/ogre/environment/pagedgeometry/include/GrassLoader.h

  • Committer: Bazaar Package Importer
  • Author(s): Michael Koch
  • Date: 2009-07-23 07:46:40 UTC
  • Revision ID: james.westby@ubuntu.com-20090723074640-wh0ukzis0kda36qv
Tags: upstream-0.5.6
ImportĀ upstreamĀ versionĀ 0.5.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------------------
 
2
Copyright (c) 2006 John Judnich
 
3
Modified 2008 by Erik Hjortsberg (erik.hjortsberg@gmail.com)
 
4
 
 
5
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.
 
6
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:
 
7
    1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
 
8
    2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
 
9
    3. This notice may not be removed or altered from any source distribution.
 
10
-------------------------------------------------------------------------------------*/
 
11
 
 
12
#ifndef __GrassLoader_H__
 
13
#define __GrassLoader_H__
 
14
 
 
15
#include "PagedGeometry.h"
 
16
#include "PropertyMaps.h"
 
17
 
 
18
#include <OgrePrerequisites.h>
 
19
#include <OgreMaterial.h>
 
20
#include <OgrePixelFormat.h>
 
21
#include <OgreStringConverter.h>
 
22
#include <OgreMeshManager.h>
 
23
 
 
24
 
 
25
#include <OgreRoot.h>
 
26
#include <OgreTimer.h>
 
27
#include <OgreCamera.h>
 
28
#include <OgreVector3.h>
 
29
#include <OgreQuaternion.h>
 
30
#include <OgreEntity.h>
 
31
#include <OgreString.h>
 
32
#include <OgreStringConverter.h>
 
33
#include <OgreMaterialManager.h>
 
34
#include <OgreMaterial.h>
 
35
#include <OgreHardwareBufferManager.h>
 
36
#include <OgreHardwareBuffer.h>
 
37
#include <OgreMeshManager.h>
 
38
#include <OgreMesh.h>
 
39
#include <OgreSubMesh.h>
 
40
#include <OgreLogManager.h>
 
41
#include <OgreTextureManager.h>
 
42
#include <OgreHardwarePixelBuffer.h>
 
43
#include <OgreRenderSystem.h>
 
44
#include <OgreRenderSystemCapabilities.h>
 
45
#include <OgreHighLevelGpuProgram.h>
 
46
#include <OgreHighLevelGpuProgramManager.h>
 
47
 
 
48
namespace PagedGeometry {
 
49
 
 
50
class GrassLayer;
 
51
class GrassLayerBase;
 
52
 
 
53
/** \brief A PageLoader-derived object you can use with PagedGeometry to produce realistic grass. 
 
54
 
 
55
Using a GrassLoader is simple - simply create an instance, attach it to your PagedGeometry object
 
56
with PagedGeometry::setPageLoader(), and add your grass. Important: For best performance, it is
 
57
recommended that you use GrassPage (included in GrassLoader.h) to display geometry loaded by GrassLoader.
 
58
 
 
59
This page type is designed for best performance with this grass system. BatchPage
 
60
will work, although performance will be reduced slightly, and ImpostorPage will run extremely slow.
 
61
 
 
62
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:
 
63
\code
 
64
        ::PagedGeometry::GrassLoader<GrassLayer> loader = new ::PagedGeometry::GrassLoader<GrassLayer>(grass);
 
65
\endcode
 
66
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.
 
67
 
 
68
 
 
69
To add grass, just call addLayer(). addLayer() returns a GrassLayer object pointer, which you should
 
70
use to further configure your newly added grass. Properties like size, density, color, animation, etc.
 
71
can be controlled through the GrassLayer class.
 
72
 
 
73
\note By default, the GrassLoader doesn't know what shape your terrain so all grass will be placed at
 
74
0 height. To inform GrassLoader of the shape of your terrain, you must specify a height function
 
75
that returns the height (y coordinate) of your terrain at the given x and z coordinates. See
 
76
the TreeLoader2D::setHeightFunction() documentation for more information.
 
77
 
 
78
\warning If you attempt to use Ogre's scene queries to get the terrain height,
 
79
keep in mind that calculating the height of Ogre's built-in terrain this way can
 
80
be VERY slow if not done properly, and may cause stuttering due to long paging delays.
 
81
*/
 
82
template <typename TGrassLayer>
 
83
class GrassLoader: public PageLoader
 
84
{
 
85
public:
 
86
        /** \brief Creates a new GrassLoader object. 
 
87
        \param geom The PagedGeometry object that this GrassLoader will be assigned to.*/
 
88
        inline GrassLoader(PagedGeometry *geom);
 
89
        ~GrassLoader();
 
90
 
 
91
        /** \brief Adds a grass layer to the scene.
 
92
        \param material The initial grass texture to use (this can be changed later).
 
93
        
 
94
        Since all grass is potentially infinite, it is not added like normal entities which
 
95
        have a specific position. Instead you add a grass "layer" to the scene. A grass layer
 
96
        is a "carpet" of a single type of grass that gets applied everywhere in your world.
 
97
        If you want multiple types of grass with different appearances, you'll have to add
 
98
        a multiple grass layers for each style.
 
99
        
 
100
        Of course, a grass layer is not completely uniform. The GrassLayer class contains
 
101
        functions to vary grass size and density levels as desired.
 
102
 
 
103
        \see GrassLayer class for more information. */
 
104
        TGrassLayer *addLayer(const Ogre::String &material);
 
105
 
 
106
        /** \brief Removes and deletes a grass layer from the scene
 
107
 
 
108
        This function simply deletes a GrassLayer previously created with addLayer(). */
 
109
        void deleteLayer(TGrassLayer *layer);
 
110
 
 
111
        /** \brief Returns a list of added grass layers.
 
112
        
 
113
        This function returns a std::list<GrassLayer*> reference, which contains all grass
 
114
        layers which have been added to this GrassLoader. */
 
115
        inline std::list<TGrassLayer*> &getLayerList() { return layerList; }
 
116
 
 
117
        /** \brief Sets the global wind direction for this GrassLoader.
 
118
 
 
119
        GrassLayer animation properties are used to configure the most of the animation
 
120
        behavour (sway length, speed, etc.), but wind direction is not included in GrassLayer
 
121
        since this is really a global property. Using this function, you can set the "global"
 
122
        wind direction which affects all animated grass associated with this PageLoader.
 
123
 
 
124
        Default value is Vector3::UNIT_X.
 
125
                
 
126
        \note This only affects grass layers which have breeze animations enabled.
 
127
        */
 
128
        inline void setWindDirection(Ogre::Vector3 &dir) { windDir = dir; }
 
129
 
 
130
        /** \brief Returns the global wind direction for this GrassLoader.
 
131
 
 
132
        \see setWindDirection() for more information about the wind direction. */
 
133
        inline Ogre::Vector3 &getWindDirection() { return windDir; }
 
134
 
 
135
        /** \brief Sets the global density factor for this GrassLoader.
 
136
 
 
137
        This function can be used to up-scale or down-scale the density of all grass
 
138
        associated with this GrassLoader. This is typically used to provide the user
 
139
        the option to reduce grass density for better performance on slower machines.
 
140
 
 
141
        Final density values are calculated by multiplying the layer density by this
 
142
        density factor. For example, a layer with .4 density and a density factor of .5
 
143
        will result in a final density of .2 (.5 * .4)
 
144
 
 
145
        By default, the density factor is set to 1.0 so the layer density is not modified.
 
146
        */
 
147
        inline void setDensityFactor(float density) { densityFactor = density; }
 
148
 
 
149
        /** \brief Returns the global density factor for this GrassLoader.
 
150
 
 
151
        \see setDensityFactor() for more information about the density factor. */
 
152
        inline float getDensityFactor() { return densityFactor; }
 
153
 
 
154
        /** \brief Sets the render queue group the grass will be rendered through
 
155
        \param queueID Enumerated value of the queue group to use
 
156
        
 
157
        Like Ogre's MovableObject::setRenderQueueGroup(), this allows you to customize
 
158
        the rendering order of your scene. Since grass is transparent, it's likely that
 
159
        you may encounter alpha-sorting issues between grass and your particle effects,
 
160
        for example. In this case you can use this function to adjust the rendering order
 
161
        of the grass to fix the problem.
 
162
 
 
163
        If you don't call this function, the RENDER_QUEUE_6 queue will be used.
 
164
 
 
165
        \note Once grass is loaded and being rendered, this won't have any effect on it.
 
166
        Be sure to call this function before the scene begins rendering, otherwise you will
 
167
        have to call PagedGeometry::reloadGeometry() to force a reload in order for the changes
 
168
        to take effect. */
 
169
        inline void setRenderQueueGroup(Ogre::uint8 queueID) { renderQueue = queueID; }
 
170
 
 
171
        /** \brief Sets the height function used to calculate grass Y coordinates
 
172
        \param heightFunction A pointer to a height function
 
173
 
 
174
        Unless you want all your grass placed at 0 height, you need to specify a height function
 
175
        so GrassLoader will be able to calculate the Y coordinate. The height function given
 
176
        to setHeightFunction() should use the following prototype (although you can name the
 
177
        function anything you want):
 
178
 
 
179
        \code
 
180
        Real getHeightAt(Real x, Real z, void *userData);
 
181
        \endcode
 
182
 
 
183
        \note If you're not using the default coordinate system (where x = right, z = back), the
 
184
        x/z parameters will actually be representing the appropriate equivalents.
 
185
 
 
186
        The userData parameter allows you to include any additional data you want when your height
 
187
        function is called, and is completely optional (although you can't actually omit it from the
 
188
        declaration, you can ignore it). Any userData value you choose to supply to setHeightFunction()
 
189
        will be passed on to your height function every time it is called.
 
190
 
 
191
        After you've defined a height function, using setHeightFunction is easy:
 
192
 
 
193
        \code
 
194
        pageLoader2D->setHeightFunction(&getHeightAt);
 
195
        //Or (if you want to pass additional data on to your height function)...
 
196
        pageLoader2D->setHeightFunction(&getHeightAt, myUserData);
 
197
        \endcode
 
198
 
 
199
        In most cases, you may not even need to use the extra "userData" parameter, but it's there in
 
200
        the event that your height function needs extra contextual data.
 
201
        */
 
202
        void setHeightFunction(Ogre::Real (*heightFunction)(Ogre::Real x, Ogre::Real z, void *userData), void *userData = NULL) {
 
203
                this->heightFunction = heightFunction;
 
204
                heightFunctionUserData = userData;
 
205
        }
 
206
 
 
207
 
 
208
        /** INTERNAL FUNCTION - DO NOT USE */
 
209
        void loadPage(PageInfo &page);
 
210
        /** INTERNAL FUNCTION - DO NOT USE */
 
211
        void unloadPage(const PageInfo &page);
 
212
        /** INTERNAL FUNCTION - DO NOT USE */
 
213
        void frameUpdate();
 
214
 
 
215
private:
 
216
        friend class GrassLayer;
 
217
 
 
218
        //Helper functions
 
219
        Ogre::Mesh *generateGrass_QUAD(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount);
 
220
        Ogre::Mesh *generateGrass_CROSSQUADS(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount);
 
221
        Ogre::Mesh *generateGrass_SPRITE(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount);
 
222
 
 
223
        //List of grass types
 
224
        std::list<TGrassLayer*> layerList;
 
225
 
 
226
        //Height data
 
227
        Ogre::Real (*heightFunction)(Ogre::Real x, Ogre::Real z, void *userData);       //Pointer to height function
 
228
        void *heightFunctionUserData;
 
229
 
 
230
        //Misc.
 
231
        PagedGeometry *geom;
 
232
        Ogre::uint8 renderQueue;
 
233
        float densityFactor;
 
234
 
 
235
        //Animation
 
236
        Ogre::Timer windTimer;
 
237
        Ogre::Vector3 windDir;
 
238
        unsigned long lastTime;
 
239
 
 
240
        static unsigned long GUID;
 
241
        static inline Ogre::String getUniqueID()
 
242
        {
 
243
                return "GrassLDR" + Ogre::StringConverter::toString(++GUID);
 
244
        }
 
245
};
 
246
 
 
247
 
 
248
 
 
249
 
 
250
 
 
251
/** \brief A technique used to render grass. Passed to GrassLayer::setRenderTechnique(). */
 
252
enum GrassTechnique
 
253
{
 
254
        /// Grass constructed of randomly placed and rotated quads
 
255
        GRASSTECH_QUAD,
 
256
        /// Grass constructed of two quads forming a "X" cross shape
 
257
        GRASSTECH_CROSSQUADS,
 
258
        /// Grass constructed of camera-facing billboard quads
 
259
        GRASSTECH_SPRITE
 
260
};
 
261
 
 
262
/** \brief A technique used to fade grass into the distance. Passed to GrassLayer::setFadeTechnique(). */
 
263
enum FadeTechnique
 
264
{
 
265
        /// Grass that fades into the distance with transparency. Fairly effective in most cases.
 
266
        FADETECH_ALPHA,
 
267
        /// Grass that fades in by "growing" up out of the ground. Very effective when grass fades in against the sky, or with alpha-rejected grass.
 
268
        FADETECH_GROW,
 
269
        /// Grass that fades in by slowly becoming opaque while it "grows" up out of the ground. Effective with alpha grass fading in against the sky.
 
270
        FADETECH_ALPHAGROW
 
271
};
 
272
 
 
273
class GrassLayerBase
 
274
{
 
275
public:
 
276
        /** \brief Sets the material that is applied to all grass billboards/quads */
 
277
        void setMaterialName(const Ogre::String &matName);
 
278
 
 
279
        /** \brief Sets the minimum size that grass quads/billboards will be */
 
280
        void setMinimumSize(float width, float height);
 
281
 
 
282
        /** \brief Sets the maximum size that grass quads/billboards will be */
 
283
        void setMaximumSize(float width, float height);
 
284
        
 
285
        /** \brief Sets the technique used to render this grass layer
 
286
        \param style The GrassTechnique style used to display grass.
 
287
        \param blendBase Whether or not grass base blending is enabled.
 
288
        
 
289
        The "style" setting allows you to choose from various construction methods, such as
 
290
        sprite-style grass quads, plain 3D quads, etc. See the GrassTechnique documentation
 
291
        for more information about this option. GRASSTECH_QUAD is used by default.
 
292
 
 
293
        Setting "blendBase" to true will enable grass base blending, a technique which helps
 
294
        reduce the unnatural flat appearance of grass quads near the camera. Since the flatness
 
295
        is most obvious where the grass intersects the terrain, this technique attempts to
 
296
        smoothly blend the base of near-by grass into the terrain.
 
297
 
 
298
        \note Base blending does not work well with alpha-rejected textures.
 
299
        */
 
300
        void setRenderTechnique(GrassTechnique style, bool blendBase = false);
 
301
 
 
302
        /** \brief Sets the technique used when fading out distant grass
 
303
        \param style The FadeTechnique style used to fade grass.
 
304
        
 
305
        This "style" setting allows you to choose from various fade techniques. Depending on
 
306
        your scene, certain techniques may look better than others. The most compatible method
 
307
        is FADETECH_ALPHA (used by default), although better results can usually be achieved
 
308
        with other methods. See the FadeTechnique documentation for more information.
 
309
        */
 
310
        void setFadeTechnique(FadeTechnique style);
 
311
 
 
312
        /** \brief Enables/disables animation on this layer
 
313
        
 
314
        Always use this function to disable animation, rather than setting SwayLength or SwaySpeed
 
315
        to 0. This function will use a different vertex shader which means improved performance
 
316
        when animation is disabled.
 
317
        */
 
318
        void setAnimationEnabled(bool enabled);
 
319
 
 
320
        /** \brief Sets how far grass should sway back and forth
 
321
 
 
322
        \note Since this is measured in world units, you may have to adjust this depending on
 
323
        the size of your grass as set by setMinimumSize() and setMaximumSize().*/
 
324
        void setSwayLength(float mag) { animMag = mag; }
 
325
 
 
326
        /** \brief Sets the sway speed of the grass (measured in "sways-per-second") */
 
327
        void setSwaySpeed(float speed) { animSpeed = speed; }
 
328
 
 
329
        /** \brief Sets the smooth distribution (positional phase shift) of the grass swaying animation
 
330
 
 
331
        If you set this to 0, grass animation will look very unnatural, since all the grass sway motions
 
332
        will be in perfect synchronization (everything sways to the right, then everything sways to the
 
333
        left, etc.) This sets the "positional phase shift", which gives the grass a "wave" like phase
 
334
        distribution. The higher this value is, the more "chaotic" the wind will appear. Lower values give
 
335
        a smoother breeze appearance, but values too high can look unrealistic.
 
336
        */
 
337
        void setSwayDistribution(float freq) { animFreq = freq; }
 
338
        
 
339
        /** \brief Sets the boundaries of the density/color maps
 
340
        \param bounds The map boundary
 
341
 
 
342
        By default, the GrassLayer has no knowledge of your terrain/world boundaries, so you must
 
343
        use this function to specify a rectangular/square area of your world, otherwise density/color maps
 
344
        won't work properly. The boundary given to this function defines the area where density/color
 
345
        maps take effect. Normally this is set to your terrain's bounds so the density/color map is aligned
 
346
        to your heightmap, but you could apply it anywhere you want.
 
347
        
 
348
        \note The grass system is infinite, so there's no need to worry about using too expansive
 
349
        boundaries. This setting simply configures the behavior of density and color maps. */
 
350
        virtual void setMapBounds(const Ogre::TRect<Ogre::Real> &bounds)
 
351
        {
 
352
                mapBounds = bounds;
 
353
        }
 
354
        
 
355
        
 
356
        /**
 
357
         *    Calculates the max number of grass instances for this layer.
 
358
         * @param densityFactor The density factor set on the grass loader
 
359
         * @param volume The volume, in world units, to fill
 
360
         * @return The max number of grass instances to create.
 
361
         */
 
362
        virtual unsigned int calculateMaxGrassCount(float densityFactor, float volume) = 0;
 
363
        
 
364
protected: 
 
365
 
 
366
        //Used by GrassLoader::loadPage() - populates an array with grass.
 
367
        //Returns the final number of grasses, which will always be <= grassCount
 
368
        virtual unsigned int _populateGrassList(PageInfo page, float *posBuff, unsigned int grassCount) = 0;
 
369
 
 
370
        //Updates the vertex shader used by this layer based on the animate enable status
 
371
        void _updateShaders();
 
372
        
 
373
        //Grass material/shape properties
 
374
        Ogre::MaterialPtr material;
 
375
        float minWidth, maxWidth;
 
376
        float minHeight, maxHeight;
 
377
        
 
378
        FadeTechnique fadeTechnique;
 
379
        GrassTechnique renderTechnique;
 
380
 
 
381
        //Property maps
 
382
        Ogre::TRect<Ogre::Real> mapBounds;
 
383
        
 
384
        //Grass shader properties
 
385
        bool animate, blend, shaderNeedsUpdate;
 
386
        float animMag, animSpeed, animFreq;
 
387
 
 
388
        //Current frame of animation for this layer
 
389
        float waveCount;
 
390
 
 
391
        PagedGeometry *geom;
 
392
        
 
393
};
 
394
 
 
395
 
 
396
/** \brief A data structure giving you full control over grass properties.
 
397
 
 
398
Grass is added to the scene through GrassLoader::addLayer(). Through this class you
 
399
can configure your grass layer any way you like - size, density, render technique,
 
400
animation, etc. Simply call the appropriate "set" member function to set the desired property.
 
401
 
 
402
Remember that you cannot create or delete layers directly. Layers can only be created
 
403
with GrassLoader::addLayer(), and may not be deleted manually (they will be deleted when
 
404
the associated GrassLoader is deleted).
 
405
*/
 
406
class GrassLayer : public GrassLayerBase
 
407
{
 
408
public:
 
409
 
 
410
        /** \brief Sets the maximum density (measured in grass quads/billboards per square unit) of grass */
 
411
        void setDensity(float density) { this->density = density; }
 
412
 
 
413
        /** \brief Sets a minimum / maximum height where grass may appear
 
414
        \param minHeight Sets the minimum height grass may have. 0 = no minimum
 
415
        \param maxHeight Sets the maximum height grass may have. 0 = no maximum
 
416
 
 
417
        By default grass appears at all altitudes. You can use this function to restrict grass to a
 
418
        certain height range. For example, if sea level is at 100 units Y, you might restrict this
 
419
        layer to display only above 100 units (so your grass doesn't grow under water).
 
420
 
 
421
        It's possible to use density maps (see setDensityMap()) to achieve similar results, but if
 
422
        your density map is extremely low resolution, this function may be the only practical option
 
423
        to prevent grass from growing under water (when used in combination with your density map).
 
424
 
 
425
        Setting minHeight to 0 means grass has no minimum height - it can grow as low as necessary.
 
426
        Similarly, setting maxHeight to 0 means grass has no maximum height - it can grow as high
 
427
        as necessary. */
 
428
        void setHeightRange(float minHeight, float maxHeight = 0) { minY = minHeight; maxY = maxHeight; }
 
429
 
 
430
        /** \brief Sets the density map used for this grass layer
 
431
        \param mapFile The density map image
 
432
        \param channel The color channel(s) to from the image to interpret as density
 
433
        
 
434
        A density map is simply a greyscale image, similar to a heightmap, that specifies the grass
 
435
        density on your map. Full pixel intensity indicates that grass should be fully dense at that
 
436
        point (the maximum density is specified by GrassLayer::setDensity()), while no pixel intensity
 
437
        indicates that no grass should appear at that location.
 
438
 
 
439
        The channel parameter allows you to extract the density information from the image's
 
440
        red, green, blue, alpha, or color values. For example, you may store density values in the
 
441
        alpha channel, in which case you would use CHANNEL_ALPHA. By default, CHANNEL_COLOR is used,
 
442
        which means the image color is converted to greyscale internally and used as a density map.
 
443
        
 
444
        Note that GrassLayer by default has no idea of your terrain/world boundaries, so you
 
445
        must specify a rectangular/square area of your world that is affected by density/color maps.
 
446
        To do this, use the setMapBounds() function. Normally this is set to your terrain's bounds
 
447
        so the density/color map is aligned to your heightmap, but you could apply it anywhere you
 
448
        want. */
 
449
        void setDensityMap(const Ogre::String &mapFile, MapChannel channel = CHANNEL_COLOR);
 
450
 
 
451
        /** \brief Sets the density map used for this grass layer
 
452
 
 
453
        Overloaded to accept a Texture object. See the original setDensityMap() documentation above
 
454
        for more detailed information on density maps.
 
455
        
 
456
        \note The texture data you provide is copied into the GrassLayer's own memory space, so you
 
457
        can delete the texture after calling this function without risk of crashing. */
 
458
        void setDensityMap(Ogre::Texture *map, MapChannel channel = CHANNEL_COLOR);
 
459
 
 
460
        /** \brief Sets the filtering mode used for density maps
 
461
 
 
462
        This function can be used to set the filtering mode used for your density map when generating
 
463
        grass. By default, bilinear filtering is used (MAPFILTER_BILINEAR). If you disable filtering
 
464
        by using MAPFILTER_NONE, the resulting layout of your grass may look square and blocky,
 
465
        depending on the resolution of your density map.
 
466
 
 
467
        MAPFILTER_NONE is slightly faster than MAPFILTER_BILINEAR, so use it if you don't notice any
 
468
        considerable blockyness.
 
469
        */
 
470
        void setDensityMapFilter(MapFilter filter);
 
471
 
 
472
        /** \brief Sets the color map used for this grass layer
 
473
        \param mapFile The color map image
 
474
        \param channel The color channel(s) to from the image to use
 
475
        
 
476
        A color map is simply a texture that allows you to vary the color and shading of grass
 
477
        across your world for a more realistic look. For example, adding a dark spot to the center
 
478
        of your color map will make grass near the center of your terrain look darker, as long as
 
479
        you have the color map aligned to your terrain (see setMapBounds()).
 
480
 
 
481
        The channel parameter allows you to extract the color information from the image's
 
482
        red, green, blue, alpha, or color values. For example, you may store the desired shade of your
 
483
        grass in the red channel of an image, in which case you would use CHANNEL_RED (when you choose
 
484
        a single channel, it is converted to a greyscale color). By default, CHANNEL_COLOR is used,
 
485
        which uses the full color information available in the image.
 
486
        
 
487
        Remember that GrassLayer by default has no idea of your terrain/world boundaries, so you
 
488
        must specify a rectangular/square area of your world that is affected by density/color maps.
 
489
        To do this, use the setMapBounds() function. Normally this is set to your terrain's bounds
 
490
        so the density/color map is aligned to your heightmap, but you could apply it anywhere you
 
491
        want. */
 
492
        void setColorMap(const Ogre::String &mapFile, MapChannel channel = CHANNEL_COLOR);
 
493
 
 
494
        /** \brief Sets the color map used for this grass layer
 
495
 
 
496
        Overloaded to accept a Texture object. See the original setColorMap() documentation above
 
497
        for more detailed information on color maps.
 
498
        
 
499
        \note The texture data you provide is copied into RAM, so you can delete the texture after
 
500
        calling this function without risk of crashing. */
 
501
        void setColorMap(Ogre::Texture *map, MapChannel channel = CHANNEL_COLOR);
 
502
 
 
503
        /** \brief Sets the filtering mode used for color maps
 
504
 
 
505
        This function can be used to set the filtering mode used for your color map when generating
 
506
        grass. By default, bilinear filtering is used (MAPFILTER_BILINEAR). If you disable filtering
 
507
        by using MAPFILTER_NONE, the resulting grass coloration may appear slightly pixelated,
 
508
        depending on the resolution of your color map.
 
509
        
 
510
        MAPFILTER_NONE is slightly faster than MAPFILTER_BILINEAR, so use it if you don't notice any
 
511
        considerable pixelation.
 
512
        */
 
513
        void setColorMapFilter(MapFilter filter);
 
514
 
 
515
        /** \brief Gets a pointer to the density map being used
 
516
 
 
517
        You can use this function to access the internal density map object used by the GrassLoader.
 
518
        Through this object you can directly manipulate the pixels of the density map, among other
 
519
        things.
 
520
 
 
521
        Note that although you can edit the density map in real-time through this class, the changes
 
522
        won't be uploaded to your video card until you call PagedGeometry::reloadGeometry(). If you
 
523
        don't, the grass you see will remain unchanged. */
 
524
        DensityMap *getDensityMap() { return densityMap; }
 
525
 
 
526
        /** \brief Gets a pointer to the color map being used
 
527
 
 
528
        You can use this function to access the internal color map object used by the GrassLoader.
 
529
        Through this object you can directly manipulate the pixels of the color map, among other
 
530
        things.
 
531
 
 
532
        Note that although you can edit the color map in real-time through this class, the changes
 
533
        won't be uploaded to your video card until you call PagedGeometry::reloadGeometry(). If you
 
534
        don't, the grass you see will remain unchanged. */
 
535
        ColorMap *getColorMap() { return colorMap; }
 
536
 
 
537
 
 
538
        /** \brief Sets the boundaries of the density/color maps
 
539
        \param bounds The map boundary
 
540
 
 
541
        By default, the GrassLayer has no knowledge of your terrain/world boundaries, so you must
 
542
        use this function to specify a rectangular/square area of your world, otherwise density/color maps
 
543
        won't work properly. The boundary given to this function defines the area where density/color
 
544
        maps take effect. Normally this is set to your terrain's bounds so the density/color map is aligned
 
545
        to your heightmap, but you could apply it anywhere you want.
 
546
        
 
547
        \note The grass system is infinite, so there's no need to worry about using too expansive
 
548
        boundaries. This setting simply configures the behavior of density and color maps. */
 
549
        virtual void setMapBounds(const Ogre::TRect<Ogre::Real> &bounds)
 
550
        {
 
551
                GrassLayerBase::setMapBounds(bounds);
 
552
                if (densityMap)
 
553
                        densityMap->setMapBounds(mapBounds);
 
554
                if (colorMap)
 
555
                        colorMap->setMapBounds(mapBounds);
 
556
        }
 
557
        
 
558
        /**
 
559
         *    Calculates the max number of grass instances for this layer.
 
560
         * @param densityFactor The density factor set on the grass loader
 
561
         * @param volume The volume, in world units, to fill
 
562
         * @return The max number of grass instances to create.
 
563
         */
 
564
        virtual unsigned int calculateMaxGrassCount(float densityFactor, float volume);
 
565
        
 
566
        
 
567
        /**
 
568
         *    If there's a colormap registered use that for lookup, else return fullbright.
 
569
         * @param x 
 
570
         * @param z 
 
571
         * @return 
 
572
         */
 
573
        inline Ogre::uint32 getColorAt(float x, float z)
 
574
        {
 
575
                if (colorMap)
 
576
                        return colorMap->getColorAt(x, z);
 
577
                else
 
578
                        return 0xFFFFFFFF;
 
579
        }
 
580
 
 
581
private:
 
582
        friend class GrassLoader<GrassLayer>;
 
583
 
 
584
        /** \brief Do not create a GrassLayer directly - use GrassLoader->addLayer() */
 
585
        GrassLayer(PagedGeometry *geom, GrassLoader<GrassLayer> *ldr);
 
586
 
 
587
        /** \brief Do not delete a GrassLayer yourself - the GrassLoader will do this automatically when it's deleted */
 
588
        ~GrassLayer();
 
589
 
 
590
        //Used by GrassLoader::loadPage() - populates an array with grass.
 
591
        //Returns the final number of grasses, which will always be <= grassCount
 
592
        virtual unsigned int _populateGrassList(PageInfo page, float *posBuff, unsigned int grassCount);
 
593
        
 
594
        //Used by GrassLoader::loadPage() - populates an array with a uniform distribution of grass
 
595
        //Returns the final number of grasses, which will always be <= grassCount
 
596
        unsigned int _populateGrassList_Uniform(PageInfo page, float *posBuff, unsigned int grassCount);
 
597
 
 
598
        //Used by GrassLoader::loadPage() - populates an array of grass positions based on the density map
 
599
        //Returns the final number of grasses, which will always be <= grassCount
 
600
        unsigned int _populateGrassList_UnfilteredDM(PageInfo page, float *posBuff, unsigned int grassCount);
 
601
 
 
602
        //Variation of _populateGrassList(), using bilinear filtering on the density map lookups
 
603
        //Returns the final number of grasses, which will always be <= grassCount
 
604
        unsigned int _populateGrassList_BilinearDM(PageInfo page, float *posBuff, unsigned int grassCount);
 
605
 
 
606
 
 
607
        GrassLoader<GrassLayer> *parent;
 
608
 
 
609
        //Grass material/shape properties
 
610
        float density;
 
611
 
 
612
        float minY, maxY;
 
613
 
 
614
 
 
615
        DensityMap *densityMap;
 
616
        MapFilter densityMapFilter;
 
617
 
 
618
        ColorMap *colorMap;
 
619
        MapFilter colorMapFilter;
 
620
 
 
621
};
 
622
 
 
623
 
 
624
/** \brief A custom page type designed specifically for use with GrassLoader.
 
625
 
 
626
You can use this in your own project if you want, but remember that no optimizations
 
627
are performed. The given entity is simply cloned and attached to a new scene node as
 
628
quickly and simply as possible (this means there's no batching overhead as in BatchPage,
 
629
but it also means potentially poor performance if you don't know what you're doing).
 
630
*/
 
631
class GrassPage: public GeometryPage
 
632
{
 
633
public:
 
634
        void init(PagedGeometry *geom);
 
635
        ~GrassPage();
 
636
 
 
637
        void addEntity(Ogre::Entity *ent, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, const Ogre::Vector3 &scale, const Ogre::ColourValue &color);
 
638
        void removeEntities();
 
639
        void setFade(bool enabled, Ogre::Real visibleDist, Ogre::Real invisibleDist) {}
 
640
        void setVisible(bool visible);
 
641
 
 
642
private:
 
643
        Ogre::SceneManager *sceneMgr;
 
644
        Ogre::SceneNode *rootNode;
 
645
 
 
646
        std::list<Ogre::SceneNode*> nodeList;
 
647
 
 
648
        static unsigned long GUID;
 
649
        static inline Ogre::String getUniqueID()
 
650
        {
 
651
                return "GrassPage" + Ogre::StringConverter::toString(++GUID);
 
652
        }
 
653
};
 
654
 
 
655
template <class TGrassLayer>
 
656
GrassLoader<TGrassLayer>::GrassLoader(PagedGeometry *geom)
 
657
{
 
658
        GrassLoader<TGrassLayer>::geom = geom;
 
659
        
 
660
        heightFunction = NULL;
 
661
        heightFunctionUserData = NULL;
 
662
 
 
663
        windDir = Ogre::Vector3::UNIT_X;
 
664
        densityFactor = 1.0f;
 
665
        renderQueue = Ogre::RENDER_QUEUE_6;
 
666
 
 
667
        windTimer.reset();
 
668
        lastTime = 0;
 
669
}
 
670
 
 
671
template <class TGrassLayer>
 
672
GrassLoader<TGrassLayer>::~GrassLoader()
 
673
{
 
674
        typename std::list<TGrassLayer*>::iterator it;
 
675
        for (it = layerList.begin(); it != layerList.end(); ++it){
 
676
                delete *it;
 
677
        }
 
678
        layerList.clear();
 
679
}
 
680
 
 
681
template <class TGrassLayer>
 
682
TGrassLayer *GrassLoader<TGrassLayer>::addLayer(const Ogre::String &material)
 
683
{
 
684
        TGrassLayer *layer = new TGrassLayer(geom, this);
 
685
        layer->setMaterialName(material);
 
686
        layerList.push_back(layer);
 
687
 
 
688
        return layer;
 
689
}
 
690
 
 
691
template <class TGrassLayer>
 
692
void GrassLoader<TGrassLayer>::deleteLayer(TGrassLayer *layer)
 
693
{
 
694
        layerList.remove(layer);
 
695
        delete layer;
 
696
}
 
697
 
 
698
template <class TGrassLayer>
 
699
void GrassLoader<TGrassLayer>::frameUpdate()
 
700
{
 
701
        unsigned long currentTime = windTimer.getMilliseconds();
 
702
        unsigned long ellapsedTime = currentTime - lastTime;
 
703
        lastTime = currentTime;
 
704
 
 
705
        float ellapsed = ellapsedTime / 1000.0f;
 
706
        
 
707
        //Update the vertex shader parameters
 
708
        typename std::list<TGrassLayer*>::iterator it;
 
709
        for (it = layerList.begin(); it != layerList.end(); ++it){
 
710
                TGrassLayer *layer = *it;
 
711
 
 
712
                layer->_updateShaders();
 
713
 
 
714
                Ogre::GpuProgramParametersSharedPtr params = layer->material->getTechnique(0)->getPass(0)->getVertexProgramParameters();
 
715
                if (layer->animate){
 
716
                        //Increment animation frame
 
717
                        layer->waveCount += ellapsed * (layer->animSpeed * Ogre::Math::PI);
 
718
                        if (layer->waveCount > Ogre::Math::PI*2) layer->waveCount -= Ogre::Math::PI*2;
 
719
 
 
720
                        //Set vertex shader parameters
 
721
                        params->setNamedConstant("time", layer->waveCount);
 
722
                        params->setNamedConstant("frequency", layer->animFreq);
 
723
 
 
724
                        Ogre::Vector3 direction = windDir * layer->animMag;
 
725
                        params->setNamedConstant("direction", Ogre::Vector4(direction.x, direction.y, direction.z, 0));
 
726
 
 
727
                }
 
728
        }
 
729
}
 
730
 
 
731
template <class TGrassLayer>
 
732
void GrassLoader<TGrassLayer>::loadPage(PageInfo &page)
 
733
{
 
734
        //Seed random number generator based on page indexes
 
735
        Ogre::uint16 xSeed = static_cast<Ogre::uint16>(page.xIndex % 0xFFFF);
 
736
        Ogre::uint16 zSeed = static_cast<Ogre::uint16>(page.zIndex % 0xFFFF);
 
737
        Ogre::uint32 seed = (xSeed << 16) | zSeed;
 
738
        srand(seed);
 
739
 
 
740
        typename std::list<TGrassLayer*>::iterator it;
 
741
        for (it = layerList.begin(); it != layerList.end(); ++it){
 
742
                TGrassLayer *layer = *it;
 
743
 
 
744
                //Calculate how much grass needs to be added
 
745
                float volume = page.bounds.width() * page.bounds.height();
 
746
                unsigned int grassCount = layer->calculateMaxGrassCount(densityFactor, volume);
 
747
 
 
748
                //The vertex buffer can't be allocated until the exact number of polygons is known,
 
749
                //so the locations of all grasses in this page must be precalculated.
 
750
 
 
751
                //Precompute grass locations into an array of floats. A plain array is used for speed;
 
752
                //there's no need to use a dynamic sized array since a maximum size is known.
 
753
                float *position = new float[grassCount*2];
 
754
                grassCount = layer->_populateGrassList(page, position, grassCount);
 
755
 
 
756
                //Don't build a mesh unless it contains something
 
757
                if (grassCount != 0){
 
758
                        Ogre::Mesh *mesh = NULL;
 
759
                        switch (layer->renderTechnique){
 
760
                                case GRASSTECH_QUAD:
 
761
                                        mesh = generateGrass_QUAD(page, layer, position, grassCount);
 
762
                                        break;
 
763
                                case GRASSTECH_CROSSQUADS:
 
764
                                        mesh = generateGrass_CROSSQUADS(page, layer, position, grassCount);
 
765
                                        break;
 
766
                                case GRASSTECH_SPRITE:
 
767
                                        mesh = generateGrass_SPRITE(page, layer, position, grassCount);
 
768
                                        break;
 
769
                        }
 
770
                        assert(mesh);
 
771
 
 
772
                        //Add the mesh to PagedGeometry
 
773
                        Ogre::Entity *entity = geom->getCamera()->getSceneManager()->createEntity(getUniqueID(), mesh->getName());
 
774
                        entity->setRenderQueueGroup(renderQueue);
 
775
                        entity->setCastShadows(false);
 
776
                        addEntity(entity, page.centerPoint, Ogre::Quaternion::IDENTITY, Ogre::Vector3::UNIT_SCALE);
 
777
                        geom->getSceneManager()->destroyEntity(entity);
 
778
 
 
779
                        //Store the mesh pointer
 
780
                        page.userData = mesh;
 
781
                } else {
 
782
                        //No mesh
 
783
                        page.userData = NULL;
 
784
                }
 
785
 
 
786
                //Delete the position list
 
787
                delete[] position;
 
788
        }
 
789
}
 
790
 
 
791
template <class TGrassLayer>
 
792
void GrassLoader<TGrassLayer>::unloadPage(const PageInfo &page)
 
793
{
 
794
        //Unload mesh
 
795
        Ogre::Mesh *mesh = (Ogre::Mesh*)page.userData;
 
796
        if (mesh)
 
797
                Ogre::MeshManager::getSingleton().remove(mesh->getName());
 
798
}
 
799
template <class TGrassLayer>
 
800
Ogre::Mesh *GrassLoader<TGrassLayer>::generateGrass_QUAD(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount)
 
801
{
 
802
        //Calculate the number of quads to be added
 
803
        unsigned int quadCount;
 
804
        quadCount = grassCount;
 
805
 
 
806
        //Create manual mesh to store grass quads
 
807
        Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(getUniqueID(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
 
808
        Ogre::SubMesh *subMesh = mesh->createSubMesh();
 
809
        subMesh->useSharedVertices = false;
 
810
 
 
811
        //Setup vertex format information
 
812
        subMesh->vertexData = new Ogre::VertexData;
 
813
        subMesh->vertexData->vertexStart = 0;
 
814
        subMesh->vertexData->vertexCount = 4 * quadCount;
 
815
 
 
816
        Ogre::VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
 
817
        size_t offset = 0;
 
818
        dcl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
 
819
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
 
820
        dcl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
 
821
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
 
822
        dcl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
 
823
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
 
824
 
 
825
        //Populate a new vertex buffer with grass
 
826
        Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton()
 
827
                .createVertexBuffer(offset, subMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
 
828
        float* pReal = static_cast<float*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
 
829
 
 
830
        //Calculate size variance
 
831
        float rndWidth = layer->maxWidth - layer->minWidth;
 
832
        float rndHeight = layer->maxHeight - layer->minHeight;
 
833
 
 
834
        float minY = Ogre::Math::POS_INFINITY, maxY = Ogre::Math::NEG_INFINITY;
 
835
        float *posPtr = grassPositions; //Position array "iterator"
 
836
        for (Ogre::uint16 i = 0; i < grassCount; ++i)
 
837
        {
 
838
                //Get the x and z positions from the position array
 
839
                float x = *posPtr++;
 
840
                float z = *posPtr++;
 
841
 
 
842
                //Get the color at the grass position
 
843
                Ogre::uint32 color(layer->getColorAt(x, z));
 
844
 
 
845
                //Calculate size
 
846
                float rnd = Ogre::Math::UnitRandom();   //The same rnd value is used for width and height to maintain aspect ratio
 
847
                float halfScaleX = (layer->minWidth + rndWidth * rnd) * 0.5f;
 
848
                float scaleY = (layer->minHeight + rndHeight * rnd);
 
849
 
 
850
                //Calculate rotation
 
851
                float angle = Ogre::Math::RangeRandom(0, Ogre::Math::TWO_PI);
 
852
                float xTrans = Ogre::Math::Cos(angle) * halfScaleX;
 
853
                float zTrans = Ogre::Math::Sin(angle) * halfScaleX;
 
854
 
 
855
                //Calculate heights and edge positions
 
856
                float x1 = x - xTrans, z1 = z - zTrans;
 
857
                float x2 = x + xTrans, z2 = z + zTrans;
 
858
 
 
859
                float y1, y2;
 
860
                if (heightFunction){
 
861
                        y1 = heightFunction(x1, z1, heightFunctionUserData);
 
862
                        y2 = heightFunction(x2, z2, heightFunctionUserData);
 
863
                } else {
 
864
                        y1 = 0;
 
865
                        y2 = 0;
 
866
                }
 
867
 
 
868
                //Add vertices
 
869
                *pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1 + scaleY); *pReal++ = (z1 - page.centerPoint.z);   //pos
 
870
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
871
                *pReal++ = 0; *pReal++ = 0;                                                             //uv
 
872
 
 
873
                *pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2 + scaleY); *pReal++ = (z2 - page.centerPoint.z);   //pos
 
874
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
875
                *pReal++ = 1; *pReal++ = 0;                                                             //uv
 
876
 
 
877
                *pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1); *pReal++ = (z1 - page.centerPoint.z);                    //pos
 
878
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
879
                *pReal++ = 0; *pReal++ = 1;                                                             //uv
 
880
 
 
881
                *pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2); *pReal++ = (z2 - page.centerPoint.z);                    //pos
 
882
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
883
                *pReal++ = 1; *pReal++ = 1;                                                             //uv
 
884
 
 
885
                //Update bounds
 
886
                if (y1 < minY) minY = y1;
 
887
                if (y2 < minY) minY = y2;
 
888
                if (y1 + scaleY > maxY) maxY = y1 + scaleY;
 
889
                if (y2 + scaleY > maxY) maxY = y2 + scaleY;
 
890
        }
 
891
 
 
892
        vbuf->unlock();
 
893
        subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
 
894
 
 
895
        //Populate index buffer
 
896
        subMesh->indexData->indexStart = 0;
 
897
        subMesh->indexData->indexCount = 6 * quadCount;
 
898
        subMesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton()
 
899
                .createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
 
900
        Ogre::uint16* pI = static_cast<Ogre::uint16*>(subMesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
 
901
        for (Ogre::uint16 i = 0; i < quadCount; ++i)
 
902
        {
 
903
                Ogre::uint16 offset = i * 4;
 
904
 
 
905
                *pI++ = 0 + offset;
 
906
                *pI++ = 2 + offset;
 
907
                *pI++ = 1 + offset;
 
908
 
 
909
                *pI++ = 1 + offset;
 
910
                *pI++ = 2 + offset;
 
911
                *pI++ = 3 + offset;
 
912
        }
 
913
 
 
914
        subMesh->indexData->indexBuffer->unlock();
 
915
 
 
916
        //Finish up mesh
 
917
        Ogre::AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
 
918
                page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
 
919
        mesh->_setBounds(bounds);
 
920
        Ogre::Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
 
921
        mesh->_setBoundingSphereRadius(temp.length() * 0.5f);
 
922
 
 
923
        Ogre::LogManager::getSingleton().setLogDetail(static_cast<Ogre::LoggingLevel>(0));
 
924
        mesh->load();
 
925
        Ogre::LogManager::getSingleton().setLogDetail(Ogre::LL_NORMAL);
 
926
 
 
927
        //Apply grass material to mesh
 
928
        subMesh->setMaterialName(layer->material->getName());
 
929
 
 
930
        //Return the mesh
 
931
        return mesh.getPointer();
 
932
}
 
933
 
 
934
template <class TGrassLayer>
 
935
Ogre::Mesh *GrassLoader<TGrassLayer>::generateGrass_CROSSQUADS(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount)
 
936
{
 
937
        //Calculate the number of quads to be added
 
938
        unsigned int quadCount;
 
939
        quadCount = grassCount * 2;
 
940
 
 
941
        //Create manual mesh to store grass quads
 
942
        Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(getUniqueID(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
 
943
        Ogre::SubMesh *subMesh = mesh->createSubMesh();
 
944
        subMesh->useSharedVertices = false;
 
945
 
 
946
        //Setup vertex format information
 
947
        subMesh->vertexData = new Ogre::VertexData;
 
948
        subMesh->vertexData->vertexStart = 0;
 
949
        subMesh->vertexData->vertexCount = 4 * quadCount;
 
950
 
 
951
        Ogre::VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
 
952
        size_t offset = 0;
 
953
        dcl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
 
954
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
 
955
        dcl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
 
956
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
 
957
        dcl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
 
958
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
 
959
 
 
960
        //Populate a new vertex buffer with grass
 
961
        Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton()
 
962
                .createVertexBuffer(offset, subMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
 
963
        float* pReal = static_cast<float*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
 
964
 
 
965
        //Calculate size variance
 
966
        float rndWidth = layer->maxWidth - layer->minWidth;
 
967
        float rndHeight = layer->maxHeight - layer->minHeight;
 
968
 
 
969
        float minY = Ogre::Math::POS_INFINITY, maxY = Ogre::Math::NEG_INFINITY;
 
970
        float *posPtr = grassPositions; //Position array "iterator"
 
971
        for (Ogre::uint16 i = 0; i < grassCount; ++i)
 
972
        {
 
973
                //Get the x and z positions from the position array
 
974
                float x = *posPtr++;
 
975
                float z = *posPtr++;
 
976
 
 
977
                //Get the color at the grass position
 
978
                Ogre::uint32 color(layer->getColorAt(x, z));
 
979
                
 
980
//              if (layer->colorMap)
 
981
//                      color = layer->colorMap->getColorAt(x, z);
 
982
//              else
 
983
//                      color = 0xFFFFFFFF;
 
984
 
 
985
                //Calculate size
 
986
                float rnd = Ogre::Math::UnitRandom();   //The same rnd value is used for width and height to maintain aspect ratio
 
987
                float halfScaleX = (layer->minWidth + rndWidth * rnd) * 0.5f;
 
988
                float scaleY = (layer->minHeight + rndHeight * rnd);
 
989
 
 
990
                //Calculate rotation
 
991
                float angle = Ogre::Math::RangeRandom(0, Ogre::Math::TWO_PI);
 
992
                float xTrans = Ogre::Math::Cos(angle) * halfScaleX;
 
993
                float zTrans = Ogre::Math::Sin(angle) * halfScaleX;
 
994
 
 
995
                //Calculate heights and edge positions
 
996
                float x1 = x - xTrans, z1 = z - zTrans;
 
997
                float x2 = x + xTrans, z2 = z + zTrans;
 
998
 
 
999
                float y1, y2;
 
1000
                if (heightFunction){
 
1001
                        y1 = heightFunction(x1, z1, heightFunctionUserData);
 
1002
                        y2 = heightFunction(x2, z2, heightFunctionUserData);
 
1003
                } else {
 
1004
                        y1 = 0;
 
1005
                        y2 = 0;
 
1006
                }
 
1007
 
 
1008
                //Add vertices
 
1009
                *pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1 + scaleY); *pReal++ = (z1 - page.centerPoint.z);   //pos
 
1010
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
1011
                *pReal++ = 0; *pReal++ = 0;                                                             //uv
 
1012
 
 
1013
                *pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2 + scaleY); *pReal++ = (z2 - page.centerPoint.z);   //pos
 
1014
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
1015
                *pReal++ = 1; *pReal++ = 0;                                                             //uv
 
1016
 
 
1017
                *pReal++ = (x1 - page.centerPoint.x); *pReal++ = (y1); *pReal++ = (z1 - page.centerPoint.z);                    //pos
 
1018
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
1019
                *pReal++ = 0; *pReal++ = 1;                                                             //uv
 
1020
 
 
1021
                *pReal++ = (x2 - page.centerPoint.x); *pReal++ = (y2); *pReal++ = (z2 - page.centerPoint.z);                    //pos
 
1022
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
1023
                *pReal++ = 1; *pReal++ = 1;                                                             //uv
 
1024
 
 
1025
                //Update bounds
 
1026
                if (y1 < minY) minY = y1;
 
1027
                if (y2 < minY) minY = y2;
 
1028
                if (y1 + scaleY > maxY) maxY = y1 + scaleY;
 
1029
                if (y2 + scaleY > maxY) maxY = y2 + scaleY;
 
1030
 
 
1031
                //Calculate heights and edge positions
 
1032
                float x3 = x + zTrans, z3 = z - xTrans;
 
1033
                float x4 = x - zTrans, z4 = z + xTrans;
 
1034
 
 
1035
                float y3, y4;
 
1036
                if (heightFunction){
 
1037
                        y3 = heightFunction(x3, z3, heightFunctionUserData);
 
1038
                        y4 = heightFunction(x4, z4, heightFunctionUserData);
 
1039
                } else {
 
1040
                        y3 = 0;
 
1041
                        y4 = 0;
 
1042
                }
 
1043
 
 
1044
                //Add vertices
 
1045
                *pReal++ = (x3 - page.centerPoint.x); *pReal++ = (y3 + scaleY); *pReal++ = (z3 - page.centerPoint.z);   //pos
 
1046
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
1047
                *pReal++ = 0; *pReal++ = 0;                                                             //uv
 
1048
 
 
1049
                *pReal++ = (x4 - page.centerPoint.x); *pReal++ = (y4 + scaleY); *pReal++ = (z4 - page.centerPoint.z);   //pos
 
1050
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
1051
                *pReal++ = 1; *pReal++ = 0;                                                             //uv
 
1052
 
 
1053
                *pReal++ = (x3 - page.centerPoint.x); *pReal++ = (y3); *pReal++ = (z3 - page.centerPoint.z);                    //pos
 
1054
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
1055
                *pReal++ = 0; *pReal++ = 1;                                                             //uv
 
1056
 
 
1057
                *pReal++ = (x4 - page.centerPoint.x); *pReal++ = (y4); *pReal++ = (z4 - page.centerPoint.z);                    //pos
 
1058
                *((Ogre::uint32*)pReal++) = color;                                                      //color
 
1059
                *pReal++ = 1; *pReal++ = 1;                                                             //uv
 
1060
 
 
1061
                //Update bounds
 
1062
                if (y3 < minY) minY = y1;
 
1063
                if (y4 < minY) minY = y2;
 
1064
                if (y3 + scaleY > maxY) maxY = y3 + scaleY;
 
1065
                if (y4 + scaleY > maxY) maxY = y4 + scaleY;
 
1066
        }
 
1067
 
 
1068
        vbuf->unlock();
 
1069
        subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
 
1070
 
 
1071
        //Populate index buffer
 
1072
        subMesh->indexData->indexStart = 0;
 
1073
        subMesh->indexData->indexCount = 6 * quadCount;
 
1074
        subMesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton()
 
1075
                .createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
 
1076
        Ogre::uint16* pI = static_cast<Ogre::uint16*>(subMesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
 
1077
        for (Ogre::uint16 i = 0; i < quadCount; ++i)
 
1078
        {
 
1079
                Ogre::uint16 offset = i * 4;
 
1080
 
 
1081
                *pI++ = 0 + offset;
 
1082
                *pI++ = 2 + offset;
 
1083
                *pI++ = 1 + offset;
 
1084
 
 
1085
                *pI++ = 1 + offset;
 
1086
                *pI++ = 2 + offset;
 
1087
                *pI++ = 3 + offset;
 
1088
        }
 
1089
 
 
1090
        subMesh->indexData->indexBuffer->unlock();
 
1091
 
 
1092
        //Finish up mesh
 
1093
        Ogre::AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
 
1094
                page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
 
1095
        mesh->_setBounds(bounds);
 
1096
        Ogre::Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
 
1097
        mesh->_setBoundingSphereRadius(temp.length() * 0.5f);
 
1098
 
 
1099
        Ogre::LogManager::getSingleton().setLogDetail(static_cast<Ogre::LoggingLevel>(0));
 
1100
        mesh->load();
 
1101
        Ogre::LogManager::getSingleton().setLogDetail(Ogre::LL_NORMAL);
 
1102
 
 
1103
        //Apply grass material to mesh
 
1104
        subMesh->setMaterialName(layer->material->getName());
 
1105
 
 
1106
        //Return the mesh
 
1107
        return mesh.getPointer();
 
1108
}
 
1109
 
 
1110
template <class TGrassLayer>
 
1111
Ogre::Mesh *GrassLoader<TGrassLayer>::generateGrass_SPRITE(PageInfo &page, TGrassLayer *layer, float *grassPositions, unsigned int grassCount)
 
1112
{
 
1113
        //Calculate the number of quads to be added
 
1114
        unsigned int quadCount;
 
1115
        quadCount = grassCount;
 
1116
 
 
1117
        //Create manual mesh to store grass quads
 
1118
        Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(getUniqueID(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
 
1119
        Ogre::SubMesh *subMesh = mesh->createSubMesh();
 
1120
        subMesh->useSharedVertices = false;
 
1121
 
 
1122
        //Setup vertex format information
 
1123
        subMesh->vertexData = new Ogre::VertexData;
 
1124
        subMesh->vertexData->vertexStart = 0;
 
1125
        subMesh->vertexData->vertexCount = 4 * quadCount;
 
1126
 
 
1127
        Ogre::VertexDeclaration* dcl = subMesh->vertexData->vertexDeclaration;
 
1128
        size_t offset = 0;
 
1129
        dcl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
 
1130
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
 
1131
        dcl->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_NORMAL);
 
1132
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
 
1133
        dcl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
 
1134
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
 
1135
        dcl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
 
1136
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
 
1137
 
 
1138
        //Populate a new vertex buffer with grass
 
1139
        Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton()
 
1140
                .createVertexBuffer(offset, subMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
 
1141
        float* pReal = static_cast<float*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
 
1142
 
 
1143
        //Calculate size variance
 
1144
        float rndWidth = layer->maxWidth - layer->minWidth;
 
1145
        float rndHeight = layer->maxHeight - layer->minHeight;
 
1146
 
 
1147
        float minY = Ogre::Math::POS_INFINITY, maxY = Ogre::Math::NEG_INFINITY;
 
1148
        float *posPtr = grassPositions; //Position array "iterator"
 
1149
        for (Ogre::uint16 i = 0; i < grassCount; ++i)
 
1150
        {
 
1151
                //Get the x and z positions from the position array
 
1152
                float x = *posPtr++;
 
1153
                float z = *posPtr++;
 
1154
 
 
1155
                //Calculate height
 
1156
                float y;
 
1157
                if (heightFunction){
 
1158
                        y = heightFunction(x, z, heightFunctionUserData);
 
1159
                } else {
 
1160
                        y = 0;
 
1161
                }
 
1162
 
 
1163
                float x1 = (x - page.centerPoint.x);
 
1164
                float z1 = (z - page.centerPoint.z);
 
1165
 
 
1166
                //Get the color at the grass position
 
1167
                Ogre::uint32 color(layer->getColorAt(x, z));
 
1168
 
 
1169
                //Calculate size
 
1170
                float rnd = Ogre::Math::UnitRandom();   //The same rnd value is used for width and height to maintain aspect ratio
 
1171
                float halfXScale = (layer->minWidth + rndWidth * rnd) * 0.5f;
 
1172
                float scaleY = (layer->minHeight + rndHeight * rnd);
 
1173
 
 
1174
                //Randomly mirror grass textures
 
1175
                float uvLeft, uvRight;
 
1176
                if (Ogre::Math::UnitRandom() > 0.5f){
 
1177
                        uvLeft = 0;
 
1178
                        uvRight = 1;
 
1179
                } else {
 
1180
                        uvLeft = 1;
 
1181
                        uvRight = 0;
 
1182
                }
 
1183
 
 
1184
                //Add vertices
 
1185
                *pReal++ = x1; *pReal++ = y; *pReal++ = z1;                                     //center position
 
1186
                *pReal++ = -halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0;  //normal (used to store relative corner positions)
 
1187
                *((Ogre::uint32*)pReal++) = color;                                                              //color
 
1188
                *pReal++ = uvLeft; *pReal++ = 0;                                                        //uv
 
1189
 
 
1190
                *pReal++ = x1; *pReal++ = y; *pReal++ = z1;                                     //center position
 
1191
                *pReal++ = +halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0;  //normal (used to store relative corner positions)
 
1192
                *((Ogre::uint32*)pReal++) = color;                                                              //color
 
1193
                *pReal++ = uvRight; *pReal++ = 0;                                                       //uv
 
1194
 
 
1195
                *pReal++ = x1; *pReal++ = y; *pReal++ = z1;                                     //center position
 
1196
                *pReal++ = -halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0;            //normal (used to store relative corner positions)
 
1197
                *((Ogre::uint32*)pReal++) = color;                                                              //color
 
1198
                *pReal++ = uvLeft; *pReal++ = 1;                                                        //uv
 
1199
 
 
1200
                *pReal++ = x1; *pReal++ = y; *pReal++ = z1;                                     //center position
 
1201
                *pReal++ = +halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0;            //normal (used to store relative corner positions)
 
1202
                *((Ogre::uint32*)pReal++) = color;                                                              //color
 
1203
                *pReal++ = uvRight; *pReal++ = 1;                                                       //uv
 
1204
 
 
1205
                //Update bounds
 
1206
                if (y < minY) minY = y;
 
1207
                if (y + scaleY > maxY) maxY = y + scaleY;
 
1208
        }
 
1209
 
 
1210
        vbuf->unlock();
 
1211
        subMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
 
1212
 
 
1213
        //Populate index buffer
 
1214
        subMesh->indexData->indexStart = 0;
 
1215
        subMesh->indexData->indexCount = 6 * quadCount;
 
1216
        subMesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton()
 
1217
                .createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, subMesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
 
1218
        Ogre::uint16* pI = static_cast<Ogre::uint16*>(subMesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
 
1219
        for (Ogre::uint16 i = 0; i < quadCount; ++i)
 
1220
        {
 
1221
                Ogre::uint16 offset = i * 4;
 
1222
 
 
1223
                *pI++ = 0 + offset;
 
1224
                *pI++ = 2 + offset;
 
1225
                *pI++ = 1 + offset;
 
1226
 
 
1227
                *pI++ = 1 + offset;
 
1228
                *pI++ = 2 + offset;
 
1229
                *pI++ = 3 + offset;
 
1230
        }
 
1231
 
 
1232
        subMesh->indexData->indexBuffer->unlock();
 
1233
 
 
1234
        //Finish up mesh
 
1235
        Ogre::AxisAlignedBox bounds(page.bounds.left - page.centerPoint.x, minY, page.bounds.top - page.centerPoint.z,
 
1236
                page.bounds.right - page.centerPoint.x, maxY, page.bounds.bottom - page.centerPoint.z);
 
1237
        mesh->_setBounds(bounds);
 
1238
        Ogre::Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
 
1239
        mesh->_setBoundingSphereRadius(temp.length() * 0.5f);
 
1240
 
 
1241
        Ogre::LogManager::getSingleton().setLogDetail(static_cast<Ogre::LoggingLevel>(0));
 
1242
        mesh->load();
 
1243
        Ogre::LogManager::getSingleton().setLogDetail(Ogre::LL_NORMAL);
 
1244
 
 
1245
        //Apply grass material to mesh
 
1246
        subMesh->setMaterialName(layer->material->getName());
 
1247
 
 
1248
        //Return the mesh
 
1249
        return mesh.getPointer();
 
1250
}
 
1251
 
 
1252
template <class TGrassLayer>
 
1253
unsigned long GrassLoader<TGrassLayer>::GUID = 0;
 
1254
 
 
1255
}
 
1256
#endif