]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/SGBuildingBin.cxx
spt: Introduce a third layer of paged nodes.
[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 static int numBuildings;
68
69 typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
70 static EffectMap buildingEffectMap;
71     
72 // Building instance scheme:
73 // vertex - local position of vertices, with 0,0,0 being the center front.
74 // fog coord - rotation
75 // color - xyz of tree quad origin, replicated 4 times.
76
77 struct BuildingBoundingBoxCallback : public Drawable::ComputeBoundingBoxCallback
78 {
79     BuildingBoundingBoxCallback() {}
80     BuildingBoundingBoxCallback(const BuildingBoundingBoxCallback&, const CopyOp&) {}
81     META_Object(simgear, BuildingBoundingBoxCallback);
82     virtual BoundingBox computeBound(const Drawable&) const;
83 };
84
85 BoundingBox
86 BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
87 {
88     BoundingBox bb;
89     const Geometry* geom = static_cast<const Geometry*>(&drawable);
90     const Vec3Array* v = static_cast<const Vec3Array*>(geom->getVertexArray());
91     const Vec4Array* pos = static_cast<const Vec4Array*>(geom->getColorArray());
92     
93     Geometry::PrimitiveSetList primSets = geom->getPrimitiveSetList();
94     for (Geometry::PrimitiveSetList::const_iterator psitr = primSets.begin(), psend = primSets.end();
95          psitr != psend;
96          ++psitr) {
97         DrawArrays* da = static_cast<DrawArrays*>(psitr->get());
98         GLint psFirst = da->getFirst();
99         GLint psEndVert = psFirst + da->getCount();
100         for (GLint i = psFirst;i < psEndVert; ++i) {
101             Vec3 pt = (*v)[i];
102             Matrixd trnsfrm = Matrixd::rotate(- M_PI * 2 * (*pos)[i].a(), Vec3(0.0f, 0.0f, 1.0f));
103             pt = pt * trnsfrm;
104             pt += Vec3((*pos)[i].x(), (*pos)[i].y(), (*pos)[i].z());
105             bb.expandBy(pt);
106         }
107     }
108     return bb;    
109 }
110
111   // Set up the building set based on the material definitions
112   SGBuildingBin::SGBuildingBin(const SGMaterial *mat) {
113     
114     material_name = mat->get_names()[0];
115     SG_LOG(SG_TERRAIN, SG_DEBUG, "Building material " << material_name);
116     texture = mat->get_building_texture();
117     lightMap = mat->get_building_lightmap();
118     SG_LOG(SG_TERRAIN, SG_DEBUG, "Building texture " << texture);
119     
120     // Generate a random seed for the building generation.
121     mt seed;
122     mt_init(&seed, unsigned(123));
123     
124     smallSharedGeometry = new osg::Geometry();
125     mediumSharedGeometry = new osg::Geometry();
126     largeSharedGeometry = new osg::Geometry();
127     
128     smallBuildingMaxRadius = std::max(mat->get_building_small_max_depth() * 0.5, mat->get_building_small_max_width() * 0.5);
129     mediumBuildingMaxRadius = std::max(mat->get_building_medium_max_depth() * 0.5, mat->get_building_medium_max_width() * 0.5);
130     largeBuildingMaxRadius = std::max(mat->get_building_large_max_depth() * 0.5, mat->get_building_large_max_width() * 0.5);
131     
132     smallBuildingMaxDepth = mat->get_building_small_max_depth();
133     mediumBuildingMaxDepth = mat->get_building_medium_max_depth();
134     largeBuildingMaxDepth = mat->get_building_large_max_depth();    
135     
136     smallBuildingFraction = mat->get_building_small_fraction();
137     mediumBuildingFraction = mat->get_building_medium_fraction();
138     
139     SG_LOG(SG_TERRAIN, SG_DEBUG, "Building fractions " << smallBuildingFraction << " " << mediumBuildingFraction);
140     
141     
142     // TODO: Reverse this - otherwise we never get any large buildings!
143     BuildingType types[] = { SGBuildingBin::SMALL, SGBuildingBin::MEDIUM, SGBuildingBin::LARGE };    
144     BuildingList lists[] = { SGBuildingBin::smallBuildings, SGBuildingBin::mediumBuildings, SGBuildingBin::largeBuildings };
145     ref_ptr<Geometry> geometries[] = { smallSharedGeometry, mediumSharedGeometry, largeSharedGeometry };
146     
147     for (int bt=0; bt < 3; bt++) {
148       SGBuildingBin::BuildingType buildingtype = types[bt];
149       ref_ptr<Geometry> sharedGeometry = geometries[bt];
150       BuildingList buildings = lists[bt];
151         
152       osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
153       osg::ref_ptr<osg::Vec2Array> t = new osg::Vec2Array;
154       osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
155       
156       v->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING);
157       t->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING);
158       n->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING);
159       
160       sharedGeometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
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   }
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       BuildingGeometryQuadtree
757           quadbuilding(GetBuildingCoord(), AddBuildingLeafObject(),
758                    SG_BUILDING_QUAD_TREE_DEPTH,
759                    MakeBuildingLeaf(20000.0, effect));
760                    
761       // Transform building positions from the "geocentric" positions we
762       // get from the scenery polys into the local Z-up coordinate
763       // system.
764       std::vector<BuildingInstance> rotatedBuildings;
765       rotatedBuildings.reserve(locs[i].size());
766       std::transform(locs[i].begin(), locs[i].end(),
767                      std::back_inserter(rotatedBuildings),
768                      BuildingInstanceTransformer(transInv));
769       quadbuilding.buildQuadTree(rotatedBuildings.begin(), rotatedBuildings.end());
770
771       for (size_t i = 0; i < quadbuilding.getRoot()->getNumChildren(); ++i)
772               group->addChild(quadbuilding.getRoot()->getChild(i));
773     }
774       
775     return group;
776   }
777     
778   // We may end up with a quadtree with many empty leaves. One might say
779   // that we should avoid constructing the leaves in the first place,
780   // but this node visitor tries to clean up after the fact.
781   struct QuadTreeCleaner : public osg::NodeVisitor
782   {      
783       QuadTreeCleaner() : NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN)
784       {
785       }
786       void apply(LOD& lod)
787       {
788           for (int i  = lod.getNumChildren() - 1; i >= 0; --i) {
789               EffectGeode* geode = dynamic_cast<EffectGeode*>(lod.getChild(i));
790               if (!geode)
791                   continue;
792               bool geodeEmpty = true;
793               if (geode->getNumDrawables() > 1) {
794                 SG_LOG(SG_TERRAIN, SG_DEBUG, "Building LOD Drawables: " << geode->getNumDrawables());
795               }
796
797               for (unsigned j = 0; j < geode->getNumDrawables(); ++j) {
798                   const Geometry* geom = dynamic_cast<Geometry*>(geode->getDrawable(j));
799                   if (!geom) {
800                       geodeEmpty = false;
801                       break;
802                   }
803                   for (unsigned k = 0; k < geom->getNumPrimitiveSets(); k++) {
804                       const PrimitiveSet* ps = geom->getPrimitiveSet(k);
805                       if (ps->getNumIndices() > 0) {
806                           geodeEmpty = false;
807                           break;
808                       }
809                   }
810               }
811               if (geodeEmpty)
812                   lod.removeChildren(i, 1);
813           }
814       }
815   };
816     
817   // This actually returns a MatrixTransform node. If we rotate the whole
818   // forest into the local Z-up coordinate system we can reuse the
819   // primitive building geometry for all the forests of the same type.
820   osg::Group* createRandomBuildings(SGBuildingBinList buildings, const osg::Matrix& transform,
821                            const SGReaderWriterOptions* options)
822   {
823       Matrix transInv = Matrix::inverse(transform);
824       static Matrix ident;
825       // Set up some shared structures.
826       MatrixTransform* mt = new MatrixTransform(transform);
827
828       SGBuildingBin* bin = NULL;
829         
830       BOOST_FOREACH(bin, buildings)
831       {      
832           numBuildings = numBuildings + bin->getNumBuildings();
833           ref_ptr<Group> group = bin->createBuildingsGroup(transInv, options);
834           
835           for (size_t i = 0; i < group->getNumChildren(); ++i)
836             mt->addChild(group->getChild(i));
837             
838           delete bin;  
839       }        
840       
841       buildings.clear();
842       QuadTreeCleaner cleaner;
843       mt->accept(cleaner);
844       return mt;
845   }
846 }