]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/SGBuildingBin.hxx
Fixed a crash: the singleton needs to be instantiated the first time SGCommandMgr...
[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 4
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   // Visibility range for buildings
122   float buildingRange;
123   
124   // Shared geometries of the building set
125   ref_ptr<Geometry> smallSharedGeometry;
126   ref_ptr<Geometry> mediumSharedGeometry;
127   ref_ptr<Geometry> largeSharedGeometry;
128     
129   struct BuildingInstance {
130     BuildingInstance(SGVec3f p, float r, const BuildingList* bl, ref_ptr<Geometry> sg) :
131       position(p),
132       rotation(r),
133       buildingList(bl),
134       sharedGeometry(sg)
135     { }
136     
137     BuildingInstance(SGVec3f p, BuildingInstance b) :
138       position(p),
139       rotation(b.rotation),
140       buildingList(b.buildingList),
141       sharedGeometry(b.sharedGeometry)
142     { }    
143     
144     SGVec3f position;
145     float rotation;
146     
147     // References to allow the QuadTreeBuilder to work
148     const BuildingList* buildingList;
149     ref_ptr<Geometry> sharedGeometry;    
150     
151     SGVec3f getPosition() { return position; }
152     float getRotation() { return rotation; }
153     
154     float getDistSqr(SGVec3f p) {
155       return distSqr(p, position);      
156     }
157
158     const osg::Vec4f getColorValue() {
159       return osg::Vec4f(toOsg(position), rotation);
160     }
161   };
162
163   // Information for an instance of a building - position and orientation
164   typedef std::vector<BuildingInstance> BuildingInstanceList; 
165   BuildingInstanceList smallBuildingLocations;
166   BuildingInstanceList mediumBuildingLocations;
167   BuildingInstanceList largeBuildingLocations;
168   
169 public:   
170
171   SGBuildingBin(const SGMaterial *mat);
172   
173   ~SGBuildingBin() {
174     smallBuildings.clear();    
175     mediumBuildings.clear();
176     largeBuildings.clear();
177     smallBuildingLocations.clear();
178     mediumBuildingLocations.clear();
179     largeBuildingLocations.clear();
180   }
181   
182   void insert(SGVec3f p, float r, BuildingType type);
183   int getNumBuildings();
184   
185   bool checkMinDist (SGVec3f p, float radius);
186   
187   std::string getMaterialName() { return material_name; }
188   
189   BuildingType getBuildingType(float roll);
190   
191   float getBuildingMaxRadius(BuildingType);
192   float getBuildingMaxDepth(BuildingType);
193   
194   // Helper classes for creating the quad tree
195   struct MakeBuildingLeaf
196   {
197       MakeBuildingLeaf(float range, Effect* effect, bool fade) :
198           _range(range), _effect(effect), _fade_out(fade) {}
199       
200       MakeBuildingLeaf(const MakeBuildingLeaf& rhs) :
201           _range(rhs._range), _effect(rhs._effect), _fade_out(rhs._fade_out)
202       {}
203
204       LOD* operator() () const
205       {
206           LOD* result = new LOD;
207           
208           if (_fade_out) {            
209               // Create a series of LOD nodes so buidling cover decreases
210               // gradually with distance from _range to 2*_range
211               for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++)
212               {   
213                   EffectGeode* geode = new EffectGeode;
214                   geode->setEffect(_effect.get());
215                   result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0)));               
216               }
217           } else {
218               // No fade-out, so all are visible for 2X range
219               EffectGeode* geode = new EffectGeode;
220               geode->setEffect(_effect.get());
221               result->addChild(geode, 0, 2.0 * _range);               
222           }
223           return result;
224       }
225       
226       float _range;
227       ref_ptr<Effect> _effect;
228       bool _fade_out;
229   };
230   
231   struct AddBuildingLeafObject
232   {
233       Geometry* createNewBuildingGeometryInstance(const BuildingInstance& building) const
234       {
235         Geometry* geom = simgear::clone(building.sharedGeometry.get(), CopyOp::SHALLOW_COPY);
236         geom->setColorArray(new Vec4Array);
237         geom->setColorBinding(Geometry::BIND_PER_VERTEX);
238         geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS));
239         return geom;
240       }      
241     
242       void operator() (LOD* lod, const BuildingInstance& building) const
243       {
244           Geode* geode = static_cast<Geode*>(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren()));
245           unsigned int numDrawables = geode->getNumDrawables();          
246           
247           // Get the last geometry of to be added and check if there is space for
248           // another building instance within it.  This is done by checking
249           // if the number of Color values matches the number of vertices.
250           // The color array is used to store the position of a particular
251           // instance.
252           Geometry* geom;
253           
254           if (numDrawables == 0) {
255             // Create a new copy of the shared geometry to instantiate
256             geom = createNewBuildingGeometryInstance(building);
257             geode->addDrawable(geom);
258           } else {
259             geom = static_cast<Geometry*>(geode->getDrawable(numDrawables - 1));      
260           }
261           
262           // Check if this building is too close to any other others.
263           DrawArrays* primSet  = static_cast<DrawArrays*>(geom->getPrimitiveSet(0));
264           Vec4Array* posArray = static_cast<Vec4Array*>(geom->getColorArray());
265           
266           // Now check if this geometry is full.
267           if (posArray->size() >= static_cast<Vec3Array*>(geom->getVertexArray())->size()) {
268             // This particular geometry is full, so we generate another
269             // by taking a shallow copy of the shared Geomety.
270             geom = createNewBuildingGeometryInstance(building);
271             geode->addDrawable(geom);
272             posArray = static_cast<Vec4Array*>(geom->getColorArray());
273             SG_LOG(SG_TERRAIN, SG_DEBUG, "Added new geometry to building geod: " << geode->getNumDrawables());
274           }
275           
276           // We now have a geometry with space for this new building.
277           // Set the position and rotation
278           osg::Vec4f c = osg::Vec4f(toOsg(building.position), building.rotation);
279           posArray->insert(posArray->end(), VERTICES_PER_BUILDING, c);
280           size_t numVerts = posArray->size();
281           primSet = static_cast<DrawArrays*>(geom->getPrimitiveSet(0));
282           primSet->setCount(numVerts);
283       }
284   };
285
286   struct GetBuildingCoord
287   {
288       Vec3 operator() (const BuildingInstance& building) const
289       {
290           return toOsg(building.position);
291       }
292   };
293
294   typedef QuadTreeBuilder<LOD*, BuildingInstance, MakeBuildingLeaf, AddBuildingLeafObject,
295                           GetBuildingCoord> BuildingGeometryQuadtree;
296                           
297   struct BuildingInstanceTransformer
298   {
299       BuildingInstanceTransformer(Matrix& mat_) : mat(mat_) {}
300       BuildingInstance operator()(const BuildingInstance& buildingInstance) const
301       {
302           Vec3 pos = toOsg(buildingInstance.position) * mat;
303           return BuildingInstance(toSG(pos), buildingInstance);
304       }
305       Matrix mat;
306   };
307   
308   ref_ptr<Group> createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options);  
309
310 };
311
312 // List of buildings
313 typedef std::list<SGBuildingBin*> SGBuildingBinList;
314
315
316 osg::Group* createRandomBuildings(SGBuildingBinList buildinglist, const osg::Matrix& transform,
317                          const SGReaderWriterOptions* options);
318 }
319 #endif