]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/leaf.cxx
Modified Files:
[simgear.git] / simgear / scene / tgdb / leaf.cxx
1 // leaf.cxx -- function to build and ssg leaf from higher level data.
2 //
3 // Written by Curtis Olson, started October 1997.
4 //
5 // Copyright (C) 1997 - 2003  Curtis L. Olson  - http://www.flightgear.org/~curt
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <simgear_config.h>
26 #endif
27
28 #include <simgear/compiler.h>
29
30 #ifdef SG_MATH_EXCEPTION_CLASH
31 #  include <math.h>
32 #endif
33
34 #include STL_STRING
35
36 #include <osg/Geode>
37 #include <osg/Geometry>
38 #include <osg/Group>
39 #include <osg/StateSet>
40 #include <osg/TriangleFunctor>
41
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>
46
47 #include "leaf.hxx"
48
49 SG_USING_STD(string);
50 SG_USING_STD(vector);
51
52
53 typedef vector < int > int_list;
54 typedef int_list::iterator int_list_iterator;
55 typedef int_list::const_iterator int_point_list_iterator;
56
57 /// class to implement the TrinagleFunctor class
58 struct SGRandomSurfacePointsFill {
59   osg::Vec3Array* lights;
60   float factor;
61
62   void operator () (const osg::Vec3& v1, const osg::Vec3& v2,
63                     const osg::Vec3& v3, bool)
64   {
65     // Compute the area
66     float area = 0.5*((v1 - v2)^(v3 - v2)).length();
67     float num = area / factor;
68     
69     // generate a light point for each unit of area
70     while ( num > 1.0 ) {
71       lights->push_back(random_pt_inside_tri( v1, v2, v3 ));
72       num -= 1.0;
73     }
74     // for partial units of area, use a zombie door method to
75     // create the proper random chance of a light being created
76     // for this triangle
77     if ( num > 0.0 ) {
78       if ( sg_random() <= num ) {
79         // a zombie made it through our door
80         lights->push_back(random_pt_inside_tri( v1, v2, v3 ));
81       }
82     }
83   }
84
85   osg::Vec3 random_pt_inside_tri(const osg::Vec3& n1, const osg::Vec3& n2,
86                                  const osg::Vec3& n3)
87   {
88     double a = sg_random();
89     double b = sg_random();
90     if ( a + b > 1.0 ) {
91       a = 1 - a;
92       b = 1 - b;
93     }
94     double c = 1 - a - b;
95     
96     return n1*a + n2*b + n3*c;
97   }
98 };
99
100 static void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor, 
101                                       osg::Vec3Array *lights )
102 {
103   osg::TriangleFunctor<SGRandomSurfacePointsFill> triangleFunctor;
104   triangleFunctor.lights = lights;
105   triangleFunctor.factor = factor;
106   leaf->accept(triangleFunctor);
107 }
108
109
110
111 ////////////////////////////////////////////////////////////////////////
112 // Scenery loaders.
113 ////////////////////////////////////////////////////////////////////////
114
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 )
123 {
124     double tex_width = 1000.0, tex_height = 1000.0;
125     osg::StateSet *state = 0;
126     float coverage = -1;
127
128     if ( mat != NULL ) {
129         // set the texture width and height values for this
130         // material
131         tex_width = mat->get_xsize();
132         tex_height = mat->get_ysize();
133         state = mat->get_state();
134         coverage = mat->get_light_coverage();
135     }
136
137     int i;
138
139     // vertices
140     int size = node_index.size();
141     if ( size < 1 ) {
142         SG_LOG( SG_TERRAIN, SG_ALERT, "Woh! node list size < 1" );
143         exit(-1);
144     }
145     osg::Vec3Array* vl = new osg::Vec3Array;
146     vl->reserve(size);
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]));
150     }
151
152     // normals
153     osg::Vec3Array* nl = new osg::Vec3Array;
154     nl->reserve(size);
155     if ( normal_index.size() ) {
156         // object file specifies normal indices (i.e. normal indices
157         // aren't 'implied'
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]));
161         }
162     } else {
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]));
167         }
168     }
169
170     // colors
171     osg::Vec4Array* cl = new osg::Vec4Array;
172     cl->push_back(osg::Vec4(1, 1, 1, 1));
173
174     // texture coordinates
175     size = tex_index.size();
176     Point3D texcoord;
177     osg::Vec2Array* tl = new osg::Vec2Array;
178     tl->reserve(size);
179     if ( size == 1 ) {
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);
184         }
185         if ( tex_height > 0 ) {
186             tmp2[1] *= (1000.0 / tex_height);
187         }
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);
195             }
196             if ( tex_height > 0 ) {
197                 tmp2[1] *= (1000.0 / tex_height);
198             }
199             tl -> push_back( tmp2 );
200         }
201     }
202
203
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()));
212
213     // lookup the state record
214     geometry->setStateSet(state);
215
216     if ( calc_lights ) {
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");
221                 coverage = 10000;
222             }
223             SGGenRandomSurfacePoints(geometry, coverage, lights);
224         }
225     }
226
227     return geometry;
228 }
229