1 // leaf.cxx -- function to build and ssg leaf from higher level data.
3 // Written by Curtis Olson, started October 1997.
5 // Copyright (C) 1997 - 2003 Curtis L. Olson - http://www.flightgear.org/~curt
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 # include <simgear_config.h>
28 #include <simgear/compiler.h>
30 #ifdef SG_MATH_EXCEPTION_CLASH
37 #include <osg/Geometry>
39 #include <osg/StateSet>
40 #include <osg/TriangleFunctor>
42 #include <simgear/debug/logstream.hxx>
43 #include <simgear/math/sg_random.h>
44 #include <simgear/scene/material/mat.hxx>
45 #include <simgear/scene/material/matlib.hxx>
53 typedef vector < int > int_list;
54 typedef int_list::iterator int_list_iterator;
55 typedef int_list::const_iterator int_point_list_iterator;
57 /// class to implement the TrinagleFunctor class
58 struct SGRandomSurfacePointsFill {
59 osg::Vec3Array* lights;
62 void operator () (const osg::Vec3& v1, const osg::Vec3& v2,
63 const osg::Vec3& v3, bool)
66 float area = 0.5*((v1 - v2)^(v3 - v2)).length();
67 float num = area / factor;
69 // generate a light point for each unit of area
71 lights->push_back(random_pt_inside_tri( v1, v2, v3 ));
74 // for partial units of area, use a zombie door method to
75 // create the proper random chance of a light being created
78 if ( sg_random() <= num ) {
79 // a zombie made it through our door
80 lights->push_back(random_pt_inside_tri( v1, v2, v3 ));
85 osg::Vec3 random_pt_inside_tri(const osg::Vec3& n1, const osg::Vec3& n2,
88 double a = sg_random();
89 double b = sg_random();
96 return n1*a + n2*b + n3*c;
100 static void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor,
101 osg::Vec3Array *lights )
103 osg::TriangleFunctor<SGRandomSurfacePointsFill> triangleFunctor;
104 triangleFunctor.lights = lights;
105 triangleFunctor.factor = factor;
106 leaf->accept(triangleFunctor);
111 ////////////////////////////////////////////////////////////////////////
113 ////////////////////////////////////////////////////////////////////////
115 osg::Drawable* SGMakeLeaf( const string& path,
116 const GLenum ty, SGMaterial *mat,
117 const point_list& nodes, const point_list& normals,
118 const point_list& texcoords,
119 const int_list& node_index,
120 const int_list& normal_index,
121 const int_list& tex_index,
122 const bool calc_lights, osg::Vec3Array *lights )
124 double tex_width = 1000.0, tex_height = 1000.0;
125 osg::StateSet *state = 0;
129 // set the texture width and height values for this
131 tex_width = mat->get_xsize();
132 tex_height = mat->get_ysize();
133 state = mat->get_state();
134 coverage = mat->get_light_coverage();
140 int size = node_index.size();
142 SG_LOG( SG_TERRAIN, SG_ALERT, "Woh! node list size < 1" );
145 osg::Vec3Array* vl = new osg::Vec3Array;
147 for ( i = 0; i < size; ++i ) {
148 Point3D node = nodes[ node_index[i] ];
149 vl->push_back(osg::Vec3(node[0], node[1], node[2]));
153 osg::Vec3Array* nl = new osg::Vec3Array;
155 if ( normal_index.size() ) {
156 // object file specifies normal indices (i.e. normal indices
158 for ( i = 0; i < size; ++i ) {
159 Point3D normal = normals[ normal_index[i] ];
160 nl->push_back(osg::Vec3(normal[0], normal[1], normal[2]));
163 // use implied normal indices. normal index = vertex index.
164 for ( i = 0; i < size; ++i ) {
165 Point3D normal = normals[ node_index[i] ];
166 nl->push_back(osg::Vec3(normal[0], normal[1], normal[2]));
171 osg::Vec4Array* cl = new osg::Vec4Array;
172 cl->push_back(osg::Vec4(1, 1, 1, 1));
174 // texture coordinates
175 size = tex_index.size();
177 osg::Vec2Array* tl = new osg::Vec2Array;
180 Point3D texcoord = texcoords[ tex_index[0] ];
181 osg::Vec2 tmp2(texcoord[0], texcoord[1]);
182 if ( tex_width > 0 ) {
183 tmp2[0] *= (1000.0 / tex_width);
185 if ( tex_height > 0 ) {
186 tmp2[1] *= (1000.0 / tex_height);
188 tl -> push_back( tmp2 );
189 } else if ( size > 1 ) {
190 for ( i = 0; i < size; ++i ) {
191 Point3D texcoord = texcoords[ tex_index[i] ];
192 osg::Vec2 tmp2(texcoord[0], texcoord[1]);
193 if ( tex_width > 0 ) {
194 tmp2[0] *= (1000.0 / tex_width);
196 if ( tex_height > 0 ) {
197 tmp2[1] *= (1000.0 / tex_height);
199 tl -> push_back( tmp2 );
204 osg::Geometry* geometry = new osg::Geometry;
205 geometry->setVertexArray(vl);
206 geometry->setNormalArray(nl);
207 geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
208 geometry->setColorArray(cl);
209 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
210 geometry->setTexCoordArray(0, tl);
211 geometry->addPrimitiveSet(new osg::DrawArrays(ty, 0, vl->size()));
213 // lookup the state record
214 geometry->setStateSet(state);
217 if ( coverage > 0.0 ) {
218 if ( coverage < 10000.0 ) {
219 SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
220 << coverage << ", pushing up to 10000");
223 SGGenRandomSurfacePoints(geometry, coverage, lights);