#include <simgear/math/SGMath.hxx>
#include "SGTriangleBin.hxx"
+
+
struct SGVertNormTex {
SGVertNormTex()
{ }
SGVec2f texCoord;
};
+// Use a DrawElementsUShort if there are few enough vertices,
+// otherwise fallback to DrawElementsUInt. Hide the differences
+// between the two from the rest of the code.
+//
+// We don't bother with DrawElementsUByte because that is generally
+// not an advantage on modern hardware.
+class DrawElementsFacade {
+public:
+ DrawElementsFacade(unsigned numVerts) :
+ _ushortElements(0), _uintElements(0)
+ {
+ if (numVerts > 65535)
+ _uintElements
+ = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
+ else
+ _ushortElements
+ = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
+ }
+
+ void push_back(unsigned val)
+ {
+ if (_uintElements)
+ _uintElements->push_back(val);
+ else
+ _ushortElements->push_back(val);
+ }
+
+ osg::DrawElements* getDrawElements()
+ {
+ if (_uintElements)
+ return _uintElements;
+ return _ushortElements;
+ }
+protected:
+ osg::DrawElementsUShort* _ushortElements;
+ osg::DrawElementsUInt* _uintElements;
+};
+
class SGTexturedTriangleBin : public SGTriangleBin<SGVertNormTex> {
public:
+ SGTexturedTriangleBin()
+ {
+ 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
// The points are offsetted away from the triangles in
// offset * positive normal direction.
void addRandomSurfacePoints(float coverage, float offset,
- std::vector<SGVec3f>& points) const
+ std::vector<SGVec3f>& points)
{
unsigned num = getNumTriangles();
for (unsigned i = 0; i < num; ++i) {
// 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)
+ {
+ 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
{
const unsigned invalid = ~unsigned(0);
std::vector<unsigned> indexMap(getNumVertices(), invalid);
-
- osg::DrawElementsUInt* drawElements;
- drawElements = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
+
+ DrawElementsFacade deFacade(vertices->size());
for (index_type i = 0; i < triangles.size(); ++i) {
triangle_ref triangle = triangles[i];
if (indexMap[triangle[0]] == invalid) {
normals->push_back(getVertex(triangle[0]).normal.osg());
texCoords->push_back(getVertex(triangle[0]).texCoord.osg());
}
- drawElements->push_back(indexMap[triangle[0]]);
+ deFacade.push_back(indexMap[triangle[0]]);
if (indexMap[triangle[1]] == invalid) {
indexMap[triangle[1]] = vertices->size();
normals->push_back(getVertex(triangle[1]).normal.osg());
texCoords->push_back(getVertex(triangle[1]).texCoord.osg());
}
- drawElements->push_back(indexMap[triangle[1]]);
+ deFacade.push_back(indexMap[triangle[1]]);
if (indexMap[triangle[2]] == invalid) {
indexMap[triangle[2]] = vertices->size();
normals->push_back(getVertex(triangle[2]).normal.osg());
texCoords->push_back(getVertex(triangle[2]).texCoord.osg());
}
- drawElements->push_back(indexMap[triangle[2]]);
+ deFacade.push_back(indexMap[triangle[2]]);
}
- geometry->addPrimitiveSet(drawElements);
+ geometry->addPrimitiveSet(deFacade.getDrawElements());
return geometry;
}
osg::Geometry* buildGeometry() const
{ return buildGeometry(getTriangles()); }
+
+private:
+ // Random seed for the triangle.
+ mt seed;
};
#endif