2
Copyright (C) 2004 Erik Hjortsberg
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
#include "TerrainGenerator.h"
24
#include "TerrainInfo.h"
26
#include "framework/LoggingInstance.h"
27
#include "services/config/ConfigService.h"
29
#include "../MathConverter.h"
30
#include "../EmberOgre.h"
31
#include "../EmberEntity.h"
32
#include "../WorldEmberEntity.h"
33
#include "../EmberEntityFactory.h"
34
#include "../ShaderManager.h"
36
#include <Eris/Entity.h>
37
#include <Eris/View.h>
38
#include <Eris/TerrainMod.h>
40
#include "TerrainShader.h"
41
#include "../environment/Foliage.h"
42
#include "../environment/Forest.h"
43
#include "ISceneManagerAdapter.h"
46
#include "TerrainPage.h"
47
#include "TerrainArea.h"
48
#include "TerrainMod.h"
49
#include <Mercator/Area.h>
50
#include <Mercator/Segment.h>
51
#include <Mercator/Terrain.h>
52
#include <Mercator/TerrainMod.h>
53
#include <Mercator/Surface.h>
54
#include <Mercator/Terrain.h>
56
#include "TerrainLayerDefinitionManager.h"
57
#include "TerrainLayerDefinition.h"
58
#include "TerrainPageSurfaceLayer.h"
59
#include "../AvatarCamera.h"
61
#include "../environment/Environment.h"
63
#include <sigc++/object_slot.h>
64
#include <sigc++/bind.h>
68
#define snprintf _snprintf
69
#include <io.h> // for _access, Win32 version of stat()
70
#include <direct.h> // for _mkdir
72
#include "framework/ConsoleBackend.h"
73
#include "framework/Tokeniser.h"
78
#define I_ROUND(_x) (::lrintf(_x))
79
#elif defined(HAVE_RINTF)
80
#define I_ROUND(_x) ((int)::rintf(_x))
81
#elif defined(HAVE_RINT)
82
#define I_ROUND(_x) ((int)::rint(_x))
84
#define I_ROUND(_x) ((int)(_x))
88
#define F_ABS(_x) (::fabsf(_x))
90
#define F_ABS(_x) (::fabs(_x))
98
TerrainGenerator::TerrainGenerator(ISceneManagerAdapter* adapter)
100
UpdateShadows("update_shadows", this, "Updates shadows in the terrain."),
101
mTerrainInfo(new TerrainInfo()),
103
mHeightMax(std::numeric_limits<Ogre::Real>::min()),
104
mHeightMin(std::numeric_limits<Ogre::Real>::max()),
106
mHasTerrainInfo(false),
107
mSceneManagerAdapter(0),
108
mFoliageBatchSize(32)
111
registerSceneManagerAdapter( adapter);
113
loadTerrainOptions();
114
mTerrainInfo->setPageIndicesSize(adapter->getPageSize());
115
mTerrain = new Mercator::Terrain(Mercator::Terrain::SHADED); //, mOptions.pageSize - 1);
117
Ember::ConfigService* configSrv = Ember::EmberServices::getSingletonPtr()->getConfigService();
118
// mTerrainPageSource = new EmberTerrainPageSource(this);
119
// EmberOgre::getSingleton().getSceneManager()->registerPageSource(EmberTerrainPageSource::Name, mTerrainPageSource);
123
// EmberOgre::getSingleton().getSceneManager()->setWorldGeometry(mOptions);
124
Ogre::Root::getSingleton().addFrameListener(this);
126
configSrv->EventChangedConfigItem.connect(sigc::mem_fun(*this, &TerrainGenerator::ConfigService_EventChangedConfigItem));
128
EmberOgre::getSingleton().getShaderManager()->EventLevelChanged.connect(sigc::bind(sigc::mem_fun(*this, &TerrainGenerator::shaderManager_LevelChanged), EmberOgre::getSingleton().getShaderManager()));
131
TerrainGenerator::~TerrainGenerator()
134
for (PageStore::iterator J = mPages.begin(); J != mPages.end(); ++J) {
138
for (ShaderStore::iterator J = mShaderMap.begin(); J != mShaderMap.end(); ++J) {
142
delete mSceneManagerAdapter;
144
//delete mTerrainPageSource;
147
Mercator::Terrain& TerrainGenerator::getTerrain()
153
void TerrainGenerator::loadTerrainOptions()
155
chdir(Ember::EmberServices::getSingletonPtr()->getConfigService()->getHomeDirectory().c_str());
157
getAdapter()->setResourceGroupName("General" );
159
getAdapter()->loadOptions(Ember::EmberServices::getSingletonPtr()->getConfigService()->getSharedConfigDirectory() + "terrain.cfg");
161
getAdapter()->setCamera( &EmberOgre::getSingleton().getMainCamera()->getCamera());
165
ISceneManagerAdapter* TerrainGenerator::getAdapter() const
167
return mSceneManagerAdapter;
170
TerrainShader* TerrainGenerator::createShader(const TerrainLayerDefinition* layerDef, Mercator::Shader* mercatorShader)
172
size_t index = mShaderMap.size();
173
S_LOG_VERBOSE("Creating new shader for shader " << layerDef->getShaderName() <<" with index " << index);
174
TerrainShader* shader = new TerrainShader(mTerrain, index, layerDef, mercatorShader);
176
mBaseShaders.push_back(shader);
177
mShaderMap[shader->getShader()] = shader;
178
EventShaderCreated.emit(shader);
182
// TerrainShader* TerrainGenerator::createShader(Ogre::MaterialPtr material, Mercator::Shader* mercatorShader)
184
// size_t index = mShaderMap.size();
185
// S_LOG_VERBOSE("Creating new shader for material " << material->getName() <<" with index " << index);
186
// TerrainShader* shader = new TerrainShader(mTerrain, index, material, mercatorShader);
188
// mBaseShaders.push_back(shader);
189
// mShaderMap[shader->getShader()] = shader;
194
void TerrainGenerator::addTerrainMod(TerrainMod* terrainMod)
196
Eris::TerrainMod* erisTerrainMod(terrainMod->getErisMod());
197
/// Listen for changes to the modifier
198
terrainMod->EventModChanged.connect(sigc::bind(sigc::mem_fun(*this, &TerrainGenerator::TerrainMod_Changed), terrainMod));
199
/// Listen for deletion of the modifier
200
terrainMod->EventModDeleted.connect(sigc::bind(sigc::mem_fun(*this, &TerrainGenerator::TerrainMod_Deleted), terrainMod));
202
/// We need to save this pointer to use when the modifier is changed or deleted
203
Mercator::TerrainMod* mod = mTerrain->addMod(*erisTerrainMod->getMod());
205
mTerrainMods.insert(TerrainModMap::value_type(erisTerrainMod->getEntity()->getId(), mod));
208
std::vector<TerrainPosition> updatedPositions;
209
updatedPositions.push_back(TerrainPosition(mod->bbox().getCenter().x(), mod->bbox().getCenter().y()));
210
reloadTerrain(updatedPositions);
214
void TerrainGenerator::TerrainMod_Changed(TerrainMod* terrainMod)
217
Eris::TerrainMod* erisTerrainMod(terrainMod->getErisMod());
218
std::vector<TerrainPosition> updatedPositions;
220
// Clear this modifier from the terrain, then reapply it so the new parameters take effect
221
// Get its owner's ID
222
const std::string& entityID = erisTerrainMod->getEntity()->getId();
223
S_LOG_INFO("modhandler: changed: Mod for entity " << entityID << " updated?");
224
TerrainModMap::iterator I = mTerrainMods.find(entityID);
225
if (I != mTerrainMods.end()) {
226
updatedPositions.push_back(TerrainPosition(I->second->bbox().getCenter().x(), I->second->bbox().getCenter().y()));
227
// Use the pointer returned from addMod() to remove it
228
mTerrain->removeMod(I->second);
229
// Remove this mod from our list so we can replace the pointer with a new one
230
mTerrainMods.erase(I);
233
// mTerrainMods.find(entityID)->second = terrainMod->getMod();
234
// mTerrain->updateMod(mTerrainMods.find(entityID)->second);
236
// Reapply the mod to the terrain with the updated parameters
237
Mercator::TerrainMod *mercatorMod = erisTerrainMod->getMod();
239
mercatorMod = mTerrain->addMod(*mercatorMod);
241
// Insert it into our list
242
mTerrainMods.insert(TerrainModMap::value_type(entityID, mercatorMod));
245
updatedPositions.push_back(TerrainPosition(mercatorMod->bbox().getCenter().x(), mercatorMod->bbox().getCenter().y()));
246
reloadTerrain(updatedPositions);
249
void TerrainGenerator::TerrainMod_Deleted(TerrainMod* terrainMod)
251
Eris::TerrainMod* erisTerrainMod(terrainMod->getErisMod());
252
// Clear this mod from the terrain
253
// Get the ID of the modifier's owner
254
const std::string& entityID = erisTerrainMod->getEntity()->getId();
255
S_LOG_INFO("modhandler: deleted: Mod for entity " << entityID << " deleted?");
256
// Use the pointer returned from addMod() to remove it
257
mTerrain->removeMod(mTerrainMods.find(entityID)->second);
258
// Remove this mod from our list
259
mTerrainMods.erase(entityID);
261
std::vector<TerrainPosition> updatedPositions;
262
updatedPositions.push_back(TerrainPosition(erisTerrainMod->getMod()->bbox().getCenter().x(), erisTerrainMod->getMod()->bbox().getCenter().y()));
263
reloadTerrain(updatedPositions);
267
void TerrainGenerator::addArea(TerrainArea* terrainArea)
270
terrainArea->EventAreaChanged.connect(sigc::bind(sigc::mem_fun(*this, &TerrainGenerator::TerrainArea_Changed), terrainArea));
271
terrainArea->EventAreaRemoved.connect(sigc::bind(sigc::mem_fun(*this, &TerrainGenerator::TerrainArea_Removed), terrainArea));
272
terrainArea->EventAreaSwapped.connect(sigc::bind(sigc::mem_fun(*this, &TerrainGenerator::TerrainArea_Swapped), terrainArea));
273
Mercator::Area* area = terrainArea->getArea();
275
//_controlfp(_PC_64, _MCW_PC);
276
//_controlfp(_RC_NEAR, _MCW_RC);
277
std::stringstream ss;
279
S_LOG_VERBOSE("Adding area to terrain with dimensions: " << ss.str());
280
mTerrain->addArea(area);
281
if (!mAreaShaders.count(area->getLayer())) {
282
S_LOG_VERBOSE("Shader does not exists, creating new.");
283
TerrainShader* shader;
284
///try to get the materialdefinition for this kind of area
285
const TerrainLayerDefinition* layerDef = TerrainLayerDefinitionManager::getSingleton().getDefinitionForArea(area->getLayer());
287
shader = createShader(layerDef, new Mercator::AreaShader(area->getLayer()));
288
mAreaShaders[area->getLayer()] = shader;
291
if (mAreaShaders.count(area->getLayer())) {
292
///mark the shader for update
293
///we'll not update immediately, we try to batch many area updates and then only update once per frame
294
markShaderForUpdate(mAreaShaders[area->getLayer()], area);
298
void TerrainGenerator::TerrainArea_Changed(TerrainArea* terrainArea)
300
Mercator::Area* area = terrainArea->getArea();
301
if (mAreaShaders.count(area->getLayer())) {
302
///mark the shader for update
303
///we'll not update immediately, we try to batch many area updates and then only update once per frame
304
markShaderForUpdate(mAreaShaders[area->getLayer()], area);
306
mTerrain->updateArea(area);
309
void TerrainGenerator::TerrainArea_Removed(TerrainArea* terrainArea)
311
Mercator::Area* area = terrainArea->getArea();
312
mTerrain->removeArea(area);
313
if (mAreaShaders.count(area->getLayer())) {
314
///mark the shader for update
315
///we'll not update immediately, we try to batch many area updates and then only update once per frame
316
markShaderForUpdate(mAreaShaders[area->getLayer()], area);
321
void TerrainGenerator::TerrainArea_Swapped(Mercator::Area& oldArea, TerrainArea* terrainArea)
323
mTerrain->removeArea(&oldArea);
324
if (mAreaShaders.count(oldArea.getLayer())) {
325
///mark the shader for update
326
///we'll not update immediately, we try to batch many area updates and then only update once per frame
327
markShaderForUpdate(mAreaShaders[oldArea.getLayer()], &oldArea);
330
Mercator::Area* area = terrainArea->getArea();
331
mTerrain->addArea(area);
332
if (!mAreaShaders.count(area->getLayer())) {
333
S_LOG_VERBOSE("Shader does not exists, creating new.");
334
TerrainShader* shader;
335
///try to get the materialdefinition for this kind of area
336
const TerrainLayerDefinition* layerDef = TerrainLayerDefinitionManager::getSingleton().getDefinitionForArea(area->getLayer());
338
shader = createShader(layerDef, new Mercator::AreaShader(area->getLayer()));
339
mAreaShaders[area->getLayer()] = shader;
342
if (mAreaShaders.count(area->getLayer())) {
343
///mark the shader for update
344
///we'll not update immediately, we try to batch many area updates and then only update once per frame
345
markShaderForUpdate(mAreaShaders[area->getLayer()], area);
349
void TerrainGenerator::markShaderForUpdate(TerrainShader* shader, Mercator::Area* terrainArea)
351
ShaderUpdateRequest& updateRequest = mShadersToUpdate[shader];
353
updateRequest.Areas.push_back(terrainArea->bbox());
355
updateRequest.UpdateAll = true;
359
bool TerrainGenerator::frameEnded(const Ogre::FrameEvent & evt)
361
//update shaders that needs updating
362
if (mShadersToUpdate.size()) {
363
// for (PageStore::iterator J = mPages.begin(); J != mPages.end(); ++J) {
364
// J->second->populateSurfaces();
367
///use a reverse iterator, since we need to update top most layers first, since lower layers might depend on them for their foliage positions
368
for (ShaderUpdateSet::reverse_iterator I = mShadersToUpdate.rbegin(); I != mShadersToUpdate.rend(); ++I) {
369
const ShaderUpdateRequest& updateRequest = I->second;
372
///We should either update all pages at once, or only those pages that intersect or contains the areas that have been changed
373
if (updateRequest.UpdateAll) {
374
for (PageStore::iterator J = mPages.begin(); J != mPages.end(); ++J) {
375
///repopulate the layer
376
J->second->updateShaderTexture((I->first), true);
379
areas = &(I->second.Areas);
380
for (PageStore::iterator J = mPages.begin(); J != mPages.end(); ++J) {
381
bool shouldUpdate = false;
382
for (AreaStore::iterator K = areas->begin(); K != areas->end(); ++K) {
383
if (WFMath::Intersect(J->second->getExtent(), *K, true) || WFMath::Contains(J->second->getExtent(), *K, true)) {
389
///repopulate the layer
390
J->second->updateShaderTexture((I->first), true);
394
EventLayerUpdated.emit(I->first, areas);
398
mShadersToUpdate.clear();
399
mChangedTerrainAreas.clear();
404
// void TerrainGenerator::prepareSegments(long segmentXStart, long segmentZStart, long numberOfSegments, bool alsoPushOntoTerrain)
406
// //TODO: implement!
410
// // for (i = segmentXStart; i < segmentXStart + numberOfSegments; ++i) {
411
// // for (j = segmentZStart; j < segmentZStart + numberOfSegments; ++j) {
412
// // if (i >= mXmin && i <= mXmax && j >= mYmin && j <=mYmax) {
413
// // mTerrain->getSegment(i, j)->populate();
414
// // mTerrain->getSegment(i, j)->populateNormals();
415
// // mTerrain->getSegment(i, j)->populateSurfaces();
416
// // TerrainPosition pos(i,j);
417
// // generateTerrainMaterials(mTerrain->getSegment(i, j), pos);
418
// // if (alsoPushOntoTerrain) {
419
// // TerrainPosition pos(i, j);
420
// // mTerrainPageSource->pushPage(pos);
425
// // // generateUnderVegetation(0, 0, 1);
426
// // // generateUnderVegetation(segmentXStart, segmentZStart, numberOfSegments);
427
// // mTerrainPageSource->setHasTerrain(true);
428
// // if (alsoPushOntoTerrain) {
429
// // mTerrainPageSource->resizeTerrain();
434
int TerrainGenerator::getPageIndexSize()
436
return mSceneManagerAdapter->getPageSize();
439
int TerrainGenerator::getPageMetersSize()
441
return getPageIndexSize() - 1;
444
void TerrainGenerator::buildHeightmap()
446
///initialize all terrain here, since we need to do that in order to get the correct height for placement even though the terrain might not show up in the SceneManager yet
448
///note that we want to use int's here, since a call to getSegment(float, float) is very much different from a call to getSegment(int, int)
450
const WFMath::AxisBox<2>& segmentBbox = mTerrainInfo->getWorldSizeInSegments();
451
for (i = static_cast<int>(segmentBbox.lowCorner().x()); i < segmentBbox.highCorner().x(); ++i) {
452
for (j = static_cast<int>(segmentBbox.lowCorner().y()); j < segmentBbox.highCorner().y(); ++j) {
453
Mercator::Segment* segment = mTerrain->getSegment(i, j);
455
//S_LOG_VERBOSE("Preparing segment at position: x=" << i << " y=" << j );
457
segment->populateNormals();
458
segment->populateSurfaces();
459
mHeightMax = std::max(mHeightMax, segment->getMax());
460
mHeightMin = std::min(mHeightMin, segment->getMin());
468
// void TerrainGenerator::createShaders(WorldEmberEntity* worldEntity)
470
// if (worldEntity) {
471
// if (worldEntity->hasAttr("surfaces")) {
478
void TerrainGenerator::registerSceneManagerAdapter(ISceneManagerAdapter* adapter)
480
mSceneManagerAdapter = adapter;
484
void TerrainGenerator::prepareAllSegments()
488
//_controlfp(_PC_64, _MCW_PC);
489
//_controlfp(_RC_NEAR, _MCW_RC);
492
// getAdapter()->setWorldPagesDimensions(mTerrainInfo->getTotalNumberOfPagesX(), mTerrainInfo->getTotalNumberOfPagesY(), mTerrainInfo->getPageOffsetX(), mTerrainInfo->getPageOffsetY());
493
getAdapter()->setWorldPagesDimensions(mTerrainInfo->getTotalNumberOfPagesY(), mTerrainInfo->getTotalNumberOfPagesX(), mTerrainInfo->getPageOffsetY(), mTerrainInfo->getPageOffsetX());
497
getAdapter()->loadScene();
498
const WFMath::AxisBox<2>& worldSize = mTerrainInfo->getWorldSizeInIndices();
499
float heightMin = mHeightMin;
500
float heightMax = mHeightMax;
501
if (heightMax < heightMin) {
502
S_LOG_WARNING("It seems like the world haven't been properly initialized. Perhaps the server has an invalid terrain?");
506
Ogre::AxisAlignedBox worldBox(worldSize.lowCorner().x(), heightMin, -worldSize.highCorner().y(), worldSize.highCorner().x(), heightMax, -worldSize.lowCorner().y());
508
std::stringstream ss;
510
S_LOG_INFO("New size of the world: " << ss.str());
512
getAdapter()->resize(worldBox ,16);
514
S_LOG_INFO("Pages: X: " << mTerrainInfo->getTotalNumberOfPagesX() << " Y: " << mTerrainInfo->getTotalNumberOfPagesY() << " Total: " << mTerrainInfo->getTotalNumberOfPagesX() * mTerrainInfo->getTotalNumberOfPagesY());
515
S_LOG_INFO("Page offset: X" << mTerrainInfo->getPageOffsetX() << " Y: " << mTerrainInfo->getPageOffsetY());
517
///load the first page, thus bypassing the normal paging system. This is to prevent the user from floating in the thin air while the paging system waits for a suitable time to load the first page.
518
getAdapter()->loadFirstPage();
520
EmberOgre::getSingleton().getEntityFactory()->getWorld()->getEnvironment()->getForest()->initialize();
525
bool TerrainGenerator::isValidTerrainAt(const TerrainPosition& position)
527
// /* int x = (int)position.x();
528
// int y = (int)position.y();*/
529
Mercator::Segment* segment = mTerrain->getSegment(position.x(),position.y());
530
return (segment && segment->isValid());
531
// return (segment && segment->isValid() && getMaterialForSegment(position));
535
TerrainPage* TerrainGenerator::getTerrainPageAtPosition(const TerrainPosition& worldPosition)
538
int xRemainder = static_cast<int>(getMin().x()) % (getPageMetersSize());
539
int yRemainder = static_cast<int>(getMin().y()) % (getPageMetersSize());
541
int xIndex = static_cast<int>(floor((worldPosition.x() + xRemainder) / (getPageMetersSize())));
542
int yIndex = static_cast<int>(ceil((worldPosition.y() + yRemainder) / (getPageMetersSize())));
543
// int yIndex = static_cast<int>(floor((worldPosition.y() + yRemainder) / (getPageMetersSize())));
545
TerrainPagestore::iterator I = mTerrainPages.find(xIndex);
546
if (I != mTerrainPages.end()) {
547
TerrainPagecolumn::iterator J = I->second.find(yIndex);
548
if (J != I->second.end()) {
556
TerrainPage* TerrainGenerator::getTerrainPageAtIndex(const Ogre::Vector2& ogreIndexPosition, bool createIfMissing)
559
//S_LOG_INFO("Requesting page at ogre position x: " << ogreIndexPosition.x << " y: " << ogreIndexPosition.y);
561
///TerrainInfo deals with WF space, so we need to flip the x and y offsets here (as it's in Ogre space)
562
Ogre::Vector2 adjustedOgrePos(ogreIndexPosition.x - mTerrainInfo->getPageOffsetY(), ogreIndexPosition.y - mTerrainInfo->getPageOffsetX());
564
TerrainPosition pos(Ogre2Atlas(adjustedOgrePos));
566
int x = static_cast<int>(pos.x());
567
int y = static_cast<int>(pos.y());
569
if (mTerrainPages[x][y] == 0) {
570
if (createIfMissing) {
572
//TerrainPosition adjustedPos(pos.x() - pageOffsetX, pos.y() - pageOffsetY);
574
mTerrainPages[x][y] = createPage(pos);
575
assert(mTerrainPages[x][y]);
580
return mTerrainPages[x][y];
583
TerrainPage* TerrainGenerator::createPage(const TerrainPosition& pos)
586
bool showFoliage = isFoliageShown();
589
///since we initialized all terrain in initTerrain we can count on all terrain segments being created and populated already
592
TerrainPage* page = new TerrainPage(TerrainPosition(pos), mShaderMap, this);
593
//mPages[ss.str()] = page;
595
std::stringstream ss;
596
ss << pos.x() << "x" << pos.y();
597
mPages[ss.str()] = page;
599
//add the base shaders, this should probably be refactored into a server side thing in the future
600
for (std::list<TerrainShader*>::iterator I = mBaseShaders.begin(); I != mBaseShaders.end(); ++I) {
604
page->createShadow(EmberOgre::getSingleton().getEntityFactory()->getWorld()->getEnvironment()->getSun()->getSunDirection());
605
page->generateTerrainMaterials(false);
617
void TerrainGenerator::updateFoliageVisibilty()
619
bool showFoliage = isFoliageShown();
621
PageStore::iterator I = mPages.begin();
622
for(;I != mPages.end(); ++I) {
624
I->second->showFoliage();
626
I->second->hideFoliage();
631
void TerrainGenerator::ConfigService_EventChangedConfigItem(const std::string& section, const std::string& key)
633
if (section == "graphics") {
634
if (key == "foliage") {
635
updateFoliageVisibilty();
640
bool TerrainGenerator::isFoliageShown() const
642
if (Ember::EmberServices::getSingletonPtr()->getConfigService()->itemExists("graphics", "foliage") && GpuProgramManager::getSingleton().isSyntaxSupported("arbvp1")) {
643
return static_cast<bool>(Ember::EmberServices::getSingletonPtr()->getConfigService()->getValue("graphics", "foliage"));
650
float TerrainGenerator::getHeight(const TerrainPosition& point) const
654
WFMath::Vector<3> vector;
656
bool success = mTerrain->getHeightAndNormal(point.x(), point.y(), height, vector);
661
///make undefined ground be one meter below the water
666
void TerrainGenerator::updateShadows()
668
Ogre::Vector3 sunDirection = EmberOgre::getSingleton().getEntityFactory()->getWorld()->getEnvironment()->getSun()->getSunDirection();
670
PageStore::iterator I = mPages.begin();
671
for(;I != mPages.end(); ++I) {
672
I->second->updateShadow(sunDirection);
677
bool TerrainGenerator::updateTerrain(const TerrainDefPointStore& terrainPoints)
679
std::vector<TerrainPosition> updatedPositions;
680
bool wasUpdate = false;
681
for (TerrainDefPointStore::const_iterator I = terrainPoints.begin(); I != terrainPoints.end(); ++I) {
683
Mercator::BasePoint bp;
684
if (mTerrain->getBasePoint(static_cast<int>(I->getPosition().x()), static_cast<int>(I->getPosition().y()), bp) && (I->getHeight() == bp.height())) {
685
S_LOG_VERBOSE( "Point [" << I->getPosition().x() << "," << I->getPosition().y() << " unchanged");
689
S_LOG_VERBOSE( "Setting base point [" << I->getPosition().x() << "," << I->getPosition().y() << " to height " << I->getHeight());
691
bp.height() = I->getHeight();
692
/// FIXME Sort out roughness and falloff, and generally
693
/// verify this code is the same as that in Terrain layer
694
mTerrain->setBasePoint(static_cast<int>(I->getPosition().x()), static_cast<int>(I->getPosition().y()), bp);
695
mTerrainInfo->setBasePoint(I->getPosition(), bp);
696
updatedPositions.push_back(TerrainPosition(I->getPosition().x() * mTerrain->getResolution(), I->getPosition().y() * mTerrain->getResolution()));
698
mSegments = &mTerrain->getTerrain();
702
///for some yet undetermined reason we'll get blank segments seeminly at random in the terrain if we'll load it dynamically when requested by the scene manager, so avoid that we'll initialize everything now
703
///HACK: this is of course just a temporary fix
704
// for (int i = 0; i < mTerrainInfo->getTotalNumberOfPagesX(); ++i) {
705
// for (int j = 0; j < mTerrainInfo->getTotalNumberOfPagesY(); ++j) {
706
// getTerrainPage(Ogre::Vector2(i, j), true);
710
///check if the size of the world has been changed
711
// if (Xmin != mXmin || Xmax != mXmax || Ymin != mYmin || Ymax != mYmax) {
712
EventWorldSizeChanged.emit();
715
if (!mHasTerrainInfo) {
716
mHasTerrainInfo = true;
719
///if it's an update, we need to reload all pages and adjust all entity positions
720
reloadTerrain(updatedPositions);
729
void TerrainGenerator::reloadTerrain(std::vector<TerrainPosition>& positions)
731
std::set<TerrainPage*> pagesToUpdate;
732
for (std::vector<TerrainPosition>::iterator I(positions.begin()); I != positions.end(); ++I) {
733
const TerrainPosition& worldPosition(*I);
735
///make sure we sample pages from all four points around the base point, in case the base point is on a page border
736
for (int i = -65; i < 66; i += 64) {
737
for (int j = -65; j < 66; j += 64) {
738
TerrainPosition position(worldPosition.x() + i, worldPosition.y() + j);
739
page = getTerrainPageAtPosition(position);
741
pagesToUpdate.insert(page);
747
EventBeforeTerrainUpdate(positions, pagesToUpdate);
748
updateHeightMapAndShaders(pagesToUpdate);
749
updateEntityPositions(pagesToUpdate);
750
EventAfterTerrainUpdate(positions, pagesToUpdate);
753
void TerrainGenerator::updateHeightMapAndShaders(const std::set<TerrainPage*>& pagesToUpdate)
755
const Ogre::Vector3& sunDirection = EmberOgre::getSingleton().getEntityFactory()->getWorld()->getEnvironment()->getSun()->getSunDirection();
757
///reload all shader textures of the affected pages
758
for (std::set<TerrainPage*>::const_iterator I = pagesToUpdate.begin(); I != pagesToUpdate.end(); ++I) {
759
(*I)->updateAllShaderTextures();
760
(*I)->updateShadow(sunDirection);
765
void TerrainGenerator::updateEntityPositions(const std::set<TerrainPage*>& pagesToUpdate)
767
EmberEntity* entity = EmberOgre::getSingleton().getEntityFactory()->getWorld();
769
updateEntityPosition(entity, pagesToUpdate);
773
void TerrainGenerator::updateEntityPosition(EmberEntity* entity, const std::set<TerrainPage*>& pagesToUpdate)
775
entity->adjustPosition();
776
for (unsigned int i = 0; i < entity->numContained(); ++i) {
777
EmberEntity* containedEntity = static_cast<EmberEntity*>(entity->getContained(i));
778
updateEntityPosition(containedEntity, pagesToUpdate);
783
const TerrainPosition TerrainGenerator::getMax( ) const
785
return mTerrainInfo->getWorldSizeInIndices().highCorner();
786
// return TerrainPosition(mXmax * 64, mYmax * 64);
789
const TerrainPosition TerrainGenerator::getMin( ) const
791
return mTerrainInfo->getWorldSizeInIndices().lowCorner();
792
// return TerrainPosition(mXmin * 64, mYmin * 64);
795
void TerrainGenerator::runCommand(const std::string &command, const std::string &args)
797
if (UpdateShadows == command) {
801
const TerrainInfo & TerrainGenerator::getTerrainInfo( ) const
803
return *mTerrainInfo;
806
void TerrainGenerator::getShadowColourAt(const Ogre::Vector2& position, Ogre::uint32& colour)
808
//TODO: add caching of the last fetched terrain page and first check if the position isn't at that page, since we'll in most cass will call this method with positions that are close to eachother
809
TerrainPosition wfPos(Ogre2Atlas(position));
810
TerrainPage* terrainPage = getTerrainPageAtPosition(wfPos);
811
TerrainPageShadow& terrainShadow = terrainPage->getPageShadow();
813
Ogre::TRect<float> ogrePageExtent = Atlas2Ogre(terrainPage->getExtent());
814
terrainShadow.getShadowColourAt(Ogre::Vector2(position.x - ogrePageExtent.left, position.y - ogrePageExtent.top), colour);
818
void TerrainGenerator::getShadowColourAt(const Ogre::Vector2& position, Ogre::ColourValue& colour)
820
//TODO: add caching of the last fetched terrain page and first check if the position isn't at that page, since we'll in most cass will call this method with positions that are close to eachother
821
TerrainPosition wfPos(Ogre2Atlas(position));
822
TerrainPage* terrainPage = getTerrainPageAtPosition(wfPos);
823
TerrainPageShadow& terrainShadow = terrainPage->getPageShadow();
824
Ogre::TRect<float> ogrePageExtent = Atlas2Ogre(terrainPage->getExtent());
825
terrainShadow.getShadowColourAt(Ogre::Vector2(position.x - ogrePageExtent.left, position.y - ogrePageExtent.top), colour);
828
bool TerrainGenerator::getNormal(const TerrainPosition& worldPosition, WFMath::Vector<3>& normal) const
830
// static WFMath::Vector<3> defaultNormal(1,1,1);
831
int ix = I_ROUND(floor(worldPosition.x() / 64));
832
int iy = I_ROUND(floor(worldPosition.y() / 64));
834
Mercator::Segment * s = mTerrain->getSegment(ix, iy);
835
if ((s == 0) || (!s->isValid())) {
838
float xPos = I_ROUND(worldPosition.x()) - (ix * 64);
839
float yPos = I_ROUND(worldPosition.y()) - (iy * 64);
840
size_t normalPos = (yPos * 64 * 3) + (xPos * 3);
841
normal.x() = s->getNormals()[normalPos];
842
normal.y() = s->getNormals()[normalPos + 1];
843
normal.z() = s->getNormals()[normalPos + 2];
849
void TerrainGenerator::shaderManager_LevelChanged(ShaderManager* shaderManager)
851
for (PageStore::iterator J = mPages.begin(); J != mPages.end(); ++J) {
852
J->second->generateTerrainMaterials(true);