1 /*
2   -----------------------------------------------------------------------------
3   This source file is part of OGRE
4   (Object-oriented Graphics Rendering Engine)
5   For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8 Also see acknowledgements in Readme.html
9 
10   You may use this sample code for anything you like, it is not covered by the
11   same license as the rest of the engine.
12   -----------------------------------------------------------------------------
13 */
14 #ifndef __Terrain_H__
15 #define __Terrain_H__
16 
17 //#define PAGING
18 
19 #define TERRAIN_PAGE_MIN_X 0
20 #define TERRAIN_PAGE_MIN_Y 0
21 #define TERRAIN_PAGE_MAX_X 0
22 #define TERRAIN_PAGE_MAX_Y 0
23 
24 #include "SdkSample.h"
25 #include "OgrePageManager.h"
26 #include "OgreTerrain.h"
27 #include "OgreTerrainGroup.h"
28 #include "OgreTerrainQuadTreeNode.h"
29 #include "OgreTerrainMaterialGeneratorA.h"
30 #include "OgreTerrainPaging.h"
31 
32 #define TERRAIN_FILE_PREFIX String("testTerrain")
33 #define TERRAIN_FILE_SUFFIX String("dat")
34 #define TERRAIN_WORLD_SIZE 12000.0f
35 #define TERRAIN_SIZE 513
36 
37 using namespace Ogre;
38 using namespace OgreBites;
39 
40 class _OgreSampleClassExport Sample_Terrain : public SdkSample
41 {
42  public:
43 
Sample_Terrain()44  Sample_Terrain()
45      : mTerrainGlobals(0)
46         , mTerrainGroup(0)
47         , mTerrainPaging(0)
48         , mPageManager(0)
49         , mFly(false)
50         , mFallVelocity(0)
51         , mMode(MODE_NORMAL)
52         , mLayerEdit(1)
53         , mBrushSizeTerrainSpace(0.02)
54         , mHeightUpdateCountDown(0)
55         , mTerrainPos(1000,0,5000)
56         , mTerrainsImported(false)
57         , mKeyPressed(0)
58 
59     {
60         mInfo["Title"] = "Terrain";
61         mInfo["Description"] = "Demonstrates use of the terrain rendering plugin.";
62         mInfo["Thumbnail"] = "thumb_terrain.png";
63         mInfo["Category"] = "Environment";
64         mInfo["Help"] = "Left click and drag anywhere in the scene to look around. Let go again to show "
65             "cursor and access widgets. Use WASD keys to move. Use +/- keys when in edit mode to change content.";
66 
67         // Update terrain at max 20fps
68         mHeightUpdateRate = 1.0 / 20.0;
69     }
70 
testCapabilities(const RenderSystemCapabilities * caps)71     void testCapabilities(const RenderSystemCapabilities* caps)
72     {
73         if (!caps->hasCapability(RSC_VERTEX_PROGRAM) || !caps->hasCapability(RSC_FRAGMENT_PROGRAM))
74         {
75             OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your graphics card does not support vertex or fragment shaders, "
76                         "so you cannot run this sample. Sorry!", "Sample_Terrain::testCapabilities");
77         }
78     }
79 
getRequiredPlugins()80     StringVector getRequiredPlugins()
81     {
82         StringVector names;
83         if (!GpuProgramManager::getSingleton().isSyntaxSupported("glsles") &&
84             !GpuProgramManager::getSingleton().isSyntaxSupported("glsl") &&
85             !GpuProgramManager::getSingleton().isSyntaxSupported("hlsl"))
86             names.push_back("Cg Program Manager");
87         return names;
88     }
89 
doTerrainModify(Terrain * terrain,const Vector3 & centrepos,Real timeElapsed)90     void doTerrainModify(Terrain* terrain, const Vector3& centrepos, Real timeElapsed)
91     {
92         Vector3 tsPos;
93         terrain->getTerrainPosition(centrepos, &tsPos);
94 #if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
95         if (mKeyPressed == '+' || mKeyPressed == '-' || mKeyPressed == SDLK_KP_PLUS ||
96             mKeyPressed == SDLK_KP_MINUS)
97         {
98             switch(mMode)
99             {
100             case MODE_EDIT_HEIGHT:
101                 {
102                     // we need point coords
103                     Real terrainSize = (terrain->getSize() - 1);
104                     long startx = (tsPos.x - mBrushSizeTerrainSpace) * terrainSize;
105                     long starty = (tsPos.y - mBrushSizeTerrainSpace) * terrainSize;
106                     long endx = (tsPos.x + mBrushSizeTerrainSpace) * terrainSize;
107                     long endy= (tsPos.y + mBrushSizeTerrainSpace) * terrainSize;
108                     startx = std::max(startx, 0L);
109                     starty = std::max(starty, 0L);
110                     endx = std::min(endx, (long)terrainSize);
111                     endy = std::min(endy, (long)terrainSize);
112                     for (long y = starty; y <= endy; ++y)
113                     {
114                         for (long x = startx; x <= endx; ++x)
115                         {
116                             Real tsXdist = (x / terrainSize) - tsPos.x;
117                             Real tsYdist = (y / terrainSize)  - tsPos.y;
118 
119                             Real weight = std::min((Real)1.0,
120                                                    Math::Sqrt(tsYdist * tsYdist + tsXdist * tsXdist) / Real(0.5 * mBrushSizeTerrainSpace));
121                             weight = 1.0 - (weight * weight);
122 
123                             float addedHeight = weight * 250.0 * timeElapsed;
124                             float newheight;
125                             if (mKeyPressed == '+'  || mKeyPressed == SDLK_KP_PLUS)
126                                 newheight = terrain->getHeightAtPoint(x, y) + addedHeight;
127                             else
128                                 newheight = terrain->getHeightAtPoint(x, y) - addedHeight;
129                             terrain->setHeightAtPoint(x, y, newheight);
130 
131                         }
132                     }
133                     if (mHeightUpdateCountDown == 0)
134                         mHeightUpdateCountDown = mHeightUpdateRate;
135                 }
136                 break;
137             case MODE_EDIT_BLEND:
138                 {
139                     TerrainLayerBlendMap* layer = terrain->getLayerBlendMap(mLayerEdit);
140                     // we need image coords
141                     Real imgSize = terrain->getLayerBlendMapSize();
142                     long startx = (tsPos.x - mBrushSizeTerrainSpace) * imgSize;
143                     long starty = (tsPos.y - mBrushSizeTerrainSpace) * imgSize;
144                     long endx = (tsPos.x + mBrushSizeTerrainSpace) * imgSize;
145                     long endy= (tsPos.y + mBrushSizeTerrainSpace) * imgSize;
146                     startx = std::max(startx, 0L);
147                     starty = std::max(starty, 0L);
148                     endx = std::min(endx, (long)imgSize);
149                     endy = std::min(endy, (long)imgSize);
150                     for (long y = starty; y <= endy; ++y)
151                     {
152                         for (long x = startx; x <= endx; ++x)
153                         {
154                             Real tsXdist = (x / imgSize) - tsPos.x;
155                             Real tsYdist = (y / imgSize)  - tsPos.y;
156 
157                             Real weight = std::min((Real)1.0,
158                                                    Math::Sqrt(tsYdist * tsYdist + tsXdist * tsXdist) / Real(0.5 * mBrushSizeTerrainSpace));
159                             weight = 1.0 - (weight * weight);
160 
161                             float paint = weight * timeElapsed;
162                             size_t imgY = imgSize - y;
163                             float val;
164                             if (mKeyPressed == '+'  || mKeyPressed == SDLK_KP_PLUS)
165                                 val = layer->getBlendValue(x, imgY) + paint;
166                             else
167                                 val = layer->getBlendValue(x, imgY) - paint;
168                             val = Math::Clamp(val, 0.0f, 1.0f);
169                             layer->setBlendValue(x, imgY, val);
170 
171                         }
172                     }
173 
174                     layer->update();
175                 }
176                 break;
177             case MODE_NORMAL:
178             case MODE_COUNT:
179                 break;
180             };
181         }
182 #endif
183 
184     }
frameRenderingQueued(const FrameEvent & evt)185     bool frameRenderingQueued(const FrameEvent& evt)
186     {
187         if (mMode != MODE_NORMAL)
188         {
189             // fire ray
190             Ray ray;
191             //ray = mCamera->getCameraToViewportRay(0.5, 0.5);
192             ray = mTrayMgr->getCursorRay(mCamera);
193 
194             TerrainGroup::RayResult rayResult = mTerrainGroup->rayIntersects(ray);
195             if (rayResult.hit)
196             {
197                 mEditMarker->setVisible(true);
198                 mEditNode->setPosition(rayResult.position);
199 
200                 // figure out which terrains this affects
201                 TerrainGroup::TerrainList terrainList;
202                 Real brushSizeWorldSpace = TERRAIN_WORLD_SIZE * mBrushSizeTerrainSpace;
203                 Sphere sphere(rayResult.position, brushSizeWorldSpace);
204                 mTerrainGroup->sphereIntersects(sphere, &terrainList);
205 
206                 for (TerrainGroup::TerrainList::iterator ti = terrainList.begin();
207                      ti != terrainList.end(); ++ti)
208                     doTerrainModify(*ti, rayResult.position, evt.timeSinceLastFrame);
209             }
210             else
211             {
212                 mEditMarker->setVisible(false);
213             }
214         }
215 
216         if (!mFly)
217         {
218             // clamp to terrain
219             Vector3 camPos = mCameraNode->getPosition();
220             Ray ray;
221             ray.setOrigin(Vector3(camPos.x, mTerrainPos.y + 10000, camPos.z));
222             ray.setDirection(Vector3::NEGATIVE_UNIT_Y);
223 
224             TerrainGroup::RayResult rayResult = mTerrainGroup->rayIntersects(ray);
225             Real distanceAboveTerrain = 50;
226             Real fallSpeed = 300;
227             Real newy = camPos.y;
228             if (rayResult.hit)
229             {
230                 if (camPos.y > rayResult.position.y + distanceAboveTerrain)
231                 {
232                     mFallVelocity += evt.timeSinceLastFrame * 20;
233                     mFallVelocity = std::min(mFallVelocity, fallSpeed);
234                     newy = camPos.y - mFallVelocity * evt.timeSinceLastFrame;
235 
236                 }
237                 newy = std::max(rayResult.position.y + distanceAboveTerrain, newy);
238                 mCameraNode->setPosition(camPos.x, newy, camPos.z);
239 
240             }
241 
242         }
243 
244         if (mHeightUpdateCountDown > 0)
245         {
246             mHeightUpdateCountDown -= evt.timeSinceLastFrame;
247             if (mHeightUpdateCountDown <= 0)
248             {
249                 mTerrainGroup->update();
250                 mHeightUpdateCountDown = 0;
251 
252             }
253         }
254 
255         if (mTerrainGroup->isDerivedDataUpdateInProgress())
256         {
257             mTrayMgr->moveWidgetToTray(mInfoLabel, TL_TOP, 0);
258             mInfoLabel->show();
259             if (mTerrainsImported)
260             {
261                 mInfoLabel->setCaption("Building terrain, please wait...");
262             }
263             else
264             {
265                 mInfoLabel->setCaption("Updating textures, patience...");
266             }
267         }
268         else
269         {
270             mTrayMgr->removeWidgetFromTray(mInfoLabel);
271             mInfoLabel->hide();
272             if (mTerrainsImported)
273             {
274                 saveTerrains(true);
275                 mTerrainsImported = false;
276             }
277         }
278 
279         return SdkSample::frameRenderingQueued(evt);  // don't forget the parent updates!
280     }
281 
saveTerrains(bool onlyIfModified)282     void saveTerrains(bool onlyIfModified)
283     {
284         mTerrainGroup->saveAllTerrains(onlyIfModified);
285     }
286 
keyReleased(const KeyboardEvent & evt)287     bool keyReleased(const KeyboardEvent& evt)
288     {
289         mKeyPressed = 0;
290         return SdkSample::keyReleased(evt);
291     }
292 
keyPressed(const KeyboardEvent & e)293     bool keyPressed (const KeyboardEvent &e)
294     {
295 #if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
296         mKeyPressed = e.keysym.sym;
297 
298         switch (e.keysym.sym)
299         {
300         case 's':
301             // CTRL-S to save
302             if (e.keysym.mod & KMOD_CTRL)
303             {
304                 saveTerrains(true);
305             }
306             else
307                 return SdkSample::keyPressed(e);
308             break;
309         case SDLK_F10:
310             // dump
311             {
312                 TerrainGroup::TerrainIterator ti = mTerrainGroup->getTerrainIterator();
313                 while (ti.hasMoreElements())
314                 {
315                     Ogre::uint32 tkey = ti.peekNextKey();
316                     TerrainGroup::TerrainSlot* ts = ti.getNext();
317                     if (ts->instance && ts->instance->isLoaded())
318                     {
319                         ts->instance->_dumpTextures("terrain_" + StringConverter::toString(tkey), ".png");
320                     }
321                 }
322             }
323             break;
324             /*
325               case SDLK_F7:
326               // change terrain size
327               if (mTerrainGroup->getTerrainSize() == 513)
328               mTerrainGroup->setTerrainSize(1025);
329               else
330               mTerrainGroup->setTerrainSize(513);
331               break;
332               case SDLK_F8:
333               // change terrain world size
334               if (mTerrainGroup->getTerrainWorldSize() == TERRAIN_WORLD_SIZE)
335               mTerrainGroup->setTerrainWorldSize(TERRAIN_WORLD_SIZE * 2);
336               else
337               mTerrainGroup->setTerrainWorldSize(TERRAIN_WORLD_SIZE);
338               break;
339             */
340         default:
341             return SdkSample::keyPressed(e);
342         }
343 #endif
344 
345         return true;
346     }
347 
itemSelected(SelectMenu * menu)348     void itemSelected(SelectMenu* menu)
349     {
350         if (menu == mEditMenu)
351         {
352             mMode = (Mode)mEditMenu->getSelectionIndex();
353         }
354         else if (menu == mShadowsMenu)
355         {
356             mShadowMode = (ShadowMode)mShadowsMenu->getSelectionIndex();
357             changeShadows();
358         }
359     }
360 
checkBoxToggled(CheckBox * box)361     void checkBoxToggled(CheckBox* box)
362     {
363         if (box == mFlyBox)
364         {
365             mFly = mFlyBox->isChecked();
366         }
367     }
368 
369  protected:
370 
371     TerrainGlobalOptions* mTerrainGlobals;
372     TerrainGroup* mTerrainGroup;
373     bool mPaging;
374     TerrainPaging* mTerrainPaging;
375     PageManager* mPageManager;
376 #ifdef PAGING
377     /// This class just pretends to provide prcedural page content to avoid page loading
378     class DummyPageProvider : public PageProvider
379     {
380     public:
prepareProceduralPage(Page * page,PagedWorldSection * section)381         bool prepareProceduralPage(Page* page, PagedWorldSection* section) { return true; }
loadProceduralPage(Page * page,PagedWorldSection * section)382         bool loadProceduralPage(Page* page, PagedWorldSection* section) { return true; }
unloadProceduralPage(Page * page,PagedWorldSection * section)383         bool unloadProceduralPage(Page* page, PagedWorldSection* section) { return true; }
unprepareProceduralPage(Page * page,PagedWorldSection * section)384         bool unprepareProceduralPage(Page* page, PagedWorldSection* section) { return true; }
385     };
386     DummyPageProvider mDummyPageProvider;
387 #endif
388     bool mFly;
389     Real mFallVelocity;
390     enum Mode
391     {
392         MODE_NORMAL = 0,
393         MODE_EDIT_HEIGHT = 1,
394         MODE_EDIT_BLEND = 2,
395         MODE_COUNT = 3
396     };
397     enum ShadowMode
398     {
399         SHADOWS_NONE = 0,
400         SHADOWS_COLOUR = 1,
401         SHADOWS_DEPTH = 2,
402         SHADOWS_COUNT = 3
403     };
404     Mode mMode;
405     ShadowMode mShadowMode;
406     Ogre::uint8 mLayerEdit;
407     Real mBrushSizeTerrainSpace;
408     SceneNode* mEditNode;
409     Entity* mEditMarker;
410     Real mHeightUpdateCountDown;
411     Real mHeightUpdateRate;
412     Vector3 mTerrainPos;
413     SelectMenu* mEditMenu;
414     SelectMenu* mShadowsMenu;
415     CheckBox* mFlyBox;
416     OgreBites::Label* mInfoLabel;
417     bool mTerrainsImported;
418     ShadowCameraSetupPtr mPSSMSetup;
419 
420     typedef std::list<Entity*> EntityList;
421     EntityList mHouseList;
422 
423     Keycode mKeyPressed;
424 
425     void defineTerrain(long x, long y, bool flat = false)
426     {
427         // if a file is available, use it
428         // if not, generate file from import
429 
430         // Usually in a real project you'll know whether the compact terrain data is
431         // available or not; I'm doing it this way to save distribution size
432 
433         if (flat)
434         {
435             mTerrainGroup->defineTerrain(x, y, 0.0f);
436         }
437         else
438         {
439             String filename = mTerrainGroup->generateFilename(x, y);
440             if (ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(), filename))
441             {
442                 mTerrainGroup->defineTerrain(x, y);
443             }
444             else
445             {
446                 Image img;
447                 getTerrainImage(x % 2 != 0, y % 2 != 0, img);
448                 mTerrainGroup->defineTerrain(x, y, &img);
449                 mTerrainsImported = true;
450             }
451         }
452     }
453 
getTerrainImage(bool flipX,bool flipY,Image & img)454     void getTerrainImage(bool flipX, bool flipY, Image& img)
455     {
456         img.load("terrain.png", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
457         if (flipX)
458             img.flipAroundY();
459         if (flipY)
460             img.flipAroundX();
461     }
462 
initBlendMaps(Terrain * terrain)463     void initBlendMaps(Terrain* terrain)
464     {
465         TerrainLayerBlendMap* blendMap0 = terrain->getLayerBlendMap(1);
466         TerrainLayerBlendMap* blendMap1 = terrain->getLayerBlendMap(2);
467         Real minHeight0 = 70;
468         Real fadeDist0 = 40;
469         Real minHeight1 = 70;
470         Real fadeDist1 = 15;
471         float* pBlend1 = blendMap1->getBlendPointer();
472         for (Ogre::uint16 y = 0; y < terrain->getLayerBlendMapSize(); ++y)
473         {
474             for (Ogre::uint16 x = 0; x < terrain->getLayerBlendMapSize(); ++x)
475             {
476                 Real tx, ty;
477 
478                 blendMap0->convertImageToTerrainSpace(x, y, &tx, &ty);
479                 Real height = terrain->getHeightAtTerrainPosition(tx, ty);
480                 Real val = (height - minHeight0) / fadeDist0;
481                 Math::Clamp(val, (Real)0, (Real)1);
482 
483                 val = (height - minHeight1) / fadeDist1;
484                 val = Math::Clamp(val, (Real)0, (Real)1);
485                 *pBlend1++ = val;
486 
487 
488             }
489         }
490         blendMap0->dirty();
491         blendMap1->dirty();
492         //blendMap0->loadImage("blendmap1.png", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
493         blendMap0->update();
494         blendMap1->update();
495 
496         // set up a colour map
497         /*
498           if (!terrain->getGlobalColourMapEnabled())
499           {
500           terrain->setGlobalColourMapEnabled(true);
501           Image colourMap;
502           colourMap.load("testcolourmap.jpg", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
503           terrain->getGlobalColourMap()->loadImage(colourMap);
504           }
505         */
506     }
507 
configureTerrainDefaults(Light * l)508     void configureTerrainDefaults(Light* l)
509     {
510         // Configure global
511         mTerrainGlobals->setMaxPixelError(8);
512         // testing composite map
513         mTerrainGlobals->setCompositeMapDistance(3000);
514         //mTerrainGlobals->setUseRayBoxDistanceCalculation(true);
515         //mTerrainGlobals->getDefaultMaterialGenerator()->setDebugLevel(1);
516         //mTerrainGlobals->setLightMapSize(256);
517 
518         // Disable the lightmap for OpenGL ES 2.0. The minimum number of samplers allowed is 8(as opposed to 16 on desktop).
519         // Otherwise we will run over the limit by just one. The minimum was raised to 16 in GL ES 3.0.
520         if (Ogre::Root::getSingletonPtr()->getRenderSystem()->getCapabilities()->getNumTextureUnits() < 9)
521         {
522             TerrainMaterialGeneratorA::SM2Profile* matProfile =
523                 static_cast<TerrainMaterialGeneratorA::SM2Profile*>(mTerrainGlobals->getDefaultMaterialGenerator()->getActiveProfile());
524             matProfile->setLightmapEnabled(false);
525         }
526 
527         // Important to set these so that the terrain knows what to use for derived (non-realtime) data
528         mTerrainGlobals->setLightMapDirection(l->getDerivedDirection());
529         mTerrainGlobals->setCompositeMapAmbient(mSceneMgr->getAmbientLight());
530         //mTerrainGlobals->setCompositeMapAmbient(ColourValue::Red);
531         mTerrainGlobals->setCompositeMapDiffuse(l->getDiffuseColour());
532 
533         // Configure default import settings for if we use imported image
534         Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings();
535         defaultimp.terrainSize = TERRAIN_SIZE;
536         defaultimp.worldSize = TERRAIN_WORLD_SIZE;
537         defaultimp.inputScale = 600;
538         defaultimp.minBatchSize = 33;
539         defaultimp.maxBatchSize = 65;
540         // textures
541         defaultimp.layerList.resize(3);
542         defaultimp.layerList[0].worldSize = 100;
543         defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_diffusespecular.dds");
544         defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_normalheight.dds");
545         defaultimp.layerList[1].worldSize = 30;
546         defaultimp.layerList[1].textureNames.push_back("grass_green-01_diffusespecular.dds");
547         defaultimp.layerList[1].textureNames.push_back("grass_green-01_normalheight.dds");
548         defaultimp.layerList[2].worldSize = 200;
549         defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_diffusespecular.dds");
550         defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_normalheight.dds");
551     }
552 
addTextureShadowDebugOverlay(TrayLocation loc,size_t num)553     void addTextureShadowDebugOverlay(TrayLocation loc, size_t num)
554     {
555         for (size_t i = 0; i < num; ++i)
556         {
557             TexturePtr shadowTex = mSceneMgr->getShadowTexture(i);
558             addTextureDebugOverlay(loc, shadowTex, i);
559         }
560     }
561 
buildDepthShadowMaterial(const String & textureName)562     MaterialPtr buildDepthShadowMaterial(const String& textureName)
563     {
564         String matName = "DepthShadows/" + textureName;
565 
566         MaterialPtr ret = MaterialManager::getSingleton().getByName(matName);
567         if (!ret)
568         {
569             MaterialPtr baseMat = MaterialManager::getSingleton().getByName("Ogre/shadow/depth/integrated/pssm");
570             ret = baseMat->clone(matName);
571             Pass* p = ret->getTechnique(0)->getPass(0);
572             p->getTextureUnitState("diffuse")->setTextureName(textureName);
573 
574             Vector4 splitPoints;
575             const PSSMShadowCameraSetup::SplitPointList& splitPointList =
576                 static_cast<PSSMShadowCameraSetup*>(mPSSMSetup.get())->getSplitPoints();
577             for (int i = 0; i < 3; ++i)
578             {
579                 splitPoints[i] = splitPointList[i];
580             }
581             p->getFragmentProgramParameters()->setNamedConstant("pssmSplitPoints", splitPoints);
582         }
583 
584         return ret;
585     }
586 
changeShadows()587     void changeShadows()
588     {
589         configureShadows(mShadowMode != SHADOWS_NONE, mShadowMode == SHADOWS_DEPTH);
590     }
591 
configureShadows(bool enabled,bool depthShadows)592     void configureShadows(bool enabled, bool depthShadows)
593     {
594         TerrainMaterialGeneratorA::SM2Profile* matProfile =
595             static_cast<TerrainMaterialGeneratorA::SM2Profile*>(mTerrainGlobals->getDefaultMaterialGenerator()->getActiveProfile());
596         matProfile->setReceiveDynamicShadowsEnabled(enabled);
597 #ifdef SHADOWS_IN_LOW_LOD_MATERIAL
598         matProfile->setReceiveDynamicShadowsLowLod(true);
599 #else
600         matProfile->setReceiveDynamicShadowsLowLod(false);
601 #endif
602 
603         // Default materials
604         for (EntityList::iterator i = mHouseList.begin(); i != mHouseList.end(); ++i)
605         {
606             (*i)->setMaterialName("Examples/TudorHouse");
607         }
608 
609         if (enabled)
610         {
611             // General scene setup
612             mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED);
613             mSceneMgr->setShadowFarDistance(3000);
614 
615             // 3 textures per directional light (PSSM)
616             mSceneMgr->setShadowTextureCountPerLightType(Ogre::Light::LT_DIRECTIONAL, 3);
617 
618             if (!mPSSMSetup)
619             {
620                 // shadow camera setup
621                 PSSMShadowCameraSetup* pssmSetup = new PSSMShadowCameraSetup();
622                 pssmSetup->setSplitPadding(mCamera->getNearClipDistance());
623                 pssmSetup->calculateSplitPoints(3, mCamera->getNearClipDistance(), mSceneMgr->getShadowFarDistance());
624                 pssmSetup->setOptimalAdjustFactor(0, 2);
625                 pssmSetup->setOptimalAdjustFactor(1, 1);
626                 pssmSetup->setOptimalAdjustFactor(2, 0.5);
627 
628                 mPSSMSetup.reset(pssmSetup);
629             }
630             mSceneMgr->setShadowCameraSetup(mPSSMSetup);
631 
632             if (depthShadows)
633             {
634                 mSceneMgr->setShadowTextureCount(3);
635                 mSceneMgr->setShadowTextureConfig(0, 2048, 2048, PF_FLOAT32_R);
636                 mSceneMgr->setShadowTextureConfig(1, 1024, 1024, PF_FLOAT32_R);
637                 mSceneMgr->setShadowTextureConfig(2, 1024, 1024, PF_FLOAT32_R);
638                 mSceneMgr->setShadowTextureSelfShadow(true);
639                 mSceneMgr->setShadowCasterRenderBackFaces(true);
640 
641                 MaterialPtr houseMat = buildDepthShadowMaterial("fw12b.jpg");
642                 for (EntityList::iterator i = mHouseList.begin(); i != mHouseList.end(); ++i)
643                 {
644                     (*i)->setMaterial(houseMat);
645                 }
646             }
647             else
648             {
649                 mSceneMgr->setShadowTextureCount(3);
650                 mSceneMgr->setShadowTextureConfig(0, 2048, 2048, PF_X8B8G8R8);
651                 mSceneMgr->setShadowTextureConfig(1, 1024, 1024, PF_X8B8G8R8);
652                 mSceneMgr->setShadowTextureConfig(2, 1024, 1024, PF_X8B8G8R8);
653                 mSceneMgr->setShadowTextureSelfShadow(false);
654                 mSceneMgr->setShadowCasterRenderBackFaces(false);
655                 mSceneMgr->setShadowTextureCasterMaterial(MaterialPtr());
656             }
657 
658             matProfile->setReceiveDynamicShadowsDepth(depthShadows);
659             matProfile->setReceiveDynamicShadowsPSSM(static_cast<PSSMShadowCameraSetup*>(mPSSMSetup.get()));
660 
661             //addTextureShadowDebugOverlay(TL_RIGHT, 3);
662         }
663         else
664         {
665             mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE);
666         }
667 
668 
669     }
670 
671     /*-----------------------------------------------------------------------------
672       | Extends setupView to change some initial camera settings for this sample.
673       -----------------------------------------------------------------------------*/
setupView()674     void setupView()
675     {
676         SdkSample::setupView();
677 
678         mCameraNode->setPosition(mTerrainPos + Vector3(1683, 50, 2116));
679         mCameraNode->lookAt(Vector3(1963, 50, 1660), Node::TS_PARENT);
680         mCamera->setNearClipDistance(0.1);
681         mCamera->setFarClipDistance(50000);
682 
683         if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE))
684         {
685             mCamera->setFarClipDistance(0);   // enable infinite far clip distance if we can
686         }
687     }
688 
setupControls()689     void setupControls()
690     {
691         mTrayMgr->showCursor();
692 
693         // make room for the controls
694         mTrayMgr->showLogo(TL_TOPRIGHT);
695         mTrayMgr->showFrameStats(TL_TOPRIGHT);
696         mTrayMgr->toggleAdvancedFrameStats();
697 
698         mInfoLabel = mTrayMgr->createLabel(TL_TOP, "TInfo", "", 350);
699 
700         mEditMenu = mTrayMgr->createLongSelectMenu(TL_BOTTOM, "EditMode", "Edit Mode", 370, 250, 3);
701         mEditMenu->addItem("None");
702         mEditMenu->addItem("Elevation");
703         mEditMenu->addItem("Blend");
704         mEditMenu->selectItem(0);  // no edit mode
705 
706         mFlyBox = mTrayMgr->createCheckBox(TL_BOTTOM, "Fly", "Fly");
707         mFlyBox->setChecked(false, false);
708 
709         mShadowsMenu = mTrayMgr->createLongSelectMenu(TL_BOTTOM, "Shadows", "Shadows", 370, 250, 3);
710         mShadowsMenu->addItem("None");
711         mShadowsMenu->addItem("Colour Shadows");
712         mShadowsMenu->addItem("Depth Shadows");
713         mShadowsMenu->selectItem(0);  // no edit mode
714 
715         // a friendly reminder
716         StringVector names;
717         names.push_back("Help");
718         mTrayMgr->createParamsPanel(TL_TOPLEFT, "Help", 100, names)->setParamValue(0, "H/F1");
719     }
720 
setupContent()721     void setupContent()
722     {
723         bool blankTerrain = false;
724         //blankTerrain = true;
725 
726         mTerrainGlobals = OGRE_NEW TerrainGlobalOptions();
727 
728         // Bugfix for D3D11 Render System because of pixel format incompatibility when using
729         // vertex compression
730         if (Ogre::Root::getSingleton().getRenderSystem()->getName() == "Direct3D11 Rendering Subsystem")
731             mTerrainGlobals->setUseVertexCompressionWhenAvailable(false);
732 
733         mEditMarker = mSceneMgr->createEntity("editMarker", "sphere.mesh");
734         mEditNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
735         mEditNode->attachObject(mEditMarker);
736         mEditNode->setScale(0.05, 0.05, 0.05);
737 
738         setupControls();
739 
740         mCameraMan->setTopSpeed(50);
741 
742         setDragLook(true);
743 
744         MaterialManager::getSingleton().setDefaultTextureFiltering(TFO_ANISOTROPIC);
745         MaterialManager::getSingleton().setDefaultAnisotropy(7);
746 
747         mSceneMgr->setFog(FOG_LINEAR, ColourValue(0.7, 0.7, 0.8), 0, 10000, 25000);
748 
749         LogManager::getSingleton().setLogDetail(LL_BOREME);
750 
751         Vector3 lightdir(0.55, -0.3, 0.75);
752         lightdir.normalise();
753 
754         Light* l = mSceneMgr->createLight("tstLight");
755         l->setType(Light::LT_DIRECTIONAL);
756         l->setDirection(lightdir);
757         l->setDiffuseColour(ColourValue::White);
758         l->setSpecularColour(ColourValue(0.4, 0.4, 0.4));
759 
760         mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));
761 
762         mTerrainGroup = OGRE_NEW TerrainGroup(mSceneMgr, Terrain::ALIGN_X_Z, TERRAIN_SIZE, TERRAIN_WORLD_SIZE);
763         mTerrainGroup->setFilenameConvention(TERRAIN_FILE_PREFIX, TERRAIN_FILE_SUFFIX);
764         mTerrainGroup->setOrigin(mTerrainPos);
765 
766         configureTerrainDefaults(l);
767 #ifdef PAGING
768         // Paging setup
769         mPageManager = OGRE_NEW PageManager();
770         // Since we're not loading any pages from .page files, we need a way just
771         // to say we've loaded them without them actually being loaded
772         mPageManager->setPageProvider(&mDummyPageProvider);
773         mPageManager->addCamera(mCamera);
774         mTerrainPaging = OGRE_NEW TerrainPaging(mPageManager);
775         PagedWorld* world = mPageManager->createWorld();
776         mTerrainPaging->createWorldSection(world, mTerrainGroup, 2000, 3000,
777                                            TERRAIN_PAGE_MIN_X, TERRAIN_PAGE_MIN_Y,
778                                            TERRAIN_PAGE_MAX_X, TERRAIN_PAGE_MAX_Y);
779 #else
780         for (long x = TERRAIN_PAGE_MIN_X; x <= TERRAIN_PAGE_MAX_X; ++x)
781             for (long y = TERRAIN_PAGE_MIN_Y; y <= TERRAIN_PAGE_MAX_Y; ++y)
782                 defineTerrain(x, y, blankTerrain);
783         // sync load since we want everything in place when we start
784         mTerrainGroup->loadAllTerrains(true);
785 #endif
786 
787         if (mTerrainsImported)
788         {
789             TerrainGroup::TerrainIterator ti = mTerrainGroup->getTerrainIterator();
790             while(ti.hasMoreElements())
791             {
792                 Terrain* t = ti.getNext()->instance;
793                 initBlendMaps(t);
794             }
795         }
796 
797         mTerrainGroup->freeTemporaryResources();
798 
799         // create a few entities on the terrain
800         Entity* e = mSceneMgr->createEntity("tudorhouse.mesh");
801         Vector3 entPos(mTerrainPos.x + 2043, 0, mTerrainPos.z + 1715);
802         Quaternion rot;
803         entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) + 65.5 + mTerrainPos.y;
804         rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)), Vector3::UNIT_Y);
805         SceneNode* sn = mSceneMgr->getRootSceneNode()->createChildSceneNode(entPos, rot);
806         sn->setScale(Vector3(0.12, 0.12, 0.12));
807         sn->attachObject(e);
808         mHouseList.push_back(e);
809 
810         e = mSceneMgr->createEntity("tudorhouse.mesh");
811         entPos = Vector3(mTerrainPos.x + 1850, 0, mTerrainPos.z + 1478);
812         entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) + 65.5 + mTerrainPos.y;
813         rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)), Vector3::UNIT_Y);
814         sn = mSceneMgr->getRootSceneNode()->createChildSceneNode(entPos, rot);
815         sn->setScale(Vector3(0.12, 0.12, 0.12));
816         sn->attachObject(e);
817         mHouseList.push_back(e);
818 
819         e = mSceneMgr->createEntity("tudorhouse.mesh");
820         entPos = Vector3(mTerrainPos.x + 1970, 0, mTerrainPos.z + 2180);
821         entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) + 65.5 + mTerrainPos.y;
822         rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)), Vector3::UNIT_Y);
823         sn = mSceneMgr->getRootSceneNode()->createChildSceneNode(entPos, rot);
824         sn->setScale(Vector3(0.12, 0.12, 0.12));
825         sn->attachObject(e);
826         mHouseList.push_back(e);
827 
828         mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
829 
830 
831     }
832 
_shutdown()833     void _shutdown()
834     {
835         if (mTerrainPaging)
836         {
837             OGRE_DELETE mTerrainPaging;
838             mTerrainPaging = 0;
839             OGRE_DELETE mPageManager;
840             mPageManager = 0;
841         }
842         else if(mTerrainGroup)
843         {
844             OGRE_DELETE mTerrainGroup;
845             mTerrainGroup = 0;
846         }
847 
848         if (mTerrainGlobals)
849         {
850             OGRE_DELETE mTerrainGlobals;
851             mTerrainGlobals = 0;
852         }
853 
854         mHouseList.clear();
855 
856         SdkSample::_shutdown();
857     }
858 
859 
860 };
861 
862 #endif
863