]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/SGBuildingBin.cxx
Work around apparent OSG 3.2.0 normal binding bug.
[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);
639       sharedGeometry->setNormalArray(n);
640
641       // Work around a bug in OSG 3.2.0 where BIND_PER_VERTEX appears
642       // not to take effect if the normal array is set subsequently.
643       sharedGeometry->setNormalBinding(osg::Geometry::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 }