//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
-// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//
#include <simgear/compiler.h>
#include <plib/sg.h>
-#include <plib/ssg.h>
+#include <simgear/math/sg_random.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/polar3d.hxx>
SG_USING_STD(vector);
#include <simgear/environment/visual_enviro.hxx>
+#include "sky.hxx"
#include "newcloud.hxx"
#include "cloudfield.hxx"
+#if defined(__MINGW32__)
+#define isnan(x) _isnan(x)
+#endif
+
+#if defined (__FreeBSD__)
+# if __FreeBSD_version < 500000
+ extern "C" {
+ inline int isnan(double r) { return !(r <= 0 || r >= 0); }
+ }
+# endif
+#endif
+
+
+#if defined (__CYGWIN__)
+#include <ieeefp.h>
+#endif
+
static list_of_culledCloud inViewClouds;
// visibility distance for clouds in meters
float SGCloudField::CloudVis = 25000.0f;
-bool SGCloudField::enable3D = true;
+bool SGCloudField::enable3D = false;
// fieldSize must be > CloudVis or we can destroy the impostor cache
// a cloud must only be seen once or the impostor will be generated for each of his positions
-double SGCloudField::fieldSize = 27000.0;
+double SGCloudField::fieldSize = 50000.0;
float SGCloudField::density = 100.0;
+double SGCloudField::timer_dt = 0.0;
+sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
+
static int last_cache_size = 1*1024;
static int cacheResolution = 64;
+static sgVec3 last_sunlight={0.0f, 0.0f, 0.0f};
int SGCloudField::get_CacheResolution(void) {
+#if 0
return cacheResolution;
+#endif
+ return 0;
}
void SGCloudField::set_CacheResolution(int resolutionPixels) {
+#if 0
if(cacheResolution == resolutionPixels)
return;
cacheResolution = resolutionPixels;
count = 1;
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
}
+#endif
}
int SGCloudField::get_CacheSize(void) {
+#if 0
return SGNewCloud::cldCache->queryCacheSize();
+#endif
+ return 0;
}
void SGCloudField::set_CacheSize(int sizeKb) {
+#if 0
// apply in rendering option dialog
if(last_cache_size == sizeKb)
return;
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
if(count == 0)
count = 1;
-// SGNewCloud::cldCache->setCacheSize(sizeKb);
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
}
+#endif
}
void SGCloudField::set_CloudVis(float distance) {
+#if 0
if( distance <= fieldSize )
SGCloudField::CloudVis = distance;
+#endif
}
void SGCloudField::set_density(float density) {
+#if 0
SGCloudField::density = density;
+#endif
}
void SGCloudField::set_enable3dClouds(bool enable) {
+#if 0
if(enable3D == enable)
return;
enable3D = enable;
if(enable) {
- SGNewCloud::cldCache->setCacheSize(last_cache_size);
+ int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
+ if(count == 0)
+ count = 1;
+ SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
} else {
SGNewCloud::cldCache->setCacheSize(0);
}
+#endif
}
// reposition the cloud layer at the specified origin and orientation
-void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt) {
+void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed) {
+#if 0
sgMat4 T1, LON, LAT;
sgVec3 axis;
this->alt = alt;
// simulate clouds movement from wind
- double speed = 10.0f;
- double direction = 45.0;
double sp_dist = speed*dt;
if (sp_dist > 0) {
double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
// correct the frustum with the right far plane
ssgContext *context = ssgGetCurrentContext();
frustum = *context->getFrustum();
- frustum.setFOV(55.0,0);
+
+ float w, h;
+ sgEnviro.getFOV( w, h );
+ frustum.setFOV( w, h );
frustum.setNearFar(1.0, CloudVis);
+ timer_dt = dt;
+#endif
}
SGCloudField::SGCloudField() :
- last_density(0.0),
deltax(0.0),
deltay(0.0),
- last_course(0.0)
+ last_course(0.0),
+ last_density(0.0),
+ draw_in_3d(true)
{
+#if 0
sgSetVec3( relative_position, 0,0,0);
theField.reserve(200);
inViewClouds.reserve(200);
+ sg_srandom_time_10();
+#else
+ draw_in_3d = false;
+#endif
}
SGCloudField::~SGCloudField() {
+#if 0
list_of_Cloud::iterator iCloud;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
delete iCloud->aCloud;
}
theField.clear();
+#endif
}
+void SGCloudField::clear(void) {
+#if 0
+ list_of_Cloud::iterator iCloud;
+ for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
+ delete iCloud->aCloud;
+ }
+ theField.clear();
+ // force a recompute of density on first redraw
+ last_density = 0.0;
+ // true to come back in set density after layer is built
+ draw_in_3d = true;
+#endif
+}
+
// use a table or else we see poping when moving the slider...
static int densTable[][10] = {
{0,0,0,0,0,0,0,0,0,0},
// set the visible flag depending on density
void SGCloudField::applyDensity(void) {
+#if 0
int row = (int) (density / 10.0);
int col = 0;
+ sgBox fieldBox;
+
list_of_Cloud::iterator iCloud;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
if(++col > 9)
col = 0;
if( densTable[row][col] ) {
iCloud->visible = true;
+ fieldBox.extend( *iCloud->aCloud->getCenter() );
} else
iCloud->visible = false;
}
last_density = density;
+ draw_in_3d = ( theField.size() != 0);
+ sgVec3 center;
+ sgSubVec3( center, fieldBox.getMax(), fieldBox.getMin() );
+ sgScaleVec3( center, 0.5f );
+ center[1] = 0.0f;
+ field_sphere.setCenter( center );
+ field_sphere.setRadius( fieldSize * 0.5f * 1.414f );
+#endif
}
// add one cloud, data is not copied, ownership given
void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
+#if 0
Cloud cl;
- sgCopyVec3( cl.pos, pos );
cl.aCloud = cloud;
cl.visible = true;
cloud->SetPos( pos );
+ sgCopyVec3( cl.pos, *cloud->getCenter() );
theField.push_back( cl );
+#endif
}
static float Rnd(float n) {
- return n * (-0.5f + rand() / (float) RAND_MAX);
+ return n * (-0.5f + sg_random());
}
// for debug only
// build a field of cloud of size 25x25 km, its a grid of 11x11 clouds
void SGCloudField::buildTestLayer(void) {
-
+#if 0
const float s = 2250.0f;
for( int z = -5 ; z <= 5 ; z++) {
for( int x = -5 ; x <= 5 ; x++ ) {
- SGNewCloud *cloud = new SGNewCloud;
+ SGNewCloud *cloud = new SGNewCloud(SGNewCloud::CLFamilly_cu);
cloud->new_cu();
sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
addCloud(pos, cloud);
}
}
applyDensity();
+#endif
}
// cull all clouds of a tiled field
void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) {
+#if 0
list_of_Cloud::iterator iCloud;
- // TODO:cull the field before culling the clouds in the field (should eliminate 3 fields)
+ sgSphere tile_sphere;
+ tile_sphere.setRadius( field_sphere.getRadius() );
+ sgVec3 tile_center;
+ sgSubVec3( tile_center, field_sphere.getCenter(), eyePos );
+ tile_sphere.setCenter( tile_center );
+ tile_sphere.orthoXform(mat);
+ if( frustum.contains( & tile_sphere ) == SG_OUTSIDE )
+ return;
+
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
sgVec3 dist;
sgSphere sphere;
if( ! iCloud->visible )
continue;
sgSubVec3( dist, iCloud->pos, eyePos );
- sphere.setCenter(dist[0], dist[2], dist[1]);
+ sphere.setCenter(dist[0], dist[2], dist[1] + eyePos[1]);
float radius = iCloud->aCloud->getRadius();
sphere.setRadius(radius);
sphere.orthoXform(mat);
sgCopyVec3( tmp.eyePos, eyePos );
// save distance for later sort, opposite distance because we want back to front
tmp.dist = - squareDist;
+ tmp.heading = -SG_PI/2.0 - atan2( dist[0], dist[2] ); // + SG_PI;
+ tmp.alt = iCloud->pos[1];
inViewClouds.push_back(tmp);
if( squareDist - radius*radius < 100*100 )
sgEnviro.set_view_in_cloud(true);
}
}
-
+#endif
}
// because no field can have an infinite size (and we don't want to reach his border)
// we draw this field and adjacent fields.
// adjacent fields are not real, its the same field displaced by some offset
-void SGCloudField::Render(void) {
+void SGCloudField::Render(float *sun_color) {
+ // sun_color used to depend on an extern SGSky *thesky definition
+ // above. However, this is bad form for a library and it's much
+ // more clean to just pass in the needed value. For reference, here is
+ // the old way that sun_color was fetched ...
+ // float *sun_color = thesky->get_sun_color();
+
+#if 0
sgVec3 eyePos;
double relx, rely;
applyDensity();
}
- // ask the impostor cache to do some cleanup
- // TODO:don't do that for every field
- SGNewCloud::cldCache->startNewFrame();
+ if( ! draw_in_3d )
+ return;
+
+ if( ! SGNewCloud::cldCache->isRttAvailable() )
+ return;
inViewClouds.clear();
sgVec3 lightVec;
ssgGetLight( 0 )->getPosition( lightVec );
sgXformVec3( lightVec, invtrans );
- sgCopyVec3( SGNewCloud::modelSunDir, lightVec );
+
sgSetVec3( SGNewCloud::modelSunDir, lightVec[0], lightVec[2], lightVec[1]);
- // try to find the lighting data (buggy)
+ // try to find the lighting data (not accurate)
sgVec4 diffuse, ambient;
ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse );
ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient );
- sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 0.70f);
- sgScaleVec3 ( SGNewCloud::ambLight, ambient , 0.60f);
+// sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 1.0f);
+ sgScaleVec3 ( SGNewCloud::ambLight, ambient , 1.1f);
+ // trying something else : clouds are more yellow/red at dawn/dusk
+ // and added a bit of blue ambient
+ sgScaleVec3 ( SGNewCloud::sunlight, sun_color , 0.4f);
+ SGNewCloud::ambLight[2] += 0.1f;
+
+ sgVec3 delta_light;
+ sgSubVec3(delta_light, last_sunlight, SGNewCloud::sunlight);
+ if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) {
+ sgCopyVec3( last_sunlight, SGNewCloud::sunlight );
+ // force the redraw of all the impostors
+ SGNewCloud::cldCache->invalidateCache();
+ }
// voodoo things on the matrix stack
ssgGetModelviewMatrix( modelview );
// cloud fields are tiled on the flat earth
// compute the position in the tile
- relx = -fmod( deltax + relative_position[SG_X] + tmp[3][0], fieldSize );
- rely = -fmod( deltay + relative_position[SG_Y] + tmp[3][1], fieldSize );
+ relx = fmod( deltax + relative_position[SG_X], fieldSize );
+ rely = fmod( deltay + relative_position[SG_Y], fieldSize );
+
+ relx = fmod( relx + fieldSize, fieldSize );
+ rely = fmod( rely + fieldSize, fieldSize );
+ sgSetVec3( eyePos, relx, alt, rely);
- sgSetVec3( eyePos, -relx, alt, -rely);
+ sgSetVec3( view_X, tmp[0][0], tmp[1][0], tmp[2][0] );
+ sgSetVec3( view_Y, tmp[0][1], tmp[1][1], tmp[2][1] );
+ sgSetVec3( view_vec, tmp[0][2], tmp[1][2], tmp[2][2] );
- tmp[3][2] = 0;
- tmp[3][0] = 0;
- tmp[3][1] = 0;
ssgLoadModelviewMatrix( tmp );
/* flat earth
glAlphaFunc(GL_GREATER, 0.0f);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
+ glDepthMask( GL_FALSE );
glEnable(GL_SMOOTH);
glEnable(GL_BLEND);
- glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_TEXTURE_2D );
glDisable( GL_FOG );
glDisable(GL_LIGHTING);
for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) {
// iCloud->aCloud->drawContainers();
iCloud->aCloud->Render(iCloud->eyePos);
+ sgEnviro.callback_cloud(iCloud->heading, iCloud->alt,
+ iCloud->aCloud->getRadius(), iCloud->aCloud->getFamilly(), - iCloud->dist, iCloud->aCloud->getId());
}
glBindTexture(GL_TEXTURE_2D, 0);
ssgLoadModelviewMatrix( modelview );
glPopMatrix();
-
+#endif
}
-