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