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

« back to all changes in this revision

Viewing changes to src/components/ogre/terrain/TerrainGenerator.cpp

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2004  Erik Hjortsberg
 
3
 
 
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.
 
8
 
 
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.
 
13
 
 
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.
 
17
*/
 
18
 
 
19
#ifdef HAVE_CONFIG_H
 
20
#include "config.h"
 
21
#endif
 
22
 
 
23
#include "TerrainGenerator.h"
 
24
#include "TerrainInfo.h"
 
25
 
 
26
#include "framework/LoggingInstance.h"
 
27
#include "services/config/ConfigService.h"
 
28
 
 
29
#include "../MathConverter.h"
 
30
#include "../EmberOgre.h"
 
31
#include "../EmberEntity.h"
 
32
#include "../WorldEmberEntity.h"
 
33
#include "../EmberEntityFactory.h"
 
34
#include "../ShaderManager.h"
 
35
 
 
36
#include <Eris/Entity.h>
 
37
#include <Eris/View.h>
 
38
#include <Eris/TerrainMod.h>
 
39
 
 
40
#include "TerrainShader.h"
 
41
#include "../environment/Foliage.h"
 
42
#include "../environment/Forest.h"
 
43
#include "ISceneManagerAdapter.h"
 
44
 
 
45
 
 
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>
 
55
 
 
56
#include "TerrainLayerDefinitionManager.h"
 
57
#include "TerrainLayerDefinition.h"
 
58
#include "TerrainPageSurfaceLayer.h"
 
59
#include "../AvatarCamera.h"
 
60
 
 
61
#include "../environment/Environment.h"
 
62
 
 
63
#include <sigc++/object_slot.h>
 
64
#include <sigc++/bind.h>
 
65
 
 
66
#ifdef WIN32
 
67
        #include <tchar.h>
 
68
        #define snprintf _snprintf
 
69
    #include <io.h> // for _access, Win32 version of stat()
 
70
    #include <direct.h> // for _mkdir
 
71
#endif
 
72
#include "framework/ConsoleBackend.h"
 
73
#include "framework/Tokeniser.h"
 
74
 
 
75
#include <limits>
 
76
 
 
77
#ifdef HAVE_LRINTF
 
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)) 
 
83
#else
 
84
    #define I_ROUND(_x) ((int)(_x)) 
 
85
#endif
 
86
 
 
87
#ifdef HAVE_FABSF
 
88
    #define F_ABS(_x) (::fabsf(_x))
 
89
#else
 
90
    #define F_ABS(_x) (::fabs(_x))
 
91
#endif
 
92
 
 
93
using namespace Ogre;
 
