void cGrCloudLayer::build( ssgSimpleState *cloud_state, float span, float elevation, float thickness, float transition ) { layer_span = span; layer_asl = elevation; layer_thickness = thickness; layer_transition = transition; scale = 4000.0; last_lon = last_lat = -999.0f; last_x = last_y = 0.0f; sgVec2 base; sgSetVec2( base, (float)grRandom(), (float)grRandom() ); // build the cloud layer sgVec4 color; sgVec3 vertex; sgVec2 tc; const float layer_scale = layer_span / scale; const float mpi = SG_PI/4; const float alt_diff = layer_asl * 1.5f; for (int i = 0; i < 4; i++) { if ( layer[i] != NULL ) { layer_transform->removeKid(layer[i]); // automatic delete } vl[i] = new ssgVertexArray( 10 ); cl[i] = new ssgColourArray( 10 ); tl[i] = new ssgTexCoordArray( 10 ); sgSetVec3( vertex, layer_span*(i-2)/2, -layer_span, (float)(alt_diff * (sin(i*mpi) - 2)) ); sgSetVec2( tc, base[0] + layer_scale * i/4, base[1] ); sgSetVec4( color, 1.0f, 1.0f, 1.0f, (i == 0) ? 0.0f : 0.15f ); cl[i]->add( color ); vl[i]->add( vertex ); tl[i]->add( tc ); for (int j = 0; j < 4; j++) { sgSetVec3( vertex, layer_span*(i-1)/2, layer_span*(j-2)/2, (float)(alt_diff * (sin((i+1)*mpi) + sin(j*mpi) - 2)) ); sgSetVec2( tc, base[0] + layer_scale * (i+1)/4, base[1] + layer_scale * j/4 ); sgSetVec4( color, 1.0f, 1.0f, 1.0f, ( (j == 0) || (i == 3)) ? ( (j == 0) && (i == 3)) ? 0.0f : 0.15f : 1.0f ); cl[i]->add( color ); vl[i]->add( vertex ); tl[i]->add( tc ); sgSetVec3( vertex, layer_span*(i-2)/2, layer_span*(j-1)/2, (float)(alt_diff * (sin(i*mpi) + sin((j+1)*mpi) - 2)) ); sgSetVec2( tc, base[0] + layer_scale * i/4, base[1] + layer_scale * (j+1)/4 ); sgSetVec4( color, 1.0f, 1.0f, 1.0f, ((j == 3) || (i == 0)) ? ((j == 3) && (i == 0)) ? 0.0f : 0.15f : 1.0f ); cl[i]->add( color ); vl[i]->add( vertex ); tl[i]->add( tc ); } sgSetVec3( vertex, layer_span*(i-1)/2, layer_span, (float)(alt_diff * (sin((i+1)*mpi) - 2)) ); sgSetVec2( tc, base[0] + layer_scale * (i+1)/4, base[1] + layer_scale ); sgSetVec4( color, 1.0f, 1.0f, 1.0f, (i == 3) ? 0.0f : 0.15f ); cl[i]->add( color ); vl[i]->add( vertex ); tl[i]->add( tc ); layer[i] = new ssgVtxTable(GL_TRIANGLE_STRIP, vl[i], NULL, tl[i], cl[i]); layer_transform->addKid( layer[i] ); layer[i]->setState( cloud_state ); } // force a repaint of the sky colors with arbitrary defaults repaint( color ); }
void cGrSky::modifyVisibility( float alt, float time_factor ) { float effvis = visibility; for ( int i = 0; i < clouds.getNum (); ++i ) { cGrCloudLayer *cloud = clouds.get(i); if ( cloud->isEnabled() ) { float asl = cloud->getElevation(); float thickness = cloud->getThickness(); float transition = cloud->getTransition(); float ratio = 1.0; if ( alt < asl - transition ) { // below cloud layer ratio = 1.0; } else if ( alt < asl ) { // in lower transition ratio = (asl - alt) / transition; } else if ( alt < asl + thickness ) { // in cloud layer ratio = 0.0; } else if ( alt < asl + thickness + transition ) { // in upper transition ratio = (alt - (asl + thickness)) / transition; } else { // above cloud layer ratio = 1.0; } // accumulate effects from multiple cloud layers effvis *= ratio; if ( ratio < 1.0 ) { if ( ! in_puff ) { // calc chance of entering cloud puff double rnd = grRandom(); double chance = rnd * rnd * rnd; if ( chance > 0.95 ) { in_puff = true; puff_length = grRandom() * 2.0; // up to 2 seconds puff_progression = 0.0; } } if ( in_puff ) { // modify actual_visibility based on puff envelope if ( puff_progression <= ramp_up ) { double x = 0.5 * SGD_PI * puff_progression / ramp_up; double factor = 1.0 - sin( x ); effvis = (float)(effvis * factor); } else if ( puff_progression >= ramp_up + puff_length ) { double x = 0.5 * SGD_PI * (puff_progression - (ramp_up + puff_length)) / ramp_down; double factor = sin( x ); effvis = (float)(effvis * factor); } else { effvis = 0.0; } puff_progression += time_factor; if ( puff_progression > puff_length + ramp_up + ramp_down) { in_puff = false; } } // never let visibility drop below 25 meters if ( effvis <= 25.0 ) { effvis = 25.0; } } } } // for effective_visibility = effvis; }