]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/leaf.cxx
- commands do now have to start with @
[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 <simgear/debug/logstream.hxx>
37 #include <simgear/math/sg_random.h>
38 #include <simgear/scene/material/mat.hxx>
39 #include <simgear/scene/material/matlib.hxx>
40
41 #include "leaf.hxx"
42
43 SG_USING_STD(string);
44 SG_USING_STD(vector);
45
46
47 typedef vector < int > int_list;
48 typedef int_list::iterator int_list_iterator;
49 typedef int_list::const_iterator int_point_list_iterator;
50
51
52 static void random_pt_inside_tri( float *res,
53                                   float *n1, float *n2, float *n3 )
54 {
55     double a = sg_random();
56     double b = sg_random();
57     if ( a + b > 1.0 ) {
58         a = 1.0 - a;
59         b = 1.0 - b;
60     }
61     double c = 1 - a - b;
62
63     res[0] = n1[0]*a + n2[0]*b + n3[0]*c;
64     res[1] = n1[1]*a + n2[1]*b + n3[1]*c;
65     res[2] = n1[2]*a + n2[2]*b + n3[2]*c;
66 }
67
68
69 void sgGenRandomSurfacePoints( ssgLeaf *leaf, double factor, 
70                                ssgVertexArray *lights )
71 {
72     int tris = leaf->getNumTriangles();
73     if ( tris > 0 ) {
74         short int n1, n2, n3;
75         float *p1, *p2, *p3;
76         sgVec3 result;
77
78         // generate a repeatable random seed
79         p1 = leaf->getVertex( 0 );
80         unsigned int seed = (unsigned int)(fabs(p1[0]*100));
81         sg_srandom( seed );
82
83         for ( int i = 0; i < tris; ++i ) {
84             leaf->getTriangle( i, &n1, &n2, &n3 );
85             p1 = leaf->getVertex(n1);
86             p2 = leaf->getVertex(n2);
87             p3 = leaf->getVertex(n3);
88             double area = sgTriArea( p1, p2, p3 );
89             double num = area / factor;
90
91             // generate a light point for each unit of area
92             while ( num > 1.0 ) {
93                 random_pt_inside_tri( result, p1, p2, p3 );
94                 lights->add( result );
95                 num -= 1.0;
96             }
97             // for partial units of area, use a zombie door method to
98             // create the proper random chance of a light being created
99             // for this triangle
100             if ( num > 0.0 ) {
101                 if ( sg_random() <= num ) {
102                     // a zombie made it through our door
103                     random_pt_inside_tri( result, p1, p2, p3 );
104                     lights->add( result );
105                 }
106             }
107         }
108     }
109 }
110
111
112 ssgVertexArray *sgGenRandomSurfacePoints( ssgLeaf *leaf, double factor ) {
113     ssgVertexArray *result = new ssgVertexArray();
114     sgGenRandomSurfacePoints( leaf, factor, result );
115
116     return result;
117 }
118
119
120 ////////////////////////////////////////////////////////////////////////
121 // Scenery loaders.
122 ////////////////////////////////////////////////////////////////////////
123
124 ssgLeaf *sgMakeLeaf( const string& path,
125                      const GLenum ty, 
126                      SGMaterialLib *matlib, const string& material,
127                      const point_list& nodes, const point_list& normals,
128                      const point_list& texcoords,
129                      const int_list& node_index,
130                      const int_list& normal_index,
131                      const int_list& tex_index,
132                      const bool calc_lights, ssgVertexArray *lights )
133 {
134     double tex_width = 1000.0, tex_height = 1000.0;
135     ssgSimpleState *state = NULL;
136     float coverage = -1;
137
138     SGMaterial *mat = matlib->find( material );
139     if ( mat == NULL ) {
140         // see if this is an on the fly texture
141         string file = path;
142         string::size_type pos = file.rfind( "/" );
143         file = file.substr( 0, pos );
144         // cout << "current file = " << file << endl;
145         file += "/";
146         file += material;
147         // cout << "current file = " << file << endl;
148         if ( ! matlib->add_item( file ) ) {
149             SG_LOG( SG_TERRAIN, SG_ALERT, 
150                     "Ack! unknown usemtl name = " << material 
151                     << " in " << path );
152         } else {
153             // locate our newly created material
154             mat = matlib->find( material );
155             if ( mat == NULL ) {
156                 SG_LOG( SG_TERRAIN, SG_ALERT, 
157                         "Ack! bad on the fly material create = "
158                         << material << " in " << path );
159             }
160         }
161     }
162
163     if ( mat != NULL ) {
164         // set the texture width and height values for this
165         // material
166         tex_width = mat->get_xsize();
167         tex_height = mat->get_ysize();
168         state = mat->get_state();
169         coverage = mat->get_light_coverage();
170         // cout << "(w) = " << tex_width << " (h) = "
171         //      << tex_width << endl;
172     } else {
173         coverage = -1;
174     }
175
176     sgVec2 tmp2;
177     sgVec3 tmp3;
178     sgVec4 tmp4;
179     int i;
180
181     // vertices
182     int size = node_index.size();
183     if ( size < 1 ) {
184         SG_LOG( SG_TERRAIN, SG_ALERT, "Woh! node list size < 1" );
185         exit(-1);
186     }
187     ssgVertexArray *vl = new ssgVertexArray( size );
188     Point3D node;
189     for ( i = 0; i < size; ++i ) {
190         node = nodes[ node_index[i] ];
191         sgSetVec3( tmp3, node[0], node[1], node[2] );
192         vl -> add( tmp3 );
193     }
194
195     // normals
196     Point3D normal;
197     ssgNormalArray *nl = new ssgNormalArray( size );
198     if ( normal_index.size() ) {
199         // object file specifies normal indices (i.e. normal indices
200         // aren't 'implied'
201         for ( i = 0; i < size; ++i ) {
202             normal = normals[ normal_index[i] ];
203             sgSetVec3( tmp3, normal[0], normal[1], normal[2] );
204             nl -> add( tmp3 );
205         }
206     } else {
207         // use implied normal indices.  normal index = vertex index.
208         for ( i = 0; i < size; ++i ) {
209             normal = normals[ node_index[i] ];
210             sgSetVec3( tmp3, normal[0], normal[1], normal[2] );
211             nl -> add( tmp3 );
212         }
213     }
214
215     // colors
216     ssgColourArray *cl = new ssgColourArray( 1 );
217     sgSetVec4( tmp4, 1.0, 1.0, 1.0, 1.0 );
218     cl->add( tmp4 );
219
220     // texture coordinates
221     size = tex_index.size();
222     Point3D texcoord;
223     ssgTexCoordArray *tl = new ssgTexCoordArray( size );
224     if ( size == 1 ) {
225         texcoord = texcoords[ tex_index[0] ];
226         sgSetVec2( tmp2, texcoord[0], texcoord[1] );
227         //sgSetVec2( tmp2, texcoord[0], texcoord[1] );
228         if ( tex_width > 0 ) {
229             tmp2[0] *= (1000.0 / tex_width);
230         }
231         if ( tex_height > 0 ) {
232             tmp2[1] *= (1000.0 / tex_height);
233         }
234         tl -> add( tmp2 );
235     } else if ( size > 1 ) {
236         for ( i = 0; i < size; ++i ) {
237             texcoord = texcoords[ tex_index[i] ];
238             sgSetVec2( tmp2, texcoord[0], texcoord[1] );
239             if ( tex_width > 0 ) {
240                 tmp2[0] *= (1000.0 / tex_width);
241             }
242             if ( tex_height > 0 ) {
243                 tmp2[1] *= (1000.0 / tex_height);
244             }
245             tl -> add( tmp2 );
246         }
247     }
248
249     ssgLeaf *leaf = new ssgVtxTable ( ty, vl, nl, tl, cl );
250
251     // lookup the state record
252
253     leaf->setState( state );
254
255     if ( calc_lights ) {
256         if ( coverage > 0.0 ) {
257             if ( coverage < 10000.0 ) {
258                 SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
259                        << coverage << ", pushing up to 10000");
260                 coverage = 10000;
261             }
262             sgGenRandomSurfacePoints(leaf, coverage, lights );
263         }
264     }
265
266     return leaf;
267 }