94
namespace EmberOgre {
 
95
namespace Terrain {
 
96
 
 
97
 
 
98
TerrainGenerator::TerrainGenerator(ISceneManagerAdapter* adapter)
 
99
 
100
UpdateShadows("update_shadows", this, "Updates shadows in the terrain."),
 
101
mTerrainInfo(new TerrainInfo()),
 
102
mTerrain(0),
 
103
mHeightMax(std::numeric_limits<Ogre::Real>::min()),
 
104
mHeightMin(std::numeric_limits<Ogre::Real>::max()),
 
105
mSegments(0),
 
106
mHasTerrainInfo(false),
 
107
mSceneManagerAdapter(0),
 
108
mFoliageBatchSize(32)
 
109
{
 
110
 
 
111
        registerSceneManagerAdapter( adapter);
 
112
        
 
113
        loadTerrainOptions();
 
114
        mTerrainInfo->setPageIndicesSize(adapter->getPageSize());
 
115
        mTerrain = new Mercator::Terrain(Mercator::Terrain::SHADED); //, mOptions.pageSize - 1);
 
116
        
 
117
        Ember::ConfigService* configSrv = Ember::EmberServices::getSingletonPtr()->getConfigService();
 
118
//      mTerrainPageSource = new EmberTerrainPageSource(this);
 
119
//      EmberOgre::getSingleton().getSceneManager()->registerPageSource(EmberTerrainPageSource::Name, mTerrainPageSource);
 
120
 
 
121
 
 
122
 
 
123
//      EmberOgre::getSingleton().getSceneManager()->setWorldGeometry(mOptions);
 
124
        Ogre::Root::getSingleton().addFrameListener(this);
 
125
        
 
126
        configSrv->EventChangedConfigItem.connect(sigc::mem_fun(*this, &TerrainGenerator::ConfigService_EventChangedConfigItem));
 
127
        
 
128
        EmberOgre::getSingleton().getShaderManager()->EventLevelChanged.connect(sigc::bind(sigc::mem_fun(*this, &TerrainGenerator::shaderManager_LevelChanged), EmberOgre::getSingleton().getShaderManager()));
 
129
}
 
130
 
 
131
TerrainGenerator::~TerrainGenerator()
 
132
{
 
133
 
 
134
        for (PageStore::iterator J = mPages.begin(); J != mPages.end(); ++J) {
 
135
                delete J->second;
 
136
        }
 
137
        
 
138
        for (ShaderStore::iterator J = mShaderMap.begin(); J != mShaderMap.end(); ++J) {
 
139
                delete J->second;
 
140
        }       
 
141
        
 
142
        delete mSceneManagerAdapter;
 
143
        delete mTerrain;
 
144
        //delete mTerrainPageSource;
 
145
}
 
146
 
 
147
Mercator::Terrain& TerrainGenerator::getTerrain()
 
148
{
 
149
        return *mTerrain;
 
150
}
 
151
 
 
152
 
 
153
void TerrainGenerator::loadTerrainOptions()
 
154
{
 
155
        chdir(Ember::EmberServices::getSingletonPtr()->getConfigService()->getHomeDirectory().c_str());
 
156
        
 
157
        getAdapter()->setResourceGroupName("General" );
 
158
 
 
159
        getAdapter()->loadOptions(Ember::EmberServices::getSingletonPtr()->getConfigService()->getSharedConfigDirectory() + "terrain.cfg");
 
160
        
 
161
        getAdapter()->setCamera( &EmberOgre::getSingleton().getMainCamera()->getCamera());
 
162
 
 
163
}
 
164
 
 
165
ISceneManagerAdapter* TerrainGenerator::getAdapter() const
 
166
{
 
167
        return mSceneManagerAdapter;
 
168
}
 
169
 
 
170
TerrainShader* TerrainGenerator::createShader(const TerrainLayerDefinition* layerDef, Mercator::Shader* mercatorShader)
 
171
{
 
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);
 
175
 
 
176
        mBaseShaders.push_back(shader);
 
177
        mShaderMap[shader->getShader()] = shader;
 
178
        EventShaderCreated.emit(shader);
 
179
        return shader;
 
180
}
 
181
 
 
182
// TerrainShader* TerrainGenerator::createShader(Ogre::MaterialPtr material, Mercator::Shader* mercatorShader)
 
183
// {
 
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);
 
187
// 
 
188
//      mBaseShaders.push_back(shader);
 
189
//      mShaderMap[shader->getShader()] = shader;
 
190
//      return shader;
 
191
// }
 
192
 
 
193
 
 
194
void TerrainGenerator::addTerrainMod(TerrainMod* terrainMod)
 
195
{
 
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));
 
201
 
 
202
        /// We need to save this pointer to use when the modifier is changed or deleted
 
203
        Mercator::TerrainMod* mod = mTerrain->addMod(*erisTerrainMod->getMod());
 
204
 
 
205
        mTerrainMods.insert(TerrainModMap::value_type(erisTerrainMod->getEntity()->getId(), mod));
 
206
    
 
207
    
 
208
        std::vector<TerrainPosition> updatedPositions;
 
209
        updatedPositions.push_back(TerrainPosition(mod->bbox().getCenter().x(), mod->bbox().getCenter().y()));
 
210
        reloadTerrain(updatedPositions);
 
211
 
 
212
}
 
