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"
33 struct SGVertNormTex {
36 SGVertNormTex(const SGVec3f& v, const SGVec3f& n, const SGVec2f& t) :
37 vertex(v), normal(n), texCoord(t)
41 inline bool operator() (const SGVertNormTex& l,
42 const SGVertNormTex& r) const
44 if (l.vertex < r.vertex) return true;
45 else if (r.vertex < l.vertex) return false;
46 else if (l.normal < r.normal) return true;
47 else if (r.normal < l.normal) return false;
48 else return l.texCoord < r.texCoord;
57 // Use a DrawElementsUShort if there are few enough vertices,
58 // otherwise fallback to DrawElementsUInt. Hide the differences
59 // between the two from the rest of the code.
61 // We don't bother with DrawElementsUByte because that is generally
62 // not an advantage on modern hardware.
63 class DrawElementsFacade {
65 DrawElementsFacade(unsigned numVerts) :
66 _ushortElements(0), _uintElements(0)
70 = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
73 = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
76 void push_back(unsigned val)
79 _uintElements->push_back(val);
81 _ushortElements->push_back(val);
84 osg::DrawElements* getDrawElements()
88 return _ushortElements;
91 osg::DrawElementsUShort* _ushortElements;
92 osg::DrawElementsUInt* _uintElements;
95 class SGTexturedTriangleBin : public SGTriangleBin<SGVertNormTex> {
98 // Computes and adds random surface points to the points list.
99 // The random points are computed with a density of (coverage points)/1
100 // The points are offsetted away from the triangles in
101 // offset * positive normal direction.
102 void addRandomSurfacePoints(float coverage, float offset,
103 std::vector<SGVec3f>& points) const
105 unsigned num = getNumTriangles();
106 for (unsigned i = 0; i < num; ++i) {
107 triangle_ref triangleRef = getTriangleRef(i);
108 SGVec3f v0 = getVertex(triangleRef[0]).vertex;
109 SGVec3f v1 = getVertex(triangleRef[1]).vertex;
110 SGVec3f v2 = getVertex(triangleRef[2]).vertex;
111 SGVec3f normal = cross(v1 - v0, v2 - v0);
114 float area = 0.5f*length(normal);
115 if (area <= SGLimitsf::min())
118 // For partial units of area, use a zombie door method to
119 // create the proper random chance of a light being created
121 float unit = area + sg_random()*coverage;
123 SGVec3f offsetVector = offset*normalize(normal);
124 // generate a light point for each unit of area
125 while ( coverage < unit ) {
126 float a = sg_random();
127 float b = sg_random();
133 SGVec3f randomPoint = offsetVector + a*v0 + b*v1 + c*v2;
134 points.push_back(randomPoint);
140 osg::Geometry* buildGeometry(const TriangleVector& triangles) const
142 // Do not build anything if there is nothing in here ...
143 if (empty() || triangles.empty())
146 // FIXME: do not include all values here ...
147 osg::Vec3Array* vertices = new osg::Vec3Array;
148 osg::Vec3Array* normals = new osg::Vec3Array;
149 osg::Vec2Array* texCoords = new osg::Vec2Array;
151 osg::Vec4Array* colors = new osg::Vec4Array;
152 colors->push_back(osg::Vec4(1, 1, 1, 1));
154 osg::Geometry* geometry = new osg::Geometry;
155 geometry->setVertexArray(vertices);
156 geometry->setNormalArray(normals);
157 geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
158 geometry->setColorArray(colors);
159 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
160 geometry->setTexCoordArray(0, texCoords);
162 const unsigned invalid = ~unsigned(0);
163 std::vector<unsigned> indexMap(getNumVertices(), invalid);
165 DrawElementsFacade deFacade(vertices->size());
166 for (index_type i = 0; i < triangles.size(); ++i) {
167 triangle_ref triangle = triangles[i];
168 if (indexMap[triangle[0]] == invalid) {
169 indexMap[triangle[0]] = vertices->size();
170 vertices->push_back(getVertex(triangle[0]).vertex.osg());
171 normals->push_back(getVertex(triangle[0]).normal.osg());
172 texCoords->push_back(getVertex(triangle[0]).texCoord.osg());
174 deFacade.push_back(indexMap[triangle[0]]);
176 if (indexMap[triangle[1]] == invalid) {
177 indexMap[triangle[1]] = vertices->size();
178 vertices->push_back(getVertex(triangle[1]).vertex.osg());
179 normals->push_back(getVertex(triangle[1]).normal.osg());
180 texCoords->push_back(getVertex(triangle[1]).texCoord.osg());
182 deFacade.push_back(indexMap[triangle[1]]);
184 if (indexMap[triangle[2]] == invalid) {
185 indexMap[triangle[2]] = vertices->size();
186 vertices->push_back(getVertex(triangle[2]).vertex.osg());
187 normals->push_back(getVertex(triangle[2]).normal.osg());
188 texCoords->push_back(getVertex(triangle[2]).texCoord.osg());
190 deFacade.push_back(indexMap[triangle[2]]);
192 geometry->addPrimitiveSet(deFacade.getDrawElements());
197 osg::Geometry* buildGeometry() const
198 { return buildGeometry(getTriangles()); }