3 * Copyright (C) 2011 Stuart Buchanan
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.
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.
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,
22 #ifndef SG_BUILDING_BIN_HXX
23 #define SG_BUILDING_BIN_HXX
31 #include <osg/Geometry>
33 #include <osg/MatrixTransform>
35 #include <osg/ShadeModel>
36 #include <osg/Material>
37 #include <osg/CullFace>
40 #include <simgear/scene/util/OsgMath.hxx>
41 #include <simgear/scene/material/mat.hxx>
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>
48 #define SG_BUILDING_QUAD_TREE_DEPTH 4
49 #define SG_BUILDING_FADE_OUT_LEVELS 4
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;
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;
74 Building(BuildingType t, float w, float d, float h, int f, bool pitch) :
81 radius(std::max(d, 0.5f*w))
92 float getFootprint() {
97 // The set of buildings that are instantiated
98 typedef std::vector<Building> BuildingList;
99 BuildingList smallBuildings;
100 BuildingList mediumBuildings;
101 BuildingList largeBuildings;
103 std::string material_name;
105 std::string lightMap;
107 // Fraction of buildings of this type
108 float smallBuildingFraction;
109 float mediumBuildingFraction;
111 // The maximum radius of each building type
112 float smallBuildingMaxRadius;
113 float mediumBuildingMaxRadius;
114 float largeBuildingMaxRadius;
116 // The maximum depth of each building type
117 float smallBuildingMaxDepth;
118 float mediumBuildingMaxDepth;
119 float largeBuildingMaxDepth;
121 // Visibility range for buildings
124 // Shared geometries of the building set
125 ref_ptr<Geometry> smallSharedGeometry;
126 ref_ptr<Geometry> mediumSharedGeometry;
127 ref_ptr<Geometry> largeSharedGeometry;
129 struct BuildingInstance {
130 BuildingInstance(SGVec3f p, float r, const BuildingList* bl, ref_ptr<Geometry> sg) :
137 BuildingInstance(SGVec3f p, BuildingInstance b) :
139 rotation(b.rotation),
140 buildingList(b.buildingList),
141 sharedGeometry(b.sharedGeometry)
147 // References to allow the QuadTreeBuilder to work
148 const BuildingList* buildingList;
149 ref_ptr<Geometry> sharedGeometry;
151 SGVec3f getPosition() { return position; }
152 float getRotation() { return rotation; }
154 float getDistSqr(SGVec3f p) {
155 return distSqr(p, position);
158 const osg::Vec4f getColorValue() {
159 return osg::Vec4f(toOsg(position), rotation);
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;
171 SGBuildingBin(const SGMaterial *mat);
174 smallBuildings.clear();
175 mediumBuildings.clear();
176 largeBuildings.clear();
177 smallBuildingLocations.clear();
178 mediumBuildingLocations.clear();
179 largeBuildingLocations.clear();
182 void insert(SGVec3f p, float r, BuildingType type);
183 int getNumBuildings();
185 bool checkMinDist (SGVec3f p, float radius);
187 std::string getMaterialName() { return material_name; }
189 BuildingType getBuildingType(float roll);
191 float getBuildingMaxRadius(BuildingType);
192 float getBuildingMaxDepth(BuildingType);
194 // Helper classes for creating the quad tree
195 struct MakeBuildingLeaf
197 MakeBuildingLeaf(float range, Effect* effect, bool fade) :
198 _range(range), _effect(effect), _fade_out(fade) {}
200 MakeBuildingLeaf(const MakeBuildingLeaf& rhs) :
201 _range(rhs._range), _effect(rhs._effect), _fade_out(rhs._fade_out)
204 LOD* operator() () const
206 LOD* result = new LOD;
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++)
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)));
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);
227 ref_ptr<Effect> _effect;
231 struct AddBuildingLeafObject
233 Geometry* createNewBuildingGeometryInstance(const BuildingInstance& building) const
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));
242 void operator() (LOD* lod, const BuildingInstance& building) const
244 Geode* geode = static_cast<Geode*>(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren()));
245 unsigned int numDrawables = geode->getNumDrawables();
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
254 if (numDrawables == 0) {
255 // Create a new copy of the shared geometry to instantiate
256 geom = createNewBuildingGeometryInstance(building);
257 geode->addDrawable(geom);
259 geom = static_cast<Geometry*>(geode->getDrawable(numDrawables - 1));
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());
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());
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);
286 struct GetBuildingCoord
288 Vec3 operator() (const BuildingInstance& building) const
290 return toOsg(building.position);
294 typedef QuadTreeBuilder<LOD*, BuildingInstance, MakeBuildingLeaf, AddBuildingLeafObject,
295 GetBuildingCoord> BuildingGeometryQuadtree;
297 struct BuildingInstanceTransformer
299 BuildingInstanceTransformer(Matrix& mat_) : mat(mat_) {}
300 BuildingInstance operator()(const BuildingInstance& buildingInstance) const
302 Vec3 pos = toOsg(buildingInstance.position) * mat;
303 return BuildingInstance(toSG(pos), buildingInstance);
308 ref_ptr<Group> createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options);
313 typedef std::list<SGBuildingBin*> SGBuildingBinList;
316 osg::Group* createRandomBuildings(SGBuildingBinList buildinglist, const osg::Matrix& transform,
317 const SGReaderWriterOptions* options);