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

« back to all changes in this revision

Viewing changes to src/components/ogre/environment/pagedgeometry/source/TreeLoader2D.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) 2006 John Judnich
 
3
 
 
4
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
 
5
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
 
6
    1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
 
7
    2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
 
8
    3. This notice may not be removed or altered from any source distribution.
 
9
-------------------------------------------------------------------------------------*/
 
10
 
 
11
#include "TreeLoader2D.h"
 
12
#include "PagedGeometry.h"
 
13
#include "PropertyMaps.h"
 
14
 
 
15
#include <OgreRoot.h>
 
16
#include <OgreException.h>
 
17
#include <OgreVector3.h>
 
18
#include <OgreQuaternion.h>
 
19
#include <OgreLogManager.h>
 
20
#include <OgreStringConverter.h>
 
21
using namespace Ogre;
 
22
 
 
23
namespace PagedGeometry {
 
24
 
 
25
TreeLoader2D::TreeLoader2D(PagedGeometry *geom, const TRect<Real> &bounds)
 
26
{
 
27
        //Calculate grid size
 
28
        TreeLoader2D::geom = geom;
 
29
        pageSize = geom->getPageSize();
 
30
 
 
31
        //Reset height function
 
32
        heightFunction = NULL;
 
33
        heightFunctionUserData = NULL;
 
34
 
 
35
        //Make sure the bounds are aligned with PagedGeometry's grid, so the TreeLoader's grid tiles will have a 1:1 relationship
 
36
        actualBounds = bounds;
 
37
        gridBounds = bounds;
 
38
        gridBounds.left = pageSize * Math::Floor((gridBounds.left - geom->getBounds().left) / pageSize) + geom->getBounds().left;
 
39
        gridBounds.top = pageSize * Math::Floor((gridBounds.top - geom->getBounds().top) / pageSize) + geom->getBounds().top;
 
40
        gridBounds.right = pageSize * Math::Ceil((gridBounds.right - geom->getBounds().left) / pageSize) + geom->getBounds().left;
 
41
        gridBounds.bottom = pageSize * Math::Ceil((gridBounds.bottom - geom->getBounds().top) / pageSize) + geom->getBounds().top;
 
42
 
 
43
        //Calculate page grid size
 
44
        pageGridX = Math::Ceil(gridBounds.width() / pageSize) + 1;
 
45
        pageGridZ = Math::Ceil(gridBounds.height() / pageSize) + 1;
 
46
 
 
47
        //Reset color map
 
48
        colorMap = NULL;
 
49
        colorMapFilter = MAPFILTER_NONE;
 
50
 
 
51
        //Default scale range
 
52
        maximumScale = 2.0f;
 
53
        minimumScale = 0.0f;
 
54
}
 
55
 
 
56
TreeLoader2D::~TreeLoader2D()
 
57
{
 
58
        //Delete all page grids
 
59
        PageGridListIterator i;
 
60
        for (i = pageGridList.begin(); i != pageGridList.end(); ++i){
 
61
                delete[] i->second;
 
62
        }
 
63
        pageGridList.clear();
 
64
}
 
65
 
 
66
void TreeLoader2D::addTree(Entity *entity, const Vector3 &position, Degree yaw, Real scale, void* userData)
 
67
{
 
68
        //First convert the coordinate to PagedGeometry's local system
 
69
        #ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
 
70
        Vector3 pos = geom->_convertToLocal(position);
 
71
        #else
 
72
        Vector3 pos = position;
 
73
        #endif
 
74
 
 
75
        //If the tree is slightly out of bounds (due to imprecise coordinate conversion), fix it
 
76
        if (pos.x < actualBounds.left)
 
77
                pos.x = actualBounds.left;
 
78
        else if (pos.x > actualBounds.right)
 
79
                pos.x = actualBounds.right;
 
80
 
 
81
        if (pos.z < actualBounds.top)
 
82
                pos.z = actualBounds.top;
 
83
        else if (pos.x > actualBounds.bottom)
 
84
                pos.z = actualBounds.bottom;
 
85
 
 
86
        Real x = pos.x;
 
87
        Real z = pos.z;
 
88
 
 
89
        //Check that the tree is within bounds (DEBUG)
 
90
        #ifdef _DEBUG
 
91
        const Real smallVal = 0.01f;
 
92
        if (pos.x < actualBounds.left-smallVal || pos.x > actualBounds.right+smallVal || pos.z < actualBounds.top-smallVal || pos.z > actualBounds.bottom+smallVal)
 
93
                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Tree position is out of bounds", "TreeLoader::addTree()");
 
94
        if (scale < minimumScale || scale > maximumScale)
 
95
                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Tree scale out of range", "TreeLoader::addTree()");
 
96
        #endif
 
97
 
 
98
        //Find the appropriate page grid for the entity
 
99
        PageGridListIterator i;
 
100
        i = pageGridList.find(entity);
 
101
 
 
102
        std::vector<TreeDef> *pageGrid;
 
103
        if (i != pageGridList.end()){
 
104
                //If it exists, get the page grid
 
105
                pageGrid = i->second;
 
106
        } else {
 
107
                //If it does not exist, create a new page grid
 
108
                pageGrid = new std::vector<TreeDef>[pageGridX * pageGridZ];
 
109
 
 
110
                //Register the new page grid in the pageGridList for later retrieval
 
111
                pageGridList.insert(PageGridListValue(entity, pageGrid));
 
112
        }
 
113
 
 
114
        //Calculate the gridbounds-relative position of the tree
 
115
        Real xrel = x - gridBounds.left;
 
116
        Real zrel = z - gridBounds.top;
 
117
 
 
118
        //Get the appropriate grid element based on the new tree's position
 
119
        int pageX = Math::Floor(xrel / pageSize);
 
120
        int pageZ = Math::Floor(zrel / pageSize);
 
121
        std::vector<TreeDef> &treeList = _getGridPage(pageGrid, pageX, pageZ);
 
122
 
 
123
        //Create the new tree
 
124
        TreeDef tree;
 
125
        tree.xPos = 65535 * (xrel - (pageX * pageSize)) / pageSize;
 
126
        tree.zPos = 65535 * (zrel - (pageZ * pageSize)) / pageSize;
 
127
        tree.rotation = 255 * (yaw.valueDegrees() / 360.0f);
 
128
        tree.scale = 255 * ((scale - minimumScale) / maximumScale);
 
129
 
 
130
#ifdef PAGEDGEOMETRY_USER_DATA
 
131
        tree.userData = userData;
 
132
#endif
 
133
 
 
134
        //Add it to the tree list
 
135
        treeList.push_back(tree);
 
136
 
 
137
        //Rebuild geometry if necessary
 
138
        geom->reloadGeometryPage(Vector3(x, 0, z));
 
139
}
 
140
 
 
141
#ifdef PAGEDGEOMETRY_USER_DATA
 
142
   std::vector<void*>
 
143
#else
 
144
   void
 
145
#endif
 
146
TreeLoader2D::deleteTrees(const Ogre::Vector3 &position, Real radius, Entity *type)
 
147
{
 
148
        //First convert the coordinate to PagedGeometry's local system
 
149
        #ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
 
150
        Vector3 pos = geom->_convertToLocal(position);
 
151
        #else
 
152
        Vector3 pos = position;
 
153
        #endif
 
154
 
 
155
#ifdef PAGEDGEOMETRY_USER_DATA
 
156
        //Keep a list of user-defined data associated with deleted trees
 
157
        std::vector<void*> deletedUserData;
 
158
#endif
 
159
 
 
160
        //If the position is slightly out of bounds, fix it
 
161
        if (pos.x < actualBounds.left)
 
162
                pos.x = actualBounds.left;
 
163
        else if (pos.x > actualBounds.right)
 
164
                pos.x = actualBounds.right;
 
165
 
 
166
        if (pos.z < actualBounds.top)
 
167
                pos.z = actualBounds.top;
 
168
        else if (pos.x > actualBounds.bottom)
 
169
                pos.z = actualBounds.bottom;
 
170
 
 
171
        Real x = pos.x;
 
172
        Real z = pos.z;
 
173
 
 
174
        //Determine the grid blocks which might contain the requested trees
 
175
        int minPageX = Math::Floor(((x-radius) - gridBounds.left) / pageSize);
 
176
        int minPageZ = Math::Floor(((z-radius) - gridBounds.top) / pageSize);
 
177
        int maxPageX = Math::Floor(((x+radius) - gridBounds.left) / pageSize);
 
178
        int maxPageZ = Math::Floor(((z+radius) - gridBounds.top) / pageSize);
 
179
        Real radiusSq = radius * radius;
 
180
 
 
181
        if (minPageX < 0) minPageX = 0; else if (minPageX >= pageGridX) minPageX = pageGridX-1;
 
182
        if (minPageZ < 0) minPageZ = 0; else if (minPageZ >= pageGridZ) minPageZ = pageGridZ-1;
 
183
        if (maxPageX < 0) maxPageX = 0; else if (maxPageX >= pageGridX) maxPageX = pageGridX-1;
 
184
        if (maxPageZ < 0) maxPageZ = 0; else if (maxPageZ >= pageGridZ) maxPageZ = pageGridZ-1;
 
185
 
 
186
        PageGridListIterator it, end;
 
187
        if (type == NULL){
 
188
                //Scan all entity types
 
189
                it = pageGridList.begin();
 
190
                end = pageGridList.end();
 
191
        } else {
 
192
                //Only scan entities of the given type
 
193
                it = pageGridList.find(type);
 
194
                assert(it != pageGridList.end());
 
195
                end = it; ++end;
 
196
        }
 
197
 
 
198
        //Scan all the grid blocks
 
199
        while (it != end){
 
200
                std::vector<TreeDef> *pageGrid = it->second;
 
201
 
 
202
                for (int tileZ = minPageZ; tileZ <= maxPageZ; ++tileZ){
 
203
                        for (int tileX = minPageX; tileX <= maxPageX; ++tileX){
 
204
                                bool modified = false;
 
205
 
 
206
                                //Scan all trees in grid block
 
207
                                std::vector<TreeDef> &treeList = _getGridPage(pageGrid, tileX, tileZ);
 
208
                                unsigned int i = 0;
 
209
                                while (i < treeList.size()){
 
210
                                        //Get tree distance
 
211
                                        float distX = (gridBounds.left + (tileX * pageSize) + ((Real)treeList[i].xPos / 65535) * pageSize) - pos.x;
 
212
                                        float distZ = (gridBounds.top + (tileZ * pageSize) + ((Real)treeList[i].zPos / 65535) * pageSize) - pos.z;
 
213
                                        float distSq = distX * distX + distZ * distZ;
 
214
 
 
215
                                        if (distSq <= radiusSq){
 
216
                                                //If it's within the radius, delete it
 
217
                                                treeList[i] = treeList.back();
 
218
#ifdef PAGEDGEOMETRY_USER_DATA
 
219
                                                deletedUserData.push_back(treeList.back().userData);
 
220
#endif
 
221
                                                treeList.pop_back();
 
222
                                                modified = true;
 
223
                                        }
 
224
                                        else
 
225
                                                ++i;
 
226
                                }
 
227
 
 
228
                                //Rebuild geometry if necessary
 
229
                                if (modified){
 
230
                                        Vector3 pos(gridBounds.left + ((0.5f + tileX) * pageSize), 0, gridBounds.top + ((0.5f + tileZ) * pageSize));
 
231
                                        geom->reloadGeometryPage(pos);
 
232
                                }
 
233
                        }
 
234
                }
 
235
 
 
236
                ++it;
 
237
        }
 
238
 
 
239
#ifdef PAGEDGEOMETRY_USER_DATA
 
240
        return deletedUserData;
 
241
#endif
 
242
}
 
243
 
 
244
void TreeLoader2D::setColorMap(const Ogre::String &mapFile, MapChannel channel)
 
245
{
 
246
        if (colorMap){
 
247
                colorMap->unload();
 
248
                colorMap = NULL;
 
249
        }
 
250
        if (mapFile != ""){
 
251
                colorMap = ColorMap::load(mapFile, channel);
 
252
                colorMap->setMapBounds(actualBounds);
 
253
                colorMap->setFilter(colorMapFilter);
 
254
        }
 
255
}
 
256
 
 
257
void TreeLoader2D::setColorMap(Ogre::Texture *map, MapChannel channel)
 
258
{
 
259
        if (colorMap){
 
260
                colorMap->unload();
 
261
                colorMap = NULL;
 
262
        }
 
263
        if (map){
 
264
                colorMap = ColorMap::load(map, channel);
 
265
                colorMap->setMapBounds(actualBounds);
 
266
                colorMap->setFilter(colorMapFilter);
 
267
        }
 
268
}
 
269
 
 
270
void TreeLoader2D::loadPage(PageInfo &page)
 
271
{
 
272
        //Calculate x/z indexes for the grid array
 
273
        page.xIndex -= Math::Floor(gridBounds.left / pageSize);
 
274
        page.zIndex -= Math::Floor(gridBounds.top / pageSize);
 
275
 
 
276
        //Check if the requested page is in bounds
 
277
        if (page.xIndex < 0 || page.zIndex < 0 || page.xIndex >= pageGridX || page.zIndex >= pageGridZ)
 
278
                return;
 
279
 
 
280
        //For each tree type...
 
281
        PageGridListIterator i;
 
282
        for (i = pageGridList.begin(); i != pageGridList.end(); ++i){
 
283
                //Get the appropriate tree list for the specified page
 
284
                std::vector<TreeDef> *pageGrid = i->second;
 
285
                std::vector<TreeDef> &treeList = _getGridPage(pageGrid, page.xIndex, page.zIndex);
 
286
                Entity *entity = i->first;
 
287
 
 
288
                //Load the listed trees into the page
 
289
                std::vector<TreeDef>::iterator o;
 
290
                for (o = treeList.begin(); o != treeList.end(); ++o){
 
291
                        //Get position
 
292
                        Vector3 pos;
 
293
                        pos.x = page.bounds.left + ((Real)o->xPos / 65535) * pageSize;
 
294
                        pos.z = page.bounds.top + ((Real)o->zPos / 65535) * pageSize;
 
295
 
 
296
                        //Calculate terrain height at pos.x / pos.z to get pos.y
 
297
                        if (heightFunction != NULL)
 
298
                                pos.y = heightFunction(pos.x, pos.z, heightFunctionUserData);
 
299
                        else
 
300
                                pos.y = 0.0f;
 
301
                        
 
302
                        //Get rotation
 
303
                        Degree angle((Real)o->rotation * (360.0f / 255));
 
304
                        Quaternion rot(angle, Vector3::UNIT_Y);
 
305
 
 
306
                        //Get scale
 
307
                        Vector3 scale;
 
308
                        scale.y = (Real)o->scale * (maximumScale / 255) + minimumScale;
 
309
                        scale.x = scale.y;
 
310
                        scale.z = scale.y;
 
311
 
 
312
                        //Get color
 
313
                        ColourValue color;
 
314
                        if (colorMap)
 
315
                                color = colorMap->getColorAt_Unpacked(pos.x, pos.z);
 
316
                        else
 
317
                                color = ColourValue::White;
 
318
 
 
319
                        addEntity(entity, pos, rot, scale, color);
 
320
                }
 
321
        }
 
322
}
 
323
 
 
324
TreeIterator2D TreeLoader2D::getTrees()
 
325
{
 
326
        return TreeIterator2D(this);
 
327
}
 
328
 
 
329
 
 
330
 
 
331
TreeIterator2D::TreeIterator2D(TreeLoader2D *trees)
 
332
{
 
333
        TreeIterator2D::trees = trees;
 
334
 
 
335
        //Setup iterators
 
336
        currentGrid = trees->pageGridList.begin();
 
337
        currentX = 0; currentZ = 0;
 
338
        currentTreeList = &trees->_getGridPage(currentGrid->second, currentX, currentZ);
 
339
        currentTree = currentTreeList->begin();
 
340
        hasMore = true;
 
341
 
 
342
        //If there's not tree in the first page, keep looking
 
343
        if (currentTree == currentTreeList->end())
 
344
                moveNext();
 
345
 
 
346
        //Read the first tree's data
 
347
        _readTree();
 
348
 
 
349
        //Read one more tree, so peekNext() will properly return the first item, while the system
 
350
        //actually is looking ahead one item (this way it can detect the end of the list before
 
351
        //it's too late)
 
352
        if (hasMore)
 
353
                moveNext();
 
354
}
 
355
 
 
356
TreeRef TreeIterator2D::getNext()
 
357
{
 
358
        TreeRef tree = peekNext();
 
359
        moveNext();
 
360
        return tree;
 
361
}
 
362
 
 
363
void TreeIterator2D::moveNext()
 
364
{
 
365
        //Out of bounds check
 
366
        if (!hasMore)
 
367
                OGRE_EXCEPT(1, "Cannot read past end of TreeIterator list", "TreeIterator::moveNext()");
 
368
 
 
369
        //Preserve the last tree
 
370
        prevTreeDat = currentTreeDat;
 
371
 
 
372
        //Increment iterators to the next tree
 
373
        if (currentTree != currentTreeList->end())
 
374
                ++currentTree;
 
375
        while (currentTree == currentTreeList->end()){
 
376
                if (++currentX >= trees->pageGridX){
 
377
                        currentX = 0;
 
378
                        if (++currentZ >= trees->pageGridZ){
 
379
                                ++currentGrid;
 
380
                                if (currentGrid == trees->pageGridList.end()){
 
381
                                        //No more trees left
 
382
                                        hasMore = false;
 
383
                                        return;
 
384
                                }
 
385
                                currentX = 0; currentZ = 0;
 
386
                        }
 
387
                }
 
388
 
 
389
                currentTreeList = &trees->_getGridPage(currentGrid->second, currentX, currentZ);
 
390
                currentTree = currentTreeList->begin();
 
391
        }
 
392
 
 
393
        //Read the current tree data
 
394
        _readTree();
 
395
}
 
396
 
 
397
void TreeIterator2D::_readTree()
 
398
{
 
399
        TreeLoader2D::TreeDef treeDef = *currentTree;
 
400
 
 
401
        //Get position
 
402
        Real boundsLeft = trees->gridBounds.left + trees->pageSize * currentX;
 
403
        Real boundsTop = trees->gridBounds.top + trees->pageSize * currentZ;
 
404
        currentTreeDat.position.x = boundsLeft + ((Real)treeDef.xPos / 65535) * trees->pageSize;
 
405
        currentTreeDat.position.z = boundsTop + ((Real)treeDef.zPos / 65535) * trees->pageSize;
 
406
 
 
407
        //Calculate terrain height at x / z to get y
 
408
        if (trees->heightFunction != NULL)
 
409
                currentTreeDat.position.y = trees->heightFunction(currentTreeDat.position.x, currentTreeDat.position.z, trees->heightFunctionUserData);
 
410
        else
 
411
                currentTreeDat.position.y = 0.0f;
 
412
        
 
413
        //Get rotation
 
414
        currentTreeDat.yaw = Degree((Real)treeDef.rotation * (360.0f / 255));
 
415
 
 
416
        //Get scale
 
417
        currentTreeDat.scale = (Real)treeDef.scale * (trees->maximumScale / 255) + trees->minimumScale;
 
418
 
 
419
        //Get entity
 
420
        currentTreeDat.entity = currentGrid->first;
 
421
}
 
422
}