213
 
 
214
void TerrainGenerator::TerrainMod_Changed(TerrainMod* terrainMod)
 
215
{
 
216
 
 
217
        Eris::TerrainMod* erisTerrainMod(terrainMod->getErisMod());
 
218
        std::vector<TerrainPosition> updatedPositions;
 
219
        
 
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);
 
231
        }
 
232
 
 
233
//      mTerrainMods.find(entityID)->second = terrainMod->getMod();
 
234
//      mTerrain->updateMod(mTerrainMods.find(entityID)->second);
 
235
 
 
236
        // Reapply the mod to the terrain with the updated parameters
 
237
        Mercator::TerrainMod *mercatorMod = erisTerrainMod->getMod();
 
238
        if (mercatorMod) {
 
239
                mercatorMod = mTerrain->addMod(*mercatorMod);
 
240
        
 
241
                // Insert it into our list
 
242
                mTerrainMods.insert(TerrainModMap::value_type(entityID, mercatorMod));
 
243
        }
 
244
 
 
245
        updatedPositions.push_back(TerrainPosition(mercatorMod->bbox().getCenter().x(), mercatorMod->bbox().getCenter().y()));
 
246
        reloadTerrain(updatedPositions);
 
247
}
 
248
 
 
249
void TerrainGenerator::TerrainMod_Deleted(TerrainMod* terrainMod)
 
250
{
 
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);
 
260
 
 
261
        std::vector<TerrainPosition> updatedPositions;
 
262
        updatedPositions.push_back(TerrainPosition(erisTerrainMod->getMod()->bbox().getCenter().x(), erisTerrainMod->getMod()->bbox().getCenter().y()));
 
263
        reloadTerrain(updatedPositions);
 
264
 
 
265
}
 
266
 
 
267
void TerrainGenerator::addArea(TerrainArea* terrainArea)
 
268
{
 
269
 
 
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();
 
274
 //   _fpreset();
 
275
        //_controlfp(_PC_64, _MCW_PC);
 
276
        //_controlfp(_RC_NEAR, _MCW_RC);
 
277
        std::stringstream ss;
 
278
        ss << area->bbox();
 
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());
 
286
                if (layerDef) {
 
287
                        shader = createShader(layerDef, new Mercator::AreaShader(area->getLayer()));
 
288
                        mAreaShaders[area->getLayer()] = shader;
 
289
                }
 
290
        }
 
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);
 
295
        }
 
296
}
 
297
 
 
298
void TerrainGenerator::TerrainArea_Changed(TerrainArea* terrainArea)
 
299
{
 
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);
 
305
        }
 
306
        mTerrain->updateArea(area);
 
307
}
 
308
 
 
309
void TerrainGenerator::TerrainArea_Removed(TerrainArea* terrainArea)
 
310
{
 
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);
 
317
        }
 
318
}
 
319
 
 
320
 
 
321
void TerrainGenerator::TerrainArea_Swapped(Mercator::Area& oldArea, TerrainArea* terrainArea)
 
322
{
 
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);
 
328
        }
 
329
        
 
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());
 
337
                if (layerDef) {
 
338
                        shader = createShader(layerDef, new Mercator::AreaShader(area->getLayer()));
 
339
                        mAreaShaders[area->getLayer()] = shader;
 
340
                }
 
341
        }
 
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);
 
346
        }
 
347
        
 
348
}
 
349
void TerrainGenerator::markShaderForUpdate(TerrainShader* shader, Mercator::Area* terrainArea)
 
350
{
 
351
        ShaderUpdateRequest& updateRequest = mShadersToUpdate[shader];
 
352
        if (terrainArea) {
 
353
                updateRequest.Areas.push_back(terrainArea->bbox());
 
354
        } else {
 
355
                updateRequest.UpdateAll = true;
 
356
        }
 
357
}
 
358
 
 
359
bool TerrainGenerator::frameEnded(const Ogre::FrameEvent & evt)
 
360
{
 
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();
 
365
//              }       
 
366
                
 
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;
 
370
                        
 
371
                        AreaStore* areas(0);
 
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);
 
