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