]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/cloud.cxx
Harald JOHNSEN:
[simgear.git] / simgear / scene / sky / cloud.cxx
1 // cloud.cxx -- model a single cloud layer
2 //
3 // Written by Curtis Olson, started June 2000.
4 //
5 // Copyright (C) 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
6 //
7 // This program is distributed in the hope that it will be useful, but
8 // WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // General Public License for more details.
11 //
12 // You should have received a copy of the GNU General Public License
13 // along with this program; if not, write to the Free Software
14 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 //
16 // $Id$
17
18
19 #include <simgear/compiler.h>
20
21 // #include <stdio.h>
22 #include <math.h>
23
24 #if defined (__APPLE__)
25 // any C++ header file undefines isinf and isnan
26 // so this should be included before <iostream>
27 inline int (isinf)(double r) { return isinf(r); }
28 inline int (isnan)(double r) { return isnan(r); } 
29 #endif
30
31 #include <plib/sg.h>
32 #include <plib/ssg.h>
33
34 #include <simgear/math/point3d.hxx>
35 #include <simgear/math/polar3d.hxx>
36 #include <simgear/math/sg_random.h>
37 #include <simgear/debug/logstream.hxx>
38 #include <simgear/misc/sg_path.hxx>
39 #include <simgear/screen/extensions.hxx>
40 #include <simgear/screen/texture.hxx>
41
42 #include "newcloud.hxx"
43 #include "cloudfield.hxx"
44 #include "cloud.hxx"
45
46 #if defined(__MINGW32__)
47 #define isnan(x) _isnan(x)
48 #endif
49
50 #if defined (__FreeBSD__)
51 #  if __FreeBSD_version < 500000
52      extern "C" {
53        inline int isnan(double r) { return !(r <= 0 || r >= 0); }
54      }
55 #  endif
56 #endif
57
58
59 static ssgStateSelector *layer_states[SGCloudLayer::SG_MAX_CLOUD_COVERAGES];
60 static bool state_initialized = false;
61 static bool bump_mapping = false;
62 static GLint nb_texture_unit = 0;
63 static ssgTexture *normal_map[SGCloudLayer::SG_MAX_CLOUD_COVERAGES][2] = { 0 };
64 static ssgTexture *color_map[SGCloudLayer::SG_MAX_CLOUD_COVERAGES][2] = { 0 };
65 static GLuint normalization_cube_map;
66
67 static glActiveTextureProc glActiveTexturePtr = 0;
68 static glClientActiveTextureProc glClientActiveTexturePtr = 0;
69 static glBlendColorProc glBlendColorPtr = 0;
70
71 bool SGCloudLayer::enable_bump_mapping = false;
72
73 static void
74 generateNormalizationCubeMap()
75 {
76     unsigned char data[ 32 * 32 * 3 ];
77     const int size = 32;
78     const float half_size = 16.0f,
79                 offset = 0.5f;
80     sgVec3 zero_normal;
81     sgSetVec3( zero_normal, 0.5f, 0.5f, 0.5f );
82     int i, j;
83
84     unsigned char *ptr = data;
85     for ( j = 0; j < size; j++ ) {
86         for ( i = 0; i < size; i++ ) {
87             sgVec3 tmp;
88             sgSetVec3( tmp, half_size,
89                             -( j + offset - half_size ),
90                             -( i + offset - half_size ) );
91             sgNormalizeVec3( tmp );
92             sgScaleVec3( tmp, 0.5f );
93             sgAddVec3( tmp, zero_normal );
94
95             *ptr++ = (unsigned char)( tmp[ 0 ] * 255 );
96             *ptr++ = (unsigned char)( tmp[ 1 ] * 255 );
97             *ptr++ = (unsigned char)( tmp[ 2 ] * 255 );
98         }
99     }
100     glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
101                   0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
102
103     ptr = data;
104     for ( j = 0; j < size; j++ ) {
105         for ( i = 0; i < size; i++ ) {
106             sgVec3 tmp;
107             sgSetVec3( tmp, -half_size,
108                             -( j + offset - half_size ),
109                             ( i + offset - half_size ) );
110             sgNormalizeVec3( tmp );
111             sgScaleVec3( tmp, 0.5f );
112             sgAddVec3( tmp, zero_normal );
113
114             *ptr++ = (unsigned char)( tmp[ 0 ] * 255 );
115             *ptr++ = (unsigned char)( tmp[ 1 ] * 255 );
116             *ptr++ = (unsigned char)( tmp[ 2 ] * 255 );
117         }
118     }
119     glTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
120                   0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
121
122     ptr = data;
123     for ( j = 0; j < size; j++ ) {
124         for ( i = 0; i < size; i++ ) {
125             sgVec3 tmp;
126             sgSetVec3( tmp, ( i + offset - half_size ),
127                             half_size,
128                             ( j + offset - half_size ) );
129             sgNormalizeVec3( tmp );
130             sgScaleVec3( tmp, 0.5f );
131             sgAddVec3( tmp, zero_normal );
132
133             *ptr++ = (unsigned char)( tmp[ 0 ] * 255 );
134             *ptr++ = (unsigned char)( tmp[ 1 ] * 255 );
135             *ptr++ = (unsigned char)( tmp[ 2 ] * 255 );
136         }
137     }
138     glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
139                   0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
140
141     ptr = data;
142     for ( j = 0; j < size; j++ ) {
143         for ( i = 0; i < size; i++ ) {
144             sgVec3 tmp;
145             sgSetVec3( tmp, ( i + offset - half_size ),
146                             -half_size,
147                             -( j + offset - half_size ) );
148             sgNormalizeVec3( tmp );
149             sgScaleVec3( tmp, 0.5f );
150             sgAddVec3( tmp, zero_normal );
151
152             *ptr++ = (unsigned char)( tmp[ 0 ] * 255 );
153             *ptr++ = (unsigned char)( tmp[ 1 ] * 255 );
154             *ptr++ = (unsigned char)( tmp[ 2 ] * 255 );
155         }
156     }
157     glTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
158                   0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
159
160     ptr = data;
161     for ( j = 0; j < size; j++ ) {
162         for ( i = 0; i < size; i++ ) {
163             sgVec3 tmp;
164             sgSetVec3( tmp, ( i + offset - half_size ),
165                             -( j + offset - half_size ),
166                             half_size );
167             sgNormalizeVec3( tmp );
168             sgScaleVec3( tmp, 0.5f );
169             sgAddVec3( tmp, zero_normal );
170
171             *ptr++ = (unsigned char)( tmp[ 0 ] * 255 );
172             *ptr++ = (unsigned char)( tmp[ 1 ] * 255 );
173             *ptr++ = (unsigned char)( tmp[ 2 ] * 255 );
174         }
175     }
176     glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
177                   0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
178
179     ptr = data;
180     for ( j = 0; j < size; j++ ) {
181         for ( i = 0; i < size; i++ ) {
182             sgVec3 tmp;
183             sgSetVec3( tmp, -( i + offset - half_size ),
184                             -( j + offset - half_size ),
185                             -half_size );
186             sgNormalizeVec3( tmp );
187             sgScaleVec3( tmp, 0.5f );
188             sgAddVec3( tmp, zero_normal );
189
190             *ptr++ = (unsigned char)( tmp[ 0 ] * 255 );
191             *ptr++ = (unsigned char)( tmp[ 1 ] * 255 );
192             *ptr++ = (unsigned char)( tmp[ 2 ] * 255 );
193         }
194     }
195     glTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
196                   0, GL_RGBA8, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
197 }
198
199
200 // Constructor
201 SGCloudLayer::SGCloudLayer( const string &tex_path ) :
202     vertices(0),
203     indices(0),
204     layer_root(new ssgRoot),
205     layer_transform(new ssgTransform),
206     state_sel(0),
207     cloud_alpha(1.0),
208     texture_path(tex_path),
209     layer_span(0.0),
210     layer_asl(0.0),
211     layer_thickness(0.0),
212     layer_transition(0.0),
213     layer_coverage(SG_CLOUD_CLEAR),
214     scale(4000.0),
215     speed(0.0),
216     direction(0.0),
217     last_lon(0.0),
218     last_lat(0.0)
219 {
220     cl[0] = cl[1] = cl[2] = cl[3] = NULL;
221     vl[0] = vl[1] = vl[2] = vl[3] = NULL;
222     tl[0] = tl[1] = tl[2] = tl[3] = NULL;
223     layer[0] = layer[1] = layer[2] = layer[3] = NULL;
224
225     layer_root->addKid(layer_transform);
226         layer3D = new SGCloudField;
227     rebuild();
228 }
229
230 // Destructor
231 SGCloudLayer::~SGCloudLayer()
232 {
233         delete layer3D;
234     delete vertices;
235     delete indices;
236     delete layer_root;          // deletes layer_transform and layer as well
237 }
238
239 float
240 SGCloudLayer::getSpan_m () const
241 {
242     return layer_span;
243 }
244
245 void
246 SGCloudLayer::setSpan_m (float span_m)
247 {
248     if (span_m != layer_span) {
249         layer_span = span_m;
250         rebuild();
251     }
252 }
253
254 float
255 SGCloudLayer::getElevation_m () const
256 {
257     return layer_asl;
258 }
259
260 void
261 SGCloudLayer::setElevation_m (float elevation_m, bool set_span)
262 {
263     layer_asl = elevation_m;
264
265     if (set_span) {
266         if (elevation_m > 4000)
267             setSpan_m(  elevation_m * 10 );
268         else
269             setSpan_m( 40000 );
270     }
271 }
272
273 float
274 SGCloudLayer::getThickness_m () const
275 {
276     return layer_thickness;
277 }
278
279 void
280 SGCloudLayer::setThickness_m (float thickness_m)
281 {
282     layer_thickness = thickness_m;
283 }
284
285 float
286 SGCloudLayer::getTransition_m () const
287 {
288     return layer_transition;
289 }
290
291 void
292 SGCloudLayer::setTransition_m (float transition_m)
293 {
294     layer_transition = transition_m;
295 }
296
297 SGCloudLayer::Coverage
298 SGCloudLayer::getCoverage () const
299 {
300     return layer_coverage;
301 }
302
303 void
304 SGCloudLayer::setCoverage (Coverage coverage)
305 {
306     if (coverage != layer_coverage) {
307         layer_coverage = coverage;
308         rebuild();
309     }
310 }
311
312
313 // build the cloud object
314 void
315 SGCloudLayer::rebuild()
316 {
317     // Initialize states and sizes if necessary.
318     if ( !state_initialized ) { 
319         state_initialized = true;
320
321         SG_LOG(SG_ASTRO, SG_INFO, "initializing cloud layers");
322
323         bump_mapping = SGIsOpenGLExtensionSupported("GL_ARB_multitexture") &&
324                        SGIsOpenGLExtensionSupported("GL_ARB_texture_cube_map") &&
325                        SGIsOpenGLExtensionSupported("GL_ARB_texture_env_combine") &&
326                        SGIsOpenGLExtensionSupported("GL_ARB_texture_env_dot3") && 
327                        SGIsOpenGLExtensionSupported("GL_ARB_imaging");
328
329         if ( bump_mapping ) {
330             glGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &nb_texture_unit );
331             if ( nb_texture_unit < 2 ) {
332                 bump_mapping = false;
333             }
334             //nb_texture_unit = 2; // Force the number of units for now
335         }
336
337         if ( bump_mapping ) {
338
339             // This bump mapping code was inspired by the tutorial available at 
340             // http://www.paulsprojects.net/tutorials/simplebump/simplebump.html
341             // and a NVidia white paper 
342             //  http://developer.nvidia.com/object/bumpmappingwithregistercombiners.html
343             // The normal map textures were generated by the normal map Gimp plugin :
344             //  http://nifelheim.dyndns.org/~cocidius/normalmap/
345             //
346             SGPath cloud_path;
347
348             glActiveTexturePtr = (glActiveTextureProc)SGLookupFunction("glActiveTextureARB");
349             glClientActiveTexturePtr = (glClientActiveTextureProc)SGLookupFunction("glClientActiveTextureARB");
350             glBlendColorPtr = (glBlendColorProc)SGLookupFunction("glBlendColor");
351
352             cloud_path.set(texture_path.str());
353             cloud_path.append("overcast.rgb");
354             color_map[ SG_CLOUD_OVERCAST ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
355             color_map[ SG_CLOUD_OVERCAST ][ 0 ]->ref();
356             cloud_path.set(texture_path.str());
357             cloud_path.append("overcast_n.rgb");
358             normal_map[ SG_CLOUD_OVERCAST ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
359             normal_map[ SG_CLOUD_OVERCAST ][ 0 ]->ref();
360
361             cloud_path.set(texture_path.str());
362             cloud_path.append("overcast_top.rgb");
363             color_map[ SG_CLOUD_OVERCAST ][ 1 ] = new ssgTexture( cloud_path.str().c_str() );
364             color_map[ SG_CLOUD_OVERCAST ][ 1 ]->ref();
365             cloud_path.set(texture_path.str());
366             cloud_path.append("overcast_top_n.rgb");
367             normal_map[ SG_CLOUD_OVERCAST ][ 1 ] = new ssgTexture( cloud_path.str().c_str() );
368             normal_map[ SG_CLOUD_OVERCAST ][ 1 ]->ref();
369
370             cloud_path.set(texture_path.str());
371             cloud_path.append("broken.rgba");
372             color_map[ SG_CLOUD_BROKEN ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
373             color_map[ SG_CLOUD_BROKEN ][ 0 ]->ref();
374             cloud_path.set(texture_path.str());
375             cloud_path.append("broken_n.rgb");
376             normal_map[ SG_CLOUD_BROKEN ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
377             normal_map[ SG_CLOUD_BROKEN ][ 0 ]->ref();
378
379             cloud_path.set(texture_path.str());
380             cloud_path.append("scattered.rgba");
381             color_map[ SG_CLOUD_SCATTERED ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
382             color_map[ SG_CLOUD_SCATTERED ][ 0 ]->ref();
383             cloud_path.set(texture_path.str());
384             cloud_path.append("scattered_n.rgb");
385             normal_map[ SG_CLOUD_SCATTERED ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
386             normal_map[ SG_CLOUD_SCATTERED ][ 0 ]->ref();
387
388             cloud_path.set(texture_path.str());
389             cloud_path.append("few.rgba");
390             color_map[ SG_CLOUD_FEW ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
391             color_map[ SG_CLOUD_FEW ][ 0 ]->ref();
392             cloud_path.set(texture_path.str());
393             cloud_path.append("few_n.rgb");
394             normal_map[ SG_CLOUD_FEW ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
395             normal_map[ SG_CLOUD_FEW ][ 0 ]->ref();
396
397             cloud_path.set(texture_path.str());
398             cloud_path.append("cirrus.rgba");
399             color_map[ SG_CLOUD_CIRRUS ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
400             color_map[ SG_CLOUD_CIRRUS ][ 0 ]->ref();
401             cloud_path.set(texture_path.str());
402             cloud_path.append("cirrus_n.rgb");
403             normal_map[ SG_CLOUD_CIRRUS ][ 0 ] = new ssgTexture( cloud_path.str().c_str() );
404             normal_map[ SG_CLOUD_CIRRUS ][ 0 ]->ref();
405
406             glGenTextures( 1, &normalization_cube_map );
407             glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, normalization_cube_map );
408             generateNormalizationCubeMap();
409             glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
410             glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
411             glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
412             glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
413             glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
414         } /* else */ {
415             SGPath cloud_path;
416             ssgStateSelector *state_sel;
417             ssgSimpleState *state;
418
419             state_sel = new ssgStateSelector( 2 );
420             state_sel->ref();
421             cloud_path.set(texture_path.str());
422             cloud_path.append("overcast.rgb");
423             state_sel->setStep( 0, sgCloudMakeState(cloud_path.str()) );
424             cloud_path.set(texture_path.str());
425             cloud_path.append("overcast_top.rgb");
426             state_sel->setStep( 1, sgCloudMakeState(cloud_path.str()) );
427             layer_states[SG_CLOUD_OVERCAST] = state_sel;
428
429             state_sel = new ssgStateSelector( 2 );
430             state_sel->ref();
431             cloud_path.set(texture_path.str());
432             cloud_path.append("broken.rgba");
433             state = sgCloudMakeState(cloud_path.str());
434             state_sel->setStep( 0, state );
435             state_sel->setStep( 1, state );
436             layer_states[SG_CLOUD_BROKEN] = state_sel;
437
438             state_sel = new ssgStateSelector( 2 );
439             state_sel->ref();
440             cloud_path.set(texture_path.str());
441             cloud_path.append("scattered.rgba");
442             state = sgCloudMakeState(cloud_path.str());
443             state_sel->setStep( 0, state );
444             state_sel->setStep( 1, state );
445             layer_states[SG_CLOUD_SCATTERED] = state_sel;
446
447             state_sel = new ssgStateSelector( 2 );
448             state_sel->ref();
449             cloud_path.set(texture_path.str());
450             cloud_path.append("few.rgba");
451             state = sgCloudMakeState(cloud_path.str());
452             state_sel->setStep( 0, state );
453             state_sel->setStep( 1, state );
454             layer_states[SG_CLOUD_FEW] = state_sel;
455
456             state_sel = new ssgStateSelector( 2 );
457             state_sel->ref();
458             cloud_path.set(texture_path.str());
459             cloud_path.append("cirrus.rgba");
460             state = sgCloudMakeState(cloud_path.str());
461             state_sel->setStep( 0, state );
462             state_sel->setStep( 1, state );
463             layer_states[SG_CLOUD_CIRRUS] = state_sel;
464
465             layer_states[SG_CLOUD_CLEAR] = 0;
466         }
467                 SGNewCloud::loadTextures(texture_path.str());
468                 layer3D->buildTestLayer();
469     }
470
471     if ( bump_mapping ) {
472
473         if ( !vertices ) {
474             vertices = new CloudVertex[ 25 ];
475             indices = new unsigned int[ 40 ];
476         }
477
478         sgVec2 base;
479         sgSetVec2( base, sg_random(), sg_random() );
480
481         const float layer_scale = layer_span / scale;
482         const float layer_to_core = (SG_EARTH_RAD * 1000 + layer_asl);
483         const float half_angle = 0.5 * layer_span / layer_to_core;
484
485         int i;
486         for ( i = -2; i <= 2; i++ ) {
487             for ( int j = -2; j <= 2; j++ ) {
488                 CloudVertex &v1 = vertices[ (i+2)*5 + (j+2) ];
489                 sgSetVec3( v1.position,
490                            0.5 * i * layer_span,
491                            0.5 * j * layer_span,
492                            -layer_to_core * ( 1 - cos( i * half_angle ) * cos( j * half_angle ) ) );
493                 sgSetVec2( v1.texCoord,
494                            base[0] + layer_scale * i * 0.25,
495                            base[1] + layer_scale * j * 0.25 );
496                 sgSetVec3( v1.sTangent,
497                            cos( i * half_angle ),
498                            0.f,
499                            -sin( i * half_angle ) );
500                 sgSetVec3( v1.tTangent,
501                            0.f,
502                            cos( j * half_angle ),
503                            -sin( j * half_angle ) );
504                 sgVectorProductVec3( v1.normal, v1.tTangent, v1.sTangent );
505                 sgSetVec4( v1.color, 1.0f, 1.0f, 1.0f, (i == 0) ? 0.0f : cloud_alpha * 0.15f );
506             }
507         }
508         /*
509          * 0 1 5 6 10 11 15 16 20 21
510          * 1 2 6 7 11 12 16 17 21 22
511          * 2 3 7 8 12 13 17 18 22 23
512          * 3 4 8 9 13 14 18 19 23 24
513          */
514         for ( i = 0; i < 4; i++ ) {
515             for ( int j = 0; j < 5; j++ ) {
516                 indices[ i*10 + (j*2) ]     =     i + 5 * j;
517                 indices[ i*10 + (j*2) + 1 ] = 1 + i + 5 * j;
518             }
519         }
520
521     } /* else */ {
522
523         scale = 4000.0;
524         last_lon = last_lat = -999.0f;
525
526         sgVec2 base;
527         sgSetVec2( base, sg_random(), sg_random() );
528
529         // build the cloud layer
530         sgVec4 color;
531         sgVec3 vertex;
532         sgVec2 tc;
533
534         const float layer_scale = layer_span / scale;
535         const float mpi = SG_PI/4;
536
537         // caclculate the difference between a flat-earth model and 
538         // a round earth model given the span and altutude ASL of
539         // the cloud layer. This is the difference in altitude between
540         // the top of the inverted bowl and the edge of the bowl.
541         // const float alt_diff = layer_asl * 0.8;
542         const float layer_to_core = (SG_EARTH_RAD * 1000 + layer_asl);
543         const float layer_angle = 0.5*layer_span / layer_to_core; // The angle is half the span
544         const float border_to_core = layer_to_core * cos(layer_angle);
545         const float alt_diff = layer_to_core - border_to_core;
546
547         for (int i = 0; i < 4; i++)
548         {
549             if ( layer[i] != NULL ) {
550                 layer_transform->removeKid(layer[i]); // automatic delete
551             }
552
553             vl[i] = new ssgVertexArray( 10 );
554             cl[i] = new ssgColourArray( 10 );
555             tl[i] = new ssgTexCoordArray( 10 );
556
557
558             sgSetVec3( vertex, layer_span*(i-2)/2, -layer_span,
559                             alt_diff * (sin(i*mpi) - 2) );
560
561             sgSetVec2( tc, base[0] + layer_scale * i/4, base[1] );
562
563             sgSetVec4( color, 1.0f, 1.0f, 1.0f, (i == 0) ? 0.0f : 0.15f );
564
565             cl[i]->add( color );
566             vl[i]->add( vertex );
567             tl[i]->add( tc );
568
569             for (int j = 0; j < 4; j++)
570             {
571                 sgSetVec3( vertex, layer_span*(i-1)/2, layer_span*(j-2)/2,
572                                 alt_diff * (sin((i+1)*mpi) + sin(j*mpi) - 2) );
573
574                 sgSetVec2( tc, base[0] + layer_scale * (i+1)/4,
575                             base[1] + layer_scale * j/4 );
576
577                 sgSetVec4( color, 1.0f, 1.0f, 1.0f,
578                                 ( (j == 0) || (i == 3)) ?  
579                                 ( (j == 0) && (i == 3)) ? 0.0f : 0.15f : 1.0f );
580
581                 cl[i]->add( color );
582                 vl[i]->add( vertex );
583                 tl[i]->add( tc );
584
585
586                 sgSetVec3( vertex, layer_span*(i-2)/2, layer_span*(j-1)/2,
587                                 alt_diff * (sin(i*mpi) + sin((j+1)*mpi) - 2) );
588
589                 sgSetVec2( tc, base[0] + layer_scale * i/4,
590                             base[1] + layer_scale * (j+1)/4 );
591
592                 sgSetVec4( color, 1.0f, 1.0f, 1.0f,
593                                 ((j == 3) || (i == 0)) ?
594                                 ((j == 3) && (i == 0)) ? 0.0f : 0.15f : 1.0f );
595                 cl[i]->add( color );
596                 vl[i]->add( vertex );
597                 tl[i]->add( tc );
598             }
599
600             sgSetVec3( vertex, layer_span*(i-1)/2, layer_span, 
601                             alt_diff * (sin((i+1)*mpi) - 2) );
602
603             sgSetVec2( tc, base[0] + layer_scale * (i+1)/4,
604                         base[1] + layer_scale );
605
606             sgSetVec4( color, 1.0f, 1.0f, 1.0f, (i == 3) ? 0.0f : 0.15f );
607
608             cl[i]->add( color );
609             vl[i]->add( vertex );
610             tl[i]->add( tc );
611
612             layer[i] = new ssgVtxTable(GL_TRIANGLE_STRIP, vl[i], NULL, tl[i], cl[i]);
613             layer_transform->addKid( layer[i] );
614
615             if ( layer_states[layer_coverage] != NULL ) {
616                 layer[i]->setState( layer_states[layer_coverage] );
617             }
618             state_sel = layer_states[layer_coverage];
619         }
620
621         // force a repaint of the sky colors with arbitrary defaults
622         repaint( color );
623     }
624 }
625
626
627 // repaint the cloud layer colors
628 bool SGCloudLayer::repaint( sgVec3 fog_color ) {
629
630     if ( bump_mapping && enable_bump_mapping ) {
631
632         for ( int i = 0; i < 25; i++ ) {
633             sgCopyVec3( vertices[ i ].color, fog_color );
634         }
635
636     } else {
637         float *color;
638
639         for ( int i = 0; i < 4; i++ ) {
640             color = cl[i]->get( 0 );
641             sgCopyVec3( color, fog_color );
642             color[3] = (i == 0) ? 0.0f : cloud_alpha * 0.15f;
643
644             for ( int j = 0; j < 4; ++j ) {
645                 color = cl[i]->get( (2*j) + 1 );
646                 sgCopyVec3( color, fog_color );
647                 color[3] = 
648                     ((j == 0) || (i == 3)) ?
649                     ((j == 0) && (i == 3)) ? 0.0f : cloud_alpha * 0.15f : cloud_alpha;
650
651                 color = cl[i]->get( (2*j) + 2 );
652                 sgCopyVec3( color, fog_color );
653                 color[3] = 
654                     ((j == 3) || (i == 0)) ?
655                     ((j == 3) && (i == 0)) ? 0.0f : cloud_alpha * 0.15f : cloud_alpha;
656             }
657
658             color = cl[i]->get( 9 );
659             sgCopyVec3( color, fog_color );
660             color[3] = (i == 3) ? 0.0f : cloud_alpha * 0.15f;
661         }
662     }
663
664     return true;
665 }
666
667 // reposition the cloud layer at the specified origin and orientation
668 // lon specifies a rotation about the Z axis
669 // lat specifies a rotation about the new Y axis
670 // spin specifies a rotation about the new Z axis (and orients the
671 // sunrise/set effects
672 bool SGCloudLayer::reposition( sgVec3 p, sgVec3 up, double lon, double lat,
673                                double alt, double dt )
674 {
675     sgMat4 T1, LON, LAT;
676     sgVec3 axis;
677
678     // combine p and asl (meters) to get translation offset
679     sgVec3 asl_offset;
680     sgCopyVec3( asl_offset, up );
681     sgNormalizeVec3( asl_offset );
682     if ( alt <= layer_asl ) {
683         sgScaleVec3( asl_offset, layer_asl );
684     } else {
685         sgScaleVec3( asl_offset, layer_asl + layer_thickness );
686     }
687     // cout << "asl_offset = " << asl_offset[0] << "," << asl_offset[1]
688     //      << "," << asl_offset[2] << endl;
689     sgAddVec3( asl_offset, p );
690     // cout << "  asl_offset = " << asl_offset[0] << "," << asl_offset[1]
691     //      << "," << asl_offset[2] << endl;
692
693     // Translate to zero elevation
694     // Point3D zero_elev = current_view.get_cur_zero_elev();
695     sgMakeTransMat4( T1, asl_offset );
696
697     // printf("  Translated to %.2f %.2f %.2f\n", 
698     //        zero_elev.x, zero_elev.y, zero_elev.z );
699
700     // Rotate to proper orientation
701     // printf("  lon = %.2f  lat = %.2f\n", 
702     //        lon * SGD_RADIANS_TO_DEGREES,
703     //        lat * SGD_RADIANS_TO_DEGREES);
704     sgSetVec3( axis, 0.0, 0.0, 1.0 );
705     sgMakeRotMat4( LON, lon * SGD_RADIANS_TO_DEGREES, axis );
706
707     sgSetVec3( axis, 0.0, 1.0, 0.0 );
708     sgMakeRotMat4( LAT, 90.0 - lat * SGD_RADIANS_TO_DEGREES, axis );
709
710     sgMat4 TRANSFORM;
711
712     sgCopyMat4( TRANSFORM, T1 );
713     sgPreMultMat4( TRANSFORM, LON );
714     sgPreMultMat4( TRANSFORM, LAT );
715
716     sgCoord layerpos;
717     sgSetCoord( &layerpos, TRANSFORM );
718
719     layer_transform->setTransform( &layerpos );
720
721     // now calculate update texture coordinates
722     if ( last_lon < -900 ) {
723         last_lon = lon;
724         last_lat = lat;
725     }
726
727     double sp_dist = speed*dt;
728
729     if ( lon != last_lon || lat != last_lat || sp_dist != 0 ) {
730         Point3D start( last_lon, last_lat, 0.0 );
731         Point3D dest( lon, lat, 0.0 );
732         double course = 0.0, dist = 0.0;
733
734         calc_gc_course_dist( dest, start, &course, &dist );
735         // cout << "course = " << course << ", dist = " << dist << endl;
736
737         // if start and dest are too close together,
738         // calc_gc_course_dist() can return a course of "nan".  If
739         // this happens, lets just use the last known good course.
740         // This is a hack, and it would probably be better to make
741         // calc_gc_course_dist() more robust.
742         if ( isnan(course) ) {
743             course = last_course;
744         } else {
745             last_course = course;
746         }
747
748         // calculate cloud movement due to external forces
749         double ax = 0.0, ay = 0.0, bx = 0.0, by = 0.0;
750
751         if (dist > 0.0) {
752             ax = cos(course) * dist;
753             ay = sin(course) * dist;
754         }
755
756         if (sp_dist > 0) {
757             bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
758             by = sin((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
759         }
760
761
762         double xoff = (ax + bx) / (2 * scale);
763         double yoff = (ay + by) / (2 * scale);
764
765         const float layer_scale = layer_span / scale;
766
767         // cout << "xoff = " << xoff << ", yoff = " << yoff << endl;
768
769         float *base;
770         if ( bump_mapping && enable_bump_mapping ) {
771             base = vertices[12].texCoord;
772         } else {
773             base = tl[0]->get( 0 );
774         }
775         base[0] += xoff;
776
777         // the while loops can lead to *long* pauses if base[0] comes
778         // with a bogus value.
779         // while ( base[0] > 1.0 ) { base[0] -= 1.0; }
780         // while ( base[0] < 0.0 ) { base[0] += 1.0; }
781         if ( base[0] > -10.0 && base[0] < 10.0 ) {
782             base[0] -= (int)base[0];
783         } else {
784             SG_LOG(SG_ASTRO, SG_DEBUG,
785                 "Error: base = " << base[0] << "," << base[1] <<
786                 " course = " << course << " dist = " << dist );
787             base[0] = 0.0;
788         }
789
790         base[1] += yoff;
791         // the while loops can lead to *long* pauses if base[0] comes
792         // with a bogus value.
793         // while ( base[1] > 1.0 ) { base[1] -= 1.0; }
794         // while ( base[1] < 0.0 ) { base[1] += 1.0; }
795         if ( base[1] > -10.0 && base[1] < 10.0 ) {
796             base[1] -= (int)base[1];
797         } else {
798             SG_LOG(SG_ASTRO, SG_ALERT,
799                     "Error: base = " << base[0] << "," << base[1] <<
800                     " course = " << course << " dist = " << dist );
801             base[1] = 0.0;
802         }
803
804         if ( bump_mapping && enable_bump_mapping ) {
805
806             for ( int i = -2; i <= 2; i++ ) {
807                 for ( int j = -2; j <= 2; j++ ) {
808                     if ( i == 0 && j == 0 )
809                         continue; // Already done on base
810                     CloudVertex &v1 = vertices[ (i+2)*5 + (j+2) ];
811                     sgSetVec2( v1.texCoord,
812                             base[0] + layer_scale * i * 0.25,
813                             base[1] + layer_scale * j * 0.25 );
814                 }
815             }
816
817         } else {
818                 // cout << "base = " << base[0] << "," << base[1] << endl;
819
820             float *tc;
821             for (int i = 0; i < 4; i++) {
822                 tc = tl[i]->get( 0 );
823                 sgSetVec2( tc, base[0] + layer_scale * i/4, base[1] );
824                 
825                 for (int j = 0; j < 4; j++)
826                 {
827                     tc = tl[i]->get( j*2+1 );
828                     sgSetVec2( tc, base[0] + layer_scale * (i+1)/4,
829                                 base[1] + layer_scale * j/4 );
830         
831                     tc = tl[i]->get( (j+1)*2 );
832                     sgSetVec2( tc, base[0] + layer_scale * i/4,
833                                 base[1] + layer_scale * (j+1)/4 );
834                 }
835         
836                 tc = tl[i]->get( 9 );
837                 sgSetVec2( tc, base[0] + layer_scale * (i+1)/4,
838                             base[1] + layer_scale );
839             }
840         }
841
842         last_lon = lon;
843         last_lat = lat;
844     }
845
846         layer3D->reposition( p, up, lon, lat, alt, dt, direction, speed);
847     return true;
848 }
849
850
851 void SGCloudLayer::draw( bool top ) {
852     if ( layer_coverage != SG_CLOUD_CLEAR ) {
853
854                 if ( SGCloudField::enable3D && layer3D->is3D())
855                         layer3D->Render();
856                 else
857         if ( bump_mapping && enable_bump_mapping ) {
858
859             sgMat4 modelview,
860                    tmp,
861                    transform;
862             ssgGetModelviewMatrix( modelview );
863             layer_transform->getTransform( transform );
864
865             sgTransposeNegateMat4( tmp, transform );
866
867             sgPostMultMat4( transform, modelview );
868             ssgLoadModelviewMatrix( transform );
869
870             sgVec3 lightVec;
871             ssgGetLight( 0 )->getPosition( lightVec );
872             sgNegateVec3( lightVec );
873             sgXformVec3( lightVec, tmp );
874
875             for ( int i = 0; i < 25; i++ ) {
876                 CloudVertex &v = vertices[ i ];
877                 sgSetVec3( v.tangentSpLight,
878                            sgScalarProductVec3( v.sTangent, lightVec ),
879                            sgScalarProductVec3( v.tTangent, lightVec ),
880                            sgScalarProductVec3( v.normal, lightVec ) );
881             }
882
883             ssgTexture *decal = color_map[ layer_coverage ][ top ? 1 : 0 ];
884             if ( top && decal == 0 ) {
885                 decal = color_map[ layer_coverage ][ 0 ];
886             }
887             ssgTexture *normal = normal_map[ layer_coverage ][ top ? 1 : 0 ];
888             if ( top && normal == 0 ) {
889                 normal = normal_map[ layer_coverage ][ 0 ];
890             }
891
892             glDisable( GL_LIGHTING );
893             glDisable( GL_CULL_FACE );
894 //            glDisable( GL_ALPHA_TEST );
895             if ( layer_coverage == SG_CLOUD_FEW ) {
896                 glEnable( GL_ALPHA_TEST );
897                 glAlphaFunc ( GL_GREATER, 0.01 );
898             }
899             glEnable( GL_BLEND ); 
900             glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
901
902             glShadeModel( GL_SMOOTH );
903             glEnable( GL_COLOR_MATERIAL ); 
904             sgVec4 color;
905             float emis = 0.05;
906             if ( 1 ) {
907                 ssgGetLight( 0 )->getColour( GL_DIFFUSE, color );
908                 emis = ( color[0]+color[1]+color[2] ) / 3.0;
909                 if ( emis < 0.05 )
910                     emis = 0.05;
911             }
912             sgSetVec4( color, emis, emis, emis, 0.0 );
913             glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, color );
914             sgSetVec4( color, 1.0f, 1.0f, 1.0f, 0.0 );
915             glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, color );
916             sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
917             glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, color );
918             sgSetVec4( color, 0.0, 0.0, 0.0, 0.0 );
919             glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, color );
920
921             glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
922
923             glActiveTexturePtr( GL_TEXTURE0_ARB );
924             glBindTexture( GL_TEXTURE_2D, normal->getHandle() );
925             glEnable( GL_TEXTURE_2D );
926
927             //Bind normalisation cube map to texture unit 1
928             glActiveTexturePtr( GL_TEXTURE1_ARB );
929             glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, normalization_cube_map );
930             glEnable( GL_TEXTURE_CUBE_MAP_ARB );
931             glActiveTexturePtr( GL_TEXTURE0_ARB );
932
933             //Set vertex arrays for cloud
934             glVertexPointer( 3, GL_FLOAT, sizeof(CloudVertex), &vertices[0].position );
935             glEnableClientState( GL_VERTEX_ARRAY );
936 /*
937             if ( nb_texture_unit >= 3 ) {
938                 glColorPointer( 4, GL_FLOAT, sizeof(CloudVertex), &vertices[0].color );
939                 glEnableClientState( GL_COLOR_ARRAY );
940             }
941 */
942             //Send texture coords for normal map to unit 0
943             glTexCoordPointer( 2, GL_FLOAT, sizeof(CloudVertex), &vertices[0].texCoord );
944             glEnableClientState( GL_TEXTURE_COORD_ARRAY );
945
946             //Send tangent space light vectors for normalisation to unit 1
947             glClientActiveTexturePtr( GL_TEXTURE1_ARB );
948             glTexCoordPointer( 3, GL_FLOAT, sizeof(CloudVertex), &vertices[0].tangentSpLight );
949             glEnableClientState( GL_TEXTURE_COORD_ARRAY );
950
951             //Set up texture environment to do (tex0 dot tex1)*color
952             glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
953             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
954             glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE );
955             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE );
956             glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE );
957
958             glActiveTexturePtr( GL_TEXTURE1_ARB );
959
960             glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
961             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
962             glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB );
963             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
964             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB );
965             glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE );
966
967             if ( nb_texture_unit >= 3 ) {
968                 glActiveTexturePtr( GL_TEXTURE2_ARB );
969                 glBindTexture( GL_TEXTURE_2D, decal->getHandle() );
970
971                 glClientActiveTexturePtr( GL_TEXTURE2_ARB );
972                 glTexCoordPointer( 2, GL_FLOAT, sizeof(CloudVertex), &vertices[0].texCoord );
973                 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
974
975                 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
976                 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD );
977                 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
978                 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
979
980                 glClientActiveTexturePtr( GL_TEXTURE0_ARB );
981                 glActiveTexturePtr( GL_TEXTURE0_ARB );
982
983                 //Draw cloud layer
984                 glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[0] );
985                 glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[10] );
986                 glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[20] );
987                 glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[30] );
988
989                 glDisable( GL_TEXTURE_2D );
990                 glActiveTexturePtr( GL_TEXTURE1_ARB );
991                 glDisable( GL_TEXTURE_CUBE_MAP_ARB );
992                 glActiveTexturePtr( GL_TEXTURE2_ARB );
993                 glDisable( GL_TEXTURE_2D );
994                 glActiveTexturePtr( GL_TEXTURE0_ARB );
995
996                 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
997                 glClientActiveTexturePtr( GL_TEXTURE1_ARB );
998                 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
999                 glClientActiveTexturePtr( GL_TEXTURE2_ARB );
1000                 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1001                 glClientActiveTexturePtr( GL_TEXTURE0_ARB );
1002
1003                 glDisableClientState( GL_COLOR_ARRAY );
1004                 glEnable( GL_LIGHTING );
1005
1006                 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1007
1008             } else {
1009                 glClientActiveTexturePtr( GL_TEXTURE0_ARB );
1010                 glActiveTexturePtr( GL_TEXTURE0_ARB );
1011
1012                 //Draw cloud layer
1013                 glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[0] );
1014                 glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[10] );
1015                 glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[20] );
1016                 glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[30] );
1017
1018                 //Disable textures
1019                 glDisable( GL_TEXTURE_2D );
1020
1021                 glActiveTexturePtr( GL_TEXTURE1_ARB );
1022                 glDisable( GL_TEXTURE_CUBE_MAP_ARB );
1023                 glActiveTexturePtr( GL_TEXTURE0_ARB );
1024
1025                 //disable vertex arrays
1026                 glDisableClientState( GL_VERTEX_ARRAY );
1027
1028                 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1029                 glClientActiveTexturePtr( GL_TEXTURE1_ARB );
1030                 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1031                 glClientActiveTexturePtr( GL_TEXTURE0_ARB );
1032
1033                 //Return to standard modulate texenv
1034                 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1035
1036                 if ( layer_coverage == SG_CLOUD_OVERCAST ) {
1037                     glDepthFunc(GL_LEQUAL);
1038
1039                     glEnable( GL_LIGHTING );
1040                     sgVec4 color;
1041                     ssgGetLight( 0 )->getColour( GL_DIFFUSE, color );
1042                     float average = ( color[0] + color[1] + color[2] ) / 3.0f;
1043                     average = 0.15 + average/10;
1044                     sgVec4 averageColor;
1045                     sgSetVec4( averageColor, average, average, average, 1.0f );
1046                     ssgGetLight( 0 )->setColour( GL_DIFFUSE, averageColor );
1047
1048                     glBlendColorPtr( average, average, average, 1.0f );
1049                     glBlendFunc( GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_COLOR );
1050
1051                     //Perform a second pass to color the torus
1052                     //Bind decal texture
1053                     glBindTexture( GL_TEXTURE_2D, decal->getHandle() );
1054                     glEnable(GL_TEXTURE_2D);
1055
1056                     //Set vertex arrays for torus
1057                     glVertexPointer( 3, GL_FLOAT, sizeof(CloudVertex), &vertices[0].position );
1058                     glEnableClientState( GL_VERTEX_ARRAY );
1059
1060                     //glColorPointer( 4, GL_FLOAT, sizeof(CloudVertex), &vertices[0].color );
1061                     //glEnableClientState( GL_COLOR_ARRAY );
1062
1063                     glNormalPointer( GL_FLOAT, sizeof(CloudVertex), &vertices[0].normal );
1064                     glEnableClientState( GL_NORMAL_ARRAY );
1065
1066                     glTexCoordPointer( 2, GL_FLOAT, sizeof(CloudVertex), &vertices[0].texCoord );
1067                     glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1068
1069                     //Draw cloud layer
1070                     glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[0] );
1071                     glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[10] );
1072                     glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[20] );
1073                     glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[30] );
1074
1075                     ssgGetLight( 0 )->setColour( GL_DIFFUSE, color );
1076
1077                     glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1078                 }
1079             }
1080             //Disable texture
1081             glDisable( GL_TEXTURE_2D );
1082
1083             glDisableClientState( GL_VERTEX_ARRAY );
1084             glDisableClientState( GL_NORMAL_ARRAY );
1085
1086             glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1087             glEnable( GL_CULL_FACE );
1088             glDepthFunc(GL_LESS);
1089
1090             ssgLoadModelviewMatrix( modelview );
1091
1092         } else {
1093             state_sel->selectStep( top ? 1 : 0 );
1094             ssgCullAndDraw( layer_root );
1095         }
1096     }
1097 }
1098
1099
1100 // make an ssgSimpleState for a cloud layer given the named texture
1101 ssgSimpleState *sgCloudMakeState( const string &path ) {
1102     ssgSimpleState *state = new ssgSimpleState();
1103
1104     SG_LOG(SG_ASTRO, SG_INFO, " texture = ");
1105
1106     state->setTexture( (char *)path.c_str() );
1107     state->setShadeModel( GL_SMOOTH );
1108     state->disable( GL_LIGHTING );
1109     state->disable( GL_CULL_FACE );
1110     state->enable( GL_TEXTURE_2D );
1111     state->enable( GL_COLOR_MATERIAL );
1112     state->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
1113     state->setMaterial( GL_EMISSION, 0.05, 0.05, 0.05, 0.0 );
1114     state->setMaterial( GL_AMBIENT, 0.2, 0.2, 0.2, 0.0 );
1115     state->setMaterial( GL_DIFFUSE, 0.5, 0.5, 0.5, 0.0 );
1116     state->setMaterial( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
1117     state->enable( GL_BLEND );
1118     state->enable( GL_ALPHA_TEST );
1119     state->setAlphaClamp( 0.01 );
1120
1121     return state;
1122 }