377
                                }
 
378
                        } else {
 
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)) {
 
384
                                                        shouldUpdate = true;
 
385
                                                        break;
 
386
                                                }
 
387
                                        }
 
388
                                        if (shouldUpdate) {
 
389
                                                ///repopulate the layer
 
390
                                                J->second->updateShaderTexture((I->first), true);
 
391
                                        }
 
392
                                }
 
393
                        }
 
394
                        EventLayerUpdated.emit(I->first, areas);
 
395
                }       
 
396
        }
 
397
        
 
398
        mShadersToUpdate.clear();
 
399
        mChangedTerrainAreas.clear();
 
400
        return true;
 
401
 
 
402
}
 
403
 
 
404
// void TerrainGenerator::prepareSegments(long segmentXStart, long segmentZStart, long numberOfSegments, bool alsoPushOntoTerrain)
 
405
// {
 
406
// //TODO: implement!
 
407
// 
 
408
// 
 
409
// //   int i,j;
 
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);
 
421
// //                           }
 
422
// //                   }
 
423
// //           }
 
424
// //   }
 
425
// // //        generateUnderVegetation(0, 0, 1);
 
426
// // //        generateUnderVegetation(segmentXStart, segmentZStart, numberOfSegments);
 
427
// //   mTerrainPageSource->setHasTerrain(true);
 
428
// //   if (alsoPushOntoTerrain) {
 
429
// //           mTerrainPageSource->resizeTerrain();
 
430
// //   }
 
431
//      
 
432
// }
 
433
 
 
434
int TerrainGenerator::getPageIndexSize() 
 
435
{
 
436
        return mSceneManagerAdapter->getPageSize();
 
437
}
 
438
 
 
439
int TerrainGenerator::getPageMetersSize() 
 
440
{
 
441
        return getPageIndexSize() - 1;
 
442
}
 
443
 
 
444
void TerrainGenerator::buildHeightmap()
 
445
{
 
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
 
447
        
 
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)
 
449
        int i,j;
 
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);
 
454
                        if (segment) {
 
455
                                //S_LOG_VERBOSE("Preparing segment at position: x=" << i << " y=" << j );
 
456
                                segment->populate();
 
457
                                segment->populateNormals();
 
458
                                segment->populateSurfaces();
 
459
                                mHeightMax = std::max(mHeightMax, segment->getMax());
 
460
                                mHeightMin = std::min(mHeightMin, segment->getMin());
 
461
                        }
 
462
                }
 
463
        }
 
464
 
 
465
 
 
466
}
 
467
 
 
468
// void TerrainGenerator::createShaders(WorldEmberEntity* worldEntity)
 
469
// {
 
470
//      if (worldEntity) {
 
471
//              if (worldEntity->hasAttr("surfaces")) {
 
472
//                      
 
473
//              }
 
474
//      }
 
475
// }
 
476
 
 
477
 
 
478
void TerrainGenerator::registerSceneManagerAdapter(ISceneManagerAdapter* adapter)
 
479
{
 
480
        mSceneManagerAdapter = adapter;
 
481
}
 
482
 
 
483
 
 
484
void TerrainGenerator::prepareAllSegments()
 
485
{
 
486
        
 
487
 //   _fpreset();
 
488
        //_controlfp(_PC_64, _MCW_PC);
 
489
        //_controlfp(_RC_NEAR, _MCW_RC);
 
490
 
 
491
        
 
492
//      getAdapter()->setWorldPagesDimensions(mTerrainInfo->getTotalNumberOfPagesX(), mTerrainInfo->getTotalNumberOfPagesY(), mTerrainInfo->getPageOffsetX(), mTerrainInfo->getPageOffsetY());
 
493
        getAdapter()->setWorldPagesDimensions(mTerrainInfo->getTotalNumberOfPagesY(), mTerrainInfo->getTotalNumberOfPagesX(), mTerrainInfo->getPageOffsetY(), mTerrainInfo->getPageOffsetX());
 
494
        
 
495
 
 
496
                
 
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?");
 
503
                heightMin = -100;
 
504
                heightMax = 100;
 
505
        }
 
