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/SGLimits.hxx>
48 #include <simgear/math/SGMisc.hxx>
49 #include <simgear/math/sg_random.h>
50 #include <simgear/misc/sg_path.hxx>
51 #include <simgear/scene/material/Effect.hxx>
52 #include <simgear/scene/material/EffectGeode.hxx>
53 #include <simgear/scene/model/model.hxx>
54 #include <simgear/props/props.hxx>
56 #include "ShaderGeometry.hxx"
57 #include "SGBuildingBin.hxx"
65 typedef std::map<std::string, osg::observer_ptr<osg::StateSet> > BuildingStateSetMap;
66 static BuildingStateSetMap statesetmap;
68 typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
69 static EffectMap buildingEffectMap;
71 // Building instance scheme:
72 // vertex - local position of vertices, with 0,0,0 being the center front.
73 // fog coord - rotation
74 // color - xyz of tree quad origin, replicated 4 times.
76 struct BuildingBoundingBoxCallback : public Drawable::ComputeBoundingBoxCallback
78 BuildingBoundingBoxCallback() {}
79 BuildingBoundingBoxCallback(const BuildingBoundingBoxCallback&, const CopyOp&) {}
80 META_Object(simgear, BuildingBoundingBoxCallback);
81 virtual BoundingBox computeBound(const Drawable&) const;
85 BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
88 const Geometry* geom = static_cast<const Geometry*>(&drawable);
89 const Vec3Array* v = static_cast<const Vec3Array*>(geom->getVertexArray());
90 const Vec4Array* pos = static_cast<const Vec4Array*>(geom->getColorArray());
92 Geometry::PrimitiveSetList primSets = geom->getPrimitiveSetList();
93 for (Geometry::PrimitiveSetList::const_iterator psitr = primSets.begin(), psend = primSets.end();
96 DrawArrays* da = static_cast<DrawArrays*>(psitr->get());
97 GLint psFirst = da->getFirst();
98 GLint psEndVert = psFirst + da->getCount();
99 for (GLint i = psFirst;i < psEndVert; ++i) {
101 Matrixd trnsfrm = Matrixd::rotate(- M_PI * 2 * (*pos)[i].a(), Vec3(0.0f, 0.0f, 1.0f));
103 pt += Vec3((*pos)[i].x(), (*pos)[i].y(), (*pos)[i].z());
110 // Set up the building set based on the material definitions
111 SGBuildingBin::SGBuildingBin(const SGMaterial *mat) {
113 material_name = mat->get_names()[0];
114 SG_LOG(SG_TERRAIN, SG_DEBUG, "Building material " << material_name);
115 texture = mat->get_building_texture();
116 lightMap = mat->get_building_lightmap();
117 SG_LOG(SG_TERRAIN, SG_DEBUG, "Building texture " << texture);
119 // Generate a random seed for the building generation.
121 mt_init(&seed, unsigned(123));
123 smallSharedGeometry = new osg::Geometry();
124 mediumSharedGeometry = new osg::Geometry();
125 largeSharedGeometry = new osg::Geometry();
127 smallBuildingMaxRadius = std::max(mat->get_building_small_max_depth() * 0.5, mat->get_building_small_max_width() * 0.5);
128 mediumBuildingMaxRadius = std::max(mat->get_building_medium_max_depth() * 0.5, mat->get_building_medium_max_width() * 0.5);
129 largeBuildingMaxRadius = std::max(mat->get_building_large_max_depth() * 0.5, mat->get_building_large_max_width() * 0.5);
131 smallBuildingMaxDepth = mat->get_building_small_max_depth();
132 mediumBuildingMaxDepth = mat->get_building_medium_max_depth();
133 largeBuildingMaxDepth = mat->get_building_large_max_depth();
135 smallBuildingFraction = mat->get_building_small_fraction();
136 mediumBuildingFraction = mat->get_building_medium_fraction();
138 buildingRange = mat->get_building_range();
140 SG_LOG(SG_TERRAIN, SG_DEBUG, "Building fractions " << smallBuildingFraction << " " << mediumBuildingFraction);
143 // TODO: Reverse this - otherwise we never get any large buildings!
144 BuildingType types[] = { SGBuildingBin::SMALL, SGBuildingBin::MEDIUM, SGBuildingBin::LARGE };
145 BuildingList lists[] = { SGBuildingBin::smallBuildings, SGBuildingBin::mediumBuildings, SGBuildingBin::largeBuildings };
146 ref_ptr<Geometry> geometries[] = { smallSharedGeometry, mediumSharedGeometry, largeSharedGeometry };
148 for (int bt=0; bt < 3; bt++) {
149 SGBuildingBin::BuildingType buildingtype = types[bt];
150 ref_ptr<Geometry> sharedGeometry = geometries[bt];
151 BuildingList buildings = lists[bt];
153 osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
154 osg::ref_ptr<osg::Vec2Array> t = new osg::Vec2Array;
155 osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
157 v->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING);
158 t->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING);
159 n->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING);
161 sharedGeometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
162 sharedGeometry->setFogCoordBinding(osg::Geometry::BIND_PER_VERTEX);
163 sharedGeometry->setComputeBoundingBoxCallback(new BuildingBoundingBoxCallback);
164 sharedGeometry->setUseDisplayList(false);
166 for (unsigned int j = 0; j < BUILDING_SET_SIZE; j++) {
173 if (buildingtype == SGBuildingBin::SMALL) {
175 width = mat->get_building_small_min_width() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_small_max_width() - mat->get_building_small_min_width());
176 depth = mat->get_building_small_min_depth() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_small_max_depth() - mat->get_building_small_min_depth());
177 floors = SGMisc<double>::round(mat->get_building_small_min_floors() + mt_rand(&seed) * (mat->get_building_small_max_floors() - mat->get_building_small_min_floors()));
178 height = floors * (2.8 + mt_rand(&seed));
180 // Small buildings are never deeper than they are wide.
181 if (depth > width) { depth = width; }
183 pitched = (mt_rand(&seed) < mat->get_building_small_pitch());
184 } else if (buildingtype == SGBuildingBin::MEDIUM) {
185 width = mat->get_building_medium_min_width() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_medium_max_width() - mat->get_building_medium_min_width());
186 depth = mat->get_building_medium_min_depth() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_medium_max_depth() - mat->get_building_medium_min_depth());
187 floors = SGMisc<double>::round(mat->get_building_medium_min_floors() + mt_rand(&seed) * (mat->get_building_medium_max_floors() - mat->get_building_medium_min_floors()));
188 height = floors * (2.8 + mt_rand(&seed));
190 while ((height > width) && (floors > mat->get_building_medium_min_floors())) {
191 // Ensure that medium buildings aren't taller than they are wide
193 height = floors * (2.8 + mt_rand(&seed));
196 pitched = (mt_rand(&seed) < mat->get_building_medium_pitch());
198 width = mat->get_building_large_min_width() + mt_rand(&seed) * (mat->get_building_large_max_width() - mat->get_building_large_min_width());
199 depth = mat->get_building_large_min_depth() + mt_rand(&seed) * (mat->get_building_large_max_depth() - mat->get_building_large_min_depth());
200 floors = SGMisc<double>::round(mat->get_building_large_min_floors() + mt_rand(&seed) * (mat->get_building_large_max_floors() - mat->get_building_large_min_floors()));
201 height = floors * (2.8 + mt_rand(&seed));
202 pitched = (mt_rand(&seed) < mat->get_building_large_pitch());
205 Building building = Building(buildingtype,
212 buildings.push_back(building);
214 // Now create an OSG Geometry based on the Building
215 float cw = 0.5f * building.width;
216 float cd = building.depth;
217 float ch = building.height;
219 // 0,0,0 is the bottom center of the front
220 // face, e.g. where the front door would be
223 // This exteds 10m below the main section
225 v->push_back( osg::Vec3( 0, -cw, -10) ); // bottom right
226 v->push_back( osg::Vec3( 0, cw, -10) ); // bottom left
227 v->push_back( osg::Vec3( 0, cw, 0) ); // top left
228 v->push_back( osg::Vec3( 0, -cw, 0) ); // top right
230 for (int i=0; i<4; ++i)
231 n->push_back( osg::Vec3(1, 0, 0) ); // normal
234 v->push_back( osg::Vec3( -cd, -cw, -10) ); // bottom right
235 v->push_back( osg::Vec3( 0, -cw, -10) ); // bottom left
236 v->push_back( osg::Vec3( 0, -cw, 0) ); // top left
237 v->push_back( osg::Vec3( -cd, -cw, 0) ); // top right
239 for (int i=0; i<4; ++i)
240 n->push_back( osg::Vec3(0, -1, 0) ); // normal
243 v->push_back( osg::Vec3( -cd, cw, -10) ); // bottom right
244 v->push_back( osg::Vec3( -cd, -cw, -10) ); // bottom left
245 v->push_back( osg::Vec3( -cd, -cw, 0) ); // top left
246 v->push_back( osg::Vec3( -cd, cw, 0) ); // top right
248 for (int i=0; i<4; ++i)
249 n->push_back( osg::Vec3(-1, 0, 0) ); // normal
252 v->push_back( osg::Vec3( 0, cw, -10) ); // bottom right
253 v->push_back( osg::Vec3( -cd, cw, -10) ); // bottom left
254 v->push_back( osg::Vec3( -cd, cw, 0) ); // top left
255 v->push_back( osg::Vec3( 0, cw, 0) ); // top right
257 for (int i=0; i<4; ++i)
258 n->push_back( osg::Vec3(0, 1, 0) ); // normal
262 v->push_back( osg::Vec3( 0, -cw, 0) ); // bottom right
263 v->push_back( osg::Vec3( 0, cw, 0) ); // bottom left
264 v->push_back( osg::Vec3( 0, cw, ch) ); // top left
265 v->push_back( osg::Vec3( 0, -cw, ch) ); // top right
267 for (int i=0; i<4; ++i)
268 n->push_back( osg::Vec3(1, 0, 0) ); // normal
271 v->push_back( osg::Vec3( -cd, -cw, 0) ); // bottom right
272 v->push_back( osg::Vec3( 0, -cw, 0) ); // bottom left
273 v->push_back( osg::Vec3( 0, -cw, ch) ); // top left
274 v->push_back( osg::Vec3( -cd, -cw, ch) ); // top right
276 for (int i=0; i<4; ++i)
277 n->push_back( osg::Vec3(0, -1, 0) ); // normal
280 v->push_back( osg::Vec3( -cd, cw, 0) ); // bottom right
281 v->push_back( osg::Vec3( -cd, -cw, 0) ); // bottom left
282 v->push_back( osg::Vec3( -cd, -cw, ch) ); // top left
283 v->push_back( osg::Vec3( -cd, cw, ch) ); // top right
285 for (int i=0; i<4; ++i)
286 n->push_back( osg::Vec3(-1, 0, 0) ); // normal
289 v->push_back( osg::Vec3( 0, cw, 0) ); // bottom right
290 v->push_back( osg::Vec3( -cd, cw, 0) ); // bottom left
291 v->push_back( osg::Vec3( -cd, cw, ch) ); // top left
292 v->push_back( osg::Vec3( 0, cw, ch) ); // top right
294 for (int i=0; i<4; ++i)
295 n->push_back( osg::Vec3(0, 1, 0) ); // normal
298 if (building.pitched) {
300 // Front pitched roof
301 v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom right
302 v->push_back( osg::Vec3( 0, cw, ch) ); // bottom left
303 v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top left
304 v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top right
306 for (int i=0; i<4; ++i)
307 n->push_back( osg::Vec3(0.707, 0, 0.707) ); // normal
310 v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom right
311 v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom left
312 v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top left
313 v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top right
315 for (int i=0; i<4; ++i)
316 n->push_back( osg::Vec3(0, -1, 0) ); // normal
319 v->push_back( osg::Vec3( -cd, cw, ch) ); // bottom right
320 v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom left
321 v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top left
322 v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top right
324 for (int i=0; i<4; ++i)
325 n->push_back( osg::Vec3(-0.707, 0, 0.707) ); // normal
327 // Right pitched roof
328 v->push_back( osg::Vec3( 0, cw, ch) ); // bottom right
329 v->push_back( osg::Vec3( -cd, cw, ch) ); // bottom left
330 v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top left
331 v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top right
333 for (int i=0; i<4; ++i)
334 n->push_back( osg::Vec3(0, 1, 0) ); // normal
336 // If the roof isn't pitched, we still generate the
337 // vertices for simplicity later.
340 v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom right
341 v->push_back( osg::Vec3( 0, cw, ch) ); // bottom left
342 v->push_back( osg::Vec3(-cd, cw, ch) ); // top left
343 v->push_back( osg::Vec3(-cd, -cw, ch) ); // top right
345 for (int i=0; i<4; ++i)
346 n->push_back( osg::Vec3(0, 0, 1) ); // normal
348 // Left non-pitched roof
349 v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom right
350 v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom left
351 v->push_back( osg::Vec3( 0, -cw, ch) ); // top left
352 v->push_back( osg::Vec3( -cd, -cw, ch) ); // top right
354 for (int i=0; i<4; ++i)
355 n->push_back( osg::Vec3(0, -1, 0) ); // normal
358 v->push_back( osg::Vec3(-cd, cw, ch) ); // bottom right
359 v->push_back( osg::Vec3(-cd, -cw, ch) ); // bottom left
360 v->push_back( osg::Vec3(-cd, -cw, ch) ); // top left
361 v->push_back( osg::Vec3(-cd, cw, ch) ); // top right
363 for (int i=0; i<4; ++i)
364 n->push_back( osg::Vec3(1, 0, 0) ); // normal
366 // Right pitched roof
367 v->push_back( osg::Vec3( 0, cw, ch) ); // bottom right
368 v->push_back( osg::Vec3(-cd, cw, ch) ); // bottom left
369 v->push_back( osg::Vec3(-cd, cw, ch) ); // top left
370 v->push_back( osg::Vec3( 0, cw, ch) ); // top right
372 for (int i=0; i<4; ++i)
373 n->push_back( osg::Vec3(0, 1, 0) ); // normal
376 // The 1024x1024 texture is split into 32x16 blocks.
377 // For a small building, each block is 6m wide and 3m high.
378 // For a medium building, each block is 10m wide and 3m high.
379 // For a large building, each block is 20m wide and 3m high
381 if (building.type == SGBuildingBin::SMALL) {
382 // Small buildings are represented on the bottom 5 rows of 3 floors
383 int row = ((int) (mt_rand(&seed) * 1000)) % 5;
384 float base_y = (float) row * 16.0 * 3.0 / 1024.0;
385 float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
386 float left_x = 32.0 / 1024.0 * round((float) building.width / 6.0f);
387 float right_x = 0.0f;
388 float front_x = 384.0/1024.0;
389 float back_x = 384.0/1024.0 + 32.0 / 1024.0 * round((float) building.depth/ 6.0f);
391 // BASEMENT - uses the baseline texture
392 for (unsigned int i = 0; i < 16; i++) {
393 t->push_back( osg::Vec2( left_x, base_y) );
397 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
398 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
399 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
400 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
403 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
404 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
405 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
406 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
408 // Back (same as front for the moment)
409 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
410 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
411 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
412 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
414 // Right (same as left for the moment)
415 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
416 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
417 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
418 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
421 if (building.pitched) {
422 // Use the entire height of the roof texture
423 top_y = base_y + 16.0 * 3.0 / 1024.0;
424 left_x = 512/1024.0 + 32.0 / 1024.0 * round(building.width / 6.0f);
425 right_x = 512/1024.0;
426 front_x = 480.0/1024.0;
427 back_x = 512.0/1024.0;
430 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
431 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
432 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
433 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
436 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
437 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
438 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
439 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
441 // Back (same as front for the moment)
442 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
443 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
444 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
445 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
447 // Right (same as left for the moment)
448 t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
449 t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
450 t->push_back( osg::Vec2( back_x, top_y ) ); // top left
451 t->push_back( osg::Vec2( front_x, top_y ) ); // top right
454 left_x = 640.0/1024.0;
455 right_x = 512.0/1024.0;
456 // Use the entire height of the roof texture
457 top_y = base_y + 16.0 * 3.0 / 1024.0;
459 // Flat roofs still have 4 surfaces, so we need to set the textures
460 for (int i=0; i<4; ++i) {
461 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
462 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
463 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
464 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
470 if (building.type == SGBuildingBin::MEDIUM)
472 int column = ((int) (mt_rand(&seed) * 1000)) % 5;
473 float base_y = 288 / 1024.0;
474 float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
475 float left_x = column * 192.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 10.0f);
476 float right_x = column * 192.0 /1024.0;
478 // BASEMENT - uses the baseline texture
479 for (unsigned int i = 0; i < 16; i++) {
480 t->push_back( osg::Vec2( left_x, base_y) );
485 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
486 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
487 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
488 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
491 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
492 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
493 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
494 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
496 // Back (same as front for the moment)
497 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
498 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
499 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
500 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
502 // Right (same as left for the moment)
503 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
504 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
505 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
506 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
509 if (building.pitched) {
510 base_y = 288.0/1024.0;
511 top_y = 576.0/1024.0;
512 left_x = 960.0/1024.0;
516 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
517 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
518 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
519 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
522 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
523 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
524 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
525 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
527 // Back (same as front for the moment)
528 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
529 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
530 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
531 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
533 // Right (same as left for the moment)
534 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
535 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
536 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
537 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
541 top_y = 576.0/1024.0;
542 left_x = column * 192.0 /1024.0;
543 right_x = (column + 1)* 192.0 /1024.0;
545 // Flat roofs still have 4 surfaces
546 for (int i=0; i<4; ++i) {
547 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
548 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
549 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
550 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
555 if (building.type == SGBuildingBin::LARGE)
557 int column = ((int) (mt_rand(&seed) * 1000)) % 8;
558 float base_y = 576 / 1024.0;
559 float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
560 float left_x = column * 128.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 20.0f);
561 float right_x = column * 128.0 /1024.0;
563 // BASEMENT - uses the baseline texture
564 for (unsigned int i = 0; i < 16; i++) {
565 t->push_back( osg::Vec2( left_x, base_y) );
570 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
571 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
572 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
573 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
576 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
577 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
578 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
579 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
581 // Back (same as front for the moment)
582 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
583 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
584 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
585 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
587 // Right (same as left for the moment)
588 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
589 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
590 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
591 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
594 if (building.pitched) {
598 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
599 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
600 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
601 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
604 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
605 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
606 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
607 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
609 // Back (same as front for the moment)
610 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
611 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
612 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
613 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
615 // Right (same as left for the moment)
616 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
617 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
618 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
619 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
625 // Flat roofs still have 4 surfaces
626 for (int i=0; i<4; ++i) {
627 t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
628 t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
629 t->push_back( osg::Vec2( left_x, top_y ) ); // top left
630 t->push_back( osg::Vec2( right_x, top_y ) ); // top right
636 // Set the vertex, texture and normals. Colors will be set per-instance
638 sharedGeometry->setVertexArray(v);
639 sharedGeometry->setTexCoordArray(0, t);
640 sharedGeometry->setNormalArray(n);
644 void SGBuildingBin::insert(SGVec3f p, float r, BuildingType type) {
646 if (type == SGBuildingBin::SMALL) {
647 smallBuildingLocations.push_back(BuildingInstance(p, r, &smallBuildings, smallSharedGeometry));
650 if (type == SGBuildingBin::MEDIUM) {
651 mediumBuildingLocations.push_back(BuildingInstance(p, r, &mediumBuildings, mediumSharedGeometry));
654 if (type == SGBuildingBin::LARGE) {
655 largeBuildingLocations.push_back(BuildingInstance(p, r, &largeBuildings, largeSharedGeometry));
659 int SGBuildingBin::getNumBuildings() {
660 return smallBuildingLocations.size() + mediumBuildingLocations.size() + largeBuildingLocations.size();
663 bool SGBuildingBin::checkMinDist (SGVec3f p, float radius) {
664 BuildingInstanceList::iterator iter;
666 float r = (radius + smallBuildingMaxRadius) * (radius + smallBuildingMaxRadius);
667 for (iter = smallBuildingLocations.begin(); iter != smallBuildingLocations.end(); ++iter) {
668 if (iter->getDistSqr(p) < r) {
673 r = (radius + mediumBuildingMaxRadius) * (radius + mediumBuildingMaxRadius);
674 for (iter = mediumBuildingLocations.begin(); iter != mediumBuildingLocations.end(); ++iter) {
675 if (iter->getDistSqr(p) < r) {
680 r = (radius + largeBuildingMaxRadius) * (radius + largeBuildingMaxRadius);
681 for (iter = largeBuildingLocations.begin(); iter != largeBuildingLocations.end(); ++iter) {
682 if (iter->getDistSqr(p) < r) {
690 SGBuildingBin::BuildingType SGBuildingBin::getBuildingType(float roll) {
692 if (roll < smallBuildingFraction) {
693 return SGBuildingBin::SMALL;
696 if (roll < (smallBuildingFraction + mediumBuildingFraction)) {
697 return SGBuildingBin::MEDIUM;
700 return SGBuildingBin::LARGE;
703 float SGBuildingBin::getBuildingMaxRadius(BuildingType type) {
705 if (type == SGBuildingBin::SMALL) return smallBuildingMaxRadius;
706 if (type == SGBuildingBin::MEDIUM) return mediumBuildingMaxRadius;
707 if (type == SGBuildingBin::LARGE) return largeBuildingMaxRadius;
712 float SGBuildingBin::getBuildingMaxDepth(BuildingType type) {
714 if (type == SGBuildingBin::SMALL) return smallBuildingMaxDepth;
715 if (type == SGBuildingBin::MEDIUM) return mediumBuildingMaxDepth;
716 if (type == SGBuildingBin::LARGE) return largeBuildingMaxDepth;
721 ref_ptr<Group> SGBuildingBin::createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options)
723 ref_ptr<Effect> effect;
724 EffectMap::iterator iter = buildingEffectMap.find(texture);
726 if ((iter == buildingEffectMap.end())||
727 (!iter->second.lock(effect)))
729 SGPropertyNode_ptr effectProp = new SGPropertyNode;
730 makeChild(effectProp, "inherits-from")->setStringValue("Effects/building");
731 SGPropertyNode* params = makeChild(effectProp, "parameters");
732 // Main texture - n=0
733 params->getChild("texture", 0, true)->getChild("image", 0, true)
734 ->setStringValue(texture);
737 params->getChild("texture", 3, true)->getChild("image", 0, true)
738 ->setStringValue(lightMap);
740 effect = makeEffect(effectProp, true, options);
741 if (iter == buildingEffectMap.end())
742 buildingEffectMap.insert(EffectMap::value_type(texture, effect));
744 iter->second = effect; // update existing, but empty observer
747 ref_ptr<Group> group = new osg::Group();
749 // Now, create a quadbuilding for the buildings.
751 BuildingInstanceList locs[] = { smallBuildingLocations,
752 SGBuildingBin::mediumBuildingLocations,
753 SGBuildingBin::largeBuildingLocations };
755 for (int i = 0; i < 3; i++)
757 // Create a quad tree. Only small and medium buildings are faded out.
758 BuildingGeometryQuadtree
759 quadbuilding(GetBuildingCoord(), AddBuildingLeafObject(),
760 SG_BUILDING_QUAD_TREE_DEPTH,
761 MakeBuildingLeaf(buildingRange, effect, (i != 2)));
763 // Transform building positions from the "geocentric" positions we
764 // get from the scenery polys into the local Z-up coordinate
766 std::vector<BuildingInstance> rotatedBuildings;
767 rotatedBuildings.reserve(locs[i].size());
768 std::transform(locs[i].begin(), locs[i].end(),
769 std::back_inserter(rotatedBuildings),
770 BuildingInstanceTransformer(transInv));
771 quadbuilding.buildQuadTree(rotatedBuildings.begin(), rotatedBuildings.end());
773 for (size_t j = 0; j < quadbuilding.getRoot()->getNumChildren(); ++j)
774 group->addChild(quadbuilding.getRoot()->getChild(j));
780 // We may end up with a quadtree with many empty leaves. One might say
781 // that we should avoid constructing the leaves in the first place,
782 // but this node visitor tries to clean up after the fact.
783 struct QuadTreeCleaner : public osg::NodeVisitor
785 QuadTreeCleaner() : NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN)
790 for (int i = lod.getNumChildren() - 1; i >= 0; --i) {
791 EffectGeode* geode = dynamic_cast<EffectGeode*>(lod.getChild(i));
794 bool geodeEmpty = true;
795 if (geode->getNumDrawables() > 1) {
796 SG_LOG(SG_TERRAIN, SG_DEBUG, "Building LOD Drawables: " << geode->getNumDrawables());
799 for (unsigned j = 0; j < geode->getNumDrawables(); ++j) {
800 const Geometry* geom = dynamic_cast<Geometry*>(geode->getDrawable(j));
805 for (unsigned k = 0; k < geom->getNumPrimitiveSets(); k++) {
806 const PrimitiveSet* ps = geom->getPrimitiveSet(k);
807 if (ps->getNumIndices() > 0) {
814 lod.removeChildren(i, 1);
819 // This actually returns a MatrixTransform node. If we rotate the whole
820 // forest into the local Z-up coordinate system we can reuse the
821 // primitive building geometry for all the forests of the same type.
822 osg::Group* createRandomBuildings(SGBuildingBinList buildings, const osg::Matrix& transform,
823 const SGReaderWriterOptions* options)
825 Matrix transInv = Matrix::inverse(transform);
827 // Set up some shared structures.
828 MatrixTransform* mt = new MatrixTransform(transform);
830 SGBuildingBin* bin = NULL;
832 BOOST_FOREACH(bin, buildings)
834 ref_ptr<Group> group = bin->createBuildingsGroup(transInv, options);
836 for (size_t i = 0; i < group->getNumChildren(); ++i)
837 mt->addChild(group->getChild(i));
843 QuadTreeCleaner cleaner;