]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/SGBuildingBin.hxx
pt_lights: 9 seconds+ break for the ODALS flash sequence is a bit too much. Set it...
[simgear.git] / simgear / scene / tgdb / SGBuildingBin.hxx
1 /* -*-c++-*-
2  *
3  * Copyright (C) 2011 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 #ifndef SG_BUILDING_BIN_HXX
23 #define SG_BUILDING_BIN_HXX
24
25 #include <math.h>
26
27 #include <vector>
28 #include <string>
29
30 #include <osg/Geode>
31 #include <osg/Geometry>
32 #include <osg/Math>
33 #include <osg/MatrixTransform>
34 #include <osg/Matrix>
35 #include <osg/ShadeModel>
36 #include <osg/Material>
37 #include <osg/CullFace>
38
39
40 #include <simgear/scene/util/OsgMath.hxx>
41 #include <simgear/scene/material/mat.hxx>
42
43 #include <simgear/scene/util/QuadTreeBuilder.hxx>
44 #include <simgear/scene/util/RenderConstants.hxx>
45 #include <simgear/scene/util/StateAttributeFactory.hxx>
46 #include <simgear/structure/OSGUtils.hxx>
47
48 #define SG_BUILDING_QUAD_TREE_DEPTH 2
49 #define SG_BUILDING_FADE_OUT_LEVELS 4
50
51 using namespace osg;
52
53 namespace simgear
54 {
55 class SGBuildingBin {
56 public:
57
58   // Number of buildings to auto-generate. Individual
59   // building instances are taken from this set.  
60   static const unsigned int BUILDING_SET_SIZE = 200;
61   
62   static const unsigned int QUADS_PER_BUILDING = 12;
63   static const unsigned int VERTICES_PER_BUILDING = 4 * QUADS_PER_BUILDING;
64   static const unsigned int VERTICES_PER_BUILDING_SET = BUILDING_SET_SIZE * VERTICES_PER_BUILDING;
65
66   enum BuildingType {
67     SMALL = 0,
68     MEDIUM,
69     LARGE };      
70     
71 private:
72
73   struct Building {
74     Building(BuildingType t, float w, float d, float h, int f, bool pitch) :
75       type(t), 
76       width(w), 
77       depth(d), 
78       height(h), 
79       floors(f),
80       pitched(pitch), 
81       radius(std::max(d, 0.5f*w))
82     { }
83     
84     BuildingType type;
85     float width;
86     float depth;
87     float height;
88     int floors;
89     bool pitched;
90     float radius;
91     
92     float getFootprint() {
93       return radius;
94     }
95   };
96   
97   // The set of buildings that are instantiated
98   typedef std::vector<Building> BuildingList;
99   BuildingList smallBuildings;
100   BuildingList mediumBuildings;
101   BuildingList largeBuildings;
102   
103   std::string material_name;
104   std::string texture;
105   std::string lightMap;
106   
107   // Fraction of buildings of this type
108   float smallBuildingFraction;
109   float mediumBuildingFraction;
110
111   // The maximum radius of each building type
112   float smallBuildingMaxRadius;
113   float mediumBuildingMaxRadius;
114   float largeBuildingMaxRadius;
115   
116   // The maximum depth of each building type
117   float smallBuildingMaxDepth;
118   float mediumBuildingMaxDepth;
119   float largeBuildingMaxDepth;
120   
121   // Shared geometries of the building set
122   ref_ptr<Geometry> smallSharedGeometry;
123   ref_ptr<Geometry> mediumSharedGeometry;
124   ref_ptr<Geometry> largeSharedGeometry;
125     
126   struct BuildingInstance {
127     BuildingInstance(SGVec3f p, float r, const BuildingList* bl, ref_ptr<Geometry> sg) :
128       position(p),
129       rotation(r),
130       buildingList(bl),
131       sharedGeometry(sg)
132     { }
133     
134     BuildingInstance(SGVec3f p, BuildingInstance b) :
135       position(p),
136       rotation(b.rotation),
137       buildingList(b.buildingList),
138       sharedGeometry(b.sharedGeometry)
139     { }    
140     
141     SGVec3f position;
142     float rotation;
143     
144     // References to allow the QuadTreeBuilder to work
145     const BuildingList* buildingList;
146     ref_ptr<Geometry> sharedGeometry;    
147     
148     SGVec3f getPosition() { return position; }
149     float getRotation() { return rotation; }
150     
151     float getDistSqr(SGVec3f p) {
152       return distSqr(p, position);      
153     }
154
155     const osg::Vec4f getColorValue() {
156       return osg::Vec4f(toOsg(position), rotation);
157     }
158   };
159
160   // Information for an instance of a building - position and orientation
161   typedef std::vector<BuildingInstance> BuildingInstanceList; 
162   BuildingInstanceList smallBuildingLocations;
163   BuildingInstanceList mediumBuildingLocations;
164   BuildingInstanceList largeBuildingLocations;
165   
166 public:   
167
168   SGBuildingBin(const SGMaterial *mat);
169   
170   ~SGBuildingBin() {
171     smallBuildings.clear();    
172     mediumBuildings.clear();
173     largeBuildings.clear();
174     smallBuildingLocations.clear();
175     mediumBuildingLocations.clear();
176     largeBuildingLocations.clear();
177   }
178   
179   void insert(SGVec3f p, float r, BuildingType type);
180   int getNumBuildings();
181   
182   bool checkMinDist (SGVec3f p, float radius);
183   
184   std::string getMaterialName() { return material_name; }
185   
186   BuildingType getBuildingType(float roll);
187   
188   float getBuildingMaxRadius(BuildingType);
189   float getBuildingMaxDepth(BuildingType);
190   
191   // Helper classes for creating the quad tree
192   struct MakeBuildingLeaf
193   {
194       MakeBuildingLeaf(float range, Effect* effect) :
195           _range(range), _effect(effect) {}
196       
197       MakeBuildingLeaf(const MakeBuildingLeaf& rhs) :
198           _range(rhs._range), _effect(rhs._effect)
199       {}
200
201       LOD* operator() () const
202       {
203           LOD* result = new LOD;
204           
205           // Create a series of LOD nodes so trees cover decreases slightly
206           // gradually with distance from _range to 2*_range
207           for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++)
208           {   
209               EffectGeode* geode = new EffectGeode;
210               geode->setEffect(_effect.get());
211               result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0)));               
212           }
213           return result;
214       }
215       
216       float _range;
217       ref_ptr<Effect> _effect;
218   };
219   
220   struct AddBuildingLeafObject
221   {
222       Geometry* createNewBuildingGeometryInstance(const BuildingInstance& building) const
223       {
224         Geometry* geom = simgear::clone(building.sharedGeometry.get(), CopyOp::SHALLOW_COPY);
225         geom->setColorArray(new Vec4Array);
226         geom->setColorBinding(Geometry::BIND_PER_VERTEX);
227         geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS));
228         return geom;
229       }      
230     
231       void operator() (LOD* lod, const BuildingInstance& building) const
232       {
233           Geode* geode = static_cast<Geode*>(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren()));
234           unsigned int numDrawables = geode->getNumDrawables();          
235           
236           // Get the last geometry of to be added and check if there is space for
237           // another building instance within it.  This is done by checking
238           // if the number of Color values matches the number of vertices.
239           // The color array is used to store the position of a particular
240           // instance.
241           Geometry* geom;
242           
243           if (numDrawables == 0) {
244             // Create a new copy of the shared geometry to instantiate
245             geom = createNewBuildingGeometryInstance(building);
246             geode->addDrawable(geom);
247           } else {
248             geom = static_cast<Geometry*>(geode->getDrawable(numDrawables - 1));      
249           }
250           
251           // Check if this building is too close to any other others.
252           DrawArrays* primSet  = static_cast<DrawArrays*>(geom->getPrimitiveSet(0));
253           Vec4Array* posArray = static_cast<Vec4Array*>(geom->getColorArray());
254           
255           // Now check if this geometry is full.
256           if (posArray->size() >= static_cast<Vec3Array*>(geom->getVertexArray())->size()) {
257             // This particular geometry is full, so we generate another
258             // by taking a shallow copy of the shared Geomety.
259             geom = createNewBuildingGeometryInstance(building);
260             geode->addDrawable(geom);
261             posArray = static_cast<Vec4Array*>(geom->getColorArray());
262             SG_LOG(SG_TERRAIN, SG_DEBUG, "Added new geometry to building geod: " << geode->getNumDrawables());
263           }
264           
265           // We now have a geometry with space for this new building.
266           // Set the position and rotation
267           osg::Vec4f c = osg::Vec4f(toOsg(building.position), building.rotation);
268           posArray->insert(posArray->end(), VERTICES_PER_BUILDING, c);
269           size_t numVerts = posArray->size();
270           primSet = static_cast<DrawArrays*>(geom->getPrimitiveSet(0));
271           primSet->setCount(numVerts);
272       }
273   };
274
275   struct GetBuildingCoord
276   {
277       Vec3 operator() (const BuildingInstance& building) const
278       {
279           return toOsg(building.position);
280       }
281   };
282
283   typedef QuadTreeBuilder<LOD*, BuildingInstance, MakeBuildingLeaf, AddBuildingLeafObject,
284                           GetBuildingCoord> BuildingGeometryQuadtree;
285                           
286   struct BuildingInstanceTransformer
287   {
288       BuildingInstanceTransformer(Matrix& mat_) : mat(mat_) {}
289       BuildingInstance operator()(const BuildingInstance& buildingInstance) const
290       {
291           Vec3 pos = toOsg(buildingInstance.position) * mat;
292           return BuildingInstance(toSG(pos), buildingInstance);
293       }
294       Matrix mat;
295   };
296   
297   ref_ptr<Group> createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options);  
298
299 };
300
301 // List of buildings
302 typedef std::list<SGBuildingBin*> SGBuildingBinList;
303
304
305 osg::Group* createRandomBuildings(SGBuildingBinList buildinglist, const osg::Matrix& transform,
306                          const SGReaderWriterOptions* options);
307 }
308 #endif