3 * Copyright (C) 2006-2007 Mathias Froehlich
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_TEXTURED_TRIANGLE_BIN_HXX
23 #define SG_TEXTURED_TRIANGLE_BIN_HXX
26 #include <osg/Geometry>
27 #include <osg/PrimitiveSet>
29 #include <simgear/math/sg_random.h>
30 #include <simgear/math/SGMath.hxx>
31 #include "SGTriangleBin.hxx"
35 struct SGVertNormTex {
38 SGVertNormTex(const SGVec3f& v, const SGVec3f& n, const SGVec2f& t) :
39 vertex(v), normal(n), texCoord(t)
43 inline bool operator() (const SGVertNormTex& l,
44 const SGVertNormTex& r) const
46 if (l.vertex < r.vertex) return true;
47 else if (r.vertex < l.vertex) return false;
48 else if (l.normal < r.normal) return true;
49 else if (r.normal < l.normal) return false;
50 else return l.texCoord < r.texCoord;
59 // Use a DrawElementsUShort if there are few enough vertices,
60 // otherwise fallback to DrawElementsUInt. Hide the differences
61 // between the two from the rest of the code.
63 // We don't bother with DrawElementsUByte because that is generally
64 // not an advantage on modern hardware.
65 class DrawElementsFacade {
67 DrawElementsFacade(unsigned numVerts) :
68 _ushortElements(0), _uintElements(0)
72 = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
75 = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
78 void push_back(unsigned val)
81 _uintElements->push_back(val);
83 _ushortElements->push_back(val);
86 osg::DrawElements* getDrawElements()
90 return _ushortElements;
93 osg::DrawElementsUShort* _ushortElements;
94 osg::DrawElementsUInt* _uintElements;
97 class SGTexturedTriangleBin : public SGTriangleBin<SGVertNormTex> {
99 SGTexturedTriangleBin()
104 // Computes and adds random surface points to the points list.
105 // The random points are computed with a density of (coverage points)/1
106 // The points are offsetted away from the triangles in
107 // offset * positive normal direction.
108 void addRandomSurfacePoints(float coverage, float offset,
109 std::vector<SGVec3f>& points)
111 unsigned num = getNumTriangles();
112 for (unsigned i = 0; i < num; ++i) {
113 triangle_ref triangleRef = getTriangleRef(i);
114 SGVec3f v0 = getVertex(triangleRef[0]).vertex;
115 SGVec3f v1 = getVertex(triangleRef[1]).vertex;
116 SGVec3f v2 = getVertex(triangleRef[2]).vertex;
117 SGVec3f normal = cross(v1 - v0, v2 - v0);
120 float area = 0.5f*length(normal);
121 if (area <= SGLimitsf::min())
124 // For partial units of area, use a zombie door method to
125 // create the proper random chance of a light being created
127 float unit = area + mt_rand(&seed)*coverage;
129 SGVec3f offsetVector = offset*normalize(normal);
130 // generate a light point for each unit of area
132 while ( coverage < unit ) {
134 float a = mt_rand(&seed);
135 float b = mt_rand(&seed);
142 SGVec3f randomPoint = offsetVector + a*v0 + b*v1 + c*v2;
143 points.push_back(randomPoint);
149 // Computes and adds random surface points to the points list for tree
151 void addRandomTreePoints(float wood_coverage,
154 std::vector<SGVec3f>& points)
156 unsigned num = getNumTriangles();
157 for (unsigned i = 0; i < num; ++i) {
158 triangle_ref triangleRef = getTriangleRef(i);
159 SGVec3f v0 = getVertex(triangleRef[0]).vertex;
160 SGVec3f v1 = getVertex(triangleRef[1]).vertex;
161 SGVec3f v2 = getVertex(triangleRef[2]).vertex;
162 SGVec3f normal = cross(v1 - v0, v2 - v0);
165 float area = 0.5f*length(normal);
166 if (area <= SGLimitsf::min())
169 // For partial units of area, use a zombie door method to
170 // create the proper random chance of a point being created
172 float unit = area + mt_rand(&seed)*wood_coverage;
174 int woodcount = (int) (unit / wood_coverage);
176 for (int j = 0; j < woodcount; j++) {
178 if (wood_size < area) {
179 // We need to place a wood within the triangle and populate it
181 // Determine the center of the wood
182 float x = mt_rand(&seed);
183 float y = mt_rand(&seed);
185 // Determine the size of this wood in m^2, and the number
186 // of trees in the wood
187 float ws = wood_size + wood_size * (mt_rand(&seed) - 0.5f);
188 unsigned total_trees = ws / tree_density;
189 float wood_length = sqrt(ws);
191 // From our wood size, work out the fraction on the two axis.
192 // This will be used as a factor when placing trees in the wood.
193 float x_tree_factor = wood_length / length(v1 -v0);
194 float y_tree_factor = wood_length / length(v2 -v0);
196 for (unsigned k = 0; k <= total_trees; k++) {
198 float a = x + x_tree_factor * (mt_rand(&seed) - 0.5f);
199 float b = y + y_tree_factor * (mt_rand(&seed) - 0.5f);
202 // In some cases, the triangle side lengths are so small that the
203 // tree_factors become so large as to make placing the tree within
204 // the triangle almost impossible. In this case, we place them
205 // randomly across the triangle.
206 if (a < 0.0f || a > 1.0f) a = mt_rand(&seed);
207 if (b < 0.0f || b > 1.0f) b = mt_rand(&seed);
209 if ( a + b > 1.0f ) {
214 float c = 1.0f - a - b;
216 SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
218 points.push_back(randomPoint);
221 // This triangle is too small to contain a complete wood, so just
222 // distribute trees across it.
223 unsigned total_trees = area / tree_density;
225 for (unsigned k = 0; k <= total_trees; k++) {
227 float a = mt_rand(&seed);
228 float b = mt_rand(&seed);
230 if ( a + b > 1.0f ) {
235 float c = 1.0f - a - b;
237 SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
238 points.push_back(randomPoint);
245 void addRandomPoints(float coverage,
246 std::vector<SGVec3f>& points)
248 unsigned num = getNumTriangles();
249 for (unsigned i = 0; i < num; ++i) {
250 triangle_ref triangleRef = getTriangleRef(i);
251 SGVec3f v0 = getVertex(triangleRef[0]).vertex;
252 SGVec3f v1 = getVertex(triangleRef[1]).vertex;
253 SGVec3f v2 = getVertex(triangleRef[2]).vertex;
254 SGVec3f normal = cross(v1 - v0, v2 - v0);
257 float area = 0.5f*length(normal);
258 if (area <= SGLimitsf::min())
261 // for partial units of area, use a zombie door method to
262 // create the proper random chance of an object being created
263 // for this triangle.
264 double num = area / coverage + mt_rand(&seed);
266 // place an object each unit of area
267 while ( num > 1.0 ) {
268 float a = mt_rand(&seed);
269 float b = mt_rand(&seed);
275 SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
276 points.push_back(randomPoint);
282 osg::Geometry* buildGeometry(const TriangleVector& triangles) const
284 // Do not build anything if there is nothing in here ...
285 if (empty() || triangles.empty())
288 // FIXME: do not include all values here ...
289 osg::Vec3Array* vertices = new osg::Vec3Array;
290 osg::Vec3Array* normals = new osg::Vec3Array;
291 osg::Vec2Array* texCoords = new osg::Vec2Array;
293 osg::Vec4Array* colors = new osg::Vec4Array;
294 colors->push_back(osg::Vec4(1, 1, 1, 1));
296 osg::Geometry* geometry = new osg::Geometry;
297 geometry->setVertexArray(vertices);
298 geometry->setNormalArray(normals);
299 geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
300 geometry->setColorArray(colors);
301 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
302 geometry->setTexCoordArray(0, texCoords);
304 const unsigned invalid = ~unsigned(0);
305 std::vector<unsigned> indexMap(getNumVertices(), invalid);
307 DrawElementsFacade deFacade(vertices->size());
308 for (index_type i = 0; i < triangles.size(); ++i) {
309 triangle_ref triangle = triangles[i];
310 if (indexMap[triangle[0]] == invalid) {
311 indexMap[triangle[0]] = vertices->size();
312 vertices->push_back(toOsg(getVertex(triangle[0]).vertex));
313 normals->push_back(toOsg(getVertex(triangle[0]).normal));
314 texCoords->push_back(toOsg(getVertex(triangle[0]).texCoord));
316 deFacade.push_back(indexMap[triangle[0]]);
318 if (indexMap[triangle[1]] == invalid) {
319 indexMap[triangle[1]] = vertices->size();
320 vertices->push_back(toOsg(getVertex(triangle[1]).vertex));
321 normals->push_back(toOsg(getVertex(triangle[1]).normal));
322 texCoords->push_back(toOsg(getVertex(triangle[1]).texCoord));
324 deFacade.push_back(indexMap[triangle[1]]);
326 if (indexMap[triangle[2]] == invalid) {
327 indexMap[triangle[2]] = vertices->size();
328 vertices->push_back(toOsg(getVertex(triangle[2]).vertex));
329 normals->push_back(toOsg(getVertex(triangle[2]).normal));
330 texCoords->push_back(toOsg(getVertex(triangle[2]).texCoord));
332 deFacade.push_back(indexMap[triangle[2]]);
334 geometry->addPrimitiveSet(deFacade.getDrawElements());
339 osg::Geometry* buildGeometry() const
340 { return buildGeometry(getTriangles()); }
343 // Random seed for the triangle.