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 3
63 #define SG_BUILDING_FADE_OUT_LEVELS 10
70 typedef std::map<std::string, osg::observer_ptr<osg::StateSet> > BuildingStateSetMap;
71 static BuildingStateSetMap statesetmap;
73 void addBuildingToLeafGeode(Geode* geode, const SGBuildingBin::Building& building)
75 // Generate a repeatable random seed
77 mt_init(&seed, unsigned(building.position.x()));
79 // Get or create geometry.
80 osg::ref_ptr<osg::Geometry> geom;
81 osg::Vec3Array* v = new osg::Vec3Array;
82 osg::Vec2Array* t = new osg::Vec2Array;
84 // Color and Normal will be per QUAD
85 osg::Vec4Array* c = new osg::Vec4Array;
86 osg::Vec3Array* n = new osg::Vec3Array;
88 if (geode->getNumDrawables() == 0) {
89 geom = new osg::Geometry;
90 v = new osg::Vec3Array;
91 t = new osg::Vec2Array;
92 c = new osg::Vec4Array;
93 n = new osg::Vec3Array;
95 // Set the color, which is bound overall, and simply white
96 c->push_back( osg::Vec4( 1, 1, 1, 1) );
97 geom->setColorArray(c);
98 geom->setColorBinding(osg::Geometry::BIND_OVERALL);
100 geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
101 // Temporary primitive set. Will be over-written later.
102 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,1));
103 geode->addDrawable(geom);
105 geom = (osg::Geometry*) geode->getDrawable(0);
106 v = (osg::Vec3Array*) geom->getVertexArray();
107 t = (osg::Vec2Array*) geom->getTexCoordArray(0);
108 c = (osg::Vec4Array*) geom->getColorArray();
109 n = (osg::Vec3Array*) geom->getNormalArray();
112 // For the moment we'll create a simple box with 5 sides (no need
116 if (building.pitched) {
117 // If it's a pitched roof, we add another 3 quads (we'll be
118 // removing the flat top).
122 // Set up the rotation and translation matrix, which we apply to
123 // vertices as they are created as we'll be adding buildings later.
124 osg::Matrix transformMat;
125 transformMat = osg::Matrix::translate(toOsg(building.position));
126 double hdg = - building.rotation * M_PI * 2;
127 osg::Matrix rotationMat = osg::Matrix::rotate(hdg,
128 osg::Vec3d(0.0, 0.0, 1.0));
129 transformMat.preMult(rotationMat);
131 // Create the vertices
132 float cw = 0.5f * building.width;
133 float cd = building.depth;
134 float ch = building.height;
136 // 0,0,0 is the bottom center of the front
137 // face, e.g. where the front door would be
141 // This exteds 10m below the main section
143 v->push_back( osg::Vec3( 0, cw, -10) * transformMat ); // bottom right
144 v->push_back( osg::Vec3( 0, -cw, -10) * transformMat ); // bottom left
145 v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // top left
146 v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // top right
148 n->push_back( osg::Vec3(-1, 0, 0) * rotationMat ); // normal
151 v->push_back( osg::Vec3( 0, -cw, -10) * transformMat ); // bottom right
152 v->push_back( osg::Vec3( cd, -cw, -10) * transformMat ); // bottom left
153 v->push_back( osg::Vec3( cd, -cw, 0) * transformMat ); // top left
154 v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // top right
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 n->push_back( osg::Vec3(1, 0, 0) * rotationMat ); // normal
167 v->push_back( osg::Vec3( cd, cw, -10) * transformMat ); // bottom right
168 v->push_back( osg::Vec3( 0, cw, -10) * transformMat ); // bottom left
169 v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // top left
170 v->push_back( osg::Vec3( cd, cw, 0) * transformMat ); // top right
172 n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
176 v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // bottom right
177 v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // bottom left
178 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // top left
179 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // top right
181 n->push_back( osg::Vec3(-1, 0, 0) * rotationMat ); // normal
184 v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // bottom right
185 v->push_back( osg::Vec3( cd, -cw, 0) * transformMat ); // bottom left
186 v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // top left
187 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // top right
189 n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
192 v->push_back( osg::Vec3( cd, -cw, 0) * transformMat ); // bottom right
193 v->push_back( osg::Vec3( cd, cw, 0) * transformMat ); // bottom left
194 v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // top left
195 v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // top right
197 n->push_back( osg::Vec3(1, 0, 0) * rotationMat ); // normal
200 v->push_back( osg::Vec3( cd, cw, 0) * transformMat ); // bottom right
201 v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // bottom left
202 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // top left
203 v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // top right
205 n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
208 if (building.pitched) {
210 // Front pitched roof
211 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // bottom right
212 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // bottom left
213 v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top left
214 v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top right
215 n->push_back( osg::Vec3(-0.707, 0, 0.707) * rotationMat ); // normal
218 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // bottom right
219 v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // bottom left
220 v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top left
221 v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top right
222 n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
225 v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // bottom right
226 v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // bottom left
227 v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top left
228 v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top right
229 n->push_back( osg::Vec3(0.707, 0, 0.707) * rotationMat ); // normal
231 // Right pitched roof
232 v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // bottom right
233 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // bottom left
234 v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top left
235 v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top right
236 n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
239 v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // bottom right
240 v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // bottom left
241 v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // top left
242 v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // top right
243 n->push_back( osg::Vec3( 0, 0, 1) * rotationMat ); // normal
246 // The 1024x1024 texture is split into 32x16 blocks.
247 // For a small building, each block is 6m wide and 3m high.
248 // For a medium building, each block is 10m wide and 3m high.
249 // For a large building, each block is 20m wide and 3m high
251 if (building.type == SGBuildingBin::SMALL) {
252 // Small buildings are represented on the bottom 5 rows of 3 floors
253 int row = ((int) (mt_rand(&seed) * 1000)) % 5;
254 float base_y = (float) row * 16.0 * 3.0 / 1024.0;
255 float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
257 float right_x = 32.0 / 1024.0 * round((float) building.width / 6.0f);
258 float front_x = 384.0/1024.0;
259 float back_x = 384.0/1024.0 + 32.0 / 1024.0 * round((float) building.depth/ 6.0f);
261 // BASEMENT - uses the baseline texture
262 for (unsigned int i = 0; i < 16; i++) {
263 t->push_back( osg::Vec2( left_x, base_y) );
267 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
268 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
269 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
270 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
273 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
274 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
275 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
276 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
278 // Back (same as front for the moment)
279 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
280 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
281 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
282 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
284 // Right (same as left for the moment)
285 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
286 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
287 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
288 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
291 if (building.pitched) {
292 // Use the entire height of the roof texture
293 top_y = base_y + 16.0 * 3.0 / 1024.0;
295 right_x = 512/1024.0 + 32.0 / 1024.0 * round(building.width / 6.0f);
296 front_x = 480.0/1024.0;
297 back_x = 512.0/1024.0;
300 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
301 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
302 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
303 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
306 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
307 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
308 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
309 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
311 // Back (same as front for the moment)
312 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
313 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
314 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
315 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
317 // Right (same as left for the moment)
318 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
319 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
320 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
321 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
324 left_x = 512.0/1024.0;
325 right_x = 640.0/1024.0;
326 // Use the entire height of the roof texture
327 top_y = base_y + 16.0 * 3.0 / 1024.0;
329 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
330 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
331 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
332 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
337 if (building.type == SGBuildingBin::MEDIUM)
339 int column = ((int) (mt_rand(&seed) * 1000)) % 5;
340 float base_y = 288 / 1024.0;
341 float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
342 float left_x = column * 192.0 /1024.0;
343 float right_x = left_x + 32.0 / 1024.0 * round((float) building.width / 10.0f);
345 // BASEMENT - uses the baseline texture
346 for (unsigned int i = 0; i < 16; i++) {
347 t->push_back( osg::Vec2( left_x, base_y) );
352 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
353 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
354 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
355 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
358 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
359 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
360 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
361 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
363 // Back (same as front for the moment)
364 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
365 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
366 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
367 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
369 // Right (same as left for the moment)
370 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
371 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
372 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
373 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
376 if (building.pitched) {
377 base_y = 288.0/1024.0;
378 top_y = 576.0/1024.0;
379 left_x = 960.0/1024.0;
382 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
383 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
384 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
385 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
388 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
389 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
390 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
391 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
393 // Back (same as front for the moment)
394 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
395 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
396 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
397 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
399 // Right (same as left for the moment)
400 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
401 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
402 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
403 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
407 top_y = 576.0/1024.0;
408 right_x = left_x + 32.0 / 1024.0 * 6.0;
410 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
411 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
412 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
413 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
417 if (building.type == SGBuildingBin::LARGE)
419 int column = ((int) (mt_rand(&seed) * 1000)) % 8;
420 float base_y = 576 / 1024.0;
421 float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
422 float left_x = column * 128.0 /1024.0;
423 float right_x = left_x + 32.0 / 1024.0 * round((float) building.width / 20.0f);
425 // BASEMENT - uses the baseline texture
426 for (unsigned int i = 0; i < 16; i++) {
427 t->push_back( osg::Vec2( left_x, base_y) );
432 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
433 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
434 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
435 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
438 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
439 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
440 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
441 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
443 // Back (same as front for the moment)
444 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
445 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
446 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
447 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
449 // Right (same as left for the moment)
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 if (building.pitched) {
460 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
461 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
462 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
463 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
466 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
467 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
468 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
469 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
471 // Back (same as front for the moment)
472 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
473 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
474 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
475 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
477 // Right (same as left for the moment)
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
487 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
488 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
489 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
490 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
495 // Set the vertex, texture and normals back.
496 geom->setVertexArray(v);
497 geom->setTexCoordArray(0, t);
498 geom->setNormalArray(n);
500 geom->setPrimitiveSet(0, new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,v->size()));
501 geode->setDrawable(0, geom);
504 // Helper classes for creating the quad tree
507 struct MakeBuildingLeaf
509 MakeBuildingLeaf(float range, Effect* effect) :
510 _range(range), _effect(effect) {}
512 MakeBuildingLeaf(const MakeBuildingLeaf& rhs) :
513 _range(rhs._range), _effect(rhs._effect)
516 LOD* operator() () const
518 LOD* result = new LOD;
520 // Create a series of LOD nodes so trees cover decreases slightly
521 // gradually with distance from _range to 2*_range
522 for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++)
524 //osg::ref_ptr<EffectGeode> geode = new EffectGeode();
525 //geode->setEffect(_effect);
526 osg::ref_ptr<osg::Geode> geode = new osg::Geode();
527 result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0)));
536 struct AddBuildingLeafObject
538 void operator() (LOD* lod, const SGBuildingBin::Building& building) const
540 Geode* geode = static_cast<Geode*>(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren()));
541 addBuildingToLeafGeode(geode, building);
545 struct GetBuildingCoord
547 Vec3 operator() (const SGBuildingBin::Building& building) const
549 return toOsg(building.position);
553 typedef QuadTreeBuilder<LOD*, SGBuildingBin::Building, MakeBuildingLeaf, AddBuildingLeafObject,
554 GetBuildingCoord> BuildingGeometryQuadtree;
557 struct BuildingTransformer
559 BuildingTransformer(Matrix& mat_) : mat(mat_) {}
560 SGBuildingBin::Building operator()(const SGBuildingBin::Building& building) const
562 Vec3 pos = toOsg(building.position);
563 return SGBuildingBin::Building(toSG(pos * mat), building);
570 // This actually returns a MatrixTransform node. If we rotate the whole
571 // forest into the local Z-up coordinate system we can reuse the
572 // primitive building geometry for all the forests of the same type.
573 osg::Group* createRandomBuildings(SGBuildingBinList buildings, const osg::Matrix& transform,
574 const SGReaderWriterOptions* options)
576 Matrix transInv = Matrix::inverse(transform);
578 // Set up some shared structures.
579 MatrixTransform* mt = new MatrixTransform(transform);
580 Effect* effect = makeEffect("Effects/model-default", true);
582 SGBuildingBin* bin = NULL;
584 BOOST_FOREACH(bin, buildings)
586 // Now, create a quadbuilding for the buildings.
587 BuildingGeometryQuadtree
588 quadbuilding(GetBuildingCoord(), AddBuildingLeafObject(),
589 SG_BUILDING_QUAD_TREE_DEPTH,
590 MakeBuildingLeaf(20000.0f, effect)); // FIXME - tie to property
592 // Transform building positions from the "geocentric" positions we
593 // get from the scenery polys into the local Z-up coordinate
595 std::vector<SGBuildingBin::Building> rotatedBuildings;
596 rotatedBuildings.reserve(bin->buildings.size());
597 std::transform(bin->buildings.begin(), bin->buildings.end(),
598 std::back_inserter(rotatedBuildings),
599 BuildingTransformer(transInv));
600 quadbuilding.buildQuadTree(rotatedBuildings.begin(), rotatedBuildings.end());
602 ref_ptr<Group> group = quadbuilding.getRoot();
604 // Set up the stateset for this building bin and the texture to use.
605 osg::StateSet* stateSet = group->getOrCreateStateSet();
606 const std::string texturename = bin->texture;
607 osg::Texture2D* texture = SGLoadTexture2D(texturename);
608 texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_EDGE);
609 texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_EDGE);
610 stateSet->setTextureAttributeAndModes(0, texture);
612 osg::ShadeModel* shadeModel = new osg::ShadeModel;
613 shadeModel->setMode(osg::ShadeModel::FLAT);
614 stateSet->setAttributeAndModes(shadeModel);
615 stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
616 stateSet->setMode(GL_FOG, osg::StateAttribute::ON);
617 stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
618 stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
619 stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
620 stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
621 stateSet->setAttribute(new osg::CullFace(osg::CullFace::BACK));
623 osg::Material* material = new osg::Material;
624 material->setAmbient(osg::Material::FRONT, osg::Vec4(0.3,0.3,0.3,1.0));
625 material->setDiffuse(osg::Material::FRONT, osg::Vec4(1.0,1.0,1.0,1.0));
626 material->setSpecular(osg::Material::FRONT, osg::Vec4(0,0,0,1.0));
627 material->setShininess(osg::Material::FRONT, 0.0);
628 material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
629 stateSet->setAttribute(material);