]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/leaf.cxx
Add some missing requirements
[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  - curt@flightgear.org
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., 675 Mass Ave, Cambridge, MA 02139, 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 static void gen_random_surface_points( ssgLeaf *leaf, ssgVertexArray *lights,
70                                        double factor ) {
71     int tris = leaf->getNumTriangles();
72     if ( tris > 0 ) {
73         short int n1, n2, n3;
74         float *p1, *p2, *p3;
75         sgVec3 result;
76
77         // generate a repeatable random seed
78         p1 = leaf->getVertex( 0 );
79         unsigned int seed = (unsigned int)(fabs(p1[0]*100));
80         sg_srandom( seed );
81
82         for ( int i = 0; i < tris; ++i ) {
83             leaf->getTriangle( i, &n1, &n2, &n3 );
84             p1 = leaf->getVertex(n1);
85             p2 = leaf->getVertex(n2);
86             p3 = leaf->getVertex(n3);
87             double area = sgTriArea( p1, p2, p3 );
88             double num = area / factor;
89
90             // generate a light point for each unit of area
91             while ( num > 1.0 ) {
92                 random_pt_inside_tri( result, p1, p2, p3 );
93                 lights->add( result );
94                 num -= 1.0;
95             }
96             // for partial units of area, use a zombie door method to
97             // create the proper random chance of a light being created
98             // for this triangle
99             if ( num > 0.0 ) {
100                 if ( sg_random() <= num ) {
101                     // a zombie made it through our door
102                     random_pt_inside_tri( result, p1, p2, p3 );
103                     lights->add( result );
104                 }
105             }
106         }
107     }
108 }
109
110
111
112 ////////////////////////////////////////////////////////////////////////
113 // Scenery loaders.
114 ////////////////////////////////////////////////////////////////////////
115
116 ssgLeaf *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, ssgVertexArray *lights )
125 {
126     double tex_width = 1000.0, tex_height = 1000.0;
127     ssgSimpleState *state = NULL;
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     sgVec2 tmp2;
169     sgVec3 tmp3;
170     sgVec4 tmp4;
171     int i;
172
173     // vertices
174     int size = node_index.size();
175     if ( size < 1 ) {
176         SG_LOG( SG_TERRAIN, SG_ALERT, "Woh! node list size < 1" );
177         exit(-1);
178     }
179     ssgVertexArray *vl = new ssgVertexArray( size );
180     Point3D node;
181     for ( i = 0; i < size; ++i ) {
182         node = nodes[ node_index[i] ];
183         sgSetVec3( tmp3, node[0], node[1], node[2] );
184         vl -> add( tmp3 );
185     }
186
187     // normals
188     Point3D normal;
189     ssgNormalArray *nl = new ssgNormalArray( size );
190     if ( normal_index.size() ) {
191         // object file specifies normal indices (i.e. normal indices
192         // aren't 'implied'
193         for ( i = 0; i < size; ++i ) {
194             normal = normals[ normal_index[i] ];
195             sgSetVec3( tmp3, normal[0], normal[1], normal[2] );
196             nl -> add( tmp3 );
197         }
198     } else {
199         // use implied normal indices.  normal index = vertex index.
200         for ( i = 0; i < size; ++i ) {
201             normal = normals[ node_index[i] ];
202             sgSetVec3( tmp3, normal[0], normal[1], normal[2] );
203             nl -> add( tmp3 );
204         }
205     }
206
207     // colors
208     ssgColourArray *cl = new ssgColourArray( 1 );
209     sgSetVec4( tmp4, 1.0, 1.0, 1.0, 1.0 );
210     cl->add( tmp4 );
211
212     // texture coordinates
213     size = tex_index.size();
214     Point3D texcoord;
215     ssgTexCoordArray *tl = new ssgTexCoordArray( size );
216     if ( size == 1 ) {
217         texcoord = texcoords[ tex_index[0] ];
218         sgSetVec2( tmp2, texcoord[0], texcoord[1] );
219         sgSetVec2( tmp2, texcoord[0], texcoord[1] );
220         if ( tex_width > 0 ) {
221             tmp2[0] *= (1000.0 / tex_width);
222         }
223         if ( tex_height > 0 ) {
224             tmp2[1] *= (1000.0 / tex_height);
225         }
226         tl -> add( tmp2 );
227     } else if ( size > 1 ) {
228         for ( i = 0; i < size; ++i ) {
229             texcoord = texcoords[ tex_index[i] ];
230             sgSetVec2( tmp2, texcoord[0], texcoord[1] );
231             if ( tex_width > 0 ) {
232                 tmp2[0] *= (1000.0 / tex_width);
233             }
234             if ( tex_height > 0 ) {
235                 tmp2[1] *= (1000.0 / tex_height);
236             }
237             tl -> add( tmp2 );
238         }
239     }
240
241     ssgLeaf *leaf = new ssgVtxTable ( ty, vl, nl, tl, cl );
242
243     // lookup the state record
244
245     leaf->setState( state );
246
247     if ( calc_lights ) {
248         if ( coverage > 0.0 ) {
249             if ( coverage < 10000.0 ) {
250                 SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
251                        << coverage << ", pushing up to 10000");
252                 coverage = 10000;
253             }
254             gen_random_surface_points(leaf, lights, coverage);
255         }
256     }
257
258     return leaf;
259 }