506
        Ogre::AxisAlignedBox worldBox(worldSize.lowCorner().x(), heightMin, -worldSize.highCorner().y(), worldSize.highCorner().x(), heightMax, -worldSize.lowCorner().y());
 
507
        
 
508
        std::stringstream ss;
 
509
        ss << worldBox;
 
510
        S_LOG_INFO("New size of the world: " << ss.str());
 
511
        
 
512
        getAdapter()->resize(worldBox ,16);
 
513
        
 
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());
 
516
        
 
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();
 
519
 
 
520
        EmberOgre::getSingleton().getEntityFactory()->getWorld()->getEnvironment()->getForest()->initialize();  
 
521
        
 
522
}
 
523
 
 
524
 
 
525
bool TerrainGenerator::isValidTerrainAt(const TerrainPosition& position)
 
526
{
 
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));
 
532
}
 
533
 
 
534
 
 
535
TerrainPage* TerrainGenerator::getTerrainPageAtPosition(const TerrainPosition& worldPosition)
 
536
{
 
537
        
 
538
        int xRemainder = static_cast<int>(getMin().x()) % (getPageMetersSize());
 
539
        int yRemainder = static_cast<int>(getMin().y()) % (getPageMetersSize());
 
540
 
 
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())));
 
544
 
 
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()) {
 
549
                        return J->second;
 
550
                }
 
551
        }
 
552
        return 0;
 
553
}
 
554
 
 
555
 
 
556
TerrainPage* TerrainGenerator::getTerrainPageAtIndex(const Ogre::Vector2& ogreIndexPosition, bool createIfMissing)
 
557
{
 
558
        //_fpreset();
 
559
        //S_LOG_INFO("Requesting page at ogre position x: " << ogreIndexPosition.x << " y: " << ogreIndexPosition.y);
 
560
        
 
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());
 
563
        
 
564
        TerrainPosition pos(Ogre2Atlas(adjustedOgrePos));
 
565
        
 
566
        int x = static_cast<int>(pos.x());
 
567
        int y = static_cast<int>(pos.y());
 
568
        
 
569
        if (mTerrainPages[x][y] == 0) {
 
570
                if (createIfMissing) {
 
571
        
 
572
                        //TerrainPosition adjustedPos(pos.x() - pageOffsetX, pos.y() - pageOffsetY);
 
573
        
 
574
                        mTerrainPages[x][y] = createPage(pos);
 
575
                        assert(mTerrainPages[x][y]);
 
576
                } else {
 
577
                        return 0;
 
578
                }
 
579
        }
 
580
        return mTerrainPages[x][y];
 
581
}
 
582
 
 
583
TerrainPage* TerrainGenerator::createPage(const TerrainPosition& pos)
 
584
{
 
585
        
 
586
        bool showFoliage = isFoliageShown();
 
587
        
 
588
        
 
589
        ///since we initialized all terrain in initTerrain we can count on all terrain segments being created and populated already
 
590
        
 
591
        
 
592
        TerrainPage* page = new TerrainPage(TerrainPosition(pos), mShaderMap, this);
 
593
        //mPages[ss.str()] = page;
 
594
        
 
595
        std::stringstream ss;
 
596
        ss << pos.x() << "x" << pos.y();
 
597
        mPages[ss.str()] = page;
 
598
        
 
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) {
 
601
                page->addShader(*I);
 
602
        }
 
603
        
 
604
        page->createShadow(EmberOgre::getSingleton().getEntityFactory()->getWorld()->getEnvironment()->getSun()->getSunDirection());
 
605
        page->generateTerrainMaterials(false);
 
606
        if (showFoliage) {
 
607
                page->showFoliage();
 
608
        }
 
609
        
 
610
 
 
611
                
 
612
        return page;
 
613
        
 
614
        
 
615
}
 
