Harald JOHNSEN:
This is another update for the cloud code, a lot of lines but this time I have started to add the doxygen doc. Misc ==== - corrected a bug when RTT is not available, the current rendering context was altered - if RTT is not available then 3d clouds are not drawn at all - impostors lighting is now recomputed when the sun changes position - distant objects are no more seen in front of clouds - blending of distant clouds is a bit better now - litle optimization of code (uses a less cpu time) - use layer wind speed and direction (no more hardcoded wind) - fov is no more hardcoded Changes ======= - clouds (cu only) are dissipating/reforming (experimental) - compute a turbulence factor that depends on surrounding clouds and type of clouds (experimental) - clouds shapes are defined in cloudlayers.xml - type of clouds present in a layer is also defined in cloudlayers.xml - cloud layers are generated from metar and other misc. data (in progress) - added a rain effect around the viewer (enabled in the rendering dialog and when the metar property says so) - added a lightning effect (enabled in the rendering dialog) : cb clouds spawn new lightnings - added a dialog to select from different weather source : metar/property, a 'fair weather' environment and a 'thunderstorm' environment.
This commit is contained in:
parent
e19091d809
commit
2ea9e723c2
@ -20,32 +20,145 @@
|
|||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <simgear_config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <plib/sg.h>
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/math/sg_random.h>
|
||||||
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
|
#include <simgear/math/point3d.hxx>
|
||||||
|
#include <simgear/math/polar3d.hxx>
|
||||||
|
#include <simgear/sound/soundmgr_openal.hxx>
|
||||||
#include <simgear/scene/sky/cloudfield.hxx>
|
#include <simgear/scene/sky/cloudfield.hxx>
|
||||||
#include <simgear/scene/sky/newcloud.hxx>
|
#include <simgear/scene/sky/newcloud.hxx>
|
||||||
#include "visual_enviro.hxx"
|
#include "visual_enviro.hxx"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
SG_USING_STD(vector);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Point3D pt;
|
||||||
|
int depth;
|
||||||
|
int prev;
|
||||||
|
} lt_tree_seg;
|
||||||
|
|
||||||
|
#define MAX_RAIN_SLICE 200
|
||||||
|
static float rainpos[MAX_RAIN_SLICE];
|
||||||
|
#define MAX_LT_TREE_SEG 400
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to render lightnings.
|
||||||
|
*/
|
||||||
|
class SGLightning {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Build a new lightning.
|
||||||
|
* The lightning has a limited life time. It will also play a thunder sounder once.
|
||||||
|
* @param lon lon longitude in degree
|
||||||
|
* @param lat lat latitude in degree
|
||||||
|
* @param alt asl of top of lightning
|
||||||
|
*/
|
||||||
|
SGLightning(double lon, double lat, double alt);
|
||||||
|
~SGLightning();
|
||||||
|
void lt_Render(void);
|
||||||
|
void lt_build(void);
|
||||||
|
void lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize);
|
||||||
|
|
||||||
|
// contains all the segments of the lightning
|
||||||
|
lt_tree_seg lt_tree[MAX_LT_TREE_SEG];
|
||||||
|
// segment count
|
||||||
|
int nb_tree;
|
||||||
|
// position of lightning
|
||||||
|
double lon, lat, alt;
|
||||||
|
int sequence_count;
|
||||||
|
// time to live
|
||||||
|
double age;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef vector<SGLightning *> list_of_lightning;
|
||||||
|
static list_of_lightning lightnings;
|
||||||
|
|
||||||
SGEnviro sgEnviro;
|
SGEnviro sgEnviro;
|
||||||
|
|
||||||
SGEnviro::SGEnviro(void) :
|
SGEnviro::SGEnviro(void) :
|
||||||
view_in_cloud(false),
|
view_in_cloud(false),
|
||||||
precipitation_enable_state(false),
|
turbulence_enable_state(false),
|
||||||
|
precipitation_enable_state(true),
|
||||||
|
lightning_enable_state(false),
|
||||||
|
soundMgr(NULL),
|
||||||
|
snd_active(false),
|
||||||
|
snd_dist(0.0),
|
||||||
|
last_cloud_turbulence(0.0),
|
||||||
|
cloud_turbulence(0.0),
|
||||||
|
elapsed_time(0.0),
|
||||||
|
dt(0.0),
|
||||||
|
min_time_before_lt(0.0),
|
||||||
|
fov_width(55.0),
|
||||||
|
fov_height(55.0),
|
||||||
precipitation_density(100.0)
|
precipitation_density(100.0)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
for(int i = 0; i < MAX_RAIN_SLICE ; i++)
|
||||||
|
rainpos[i] = sg_random();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SGEnviro::~SGEnviro(void) {
|
SGEnviro::~SGEnviro(void) {
|
||||||
|
list_of_lightning::iterator iLightning;
|
||||||
|
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
||||||
|
delete (*iLightning);
|
||||||
|
}
|
||||||
|
lightnings.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGEnviro::startOfFrame(void) {
|
void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) {
|
||||||
view_in_cloud = false;
|
view_in_cloud = false;
|
||||||
|
// ask the impostor cache to do some cleanup
|
||||||
if(SGNewCloud::cldCache)
|
if(SGNewCloud::cldCache)
|
||||||
SGNewCloud::cldCache->startNewFrame();
|
SGNewCloud::cldCache->startNewFrame();
|
||||||
|
last_cloud_turbulence = cloud_turbulence;
|
||||||
|
cloud_turbulence = 0.0;
|
||||||
|
elapsed_time += delta_time;
|
||||||
|
min_time_before_lt -= delta_time;
|
||||||
|
dt = delta_time;
|
||||||
|
|
||||||
|
sgMat4 T1, LON, LAT;
|
||||||
|
sgVec3 axis;
|
||||||
|
|
||||||
|
sgMakeTransMat4( T1, p );
|
||||||
|
|
||||||
|
sgSetVec3( axis, 0.0, 0.0, 1.0 );
|
||||||
|
sgMakeRotMat4( LON, lon, axis );
|
||||||
|
|
||||||
|
sgSetVec3( axis, 0.0, 1.0, 0.0 );
|
||||||
|
sgMakeRotMat4( LAT, 90.0 - lat, axis );
|
||||||
|
|
||||||
|
sgMat4 TRANSFORM;
|
||||||
|
|
||||||
|
sgCopyMat4( TRANSFORM, T1 );
|
||||||
|
sgPreMultMat4( TRANSFORM, LON );
|
||||||
|
sgPreMultMat4( TRANSFORM, LAT );
|
||||||
|
|
||||||
|
sgCoord pos;
|
||||||
|
sgSetCoord( &pos, TRANSFORM );
|
||||||
|
|
||||||
|
sgMakeCoordMat4( transform, &pos );
|
||||||
|
last_lon = lon;
|
||||||
|
last_lat = lat;
|
||||||
|
last_alt = alt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGEnviro::endOfFrame(void) {
|
void SGEnviro::endOfFrame(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double SGEnviro::get_cloud_turbulence(void) const {
|
||||||
|
return last_cloud_turbulence;
|
||||||
|
}
|
||||||
|
|
||||||
// this can be queried to add some turbulence for example
|
// this can be queried to add some turbulence for example
|
||||||
bool SGEnviro::is_view_in_cloud(void) const {
|
bool SGEnviro::is_view_in_cloud(void) const {
|
||||||
return view_in_cloud;
|
return view_in_cloud;
|
||||||
@ -71,6 +184,10 @@ bool SGEnviro::get_clouds_enable_state(void) const {
|
|||||||
return SGCloudField::get_enable3dClouds();
|
return SGCloudField::get_enable3dClouds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SGEnviro::get_turbulence_enable_state(void) const {
|
||||||
|
return turbulence_enable_state;
|
||||||
|
}
|
||||||
|
|
||||||
void SGEnviro::set_CacheResolution(int resolutionPixels) {
|
void SGEnviro::set_CacheResolution(int resolutionPixels) {
|
||||||
SGCloudField::set_CacheResolution(resolutionPixels);
|
SGCloudField::set_CacheResolution(resolutionPixels);
|
||||||
}
|
}
|
||||||
@ -87,7 +204,9 @@ void SGEnviro::set_clouds_density(float density) {
|
|||||||
void SGEnviro::set_clouds_enable_state(bool enable) {
|
void SGEnviro::set_clouds_enable_state(bool enable) {
|
||||||
SGCloudField::set_enable3dClouds(enable);
|
SGCloudField::set_enable3dClouds(enable);
|
||||||
}
|
}
|
||||||
|
void SGEnviro::set_turbulence_enable_state(bool enable) {
|
||||||
|
turbulence_enable_state = enable;
|
||||||
|
}
|
||||||
// rain/snow
|
// rain/snow
|
||||||
float SGEnviro::get_precipitation_density(void) const {
|
float SGEnviro::get_precipitation_density(void) const {
|
||||||
return precipitation_density;
|
return precipitation_density;
|
||||||
@ -105,9 +224,453 @@ void SGEnviro::set_precipitation_enable_state(bool enable) {
|
|||||||
|
|
||||||
// others
|
// others
|
||||||
bool SGEnviro::get_lightning_enable_state(void) const {
|
bool SGEnviro::get_lightning_enable_state(void) const {
|
||||||
return false;
|
return lightning_enable_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGEnviro::set_lightning_enable_state(bool enable) {
|
void SGEnviro::set_lightning_enable_state(bool enable) {
|
||||||
|
lightning_enable_state = enable;
|
||||||
|
if( ! enable ) {
|
||||||
|
// TODO:cleanup
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SGEnviro::setLight(sgVec4 adj_fog_color) {
|
||||||
|
sgCopyVec4( fog_color, adj_fog_color );
|
||||||
|
if( false ) {
|
||||||
|
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SGEnviro::callback_cloud(float heading, float alt, float radius, int familly, float dist) {
|
||||||
|
// send data to wx radar
|
||||||
|
// compute turbulence
|
||||||
|
// draw precipitation
|
||||||
|
// draw lightning
|
||||||
|
// compute illumination
|
||||||
|
|
||||||
|
// http://www.pilotfriend.com/flight_training/weather/THUNDERSTORM%20HAZARDS1.htm
|
||||||
|
double turbulence = 0.0;
|
||||||
|
if( dist < radius * radius * 2.25f ) {
|
||||||
|
switch(familly) {
|
||||||
|
case SGNewCloud::CLFamilly_st:
|
||||||
|
turbulence = 0.2;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_ci:
|
||||||
|
case SGNewCloud::CLFamilly_cs:
|
||||||
|
case SGNewCloud::CLFamilly_cc:
|
||||||
|
case SGNewCloud::CLFamilly_ac:
|
||||||
|
case SGNewCloud::CLFamilly_as:
|
||||||
|
turbulence = 0.1;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_sc:
|
||||||
|
turbulence = 0.3;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_ns:
|
||||||
|
turbulence = 0.4;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_cu:
|
||||||
|
turbulence = 0.5;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_cb:
|
||||||
|
turbulence = 0.6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// full turbulence inside cloud, half in the vicinity
|
||||||
|
if( dist > radius * radius )
|
||||||
|
turbulence *= 0.5;
|
||||||
|
if( turbulence > cloud_turbulence )
|
||||||
|
cloud_turbulence = turbulence;
|
||||||
|
// we can do 'local' precipitations too
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to LWC for radar (experimental)
|
||||||
|
// http://www-das.uwyo.edu/~geerts/cwx/notes/chap08/moist_cloud.html
|
||||||
|
double LWC = 0.0;
|
||||||
|
switch(familly) {
|
||||||
|
case SGNewCloud::CLFamilly_st:
|
||||||
|
LWC = 0.29;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_cu:
|
||||||
|
LWC = 0.27;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_cb:
|
||||||
|
LWC = 2.0;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_sc:
|
||||||
|
LWC = 0.44;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_ci:
|
||||||
|
LWC = 0.03;
|
||||||
|
break;
|
||||||
|
// no data
|
||||||
|
case SGNewCloud::CLFamilly_cs:
|
||||||
|
case SGNewCloud::CLFamilly_cc:
|
||||||
|
case SGNewCloud::CLFamilly_ac:
|
||||||
|
case SGNewCloud::CLFamilly_as:
|
||||||
|
LWC = 0.03;
|
||||||
|
break;
|
||||||
|
case SGNewCloud::CLFamilly_ns:
|
||||||
|
LWC = 0.29*2.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// TODO:send data to radar antenna
|
||||||
|
// NB:data valid only from cockpit view
|
||||||
|
|
||||||
|
// spawn a new lightning
|
||||||
|
if(min_time_before_lt <= 0.0 && (familly == SGNewCloud::CLFamilly_cb) &&
|
||||||
|
dist < 15000.0 * 15000.0 && sg_random() > 0.9f) {
|
||||||
|
double lat, lon;
|
||||||
|
Point3D orig, dest;
|
||||||
|
orig.setlat(last_lat * SG_DEGREES_TO_RADIANS );
|
||||||
|
orig.setlon(last_lon * SG_DEGREES_TO_RADIANS );
|
||||||
|
orig.setelev(0.0);
|
||||||
|
dist = sgSqrt(dist);
|
||||||
|
dest = calc_gc_lon_lat(orig, heading, dist);
|
||||||
|
lon = dest.lon() * SG_RADIANS_TO_DEGREES;
|
||||||
|
lat = dest.lat() * SG_RADIANS_TO_DEGREES;
|
||||||
|
addLightning( lon, lat, alt );
|
||||||
|
|
||||||
|
// reset timer
|
||||||
|
min_time_before_lt = 5.0 + sg_random() * 30;
|
||||||
|
// DEBUG only
|
||||||
|
// min_time_before_lt = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// precipitation rendering code
|
||||||
|
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
|
||||||
|
|
||||||
|
sgVec3 light;
|
||||||
|
sgVec3 min_light = {0.35, 0.35, 0.35};
|
||||||
|
sgAddVec3( light, fog_color, min_light );
|
||||||
|
float da = SG_PI * 2.0f / (float) slices;
|
||||||
|
// low number = faster
|
||||||
|
float speedf = 2.5f - speed / 200.0;
|
||||||
|
if( speedf < 1.0f )
|
||||||
|
speedf = 1.0f;
|
||||||
|
float lenf = 0.03f + speed / 2000.0;
|
||||||
|
if( lenf > 0.10f )
|
||||||
|
lenf = 0.10f;
|
||||||
|
float t = fmod((float) elapsed_time, speedf) / speedf;
|
||||||
|
// t = 0.1f;
|
||||||
|
if( !down )
|
||||||
|
t = 1.0f - t;
|
||||||
|
float angle = 0.0f;
|
||||||
|
glColor4f(1.0f, 0.7f, 0.7f, 0.9f);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
int rainpos_indice = 0;
|
||||||
|
for( int i = 0 ; i < slices ; i++ ) {
|
||||||
|
float x = cos(angle) * baseRadius;
|
||||||
|
float y = sin(angle) * baseRadius;
|
||||||
|
angle += da;
|
||||||
|
sgVec3 dir = {x, -height, y};
|
||||||
|
|
||||||
|
// rain drops at 2 different speed to simulate depth
|
||||||
|
float t1 = (i & 1 ? t : t + t) + rainpos[rainpos_indice];
|
||||||
|
if(t1 > 1.0f) t1 -= 1.0f;
|
||||||
|
if(t1 > 1.0f) t1 -= 1.0f;
|
||||||
|
|
||||||
|
// distant raindrops are more transparent
|
||||||
|
float c = (i & 1 ? t1 * 0.5f : t1 * 0.9f);
|
||||||
|
glColor4f(c * light[0], c * light[1], c * light[2], c);
|
||||||
|
sgVec3 p1, p2;
|
||||||
|
sgScaleVec3(p1, dir, t1);
|
||||||
|
// distant raindrops are shorter
|
||||||
|
float t2 = t1 + (i & 1 ? lenf : lenf+lenf);
|
||||||
|
sgScaleVec3(p2, dir, t2);
|
||||||
|
|
||||||
|
glVertex3f(p1[0], p1[1] + height, p1[2]);
|
||||||
|
glVertex3f(p2[0], p2[1] + height, p2[2]);
|
||||||
|
if( ++rainpos_indice >= MAX_RAIN_SLICE )
|
||||||
|
rainpos_indice = 0;
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:check alt vs layer
|
||||||
|
void SGEnviro::drawRain(double pitch, double roll, double speed, double rain_norm) {
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||||
|
glDisable( GL_FOG );
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
|
int slice_count = (40.0 + rain_norm*150.0)* precipitation_density / 100.0;
|
||||||
|
|
||||||
|
float angle = speed;
|
||||||
|
if( angle > 90.0 )
|
||||||
|
angle = 90.0;
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
// TODO:find the real view orientation, not the AC one
|
||||||
|
// the cone rotate with speed
|
||||||
|
angle = -pitch - angle;
|
||||||
|
glRotatef(angle, 1.0, 0.0, 0.0);
|
||||||
|
glRotatef(roll, 0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
// up cone
|
||||||
|
DrawCone2(15.0, 30.0, slice_count, true, rain_norm, speed);
|
||||||
|
// down cone (usually not visible)
|
||||||
|
if(angle > 0.0)
|
||||||
|
DrawCone2(15.0, -30.0, slice_count, false, rain_norm, speed);
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
||||||
|
glEnable( GL_FOG );
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SGEnviro::set_soundMgr(SGSoundMgr *mgr) {
|
||||||
|
soundMgr = mgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double speed) {
|
||||||
|
// TODO:check alt with right layer (wich layer ?)
|
||||||
|
if( precipitation_enable_state && rain_norm > 0.0)
|
||||||
|
drawRain(pitch, roll, speed, rain_norm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SGLightning::SGLightning(double _lon, double _lat, double _alt) :
|
||||||
|
lon(_lon),
|
||||||
|
lat(_lat),
|
||||||
|
alt(_alt),
|
||||||
|
age(1.0 + sg_random() * 4.0),
|
||||||
|
nb_tree(0)
|
||||||
|
{
|
||||||
|
// sequence_count = 1 + sg_random() * 5.0;
|
||||||
|
lt_build();
|
||||||
|
}
|
||||||
|
|
||||||
|
SGLightning::~SGLightning() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// lightning rendering code
|
||||||
|
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
|
||||||
|
|
||||||
|
sgVec3 dir, newdir;
|
||||||
|
int nseg = 0;
|
||||||
|
Point3D pt = start;
|
||||||
|
if( nbseg == 50 )
|
||||||
|
sgSetVec3( dir, 0.0, -1.0, 0.0 );
|
||||||
|
else {
|
||||||
|
sgSetVec3( dir, sg_random() - 0.5f, sg_random() - 0.5f, sg_random() - 0.5f);
|
||||||
|
sgNormaliseVec3(dir);
|
||||||
|
}
|
||||||
|
if( nb_tree >= MAX_LT_TREE_SEG )
|
||||||
|
return;
|
||||||
|
|
||||||
|
lt_tree[nb_tree].depth = tree_nr;
|
||||||
|
nseg = 0;
|
||||||
|
lt_tree[nb_tree].pt = pt;
|
||||||
|
lt_tree[nb_tree].prev = -1;
|
||||||
|
nb_tree ++;
|
||||||
|
|
||||||
|
// TODO:check agl
|
||||||
|
while(nseg < nbseg && pt.y() > 0.0) {
|
||||||
|
int prev = nb_tree - 1;
|
||||||
|
nseg++;
|
||||||
|
// add a branch
|
||||||
|
if( energy * sg_random() > 0.8f )
|
||||||
|
lt_build_tree_branch(tree_nr + 1, pt, energy * 0.9f, nbseg == 50 ? 10 : nbseg * 0.4f, segsize * 0.7f);
|
||||||
|
|
||||||
|
if( nb_tree >= MAX_LT_TREE_SEG )
|
||||||
|
return;
|
||||||
|
sgSetVec3(newdir, (sg_random() - 0.5f), (sg_random() - 0.5f) - (nbseg == 50 ? 0.5f : 0.0), (sg_random() - 0.5f));
|
||||||
|
sgNormaliseVec3(newdir);
|
||||||
|
sgAddVec3( dir, newdir);
|
||||||
|
sgNormaliseVec3(dir);
|
||||||
|
sgVec3 scaleDir;
|
||||||
|
sgScaleVec3( scaleDir, dir, segsize * energy * 0.5f );
|
||||||
|
pt[PX] += scaleDir[0];
|
||||||
|
pt[PY] += scaleDir[1];
|
||||||
|
pt[PZ] += scaleDir[2];
|
||||||
|
|
||||||
|
lt_tree[nb_tree].depth = tree_nr;
|
||||||
|
lt_tree[nb_tree].pt = pt;
|
||||||
|
lt_tree[nb_tree].prev = prev;
|
||||||
|
nb_tree ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SGLightning::lt_build(void) {
|
||||||
|
Point3D top;
|
||||||
|
nb_tree = 0;
|
||||||
|
top[PX] = 0 ;
|
||||||
|
top[PY] = alt;
|
||||||
|
top[PZ] = 0;
|
||||||
|
lt_build_tree_branch(0, top, 1.0, 50, top[PY] / 8.0);
|
||||||
|
if( ! sgEnviro.soundMgr )
|
||||||
|
return;
|
||||||
|
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||||
|
Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||||
|
double course = 0.0, dist = 0.0;
|
||||||
|
calc_gc_course_dist( dest, start, &course, &dist );
|
||||||
|
if( dist < 10000.0 && ! sgEnviro.snd_playing && (dist < sgEnviro.snd_dist || ! sgEnviro.snd_active) ) {
|
||||||
|
sgEnviro.snd_timer = 0.0;
|
||||||
|
sgEnviro.snd_wait = dist / 340;
|
||||||
|
sgEnviro.snd_dist = dist;
|
||||||
|
sgEnviro.snd_pos_lat = lat;
|
||||||
|
sgEnviro.snd_pos_lon = lon;
|
||||||
|
sgEnviro.snd_active = true;
|
||||||
|
sgEnviro.snd_playing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SGLightning::lt_Render(void) {
|
||||||
|
float flash = 0.5;
|
||||||
|
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
|
||||||
|
flash = sg_random() * 0.75f + 0.25f;
|
||||||
|
float h = lt_tree[0].pt[PY];
|
||||||
|
sgVec4 col={0.62f, 0.83f, 1.0f, 1.0f};
|
||||||
|
sgVec4 c;
|
||||||
|
|
||||||
|
#define DRAW_SEG() \
|
||||||
|
{glBegin(GL_LINES); \
|
||||||
|
glColor4fv(c); \
|
||||||
|
glVertex3f(lt_tree[n].pt[PX], lt_tree[n].pt[PZ], lt_tree[n].pt[PY]); \
|
||||||
|
glVertex3f(lt_tree[lt_tree[n].prev].pt[PX], lt_tree[lt_tree[n].prev].pt[PZ], lt_tree[lt_tree[n].prev].pt[PY]); \
|
||||||
|
glEnd();}
|
||||||
|
|
||||||
|
glDepthMask( GL_FALSE );
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glDisable( GL_FOG );
|
||||||
|
glPushMatrix();
|
||||||
|
sgMat4 modelview, tmp;
|
||||||
|
ssgGetModelviewMatrix( modelview );
|
||||||
|
sgCopyMat4( tmp, sgEnviro.transform );
|
||||||
|
sgPostMultMat4( tmp, modelview );
|
||||||
|
ssgLoadModelviewMatrix( tmp );
|
||||||
|
|
||||||
|
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||||
|
Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||||
|
double course = 0.0, dist = 0.0;
|
||||||
|
calc_gc_course_dist( dest, start, &course, &dist );
|
||||||
|
double ax = 0.0, ay = 0.0;
|
||||||
|
ax = cos(course) * dist;
|
||||||
|
ay = sin(course) * dist;
|
||||||
|
|
||||||
|
glTranslatef( ax, ay, -sgEnviro.last_alt );
|
||||||
|
// glTranslatef( ax, ay, 0 );
|
||||||
|
|
||||||
|
for( int n = 0 ; n < nb_tree ; n++ ) {
|
||||||
|
if( lt_tree[n].prev < 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float t1 = sgLerp(0.5, 1.0, lt_tree[n].pt[PY] / h);
|
||||||
|
t1 *= flash;
|
||||||
|
if( lt_tree[n].depth >= 2 ) {
|
||||||
|
glLineWidth(3);
|
||||||
|
sgScaleVec4(c, col, t1 * 0.6f);
|
||||||
|
DRAW_SEG();
|
||||||
|
} else {
|
||||||
|
if( lt_tree[n].depth == 0 ) {
|
||||||
|
glLineWidth(12);
|
||||||
|
sgScaleVec4(c, col, t1 * 0.5f);
|
||||||
|
DRAW_SEG();
|
||||||
|
|
||||||
|
glLineWidth(6);
|
||||||
|
sgScaleVec4(c, col, t1);
|
||||||
|
DRAW_SEG();
|
||||||
|
} else {
|
||||||
|
glLineWidth(6);
|
||||||
|
sgScaleVec4(c, col, t1 * 0.7f);
|
||||||
|
DRAW_SEG();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( lt_tree[n].depth == 0 )
|
||||||
|
glLineWidth(3);
|
||||||
|
else
|
||||||
|
glLineWidth(2);
|
||||||
|
|
||||||
|
sgSetVec4(c, t1, t1, t1, t1);
|
||||||
|
DRAW_SEG();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
glLineWidth(1);
|
||||||
|
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
||||||
|
glPopMatrix();
|
||||||
|
glDepthMask( GL_TRUE );
|
||||||
|
glEnable( GL_FOG );
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SGEnviro::addLightning(double lon, double lat, double alt) {
|
||||||
|
if( lightnings.size() > 10)
|
||||||
|
return;
|
||||||
|
SGLightning *lt= new SGLightning(lon, lat, alt);
|
||||||
|
lightnings.push_back(lt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SGEnviro::drawLightning(void) {
|
||||||
|
list_of_lightning::iterator iLightning;
|
||||||
|
// play 'thunder' for lightning
|
||||||
|
if( snd_active )
|
||||||
|
if( !snd_playing ) {
|
||||||
|
// wait until sound has reached us
|
||||||
|
snd_timer += dt;
|
||||||
|
if( snd_timer >= snd_wait ) {
|
||||||
|
snd_playing = true;
|
||||||
|
// compute relative position of lightning
|
||||||
|
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||||
|
Point3D dest( snd_pos_lon*SG_DEGREES_TO_RADIANS, snd_pos_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||||
|
double course = 0.0, dist = 0.0;
|
||||||
|
calc_gc_course_dist( dest, start, &course, &dist );
|
||||||
|
double ax = 0.0, ay = 0.0;
|
||||||
|
ax = cos(course) * dist;
|
||||||
|
ay = sin(course) * dist;
|
||||||
|
SGSoundSample *snd = soundMgr->find("thunder");
|
||||||
|
if( snd ) {
|
||||||
|
ALfloat pos[3]={ax, ay, -sgEnviro.last_alt };
|
||||||
|
snd->set_source_pos(pos);
|
||||||
|
snd->play_once();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if( !soundMgr->is_playing("thunder") ) {
|
||||||
|
snd_active = false;
|
||||||
|
snd_playing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ! lightning_enable_state )
|
||||||
|
return;
|
||||||
|
|
||||||
|
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
||||||
|
if( dt )
|
||||||
|
if( sg_random() > 0.95f )
|
||||||
|
(*iLightning)->lt_build();
|
||||||
|
(*iLightning)->lt_Render();
|
||||||
|
(*iLightning)->age -= dt;
|
||||||
|
if( (*iLightning)->age < 0.0 ) {
|
||||||
|
delete (*iLightning);
|
||||||
|
lightnings.erase( iLightning );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SGEnviro::setFOV( float w, float h ) {
|
||||||
|
fov_width = w;
|
||||||
|
fov_height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SGEnviro::getFOV( float &w, float &h ) {
|
||||||
|
w = fov_width;
|
||||||
|
h = fov_height;
|
||||||
|
}
|
||||||
|
@ -22,23 +22,89 @@
|
|||||||
#ifndef _VISUAL_ENVIRO_HXX
|
#ifndef _VISUAL_ENVIRO_HXX
|
||||||
#define _VISUAL_ENVIRO_HXX
|
#define _VISUAL_ENVIRO_HXX
|
||||||
|
|
||||||
class SGEnviro {
|
#include <simgear/compiler.h>
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
class SGLightning;
|
||||||
|
class SGSoundMgr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visual environment helper class.
|
||||||
|
*/
|
||||||
|
class SGEnviro {
|
||||||
|
friend SGLightning;
|
||||||
private:
|
private:
|
||||||
|
void DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed);
|
||||||
|
void lt_update(void);
|
||||||
|
|
||||||
bool view_in_cloud;
|
bool view_in_cloud;
|
||||||
bool precipitation_enable_state;
|
bool precipitation_enable_state;
|
||||||
float precipitation_density;
|
float precipitation_density;
|
||||||
|
bool turbulence_enable_state;
|
||||||
|
double last_cloud_turbulence, cloud_turbulence;
|
||||||
|
bool lightning_enable_state;
|
||||||
|
double elapsed_time, dt;
|
||||||
|
sgVec4 fog_color;
|
||||||
|
sgMat4 transform;
|
||||||
|
double last_lon, last_lat, last_alt;
|
||||||
|
SGSoundMgr *soundMgr;
|
||||||
|
bool snd_active, snd_playing;
|
||||||
|
double snd_timer, snd_wait, snd_pos_lat, snd_pos_lon, snd_dist;
|
||||||
|
double min_time_before_lt;
|
||||||
|
|
||||||
|
float fov_width, fov_height;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SGEnviro();
|
SGEnviro();
|
||||||
~SGEnviro();
|
~SGEnviro();
|
||||||
|
|
||||||
void startOfFrame(void);
|
/**
|
||||||
|
* Forward a few states used for renderings.
|
||||||
|
*/
|
||||||
|
void startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time);
|
||||||
|
|
||||||
void endOfFrame(void);
|
void endOfFrame(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whenever a cloud is drawn we check his 'impact' on the environment.
|
||||||
|
* @param heading direction of cloud in radians
|
||||||
|
* @param alt asl of cloud in meters
|
||||||
|
* @param radius radius of cloud in meters
|
||||||
|
* @param familly cloud familly
|
||||||
|
* @param dist squared dist to cloud in meters
|
||||||
|
*/
|
||||||
|
void callback_cloud(float heading, float alt, float radius, int familly, float dist);
|
||||||
|
|
||||||
|
void drawRain(double pitch, double roll, double speed, double rain_norm);
|
||||||
|
/**
|
||||||
|
* Draw rain or snow precipitation around the viewer.
|
||||||
|
* @param rain_norm rain normalized intensity given by metar class
|
||||||
|
* @param snow_norm snow normalized intensity given by metar class
|
||||||
|
* @param hail_norm hail normalized intensity given by metar class
|
||||||
|
* @param pitch pitch rotation of viewer
|
||||||
|
* @param roll roll rotation of viewer
|
||||||
|
* @param speed moving speed of viewer in kt
|
||||||
|
*/
|
||||||
|
void drawPrecipitation(double rain_norm, double snow_norm, double hail_norm,
|
||||||
|
double pitch, double roll, double speed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the lightnings spawned by cumulo nimbus.
|
||||||
|
*/
|
||||||
|
void drawLightning(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward the fog color used by the rain rendering.
|
||||||
|
* @param adj_fog_color color of the fog
|
||||||
|
*/
|
||||||
|
void setLight(sgVec4 adj_fog_color);
|
||||||
|
|
||||||
// this can be queried to add some turbulence for example
|
// this can be queried to add some turbulence for example
|
||||||
bool is_view_in_cloud(void) const;
|
bool is_view_in_cloud(void) const;
|
||||||
void set_view_in_cloud(bool incloud);
|
void set_view_in_cloud(bool incloud);
|
||||||
|
double get_cloud_turbulence(void) const;
|
||||||
|
|
||||||
// Clouds
|
// Clouds
|
||||||
// return the size of the memory pool used by texture impostors
|
// return the size of the memory pool used by texture impostors
|
||||||
@ -47,23 +113,76 @@ public:
|
|||||||
float get_clouds_visibility(void) const;
|
float get_clouds_visibility(void) const;
|
||||||
float get_clouds_density(void) const;
|
float get_clouds_density(void) const;
|
||||||
bool get_clouds_enable_state(void) const;
|
bool get_clouds_enable_state(void) const;
|
||||||
|
bool get_turbulence_enable_state(void) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the impostor texture cache for 3D clouds.
|
||||||
|
* @param sizeKb size of the texture pool in Kb
|
||||||
|
*/
|
||||||
void set_clouds_CacheSize(int sizeKb);
|
void set_clouds_CacheSize(int sizeKb);
|
||||||
|
/**
|
||||||
|
* Set the resolution of the impostor texture for 3D clouds.
|
||||||
|
* @param resolutionPixels size of each texture in pixels (64|128|256)
|
||||||
|
*/
|
||||||
void set_CacheResolution(int resolutionPixels);
|
void set_CacheResolution(int resolutionPixels);
|
||||||
|
/**
|
||||||
|
* Set the maximum range used when drawing clouds.
|
||||||
|
* Clouds are blended from totaly transparent at max range to totaly opaque around the viewer
|
||||||
|
* @param distance in meters
|
||||||
|
*/
|
||||||
void set_clouds_visibility(float distance);
|
void set_clouds_visibility(float distance);
|
||||||
|
/**
|
||||||
|
* Set the proportion of clouds that will be rendered to limit drop in FPS.
|
||||||
|
* @param density 0..100 no clouds drawn when density == 0, all are drawn when density == 100
|
||||||
|
*/
|
||||||
void set_clouds_density(float density);
|
void set_clouds_density(float density);
|
||||||
|
/**
|
||||||
|
* Enable or disable the use of 3D clouds.
|
||||||
|
* @param enable when false we draw the 2D layers
|
||||||
|
*/
|
||||||
void set_clouds_enable_state(bool enable);
|
void set_clouds_enable_state(bool enable);
|
||||||
|
/**
|
||||||
|
* Enable or disable the use of proximity cloud turbulence.
|
||||||
|
* @param enable when true the turbulence is computed based on type of cloud around the AC
|
||||||
|
*/
|
||||||
|
void set_turbulence_enable_state(bool enable);
|
||||||
|
|
||||||
// rain/snow
|
// rain/snow
|
||||||
float get_precipitation_density(void) const;
|
float get_precipitation_density(void) const;
|
||||||
bool get_precipitation_enable_state(void) const;
|
bool get_precipitation_enable_state(void) const;
|
||||||
|
|
||||||
void set_precipitation_density(float density);
|
void set_precipitation_density(float density);
|
||||||
|
/**
|
||||||
|
* Enable or disable the rendering of precipitation around the viewer.
|
||||||
|
* @param enable when true we will draw precipitation depending on metar data
|
||||||
|
*/
|
||||||
void set_precipitation_enable_state(bool enable);
|
void set_precipitation_enable_state(bool enable);
|
||||||
|
|
||||||
// others
|
// others
|
||||||
bool get_lightning_enable_state(void) const;
|
bool get_lightning_enable_state(void) const;
|
||||||
|
/**
|
||||||
|
* Enable or disable the rendering of lightning and the thunder sound.
|
||||||
|
* @param enable when true we will draw lightning spwaned by cumulonimbus
|
||||||
|
*/
|
||||||
void set_lightning_enable_state(bool enable);
|
void set_lightning_enable_state(bool enable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawn a new lighning at specified lon/lat.
|
||||||
|
* @param lon position of the new lightning
|
||||||
|
* @param lat position of the new lightning
|
||||||
|
* @param alt asl of the starting point of the lightning in meters
|
||||||
|
*/
|
||||||
|
void addLightning(double lon, double lat, double alt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward the sound manager instance to be able to play samples.
|
||||||
|
* @param mgr a running sound manager
|
||||||
|
*/
|
||||||
|
void set_soundMgr(SGSoundMgr *mgr);
|
||||||
|
|
||||||
|
void setFOV( float w, float h );
|
||||||
|
void getFOV( float &w, float &h );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SGEnviro sgEnviro;
|
extern SGEnviro sgEnviro;
|
||||||
|
@ -47,6 +47,7 @@ void SGBbCache::freeTextureMemory(void) {
|
|||||||
|
|
||||||
if( bbListCount ) {
|
if( bbListCount ) {
|
||||||
for(int i = 0 ; i < bbListCount ; i++) {
|
for(int i = 0 ; i < bbListCount ; i++) {
|
||||||
|
bbList[i].cldID = 0;
|
||||||
if(bbList[i].texID)
|
if(bbList[i].texID)
|
||||||
glDeleteTextures(1, & bbList[i].texID);
|
glDeleteTextures(1, & bbList[i].texID);
|
||||||
}
|
}
|
||||||
@ -78,11 +79,12 @@ bool SGBbCache::allocTextureMemory(int cacheCount, int textureDimension) {
|
|||||||
cacheSizeKb = (textureDimension * textureDimension * 4);
|
cacheSizeKb = (textureDimension * textureDimension * 4);
|
||||||
cacheSizeKb *= cacheCount;
|
cacheSizeKb *= cacheCount;
|
||||||
cacheSizeKb /= 1024;
|
cacheSizeKb /= 1024;
|
||||||
if(rt) {
|
if(rtAvailable) {
|
||||||
rt->BeginCapture();
|
if( rt->BeginCapture() ) {
|
||||||
glViewport(0, 0, textureDimension, textureDimension);
|
glViewport(0, 0, textureDimension, textureDimension);
|
||||||
rt->EndCapture();
|
rt->EndCapture();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,9 +115,9 @@ void SGBbCache::init(int cacheCount) {
|
|||||||
rt->Reset("rgba tex2D ctt");
|
rt->Reset("rgba tex2D ctt");
|
||||||
// rt->Reset("rgba tex2D");
|
// rt->Reset("rgba tex2D");
|
||||||
if( rt->Initialize(256, 256, true) ) {
|
if( rt->Initialize(256, 256, true) ) {
|
||||||
rtAvailable = true;
|
|
||||||
if (rt->BeginCapture())
|
if (rt->BeginCapture())
|
||||||
{
|
{
|
||||||
|
rtAvailable = true;
|
||||||
glViewport(0, 0, 256, 256);
|
glViewport(0, 0, 256, 256);
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
@ -219,6 +221,7 @@ int SGBbCache::alloc(int cldId) {
|
|||||||
bbList[i].angleX = -999;
|
bbList[i].angleX = -999;
|
||||||
bbList[i].angleY = -999;
|
bbList[i].angleY = -999;
|
||||||
bbList[i].frameUsed = 0;
|
bbList[i].frameUsed = 0;
|
||||||
|
bbList[i].needRedraw = true;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,6 +282,7 @@ void SGBbCache::setTextureData(int bbId) {
|
|||||||
// bbList[bbId].angleY = angleY;
|
// bbList[bbId].angleY = angleY;
|
||||||
bbList[bbId].frame = frameNumber;
|
bbList[bbId].frame = frameNumber;
|
||||||
bbList[bbId].frameUsed = frameNumber;
|
bbList[bbId].frameUsed = frameNumber;
|
||||||
|
bbList[bbId].needRedraw = false;
|
||||||
builtBBCount ++;
|
builtBBCount ++;
|
||||||
builtBBframe ++;
|
builtBBframe ++;
|
||||||
}
|
}
|
||||||
@ -305,11 +309,14 @@ bool SGBbCache::isBbValid( int cldId, int bbId, float angleY, float angleX) {
|
|||||||
if( builtBBframe >= maxImpostorRegenFrame )
|
if( builtBBframe >= maxImpostorRegenFrame )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( fabs(angleY - bbList[bbId].angleY) >= 4.0 )
|
if( bbList[bbId].needRedraw )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( fabs(angleX - bbList[bbId].angleX) >= 4.0 )
|
// if( fabs(angleY - bbList[bbId].angleY) >= 4.0 )
|
||||||
return false;
|
// return false;
|
||||||
|
|
||||||
|
// if( fabs(angleX - bbList[bbId].angleX) >= 4.0 )
|
||||||
|
// return false;
|
||||||
|
|
||||||
bbList[bbId].frameUsed = frameNumber;
|
bbList[bbId].frameUsed = frameNumber;
|
||||||
return true;
|
return true;
|
||||||
@ -328,7 +335,7 @@ void SGBbCache::setReference( int cldId, int bbId, float angleY, float angleX) {
|
|||||||
void SGBbCache::startNewFrame(void) {
|
void SGBbCache::startNewFrame(void) {
|
||||||
builtBBframe = 0;
|
builtBBframe = 0;
|
||||||
// TOTO:find reasonable value
|
// TOTO:find reasonable value
|
||||||
int minFrameNumber = frameNumber - 500;
|
int minFrameNumber = frameNumber - 100;
|
||||||
frameNumber++;
|
frameNumber++;
|
||||||
// cleanup of unused enties
|
// cleanup of unused enties
|
||||||
for( int bbId = 0 ; bbId < bbListCount ; bbId++)
|
for( int bbId = 0 ; bbId < bbListCount ; bbId++)
|
||||||
@ -337,3 +344,21 @@ void SGBbCache::startNewFrame(void) {
|
|||||||
bbList[bbId].cldID = 0;
|
bbList[bbId].cldID = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// force all impostors to be rebuilt, this will enventually be done over several frames
|
||||||
|
void SGBbCache::invalidateCache(void) {
|
||||||
|
|
||||||
|
for( int bbId = 0 ; bbId < bbListCount ; bbId++)
|
||||||
|
// bbList[bbId].cldID = 0;
|
||||||
|
bbList[bbId].needRedraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flag the impostor for a lazy update
|
||||||
|
void SGBbCache::invalidate(int cldId, int bbId) {
|
||||||
|
if( bbId < 0 || bbId >= bbListCount )
|
||||||
|
return;
|
||||||
|
if( bbList[bbId].cldID != cldId )
|
||||||
|
return;
|
||||||
|
bbList[bbId].needRedraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -29,20 +29,36 @@
|
|||||||
#include <simgear/screen/extensions.hxx>
|
#include <simgear/screen/extensions.hxx>
|
||||||
#include <simgear/screen/RenderTexture.h>
|
#include <simgear/screen/RenderTexture.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Billboard helper class.
|
||||||
|
*/
|
||||||
class SGBbCache {
|
class SGBbCache {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
|
* storage class for impostors state.
|
||||||
|
*/
|
||||||
|
class bbInfo {
|
||||||
|
public:
|
||||||
|
/// the texture used by this impostor
|
||||||
GLuint texID;
|
GLuint texID;
|
||||||
|
/// the cloud owning this impostor
|
||||||
int cldID;
|
int cldID;
|
||||||
float angleX, angleY;
|
float angleX, angleY;
|
||||||
// creation frame number for debug only
|
// creation frame number for debug only
|
||||||
int frame;
|
int frame;
|
||||||
// last time this entry was used
|
/// last time this entry was used
|
||||||
int frameUsed;
|
int frameUsed;
|
||||||
} bbInfo;
|
/// dirty flag for lazy rebuild of impostor
|
||||||
|
bool needRedraw;
|
||||||
|
};
|
||||||
|
|
||||||
void freeTextureMemory(void);
|
void freeTextureMemory(void);
|
||||||
|
/**
|
||||||
|
* Allocate and initialize the texture pool.
|
||||||
|
* @param count the number of texture to build
|
||||||
|
* @param textureDimension size in pixel of each texture
|
||||||
|
*/
|
||||||
bool allocTextureMemory(int count, int textureDimension);
|
bool allocTextureMemory(int count, int textureDimension);
|
||||||
|
|
||||||
// a list of impostors
|
// a list of impostors
|
||||||
@ -64,53 +80,126 @@ public:
|
|||||||
SGBbCache(void);
|
SGBbCache(void);
|
||||||
~SGBbCache(void);
|
~SGBbCache(void);
|
||||||
|
|
||||||
// call this first to initialize everything, cacheCount is the number of texture to allocate
|
/**
|
||||||
|
* Call this first to initialize the cache.
|
||||||
|
* @param cacheCount the number of texture to allocate
|
||||||
|
*/
|
||||||
void init(int cacheCount);
|
void init(int cacheCount);
|
||||||
|
|
||||||
// free one cache slot, usualy when the cached object is destroyed
|
/**
|
||||||
|
* Free one cache slot, usualy when the cached object is destroyed.
|
||||||
|
* @param bbId the impostor slot
|
||||||
|
* @param cldId the cloud identifier
|
||||||
|
*/
|
||||||
void free(int bbId, int cldId);
|
void free(int bbId, int cldId);
|
||||||
|
|
||||||
// allocate a new texture, return an index in the cache
|
/**
|
||||||
|
* Allocate a new impostor.
|
||||||
|
* @param cldId the cloud identifier
|
||||||
|
* @return an impostor slot
|
||||||
|
*/
|
||||||
int alloc(int cldId);
|
int alloc(int cldId);
|
||||||
|
|
||||||
// give the texture name to use
|
/**
|
||||||
|
* Query the texture name associated with this cloud.
|
||||||
|
* @param bbId the impostor slot
|
||||||
|
* @param cldId the cloud identifier
|
||||||
|
* @return a texture name
|
||||||
|
*/
|
||||||
GLuint QueryTexID(int cldId, int bbId);
|
GLuint QueryTexID(int cldId, int bbId);
|
||||||
|
|
||||||
// save the rendered texture from the current context to a new texture
|
/**
|
||||||
|
* Save the rendered texture from the current context to a new texture.
|
||||||
|
* @param bbId the impostor slot
|
||||||
|
*/
|
||||||
void setTextureData(int bbId);
|
void setTextureData(int bbId);
|
||||||
|
|
||||||
// start the rendering of a billboard in the RTT context
|
/**
|
||||||
|
* Start the rendering of a billboard in the RTT context.
|
||||||
|
*/
|
||||||
void beginCapture(void);
|
void beginCapture(void);
|
||||||
|
|
||||||
// adjust the projection matrix of the RTT context to the size of the object
|
/**
|
||||||
|
* Adjust the projection matrix of the RTT context to the size of the object.
|
||||||
|
* @param radius radius in meters of the object to draw
|
||||||
|
* @param dist_center distance between viewer and object
|
||||||
|
*/
|
||||||
void setRadius(float radius, float dist_center);
|
void setRadius(float radius, float dist_center);
|
||||||
|
|
||||||
// forget the RTT and go back to the previous rendering context
|
/**
|
||||||
|
* Forget the RTT and go back to the previous rendering context.
|
||||||
|
*/
|
||||||
void endCapture(void);
|
void endCapture(void);
|
||||||
|
|
||||||
// for debugging only, give the number of frames since the inpostor was built
|
/**
|
||||||
|
* For debugging only, give the number of frames since the impostor was built.
|
||||||
|
* @param bbId the impostor slot
|
||||||
|
*/
|
||||||
int queryImpostorAge(int bbId);
|
int queryImpostorAge(int bbId);
|
||||||
|
|
||||||
// can we still use this impostor ?
|
/**
|
||||||
|
* Can we still use this impostor ? Check versus view angles and load.
|
||||||
|
* @param bbId the impostor slot
|
||||||
|
* @param cloudId the cloud identifier
|
||||||
|
* @param angleY rotation needed to face the impostor
|
||||||
|
* @param angleX rotation needed to face the impostor
|
||||||
|
*/
|
||||||
bool isBbValid( int cloudId, int bbId, float angleY, float angleX);
|
bool isBbValid( int cloudId, int bbId, float angleY, float angleX);
|
||||||
|
|
||||||
// save view angles of this billboard
|
/**
|
||||||
|
* Save view angles of this billboard.
|
||||||
|
* @param bbId the impostor slot
|
||||||
|
* @param cloudId the cloud identifier
|
||||||
|
* @param angleY rotation needed to face the impostor
|
||||||
|
* @param angleX rotation needed to face the impostor
|
||||||
|
*/
|
||||||
void setReference( int cloudId, int bbId, float angleY, float angleX);
|
void setReference( int cloudId, int bbId, float angleY, float angleX);
|
||||||
|
|
||||||
// prepare the cache for the rendering of a new frame
|
/**
|
||||||
|
* Prepare the cache for the rendering of a new frame.
|
||||||
|
* Do some garbage collect of unused impostors
|
||||||
|
*/
|
||||||
void startNewFrame(void);
|
void startNewFrame(void);
|
||||||
|
|
||||||
// alloc the impostors texture memory given the size of the memory pool
|
/**
|
||||||
// if sizeKb == 0 then the memory pool is freed and impostors are disabled
|
* Alloc the impostors texture memory given the size of the memory pool.
|
||||||
|
* If sizeKb == 0 then the memory pool is freed and impostors are disabled
|
||||||
|
* @param sizeKb size of the texture pool in K
|
||||||
|
*/
|
||||||
bool setCacheSize(int sizeKb);
|
bool setCacheSize(int sizeKb);
|
||||||
|
|
||||||
// alloc the impostors texture memory given the count and size of texture
|
/**
|
||||||
// if count == 0 then the memory pool is freed and impostors are disabled
|
* Alloc the impostors texture memory given the count and size of texture.
|
||||||
|
* If count == 0 then the memory pool is freed and impostors are disabled
|
||||||
|
* @param count number of texture to allocate
|
||||||
|
* @param textureDimension size of each texture in pixels
|
||||||
|
*/
|
||||||
bool setCacheSize(int count, int textureDimension);
|
bool setCacheSize(int count, int textureDimension);
|
||||||
|
|
||||||
// return the size of the memory pool used by texture impostors
|
bool isRttAvailable(void) { return rtAvailable; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force all impostors to be rebuilt.
|
||||||
|
*/
|
||||||
|
void invalidateCache(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag the impostor for a lazy update.
|
||||||
|
* @param bbId the impostor slot
|
||||||
|
* @param cldId the cloud identifier
|
||||||
|
*/
|
||||||
|
void invalidate(int cldId, int bbId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the size of the memory pool used by texture impostors.
|
||||||
|
* @return size of the memory pool in Kb
|
||||||
|
*/
|
||||||
int queryCacheSize(void);
|
int queryCacheSize(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of impostor to regen each frame.
|
||||||
|
* If we can't update all of them we will do that in the next frame
|
||||||
|
*/
|
||||||
int maxImpostorRegenFrame;
|
int maxImpostorRegenFrame;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -843,7 +843,7 @@ bool SGCloudLayer::reposition( sgVec3 p, sgVec3 up, double lon, double lat,
|
|||||||
last_lat = lat;
|
last_lat = lat;
|
||||||
}
|
}
|
||||||
|
|
||||||
layer3D->reposition( p, up, lon, lat, alt, dt);
|
layer3D->reposition( p, up, lon, lat, alt, dt, direction, speed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -851,7 +851,7 @@ bool SGCloudLayer::reposition( sgVec3 p, sgVec3 up, double lon, double lat,
|
|||||||
void SGCloudLayer::draw( bool top ) {
|
void SGCloudLayer::draw( bool top ) {
|
||||||
if ( layer_coverage != SG_CLOUD_CLEAR ) {
|
if ( layer_coverage != SG_CLOUD_CLEAR ) {
|
||||||
|
|
||||||
if ( SGCloudField::enable3D )
|
if ( SGCloudField::enable3D && layer3D->is3D())
|
||||||
layer3D->Render();
|
layer3D->Render();
|
||||||
else
|
else
|
||||||
if ( bump_mapping && enable_bump_mapping ) {
|
if ( bump_mapping && enable_bump_mapping ) {
|
||||||
|
@ -184,6 +184,9 @@ public:
|
|||||||
|
|
||||||
static bool enable_bump_mapping;
|
static bool enable_bump_mapping;
|
||||||
|
|
||||||
|
/** return the 3D layer cloud associated with this 2D layer */
|
||||||
|
SGCloudField *get_layer3D(void) { return layer3D; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct CloudVertex {
|
struct CloudVertex {
|
||||||
|
@ -45,13 +45,17 @@ static list_of_culledCloud inViewClouds;
|
|||||||
|
|
||||||
// visibility distance for clouds in meters
|
// visibility distance for clouds in meters
|
||||||
float SGCloudField::CloudVis = 25000.0f;
|
float SGCloudField::CloudVis = 25000.0f;
|
||||||
bool SGCloudField::enable3D = true;
|
bool SGCloudField::enable3D = false;
|
||||||
// fieldSize must be > CloudVis or we can destroy the impostor cache
|
// 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
|
// 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;
|
float SGCloudField::density = 100.0;
|
||||||
|
double SGCloudField::timer_dt = 0.0;
|
||||||
|
sgVec3 SGCloudField::view_vec;
|
||||||
|
|
||||||
static int last_cache_size = 1*1024;
|
static int last_cache_size = 1*1024;
|
||||||
static int cacheResolution = 64;
|
static int cacheResolution = 64;
|
||||||
|
static sgVec3 last_sunlight={0.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
int SGCloudField::get_CacheResolution(void) {
|
int SGCloudField::get_CacheResolution(void) {
|
||||||
return cacheResolution;
|
return cacheResolution;
|
||||||
@ -85,7 +89,6 @@ void SGCloudField::set_CacheSize(int sizeKb) {
|
|||||||
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
|
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
|
||||||
if(count == 0)
|
if(count == 0)
|
||||||
count = 1;
|
count = 1;
|
||||||
// SGNewCloud::cldCache->setCacheSize(sizeKb);
|
|
||||||
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
|
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,14 +104,17 @@ void SGCloudField::set_enable3dClouds(bool enable) {
|
|||||||
return;
|
return;
|
||||||
enable3D = enable;
|
enable3D = enable;
|
||||||
if(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 {
|
} else {
|
||||||
SGNewCloud::cldCache->setCacheSize(0);
|
SGNewCloud::cldCache->setCacheSize(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reposition the cloud layer at the specified origin and orientation
|
// 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) {
|
||||||
sgMat4 T1, LON, LAT;
|
sgMat4 T1, LON, LAT;
|
||||||
sgVec3 axis;
|
sgVec3 axis;
|
||||||
|
|
||||||
@ -135,8 +141,6 @@ void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, doub
|
|||||||
this->alt = alt;
|
this->alt = alt;
|
||||||
|
|
||||||
// simulate clouds movement from wind
|
// simulate clouds movement from wind
|
||||||
double speed = 10.0f;
|
|
||||||
double direction = 45.0;
|
|
||||||
double sp_dist = speed*dt;
|
double sp_dist = speed*dt;
|
||||||
if (sp_dist > 0) {
|
if (sp_dist > 0) {
|
||||||
double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
|
double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
|
||||||
@ -181,11 +185,16 @@ void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, doub
|
|||||||
// correct the frustum with the right far plane
|
// correct the frustum with the right far plane
|
||||||
ssgContext *context = ssgGetCurrentContext();
|
ssgContext *context = ssgGetCurrentContext();
|
||||||
frustum = *context->getFrustum();
|
frustum = *context->getFrustum();
|
||||||
frustum.setFOV(55.0,0);
|
|
||||||
|
float w, h;
|
||||||
|
sgEnviro.getFOV( w, h );
|
||||||
|
frustum.setFOV( w, h );
|
||||||
frustum.setNearFar(1.0, CloudVis);
|
frustum.setNearFar(1.0, CloudVis);
|
||||||
|
timer_dt = dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGCloudField::SGCloudField() :
|
SGCloudField::SGCloudField() :
|
||||||
|
draw_in_3d(true),
|
||||||
last_density(0.0),
|
last_density(0.0),
|
||||||
deltax(0.0),
|
deltax(0.0),
|
||||||
deltay(0.0),
|
deltay(0.0),
|
||||||
@ -206,6 +215,18 @@ SGCloudField::~SGCloudField() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SGCloudField::clear(void) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// use a table or else we see poping when moving the slider...
|
// use a table or else we see poping when moving the slider...
|
||||||
static int densTable[][10] = {
|
static int densTable[][10] = {
|
||||||
{0,0,0,0,0,0,0,0,0,0},
|
{0,0,0,0,0,0,0,0,0,0},
|
||||||
@ -235,15 +256,16 @@ void SGCloudField::applyDensity(void) {
|
|||||||
iCloud->visible = false;
|
iCloud->visible = false;
|
||||||
}
|
}
|
||||||
last_density = density;
|
last_density = density;
|
||||||
|
draw_in_3d = ( theField.size() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add one cloud, data is not copied, ownership given
|
// add one cloud, data is not copied, ownership given
|
||||||
void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
|
void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
|
||||||
Cloud cl;
|
Cloud cl;
|
||||||
sgCopyVec3( cl.pos, pos );
|
|
||||||
cl.aCloud = cloud;
|
cl.aCloud = cloud;
|
||||||
cl.visible = true;
|
cl.visible = true;
|
||||||
cloud->SetPos( pos );
|
cloud->SetPos( pos );
|
||||||
|
sgCopyVec3( cl.pos, *cloud->getCenter() );
|
||||||
theField.push_back( cl );
|
theField.push_back( cl );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +282,7 @@ void SGCloudField::buildTestLayer(void) {
|
|||||||
|
|
||||||
for( int z = -5 ; z <= 5 ; z++) {
|
for( int z = -5 ; z <= 5 ; z++) {
|
||||||
for( int x = -5 ; x <= 5 ; x++ ) {
|
for( int x = -5 ; x <= 5 ; x++ ) {
|
||||||
SGNewCloud *cloud = new SGNewCloud;
|
SGNewCloud *cloud = new SGNewCloud(SGNewCloud::CLFamilly_cu);
|
||||||
cloud->new_cu();
|
cloud->new_cu();
|
||||||
sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
|
sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
|
||||||
addCloud(pos, cloud);
|
addCloud(pos, cloud);
|
||||||
@ -291,6 +313,8 @@ void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) {
|
|||||||
sgCopyVec3( tmp.eyePos, eyePos );
|
sgCopyVec3( tmp.eyePos, eyePos );
|
||||||
// save distance for later sort, opposite distance because we want back to front
|
// save distance for later sort, opposite distance because we want back to front
|
||||||
tmp.dist = - squareDist;
|
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);
|
inViewClouds.push_back(tmp);
|
||||||
if( squareDist - radius*radius < 100*100 )
|
if( squareDist - radius*radius < 100*100 )
|
||||||
sgEnviro.set_view_in_cloud(true);
|
sgEnviro.set_view_in_cloud(true);
|
||||||
@ -316,9 +340,11 @@ void SGCloudField::Render(void) {
|
|||||||
applyDensity();
|
applyDensity();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ask the impostor cache to do some cleanup
|
if( ! draw_in_3d )
|
||||||
// TODO:don't do that for every field
|
return;
|
||||||
SGNewCloud::cldCache->startNewFrame();
|
|
||||||
|
if( ! SGNewCloud::cldCache->isRttAvailable() )
|
||||||
|
return;
|
||||||
|
|
||||||
inViewClouds.clear();
|
inViewClouds.clear();
|
||||||
|
|
||||||
@ -332,14 +358,22 @@ void SGCloudField::Render(void) {
|
|||||||
sgVec3 lightVec;
|
sgVec3 lightVec;
|
||||||
ssgGetLight( 0 )->getPosition( lightVec );
|
ssgGetLight( 0 )->getPosition( lightVec );
|
||||||
sgXformVec3( lightVec, invtrans );
|
sgXformVec3( lightVec, invtrans );
|
||||||
sgCopyVec3( SGNewCloud::modelSunDir, lightVec );
|
|
||||||
sgSetVec3( SGNewCloud::modelSunDir, lightVec[0], lightVec[2], lightVec[1]);
|
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;
|
sgVec4 diffuse, ambient;
|
||||||
ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse );
|
ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse );
|
||||||
ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient );
|
ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient );
|
||||||
sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 0.70f);
|
sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 1.0f);
|
||||||
sgScaleVec3 ( SGNewCloud::ambLight, ambient , 0.60f);
|
sgScaleVec3 ( SGNewCloud::ambLight, ambient , 1.0f);
|
||||||
|
|
||||||
|
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
|
// voodoo things on the matrix stack
|
||||||
ssgGetModelviewMatrix( modelview );
|
ssgGetModelviewMatrix( modelview );
|
||||||
@ -348,10 +382,13 @@ void SGCloudField::Render(void) {
|
|||||||
|
|
||||||
// cloud fields are tiled on the flat earth
|
// cloud fields are tiled on the flat earth
|
||||||
// compute the position in the tile
|
// compute the position in the tile
|
||||||
relx = -fmod( deltax + relative_position[SG_X] + tmp[3][0], fieldSize );
|
relx = fmod( deltax + relative_position[SG_X] + tmp[3][0], fieldSize );
|
||||||
rely = -fmod( deltay + relative_position[SG_Y] + tmp[3][1], fieldSize );
|
rely = fmod( deltay + relative_position[SG_Y] + tmp[3][1], fieldSize );
|
||||||
|
|
||||||
sgSetVec3( eyePos, -relx, alt, -rely);
|
relx = fmod( relx + fieldSize, fieldSize );
|
||||||
|
rely = fmod( rely + fieldSize, fieldSize );
|
||||||
|
sgSetVec3( eyePos, relx, alt, rely);
|
||||||
|
sgCopyVec3( view_vec, tmp[1] );
|
||||||
|
|
||||||
tmp[3][2] = 0;
|
tmp[3][2] = 0;
|
||||||
tmp[3][0] = 0;
|
tmp[3][0] = 0;
|
||||||
@ -400,6 +437,8 @@ void SGCloudField::Render(void) {
|
|||||||
for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) {
|
for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) {
|
||||||
// iCloud->aCloud->drawContainers();
|
// iCloud->aCloud->drawContainers();
|
||||||
iCloud->aCloud->Render(iCloud->eyePos);
|
iCloud->aCloud->Render(iCloud->eyePos);
|
||||||
|
sgEnviro.callback_cloud(iCloud->heading, iCloud->alt,
|
||||||
|
iCloud->aCloud->getRadius(), iCloud->aCloud->getFamilly(), - iCloud->dist);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
@ -37,12 +37,17 @@ public:
|
|||||||
SGNewCloud *aCloud;
|
SGNewCloud *aCloud;
|
||||||
sgVec3 eyePos;
|
sgVec3 eyePos;
|
||||||
float dist;
|
float dist;
|
||||||
|
float heading;
|
||||||
|
float alt;
|
||||||
bool operator<(const culledCloud &b) const {
|
bool operator<(const culledCloud &b) const {
|
||||||
return this->dist < b.dist;
|
return (this->dist < b.dist);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typedef vector<culledCloud> list_of_culledCloud;
|
typedef vector<culledCloud> list_of_culledCloud;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A layer of 3D clouds.
|
||||||
|
*/
|
||||||
class SGCloudField {
|
class SGCloudField {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -51,12 +56,6 @@ private:
|
|||||||
SGNewCloud *aCloud;
|
SGNewCloud *aCloud;
|
||||||
sgVec3 pos;
|
sgVec3 pos;
|
||||||
bool visible;
|
bool visible;
|
||||||
// float dist;
|
|
||||||
// bool culled;
|
|
||||||
|
|
||||||
// bool operator<(const Cloud &b) {
|
|
||||||
// return this->dist < b.dist;
|
|
||||||
// }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -79,12 +78,15 @@ private:
|
|||||||
double last_lon, last_lat, last_course;
|
double last_lon, last_lat, last_course;
|
||||||
|
|
||||||
float last_density;
|
float last_density;
|
||||||
|
bool draw_in_3d;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SGCloudField();
|
SGCloudField();
|
||||||
~SGCloudField();
|
~SGCloudField();
|
||||||
|
|
||||||
|
void clear(void);
|
||||||
|
|
||||||
// add one cloud, data is not copied, ownership given
|
// add one cloud, data is not copied, ownership given
|
||||||
void addCloud( sgVec3 pos, SGNewCloud *cloud);
|
void addCloud( sgVec3 pos, SGNewCloud *cloud);
|
||||||
|
|
||||||
@ -95,13 +97,17 @@ public:
|
|||||||
void Render(void);
|
void Render(void);
|
||||||
|
|
||||||
// reposition the cloud layer at the specified origin and orientation
|
// reposition the cloud layer at the specified origin and orientation
|
||||||
void reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt);
|
void reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed);
|
||||||
|
|
||||||
|
bool is3D(void) { return draw_in_3d; }
|
||||||
|
|
||||||
// visibility distance for clouds in meters
|
// visibility distance for clouds in meters
|
||||||
static float CloudVis;
|
static float CloudVis;
|
||||||
|
|
||||||
static float density;
|
static sgVec3 view_vec;
|
||||||
|
|
||||||
|
static float density;
|
||||||
|
static double timer_dt;
|
||||||
static double fieldSize;
|
static double fieldSize;
|
||||||
static bool enable3D;
|
static bool enable3D;
|
||||||
|
|
||||||
|
@ -47,6 +47,8 @@ static ssgTexture *cloudTextures[SGNewCloud::CLTexture_max];
|
|||||||
bool SGNewCloud::useAnisotropic = true;
|
bool SGNewCloud::useAnisotropic = true;
|
||||||
SGBbCache *SGNewCloud::cldCache = 0;
|
SGBbCache *SGNewCloud::cldCache = 0;
|
||||||
static bool texturesLoaded = false;
|
static bool texturesLoaded = false;
|
||||||
|
static float minx, maxx, miny, maxy, minz, maxz;
|
||||||
|
|
||||||
float SGNewCloud::nearRadius = 3500.0f;
|
float SGNewCloud::nearRadius = 3500.0f;
|
||||||
bool SGNewCloud::lowQuality = false;
|
bool SGNewCloud::lowQuality = false;
|
||||||
sgVec3 SGNewCloud::sunlight = {0.5f, 0.5f, 0.5f};
|
sgVec3 SGNewCloud::sunlight = {0.5f, 0.5f, 0.5f};
|
||||||
@ -54,25 +56,60 @@ sgVec3 SGNewCloud::ambLight = {0.5f, 0.5f, 0.5f};
|
|||||||
sgVec3 SGNewCloud::modelSunDir = {0,1,0};
|
sgVec3 SGNewCloud::modelSunDir = {0,1,0};
|
||||||
|
|
||||||
|
|
||||||
// constructor
|
void SGNewCloud::init(void) {
|
||||||
SGNewCloud::SGNewCloud() :
|
bbId = -1;
|
||||||
bbId(-1),
|
fadeActive = false;
|
||||||
// rank(-1),
|
duration = 100.0f;
|
||||||
minx(999), miny(999), minz(999), maxx(-999), maxy(-999), maxz(-999)
|
fadetimer = 100.0f;
|
||||||
|
pauseLength = 0.0f;
|
||||||
{
|
last_step = -1.0f;
|
||||||
|
familly = CLFamilly_nn;
|
||||||
cloudId = (int) this;
|
cloudId = (int) this;
|
||||||
sgSetVec3(center, 0.0f, 0.0f, 0.0f);
|
sgSetVec3(center, 0.0f, 0.0f, 0.0f);
|
||||||
sgSetVec3(cloudpos, 0.0f, 0.0f, 0.0f);
|
sgSetVec3(cloudpos, 0.0f, 0.0f, 0.0f);
|
||||||
|
radius = 0.0f;
|
||||||
|
delta_base = 0.0f;
|
||||||
list_spriteContainer.reserve(8);
|
list_spriteContainer.reserve(8);
|
||||||
list_spriteDef.reserve(40);
|
list_spriteDef.reserve(40);
|
||||||
// if( ! texturesLoaded ) {}
|
|
||||||
if( cldCache == 0 ) {
|
if( cldCache == 0 ) {
|
||||||
cldCache = new SGBbCache;
|
cldCache = new SGBbCache;
|
||||||
cldCache->init( 64 );
|
cldCache->init( 64 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
SGNewCloud::SGNewCloud(CLFamilly_type classification)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
familly = classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGNewCloud::SGNewCloud(string classification)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
if( classification == "cu" )
|
||||||
|
familly = CLFamilly_cu;
|
||||||
|
else if( classification == "cb" )
|
||||||
|
familly = CLFamilly_cb;
|
||||||
|
else if( classification == "st" )
|
||||||
|
familly = CLFamilly_st;
|
||||||
|
else if( classification == "ns" )
|
||||||
|
familly = CLFamilly_ns;
|
||||||
|
else if( classification == "sc" )
|
||||||
|
familly = CLFamilly_sc;
|
||||||
|
else if( classification == "as" )
|
||||||
|
familly = CLFamilly_as;
|
||||||
|
else if( classification == "ac" )
|
||||||
|
familly = CLFamilly_ac;
|
||||||
|
else if( classification == "ci" )
|
||||||
|
familly = CLFamilly_ci;
|
||||||
|
else if( classification == "cc" )
|
||||||
|
familly = CLFamilly_cc;
|
||||||
|
else if( classification == "cs" )
|
||||||
|
familly = CLFamilly_cs;
|
||||||
|
}
|
||||||
|
|
||||||
SGNewCloud::~SGNewCloud() {
|
SGNewCloud::~SGNewCloud() {
|
||||||
list_spriteDef.clear();
|
list_spriteDef.clear();
|
||||||
list_spriteContainer.clear();
|
list_spriteContainer.clear();
|
||||||
@ -101,12 +138,26 @@ void SGNewCloud::loadTextures(const string &tex_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SGNewCloud::startFade(bool direction, float duration, float pauseLength) {
|
void SGNewCloud::startFade(bool direction, float duration, float pauseLength) {
|
||||||
|
if(duration <= 0.0) {
|
||||||
|
fadeActive = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->direction = direction;
|
||||||
|
fadetimer = 0.0;
|
||||||
|
this->duration = duration;
|
||||||
|
this->pauseLength = pauseLength;
|
||||||
|
last_step = -1.0;
|
||||||
|
fadeActive = true;
|
||||||
}
|
}
|
||||||
void SGNewCloud::setFade(float howMuch) {
|
void SGNewCloud::setFade(float howMuch) {
|
||||||
|
duration = 100.0;
|
||||||
|
fadetimer = howMuch;
|
||||||
|
fadeActive = false;
|
||||||
|
last_step = -1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static float rayleighCoeffAngular(float cosAngle) {
|
static inline float rayleighCoeffAngular(float cosAngle) {
|
||||||
return 3.0f / 4.0f * (1.0f + cosAngle * cosAngle);
|
return 3.0f / 4.0f * (1.0f + cosAngle * cosAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,10 +179,10 @@ static void PolarToCart3d(sgVec3 p, sgVec3 cart) {
|
|||||||
// compute the light for a cloud sprite corner
|
// compute the light for a cloud sprite corner
|
||||||
// from the normal and the sun, scaled by the Rayleigh factor
|
// from the normal and the sun, scaled by the Rayleigh factor
|
||||||
// and finaly added to the ambient light
|
// and finaly added to the ambient light
|
||||||
static void lightFunction(sgVec3 normal, sgVec4 light, float pf) {
|
static inline void lightFunction(sgVec3 normal, sgVec4 light, float pf) {
|
||||||
float cosAngle = sgScalarProductVec3( normal, SGNewCloud::modelSunDir);
|
float cosAngle = sgScalarProductVec3( normal, SGNewCloud::modelSunDir);
|
||||||
float vl = (1.0f - 0.1f + cosAngle / 10.0f) * pf;
|
float vl = (1.0f - 0.5f + cosAngle * 0.5f) * pf;
|
||||||
sgScaleVec3( light, SGNewCloud::sunlight, vl );
|
sgScaleVec3( light, SGNewCloud::sunlight, 0.25f + 0.75f * vl );
|
||||||
sgAddVec3( light, SGNewCloud::ambLight );
|
sgAddVec3( light, SGNewCloud::ambLight );
|
||||||
// we need to clamp or else the light will bug when adding transparency
|
// we need to clamp or else the light will bug when adding transparency
|
||||||
if( light[0] > 1.0 ) light[0] = 1.0;
|
if( light[0] > 1.0 ) light[0] = 1.0;
|
||||||
@ -142,11 +193,10 @@ static void lightFunction(sgVec3 normal, sgVec4 light, float pf) {
|
|||||||
|
|
||||||
// compute the light for a cloud sprite
|
// compute the light for a cloud sprite
|
||||||
// we use ambient light and orientation versus sun position
|
// we use ambient light and orientation versus sun position
|
||||||
// TODO:check sun pos and check code
|
|
||||||
void SGNewCloud::computeSimpleLight(sgVec3 FakeEyePos) {
|
void SGNewCloud::computeSimpleLight(sgVec3 FakeEyePos) {
|
||||||
// constant Rayleigh factor if we are not doing Anisotropic lighting
|
// constant Rayleigh factor if we are not doing Anisotropic lighting
|
||||||
float pf = 1.0f;
|
float pf = 1.0f;
|
||||||
const float ang = 45.0f * SG_PI / 180.0f;
|
|
||||||
list_of_spriteDef::iterator iSprite;
|
list_of_spriteDef::iterator iSprite;
|
||||||
for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
|
for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
|
||||||
if( useAnisotropic ) {
|
if( useAnisotropic ) {
|
||||||
@ -156,44 +206,11 @@ void SGNewCloud::computeSimpleLight(sgVec3 FakeEyePos) {
|
|||||||
float cosAngle = sgScalarProductVec3(eyeDir, modelSunDir);
|
float cosAngle = sgScalarProductVec3(eyeDir, modelSunDir);
|
||||||
pf = rayleighCoeffAngular(cosAngle);
|
pf = rayleighCoeffAngular(cosAngle);
|
||||||
}
|
}
|
||||||
// compute the vector going from the container box center to the sprite
|
lightFunction(iSprite->n0, iSprite->l0, pf);
|
||||||
// TODO : this is a constant except for cloudpos, compute the normal in setpos function
|
lightFunction(iSprite->n1, iSprite->l1, pf);
|
||||||
sgVec3 normal;
|
lightFunction(iSprite->n2, iSprite->l2, pf);
|
||||||
spriteContainer *thisSpriteContainer = &list_spriteContainer[iSprite->box];
|
lightFunction(iSprite->n3, iSprite->l3, pf);
|
||||||
sgSubVec3(normal, iSprite->pos, thisSpriteContainer->pos);
|
|
||||||
sgSubVec3(normal, thisSpriteContainer->center);
|
|
||||||
sgSubVec3(normal, cloudpos);
|
|
||||||
sgNormaliseVec3(normal);
|
|
||||||
if( lowQuality ) {
|
|
||||||
// juste use the traditional normal to compute some lightning
|
|
||||||
sgVec4 centerColor;
|
|
||||||
lightFunction(normal, centerColor, pf);
|
|
||||||
sgCopyVec4(iSprite->l0, centerColor);
|
|
||||||
sgCopyVec4(iSprite->l1, centerColor);
|
|
||||||
sgCopyVec4(iSprite->l2, centerColor);
|
|
||||||
sgCopyVec4(iSprite->l3, centerColor);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// use exotic lightning function, this will give more 'relief' to the clouds
|
|
||||||
// compute a normal for each vextex this will simulate a smooth shading for a round shape
|
|
||||||
sgVec3 polar, cart, pt;
|
|
||||||
// I suspect this code to be bugged...
|
|
||||||
CartToPolar3d(normal, polar);
|
|
||||||
|
|
||||||
// offset the normal vector by some angle for each vertex
|
|
||||||
sgSetVec3(pt, polar[0] - ang, polar[1] - ang, polar[2]);
|
|
||||||
PolarToCart3d(pt, cart);
|
|
||||||
lightFunction(cart, iSprite->l0, pf);
|
|
||||||
sgSetVec3(pt, polar[0] + ang, polar[1] - ang, polar[2]);
|
|
||||||
PolarToCart3d(pt, cart);
|
|
||||||
lightFunction(cart, iSprite->l1, pf);
|
|
||||||
sgSetVec3(pt, polar[0] + ang, polar[1] + ang, polar[2]);
|
|
||||||
PolarToCart3d(pt, cart);
|
|
||||||
lightFunction(cart, iSprite->l2, pf);
|
|
||||||
sgSetVec3(pt, polar[0] - ang, polar[1] + ang, polar[2]);
|
|
||||||
PolarToCart3d(pt, cart);
|
|
||||||
lightFunction(cart, iSprite->l3, pf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,13 +223,16 @@ void SGNewCloud::addContainer (float x, float y, float z, float r, CLbox_type ty
|
|||||||
cont.cont_type = type;
|
cont.cont_type = type;
|
||||||
sgSetVec3( cont.center, 0.0f, 0.0f, 0.0f);
|
sgSetVec3( cont.center, 0.0f, 0.0f, 0.0f);
|
||||||
list_spriteContainer.push_back( cont );
|
list_spriteContainer.push_back( cont );
|
||||||
|
// don't place cloud below his base
|
||||||
|
if( y - r*0.50 < delta_base )
|
||||||
|
delta_base = y - r*0.50;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add a sprite inside a box
|
// add a sprite inside a box
|
||||||
void SGNewCloud::addSprite(float x, float y, float z, float r, CLbox_type type, int box) {
|
void SGNewCloud::addSprite(float x, float y, float z, float r, CLbox_type type, int box) {
|
||||||
spriteDef newSpriteDef;
|
spriteDef newSpriteDef;
|
||||||
int rank = list_spriteDef.size();
|
int rank = list_spriteDef.size();
|
||||||
sgSetVec3( newSpriteDef.pos, x, y, z);
|
sgSetVec3( newSpriteDef.pos, x, y - delta_base, z);
|
||||||
newSpriteDef.box = box;
|
newSpriteDef.box = box;
|
||||||
newSpriteDef.sprite_type = type;
|
newSpriteDef.sprite_type = type;
|
||||||
newSpriteDef.rank = rank;
|
newSpriteDef.rank = rank;
|
||||||
@ -223,7 +243,7 @@ void SGNewCloud::addSprite(float x, float y, float z, float r, CLbox_type type,
|
|||||||
sgSubVec3( deltaPos, newSpriteDef.pos, thisBox->pos );
|
sgSubVec3( deltaPos, newSpriteDef.pos, thisBox->pos );
|
||||||
sgAddVec3( thisBox->center, deltaPos );
|
sgAddVec3( thisBox->center, deltaPos );
|
||||||
|
|
||||||
r = r * 0.6f; // 0.5 * 1.xxx
|
r = r * 0.65f; // 0.5 * 1.xxx
|
||||||
if( x - r < minx )
|
if( x - r < minx )
|
||||||
minx = x - r;
|
minx = x - r;
|
||||||
if( y - r < miny )
|
if( y - r < miny )
|
||||||
@ -248,19 +268,21 @@ static float Rnd(float n) {
|
|||||||
void SGNewCloud::genSprites( void ) {
|
void SGNewCloud::genSprites( void ) {
|
||||||
float x, y, z, r;
|
float x, y, z, r;
|
||||||
int N, sc;
|
int N, sc;
|
||||||
|
minx = miny = minz = 99999.0;
|
||||||
|
maxx = maxy = maxz = -99999.0;
|
||||||
|
|
||||||
N = list_spriteContainer.size();
|
N = list_spriteContainer.size();
|
||||||
for(int i = 0 ; i < N ; i++ ) {
|
for(int i = 0 ; i < N ; i++ ) {
|
||||||
spriteContainer *thisBox = & list_spriteContainer[i];
|
spriteContainer *thisBox = & list_spriteContainer[i];
|
||||||
// the type defines how the sprites can be positioned inside the box, their size, etc
|
// the type defines how the sprites can be positioned inside the box, their size, etc
|
||||||
switch(thisBox->cont_type) {
|
switch(thisBox->cont_type) {
|
||||||
case CLbox_sc:
|
case CLbox_sc:
|
||||||
for( sc = 0 ; sc <= 4 ; sc ++ ) {
|
sc = 1;
|
||||||
r = thisBox->r + Rnd(0.2f);
|
r = thisBox->r + Rnd(0.2f);
|
||||||
x = thisBox->pos[SG_X] + Rnd(thisBox->r);
|
x = thisBox->pos[SG_X] + Rnd(thisBox->r * 0.75f);
|
||||||
y = thisBox->pos[SG_Y] + Rnd(thisBox->r * 0.2f);
|
y = thisBox->pos[SG_Y] + Rnd(thisBox->r * 0.75f);
|
||||||
z = thisBox->pos[SG_Z] + Rnd(thisBox->r);
|
z = thisBox->pos[SG_Z] + Rnd(thisBox->r * 0.75f);
|
||||||
addSprite(x, y, z, r, thisBox->cont_type, i);
|
addSprite(x, y, z, r, thisBox->cont_type, i);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLbox_stratus:
|
case CLbox_stratus:
|
||||||
sc = 1;
|
sc = 1;
|
||||||
@ -302,10 +324,46 @@ void SGNewCloud::genSprites( void ) {
|
|||||||
radius /= 2.0f;
|
radius /= 2.0f;
|
||||||
sgSetVec3( center, (maxx + minx) / 2.0f, (maxy + miny) / 2.0f, (maxz + minz) / 2.0f );
|
sgSetVec3( center, (maxx + minx) / 2.0f, (maxy + miny) / 2.0f, (maxz + minz) / 2.0f );
|
||||||
|
|
||||||
/* fadingrank = 0
|
const float ang = 45.0f * SG_PI / 180.0f;
|
||||||
' fadingrank = UBound(tbSpriteDef()) * 10
|
|
||||||
fadingdir = 0*/
|
// compute normals
|
||||||
// TODO : compute initial sprite normals for lighting function
|
list_of_spriteDef::iterator iSprite;
|
||||||
|
for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
|
||||||
|
sgVec3 normal;
|
||||||
|
spriteContainer *thisSpriteContainer = &list_spriteContainer[iSprite->box];
|
||||||
|
if( familly == CLFamilly_sc || familly == CLFamilly_cu || familly == CLFamilly_cb) {
|
||||||
|
sgSubVec3(normal, iSprite->pos, center);
|
||||||
|
} else {
|
||||||
|
sgSubVec3(normal, iSprite->pos, thisSpriteContainer->pos);
|
||||||
|
sgSubVec3(normal, thisSpriteContainer->center);
|
||||||
|
sgSubVec3(normal, cloudpos);
|
||||||
|
}
|
||||||
|
if( normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f )
|
||||||
|
sgSetVec3( normal, 0.0f, 1.0f, 0.0f );
|
||||||
|
sgNormaliseVec3(normal);
|
||||||
|
// use exotic lightning function, this will give more 'relief' to the clouds
|
||||||
|
// compute a normal for each vextex this will simulate a smooth shading for a round shape
|
||||||
|
sgVec3 polar, pt;
|
||||||
|
// I suspect this code to be bugged...
|
||||||
|
CartToPolar3d(normal, polar);
|
||||||
|
sgCopyVec3(iSprite->normal, normal);
|
||||||
|
|
||||||
|
// offset the normal vector by some angle for each vertex
|
||||||
|
sgSetVec3(pt, polar[0] - ang, polar[1] - ang, polar[2]);
|
||||||
|
PolarToCart3d(pt, iSprite->n0);
|
||||||
|
sgSetVec3(pt, polar[0] + ang, polar[1] - ang, polar[2]);
|
||||||
|
PolarToCart3d(pt, iSprite->n1);
|
||||||
|
sgSetVec3(pt, polar[0] + ang, polar[1] + ang, polar[2]);
|
||||||
|
PolarToCart3d(pt, iSprite->n2);
|
||||||
|
sgSetVec3(pt, polar[0] - ang, polar[1] + ang, polar[2]);
|
||||||
|
PolarToCart3d(pt, iSprite->n3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// experimental : clouds are dissipating with time
|
||||||
|
if( familly == CLFamilly_cu ) {
|
||||||
|
startFade(true, 300.0f, 30.0f);
|
||||||
|
fadetimer = sg_random() * 300.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -364,7 +422,6 @@ void SGNewCloud::SetPos(sgVec3 newPos) {
|
|||||||
}
|
}
|
||||||
sgAddVec3( center, deltaPos );
|
sgAddVec3( center, deltaPos );
|
||||||
sgSetVec3( cloudpos, newPos[SG_X], newPos[SG_Y], newPos[SG_Z]);
|
sgSetVec3( cloudpos, newPos[SG_X], newPos[SG_Y], newPos[SG_Z]);
|
||||||
// TODO : recompute sprite normal so we don't have to redo that each frame
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -393,18 +450,30 @@ void SGNewCloud::sortSprite( sgVec3 eye ) {
|
|||||||
// render the cloud on screen or on the RTT texture to build the impostor
|
// render the cloud on screen or on the RTT texture to build the impostor
|
||||||
void SGNewCloud::Render3Dcloud( bool drawBB, sgVec3 FakeEyePos, sgVec3 deltaPos, float dist_center ) {
|
void SGNewCloud::Render3Dcloud( bool drawBB, sgVec3 FakeEyePos, sgVec3 deltaPos, float dist_center ) {
|
||||||
|
|
||||||
/* int clrank = fadingrank / 10;
|
float step = ( list_spriteDef.size() * (direction ? fadetimer : duration-fadetimer)) / duration;
|
||||||
int clfadeinrank = fadingrank - clrank * 10;*/
|
int clrank = (int) step;
|
||||||
float CloudVisFade = 1.0 / (1.5 * SGCloudField::get_CloudVis());
|
float clfadeinrank = (step - clrank);
|
||||||
|
last_step = step;
|
||||||
|
|
||||||
|
float CloudVisFade = 1.0 / (0.7f * SGCloudField::get_CloudVis());
|
||||||
|
// blend clouds with sky based on distance to limit the contrast of distant cloud
|
||||||
|
float t = 1.0f - dist_center * CloudVisFade;
|
||||||
|
// if ( t < 0.0f )
|
||||||
|
// return;
|
||||||
|
|
||||||
computeSimpleLight( FakeEyePos );
|
computeSimpleLight( FakeEyePos );
|
||||||
|
|
||||||
// view point sort, we sort because of transparency
|
// view point sort, we sort because of transparency
|
||||||
sortSprite( FakeEyePos );
|
sortSprite( FakeEyePos );
|
||||||
|
|
||||||
|
float dark = (familly == CLFamilly_cb ? 0.9f : 1.0f);
|
||||||
|
|
||||||
GLint previousTexture = -1, thisTexture;
|
GLint previousTexture = -1, thisTexture;
|
||||||
list_of_spriteDef::iterator iSprite;
|
list_of_spriteDef::iterator iSprite;
|
||||||
for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
|
for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
|
||||||
|
// skip this sprite if faded
|
||||||
|
if(iSprite->rank > clrank)
|
||||||
|
continue;
|
||||||
// choose texture to use depending on sprite type
|
// choose texture to use depending on sprite type
|
||||||
switch(iSprite->sprite_type) {
|
switch(iSprite->sprite_type) {
|
||||||
case CLbox_stratus:
|
case CLbox_stratus:
|
||||||
@ -421,11 +490,6 @@ void SGNewCloud::Render3Dcloud( bool drawBB, sgVec3 FakeEyePos, sgVec3 deltaPos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sgVec3 translate;
|
sgVec3 translate;
|
||||||
if( drawBB ) {
|
|
||||||
sgCopyVec3( translate, iSprite->pos);
|
|
||||||
sgSubVec3( translate, iSprite->pos, deltaPos );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sgSubVec3( translate, iSprite->pos, deltaPos);
|
sgSubVec3( translate, iSprite->pos, deltaPos);
|
||||||
|
|
||||||
|
|
||||||
@ -433,24 +497,33 @@ void SGNewCloud::Render3Dcloud( bool drawBB, sgVec3 FakeEyePos, sgVec3 deltaPos,
|
|||||||
float flipx = (float) ( iSprite->rank & 1 );
|
float flipx = (float) ( iSprite->rank & 1 );
|
||||||
float flipy = (float) ( (iSprite->rank >> 1) & 1 );
|
float flipy = (float) ( (iSprite->rank >> 1) & 1 );
|
||||||
// cu texture have a flat bottom so we can't do a vertical flip
|
// cu texture have a flat bottom so we can't do a vertical flip
|
||||||
if( iSprite->sprite_type == CLbox_cumulus || iSprite->sprite_type == CLbox_stratus )
|
if( iSprite->sprite_type == CLbox_cumulus )
|
||||||
flipy = 0.0f;
|
flipy = 0.0f;
|
||||||
if( iSprite->sprite_type == CLbox_stratus )
|
// if( iSprite->sprite_type == CLbox_stratus )
|
||||||
flipx = 0.0f;
|
// flipx = 0.0f;
|
||||||
// adjust colors depending on cloud type
|
// adjust colors depending on cloud type
|
||||||
// TODO : rewrite that later, still experimental
|
// TODO : rewrite that later, still experimental
|
||||||
switch(iSprite->sprite_type) {
|
switch(iSprite->sprite_type) {
|
||||||
case CLbox_cumulus:
|
case CLbox_cumulus:
|
||||||
// dark bottom
|
// dark bottom
|
||||||
sgScaleVec3(iSprite->l0, 0.6f);
|
sgScaleVec3(iSprite->l0, 0.8f * dark);
|
||||||
sgScaleVec3(iSprite->l1, 0.6f);
|
sgScaleVec3(iSprite->l1, 0.8f * dark);
|
||||||
|
sgScaleVec3(iSprite->l2, dark);
|
||||||
|
sgScaleVec3(iSprite->l3, dark);
|
||||||
break;
|
break;
|
||||||
case CLbox_stratus:
|
case CLbox_stratus:
|
||||||
// usually dark grey
|
// usually dark grey
|
||||||
|
if( familly == CLFamilly_st ) {
|
||||||
sgScaleVec3(iSprite->l0, 0.8f);
|
sgScaleVec3(iSprite->l0, 0.8f);
|
||||||
sgScaleVec3(iSprite->l1, 0.8f);
|
sgScaleVec3(iSprite->l1, 0.8f);
|
||||||
sgScaleVec3(iSprite->l2, 0.8f);
|
sgScaleVec3(iSprite->l2, 0.8f);
|
||||||
sgScaleVec3(iSprite->l3, 0.8f);
|
sgScaleVec3(iSprite->l3, 0.8f);
|
||||||
|
} else {
|
||||||
|
sgScaleVec3(iSprite->l0, 0.7f);
|
||||||
|
sgScaleVec3(iSprite->l1, 0.7f);
|
||||||
|
sgScaleVec3(iSprite->l2, 0.7f);
|
||||||
|
sgScaleVec3(iSprite->l3, 0.7f);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// darker bottom than top
|
// darker bottom than top
|
||||||
@ -466,27 +539,40 @@ void SGNewCloud::Render3Dcloud( bool drawBB, sgVec3 FakeEyePos, sgVec3 deltaPos,
|
|||||||
sgCopyVec4 ( l2, iSprite->l2 );
|
sgCopyVec4 ( l2, iSprite->l2 );
|
||||||
sgCopyVec4 ( l3, iSprite->l3 );
|
sgCopyVec4 ( l3, iSprite->l3 );
|
||||||
if( ! drawBB ) {
|
if( ! drawBB ) {
|
||||||
// blend clouds with sky based on distance to limit the contrast of distant cloud
|
|
||||||
float t = 1.0f - dist_center * CloudVisFade;
|
|
||||||
if ( t < 0.0f )
|
|
||||||
t = 0.0f; // no, it should have been culled
|
|
||||||
// now clouds at the far plane are half blended
|
// now clouds at the far plane are half blended
|
||||||
sgScaleVec4( l0, t );
|
sgScaleVec4( l0, t );
|
||||||
sgScaleVec4( l1, t );
|
sgScaleVec4( l1, t );
|
||||||
sgScaleVec4( l2, t );
|
sgScaleVec4( l2, t );
|
||||||
sgScaleVec4( l3, t );
|
sgScaleVec4( l3, t );
|
||||||
}
|
}
|
||||||
|
if( iSprite->rank == clrank ) {
|
||||||
|
sgScaleVec4( l0, clfadeinrank );
|
||||||
|
sgScaleVec4( l1, clfadeinrank );
|
||||||
|
sgScaleVec4( l2, clfadeinrank );
|
||||||
|
sgScaleVec4( l3, clfadeinrank );
|
||||||
|
}
|
||||||
// compute the rotations so that the quad is facing the camera
|
// compute the rotations so that the quad is facing the camera
|
||||||
sgVec3 pos;
|
sgVec3 pos;
|
||||||
sgSetVec3( pos, translate[SG_X], translate[SG_Z], translate[SG_Y] );
|
sgSetVec3( pos, translate[SG_X], translate[SG_Z], translate[SG_Y] );
|
||||||
sgCopyVec3( translate, pos );
|
sgCopyVec3( translate, pos );
|
||||||
sgNormaliseVec3( translate );
|
sgNormaliseVec3( translate );
|
||||||
|
#if 0
|
||||||
|
// change view angle when near a sprite
|
||||||
|
sgVec3 trans={translate[0], translate[2], translate[1]};
|
||||||
|
float angle = sgScalarProductVec3( SGCloudField::view_vec, trans );
|
||||||
|
if( fabs(angle) < 0.85f ) {
|
||||||
|
// view not ok from under
|
||||||
|
sgSetVec3( translate, -SGCloudField::view_vec[0],-SGCloudField::view_vec[2],-SGCloudField::view_vec[1] );
|
||||||
|
// sgSetVec3( l0,1,0,0 );
|
||||||
|
// sgSetVec3( l1,1,0,0 );
|
||||||
|
// sgSetVec3( l2,1,0,0 );
|
||||||
|
// sgSetVec3( l3,1,0,0 );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
sgVec3 x, y, up = {0.0f, 0.0f, 1.0f};
|
sgVec3 x, y, up = {0.0f, 0.0f, 1.0f};
|
||||||
sgVectorProductVec3(x, translate, up);
|
sgVectorProductVec3(x, translate, up);
|
||||||
sgNormaliseVec3(x);
|
|
||||||
sgScaleVec3(x, r);
|
|
||||||
sgVectorProductVec3(y, x, translate);
|
sgVectorProductVec3(y, x, translate);
|
||||||
sgNormaliseVec3(y);
|
sgScaleVec3(x, r);
|
||||||
sgScaleVec3(y, r);
|
sgScaleVec3(y, r);
|
||||||
|
|
||||||
sgVec3 left, right;
|
sgVec3 left, right;
|
||||||
@ -558,33 +644,61 @@ void SGNewCloud::CalcAngles(sgVec3 refpos, sgVec3 FakeEyePos, float *angleY, flo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// draw a cloud but this time we use the impostor texture
|
// draw a cloud but this time we use the impostor texture
|
||||||
void SGNewCloud::RenderBB(sgVec3 deltaPos, float angleY, float angleX, float dist_center) {
|
void SGNewCloud::RenderBB(sgVec3 deltaPos, bool first_time, float dist_center) {
|
||||||
// TODO:glrotate is not needed
|
|
||||||
glPushMatrix();
|
sgVec3 translate;
|
||||||
glTranslatef(center[SG_X] - deltaPos[SG_X], center[SG_Z] - deltaPos[SG_Z], center[SG_Y] - deltaPos[SG_Y]);
|
sgSubVec3( translate, center, deltaPos);
|
||||||
glRotatef(angleY, 0.0f, 0.0f, 1.0f);
|
|
||||||
glRotatef(angleX, 1.0f, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
// blend clouds with sky based on distance to limit the contrast of distant cloud
|
// blend clouds with sky based on distance to limit the contrast of distant cloud
|
||||||
float CloudVisFade = (1.5 * SGCloudField::get_CloudVis());
|
float CloudVisFade = (1.0f * SGCloudField::get_CloudVis());
|
||||||
|
|
||||||
float t = 1.0f - dist_center / CloudVisFade;
|
float t = 1.0f - (dist_center - 1.0*radius) / CloudVisFade;
|
||||||
// err the alpha value is not good for impostor, debug that
|
|
||||||
t *= 1.65;
|
|
||||||
if ( t < 0.0f )
|
if ( t < 0.0f )
|
||||||
t = 0.0f;
|
return;
|
||||||
|
if( t > 1.0f )
|
||||||
|
t = 1.0f;
|
||||||
|
if( t > 0.50f )
|
||||||
|
t *= 1.1f;
|
||||||
glColor4f(t, t, t, t);
|
glColor4f(t, t, t, t);
|
||||||
float r = radius;
|
float r = radius;
|
||||||
|
// compute the rotations so that the quad is facing the camera
|
||||||
|
sgVec3 pos;
|
||||||
|
sgSetVec3( pos, translate[SG_X], translate[SG_Z], translate[SG_Y] );
|
||||||
|
sgCopyVec3( translate, pos );
|
||||||
|
sgNormaliseVec3( translate );
|
||||||
|
sgVec3 x, y, up = {0.0f, 0.0f, 1.0f};
|
||||||
|
sgVectorProductVec3(x, translate, up);
|
||||||
|
sgVectorProductVec3(y, x, translate);
|
||||||
|
if(first_time) {
|
||||||
|
sgCopyVec3( rotX, x );
|
||||||
|
sgCopyVec3( rotY, y );
|
||||||
|
} else if(fabs(sgScalarProductVec3(rotX, x)) < 0.93f || fabs(sgScalarProductVec3(rotY, y)) < 0.93f ) {
|
||||||
|
// ask for a redraw of this impostor if the view angle changed too much
|
||||||
|
sgCopyVec3( rotX, x );
|
||||||
|
sgCopyVec3( rotY, y );
|
||||||
|
cldCache->invalidate(cloudId, bbId);
|
||||||
|
}
|
||||||
|
sgScaleVec3(x, r);
|
||||||
|
sgScaleVec3(y, r);
|
||||||
|
|
||||||
|
sgVec3 left, right;
|
||||||
|
sgCopyVec3( left, pos );
|
||||||
|
sgSubVec3 (left, y);
|
||||||
|
sgAddVec3 (right, left, x);
|
||||||
|
sgSubVec3 (left, x);
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glTexCoord2f(0.0f, 1.0f);
|
|
||||||
glVertex2f(-r, r);
|
|
||||||
glTexCoord2f(1.0f, 1.0f);
|
|
||||||
glVertex2f(r, r);
|
|
||||||
glTexCoord2f(1.0f, 0.0f);
|
|
||||||
glVertex2f(r, -r);
|
|
||||||
glTexCoord2f(0.0f, 0.0f);
|
glTexCoord2f(0.0f, 0.0f);
|
||||||
glVertex2f(-r, -r);
|
glVertex3fv(left);
|
||||||
|
glTexCoord2f(1.0f, 0.0f);
|
||||||
|
glVertex3fv(right);
|
||||||
|
sgScaleVec3( y, 2.0 );
|
||||||
|
sgAddVec3( left, y);
|
||||||
|
sgAddVec3( right, y);
|
||||||
|
glTexCoord2f(1.0f, 1.0f);
|
||||||
|
glVertex3fv(right);
|
||||||
|
glTexCoord2f(0.0f, 1.0f);
|
||||||
|
glVertex3fv(left);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
#if 0 // debug only
|
#if 0 // debug only
|
||||||
@ -607,8 +721,6 @@ void SGNewCloud::RenderBB(sgVec3 deltaPos, float angleY, float angleX, float dis
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine if it is a good idea to use an impostor to render the cloud
|
// determine if it is a good idea to use an impostor to render the cloud
|
||||||
@ -631,19 +743,26 @@ bool SGNewCloud::isBillboardable(float dist) {
|
|||||||
void SGNewCloud::Render(sgVec3 FakeEyePos) {
|
void SGNewCloud::Render(sgVec3 FakeEyePos) {
|
||||||
sgVec3 dist;
|
sgVec3 dist;
|
||||||
|
|
||||||
|
|
||||||
sgVec3 deltaPos;
|
sgVec3 deltaPos;
|
||||||
sgCopyVec3( deltaPos, FakeEyePos);
|
sgCopyVec3( deltaPos, FakeEyePos);
|
||||||
sgSubVec3( dist, center, FakeEyePos);
|
sgSubVec3( dist, center, FakeEyePos);
|
||||||
float dist_center = sgLengthVec3(dist);
|
float dist_center = sgLengthVec3(dist);
|
||||||
|
|
||||||
|
if( fadeActive ) {
|
||||||
|
fadetimer += SGCloudField::timer_dt;
|
||||||
|
if( fadetimer > duration + pauseLength ) {
|
||||||
|
// fade out after fade in, and vice versa
|
||||||
|
direction = ! direction;
|
||||||
|
fadetimer = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( !isBillboardable(dist_center) ) {
|
if( !isBillboardable(dist_center) ) {
|
||||||
// not a good candidate for impostors, draw a real cloud
|
// not a good candidate for impostors, draw a real cloud
|
||||||
Render3Dcloud(false, FakeEyePos, deltaPos, dist_center);
|
Render3Dcloud(false, FakeEyePos, deltaPos, dist_center);
|
||||||
} else {
|
} else {
|
||||||
GLuint texID = 0;
|
GLuint texID = 0;
|
||||||
|
bool first_time = false;
|
||||||
// lets use our impostor
|
// lets use our impostor
|
||||||
if( bbId >= 0)
|
if( bbId >= 0)
|
||||||
texID = cldCache->QueryTexID(cloudId, bbId);
|
texID = cldCache->QueryTexID(cloudId, bbId);
|
||||||
@ -653,13 +772,19 @@ void SGNewCloud::Render(sgVec3 FakeEyePos) {
|
|||||||
// allocate a new Impostor
|
// allocate a new Impostor
|
||||||
bbId = cldCache->alloc(cloudId);
|
bbId = cldCache->alloc(cloudId);
|
||||||
texID = cldCache->QueryTexID(cloudId, bbId);
|
texID = cldCache->QueryTexID(cloudId, bbId);
|
||||||
|
first_time = true;
|
||||||
}
|
}
|
||||||
if( texID == 0 ) {
|
if( texID == 0 ) {
|
||||||
// no more free texture in the pool
|
// no more free texture in the pool
|
||||||
Render3Dcloud(false, FakeEyePos, deltaPos, dist_center);
|
Render3Dcloud(false, FakeEyePos, deltaPos, dist_center);
|
||||||
} else {
|
} else {
|
||||||
float angleX, angleY;
|
float angleX=0.0f, angleY=0.0f;
|
||||||
CalcAngles(center, FakeEyePos, &angleY, &angleX);
|
|
||||||
|
// force a redraw of the impostor if the cloud shape has changed enought
|
||||||
|
float step = ( list_spriteDef.size() * (direction ? fadetimer : duration-fadetimer)) / duration;
|
||||||
|
if( fabs(step - last_step) > 0.5f )
|
||||||
|
cldCache->invalidate(cloudId, bbId);
|
||||||
|
|
||||||
if( ! cldCache->isBbValid( cloudId, bbId, angleY, angleX)) {
|
if( ! cldCache->isBbValid( cloudId, bbId, angleY, angleX)) {
|
||||||
// we must build or rebuild this billboard
|
// we must build or rebuild this billboard
|
||||||
// start render to texture
|
// start render to texture
|
||||||
@ -679,7 +804,7 @@ void SGNewCloud::Render(sgVec3 FakeEyePos) {
|
|||||||
}
|
}
|
||||||
// draw the newly built BB or an old one
|
// draw the newly built BB or an old one
|
||||||
glBindTexture(GL_TEXTURE_2D, texID);
|
glBindTexture(GL_TEXTURE_2D, texID);
|
||||||
RenderBB(deltaPos, angleY, angleX, dist_center);
|
RenderBB(deltaPos, first_time, dist_center);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,10 +33,27 @@
|
|||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
SG_USING_STD(vector);
|
SG_USING_STD(vector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3D cloud class.
|
||||||
|
*/
|
||||||
class SGNewCloud {
|
class SGNewCloud {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SGNewCloud();
|
enum CLFamilly_type {
|
||||||
|
CLFamilly_cu = 0,
|
||||||
|
CLFamilly_cb,
|
||||||
|
CLFamilly_st,
|
||||||
|
CLFamilly_ns,
|
||||||
|
CLFamilly_sc,
|
||||||
|
CLFamilly_as,
|
||||||
|
CLFamilly_ac,
|
||||||
|
CLFamilly_ci,
|
||||||
|
CLFamilly_cc,
|
||||||
|
CLFamilly_cs,
|
||||||
|
CLFamilly_nn
|
||||||
|
};
|
||||||
|
SGNewCloud(CLFamilly_type classification=CLFamilly_nn);
|
||||||
|
SGNewCloud(string classification);
|
||||||
~SGNewCloud();
|
~SGNewCloud();
|
||||||
|
|
||||||
enum CLbox_type {
|
enum CLbox_type {
|
||||||
@ -51,6 +68,7 @@ public:
|
|||||||
CLTexture_stratus = 2,
|
CLTexture_stratus = 2,
|
||||||
CLTexture_max
|
CLTexture_max
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
class spriteDef {
|
class spriteDef {
|
||||||
@ -59,11 +77,12 @@ private:
|
|||||||
float r;
|
float r;
|
||||||
CLbox_type sprite_type;
|
CLbox_type sprite_type;
|
||||||
sgVec4 l0, l1, l2, l3;
|
sgVec4 l0, l1, l2, l3;
|
||||||
|
sgVec3 normal, n0, n1, n2, n3;
|
||||||
int rank;
|
int rank;
|
||||||
int box;
|
int box;
|
||||||
float dist; // distance used during sort
|
float dist; // distance used during sort
|
||||||
bool operator<(const spriteDef &b) const {
|
bool operator<(const spriteDef &b) const {
|
||||||
return this->dist < b.dist;
|
return (this->dist < b.dist);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,6 +97,8 @@ private:
|
|||||||
typedef vector<spriteDef> list_of_spriteDef;
|
typedef vector<spriteDef> list_of_spriteDef;
|
||||||
typedef vector<spriteContainer> list_of_spriteContainer;
|
typedef vector<spriteContainer> list_of_spriteContainer;
|
||||||
|
|
||||||
|
void init(void);
|
||||||
|
|
||||||
void computeSimpleLight(sgVec3 eyePos);
|
void computeSimpleLight(sgVec3 eyePos);
|
||||||
void addSprite(float x, float y, float z, float r, CLbox_type type, int box);
|
void addSprite(float x, float y, float z, float r, CLbox_type type, int box);
|
||||||
|
|
||||||
@ -91,23 +112,26 @@ private:
|
|||||||
void CalcAngles(sgVec3 refpos, sgVec3 eyePos, float *angleY, float *angleX);
|
void CalcAngles(sgVec3 refpos, sgVec3 eyePos, float *angleY, float *angleX);
|
||||||
|
|
||||||
// draw a cloud but this time we use the impostor texture
|
// draw a cloud but this time we use the impostor texture
|
||||||
void RenderBB(sgVec3 deltaPos, float angleY, float angleX, float dist_center);
|
void RenderBB(sgVec3 deltaPos, bool first_time, float dist_center);
|
||||||
|
|
||||||
// determine if it is a good idea to use an impostor to render the cloud
|
// determine if it is a good idea to use an impostor to render the cloud
|
||||||
bool isBillboardable(float dist);
|
bool isBillboardable(float dist);
|
||||||
|
|
||||||
int cloudId, bbId;
|
int cloudId, bbId;
|
||||||
|
sgVec3 rotX, rotY;
|
||||||
|
|
||||||
// int rank;
|
// int rank;
|
||||||
sgVec3 cloudpos, center;
|
sgVec3 cloudpos, center;
|
||||||
|
float delta_base;
|
||||||
list_of_spriteDef list_spriteDef;
|
list_of_spriteDef list_spriteDef;
|
||||||
list_of_spriteContainer list_spriteContainer;
|
list_of_spriteContainer list_spriteContainer;
|
||||||
float minx, maxx, miny, maxy, minz, maxz;
|
|
||||||
float radius;
|
float radius;
|
||||||
|
CLFamilly_type familly;
|
||||||
|
|
||||||
// fading data
|
// fading data
|
||||||
bool direction, fadeActive;
|
bool direction, fadeActive;
|
||||||
float duration, pauseLength;
|
float duration, pauseLength, fadetimer;
|
||||||
// need timer here
|
float last_step;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// add a new box to the cloud
|
// add a new box to the cloud
|
||||||
@ -133,6 +157,9 @@ public:
|
|||||||
void setFade(float howMuch);
|
void setFade(float howMuch);
|
||||||
|
|
||||||
inline float getRadius() { return radius; }
|
inline float getRadius() { return radius; }
|
||||||
|
inline sgVec3 *getCenter() { return ¢er; }
|
||||||
|
|
||||||
|
inline CLFamilly_type getFamilly(void) { return familly; }
|
||||||
|
|
||||||
// load all textures used to draw cloud sprites
|
// load all textures used to draw cloud sprites
|
||||||
static void loadTextures( const string &tex_path );
|
static void loadTextures( const string &tex_path );
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <simgear/math/sg_random.h>
|
#include <simgear/math/sg_random.h>
|
||||||
|
|
||||||
#include "sky.hxx"
|
#include "sky.hxx"
|
||||||
|
#include "cloudfield.hxx"
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SGSky::SGSky( void ) {
|
SGSky::SGSky( void ) {
|
||||||
@ -187,6 +187,8 @@ void SGSky::preDraw( float alt, float fog_exp2_density ) {
|
|||||||
// in cloud layer
|
// in cloud layer
|
||||||
|
|
||||||
// bail now and don't draw any clouds
|
// bail now and don't draw any clouds
|
||||||
|
if( cloud_layers[i]->get_layer3D()->is3D() && SGCloudField::enable3D )
|
||||||
|
continue;
|
||||||
in_cloud = i;
|
in_cloud = i;
|
||||||
} else {
|
} else {
|
||||||
// above cloud layer
|
// above cloud layer
|
||||||
@ -286,7 +288,8 @@ void SGSky::modify_vis( float alt, float time_factor ) {
|
|||||||
ratio = 1.0;
|
ratio = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( cloud_layers[i]->getCoverage() == SGCloudLayer::SG_CLOUD_CLEAR ) {
|
if ( cloud_layers[i]->getCoverage() == SGCloudLayer::SG_CLOUD_CLEAR ||
|
||||||
|
cloud_layers[i]->get_layer3D()->is3D() && SGCloudField::enable3D) {
|
||||||
// do nothing, clear layers aren't drawn, don't affect
|
// do nothing, clear layers aren't drawn, don't affect
|
||||||
// visibility andn dont' need to be faded in or out.
|
// visibility andn dont' need to be faded in or out.
|
||||||
} else if ( (cloud_layers[i]->getCoverage() ==
|
} else if ( (cloud_layers[i]->getCoverage() ==
|
||||||
|
@ -12,7 +12,7 @@ IMAGE_SERVER_INCL =
|
|||||||
IMAGE_SERVER_SRCS =
|
IMAGE_SERVER_SRCS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
noinst_HEADERS = colours.h RenderTexture.h
|
noinst_HEADERS = colours.h GLBitmaps.h
|
||||||
|
|
||||||
include_HEADERS = \
|
include_HEADERS = \
|
||||||
colors.hxx \
|
colors.hxx \
|
||||||
@ -20,11 +20,12 @@ include_HEADERS = \
|
|||||||
$(IMAGE_SERVER_INCL) \
|
$(IMAGE_SERVER_INCL) \
|
||||||
screen-dump.hxx \
|
screen-dump.hxx \
|
||||||
extensions.hxx \
|
extensions.hxx \
|
||||||
|
RenderTexture.h \
|
||||||
tr.h
|
tr.h
|
||||||
|
|
||||||
libsgscreen_a_SOURCES = \
|
libsgscreen_a_SOURCES = \
|
||||||
texture.cxx \
|
texture.cxx \
|
||||||
GLBitmaps.cxx GLBitmaps.h \
|
GLBitmaps.cxx \
|
||||||
$(IMAGE_SERVER_SRCS) \
|
$(IMAGE_SERVER_SRCS) \
|
||||||
screen-dump.cxx \
|
screen-dump.cxx \
|
||||||
tr.cxx \
|
tr.cxx \
|
||||||
|
Loading…
Reference in New Issue
Block a user