3 * Copyright (C) 2012 Stuart Buchanan
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 # include <simgear_config.h>
31 #include <boost/foreach.hpp>
32 #include <boost/tuple/tuple_comparison.hpp>
35 #include <osg/Geometry>
37 #include <osg/MatrixTransform>
39 #include <osg/ShadeModel>
40 #include <osg/Material>
41 #include <osg/CullFace>
43 #include <osgDB/ReadFile>
44 #include <osgDB/FileUtils>
46 #include <simgear/debug/logstream.hxx>
47 #include <simgear/math/sg_random.h>
48 #include <simgear/misc/sg_path.hxx>
49 #include <simgear/scene/material/Effect.hxx>
50 #include <simgear/scene/material/EffectGeode.hxx>
51 #include <simgear/scene/model/model.hxx>
52 #include <simgear/props/props.hxx>
53 #include <simgear/scene/util/QuadTreeBuilder.hxx>
54 #include <simgear/scene/util/RenderConstants.hxx>
55 #include <simgear/scene/util/StateAttributeFactory.hxx>
56 #include <simgear/structure/OSGUtils.hxx>
59 #include "ShaderGeometry.hxx"
60 #include "SGBuildingBin.hxx"
62 #define SG_BUILDING_QUAD_TREE_DEPTH 2
63 #define SG_BUILDING_FADE_OUT_LEVELS 4
70 typedef std::map<std::string, osg::observer_ptr<osg::StateSet> > BuildingStateSetMap;
71 static BuildingStateSetMap statesetmap;
72 static int numBuildings;
74 void addBuildingToLeafGeode(Geode* geode, const SGBuildingBin::Building& building)
76 // Generate a repeatable random seed
78 mt_init(&seed, unsigned(building.position.x()));
80 // Get or create geometry.
81 osg::ref_ptr<osg::Geometry> geom;
82 osg::ref_ptr<osg::Vec3Array> v;
83 osg::ref_ptr<osg::Vec2Array> t;
84 osg::ref_ptr<osg::Vec4Array> c;
85 osg::ref_ptr<osg::Vec3Array> n;
87 if (geode->getNumDrawables() == 0) {
88 geom = new osg::Geometry;
89 v = new osg::Vec3Array;
90 t = new osg::Vec2Array;
91 c = new osg::Vec4Array;
92 n = new osg::Vec3Array;
94 // Set the color, which is bound overall, and simply white
95 c->push_back( osg::Vec4( 1, 1, 1, 1) );
96 geom->setColorArray(c);
97 geom->setColorBinding(osg::Geometry::BIND_OVERALL);
99 geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
100 // Temporary primitive set. Will be over-written later.
101 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,1));
102 geode->addDrawable(geom);
104 geom = (osg::Geometry*) geode->getDrawable(0);
105 v = (osg::Vec3Array*) geom->getVertexArray();
106 t = (osg::Vec2Array*) geom->getTexCoordArray(0);
107 c = (osg::Vec4Array*) geom->getColorArray();
108 n = (osg::Vec3Array*) geom->getNormalArray();
111 // For the moment we'll create a simple box with 5 sides (no need
115 if (building.pitched) {
116 // If it's a pitched roof, we add another 3 quads (we'll be
117 // removing the flat top).
121 // Set up the rotation and translation matrix, which we apply to
122 // vertices as they are created as we'll be adding buildings later.
123 osg::Matrix transformMat;
124 transformMat = osg::Matrix::translate(toOsg(building.position));
125 double hdg = - building.rotation * M_PI * 2;
126 osg::Matrix rotationMat = osg::Matrix::rotate(hdg,
127 osg::Vec3d(0.0, 0.0, 1.0));
128 transformMat.preMult(rotationMat);
130 // Create the vertices
131 float cw = 0.5f * building.width;
132 float cd = building.depth;
133 float ch = building.height;
135 // 0,0,0 is the bottom center of the front
136 // face, e.g. where the front door would be
139 // This exteds 10m below the main section
141 v->push_back( osg::Vec3( 0, -cw, -10) * transformMat ); // bottom right
142 v->push_back( osg::Vec3( 0, cw, -10) * transformMat ); // bottom left
143 v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // top left
144 v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // top right
146 for (int i=0; i<4; ++i)
147 n->push_back( osg::Vec3(1, 0, 0) * rotationMat ); // normal
150 v->push_back( osg::Vec3( -cd, -cw, -10) * transformMat ); // bottom right
151 v->push_back( osg::Vec3( 0, -cw, -10) * transformMat ); // bottom left
152 v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // top left
153 v->push_back( osg::Vec3( -cd, -cw, 0) * transformMat ); // top right
155 for (int i=0; i<4; ++i)
156 n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
159 v->push_back( osg::Vec3( -cd, cw, -10) * transformMat ); // bottom right
160 v->push_back( osg::Vec3( -cd, -cw, -10) * transformMat ); // bottom left
161 v->push_back( osg::Vec3( -cd, -cw, 0) * transformMat ); // top left
162 v->push_back( osg::Vec3( -cd, cw, 0) * transformMat ); // top right
164 for (int i=0; i<4; ++i)
165 n->push_back( osg::Vec3(-1, 0, 0) * rotationMat ); // normal
168 v->push_back( osg::Vec3( 0, cw, -10) * transformMat ); // bottom right
169 v->push_back( osg::Vec3( -cd, cw, -10) * transformMat ); // bottom left
170 v->push_back( osg::Vec3( -cd, cw, 0) * transformMat ); // top left
171 v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // top right
173 for (int i=0; i<4; ++i)
174 n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
178 v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // bottom right
179 v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // bottom left
180 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // top left
181 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // top right
183 for (int i=0; i<4; ++i)
184 n->push_back( osg::Vec3(1, 0, 0) * rotationMat ); // normal
187 v->push_back( osg::Vec3( -cd, -cw, 0) * transformMat ); // bottom right
188 v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // bottom left
189 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // top left
190 v->push_back( osg::Vec3( -cd, -cw, ch) * transformMat ); // top right
192 for (int i=0; i<4; ++i)
193 n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
196 v->push_back( osg::Vec3( -cd, cw, 0) * transformMat ); // bottom right
197 v->push_back( osg::Vec3( -cd, -cw, 0) * transformMat ); // bottom left
198 v->push_back( osg::Vec3( -cd, -cw, ch) * transformMat ); // top left
199 v->push_back( osg::Vec3( -cd, cw, ch) * transformMat ); // top right
201 for (int i=0; i<4; ++i)
202 n->push_back( osg::Vec3(-1, 0, 0) * rotationMat ); // normal
205 v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // bottom right
206 v->push_back( osg::Vec3( -cd, cw, 0) * transformMat ); // bottom left
207 v->push_back( osg::Vec3( -cd, cw, ch) * transformMat ); // top left
208 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // top right
210 for (int i=0; i<4; ++i)
211 n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
214 if (building.pitched) {
216 // Front pitched roof
217 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // bottom right
218 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // bottom left
219 v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) * transformMat ); // top left
220 v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) * transformMat ); // top right
222 for (int i=0; i<4; ++i)
223 n->push_back( osg::Vec3(0.707, 0, 0.707) * rotationMat ); // normal
226 v->push_back( osg::Vec3( -cd, -cw, ch) * transformMat ); // bottom right
227 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // bottom left
228 v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) * transformMat ); // top left
229 v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) * transformMat ); // top right
231 for (int i=0; i<4; ++i)
232 n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
235 v->push_back( osg::Vec3( -cd, cw, ch) * transformMat ); // bottom right
236 v->push_back( osg::Vec3( -cd, -cw, ch) * transformMat ); // bottom left
237 v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) * transformMat ); // top left
238 v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) * transformMat ); // top right
240 for (int i=0; i<4; ++i)
241 n->push_back( osg::Vec3(-0.707, 0, 0.707) * rotationMat ); // normal
243 // Right pitched roof
244 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // bottom right
245 v->push_back( osg::Vec3( -cd, cw, ch) * transformMat ); // bottom left
246 v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) * transformMat ); // top left
247 v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) * transformMat ); // top right
249 for (int i=0; i<4; ++i)
250 n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
253 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // bottom right
254 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // bottom left
255 v->push_back( osg::Vec3( -cd, cw, ch) * transformMat ); // top left
256 v->push_back( osg::Vec3( -cd, -cw, ch) * transformMat ); // top right
258 for (int i=0; i<4; ++i)
259 n->push_back( osg::Vec3( 0, 0, 1) * rotationMat ); // normal
262 // The 1024x1024 texture is split into 32x16 blocks.
263 // For a small building, each block is 6m wide and 3m high.
264 // For a medium building, each block is 10m wide and 3m high.
265 // For a large building, each block is 20m wide and 3m high
267 if (building.type == SGBuildingBin::SMALL) {
268 // Small buildings are represented on the bottom 5 rows of 3 floors
269 int row = ((int) (mt_rand(&seed) * 1000)) % 5;
270 float base_y = (float) row * 16.0 * 3.0 / 1024.0;
271 float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
272 float left_x = 32.0 / 1024.0 * round((float) building.width / 6.0f);
273 float right_x = 0.0f;
274 float front_x = 384.0/1024.0;
275 float back_x = 384.0/1024.0 + 32.0 / 1024.0 * round((float) building.depth/ 6.0f);
277 // BASEMENT - uses the baseline texture
278 for (unsigned int i = 0; i < 16; i++) {
279 t->push_back( osg::Vec2( left_x, base_y) );
283 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
284 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
285 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
286 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
289 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
290 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
291 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
292 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
294 // Back (same as front for the moment)
295 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
296 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
297 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
298 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
300 // Right (same as left for the moment)
301 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
302 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
303 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
304 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
307 if (building.pitched) {
308 // Use the entire height of the roof texture
309 top_y = base_y + 16.0 * 3.0 / 1024.0;
310 left_x = 512/1024.0 + 32.0 / 1024.0 * round(building.width / 6.0f);
311 right_x = 512/1024.0;
312 front_x = 480.0/1024.0;
313 back_x = 512.0/1024.0;
316 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
317 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
318 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
319 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
322 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
323 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
324 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
325 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
327 // Back (same as front for the moment)
328 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
329 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
330 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
331 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
333 // Right (same as left for the moment)
334 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
335 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
336 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
337 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
340 left_x = 640.0/1024.0;
341 right_x = 512.0/1024.0;
342 // Use the entire height of the roof texture
343 top_y = base_y + 16.0 * 3.0 / 1024.0;
345 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
346 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
347 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
348 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
353 if (building.type == SGBuildingBin::MEDIUM)
355 int column = ((int) (mt_rand(&seed) * 1000)) % 5;
356 float base_y = 288 / 1024.0;
357 float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
358 float left_x = column * 192.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 10.0f);
359 float right_x = column * 192.0 /1024.0;
361 // BASEMENT - uses the baseline texture
362 for (unsigned int i = 0; i < 16; i++) {
363 t->push_back( osg::Vec2( left_x, base_y) );
368 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
369 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
370 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
371 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
374 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
375 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
376 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
377 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
379 // Back (same as front for the moment)
380 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
381 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
382 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
383 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
385 // Right (same as left for the moment)
386 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
387 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
388 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
389 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
392 if (building.pitched) {
393 base_y = 288.0/1024.0;
394 top_y = 576.0/1024.0;
395 left_x = 960.0/1024.0;
399 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
400 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
401 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
402 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
405 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
406 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
407 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
408 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
410 // Back (same as front for the moment)
411 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
412 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
413 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
414 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
416 // Right (same as left for the moment)
417 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
418 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
419 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
420 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
424 top_y = 576.0/1024.0;
425 left_x = column * 192.0 /1024.0;
426 right_x = (column + 1)* 192.0 /1024.0;
428 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
429 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
430 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
431 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
435 if (building.type == SGBuildingBin::LARGE)
437 int column = ((int) (mt_rand(&seed) * 1000)) % 8;
438 float base_y = 576 / 1024.0;
439 float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
440 float left_x = column * 128.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 20.0f);
441 float right_x = column * 128.0 /1024.0;
443 // BASEMENT - uses the baseline texture
444 for (unsigned int i = 0; i < 16; i++) {
445 t->push_back( osg::Vec2( left_x, base_y) );
450 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
451 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
452 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
453 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
456 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
457 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
458 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
459 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
461 // Back (same as front for the moment)
462 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
463 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
464 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
465 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
467 // Right (same as left for the moment)
468 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
469 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
470 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
471 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
474 if (building.pitched) {
478 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
479 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
480 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
481 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
484 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
485 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
486 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
487 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
489 // Back (same as front for the moment)
490 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
491 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
492 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
493 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
495 // Right (same as left for the moment)
496 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
497 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
498 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
499 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
505 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
506 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
507 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
508 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
513 // Set the vertex, texture and normals back.
514 geom->setVertexArray(v);
515 geom->setTexCoordArray(0, t);
516 geom->setNormalArray(n);
518 geom->setPrimitiveSet(0, new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,v->size()));
519 geode->setDrawable(0, geom);
522 typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
524 static EffectMap buildingEffectMap;
526 // Helper classes for creating the quad tree
529 struct MakeBuildingLeaf
531 MakeBuildingLeaf(float range, Effect* effect) :
532 _range(range), _effect(effect) {}
534 MakeBuildingLeaf(const MakeBuildingLeaf& rhs) :
535 _range(rhs._range), _effect(rhs._effect)
538 LOD* operator() () const
540 LOD* result = new LOD;
542 // Create a series of LOD nodes so trees cover decreases slightly
543 // gradually with distance from _range to 2*_range
544 for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++)
546 EffectGeode* geode = new EffectGeode;
547 geode->setEffect(_effect.get());
548 result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0)));
554 ref_ptr<Effect> _effect;
557 struct AddBuildingLeafObject
559 void operator() (LOD* lod, const SGBuildingBin::Building& building) const
561 Geode* geode = static_cast<Geode*>(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren()));
562 addBuildingToLeafGeode(geode, building);
566 struct GetBuildingCoord
568 Vec3 operator() (const SGBuildingBin::Building& building) const
570 return toOsg(building.position);
574 typedef QuadTreeBuilder<LOD*, SGBuildingBin::Building, MakeBuildingLeaf, AddBuildingLeafObject,
575 GetBuildingCoord> BuildingGeometryQuadtree;
578 struct BuildingTransformer
580 BuildingTransformer(Matrix& mat_) : mat(mat_) {}
581 SGBuildingBin::Building operator()(const SGBuildingBin::Building& building) const
583 Vec3 pos = toOsg(building.position);
584 return SGBuildingBin::Building(toSG(pos * mat), building);
591 // This actually returns a MatrixTransform node. If we rotate the whole
592 // forest into the local Z-up coordinate system we can reuse the
593 // primitive building geometry for all the forests of the same type.
594 osg::Group* createRandomBuildings(SGBuildingBinList buildings, const osg::Matrix& transform,
595 const SGReaderWriterOptions* options)
597 Matrix transInv = Matrix::inverse(transform);
599 // Set up some shared structures.
600 MatrixTransform* mt = new MatrixTransform(transform);
602 SGBuildingBin* bin = NULL;
604 BOOST_FOREACH(bin, buildings)
606 numBuildings = numBuildings + bin->getNumBuildings();
607 SG_LOG(SG_TERRAIN, SG_DEBUG, "Total random buildings generated: " << numBuildings);
609 ref_ptr<Effect> effect;
610 EffectMap::iterator iter = buildingEffectMap.find(bin->texture);
612 if ((iter == buildingEffectMap.end())||
613 (!iter->second.lock(effect)))
615 SGPropertyNode_ptr effectProp = new SGPropertyNode;
616 makeChild(effectProp, "inherits-from")->setStringValue("Effects/building");
617 SGPropertyNode* params = makeChild(effectProp, "parameters");
618 // Main texture - n=0
619 params->getChild("texture", 0, true)->getChild("image", 0, true)
620 ->setStringValue(bin->texture);
623 params->getChild("texture", 3, true)->getChild("image", 0, true)
624 ->setStringValue(bin->lightMap);
626 effect = makeEffect(effectProp, true, options);
627 if (iter == buildingEffectMap.end())
628 buildingEffectMap.insert(EffectMap::value_type(bin->texture, effect));
630 iter->second = effect; // update existing, but empty observer
633 // Now, create a quadbuilding for the buildings.
634 BuildingGeometryQuadtree
635 quadbuilding(GetBuildingCoord(), AddBuildingLeafObject(),
636 SG_BUILDING_QUAD_TREE_DEPTH,
637 MakeBuildingLeaf(20000.0f, effect)); // FIXME - tie to property
639 // Transform building positions from the "geocentric" positions we
640 // get from the scenery polys into the local Z-up coordinate
642 std::vector<SGBuildingBin::Building> rotatedBuildings;
643 rotatedBuildings.reserve(bin->buildings.size());
644 std::transform(bin->buildings.begin(), bin->buildings.end(),
645 std::back_inserter(rotatedBuildings),
646 BuildingTransformer(transInv));
647 quadbuilding.buildQuadTree(rotatedBuildings.begin(), rotatedBuildings.end());
649 ref_ptr<Group> group = quadbuilding.getRoot();