616
 
 
617
void TerrainGenerator::updateFoliageVisibilty()
 
618
{
 
619
        bool showFoliage = isFoliageShown();
 
620
        
 
621
        PageStore::iterator I = mPages.begin();
 
622
        for(;I != mPages.end(); ++I) {
 
623
                if (showFoliage) {
 
624
                        I->second->showFoliage();
 
625
                } else {
 
626
                        I->second->hideFoliage();
 
627
                }
 
628
        }
 
629
}
 
630
 
 
631
void TerrainGenerator::ConfigService_EventChangedConfigItem(const std::string& section, const std::string& key)
 
632
{
 
633
        if (section == "graphics") {
 
634
                if (key == "foliage") {
 
635
                        updateFoliageVisibilty();
 
636
                }
 
637
        }
 
638
}
 
639
 
 
640
bool TerrainGenerator::isFoliageShown() const
 
641
{
 
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"));
 
644
        }       
 
645
        return false;
 
646
}
 
647
 
 
648
 
 
649
 
 
650
float TerrainGenerator::getHeight(const TerrainPosition& point) const
 
651
{
 
652
        
 
653
        float height = 0;
 
654
        WFMath::Vector<3> vector;
 
655
        
 
656
        bool success = mTerrain->getHeightAndNormal(point.x(), point.y(), height, vector);
 
657
        if (success) {
 
658
                return height;
 
659
        } 
 
660
 
 
661
///make undefined ground be one meter below the water
 
662
        return -1;
 
663
        
 
664
}
 
665
 
 
666
void TerrainGenerator::updateShadows()
 
667
{
 
668
        Ogre::Vector3 sunDirection = EmberOgre::getSingleton().getEntityFactory()->getWorld()->getEnvironment()->getSun()->getSunDirection();
 
669
 
 
670
        PageStore::iterator I = mPages.begin();
 
671
        for(;I != mPages.end(); ++I) {
 
672
                I->second->updateShadow(sunDirection);
 
673
        }
 
674
}
 
675
 
 
676
 
 
677
bool TerrainGenerator::updateTerrain(const TerrainDefPointStore& terrainPoints)
 
678
{
 
679
        std::vector<TerrainPosition> updatedPositions;
 
680
        bool wasUpdate = false;
 
681
        for (TerrainDefPointStore::const_iterator I = terrainPoints.begin(); I != terrainPoints.end(); ++I) {
 
682
                
 
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");
 
686
            continue;
 
687
        } else {
 
688
                wasUpdate = true;
 
689
                        S_LOG_VERBOSE( "Setting base point [" << I->getPosition().x() << "," << I->getPosition().y() << " to height " << I->getHeight());
 
690
        }
 
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()));
 
697
        }
 
698
    mSegments = &mTerrain->getTerrain();
 
699
 
 
700
        buildHeightmap();
 
701
        
 
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);
 
707
//              }
 
708
//      }
 
709
        
 
710
        ///check if the size of the world has been changed
 
711
//      if (Xmin != mXmin || Xmax != mXmax || Ymin != mYmin || Ymax != mYmax) {
 
712
                EventWorldSizeChanged.emit();
 
713
//      }
 
714
        
 
715
        if (!mHasTerrainInfo) {
 
716
                mHasTerrainInfo = true;
 
717
        } else {
 
718
                if (wasUpdate) {
 
719
                        ///if it's an update, we need to reload all pages and adjust all entity positions
 
720
                        reloadTerrain(updatedPositions);
 
721
                }
 
722
        }
 
723
        
 
724
 
 
725
        return true;
 
726
}
 
727
 
 
728
 
 
729
void TerrainGenerator::reloadTerrain(std::vector<TerrainPosition>& positions)
 
730
{
 
731
        std::set<TerrainPage*> pagesToUpdate;
 
732
        for (std::vector<TerrainPosition>::iterator I(positions.begin()); I != positions.end(); ++I) {
 
733
                const TerrainPosition& worldPosition(*I);
 
734
                TerrainPage* page;
 
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);
 
740
                                if (page) {
 
741
                                        pagesToUpdate.insert(page);
 
742
                                }
 
743
                        }
 
