// $Id$
-/*
- A C-program for MT19937, with initialization improved 2002/2/10.
- Coded by Takuji Nishimura and Makoto Matsumoto.
- This is a faster version by taking Shawn Cokus's optimization,
- Matthe Bellew's simplification, Isaku Wada's real version.
-
- Before using, initialize the state by using init_genrand(seed)
- or init_by_array(init_key, key_length).
-
- Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. The names of its contributors may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
- Any feedback is very welcome.
- http://www.math.keio.ac.jp/matumoto/emt.html
- email: matumoto@math.keio.ac.jp
-*/
+/*
+ * "Cleaned up" and simplified Mersenne Twister implementation.
+ * Vastly smaller and more easily understood and embedded. Stores the
+ * state in a user-maintained structure instead of static memory, so
+ * you can have more than one, or save snapshots of the RNG state.
+ * Lacks the "init_by_array()" feature of the original code in favor
+ * of the simpler 32 bit seed initialization. Lacks the floating
+ * point generator, which is an orthogonal problem not related to
+ * random number generation. Verified to be identical to the original
+ * MT199367ar code through the first 10M generated numbers.
+ */
+
+
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#include "sg_random.h"
-/* Period parameters */
-#define N 624
-#define M 397
-#define MATRIX_A 0x9908b0dfUL /* constant vector a */
-#define UMASK 0x80000000UL /* most significant w-r bits */
-#define LMASK 0x7fffffffUL /* least significant r bits */
-#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
-#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
-
-static unsigned long state[N]; /* the array for the state vector */
-static int left = 1;
-static int initf = 0;
-static unsigned long *next;
-
-/* initializes state[N] with a seed */
-void init_genrand(unsigned long s)
+// Structure for the random number functions.
+mt random_seed;
+
+#define MT(i) mt->array[i]
+
+void mt_init(mt *mt, unsigned int seed)
{
- int j;
- state[0]= s & 0xffffffffUL;
- for (j=1; j<N; j++) {
- state[j] = (1812433253UL * (state[j-1] ^ (state[j-1] >> 30)) + j);
- /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
- /* In the previous versions, MSBs of the seed affect */
- /* only MSBs of the array state[]. */
- /* 2002/01/09 modified by Makoto Matsumoto */
- state[j] &= 0xffffffffUL; /* for >32 bit machines */
- }
- left = 1; initf = 1;
+ int i;
+ MT(0)= seed;
+ for(i=1; i<MT_N; i++)
+ MT(i) = (1812433253 * (MT(i-1) ^ (MT(i-1) >> 30)) + i);
+ mt->index = MT_N+1;
}
-static void next_state(void)
+unsigned int mt_rand32(mt *mt)
{
- unsigned long *p=state;
- int j;
-
- /* if init_genrand() has not been called, */
- /* a default initial seed is used */
- if (initf==0) init_genrand(5489UL);
-
- left = N;
- next = state;
-
- for (j=N-M+1; --j; p++)
- *p = p[M] ^ TWIST(p[0], p[1]);
-
- for (j=M; --j; p++)
- *p = p[M-N] ^ TWIST(p[0], p[1]);
+ unsigned int i, y;
+ if(mt->index >= MT_N) {
+ for(i=0; i<MT_N; i++) {
+ y = (MT(i) & 0x80000000) | (MT((i+1)%MT_N) & 0x7fffffff);
+ MT(i) = MT((i+MT_M)%MT_N) ^ (y>>1) ^ (y&1 ? 0x9908b0df : 0);
+ }
+ mt->index = 0;
+ }
+ y = MT(mt->index++);
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680;
+ y ^= (y << 15) & 0xefc60000;
+ y ^= (y >> 18);
+ return y;
+}
- *p = p[M-N] ^ TWIST(p[0], state[0]);
+double mt_rand(mt *mt)
+{
+ /* divided by 2^32-1 */
+ return (double)mt_rand32(mt) * (1.0/4294967295.0);
}
// Seed the random number generater with time() so we don't see the
// same sequence every time
void sg_srandom_time() {
- init_genrand(time(NULL));
+ mt_init(&random_seed, (unsigned int) time(NULL));
}
// Seed the random number generater with time() in 10 minute intervals
// so we get the same sequence within 10 minutes interval.
// This is useful for synchronizing two display systems.
void sg_srandom_time_10() {
- init_genrand(time(NULL) / 600);
+ mt_init(&random_seed, (unsigned int) time(NULL) / 600);
}
-
// Seed the random number generater with your own seed so can set up
// repeatable randomization.
void sg_srandom( unsigned int seed ) {
- init_genrand( seed );
+ mt_init(&random_seed, seed);
}
-
// return a random number between [0.0, 1.0)
double sg_random() {
- unsigned long y;
-
- if (--left == 0)
- next_state();
- y = *next++;
-
- /* Tempering */
- y ^= (y >> 11);
- y ^= (y << 7) & 0x9d2c5680UL;
- y ^= (y << 15) & 0xefc60000UL;
- y ^= (y >> 18);
-
- return (double)y * (1.0/4294967295.0);
- /* divided by 2^32-1 */
+ return mt_rand(&random_seed);
}
-
#endif
+#define MT_N 624
+#define MT_M 397
+
+/**
+ * Structure to hold MT algorithm state to easily allow independant
+ * sets of random numbers with different seeds.
+ */
+struct {unsigned int array[MT_N]; int index; } typedef mt;
+
+/**
+ * Initialize a new MT state with a given seed.
+ */
+void mt_init(mt *mt, unsigned int seed);
+
+/**
+ * Generate a new 32-bit random number based on the given MT state.
+ */
+unsigned int mt_rand32( mt *mt);
+
+/**
+ * Generate a new random number between [0.0, 1.0) based
+ * on the given MT state.
+ */
+double mt_rand(mt *mt);
+
/**
* Seed the random number generater with time() so we don't see the
* same sequence every time.
* repeatable randomization.
* @param seed random number generator seed
*/
-void sg_srandom( unsigned int seed );
+void sg_srandom(unsigned int seed );
/**
* Return a random number between [0.0, 1.0)
prop_root, sim_time_sec,
/*cache_object*/ true );
if (entity != 0) {
- // FIXME: this stuff can be handled
- // in the XML wrapper as well (at least,
- // the billboarding should be handled
- // there).
- osg::LOD * lod = new osg::LOD;
- lod->setName("Model LOD");
- lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
- lod->setRange(0, 0, _range_m);
- if (_heading_type == HEADING_BILLBOARD) {
+ // FIXME: this stuff can be handled
+ // in the XML wrapper as well (at least,
+ // the billboarding should be handled
+ // there).
+
+ // Create multiple LoD nodes so instead of all objects
+ // of the same type appearing at once, some appear further
+ // away.
+ //
+ // Very basic hardcoded distribution:
+ // 4 at normal range
+ // 2 at 1.5 times normal range
+ // 1 at 2 time normal range.
+ //
+ // We achieve this by creating the three different LoD
+ // nodes and adding them to the _models list multiple times.
+
+ osg::LOD * lod1 = new osg::LOD;
+ lod1->setName("Model LOD");
+ lod1->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
+ lod1->setRange(0, 0, _range_m);
+
+ osg::LOD * lod15 = new osg::LOD;
+ lod15->setName("Model LOD - 1.5");
+ lod15->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
+ lod15->setRange(0, 0, 1.5 * _range_m);
+
+ osg::LOD * lod2 = new osg::LOD;
+ lod2->setName("Model LOD - 2.0");
+ lod2->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
+ lod2->setRange(0, 0, 2.0 * _range_m);
+
+ if (_heading_type == HEADING_BILLBOARD) {
// if the model is a billboard, it is likely :
// 1. a branch with only leaves,
// 2. a tree or a non rectangular shape faked by transparency
stateSet->setAttributeAndModes(alphaFunc,
osg::StateAttribute::OVERRIDE);
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
+
+ lod1->addChild(entity);
+ lod15->addChild(entity);
+ lod2->addChild(entity);
+ } else {
+ lod1->addChild(entity);
+ lod15->addChild(entity);
+ lod2->addChild(entity);
+ }
+
+ // Vary the distribution of LoDs by adding multiple times.
+ _models.push_back(lod1);
+ _models.push_back(lod1);
+ _models.push_back(lod1);
+ _models.push_back(lod1);
+
+ _models.push_back(lod15);
+ _models.push_back(lod15);
+
+ _models.push_back(lod2);
- osg::Transform* transform = new osg::Transform;
- transform->setName("Model Billboard Transform");
- transform->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
- transform->addChild(entity);
- lod->addChild(transform);
- } else {
- lod->addChild(entity);
- }
- _models.push_back(lod);
} else {
- SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
+ SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
}
}
}
}
+
+
// end of matmodel.cxx
#include <osg/ref_ptr>
#include <osg/Node>
+#include <osg/NodeVisitor>
+#include <osg/Billboard>
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
HeadingType get_heading_type () const;
virtual ~SGMatModel ();
+
protected:
vector<SGSharedPtr<SGMatModel> > _objects;
};
-
#endif // _SG_MAT_MODEL_HXX
--- /dev/null
+/* -*-c++-*-
+ *
+ * Copyright (C) 2007 Stuart Buchanan
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SG_MAT_MODEL_BIN_HXX
+#define SG_MAT_MODEL_BIN_HXX
+
+#include <math.h>
+
+class SGMatModelBin {
+public:
+ struct MatModel {
+ MatModel(const SGVec3f& p, SGMatModel *m) :
+ position(p), model(m)
+ { }
+ SGVec3f position;
+ SGMatModel *model;
+ };
+ typedef std::vector<MatModel> MatModelList;
+
+ void insert(const MatModel& model)
+ {
+ float x = model.position.x();
+ float y = model.position.y();
+ float z = model.position.z();
+
+ if (_models.size() == 0)
+ {
+ min_x = x;
+ max_x = x;
+
+ min_y = y;
+ max_y = y;
+
+ min_z = z;
+ max_z = z;
+ }
+ else
+ {
+ min_x = SGMisc<float>::min(min_x, x);
+ max_x = SGMisc<float>::max(max_x, x);
+
+ min_y = SGMisc<float>::min(min_y, y);
+ max_y = SGMisc<float>::max(max_y, y);
+
+ min_z = SGMisc<float>::min(min_z, z);
+ max_z = SGMisc<float>::max(max_z, z);
+ }
+
+ _models.push_back(model);
+ }
+
+ void insert(const SGVec3f& p, SGMatModel *m)
+ { insert(MatModel(p, m)); }
+
+ unsigned getNumModels() const
+ { return _models.size(); }
+ const MatModel& getMatModel(unsigned i) const
+ { return _models[i]; }
+
+private:
+ MatModelList _models;
+ float min_x;
+ float max_x;
+ float min_y;
+ float max_y;
+ float min_z;
+ float max_z;
+};
+
+#endif
#include <simgear/math/SGMath.hxx>
#include "SGTriangleBin.hxx"
+
+
struct SGVertNormTex {
SGVertNormTex()
{ }
class SGTexturedTriangleBin : public SGTriangleBin<SGVertNormTex> {
public:
+ SGTexturedTriangleBin()
+ {
+ seed = new mt;
+ mt_init(seed, 123);
+ }
// Computes and adds random surface points to the points list.
// The random points are computed with a density of (coverage points)/1
// For partial units of area, use a zombie door method to
// create the proper random chance of a light being created
// for this triangle
- float unit = area + sg_random()*coverage;
+ float unit = area + mt_rand(seed)*coverage;
SGVec3f offsetVector = offset*normalize(normal);
// generate a light point for each unit of area
while ( coverage < unit ) {
- float a = sg_random();
- float b = sg_random();
+ float a = mt_rand(seed);
+ float b = mt_rand(seed);
if ( a + b > 1 ) {
a = 1 - a;
b = 1 - b;
}
}
}
+
+ void addRandomPoints(float coverage,
+ std::vector<SGVec3f>& points) const
+ {
+ unsigned num = getNumTriangles();
+ for (unsigned i = 0; i < num; ++i) {
+ triangle_ref triangleRef = getTriangleRef(i);
+ SGVec3f v0 = getVertex(triangleRef[0]).vertex;
+ SGVec3f v1 = getVertex(triangleRef[1]).vertex;
+ SGVec3f v2 = getVertex(triangleRef[2]).vertex;
+ SGVec3f normal = cross(v1 - v0, v2 - v0);
+
+ // Compute the area
+ float area = 0.5f*length(normal);
+ if (area <= SGLimitsf::min())
+ continue;
+
+ // for partial units of area, use a zombie door method to
+ // create the proper random chance of an object being created
+ // for this triangle.
+ double num = area / coverage + mt_rand(seed);
+
+ // place an object each unit of area
+ while ( num > 1.0 ) {
+ float a = mt_rand(seed);
+ float b = mt_rand(seed);
+ if ( a + b > 1 ) {
+ a = 1 - a;
+ b = 1 - b;
+ }
+ float c = 1 - a - b;
+ SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
+ points.push_back(randomPoint);
+ num -= 1.0;
+ }
+ }
+ }
osg::Geometry* buildGeometry(const TriangleVector& triangles) const
{
osg::Geometry* buildGeometry() const
{ return buildGeometry(getTriangles()); }
+
+private:
+ // Random seed for the triangle.
+ mt* seed;
};
#endif
#include <simgear/scene/model/SGOffsetTransform.hxx>
#include <simgear/scene/util/SGUpdateVisitor.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
+#include <simgear/scene/util/QuadTreeBuilder.hxx>
#include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGGuard.hxx>
#include "SGTexturedTriangleBin.hxx"
#include "SGLightBin.hxx"
+#include "SGModelBin.hxx"
#include "SGDirectionalLightBin.hxx"
#include "GroundLightManager.hxx"
+#include "userdata.hxx"
#include "pt_lights.hxx"
using namespace simgear;
SGDirectionalLightListBin rabitLights;
SGLightListBin odalLights;
SGDirectionalLightListBin reilLights;
-
+ SGMatModelBin randomModels;
+
static SGVec4f
getMaterialLightColor(const SGMaterial* material)
{
void computeRandomSurfaceLights(SGMaterialLib* matlib)
{
SGMaterialTriangleMap::const_iterator i;
+
+ // generate a repeatable random seed
+ mt* seed = new mt;
+ mt_init(seed, unsigned(123));
+
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
SGMaterial *mat = matlib->find(i->first);
if (!mat)
coverage = 10000;
}
- // generate a repeatable random seed
- sg_srandom(unsigned(coverage));
-
std::vector<SGVec3f> randomPoints;
i->second.addRandomSurfacePoints(coverage, 3, randomPoints);
std::vector<SGVec3f>::iterator j;
for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
- float zombie = sg_random();
+ float zombie = mt_rand(seed);
// factor = sg_random() ^ 2, range = 0 .. 1 concentrated towards 0
- float factor = sg_random();
+ float factor = mt_rand(seed);
factor *= factor;
float bright = 1;
}
}
}
+
+ void computeRandomObjects(SGMaterialLib* matlib)
+ {
+ SGMaterialTriangleMap::const_iterator i;
+ for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
+ SGMaterial *mat = matlib->find(i->first);
+ if (!mat)
+ continue;
+
+ int group_count = mat->get_object_group_count();
+
+ if (group_count > 0)
+ {
+ for (int j = 0; j < group_count; j++)
+ {
+ SGMatModelGroup *object_group = mat->get_object_group(j);
+ int nObjects = object_group->get_object_count();
+
+ if (nObjects > 0)
+ {
+ // For each of the random models in the group, determine an appropriate
+ // number of random placements and insert them.
+ for (int k = 0; k < nObjects; k++) {
+ SGMatModel * object = object_group->get_object(k);
+
+ std::vector<SGVec3f> randomPoints;
+
+ i->second.addRandomPoints(object->get_coverage_m2(), randomPoints);
+ std::vector<SGVec3f>::iterator l;
+ for (l = randomPoints.begin(); l != randomPoints.end(); ++l) {
+ randomModels.insert(*l, object);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib)
{
osg::Node*
SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects)
{
- SGBinObject obj;
- if (!obj.read_bin(path))
+ SGBinObject tile;
+ if (!tile.read_bin(path))
return false;
SGTileGeometryBin tileGeometryBin;
- if (!tileGeometryBin.insertBinObj(obj, matlib))
+ if (!tileGeometryBin.insertBinObj(tile, matlib))
return false;
- SGVec3d center = obj.get_gbs_center2();
+ SGVec3d center = tile.get_gbs_center2();
SGGeod geodPos = SGGeod::fromCart(center);
SGQuatd hlOr = SGQuatd::fromLonLat(geodPos);
SGVec3f up = toVec3f(hlOr.backTransform(SGVec3d(0, 0, -1)));
+ osg::Matrix world2Tile(-hlOr.osg());
GroundLightManager* lightManager = GroundLightManager::instance();
osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
+ osg::ref_ptr<osg::Group> randomObjects;
osg::Group* terrainGroup = new osg::Group;
+
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
if (node)
terrainGroup->addChild(node);
+
+ if (use_random_objects) {
+ tileGeometryBin.computeRandomObjects(matlib);
+
+ if (tileGeometryBin.randomModels.getNumModels() > 0) {
+ // Generate a repeatable random seed
+ mt* seed = new mt;
+ mt_init(seed, unsigned(123));
+
+ // Determine an rotation matrix for the models to place them
+ // perpendicular to the earth's surface. We use the same matrix,
+ // based on the centre of the tile, as the small angular differences
+ // between different points on the tile aren't worth worrying about
+ // for random objects. We also need to flip the orientation 180 degrees
+ static const osg::Matrix flip(1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, -1, 0,
+ 0, 0, 0, 1);
+ osg::Matrix mAtt = flip * osg::Matrix::rotate(hlOr.osg());
+ std::vector<osg::ref_ptr<osg::Node> > models;
+
+ for (unsigned int i = 0; i < tileGeometryBin.randomModels.getNumModels(); i++) {
+ SGMatModelBin::MatModel obj = tileGeometryBin.randomModels.getMatModel(i);
+ osg::Node* node = sgGetRandomModel(obj.model);
+
+ // Create a matrix to place the object in the correct location, and then
+ // apply the rotation matrix created above, with an additional random
+ // heading rotation if appropriate.
+ osg::Matrix mPos = osg::Matrix::translate(obj.position.osg());
+ osg::MatrixTransform* position;
+
+ if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) {
+ // Rotate the object around the z axis.
+ double hdg = mt_rand(seed) * M_PI * 2;
+ osg::Matrix rot(cos(hdg), -sin(hdg), 0, 0,
+ sin(hdg), cos(hdg), 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+ position = new osg::MatrixTransform(rot * mAtt * mPos);
+ } else {
+ position = new osg::MatrixTransform(mAtt * mPos);
+ }
+
+ position->addChild(node);
+ models.push_back(position);
+ // Add to the leaf of the quadtree based on object location.
+ }
+ randomObjects = QuadTreeBuilder::makeQuadTree(models, world2Tile);
+ randomObjects->setName("random objects");
+ }
+ }
if (calc_lights) {
// FIXME: ugly, has a side effect
lightLOD->setNodeMask(nodeMask);
transform->addChild(lightLOD);
}
+
+ if (randomObjects.valid()) {
+
+ // Add a LoD node, so we don't try to display anything when the tile center
+ // is more than 20km away.
+ osg::LOD* objectLOD = new osg::LOD;
+ objectLOD->addChild(randomObjects.get(), 0, 20000);
+ unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECIEVESHADOW_BIT;
+ objectLOD->setNodeMask(nodeMask);
+ transform->addChild(objectLOD);
+ }
+
return transform;
}
#include <simgear/scene/material/mat.hxx>
#include <simgear/scene/material/matmodel.hxx>
+#include "SGModelBin.hxx"
#include "userdata.hxx"
#include "SGReaderWriterBTG.hxx"
sim_time_sec = t;
}
+ osg::Node* sgGetRandomModel(SGMatModel *obj) {
+ return obj->get_random_model(modellib, model_root, root_props, sim_time_sec);
+ }
+
+osg::Node* sgGetModel(int i, SGMatModel *obj) {
+ return obj->get_model(i, modellib, model_root, root_props, sim_time_sec);
+ }
static void random_pt_inside_tri( float *res,
float *n1, float *n2, float *n3 )
void sgUserDataInit( SGModelLib *m, const string &r,
SGPropertyNode *p, double t );
+/**
+ * Get a random model.
+ */
+osg::Node* sgGetRandomModel(SGMatModel *obj);
+
+/**
+ * Get a specific model.
+ */
+osg::Node* sgGetModel(int i, SGMatModel *obj);
/**
* User data for populating leaves when they come in range.
SGStateAttributeVisitor.hxx \
SGTextureStateAttributeVisitor.hxx \
SGUpdateVisitor.hxx \
+ QuadTreeBuilder.hxx \
RenderConstants.hxx \
StateAttributeFactory.hxx \
VectorArrayAdapter.hxx
SGSceneUserData.cxx \
SGStateAttributeVisitor.cxx \
SGTextureStateAttributeVisitor.cxx \
- StateAttributeFactory.cxx
+ StateAttributeFactory.cxx \
+ QuadTreeBuilder.cxx
INCLUDES = -I$(top_srcdir)
--- /dev/null
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include <osg/BoundingBox>
+#include <osg/Math>
+
+#include "QuadTreeBuilder.hxx"
+
+using namespace std;
+using namespace osg;
+
+namespace simgear
+{
+QuadTreeBuilder::QuadTreeBuilder(const Vec2& min, const Vec2& max) :
+ _root(new osg::Group), _min(min), _max(max)
+{
+ for (int i = 0; i < 4; ++i) {
+ Group* interior = new osg::Group;
+ _root->addChild(interior);
+ for (int j = 0; j < 4; ++j) {
+ Group* leaf = new osg::Group;
+ interior->addChild(leaf);
+ _leaves[i][j] = leaf;
+ }
+ }
+}
+
+void QuadTreeBuilder::addNode(Node* node, const Matrix& transform)
+{
+ Vec3 center = node->getBound().center() * transform;
+
+ int x = (int)(4.0 * (center.x() - _min.x()) / (_max.x() - _min.x()));
+ x = clampTo(x, 0, 3);
+ int y = (int)(4.0 * (center.y() - _min.y()) / (_max.y() - _min.y()));
+ y = clampTo(y, 0, 3);
+ _leaves[y][x]->addChild(node);
+}
+
+osg::Group* QuadTreeBuilder::makeQuadTree(vector<ref_ptr<Node> >& nodes,
+ const Matrix& transform)
+{
+ typedef vector<ref_ptr<Node> > NodeList;
+ BoundingBox extents;
+ for (NodeList::iterator iter = nodes.begin(); iter != nodes.end(); ++iter) {
+ const Vec3 center = (*iter)->getBound().center() * transform;
+ extents.expandBy(center);
+ }
+ const Vec2 quadMin(extents.xMin(), extents.yMin());
+ const Vec2 quadMax(extents.xMax(), extents.yMax());
+ ref_ptr<Group> result;
+ {
+ QuadTreeBuilder quadTree(quadMin, quadMax);
+ for (NodeList::iterator iter = nodes.begin();
+ iter != nodes.end();
+ ++iter) {
+ quadTree.addNode(iter->get(), transform);
+ }
+ result = quadTree.getRoot();
+ }
+ return result.release();
+}
+
+}
--- /dev/null
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#ifndef SIMGEAR_QUADTREEBUILDER_HXX
+#define SIMGEAR_QUADTREEBUILDER_HXX 1
+
+#include <vector>
+#include <osg/ref_ptr>
+#include <osg/Node>
+#include <osg/Group>
+#include <osg/Matrix>
+#include <osg/Vec2>
+
+namespace simgear
+{
+// Create a quad tree based on x, y extents
+class QuadTreeBuilder {
+public:
+ QuadTreeBuilder(const osg::Vec2& min, const osg::Vec2& max);
+ ~QuadTreeBuilder() {}
+ osg::Group* getRoot() { return _root.get(); }
+ // Add node to the quadtree using its x, y
+ void addNode(osg::Node* node, const osg::Matrix& transform);
+ // Make a quadtree of nodes from a vector of nodes
+ static osg::Group* makeQuadTree(std::vector<osg::ref_ptr<osg::Node> >& nodes,
+ const osg::Matrix& transform);
+protected:
+ osg::ref_ptr<osg::Group> _root;
+ osg::Group* _leaves[4][4];
+ osg::Vec2 _min;
+ osg::Vec2 _max;
+};
+}
+#endif