]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/SGBuildingBin.cxx
Fix detection of airports in the stg loader.
[simgear.git] / simgear / scene / tgdb / SGBuildingBin.cxx
1 /* -*-c++-*-
2  *
3  * Copyright (C) 2012 Stuart Buchanan
4  *
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.
9  *
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.
14  *
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,
18  * MA 02110-1301, USA.
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include <simgear_config.h>
24 #endif
25
26 #include <algorithm>
27 #include <vector>
28 #include <string>
29 #include <map>
30
31 #include <boost/foreach.hpp>
32 #include <boost/tuple/tuple_comparison.hpp>
33
34 #include <osg/Geode>
35 #include <osg/Geometry>
36 #include <osg/Math>
37 #include <osg/MatrixTransform>
38 #include <osg/Matrix>
39 #include <osg/ShadeModel>
40 #include <osg/Material>
41 #include <osg/CullFace>
42
43 #include <osgDB/ReadFile>
44 #include <osgDB/FileUtils>
45
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>
55
56 #include "ShaderGeometry.hxx"
57 #include "SGBuildingBin.hxx"
58
59
60 using namespace osg;
61
62 namespace simgear
63 {
64
65 typedef std::map<std::string, osg::observer_ptr<osg::StateSet> > BuildingStateSetMap;
66 static BuildingStateSetMap statesetmap;
67
68 typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
69 static EffectMap buildingEffectMap;
70
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.
75
76 struct BuildingBoundingBoxCallback : public Drawable::ComputeBoundingBoxCallback
77 {
78     BuildingBoundingBoxCallback() {}
79     BuildingBoundingBoxCallback(const BuildingBoundingBoxCallback&, const CopyOp&) {}
80     META_Object(simgear, BuildingBoundingBoxCallback);
81     virtual BoundingBox computeBound(const Drawable&) const;
82 };
83
84 BoundingBox
85 BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
86 {
87     BoundingBox bb;
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());
91
92     Geometry::PrimitiveSetList primSets = geom->getPrimitiveSetList();
93     for (Geometry::PrimitiveSetList::const_iterator psitr = primSets.begin(), psend = primSets.end();
94          psitr != psend;
95          ++psitr) {
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) {
100             Vec3 pt = (*v)[i];
101             Matrixd trnsfrm = Matrixd::rotate(- M_PI * 2 * (*pos)[i].a(), Vec3(0.0f, 0.0f, 1.0f));
102             pt = pt * trnsfrm;
103             pt += Vec3((*pos)[i].x(), (*pos)[i].y(), (*pos)[i].z());
104             bb.expandBy(pt);
105         }
106     }
107     return bb;
108 }
109
110   // Set up the building set based on the material definitions
111   SGBuildingBin::SGBuildingBin(const SGMaterial *mat, bool useVBOs) {
112
113     material_name = new std::string(mat->get_names()[0]);
114     SG_LOG(SG_TERRAIN, SG_DEBUG, "Building material " << material_name);
115     texture = new std::string(mat->get_building_texture());
116     lightMap = new std::string(mat->get_building_lightmap());
117     SG_LOG(SG_TERRAIN, SG_DEBUG, "Building texture " << texture);
118
119     // Generate a random seed for the building generation.
120     mt seed;
121     mt_init(&seed, unsigned(123));
122
123     smallSharedGeometry = new osg::Geometry();
124     mediumSharedGeometry = new osg::Geometry();
125     largeSharedGeometry = new osg::Geometry();
126
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);
130
131     smallBuildingMaxDepth = mat->get_building_small_max_depth();
132     mediumBuildingMaxDepth = mat->get_building_medium_max_depth();
133     largeBuildingMaxDepth = mat->get_building_large_max_depth();
134
135     smallBuildingFraction = mat->get_building_small_fraction();
136     mediumBuildingFraction = mat->get_building_medium_fraction();
137
138     buildingRange = mat->get_building_range();
139
140     SG_LOG(SG_TERRAIN, SG_DEBUG, "Building fractions " << smallBuildingFraction << " " << mediumBuildingFraction);
141
142
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 };
147
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];
152
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;
156
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);
160
161       sharedGeometry->setFogCoordBinding(osg::Geometry::BIND_PER_VERTEX);
162       sharedGeometry->setComputeBoundingBoxCallback(new BuildingBoundingBoxCallback);
163       sharedGeometry->setUseDisplayList(false);
164       sharedGeometry->setDataVariance(osg::Object::STATIC);
165       if (useVBOs) {
166           sharedGeometry->setUseVertexBufferObjects(true);
167       }
168       
169       for (unsigned int j = 0; j < BUILDING_SET_SIZE; j++) {
170         float width;
171         float depth;
172         int floors;
173         float height;
174         bool pitched;
175
176         if (buildingtype == SGBuildingBin::SMALL) {
177           // Small building
178           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());
179           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());
180           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()));
181           height = floors * (2.8 + mt_rand(&seed));
182
183           // Small buildings are never deeper than they are wide.
184           if (depth > width) { depth = width; }
185
186           pitched = (mt_rand(&seed) < mat->get_building_small_pitch());
187         } else if (buildingtype == SGBuildingBin::MEDIUM) {
188           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());
189           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());
190           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()));
191           height = floors * (2.8 + mt_rand(&seed));
192
193           while ((height > width) && (floors > mat->get_building_medium_min_floors())) {
194             // Ensure that medium buildings aren't taller than they are wide
195             floors--;
196             height = floors * (2.8 + mt_rand(&seed));
197           }
198
199           pitched = (mt_rand(&seed) < mat->get_building_medium_pitch());
200         } else {
201           width = mat->get_building_large_min_width() + mt_rand(&seed) * (mat->get_building_large_max_width() - mat->get_building_large_min_width());
202           depth = mat->get_building_large_min_depth() + mt_rand(&seed) * (mat->get_building_large_max_depth() - mat->get_building_large_min_depth());
203           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()));
204           height = floors * (2.8 + mt_rand(&seed));
205           pitched = (mt_rand(&seed) < mat->get_building_large_pitch());
206         }
207
208         Building building = Building(buildingtype,
209                                     width,
210                                     depth,
211                                     height,
212                                     floors,
213                                     pitched);
214
215         buildings.push_back(building);
216
217         // Now create an OSG Geometry based on the Building
218         float cw = 0.5f * building.width;
219         float cd = building.depth;
220         float ch = building.height;
221
222         // 0,0,0 is the bottom center of the front
223         // face, e.g. where the front door would be
224
225         // BASEMENT
226         // This exteds 10m below the main section
227         // Front face
228         v->push_back( osg::Vec3( 0, -cw, -10) ); // bottom right
229         v->push_back( osg::Vec3( 0,  cw, -10) ); // bottom left
230         v->push_back( osg::Vec3( 0,  cw,   0) ); // top left
231         v->push_back( osg::Vec3( 0, -cw,   0) ); // top right
232
233         for (int i=0; i<4; ++i)
234           n->push_back( osg::Vec3(1, 0, 0) ); // normal
235
236         // Left face
237         v->push_back( osg::Vec3( -cd, -cw, -10) ); // bottom right
238         v->push_back( osg::Vec3(   0, -cw, -10) ); // bottom left
239         v->push_back( osg::Vec3(   0, -cw,   0) ); // top left
240         v->push_back( osg::Vec3( -cd, -cw,   0) ); // top right
241
242         for (int i=0; i<4; ++i)
243           n->push_back( osg::Vec3(0, -1, 0) ); // normal
244
245         // Back face
246         v->push_back( osg::Vec3( -cd,  cw, -10) ); // bottom right
247         v->push_back( osg::Vec3( -cd, -cw, -10) ); // bottom left
248         v->push_back( osg::Vec3( -cd, -cw,   0) ); // top left
249         v->push_back( osg::Vec3( -cd,  cw,   0) ); // top right
250
251         for (int i=0; i<4; ++i)
252           n->push_back( osg::Vec3(-1, 0, 0) ); // normal
253
254         // Right face
255         v->push_back( osg::Vec3(   0, cw, -10) ); // bottom right
256         v->push_back( osg::Vec3( -cd, cw, -10) ); // bottom left
257         v->push_back( osg::Vec3( -cd, cw,   0) ); // top left
258         v->push_back( osg::Vec3(   0, cw,   0) ); // top right
259
260         for (int i=0; i<4; ++i)
261           n->push_back( osg::Vec3(0, 1, 0) ); // normal
262
263         // MAIN BODY
264         // Front face
265         v->push_back( osg::Vec3( 0, -cw,  0) ); // bottom right
266         v->push_back( osg::Vec3( 0,  cw,  0) ); // bottom left
267         v->push_back( osg::Vec3( 0,  cw, ch) ); // top left
268         v->push_back( osg::Vec3( 0, -cw, ch) ); // top right
269
270         for (int i=0; i<4; ++i)
271           n->push_back( osg::Vec3(1, 0, 0) ); // normal
272
273         // Left face
274         v->push_back( osg::Vec3( -cd, -cw,  0) ); // bottom right
275         v->push_back( osg::Vec3(   0, -cw,  0) ); // bottom left
276         v->push_back( osg::Vec3(   0, -cw, ch) ); // top left
277         v->push_back( osg::Vec3( -cd, -cw, ch) ); // top right
278
279         for (int i=0; i<4; ++i)
280           n->push_back( osg::Vec3(0, -1, 0) ); // normal
281
282         // Back face
283         v->push_back( osg::Vec3( -cd,  cw,  0) ); // bottom right
284         v->push_back( osg::Vec3( -cd, -cw,  0) ); // bottom left
285         v->push_back( osg::Vec3( -cd, -cw, ch) ); // top left
286         v->push_back( osg::Vec3( -cd,  cw, ch) ); // top right
287
288         for (int i=0; i<4; ++i)
289           n->push_back( osg::Vec3(-1, 0, 0) ); // normal
290
291         // Right face
292         v->push_back( osg::Vec3(   0, cw,  0) ); // bottom right
293         v->push_back( osg::Vec3( -cd, cw,  0) ); // bottom left
294         v->push_back( osg::Vec3( -cd, cw, ch) ); // top left
295         v->push_back( osg::Vec3(   0, cw, ch) ); // top right
296
297         for (int i=0; i<4; ++i)
298           n->push_back( osg::Vec3(0, 1, 0) ); // normal
299
300         // ROOF
301         if (building.pitched) {
302
303           // Front pitched roof
304           v->push_back( osg::Vec3(    0, -cw,   ch) ); // bottom right
305           v->push_back( osg::Vec3(    0,  cw,   ch) ); // bottom left
306           v->push_back( osg::Vec3(-0.5*cd,  cw, ch+3) ); // top left
307           v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top right
308
309           for (int i=0; i<4; ++i)
310             n->push_back( osg::Vec3(0.707, 0, 0.707) ); // normal
311
312           // Left pitched roof
313           v->push_back( osg::Vec3(    -cd, -cw,   ch) ); // bottom right
314           v->push_back( osg::Vec3(      0, -cw,   ch) ); // bottom left
315           v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top left
316           v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top right
317
318           for (int i=0; i<4; ++i)
319             n->push_back( osg::Vec3(0, -1, 0) ); // normal
320
321           // Back pitched roof
322           v->push_back( osg::Vec3(    -cd,  cw,   ch) ); // bottom right
323           v->push_back( osg::Vec3(    -cd, -cw,   ch) ); // bottom left
324           v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top left
325           v->push_back( osg::Vec3(-0.5*cd,  cw, ch+3) ); // top right
326
327           for (int i=0; i<4; ++i)
328             n->push_back( osg::Vec3(-0.707, 0, 0.707) ); // normal
329
330           // Right pitched roof
331           v->push_back( osg::Vec3(      0, cw,   ch) ); // bottom right
332           v->push_back( osg::Vec3(    -cd, cw,   ch) ); // bottom left
333           v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top left
334           v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top right
335
336           for (int i=0; i<4; ++i)
337             n->push_back( osg::Vec3(0, 1, 0) ); // normal
338         } else {
339           // If the roof isn't pitched, we still generate the
340           // vertices for simplicity later.
341
342           // Top of the roof
343           v->push_back( osg::Vec3(  0, -cw, ch) ); // bottom right
344           v->push_back( osg::Vec3(  0,  cw, ch) ); // bottom left
345           v->push_back( osg::Vec3(-cd,  cw, ch) ); // top left
346           v->push_back( osg::Vec3(-cd, -cw, ch) ); // top right
347
348           for (int i=0; i<4; ++i)
349             n->push_back( osg::Vec3(0, 0, 1) ); // normal
350
351           // Left non-pitched roof
352           v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom right
353           v->push_back( osg::Vec3(   0, -cw, ch) ); // bottom left
354           v->push_back( osg::Vec3(   0, -cw, ch) ); // top left
355           v->push_back( osg::Vec3( -cd, -cw, ch) ); // top right
356
357           for (int i=0; i<4; ++i)
358             n->push_back( osg::Vec3(0, -1, 0) ); // normal
359
360           // Back pitched roof
361           v->push_back( osg::Vec3(-cd,  cw, ch) ); // bottom right
362           v->push_back( osg::Vec3(-cd, -cw, ch) ); // bottom left
363           v->push_back( osg::Vec3(-cd, -cw, ch) ); // top left
364           v->push_back( osg::Vec3(-cd,  cw, ch) ); // top right
365
366           for (int i=0; i<4; ++i)
367             n->push_back( osg::Vec3(1, 0, 0) ); // normal
368
369           // Right pitched roof
370           v->push_back( osg::Vec3(  0, cw, ch) ); // bottom right
371           v->push_back( osg::Vec3(-cd, cw, ch) ); // bottom left
372           v->push_back( osg::Vec3(-cd, cw, ch) ); // top left
373           v->push_back( osg::Vec3(  0, cw, ch) ); // top right
374
375           for (int i=0; i<4; ++i)
376             n->push_back( osg::Vec3(0, 1, 0) ); // normal
377         }
378
379         // The 1024x1024 texture is split into 32x16 blocks.
380         // For a small building, each block is 6m wide and 3m high.
381         // For a medium building, each block is 10m wide and 3m high.
382         // For a large building, each block is 20m wide and 3m high
383
384         if (building.type == SGBuildingBin::SMALL) {
385           // Small buildings are represented on the bottom 5 rows of 3 floors
386           int row = ((int) (mt_rand(&seed) * 1000)) % 5;
387           float base_y = (float) row * 16.0 * 3.0 / 1024.0;
388           float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
389           float left_x = 32.0 / 1024.0 * round((float) building.width / 6.0f);
390           float right_x = 0.0f;
391           float front_x = 384.0/1024.0;
392           float back_x = 384.0/1024.0 + 32.0 / 1024.0 * round((float) building.depth/ 6.0f);
393
394           // BASEMENT - uses the baseline texture
395           for (unsigned int i = 0; i < 16; i++) {
396             t->push_back( osg::Vec2( left_x, base_y) );
397           }
398           // MAIN BODY
399           // Front
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
404
405           // Left
406           t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
407           t->push_back( osg::Vec2( back_x,  base_y) ); // bottom left
408           t->push_back( osg::Vec2( back_x,  top_y ) ); // top left
409           t->push_back( osg::Vec2( front_x, top_y ) ); // top right
410
411           // Back (same as front for the moment)
412           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
413           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
414           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
415           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
416
417           // Right (same as left for the moment)
418           t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
419           t->push_back( osg::Vec2( back_x,  base_y) ); // bottom left
420           t->push_back( osg::Vec2( back_x,  top_y ) ); // top left
421           t->push_back( osg::Vec2( front_x, top_y ) ); // top right
422
423           // ROOF
424           if (building.pitched) {
425             // Use the entire height of the roof texture
426             top_y = base_y + 16.0 * 3.0 / 1024.0;
427             left_x = 512/1024.0 + 32.0 / 1024.0 * round(building.width / 6.0f);
428             right_x = 512/1024.0;
429             front_x = 480.0/1024.0;
430             back_x = 512.0/1024.0;
431
432             // Front
433             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
434             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
435             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
436             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
437
438             // Left
439             t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
440             t->push_back( osg::Vec2( back_x,  base_y) ); // bottom left
441             t->push_back( osg::Vec2( back_x,  top_y ) ); // top left
442             t->push_back( osg::Vec2( front_x, top_y ) ); // top right
443
444             // Back (same as front for the moment)
445             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
446             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
447             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
448             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
449
450             // Right (same as left for the moment)
451             t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
452             t->push_back( osg::Vec2( back_x,  base_y) ); // bottom left
453             t->push_back( osg::Vec2( back_x,  top_y ) ); // top left
454             t->push_back( osg::Vec2( front_x, top_y ) ); // top right
455           } else {
456             // Flat roof
457             left_x = 640.0/1024.0;
458             right_x = 512.0/1024.0;
459             // Use the entire height of the roof texture
460             top_y = base_y + 16.0 * 3.0 / 1024.0;
461
462             // Flat roofs still have 4 surfaces, so we need to set the textures
463             for (int i=0; i<4; ++i) {
464               t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
465               t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
466               t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
467               t->push_back( osg::Vec2( right_x, top_y ) ); // top right
468             }
469           }
470
471         }
472
473         if (building.type == SGBuildingBin::MEDIUM)
474         {
475           int column = ((int) (mt_rand(&seed) * 1000)) % 5;
476           float base_y = 288 / 1024.0;
477           float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
478           float left_x = column * 192.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 10.0f);
479           float right_x = column * 192.0 /1024.0;
480
481           // BASEMENT - uses the baseline texture
482           for (unsigned int i = 0; i < 16; i++) {
483             t->push_back( osg::Vec2( left_x, base_y) );
484           }
485
486           // MAIN BODY
487           // Front
488           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
489           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
490           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
491           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
492
493           // Left
494           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
495           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
496           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
497           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
498
499           // Back (same as front for the moment)
500           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
501           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
502           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
503           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
504
505           // Right (same as left for the moment)
506           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
507           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
508           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
509           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
510
511           // ROOF
512           if (building.pitched) {
513             base_y = 288.0/1024.0;
514             top_y = 576.0/1024.0;
515             left_x = 960.0/1024.0;
516             right_x = 1.0;
517
518             // Front
519             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
520             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
521             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
522             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
523
524             // Left
525             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
526             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
527             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
528             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
529
530             // Back (same as front for the moment)
531             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
532             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
533             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
534             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
535
536             // Right (same as left for the moment)
537             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
538             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
539             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
540             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
541           } else {
542             // Flat roof
543             base_y = 416/1024.0;
544             top_y = 576.0/1024.0;
545             left_x = column * 192.0 /1024.0;
546             right_x = (column + 1)* 192.0 /1024.0;
547
548             // Flat roofs still have 4 surfaces
549             for (int i=0; i<4; ++i) {
550               t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
551               t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
552               t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
553               t->push_back( osg::Vec2( right_x, top_y ) ); // top right
554             }
555           }
556         }
557
558         if (building.type == SGBuildingBin::LARGE)
559         {
560           int column = ((int) (mt_rand(&seed) * 1000)) % 8;
561           float base_y = 576 / 1024.0;
562           float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
563           float left_x = column * 128.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 20.0f);
564           float right_x = column * 128.0 /1024.0;
565
566           // BASEMENT - uses the baseline texture
567           for (unsigned int i = 0; i < 16; i++) {
568             t->push_back( osg::Vec2( left_x, base_y) );
569           }
570
571           // MAIN BODY
572           // Front
573           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
574           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
575           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
576           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
577
578           // Left
579           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
580           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
581           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
582           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
583
584           // Back (same as front for the moment)
585           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
586           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
587           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
588           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
589
590           // Right (same as left for the moment)
591           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
592           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
593           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
594           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
595
596           // ROOF
597           if (building.pitched) {
598             base_y = 896/1024.0;
599             top_y = 1.0;
600             // Front
601             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
602             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
603             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
604             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
605
606             // Left
607             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
608             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
609             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
610             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
611
612             // Back (same as front for the moment)
613             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
614             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
615             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
616             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
617
618             // Right (same as left for the moment)
619             t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
620             t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
621             t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
622             t->push_back( osg::Vec2( right_x, top_y ) ); // top right
623           } else {
624             // Flat roof
625             base_y = 896/1024.0;
626             top_y = 1.0;
627
628             // Flat roofs still have 4 surfaces
629             for (int i=0; i<4; ++i) {
630               t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
631               t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
632               t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
633               t->push_back( osg::Vec2( right_x, top_y ) ); // top right
634             }
635           }
636         }
637       }
638
639       // Set the vertex, texture and normals.  Colors will be set per-instance
640       // later.
641       sharedGeometry->setVertexArray(v);
642       sharedGeometry->setTexCoordArray(0, t, Array::BIND_PER_VERTEX);
643       sharedGeometry->setNormalArray(n, Array::BIND_PER_VERTEX);
644     }
645   }
646
647   void SGBuildingBin::insert(SGVec3f p, float r, BuildingType type) {
648
649     if (type == SGBuildingBin::SMALL) {
650       smallBuildingLocations.push_back(BuildingInstance(p, r, &smallBuildings, smallSharedGeometry));
651     }
652
653     if (type == SGBuildingBin::MEDIUM) {
654       mediumBuildingLocations.push_back(BuildingInstance(p, r, &mediumBuildings, mediumSharedGeometry));
655     }
656
657     if (type == SGBuildingBin::LARGE) {
658       largeBuildingLocations.push_back(BuildingInstance(p, r, &largeBuildings, largeSharedGeometry));
659     }
660   }
661
662   int SGBuildingBin::getNumBuildings() {
663     return smallBuildingLocations.size() + mediumBuildingLocations.size() + largeBuildingLocations.size();
664   }
665
666   bool SGBuildingBin::checkMinDist (SGVec3f p, float radius) {
667     BuildingInstanceList::iterator iter;
668
669     float r = (radius + smallBuildingMaxRadius) * (radius + smallBuildingMaxRadius);
670     for (iter = smallBuildingLocations.begin(); iter != smallBuildingLocations.end(); ++iter) {
671       if (iter->getDistSqr(p) < r) {
672         return false;
673       }
674     }
675
676     r = (radius + mediumBuildingMaxRadius) * (radius + mediumBuildingMaxRadius);
677     for (iter = mediumBuildingLocations.begin(); iter != mediumBuildingLocations.end(); ++iter) {
678       if (iter->getDistSqr(p) < r) {
679         return false;
680       }
681     }
682
683     r = (radius + largeBuildingMaxRadius) * (radius + largeBuildingMaxRadius);
684     for (iter = largeBuildingLocations.begin(); iter != largeBuildingLocations.end(); ++iter) {
685       if (iter->getDistSqr(p) < r) {
686         return false;
687       }
688     }
689
690     return true;
691   }
692
693   SGBuildingBin::BuildingType SGBuildingBin::getBuildingType(float roll) {
694
695     if (roll < smallBuildingFraction) {
696       return SGBuildingBin::SMALL;
697     }
698
699     if (roll < (smallBuildingFraction + mediumBuildingFraction)) {
700       return SGBuildingBin::MEDIUM;
701     }
702
703     return SGBuildingBin::LARGE;
704   }
705
706   float SGBuildingBin::getBuildingMaxRadius(BuildingType type) {
707
708     if (type == SGBuildingBin::SMALL) return smallBuildingMaxRadius;
709     if (type == SGBuildingBin::MEDIUM) return mediumBuildingMaxRadius;
710     if (type == SGBuildingBin::LARGE) return largeBuildingMaxRadius;
711
712     return 0;
713   }
714
715   float SGBuildingBin::getBuildingMaxDepth(BuildingType type) {
716
717     if (type == SGBuildingBin::SMALL) return smallBuildingMaxDepth;
718     if (type == SGBuildingBin::MEDIUM) return mediumBuildingMaxDepth;
719     if (type == SGBuildingBin::LARGE) return largeBuildingMaxDepth;
720
721     return 0;
722   }
723
724   ref_ptr<Group> SGBuildingBin::createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options)
725   {
726     ref_ptr<Effect> effect;
727     EffectMap::iterator iter = buildingEffectMap.find(*texture);
728
729     if ((iter == buildingEffectMap.end())||
730         (!iter->second.lock(effect)))
731     {
732       SGPropertyNode_ptr effectProp = new SGPropertyNode;
733       makeChild(effectProp, "inherits-from")->setStringValue("Effects/building");
734       SGPropertyNode* params = makeChild(effectProp, "parameters");
735       // Main texture - n=0
736       params->getChild("texture", 0, true)->getChild("image", 0, true)
737           ->setStringValue(*texture);
738
739       // Light map - n=3
740       params->getChild("texture", 3, true)->getChild("image", 0, true)
741           ->setStringValue(*lightMap);
742
743       effect = makeEffect(effectProp, true, options);
744       if (iter == buildingEffectMap.end())
745           buildingEffectMap.insert(EffectMap::value_type(*texture, effect));
746       else
747           iter->second = effect; // update existing, but empty observer
748     }
749
750     ref_ptr<Group> group = new osg::Group();
751
752     // Now, create a quadbuilding for the buildings.
753
754     BuildingInstanceList locs[] = { smallBuildingLocations,
755                                     SGBuildingBin::mediumBuildingLocations,
756                                     SGBuildingBin::largeBuildingLocations };
757
758     for (int i = 0; i < 3; i++)
759     {
760       // Create a quad tree.  Only small and medium buildings are faded out.
761       BuildingGeometryQuadtree
762           quadbuilding(GetBuildingCoord(), AddBuildingLeafObject(),
763                    SG_BUILDING_QUAD_TREE_DEPTH,
764                    MakeBuildingLeaf(buildingRange, effect, (i != 2)));
765
766       // Transform building positions from the "geocentric" positions we
767       // get from the scenery polys into the local Z-up coordinate
768       // system.
769       std::vector<BuildingInstance> rotatedBuildings;
770       rotatedBuildings.reserve(locs[i].size());
771       std::transform(locs[i].begin(), locs[i].end(),
772                      std::back_inserter(rotatedBuildings),
773                      BuildingInstanceTransformer(transInv));
774       quadbuilding.buildQuadTree(rotatedBuildings.begin(), rotatedBuildings.end());
775
776       for (size_t j = 0; j < quadbuilding.getRoot()->getNumChildren(); ++j)
777               group->addChild(quadbuilding.getRoot()->getChild(j));
778     }
779
780     return group;
781   }
782
783   // We may end up with a quadtree with many empty leaves. One might say
784   // that we should avoid constructing the leaves in the first place,
785   // but this node visitor tries to clean up after the fact.
786   struct QuadTreeCleaner : public osg::NodeVisitor
787   {
788       QuadTreeCleaner() : NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN)
789       {
790       }
791       void apply(LOD& lod)
792       {
793           for (int i  = lod.getNumChildren() - 1; i >= 0; --i) {
794               EffectGeode* geode = dynamic_cast<EffectGeode*>(lod.getChild(i));
795               if (!geode)
796                   continue;
797               bool geodeEmpty = true;
798               if (geode->getNumDrawables() > 1) {
799                 SG_LOG(SG_TERRAIN, SG_DEBUG, "Building LOD Drawables: " << geode->getNumDrawables());
800               }
801
802               for (unsigned j = 0; j < geode->getNumDrawables(); ++j) {
803                   const Geometry* geom = dynamic_cast<Geometry*>(geode->getDrawable(j));
804                   if (!geom) {
805                       geodeEmpty = false;
806                       break;
807                   }
808                   for (unsigned k = 0; k < geom->getNumPrimitiveSets(); k++) {
809                       const PrimitiveSet* ps = geom->getPrimitiveSet(k);
810                       if (ps->getNumIndices() > 0) {
811                           geodeEmpty = false;
812                           break;
813                       }
814                   }
815               }
816               if (geodeEmpty)
817                   lod.removeChildren(i, 1);
818           }
819       }
820   };
821
822   // This actually returns a MatrixTransform node. If we rotate the whole
823   // forest into the local Z-up coordinate system we can reuse the
824   // primitive building geometry for all the forests of the same type.
825   osg::Group* createRandomBuildings(SGBuildingBinList& buildings, const osg::Matrix& transform,
826                            const SGReaderWriterOptions* options)
827   {
828       Matrix transInv = Matrix::inverse(transform);
829       static Matrix ident;
830       // Set up some shared structures.
831       MatrixTransform* mt = new MatrixTransform(transform);
832       SGBuildingBinList::iterator i;
833
834       for (i = buildings.begin(); i != buildings.end(); ++i) {
835           SGBuildingBin* bin = *i;
836           ref_ptr<Group> group = bin->createBuildingsGroup(transInv, options);
837
838           for (size_t j = 0; j < group->getNumChildren(); ++j) {
839             mt->addChild(group->getChild(j));
840           }
841
842           delete bin;
843       }
844
845       buildings.clear();
846
847       QuadTreeCleaner cleaner;
848       mt->accept(cleaner);
849       return mt;
850   }
851 }