]> 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
58 static inline
59 osg::Vec3 random_pt_inside_tri(const osg::Vec3& n1, const osg::Vec3& n2,
60                                const osg::Vec3& n3 )
61 {
62     double a = sg_random();
63     double b = sg_random();
64     if ( a + b > 1.0 ) {
65         a = 1.0 - a;
66         b = 1.0 - b;
67     }
68     double c = 1 - a - b;
69
70     return n1*a + n2*b + n3*c;
71 }
72
73 /// class to implement the TrinagleFunctor class
74 struct SGRandomSurfacePointsFill {
75   osg::Vec3Array* lights;
76   float factor;
77
78   void operator () (const osg::Vec3& v1, const osg::Vec3& v2,
79                     const osg::Vec3& v3, bool)
80   {
81     // Compute the area
82     float area = 0.5*((v1 - v2)^(v3 - v2)).length();
83     float num = area / factor;
84     
85     // generate a light point for each unit of area
86     while ( num > 1.0 ) {
87       lights->push_back(random_pt_inside_tri( v1, v2, v3 ));
88       num -= 1.0;
89     }
90     // for partial units of area, use a zombie door method to
91     // create the proper random chance of a light being created
92     // for this triangle
93     if ( num > 0.0 ) {
94       if ( sg_random() <= num ) {
95         // a zombie made it through our door
96         lights->push_back(random_pt_inside_tri( v1, v2, v3 ));
97       }
98     }
99   }
100 };
101
102 static void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor, 
103                                       osg::Vec3Array *lights )
104 {
105   osg::TriangleFunctor<SGRandomSurfacePointsFill> triangleFunctor;
106   triangleFunctor.lights = lights;
107   triangleFunctor.factor = factor;
108   leaf->accept(triangleFunctor);
109 }
110
111
112 ////////////////////////////////////////////////////////////////////////
113 // Scenery loaders.
114 ////////////////////////////////////////////////////////////////////////
115
116 osg::Node* SGMakeLeaf( const string& path,
117                      const GLenum ty, 
118                      SGMaterialLib *matlib, const string& material,
119                      const point_list& nodes, const point_list& normals,
120                      const point_list& texcoords,
121                      const int_list& node_index,
122                      const int_list& normal_index,
123                      const int_list& tex_index,
124                      const bool calc_lights, osg::Vec3Array *lights )
125 {
126     double tex_width = 1000.0, tex_height = 1000.0;
127     osg::StateSet *state = 0;
128     float coverage = -1;
129
130     SGMaterial *mat = matlib->find( material );
131     if ( mat == NULL ) {
132         // see if this is an on the fly texture
133         string file = path;
134         string::size_type pos = file.rfind( "/" );
135         file = file.substr( 0, pos );
136         // cout << "current file = " << file << endl;
137         file += "/";
138         file += material;
139         // cout << "current file = " << file << endl;
140         if ( ! matlib->add_item( file ) ) {
141             SG_LOG( SG_TERRAIN, SG_ALERT, 
142                     "Ack! unknown usemtl name = " << material 
143                     << " in " << path );
144         } else {
145             // locate our newly created material
146             mat = matlib->find( material );
147             if ( mat == NULL ) {
148                 SG_LOG( SG_TERRAIN, SG_ALERT, 
149                         "Ack! bad on the fly material create = "
150                         << material << " in " << path );
151             }
152         }
153     }
154
155     if ( mat != NULL ) {
156         // set the texture width and height values for this
157         // material
158         tex_width = mat->get_xsize();
159         tex_height = mat->get_ysize();
160         state = mat->get_state();
161         coverage = mat->get_light_coverage();
162         // cout << "(w) = " << tex_width << " (h) = "
163         //      << tex_width << endl;
164     } else {
165         coverage = -1;
166     }
167
168     int i;
169
170     // vertices
171     int size = node_index.size();
172     if ( size < 1 ) {
173         SG_LOG( SG_TERRAIN, SG_ALERT, "Woh! node list size < 1" );
174         exit(-1);
175     }
176     osg::Vec3Array* vl = new osg::Vec3Array;
177     vl->reserve(size);
178     for ( i = 0; i < size; ++i ) {
179         Point3D node = nodes[ node_index[i] ];
180         vl->push_back(osg::Vec3(node[0], node[1], node[2]));
181     }
182
183     // normals
184     osg::Vec3Array* nl = new osg::Vec3Array;
185     nl->reserve(size);
186     if ( normal_index.size() ) {
187         // object file specifies normal indices (i.e. normal indices
188         // aren't 'implied'
189         for ( i = 0; i < size; ++i ) {
190             Point3D normal = normals[ normal_index[i] ];
191             nl->push_back(osg::Vec3(normal[0], normal[1], normal[2]));
192         }
193     } else {
194         // use implied normal indices.  normal index = vertex index.
195         for ( i = 0; i < size; ++i ) {
196             Point3D normal = normals[ node_index[i] ];
197             nl->push_back(osg::Vec3(normal[0], normal[1], normal[2]));
198         }
199     }
200
201     // colors
202     osg::Vec4Array* cl = new osg::Vec4Array;
203     cl->push_back(osg::Vec4(1, 1, 1, 1));
204
205     // texture coordinates
206     size = tex_index.size();
207     Point3D texcoord;
208     osg::Vec2Array* tl = new osg::Vec2Array;
209     tl->reserve(size);
210     if ( size == 1 ) {
211         Point3D texcoord = texcoords[ tex_index[0] ];
212         osg::Vec2 tmp2(texcoord[0], texcoord[1]);
213         if ( tex_width > 0 ) {
214             tmp2[0] *= (1000.0 / tex_width);
215         }
216         if ( tex_height > 0 ) {
217             tmp2[1] *= (1000.0 / tex_height);
218         }
219         tl -> push_back( tmp2 );
220     } else if ( size > 1 ) {
221         for ( i = 0; i < size; ++i ) {
222             Point3D texcoord = texcoords[ tex_index[i] ];
223             osg::Vec2 tmp2(texcoord[0], texcoord[1]);
224             if ( tex_width > 0 ) {
225                 tmp2[0] *= (1000.0 / tex_width);
226             }
227             if ( tex_height > 0 ) {
228                 tmp2[1] *= (1000.0 / tex_height);
229             }
230             tl -> push_back( tmp2 );
231         }
232     }
233
234
235     osg::Geometry* geometry = new osg::Geometry;
236     geometry->setVertexArray(vl);
237     geometry->setNormalArray(nl);
238     geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
239     geometry->setColorArray(cl);
240     geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
241     geometry->setTexCoordArray(0, tl);
242     geometry->addPrimitiveSet(new osg::DrawArrays(ty, 0, vl->size()));
243     osg::Geode* geode = new osg::Geode;
244     geode->addDrawable(geometry);
245
246     // lookup the state record
247     geode->setStateSet(state);
248     geode->setUserData( new SGMaterialUserData(mat) );
249
250     if ( calc_lights ) {
251         if ( coverage > 0.0 ) {
252             if ( coverage < 10000.0 ) {
253                 SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
254                        << coverage << ", pushing up to 10000");
255                 coverage = 10000;
256             }
257             SGGenRandomSurfacePoints(geometry, coverage, lights );
258         }
259     }
260
261     return geode;
262 }