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

« back to all changes in this revision

Viewing changes to .pc/0022-fix-typos.patch/src/components/ogre/environment/pagedgeometry/include/GrassLoader.h

  • Committer: Package Import Robot
  • Author(s): Olek Wojnar, Stephen M. Webb, Olek Wojnar
  • Date: 2016-08-06 18:39:19 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20160806183919-4g72j3flj7xe2stj
Tags: 0.7.2+dfsg-1
[ Stephen M. Webb ]
* debian/control: updated build-depends to newer minimum versions
  (closes: #704786)
* debian/control: updated Standards-Version to 3.9.4 (updated VCS-* fields)
* debian/patches/0001-ember.in-test-expr.patch: removed (fixed upstream)
* debian/patches/0002-add-update_lua_bindings.patch: removed (fixed upstream)
* debian/patches/0003-add-atlas-pkg.patch: removed (fixed upstream)
* debian/patches/0004-domain-bindings-lua-makefile.patch: refreshed
* debian/patches/0005-ember.in-prefix.patch: removed (fixed upstream)
* debian/patches/0006-spellcheck-similiar.patch: removed (fixed upstream)
* debian/patches/0007-revert-libwfut-version.patch: refreshed
* debian/patches/0008-replace-fastdeletegate-with-sigc++.patch: removed
 (fixed upstream)
* debian/patches/0009-spelling-bach.patch: removed (fixed upstream)
* debian/patches/0010-fix-ember-script-args.patch: removed (fixed upstream)
* debian/patches/0011-qualify-template-functions.patch: removed (fixed
  upstream)
* debian/patches/0012-fix-osdir-headers.patch: removed (fixed upstream)
* debian/patches/0013-remove-invalid-linker-flags.patch: removed (fixed
  upstream)
* debian/patches/0014-add-missing-ogrelodstrategy.patch: new
* debian/control: fixed Vcs-Browser URL
* debian/patches/0015-verbose-configure-errors.patch: new
* debian/patches/0016-boost-1.53.patch: new
* debian/control: bump boost build dependeny to 1.53

[ Olek Wojnar ]
* New upstream release (Closes: #799748)
* Add myself as new uploader
  - Remove Stephen Webb per his request
  - Thanks for all the contributions, Stephen!
* d/patches/0007-revert-libwfut-version.patch: removed (unnecessary)
* d/control
  - Remove pre-dependency on dpkg
  - Update standards to 3.9.8 (no changes)
  - Update Vcs lines for secure URIs
* Import patch from the wfmath package to replace MersenneTwister.h
  -- Avoids problems from ambiguous copyright of the original file
* Update dependencies for version 0.7.2
* Enable all hardening options
* Add three lintian overrides
  -- Ignore install into usr/bin (binary)
  -- Ignore .rc files needed for WIN32 build (source)
  -- Ignore false positive of spelling error (binary)
* d/copyright: Update contributors and dates
* d/rules
  -- Do not remove "sounddefinitions" directory
  -- Enable parallel build
  -- Do not install into games directories
  -- Remove dh_builddeb override since xz is now the default
* d/watch: update file extensions
* Remove three patches, add eight patches, update remaining patches
  -- 0004-domain-bindings-lua-makefile.patch (implemented upstream)
  -- 0014-add-missing-ogrelodstrategy.patch (implemented upstream)
  -- 0016-boost-1.53.patch (patch target file removed upstream)
  -- 0018-enable-subdir-objects.patch (Fix automake 1.14 warnings)
  -- 0019-update-boost-m4.patch (Fix invalid boost_major_version)
  -- 0020-remove-obsolete-includes.patch (Fix obsolete includes)
  -- 0021-GraphicalChangeAdapter-fix-for-newer-compilers.patch (Added)
  -- 0022-fix-typos.patch (Fix typos identified by lintian)
  -- 0023-add-keywords-to-desktop-file.patch (Add Keywords to .desktop file)
  -- 0024-fix-icon-location (Make icon location Icon Theme Spec-compliant)
  -- 0025-fix-duplicate-script-install.patch (Was causing build failures)

Show diffs side-by-side

added added

removed removed

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