744
                }
 
745
        }
 
746
 
 
747
        EventBeforeTerrainUpdate(positions, pagesToUpdate);
 
748
        updateHeightMapAndShaders(pagesToUpdate);
 
749
        updateEntityPositions(pagesToUpdate);
 
750
        EventAfterTerrainUpdate(positions, pagesToUpdate);
 
751
        
 
752
}
 
753
void TerrainGenerator::updateHeightMapAndShaders(const std::set<TerrainPage*>& pagesToUpdate)
 
754
{
 
755
        const Ogre::Vector3& sunDirection = EmberOgre::getSingleton().getEntityFactory()->getWorld()->getEnvironment()->getSun()->getSunDirection();
 
756
 
 
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);
 
761
                (*I)->update();
 
762
        }
 
763
}
 
764
 
 
765
void TerrainGenerator::updateEntityPositions(const std::set<TerrainPage*>& pagesToUpdate)
 
766
{
 
767
        EmberEntity* entity = EmberOgre::getSingleton().getEntityFactory()->getWorld();
 
768
        if (entity) {
 
769
                updateEntityPosition(entity, pagesToUpdate);
 
770
        }
 
771
}
 
772
 
 
773
void TerrainGenerator::updateEntityPosition(EmberEntity* entity, const std::set<TerrainPage*>& pagesToUpdate)
 
774
{
 
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);
 
779
        }
 
780
}
 
781
 
 
782
 
 
783
const TerrainPosition TerrainGenerator::getMax( ) const
 
784
{
 
785
        return mTerrainInfo->getWorldSizeInIndices().highCorner();
 
786
//      return TerrainPosition(mXmax * 64, mYmax * 64);
 
787
}
 
788
 
 
789
const TerrainPosition TerrainGenerator::getMin( ) const
 
790
{
 
791
        return mTerrainInfo->getWorldSizeInIndices().lowCorner();
 
792
//      return TerrainPosition(mXmin * 64, mYmin * 64);
 
793
}
 
794
 
 
795
void TerrainGenerator::runCommand(const std::string &command, const std::string &args)
 
796
{
 
797
        if (UpdateShadows == command) {
 
798
                updateShadows();
 
799
        }
 
800
}
 
801
const TerrainInfo & TerrainGenerator::getTerrainInfo( ) const
 
802
{
 
803
        return *mTerrainInfo;
 
804
}
 
805
 
 
806
void TerrainGenerator::getShadowColourAt(const Ogre::Vector2& position, Ogre::uint32& colour)
 
807
{
 
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();
 
812
        
 
813
        Ogre::TRect<float> ogrePageExtent = Atlas2Ogre(terrainPage->getExtent());
 
814
        terrainShadow.getShadowColourAt(Ogre::Vector2(position.x - ogrePageExtent.left, position.y - ogrePageExtent.top), colour);
 
815
 
 
816
}
 
817
 
 
818
void TerrainGenerator::getShadowColourAt(const Ogre::Vector2& position, Ogre::ColourValue& colour)
 
819
{
 
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);
 
826
}
 
827
 
 
828
bool TerrainGenerator::getNormal(const TerrainPosition& worldPosition, WFMath::Vector<3>& normal) const
 
829
{
 
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));
 
833
 
 
834
        Mercator::Segment * s = mTerrain->getSegment(ix, iy);
 
835
        if ((s == 0) || (!s->isValid())) {
 
836
                return false;
 
837
        }
 
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];
 
844
 
 
845
        return true;
 
846
 
 
847
}
 
848
 
 
849
void TerrainGenerator::shaderManager_LevelChanged(ShaderManager* shaderManager)
 
850
{
 
851
        for (PageStore::iterator J = mPages.begin(); J != mPages.end(); ++J) {
 
852
                J->second->generateTerrainMaterials(true);
 
853
        }
 
854
}
 
855
 
 
856
}
 
857
}