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