]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/SGBuildingBin.cxx
Use Effects system for random buildings.
[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/sg_random.h>
48 #include <simgear/misc/sg_path.hxx>
49 #include <simgear/scene/material/Effect.hxx>
50 #include <simgear/scene/material/EffectGeode.hxx>
51 #include <simgear/scene/model/model.hxx>
52 #include <simgear/props/props.hxx>
53 #include <simgear/scene/util/QuadTreeBuilder.hxx>
54 #include <simgear/scene/util/RenderConstants.hxx>
55 #include <simgear/scene/util/StateAttributeFactory.hxx>
56 #include <simgear/structure/OSGUtils.hxx>
57
58
59 #include "ShaderGeometry.hxx"
60 #include "SGBuildingBin.hxx"
61
62 #define SG_BUILDING_QUAD_TREE_DEPTH 2
63 #define SG_BUILDING_FADE_OUT_LEVELS 4
64
65 using namespace osg;
66
67 namespace simgear
68 {
69   
70 typedef std::map<std::string, osg::observer_ptr<osg::StateSet> > BuildingStateSetMap;
71 static BuildingStateSetMap statesetmap;
72
73 void addBuildingToLeafGeode(Geode* geode, const SGBuildingBin::Building& building)
74 {
75       // Generate a repeatable random seed
76       mt seed;
77       mt_init(&seed, unsigned(building.position.x()));      
78       
79       // Get or create geometry.
80       osg::ref_ptr<osg::Geometry> geom;
81       osg::Vec3Array* v = new osg::Vec3Array;
82       osg::Vec2Array* t = new osg::Vec2Array;
83       osg::Vec4Array* c = new osg::Vec4Array; // single value
84       osg::Vec3Array* n = new osg::Vec3Array;            
85       
86       if (geode->getNumDrawables() == 0) {
87         geom = new osg::Geometry;        
88         v = new osg::Vec3Array;
89         t = new osg::Vec2Array;
90         c = new osg::Vec4Array;
91         n = new osg::Vec3Array;
92         
93         // Set the color, which is bound overall, and simply white
94         c->push_back( osg::Vec4( 1, 1, 1, 1) );
95         geom->setColorArray(c);
96         geom->setColorBinding(osg::Geometry::BIND_OVERALL);
97
98         geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
99         // Temporary primitive set. Will be over-written later.
100         geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,1));
101         geode->addDrawable(geom);
102       } else {
103         geom = (osg::Geometry*) geode->getDrawable(0);        
104         v = (osg::Vec3Array*) geom->getVertexArray();
105         t = (osg::Vec2Array*) geom->getTexCoordArray(0);
106         c = (osg::Vec4Array*) geom->getColorArray();
107         n = (osg::Vec3Array*) geom->getNormalArray();
108       }
109       
110       // For the moment we'll create a simple box with 5 sides (no need 
111       // for a base).
112       int num_quads = 5;    
113       
114       if (building.pitched) {
115         // If it's a pitched roof, we add another 3 quads (we'll be
116         // removing the flat top).
117         num_quads+=3;        
118       }          
119
120       // Set up the rotation and translation matrix, which we apply to
121       // vertices as they are created as we'll be adding buildings later.
122       osg::Matrix transformMat;
123       transformMat = osg::Matrix::translate(toOsg(building.position));
124       double hdg =  - building.rotation * M_PI * 2;
125       osg::Matrix rotationMat = osg::Matrix::rotate(hdg,
126                                                osg::Vec3d(0.0, 0.0, 1.0));
127       transformMat.preMult(rotationMat);                  
128
129       // Create the vertices
130       float cw = 0.5f * building.width;
131       float cd = building.depth;
132       float ch = building.height;
133       
134       // 0,0,0 is the bottom center of the front
135       // face, e.g. where the front door would be
136       
137       
138       // BASEMENT
139       // This exteds 10m below the main section
140       // Front face        
141       v->push_back( osg::Vec3( 0,  cw, -10) * transformMat ); // bottom right
142       v->push_back( osg::Vec3( 0, -cw, -10) * transformMat ); // bottom left
143       v->push_back( osg::Vec3( 0, -cw,   0) * transformMat ); // top left
144       v->push_back( osg::Vec3( 0,  cw,   0) * transformMat ); // top right
145       
146       for (int i=0; i<4; ++i)
147         n->push_back( osg::Vec3(-1, 0, 0) * rotationMat ); // normal
148       
149       // Left face
150       v->push_back( osg::Vec3(  0, -cw, -10) * transformMat ); // bottom right
151       v->push_back( osg::Vec3( cd, -cw, -10) * transformMat ); // bottom left
152       v->push_back( osg::Vec3( cd, -cw,   0) * transformMat ); // top left
153       v->push_back( osg::Vec3(  0, -cw,   0) * transformMat ); // top right
154
155       for (int i=0; i<4; ++i)
156         n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
157
158       // Back face
159       v->push_back( osg::Vec3( cd, -cw, -10) * transformMat ); // bottom right
160       v->push_back( osg::Vec3( cd,  cw, -10) * transformMat ); // bottom left
161       v->push_back( osg::Vec3( cd,  cw,   0) * transformMat ); // top left
162       v->push_back( osg::Vec3( cd, -cw,   0) * transformMat ); // top right
163       
164       for (int i=0; i<4; ++i)
165         n->push_back( osg::Vec3(1, 0, 0) * rotationMat ); // normal
166       
167       // Right face
168       v->push_back( osg::Vec3( cd, cw, -10) * transformMat ); // bottom right
169       v->push_back( osg::Vec3(  0, cw, -10) * transformMat ); // bottom left
170       v->push_back( osg::Vec3(  0, cw,   0) * transformMat ); // top left
171       v->push_back( osg::Vec3( cd, cw,   0) * transformMat ); // top right
172
173       for (int i=0; i<4; ++i)
174         n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal      
175       
176       // MAIN BODY
177       // Front face        
178       v->push_back( osg::Vec3( 0,  cw,  0) * transformMat ); // bottom right
179       v->push_back( osg::Vec3( 0, -cw,  0) * transformMat ); // bottom left
180       v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // top left
181       v->push_back( osg::Vec3( 0,  cw, ch) * transformMat ); // top right
182       
183       for (int i=0; i<4; ++i)
184         n->push_back( osg::Vec3(-1, 0, 0) * rotationMat ); // normal
185       
186       // Left face
187       v->push_back( osg::Vec3(  0, -cw,  0) * transformMat ); // bottom right
188       v->push_back( osg::Vec3( cd, -cw,  0) * transformMat ); // bottom left
189       v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // top left
190       v->push_back( osg::Vec3(  0, -cw, ch) * transformMat ); // top right
191
192       for (int i=0; i<4; ++i)
193         n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
194
195       // Back face
196       v->push_back( osg::Vec3( cd, -cw,  0) * transformMat ); // bottom right
197       v->push_back( osg::Vec3( cd,  cw,  0) * transformMat ); // bottom left
198       v->push_back( osg::Vec3( cd,  cw, ch) * transformMat ); // top left
199       v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // top right
200       
201       for (int i=0; i<4; ++i)
202         n->push_back( osg::Vec3(1, 0, 0) * rotationMat ); // normal
203       
204       // Right face
205       v->push_back( osg::Vec3( cd, cw,  0) * transformMat ); // bottom right
206       v->push_back( osg::Vec3(  0, cw,  0) * transformMat ); // bottom left
207       v->push_back( osg::Vec3(  0, cw, ch) * transformMat ); // top left
208       v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // top right
209
210       for (int i=0; i<4; ++i)
211         n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
212       
213       // ROOF
214       if (building.pitched) {      
215         
216         // Front pitched roof
217         v->push_back( osg::Vec3(     0,  cw,   ch) * transformMat ); // bottom right
218         v->push_back( osg::Vec3(     0, -cw,   ch) * transformMat ); // bottom left
219         v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top left
220         v->push_back( osg::Vec3(0.5*cd,  cw, ch+3) * transformMat ); // top right
221         
222         for (int i=0; i<4; ++i)
223           n->push_back( osg::Vec3(-0.707, 0, 0.707) * rotationMat ); // normal
224         
225         // Left pitched roof
226         v->push_back( osg::Vec3(     0, -cw,   ch) * transformMat ); // bottom right
227         v->push_back( osg::Vec3(    cd, -cw,   ch) * transformMat ); // bottom left
228         v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top left
229         v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top right
230         
231         for (int i=0; i<4; ++i)
232           n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
233
234         // Back pitched roof
235         v->push_back( osg::Vec3(    cd, -cw,   ch) * transformMat ); // bottom right
236         v->push_back( osg::Vec3(    cd,  cw,   ch) * transformMat ); // bottom left
237         v->push_back( osg::Vec3(0.5*cd,  cw, ch+3) * transformMat ); // top left
238         v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top right
239         
240         for (int i=0; i<4; ++i)
241           n->push_back( osg::Vec3(0.707, 0, 0.707) * rotationMat ); // normal      
242
243         // Right pitched roof
244         v->push_back( osg::Vec3(    cd, cw,   ch) * transformMat ); // bottom right
245         v->push_back( osg::Vec3(     0, cw,   ch) * transformMat ); // bottom left
246         v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top left
247         v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top right
248         
249         for (int i=0; i<4; ++i)
250           n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
251       } else {      
252         // Top face
253         v->push_back( osg::Vec3(  0,  cw, ch) * transformMat ); // bottom right
254         v->push_back( osg::Vec3(  0, -cw, ch) * transformMat ); // bottom left
255         v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // top left
256         v->push_back( osg::Vec3( cd,  cw, ch) * transformMat ); // top right
257         
258         for (int i=0; i<4; ++i)
259           n->push_back( osg::Vec3( 0, 0, 1) * rotationMat ); // normal
260       }
261       
262       // The 1024x1024 texture is split into 32x16 blocks.
263       // For a small building, each block is 6m wide and 3m high.
264       // For a medium building, each block is 10m wide and 3m high.
265       // For a large building, each block is 20m wide and 3m high
266       
267       if (building.type == SGBuildingBin::SMALL) {
268         // Small buildings are represented on the bottom 5 rows of 3 floors
269         int row = ((int) (mt_rand(&seed) * 1000)) % 5;
270         float base_y = (float) row * 16.0 * 3.0 / 1024.0;
271         float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
272         float left_x = 0.0f;
273         float right_x = 32.0 / 1024.0 * round((float) building.width / 6.0f);
274         float front_x = 384.0/1024.0;
275         float back_x = 384.0/1024.0 + 32.0 / 1024.0 * round((float) building.depth/ 6.0f);
276
277         // BASEMENT - uses the baseline texture
278         for (unsigned int i = 0; i < 16; i++) {          
279           t->push_back( osg::Vec2( left_x, base_y) ); 
280         }
281         // MAIN BODY
282         // Front
283         t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
284         t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
285         t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
286         t->push_back( osg::Vec2( right_x, top_y ) ); // top right
287         
288         // Left
289         t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
290         t->push_back( osg::Vec2( back_x,  base_y) ); // bottom left
291         t->push_back( osg::Vec2( back_x,  top_y ) ); // top left
292         t->push_back( osg::Vec2( front_x, top_y ) ); // top right
293         
294         // Back (same as front for the moment)
295         t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
296         t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
297         t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
298         t->push_back( osg::Vec2( right_x, top_y ) ); // top right
299         
300         // Right (same as left for the moment)
301         t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
302         t->push_back( osg::Vec2( back_x,  base_y) ); // bottom left
303         t->push_back( osg::Vec2( back_x,  top_y ) ); // top left
304         t->push_back( osg::Vec2( front_x, top_y ) ); // top right
305
306         // ROOF
307         if (building.pitched) { 
308           // Use the entire height of the roof texture
309           top_y = base_y + 16.0 * 3.0 / 1024.0;     
310           left_x = 512/1024.0;
311           right_x = 512/1024.0 + 32.0 / 1024.0 * round(building.width / 6.0f);
312           front_x = 480.0/1024.0;
313           back_x = 512.0/1024.0;
314           
315           // Front
316           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
317           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
318           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
319           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
320           
321           // Left
322           t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
323           t->push_back( osg::Vec2( back_x,  base_y) ); // bottom left
324           t->push_back( osg::Vec2( back_x,  top_y ) ); // top left
325           t->push_back( osg::Vec2( front_x, top_y ) ); // top right
326           
327           // Back (same as front for the moment)
328           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
329           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
330           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
331           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
332           
333           // Right (same as left for the moment)
334           t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
335           t->push_back( osg::Vec2( back_x,  base_y) ); // bottom left
336           t->push_back( osg::Vec2( back_x,  top_y ) ); // top left
337           t->push_back( osg::Vec2( front_x, top_y ) ); // top right
338         } else {
339           // Flat roof
340           left_x = 512.0/1024.0;
341           right_x = 640.0/1024.0;
342           // Use the entire height of the roof texture
343           top_y = base_y + 16.0 * 3.0 / 1024.0;    
344           
345           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
346           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
347           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
348           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
349         }
350         
351       }
352       
353       if (building.type == SGBuildingBin::MEDIUM) 
354       {
355         int column = ((int) (mt_rand(&seed) * 1000)) % 5;        
356         float base_y = 288 / 1024.0;
357         float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
358         float left_x = column * 192.0 /1024.0;
359         float right_x = left_x + 32.0 / 1024.0 * round((float) building.width / 10.0f);
360
361         // BASEMENT - uses the baseline texture
362         for (unsigned int i = 0; i < 16; i++) {          
363           t->push_back( osg::Vec2( left_x, base_y) ); 
364         }      
365
366         // MAIN BODY
367         // Front
368         t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
369         t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
370         t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
371         t->push_back( osg::Vec2( right_x, top_y ) ); // top right
372         
373         // Left
374         t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
375         t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
376         t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
377         t->push_back( osg::Vec2( right_x, top_y ) ); // top right
378         
379         // Back (same as front for the moment)
380         t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
381         t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
382         t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
383         t->push_back( osg::Vec2( right_x, top_y ) ); // top right
384         
385         // Right (same as left for the moment)
386         t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
387         t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
388         t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
389         t->push_back( osg::Vec2( right_x, top_y ) ); // top right
390
391         // ROOF
392         if (building.pitched) {      
393           base_y = 288.0/1024.0;
394           top_y = 576.0/1024.0;
395           left_x = 960.0/1024.0;
396           right_x = 1.0;
397           // Front
398           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
399           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
400           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
401           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
402           
403           // Left
404           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
405           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
406           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
407           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
408             
409           // Back (same as front for the moment)
410           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
411           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
412           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
413           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
414           
415           // Right (same as left for the moment)
416           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
417           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
418           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
419           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
420         } else {
421           // Flat roof
422           base_y = 416/1024.0;
423           top_y = 576.0/1024.0;
424           right_x = left_x + 32.0 / 1024.0 * 6.0;
425           
426           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
427           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
428           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
429           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
430         }
431       }
432
433       if (building.type == SGBuildingBin::LARGE)
434       {
435         int column = ((int) (mt_rand(&seed) * 1000)) % 8;        
436         float base_y = 576 / 1024.0;
437         float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
438         float left_x = column * 128.0 /1024.0;
439         float right_x = left_x + 32.0 / 1024.0 * round((float) building.width / 20.0f);
440
441         // BASEMENT - uses the baseline texture
442         for (unsigned int i = 0; i < 16; i++) {          
443           t->push_back( osg::Vec2( left_x, base_y) ); 
444         }      
445
446         // MAIN BODY
447         // Front
448         t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
449         t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
450         t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
451         t->push_back( osg::Vec2( right_x, top_y ) ); // top right
452         
453         // Left
454         t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
455         t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
456         t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
457         t->push_back( osg::Vec2( right_x, top_y ) ); // top right
458         
459         // Back (same as front for the moment)
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         // Right (same as left for the moment)
466         t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
467         t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
468         t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
469         t->push_back( osg::Vec2( right_x, top_y ) ); // top right
470
471         // ROOF
472         if (building.pitched) {      
473           base_y = 896/1024.0;
474           top_y = 1.0;
475           // Front
476           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
477           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
478           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
479           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
480           
481           // Left
482           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
483           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
484           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
485           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
486             
487           // Back (same as front for the moment)
488           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
489           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
490           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
491           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
492           
493           // Right (same as left for the moment)
494           t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
495           t->push_back( osg::Vec2( left_x,  base_y) ); // bottom left
496           t->push_back( osg::Vec2( left_x,  top_y ) ); // top left
497           t->push_back( osg::Vec2( right_x, top_y ) ); // top right
498         } else {
499           // Flat roof
500           base_y = 896/1024.0;
501           top_y = 1.0;
502           
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
509       }
510
511       // Set the vertex, texture and normals back.
512       geom->setVertexArray(v);
513       geom->setTexCoordArray(0, t);
514       geom->setNormalArray(n);
515       
516       geom->setPrimitiveSet(0, new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,v->size()));
517       geode->setDrawable(0, geom);      
518 }
519
520 typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
521
522 static EffectMap buildingEffectMap;
523
524 // Helper classes for creating the quad tree
525 namespace
526 {
527 struct MakeBuildingLeaf
528 {
529     MakeBuildingLeaf(float range, Effect* effect) :
530         _range(range), _effect(effect) {}
531     
532     MakeBuildingLeaf(const MakeBuildingLeaf& rhs) :
533         _range(rhs._range), _effect(rhs._effect)
534     {}
535
536     LOD* operator() () const
537     {
538         LOD* result = new LOD;
539         
540         // Create a series of LOD nodes so trees cover decreases slightly
541         // gradually with distance from _range to 2*_range
542         for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++)
543         {   
544             EffectGeode* geode = new EffectGeode;
545             geode->setEffect(_effect.get());
546             result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0)));               
547         }
548         return result;
549     }
550     
551     float _range;
552     ref_ptr<Effect> _effect;
553 };
554
555 struct AddBuildingLeafObject
556 {
557     void operator() (LOD* lod, const SGBuildingBin::Building& building) const
558     {
559         Geode* geode = static_cast<Geode*>(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren()));
560         addBuildingToLeafGeode(geode, building);
561     }
562 };
563
564 struct GetBuildingCoord
565 {
566     Vec3 operator() (const SGBuildingBin::Building& building) const
567     {
568         return toOsg(building.position);
569     }
570 };
571
572 typedef QuadTreeBuilder<LOD*, SGBuildingBin::Building, MakeBuildingLeaf, AddBuildingLeafObject,
573                         GetBuildingCoord> BuildingGeometryQuadtree;
574 }
575
576 struct BuildingTransformer
577 {
578     BuildingTransformer(Matrix& mat_) : mat(mat_) {}
579     SGBuildingBin::Building operator()(const SGBuildingBin::Building& building) const
580     {
581         Vec3 pos = toOsg(building.position);
582         return SGBuildingBin::Building(toSG(pos * mat), building);
583     }
584     Matrix mat;
585 };
586
587
588
589 // This actually returns a MatrixTransform node. If we rotate the whole
590 // forest into the local Z-up coordinate system we can reuse the
591 // primitive building geometry for all the forests of the same type.
592 osg::Group* createRandomBuildings(SGBuildingBinList buildings, const osg::Matrix& transform,
593                          const SGReaderWriterOptions* options)
594 {
595     Matrix transInv = Matrix::inverse(transform);
596     static Matrix ident;
597     // Set up some shared structures.
598     MatrixTransform* mt = new MatrixTransform(transform);
599
600     SGBuildingBin* bin = NULL;
601       
602     BOOST_FOREACH(bin, buildings)
603     {      
604       
605         ref_ptr<Effect> effect;
606         EffectMap::iterator iter = buildingEffectMap.find(bin->texture);
607
608         if ((iter == buildingEffectMap.end())||
609             (!iter->second.lock(effect)))
610         {
611             SGPropertyNode_ptr effectProp = new SGPropertyNode;
612             makeChild(effectProp, "inherits-from")->setStringValue("Effects/building");
613             SGPropertyNode* params = makeChild(effectProp, "parameters");
614             // emphasize n = 0
615             params->getChild("texture", 0, true)->getChild("image", 0, true)
616                 ->setStringValue(bin->texture);
617             effect = makeEffect(effectProp, true, options);
618             if (iter == buildingEffectMap.end())
619                 buildingEffectMap.insert(EffectMap::value_type(bin->texture, effect));
620             else
621                 iter->second = effect; // update existing, but empty observer
622         }
623       
624         // Now, create a quadbuilding for the buildings.            
625         BuildingGeometryQuadtree
626             quadbuilding(GetBuildingCoord(), AddBuildingLeafObject(),
627                      SG_BUILDING_QUAD_TREE_DEPTH,
628                      MakeBuildingLeaf(20000.0f, effect)); // FIXME - tie to property
629                      
630         // Transform building positions from the "geocentric" positions we
631         // get from the scenery polys into the local Z-up coordinate
632         // system.
633         std::vector<SGBuildingBin::Building> rotatedBuildings;
634         rotatedBuildings.reserve(bin->buildings.size());
635         std::transform(bin->buildings.begin(), bin->buildings.end(),
636                        std::back_inserter(rotatedBuildings),
637                        BuildingTransformer(transInv));
638         quadbuilding.buildQuadTree(rotatedBuildings.begin(), rotatedBuildings.end());
639         
640         ref_ptr<Group> group = quadbuilding.getRoot();
641         
642         /*
643         // Set up the stateset for this building bin and the texture to use.
644         osg::StateSet* stateSet = group->getOrCreateStateSet();
645         const std::string texturename = bin->texture;
646         osg::Texture2D* texture = SGLoadTexture2D(texturename);
647         texture->setWrap(osg::Texture2D::WRAP_S,  osg::Texture2D::CLAMP_TO_EDGE);
648         texture->setWrap(osg::Texture2D::WRAP_T,  osg::Texture2D::CLAMP_TO_EDGE);
649         stateSet->setTextureAttributeAndModes(0, texture);
650                 
651         osg::ShadeModel* shadeModel = new osg::ShadeModel;
652         shadeModel->setMode(osg::ShadeModel::FLAT);
653         stateSet->setAttributeAndModes(shadeModel);
654         stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
655         stateSet->setMode(GL_FOG, osg::StateAttribute::ON);
656         stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
657         stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
658         stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
659         stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
660         stateSet->setAttribute(new osg::CullFace(osg::CullFace::BACK));
661
662         osg::Material* material = new osg::Material;
663         material->setAmbient(osg::Material::FRONT, osg::Vec4(0.3,0.3,0.3,1.0));
664         material->setDiffuse(osg::Material::FRONT, osg::Vec4(1.0,1.0,1.0,1.0));
665         material->setSpecular(osg::Material::FRONT, osg::Vec4(0,0,0,1.0));
666         material->setShininess(osg::Material::FRONT, 0.0);
667         material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
668         stateSet->setAttribute(material);
669         */
670         mt->addChild(group);        
671     }
672     
673     return mt;
674 }
675
676 }