Harald Johnson:
- new and updated sources for the new volumetric clouds - 2 new textures for the clouds - an update to the render dialog to enable/disable and change a few parameters for the new clouds
This commit is contained in:
@@ -2,8 +2,8 @@ includedir = @includedir@/environment
|
||||
|
||||
lib_LIBRARIES = libsgenvironment.a
|
||||
|
||||
include_HEADERS = metar.hxx
|
||||
include_HEADERS = metar.hxx visual_enviro.hxx
|
||||
|
||||
libsgenvironment_a_SOURCES = metar.cxx
|
||||
libsgenvironment_a_SOURCES = metar.cxx visual_enviro.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
81
simgear/environment/visual_enviro.cxx
Normal file
81
simgear/environment/visual_enviro.cxx
Normal file
@@ -0,0 +1,81 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#include <simgear/scene/sky/cloudfield.hxx>
|
||||
#include <simgear/scene/sky/newcloud.hxx>
|
||||
#include "visual_enviro.hxx"
|
||||
|
||||
SGEnviro sgEnviro;
|
||||
|
||||
SGEnviro::SGEnviro(void) {
|
||||
}
|
||||
|
||||
SGEnviro::~SGEnviro(void) {
|
||||
}
|
||||
|
||||
int SGEnviro::get_clouds_CacheSize(void) const {
|
||||
return SGCloudField::get_CacheSize();
|
||||
}
|
||||
float SGEnviro::get_clouds_visibility(void) const {
|
||||
return SGCloudField::get_CloudVis();
|
||||
}
|
||||
float SGEnviro::get_clouds_density(void) const {
|
||||
return SGCloudField::get_density();
|
||||
}
|
||||
bool SGEnviro::get_clouds_enable_state(void) const {
|
||||
return SGCloudField::get_enable3dClouds();
|
||||
}
|
||||
|
||||
void SGEnviro::set_clouds_CacheSize(int sizeKb) {
|
||||
SGCloudField::set_CacheSize(sizeKb);
|
||||
}
|
||||
void SGEnviro::set_clouds_visibility(float distance) {
|
||||
SGCloudField::set_CloudVis(distance);
|
||||
}
|
||||
void SGEnviro::set_clouds_density(float density) {
|
||||
SGCloudField::set_density(density);
|
||||
}
|
||||
void SGEnviro::set_clouds_enable_state(bool enable) {
|
||||
SGCloudField::set_enable3dClouds(enable);
|
||||
}
|
||||
|
||||
// rain/snow
|
||||
float SGEnviro::get_precipitation_density(void) const {
|
||||
return 0.0;
|
||||
}
|
||||
bool SGEnviro::get_precipitation_enable_state(void) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SGEnviro::set_precipitation_density(float density) {
|
||||
}
|
||||
void SGEnviro::set_precipitation_enable_state(bool enable) {
|
||||
}
|
||||
|
||||
// others
|
||||
bool SGEnviro::get_lightning_enable_state(void) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SGEnviro::set_lightning_enable_state(bool enable) {
|
||||
}
|
||||
|
||||
81
simgear/environment/visual_enviro.cxx~
Normal file
81
simgear/environment/visual_enviro.cxx~
Normal file
@@ -0,0 +1,81 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#include <simgear/scene/sky/cloudfield.hxx>
|
||||
#include <simgear/scene/sky/newcloud.hxx>
|
||||
#include "visual_enviro.hxx"
|
||||
|
||||
SGEnviro sgEnviro;
|
||||
|
||||
SGEnviro::SGEnviro(void) {
|
||||
}
|
||||
|
||||
SGEnviro::~SGEnviro(void) {
|
||||
}
|
||||
|
||||
int SGEnviro::get_clouds_CacheSize(void) const {
|
||||
return SGCloudField::get_CacheSize();
|
||||
}
|
||||
float SGEnviro::get_clouds_visibility(void) const {
|
||||
return SGCloudField::get_CloudVis();
|
||||
}
|
||||
float SGEnviro::get_clouds_density(void) const {
|
||||
return SGCloudField::get_density();
|
||||
}
|
||||
bool SGEnviro::get_clouds_enable_state(void) const {
|
||||
return SGCloudField::get_enable3dClouds();
|
||||
}
|
||||
|
||||
void SGEnviro::set_clouds_CacheSize(int sizeKb) {
|
||||
SGCloudField::set_CacheSize(sizeKb);
|
||||
}
|
||||
void SGEnviro::set_clouds_visibility(float distance) {
|
||||
SGCloudField::set_CloudVis(distance);
|
||||
}
|
||||
void SGEnviro::set_clouds_density(float density) {
|
||||
SGCloudField::set_density(density);
|
||||
}
|
||||
void SGEnviro::set_clouds_enable_state(bool enable) {
|
||||
SGCloudField::set_enable3dClouds(enable);
|
||||
}
|
||||
|
||||
// rain/snow
|
||||
float SGEnviro::get_precipitation_density(void) const {
|
||||
return 0.0;
|
||||
}
|
||||
bool SGEnviro::get_precipitation_enable_state(void) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SGEnviro::set_precipitation_density(float density) {
|
||||
}
|
||||
void SGEnviro::set_precipitation_enable_state(bool enable) {
|
||||
}
|
||||
|
||||
// others
|
||||
bool SGEnviro::get_lightning_enable_state(void) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SGEnviro::set_lightning_enable_state(bool enable) {
|
||||
}
|
||||
|
||||
58
simgear/environment/visual_enviro.hxx
Normal file
58
simgear/environment/visual_enviro.hxx
Normal file
@@ -0,0 +1,58 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
#ifndef _VISUAL_ENVIRO_HXX
|
||||
#define _VISUAL_ENVIRO_HXX
|
||||
|
||||
class SGEnviro {
|
||||
|
||||
public:
|
||||
SGEnviro();
|
||||
~SGEnviro();
|
||||
|
||||
// Clouds
|
||||
// return the size of the memory pool used by texture impostors
|
||||
int get_clouds_CacheSize(void) const;
|
||||
float get_clouds_visibility(void) const;
|
||||
float get_clouds_density(void) const;
|
||||
bool get_clouds_enable_state(void) const;
|
||||
|
||||
void set_clouds_CacheSize(int sizeKb);
|
||||
void set_clouds_visibility(float distance);
|
||||
void set_clouds_density(float density);
|
||||
void set_clouds_enable_state(bool enable);
|
||||
|
||||
// rain/snow
|
||||
float get_precipitation_density(void) const;
|
||||
bool get_precipitation_enable_state(void) const;
|
||||
|
||||
void set_precipitation_density(float density);
|
||||
void set_precipitation_enable_state(bool enable);
|
||||
|
||||
// others
|
||||
bool get_lightning_enable_state(void) const;
|
||||
void set_lightning_enable_state(bool enable);
|
||||
};
|
||||
|
||||
extern SGEnviro sgEnviro;
|
||||
|
||||
#endif // _VISUAL_ENVIRO_HXX
|
||||
|
||||
58
simgear/environment/visual_enviro.hxx~
Normal file
58
simgear/environment/visual_enviro.hxx~
Normal file
@@ -0,0 +1,58 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
#ifndef _VISUAL_ENVIRO_HXX
|
||||
#define _VISUAL_ENVIRO_HXX
|
||||
|
||||
class SGEnviro {
|
||||
|
||||
public:
|
||||
SGEnviro();
|
||||
~SGEnviro();
|
||||
|
||||
// Clouds
|
||||
// return the size of the memory pool used by texture impostors
|
||||
int get_clouds_CacheSize(void) const;
|
||||
float get_clouds_visibility(void) const;
|
||||
float get_clouds_density(void) const;
|
||||
bool get_clouds_enable_state(void) const;
|
||||
|
||||
void set_clouds_CacheSize(int sizeKb);
|
||||
void set_clouds_visibility(float distance);
|
||||
void set_clouds_density(float density);
|
||||
void set_clouds_enable_state(bool enable);
|
||||
|
||||
// rain/snow
|
||||
float get_precipitation_density(void) const;
|
||||
bool get_precipitation_enable_state(void) const;
|
||||
|
||||
void set_precipitation_density(float density);
|
||||
void set_precipitation_enable_state(bool enable);
|
||||
|
||||
// others
|
||||
bool get_lightning_enable_state(void) const;
|
||||
void set_lightning_enable_state(bool enable);
|
||||
};
|
||||
|
||||
extern SGEnviro sgEnviro;
|
||||
|
||||
#endif // _VISUAL_ENVIRO_HXX
|
||||
|
||||
@@ -11,7 +11,10 @@ include_HEADERS = \
|
||||
oursun.hxx \
|
||||
sky.hxx \
|
||||
sphere.hxx \
|
||||
stars.hxx
|
||||
stars.hxx \
|
||||
bbcache.hxx \
|
||||
cloudfield.hxx \
|
||||
newcloud.hxx
|
||||
|
||||
libsgsky_a_SOURCES = \
|
||||
cloud.cxx \
|
||||
@@ -20,6 +23,9 @@ libsgsky_a_SOURCES = \
|
||||
oursun.cxx \
|
||||
sky.cxx \
|
||||
sphere.cxx \
|
||||
stars.cxx
|
||||
stars.cxx \
|
||||
bbcache.cxx \
|
||||
cloudfield.cxx \
|
||||
newcloud.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
339
simgear/scene/sky/bbcache.cxx
Normal file
339
simgear/scene/sky/bbcache.cxx
Normal file
@@ -0,0 +1,339 @@
|
||||
// Billboard helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/screen/extensions.hxx>
|
||||
#include <simgear/screen/RenderTexture.h>
|
||||
#include SG_GLUT_H
|
||||
|
||||
#include "bbcache.hxx"
|
||||
|
||||
|
||||
/*
|
||||
memory usage :
|
||||
size 1 tex 8 tex 32 tex 64 tex
|
||||
64x64x4 16k 128k 512k 1Mo
|
||||
128x128x4 64k 512k 2Mo 4Mo
|
||||
256x256x4 256k 2Mo 8Mo 16Mo
|
||||
*/
|
||||
|
||||
void SGBbCache::freeTextureMemory(void) {
|
||||
|
||||
if( bbListCount ) {
|
||||
for(int i = 0 ; i < bbListCount ; i++) {
|
||||
if(bbList[i].texID)
|
||||
glDeleteTextures(1, & bbList[i].texID);
|
||||
}
|
||||
delete [] bbList;
|
||||
}
|
||||
bbListCount = 0;
|
||||
cacheSizeKb = 0;
|
||||
textureWH = 0;
|
||||
}
|
||||
|
||||
bool SGBbCache::allocTextureMemory(int cacheCount, int textureDimension) {
|
||||
textureWH = textureDimension;
|
||||
bbListCount = cacheCount;
|
||||
bbList = new bbInfo[bbListCount];
|
||||
for(int i = 0 ; i < bbListCount ; i++) {
|
||||
bbList[i].cldID = 0;
|
||||
bbList[i].texID = 0;
|
||||
glGenTextures(1, &bbList[i].texID);
|
||||
glBindTexture(GL_TEXTURE_2D, bbList[i].texID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
|
||||
textureDimension, textureDimension, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
cacheSizeKb = (textureDimension * textureDimension * 4);
|
||||
cacheSizeKb *= cacheCount;
|
||||
cacheSizeKb /= 1024;
|
||||
if(rt) {
|
||||
rt->BeginCapture();
|
||||
glViewport(0, 0, textureDimension, textureDimension);
|
||||
rt->EndCapture();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SGBbCache::SGBbCache(void) :
|
||||
bbListCount(0),
|
||||
cacheSizeKb(0),
|
||||
textureWH(0),
|
||||
builtBBCount(0),
|
||||
rt(0),
|
||||
rtAvailable(false),
|
||||
frameNumber(0),
|
||||
maxImpostorRegenFrame(10)
|
||||
{
|
||||
}
|
||||
|
||||
SGBbCache::~SGBbCache(void) {
|
||||
if(rt)
|
||||
delete rt;
|
||||
freeTextureMemory();
|
||||
}
|
||||
|
||||
|
||||
void SGBbCache::init(int cacheCount) {
|
||||
|
||||
rt = new RenderTexture();
|
||||
// don't use default rtt on nvidia/win because of poor performance of glCopyTexSubImage2D
|
||||
// wihtout default pattrib params - see opengl forum
|
||||
rt->Reset("rgba tex2D ctt");
|
||||
// rt->Reset("rgba tex2D");
|
||||
if( rt->Initialize(256, 256, true) ) {
|
||||
rtAvailable = true;
|
||||
if (rt->BeginCapture())
|
||||
{
|
||||
glViewport(0, 0, 256, 256);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(60.0, 1, 1, 5.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_FOG);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.0f);
|
||||
glEnable(GL_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
rt->EndCapture();
|
||||
}
|
||||
}
|
||||
if( cacheCount )
|
||||
allocTextureMemory( cacheCount, 256 );
|
||||
|
||||
}
|
||||
|
||||
// TODO:not callable atm, texture size not handled correctly
|
||||
bool SGBbCache::setCacheSize(int count, int textureDimension) {
|
||||
if( count < 0 || count > 500)
|
||||
return false;
|
||||
freeTextureMemory();
|
||||
if( count == 0)
|
||||
return true;
|
||||
|
||||
// only allow some reasonable dimensions
|
||||
switch(textureDimension) {
|
||||
case 0:
|
||||
// default size
|
||||
textureDimension = 256;
|
||||
break;
|
||||
case 64:
|
||||
case 128:
|
||||
case 256:
|
||||
break;
|
||||
case 512:
|
||||
// rt is 256 so higher texture size has no meaning
|
||||
textureDimension = 256;
|
||||
break;
|
||||
default:
|
||||
textureDimension = 128;
|
||||
break;
|
||||
}
|
||||
return allocTextureMemory( count, textureDimension);
|
||||
}
|
||||
|
||||
// TODO:not callable atm, texture size not handled correctly
|
||||
bool SGBbCache::setCacheSize(int sizeKb) {
|
||||
if( sizeKb < 0 || sizeKb > 256*1024)
|
||||
return false;
|
||||
freeTextureMemory();
|
||||
if( sizeKb == 0)
|
||||
return true;
|
||||
int count = 1;
|
||||
int textureDimension = 256;
|
||||
if( cacheSizeKb >= 8*1024 ) {
|
||||
// more than 32 256x256 textures
|
||||
textureDimension = 256;
|
||||
} else if( cacheSizeKb >= 2*1024 ) {
|
||||
// more than 32 128x128 textures
|
||||
textureDimension = 128;
|
||||
} else {
|
||||
// don't go under 64x64 textures
|
||||
textureDimension = 64;
|
||||
}
|
||||
count = (sizeKb * 1024) / (textureDimension * textureDimension * 4);
|
||||
if(count == 0)
|
||||
count = 1;
|
||||
return allocTextureMemory( count, textureDimension);
|
||||
}
|
||||
|
||||
int SGBbCache::queryCacheSize(void) {
|
||||
return cacheSizeKb;
|
||||
}
|
||||
|
||||
void SGBbCache::free(int bbId, int cldId) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return;
|
||||
if( bbList[bbId].cldID != cldId )
|
||||
return;
|
||||
bbList[bbId].cldID = 0;
|
||||
}
|
||||
|
||||
int SGBbCache::alloc(int cldId) {
|
||||
// pretend we have no more texture if render to texture is not available
|
||||
if( ! rtAvailable )
|
||||
return -1;
|
||||
for(int i = 0 ; i < bbListCount ; i++) {
|
||||
if( (bbList[i].cldID == 0) && (bbList[i].texID != 0) ) {
|
||||
bbList[i].cldID = cldId;
|
||||
bbList[i].angleX = -999;
|
||||
bbList[i].angleY = -999;
|
||||
bbList[i].frameUsed = 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
GLuint SGBbCache::QueryTexID(int cldId, int bbId) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return 0;
|
||||
if( bbList[bbId].cldID != cldId )
|
||||
return 0;
|
||||
return bbList[bbId].texID;
|
||||
}
|
||||
|
||||
int SGBbCache::queryImpostorAge(int bbId) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return 0;
|
||||
return frameNumber - bbList[bbId].frame;
|
||||
}
|
||||
|
||||
void SGBbCache::beginCapture(void) {
|
||||
|
||||
rt->BeginCapture();
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SGBbCache::setRadius(float radius, float dist_center) {
|
||||
float border;
|
||||
//set viewport to texture resolution
|
||||
//glViewport(0, 0, 256, 256);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
float near_ = dist_center - radius;
|
||||
float far_ = dist_center + radius;
|
||||
if( near_ <= 0 ) {
|
||||
// we are in trouble
|
||||
glFrustum(-1, 1, -1, 1, 1, 1 + radius * 2);
|
||||
} else {
|
||||
border = (near_ * radius) / sqrt(dist_center * dist_center - radius * radius);
|
||||
glFrustum(-border, border, -border, border, near_, far_);
|
||||
}
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
void SGBbCache::setTextureData(int bbId) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, bbList[bbId].texID);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, textureWH, textureWH);
|
||||
|
||||
// bbList[bbId].angleX = angleX;
|
||||
// bbList[bbId].angleY = angleY;
|
||||
bbList[bbId].frame = frameNumber;
|
||||
bbList[bbId].frameUsed = frameNumber;
|
||||
builtBBCount ++;
|
||||
builtBBframe ++;
|
||||
}
|
||||
|
||||
void SGBbCache::endCapture(void) {
|
||||
|
||||
rt->EndCapture();
|
||||
// glBindTexture(GL_TEXTURE_2D, rt->GetTextureID() );
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool SGBbCache::isBbValid( int cldId, int bbId, float angleY, float angleX) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return false;
|
||||
if( bbList[bbId].cldID != cldId )
|
||||
return false;
|
||||
|
||||
// it was just allocated
|
||||
if( bbList[bbId].frameUsed == 0)
|
||||
return false;
|
||||
|
||||
// we reuse old impostor to speed up things
|
||||
if( builtBBframe >= maxImpostorRegenFrame )
|
||||
return true;
|
||||
|
||||
if( fabs(angleY - bbList[bbId].angleY) >= 5.0 )
|
||||
return false;
|
||||
|
||||
if( fabs(angleX - bbList[bbId].angleX) >= 5.0 )
|
||||
return false;
|
||||
|
||||
bbList[bbId].frameUsed = frameNumber;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO:this is not the right way to handle that
|
||||
void SGBbCache::setReference( int cldId, int bbId, float angleY, float angleX) {
|
||||
if( bbId < 0 || bbId >= bbListCount )
|
||||
return;
|
||||
if( bbList[bbId].cldID != cldId )
|
||||
return;
|
||||
bbList[bbId].angleX = angleX;
|
||||
bbList[bbId].angleY = angleY;
|
||||
}
|
||||
|
||||
void SGBbCache::startNewFrame(void) {
|
||||
builtBBframe = 0;
|
||||
// TOTO:find reasonable value
|
||||
int minFrameNumber = frameNumber - 500;
|
||||
frameNumber++;
|
||||
// cleanup of unused enties
|
||||
for( int bbId = 0 ; bbId < bbListCount ; bbId++)
|
||||
if( (bbList[bbId].cldID != 0) && (bbList[bbId].frameUsed < minFrameNumber) ) {
|
||||
// entry is now free
|
||||
bbList[bbId].cldID = 0;
|
||||
}
|
||||
}
|
||||
117
simgear/scene/sky/bbcache.hxx
Normal file
117
simgear/scene/sky/bbcache.hxx
Normal file
@@ -0,0 +1,117 @@
|
||||
// Billboard helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _BBCACHE_HXX
|
||||
#define _BBCACHE_HXX
|
||||
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/screen/extensions.hxx>
|
||||
#include <simgear/screen/RenderTexture.h>
|
||||
|
||||
class SGBbCache {
|
||||
private:
|
||||
|
||||
typedef struct {
|
||||
GLuint texID;
|
||||
int cldID;
|
||||
float angleX, angleY;
|
||||
// creation frame number for debug only
|
||||
int frame;
|
||||
// last time this entry was used
|
||||
int frameUsed;
|
||||
} bbInfo;
|
||||
|
||||
void freeTextureMemory(void);
|
||||
bool allocTextureMemory(int count, int textureDimension);
|
||||
|
||||
// a list of impostors
|
||||
bbInfo *bbList;
|
||||
int bbListCount;
|
||||
int textureWH;
|
||||
int cacheSizeKb;
|
||||
|
||||
// for debug only, stats
|
||||
int builtBBCount;
|
||||
// count of generated BB during the current frame
|
||||
int builtBBframe;
|
||||
|
||||
long frameNumber;
|
||||
RenderTexture *rt;
|
||||
bool rtAvailable;
|
||||
|
||||
public:
|
||||
SGBbCache(void);
|
||||
~SGBbCache(void);
|
||||
|
||||
// call this first to initialize everything, cacheCount is the number of texture to allocate
|
||||
void init(int cacheCount);
|
||||
|
||||
// free one cache slot, usualy when the cached object is destroyed
|
||||
void free(int bbId, int cldId);
|
||||
|
||||
// allocate a new texture, return an index in the cache
|
||||
int alloc(int cldId);
|
||||
|
||||
// give the texture name to use
|
||||
GLuint QueryTexID(int cldId, int bbId);
|
||||
|
||||
// save the rendered texture from the current context to a new texture
|
||||
void setTextureData(int bbId);
|
||||
|
||||
// start the rendering of a billboard in the RTT context
|
||||
void beginCapture(void);
|
||||
|
||||
// adjust the projection matrix of the RTT context to the size of the object
|
||||
void setRadius(float radius, float dist_center);
|
||||
|
||||
// forget the RTT and go back to the previous rendering context
|
||||
void endCapture(void);
|
||||
|
||||
// for debugging only, give the number of frames since the inpostor was built
|
||||
int queryImpostorAge(int bbId);
|
||||
|
||||
// can we still use this impostor ?
|
||||
bool isBbValid( int cloudId, int bbId, float angleY, float angleX);
|
||||
|
||||
// save view angles of this billboard
|
||||
void setReference( int cloudId, int bbId, float angleY, float angleX);
|
||||
|
||||
// prepare the cache for the rendering of a new frame
|
||||
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
|
||||
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
|
||||
bool setCacheSize(int count, int textureDimension);
|
||||
|
||||
// return the size of the memory pool used by texture impostors
|
||||
int queryCacheSize(void);
|
||||
|
||||
int maxImpostorRegenFrame;
|
||||
};
|
||||
|
||||
#endif // _BBCACHE_HXX
|
||||
@@ -39,6 +39,8 @@ inline int (isnan)(double r) { return isnan(r); }
|
||||
#include <simgear/screen/extensions.hxx>
|
||||
#include <simgear/screen/texture.hxx>
|
||||
|
||||
#include "newcloud.hxx"
|
||||
#include "cloudfield.hxx"
|
||||
#include "cloud.hxx"
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
@@ -221,12 +223,14 @@ SGCloudLayer::SGCloudLayer( const string &tex_path ) :
|
||||
layer[0] = layer[1] = layer[2] = layer[3] = NULL;
|
||||
|
||||
layer_root->addKid(layer_transform);
|
||||
layer3D = new SGCloudField;
|
||||
rebuild();
|
||||
}
|
||||
|
||||
// Destructor
|
||||
SGCloudLayer::~SGCloudLayer()
|
||||
{
|
||||
delete layer3D;
|
||||
delete vertices;
|
||||
delete indices;
|
||||
delete layer_root; // deletes layer_transform and layer as well
|
||||
@@ -460,6 +464,8 @@ SGCloudLayer::rebuild()
|
||||
|
||||
layer_states[SG_CLOUD_CLEAR] = 0;
|
||||
}
|
||||
SGNewCloud::loadTextures(texture_path.str());
|
||||
layer3D->buildTestLayer();
|
||||
}
|
||||
|
||||
if ( bump_mapping ) {
|
||||
@@ -837,6 +843,7 @@ bool SGCloudLayer::reposition( sgVec3 p, sgVec3 up, double lon, double lat,
|
||||
last_lat = lat;
|
||||
}
|
||||
|
||||
layer3D->reposition( p, up, lon, lat, alt, dt);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -844,6 +851,9 @@ bool SGCloudLayer::reposition( sgVec3 p, sgVec3 up, double lon, double lat,
|
||||
void SGCloudLayer::draw( bool top ) {
|
||||
if ( layer_coverage != SG_CLOUD_CLEAR ) {
|
||||
|
||||
if ( SGCloudField::enable3D )
|
||||
layer3D->Render();
|
||||
else
|
||||
if ( bump_mapping && enable_bump_mapping ) {
|
||||
|
||||
sgMat4 modelview,
|
||||
|
||||
@@ -39,6 +39,7 @@ SG_USING_STD(string);
|
||||
// SG_USING_STD(cout);
|
||||
// SG_USING_STD(endl);
|
||||
|
||||
class SGCloudField;
|
||||
|
||||
/**
|
||||
* A class layer to model a single cloud layer
|
||||
@@ -225,6 +226,8 @@ private:
|
||||
// position, not view position
|
||||
// double xoff, yoff;
|
||||
double last_lon, last_lat, last_course;
|
||||
|
||||
SGCloudField *layer3D;
|
||||
};
|
||||
|
||||
|
||||
|
||||
327
simgear/scene/sky/cloudfield.cxx
Normal file
327
simgear/scene/sky/cloudfield.cxx
Normal file
@@ -0,0 +1,327 @@
|
||||
// a layer of 3d clouds
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
|
||||
#include STL_ALGORITHM
|
||||
#include SG_GLUT_H
|
||||
#include <vector>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
|
||||
#include "newcloud.hxx"
|
||||
#include "cloudfield.hxx"
|
||||
|
||||
static list_of_culledCloud inViewClouds;
|
||||
|
||||
// visibility distance for clouds in meters
|
||||
float SGCloudField::CloudVis = 25000.0f;
|
||||
bool SGCloudField::enable3D = true;
|
||||
// fieldSize must be > CloudVis or we can destroy the impostor cache
|
||||
// a cloud must only be seen once or the impostor will be generated for each of his positions
|
||||
double SGCloudField::fieldSize = 30000.0;
|
||||
float SGCloudField::density = 100.0;
|
||||
static int last_cache_size = 4*1024;
|
||||
|
||||
int SGCloudField::get_CacheSize(void) {
|
||||
return SGNewCloud::cldCache->queryCacheSize();
|
||||
}
|
||||
|
||||
void SGCloudField::set_CacheSize(int sizeKb) {
|
||||
// apply in rendering option dialog
|
||||
if(last_cache_size == sizeKb)
|
||||
return;
|
||||
if(sizeKb == 0)
|
||||
return;
|
||||
if(sizeKb)
|
||||
last_cache_size = sizeKb;
|
||||
SGNewCloud::cldCache->setCacheSize(sizeKb);
|
||||
}
|
||||
void SGCloudField::set_CloudVis(float distance) {
|
||||
SGCloudField::CloudVis = distance;
|
||||
}
|
||||
void SGCloudField::set_density(float density) {
|
||||
SGCloudField::density = density;
|
||||
}
|
||||
void SGCloudField::set_enable3dClouds(bool enable) {
|
||||
if(enable3D == enable)
|
||||
return;
|
||||
enable3D = enable;
|
||||
if(enable) {
|
||||
SGNewCloud::cldCache->setCacheSize(last_cache_size);
|
||||
} else {
|
||||
SGNewCloud::cldCache->setCacheSize(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
sgMat4 T1, LON, LAT;
|
||||
sgVec3 axis;
|
||||
|
||||
sgMakeTransMat4( T1, p );
|
||||
|
||||
sgSetVec3( axis, 0.0, 0.0, 1.0 );
|
||||
sgMakeRotMat4( LON, lon * SGD_RADIANS_TO_DEGREES, axis );
|
||||
|
||||
sgSetVec3( axis, 0.0, 1.0, 0.0 );
|
||||
sgMakeRotMat4( LAT, 90.0 - lat * SGD_RADIANS_TO_DEGREES, axis );
|
||||
|
||||
sgMat4 TRANSFORM;
|
||||
|
||||
sgCopyMat4( TRANSFORM, T1 );
|
||||
sgPreMultMat4( TRANSFORM, LON );
|
||||
sgPreMultMat4( TRANSFORM, LAT );
|
||||
|
||||
sgCoord layerpos;
|
||||
sgSetCoord( &layerpos, TRANSFORM );
|
||||
|
||||
sgMakeCoordMat4( transform, &layerpos );
|
||||
|
||||
// TODO:use a simple sphere earth
|
||||
double az1, az2, s;
|
||||
geo_inverse_wgs_84( 0.0, 0.0, 0.0, lat*SG_RADIANS_TO_DEGREES , lon*SG_RADIANS_TO_DEGREES, &az1, &az2, &s);
|
||||
az1 = az1 * SG_DEGREES_TO_RADIANS;
|
||||
// compute the view position on a 'flat' earth
|
||||
deltay = -cos(SG_PI/2+az1) * s;
|
||||
deltax = -sin(SG_PI/2+az1) * s;
|
||||
// deltax = cos(0.0) * s;
|
||||
// deltay = sin(0.0) * s;
|
||||
this->alt = alt;
|
||||
|
||||
// simulate clouds movement from wind
|
||||
double speed = 10.0f;
|
||||
double direction = 45.0;
|
||||
double sp_dist = speed*dt;
|
||||
if (sp_dist > 0) {
|
||||
double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
|
||||
double by = sin((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
|
||||
relative_position[SG_X] += bx;
|
||||
relative_position[SG_Y] += by;
|
||||
}
|
||||
|
||||
// correct the frustum with the right far plane
|
||||
ssgContext *context = ssgGetCurrentContext();
|
||||
frustum = *context->getFrustum();
|
||||
frustum.setNearFar(1.0, CloudVis);
|
||||
}
|
||||
|
||||
SGCloudField::SGCloudField() {
|
||||
sgSetVec3( relative_position, 0,0,0);
|
||||
theField.reserve(200);
|
||||
inViewClouds.reserve(200);
|
||||
}
|
||||
|
||||
SGCloudField::~SGCloudField() {
|
||||
list_of_Cloud::iterator iCloud;
|
||||
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
|
||||
delete iCloud->aCloud;
|
||||
}
|
||||
theField.clear();
|
||||
}
|
||||
|
||||
|
||||
// add one cloud, data is not copied, ownership given
|
||||
void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
|
||||
Cloud cl;
|
||||
sgCopyVec3( cl.pos, pos );
|
||||
cl.aCloud = cloud;
|
||||
cloud->SetPos( pos );
|
||||
theField.push_back( cl );
|
||||
}
|
||||
|
||||
|
||||
static float Rnd(float n) {
|
||||
return n * (-0.5f + rand() / (float) RAND_MAX);
|
||||
}
|
||||
|
||||
// for debug only
|
||||
// build a field of cloud of size 25x25 km, its a grid of 11x11 clouds
|
||||
void SGCloudField::buildTestLayer(void) {
|
||||
|
||||
const float s = 2200.0f;
|
||||
|
||||
for( int z = -5 ; z <= 5 ; z++) {
|
||||
for( int x = -5 ; x <= 5 ; x++ ) {
|
||||
SGNewCloud *cloud = new SGNewCloud;
|
||||
cloud->new_cu();
|
||||
sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
|
||||
addCloud(pos, cloud);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// cull all clouds of a tiled field
|
||||
void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) {
|
||||
list_of_Cloud::iterator iCloud;
|
||||
// const float distVisCompare = CloudVis * CloudVis;
|
||||
|
||||
// TODO:cull the field before culling the clouds in the field (should eliminate 3 fields)
|
||||
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
|
||||
sgVec3 dist;
|
||||
sgSphere sphere;
|
||||
sgSubVec3( dist, iCloud->pos, eyePos );
|
||||
sphere.setCenter(dist[0], dist[2], dist[1]);
|
||||
sphere.setRadius(iCloud->aCloud->getRadius());
|
||||
sphere.orthoXform(mat);
|
||||
if( frustum.contains( & sphere ) != SG_OUTSIDE ) {
|
||||
float squareDist = dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2];
|
||||
culledCloud tmp;
|
||||
tmp.aCloud = iCloud->aCloud;
|
||||
sgCopyVec3( tmp.eyePos, eyePos );
|
||||
// save distance for later sort, opposite distance because we want back to front
|
||||
tmp.dist = - squareDist;
|
||||
inViewClouds.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline void myswap(float &a, float &b) {
|
||||
float tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
// Render a cloud field
|
||||
// because no field can have an infinite size (and we don't want to reach his border)
|
||||
// we draw this field and adjacent fields.
|
||||
// adjacent fields are not real, its the same field displaced by some offset
|
||||
void SGCloudField::Render(void) {
|
||||
sgVec3 eyePos;
|
||||
double relx, rely;
|
||||
|
||||
if( ! enable3D )
|
||||
return;
|
||||
|
||||
// ask the impostor cache to do some cleanup
|
||||
// TODO:don't do that for every field
|
||||
SGNewCloud::cldCache->startNewFrame();
|
||||
|
||||
inViewClouds.clear();
|
||||
|
||||
// cloud fields are tiled on the flat earth
|
||||
// compute the position in the tile
|
||||
relx = -fmod( deltax + relative_position[SG_X], fieldSize );
|
||||
rely = -fmod( deltay + relative_position[SG_Y], fieldSize );
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
sgMat4 modelview, tmp, invtrans;
|
||||
|
||||
// try to find the sun position (buggy)
|
||||
sgTransposeNegateMat4( invtrans, transform );
|
||||
sgVec3 lightVec;
|
||||
ssgGetLight( 0 )->getPosition( lightVec );
|
||||
sgNegateVec3( lightVec );
|
||||
sgXformVec3( lightVec, invtrans );
|
||||
sgNormaliseVec3( lightVec );
|
||||
sgCopyVec3( SGNewCloud::modelSunDir, lightVec );
|
||||
|
||||
// try to find the lighting data (buggy)
|
||||
sgVec4 diffuse, ambient;
|
||||
ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse );
|
||||
ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient );
|
||||
sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 0.70f);
|
||||
sgScaleVec3 ( SGNewCloud::ambLight, ambient , 0.60f);
|
||||
|
||||
// voodoo things on the matrix stack
|
||||
ssgGetModelviewMatrix( modelview );
|
||||
sgCopyMat4( tmp, transform );
|
||||
sgPostMultMat4( tmp, modelview );
|
||||
|
||||
sgSetVec3( eyePos, -relx, -tmp[3][2], -rely);
|
||||
sgSetVec3( eyePos, -relx, 0, -rely);
|
||||
sgSetVec3( eyePos, -relx, alt, -rely);
|
||||
// sgSetVec3( eyePos, 0, - tmp[3][2], 0);
|
||||
// sgSetVec3( eyePos, 20000, - tmp[3][2], 20000);
|
||||
|
||||
tmp[3][2] = 0;
|
||||
tmp[3][0] = 0;
|
||||
tmp[3][1] = 0;
|
||||
ssgLoadModelviewMatrix( tmp );
|
||||
|
||||
/* flat earth
|
||||
|
||||
^
|
||||
|
|
||||
| FFF
|
||||
| FoF
|
||||
| FFF
|
||||
|
|
||||
O----------->
|
||||
o = we are here
|
||||
F = adjacent fields
|
||||
*/
|
||||
|
||||
for(int x = -1 ; x <= 1 ; x++)
|
||||
for(int y = -1 ; y <= 1 ; y++ ) {
|
||||
sgVec3 fieldPos;
|
||||
// pretend we are not where we are
|
||||
sgSetVec3(fieldPos, eyePos[0] + x*fieldSize, eyePos[1], eyePos[2] + y*fieldSize);
|
||||
cullClouds(fieldPos, tmp);
|
||||
}
|
||||
// sort all visible clouds back to front (because of transparency)
|
||||
sort( inViewClouds.begin(), inViewClouds.end() );
|
||||
|
||||
// TODO:push states
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.0f);
|
||||
glDisable(GL_CULL_FACE);
|
||||
// glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
// glEnable( GL_COLOR_MATERIAL );
|
||||
glEnable( GL_TEXTURE_2D );
|
||||
glDisable( GL_FOG );
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// test data: field = 11x11 cloud, 9 fields
|
||||
// depending on position and view direction, perhaps 40 to 60 clouds not culled
|
||||
list_of_culledCloud::iterator iCloud;
|
||||
for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) {
|
||||
// iCloud->aCloud->drawContainers();
|
||||
iCloud->aCloud->Render(iCloud->eyePos);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
||||
|
||||
ssgLoadModelviewMatrix( modelview );
|
||||
|
||||
glPopMatrix();
|
||||
// glEnable(GL_DEPTH_TEST);
|
||||
|
||||
}
|
||||
|
||||
114
simgear/scene/sky/cloudfield.hxx
Normal file
114
simgear/scene/sky/cloudfield.hxx
Normal file
@@ -0,0 +1,114 @@
|
||||
// a layer of 3d clouds
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _CLOUDFIELD_HXX
|
||||
#define _CLOUDFIELD_HXX
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <simgear/compiler.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
SG_USING_STD(vector);
|
||||
|
||||
class SGNewCloud;
|
||||
|
||||
class culledCloud {
|
||||
public:
|
||||
SGNewCloud *aCloud;
|
||||
sgVec3 eyePos;
|
||||
float dist;
|
||||
bool operator<(const culledCloud &b) const {
|
||||
return (this->dist < b.dist);
|
||||
}
|
||||
};
|
||||
typedef vector<culledCloud> list_of_culledCloud;
|
||||
|
||||
class SGCloudField {
|
||||
|
||||
private:
|
||||
class Cloud {
|
||||
public:
|
||||
SGNewCloud *aCloud;
|
||||
sgVec3 pos;
|
||||
// float dist;
|
||||
// bool culled;
|
||||
|
||||
// bool operator<(const Cloud &b) {
|
||||
// return this->dist < b.dist;
|
||||
// }
|
||||
};
|
||||
|
||||
|
||||
typedef vector<Cloud> list_of_Cloud;
|
||||
|
||||
// cull all clouds of a tiled field
|
||||
void cullClouds(sgVec3 eyePos, sgMat4 mat);
|
||||
|
||||
list_of_Cloud theField;
|
||||
// this is a relative position only, with that we can move all clouds at once
|
||||
sgVec3 relative_position;
|
||||
// double lon, lat;
|
||||
|
||||
sgFrustum frustum;
|
||||
|
||||
sgMat4 transform;
|
||||
double deltax, deltay, alt;
|
||||
|
||||
public:
|
||||
|
||||
SGCloudField();
|
||||
~SGCloudField();
|
||||
|
||||
// add one cloud, data is not copied, ownership given
|
||||
void addCloud( sgVec3 pos, SGNewCloud *cloud);
|
||||
|
||||
// for debug only
|
||||
void buildTestLayer(void);
|
||||
|
||||
// Render a cloud field
|
||||
void Render(void);
|
||||
|
||||
// reposition the cloud layer at the specified origin and orientation
|
||||
void reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt);
|
||||
|
||||
// visibility distance for clouds in meters
|
||||
static float CloudVis;
|
||||
|
||||
static float density;
|
||||
|
||||
static double fieldSize;
|
||||
static bool enable3D;
|
||||
|
||||
// return the size of the memory pool used by texture impostors
|
||||
static int get_CacheSize(void);
|
||||
static float get_CloudVis(void) { return CloudVis; }
|
||||
static float get_density(void) { return density; }
|
||||
static bool get_enable3dClouds(void) { return enable3D; }
|
||||
|
||||
static void set_CacheSize(int sizeKb);
|
||||
static void set_CloudVis(float distance);
|
||||
static void set_density(float density);
|
||||
static void set_enable3dClouds(bool enable);
|
||||
};
|
||||
|
||||
#endif // _CLOUDFIELD_HXX
|
||||
726
simgear/scene/sky/newcloud.cxx
Normal file
726
simgear/scene/sky/newcloud.cxx
Normal file
@@ -0,0 +1,726 @@
|
||||
// 3D cloud class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include STL_ALGORITHM
|
||||
#include SG_GLUT_H
|
||||
|
||||
#include "newcloud.hxx"
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
static ssgTexture *cloudTextures[SGNewCloud::CLTexture_max];
|
||||
|
||||
|
||||
bool SGNewCloud::useAnisotropic = true;
|
||||
SGBbCache *SGNewCloud::cldCache = 0;
|
||||
static bool texturesLoaded = false;
|
||||
float SGNewCloud::nearRadius = 2500.0f;
|
||||
bool SGNewCloud::lowQuality = false;
|
||||
sgVec3 SGNewCloud::sunlight = {0.5f, 0.5f, 0.5f};
|
||||
sgVec3 SGNewCloud::ambLight = {0.5f, 0.5f, 0.5f};
|
||||
sgVec3 SGNewCloud::modelSunDir = {0,1,0};
|
||||
|
||||
|
||||
// constructor
|
||||
SGNewCloud::SGNewCloud() :
|
||||
bbId(-1),
|
||||
// rank(-1),
|
||||
minx(999), miny(999), minz(999), maxx(-999), maxy(-999), maxz(-999)
|
||||
|
||||
{
|
||||
cloudId = (int) this;
|
||||
sgSetVec3(center, 0.0f, 0.0f, 0.0f);
|
||||
sgSetVec3(cloudpos, 0.0f, 0.0f, 0.0f);
|
||||
list_spriteContainer.reserve(8);
|
||||
list_spriteDef.reserve(40);
|
||||
// if( ! texturesLoaded ) {}
|
||||
if( cldCache == 0 ) {
|
||||
cldCache = new SGBbCache;
|
||||
cldCache->init( 20 );
|
||||
}
|
||||
}
|
||||
|
||||
SGNewCloud::~SGNewCloud() {
|
||||
list_spriteDef.clear();
|
||||
list_spriteContainer.clear();
|
||||
cldCache->free( bbId, cloudId );
|
||||
}
|
||||
|
||||
|
||||
// load all textures used to draw cloud sprites
|
||||
void SGNewCloud::loadTextures(const string &tex_path) {
|
||||
if( texturesLoaded )
|
||||
return;
|
||||
texturesLoaded = true;
|
||||
|
||||
SGPath cloud_path;
|
||||
|
||||
cloud_path.set(tex_path);
|
||||
cloud_path.append("cl_cumulus.rgb");
|
||||
cloudTextures[ CLTexture_cumulus ] = new ssgTexture( cloud_path.str().c_str(), false, false, false );
|
||||
cloudTextures[ CLTexture_cumulus ]->ref();
|
||||
|
||||
cloud_path.set(tex_path);
|
||||
cloud_path.append("cl_stratus.rgb");
|
||||
cloudTextures[ CLTexture_stratus ] = new ssgTexture( cloud_path.str().c_str(), false, false, false );
|
||||
cloudTextures[ CLTexture_stratus ]->ref();
|
||||
|
||||
}
|
||||
|
||||
void SGNewCloud::startFade(bool direction, float duration, float pauseLength) {
|
||||
}
|
||||
void SGNewCloud::setFade(float howMuch) {
|
||||
}
|
||||
|
||||
|
||||
static float rayleighCoeffAngular(float cosAngle) {
|
||||
return 3.0f / 4.0f * (1.0f + cosAngle * cosAngle);
|
||||
}
|
||||
|
||||
// cp is normalized (len==1)
|
||||
static void CartToPolar3d(sgVec3 cp, sgVec3 polar) {
|
||||
polar[0] = atan2(cp[1], cp[0]);
|
||||
polar[1] = SG_PI / 2.0f - atan2(sqrtf (cp[0] * cp[0] + cp[1] * cp[1]), cp[2]);
|
||||
polar[2] = 1.0f;
|
||||
}
|
||||
|
||||
static void PolarToCart3d(sgVec3 p, sgVec3 cart) {
|
||||
float tmp = cos(p[1]);
|
||||
cart[0] = cos(p[0]) * tmp;
|
||||
cart[1] = sin(p[0]) * tmp;
|
||||
cart[2] = sin(p[1]);
|
||||
}
|
||||
|
||||
|
||||
// compute the light for a cloud sprite corner
|
||||
// from the normal and the sun, scaled by the Rayleigh factor
|
||||
// and finaly added to the ambient light
|
||||
static void lightFunction(sgVec3 normal, sgVec4 light, float pf) {
|
||||
float cosAngle = sgScalarProductVec3( normal, SGNewCloud::modelSunDir);
|
||||
float vl = (1.0f - 0.1f + cosAngle / 10.0f) * pf;
|
||||
sgScaleVec3( light, SGNewCloud::sunlight, vl );
|
||||
sgAddVec3( light, SGNewCloud::ambLight );
|
||||
// we need to clamp or else the light will bug when adding transparency
|
||||
if( light[0] > 1.0 ) light[0] = 1.0;
|
||||
if( light[1] > 1.0 ) light[1] = 1.0;
|
||||
if( light[2] > 1.0 ) light[2] = 1.0;
|
||||
light[3] = 1.0;
|
||||
}
|
||||
|
||||
// compute the light for a cloud sprite
|
||||
// we use ambient light and orientation versus sun position
|
||||
// TODO:check sun pos and check code
|
||||
void SGNewCloud::computeSimpleLight(sgVec3 FakeEyePos) {
|
||||
// constant Rayleigh factor if we are not doing Anisotropic lighting
|
||||
float pf = 1.0f;
|
||||
const float ang = 45.0f * SG_PI / 180.0f;
|
||||
list_of_spriteDef::iterator iSprite;
|
||||
for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
|
||||
if( useAnisotropic ) {
|
||||
sgVec3 eyeDir;
|
||||
sgSubVec3(eyeDir, iSprite->pos, FakeEyePos);
|
||||
sgNormaliseVec3(eyeDir);
|
||||
float cosAngle = sgScalarProductVec3(eyeDir, modelSunDir);
|
||||
pf = rayleighCoeffAngular(cosAngle);
|
||||
}
|
||||
// compute the vector going from the container box center to the sprite
|
||||
// TODO : this is a constant except for cloudpos, compute the normal in setpos function
|
||||
sgVec3 normal;
|
||||
spriteContainer *thisSpriteContainer = &list_spriteContainer[iSprite->box];
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add a new box to the cloud
|
||||
void SGNewCloud::addContainer (float x, float y, float z, float r, CLbox_type type) {
|
||||
spriteContainer cont;
|
||||
sgSetVec3( cont.pos, x, y, z );
|
||||
cont.r = r;
|
||||
cont.cont_type = type;
|
||||
sgSetVec3( cont.center, 0.0f, 0.0f, 0.0f);
|
||||
list_spriteContainer.push_back( cont );
|
||||
}
|
||||
|
||||
// add a sprite inside a box
|
||||
void SGNewCloud::addSprite(float x, float y, float z, float r, CLbox_type type, int box) {
|
||||
spriteDef newSpriteDef;
|
||||
int rank = list_spriteDef.size();
|
||||
sgSetVec3( newSpriteDef.pos, x, y, z);
|
||||
newSpriteDef.box = box;
|
||||
newSpriteDef.sprite_type = type;
|
||||
newSpriteDef.rank = rank;
|
||||
newSpriteDef.r = r;
|
||||
list_spriteDef.push_back( newSpriteDef );
|
||||
spriteContainer *thisBox = &list_spriteContainer[box];
|
||||
sgVec3 deltaPos;
|
||||
sgSubVec3( deltaPos, newSpriteDef.pos, thisBox->pos );
|
||||
sgAddVec3( thisBox->center, deltaPos );
|
||||
|
||||
r = r * 0.6f; // 0.5 * 1.xxx
|
||||
if( x - r < minx )
|
||||
minx = x - r;
|
||||
if( y - r < miny )
|
||||
miny = y - r;
|
||||
if( z - r < minz )
|
||||
minz = z - r;
|
||||
if( x + r > maxx )
|
||||
maxx = x + r;
|
||||
if( y + r > maxy )
|
||||
maxy = y + r;
|
||||
if( z + r > maxz )
|
||||
maxz = z + r;
|
||||
|
||||
}
|
||||
|
||||
// return a random number between -n/2 and n/2
|
||||
static float Rnd(float n) {
|
||||
return n * (-0.5f + rand() / (float) RAND_MAX);
|
||||
}
|
||||
|
||||
// generate all sprite with defined boxes
|
||||
void SGNewCloud::genSprites( void ) {
|
||||
float x, y, z, r;
|
||||
int N, sc;
|
||||
N = list_spriteContainer.size();
|
||||
for(int i = 0 ; i < N ; i++ ) {
|
||||
spriteContainer *thisBox = & list_spriteContainer[i];
|
||||
// the type defines how the sprites can be positioned inside the box, their size, etc
|
||||
switch(thisBox->cont_type) {
|
||||
case CLbox_sc:
|
||||
for( sc = 0 ; sc <= 4 ; sc ++ ) {
|
||||
r = thisBox->r + Rnd(0.2f);
|
||||
x = thisBox->pos[SG_X] + Rnd(thisBox->r);
|
||||
y = thisBox->pos[SG_Y] + Rnd(thisBox->r * 0.2f);
|
||||
z = thisBox->pos[SG_Z] + Rnd(thisBox->r);
|
||||
addSprite(x, y, z, r, thisBox->cont_type, i);
|
||||
}
|
||||
break;
|
||||
case CLbox_stratus:
|
||||
sc = 1;
|
||||
r = thisBox->r;
|
||||
x = thisBox->pos[SG_X];
|
||||
y = thisBox->pos[SG_Y];
|
||||
z = thisBox->pos[SG_Z];
|
||||
addSprite(x, y, z, r, thisBox->cont_type, i);
|
||||
break;
|
||||
case CLbox_cumulus:
|
||||
for( sc = 0 ; sc <= 4 ; sc ++ ) {
|
||||
r = thisBox->r + Rnd(0.2f);
|
||||
x = thisBox->pos[SG_X] + Rnd(thisBox->r * 0.75f);
|
||||
y = thisBox->pos[SG_Y] + Rnd(thisBox->r * 0.5f);
|
||||
z = thisBox->pos[SG_Z] + Rnd(thisBox->r * 0.75f);
|
||||
if ( y < thisBox->pos[SG_Y] - thisBox->r / 10.0f )
|
||||
y = thisBox->pos[SG_Y] - thisBox->r / 10.0f;
|
||||
addSprite(x, y, z, r, thisBox->cont_type, i);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for( sc = 0 ; sc <= 4 ; sc ++ ) {
|
||||
r = thisBox->r + Rnd(0.2f);
|
||||
x = thisBox->pos[SG_X] + Rnd(thisBox->r);
|
||||
y = thisBox->pos[SG_Y] + Rnd(thisBox->r);
|
||||
z = thisBox->pos[SG_Z] + Rnd(thisBox->r);
|
||||
addSprite(x, y, z, r, thisBox->cont_type, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
sgScaleVec3(thisBox->center, 1.0f / sc);
|
||||
}
|
||||
|
||||
radius = maxx - minx;
|
||||
if ( (maxy - miny) > radius )
|
||||
radius = (maxy - miny);
|
||||
if ( (maxz - minz) > radius )
|
||||
radius = (maxz - minz);
|
||||
radius /= 2.0f;
|
||||
sgSetVec3( center, (maxx + minx) / 2.0f, (maxy + miny) / 2.0f, (maxz + minz) / 2.0f );
|
||||
|
||||
/* fadingrank = 0
|
||||
' fadingrank = UBound(tbSpriteDef()) * 10
|
||||
fadingdir = 0*/
|
||||
// TODO : compute initial sprite normals for lighting function
|
||||
}
|
||||
|
||||
|
||||
// definition of a cu cloud, only for testing
|
||||
void SGNewCloud::new_cu(void) {
|
||||
float s = 150.0f;
|
||||
float r = Rnd(1.0) + 0.5;
|
||||
if( r < 0.5f ) {
|
||||
addContainer(0.0f, 0.0f, 0.0f, s, CLbox_cumulus);
|
||||
addContainer(s, 0, 0, s, CLbox_cumulus);
|
||||
addContainer(0, 0, 2 * s, s, CLbox_cumulus);
|
||||
addContainer(s, 0, 2 * s, s, CLbox_cumulus);
|
||||
|
||||
addContainer(-1.2f * s, 0.2f * s, s, s * 1.4f, CLbox_cumulus);
|
||||
addContainer(0.2f * s, 0.2f * s, s, s * 1.4f, CLbox_cumulus);
|
||||
addContainer(1.6f * s, 0.2f * s, s, s * 1.4f, CLbox_cumulus);
|
||||
} else if ( r < 0.90f ) {
|
||||
addContainer(0, 0, 0, s * 1.2, CLbox_cumulus);
|
||||
addContainer(s, 0, 0, s, CLbox_cumulus);
|
||||
addContainer(0, 0, s, s, CLbox_cumulus);
|
||||
addContainer(s * 1.1, 0, s, s * 1.2, CLbox_cumulus);
|
||||
|
||||
addContainer(-1.2 * s, 1 + 0.2 * s, s * 0.5, s * 1.4, CLbox_standard);
|
||||
addContainer(0.2 * s, 1 + 0.25 * s, s * 0.5, s * 1.5, CLbox_standard);
|
||||
addContainer(1.6 * s, 1 + 0.2 * s, s * 0.5, s * 1.4, CLbox_standard);
|
||||
|
||||
} else {
|
||||
// cb
|
||||
s = 475.0f;
|
||||
addContainer(0, 0, 0, s, CLbox_cumulus);
|
||||
addContainer(0, 0, s, s, CLbox_cumulus);
|
||||
addContainer(s, 0, s, s, CLbox_cumulus);
|
||||
addContainer(s, 0, 0, s, CLbox_cumulus);
|
||||
|
||||
addContainer(s / 2, s, s / 2, s * 1.5, CLbox_standard);
|
||||
|
||||
addContainer(0, 2 * s, 0, s, CLbox_standard);
|
||||
addContainer(0, 2 * s, s, s, CLbox_standard);
|
||||
addContainer(s, 2 * s, s, s, CLbox_standard);
|
||||
addContainer(s, 2 * s, 0, s, CLbox_standard);
|
||||
|
||||
}
|
||||
genSprites();
|
||||
}
|
||||
|
||||
|
||||
// define the new position of the cloud (inside the cloud field, not on sphere)
|
||||
void SGNewCloud::SetPos(sgVec3 newPos) {
|
||||
int N = list_spriteDef.size();
|
||||
sgVec3 deltaPos;
|
||||
sgSubVec3( deltaPos, newPos, cloudpos );
|
||||
|
||||
// for each particle
|
||||
for(int i = 0 ; i < N ; i ++) {
|
||||
sgAddVec3( list_spriteDef[i].pos, deltaPos );
|
||||
}
|
||||
sgAddVec3( center, deltaPos );
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Public Sub drawContainers()
|
||||
Dim N As Integer, i As Integer
|
||||
N = UBound(tbSpriteCont())
|
||||
|
||||
Call glPolygonMode(faceFrontAndBack, pgmLine)
|
||||
|
||||
Call glColor3f(0.9, 0.9, 0.9)
|
||||
|
||||
For i = 0 To N - 1
|
||||
With tbSpriteCont(i)
|
||||
Call glPushMatrix
|
||||
Call glTranslatef(.x * c_scale + cloudpos(0), .y * c_scale + cloudpos(1), .z * c_scale + cloudpos(2))
|
||||
Call gCtl.Shapes.box(.r * c_scale, .r * c_scale, .r * c_scale)
|
||||
Call glPopMatrix
|
||||
End With
|
||||
Next i
|
||||
If 0 Then
|
||||
Call glPushMatrix
|
||||
Call glTranslatef(ccenter(0), ccenter(1), ccenter(2))
|
||||
Call gCtl.Shapes.Sphere(cradius, 8, 8)
|
||||
Call glPopMatrix
|
||||
End If
|
||||
End Sub
|
||||
*/
|
||||
void SGNewCloud::drawContainers() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
//bool SGNewCloud::compareSpriteFunction(const spriteDef &a, const spriteDef &b) {
|
||||
// return (a.dist > b.dist);
|
||||
//}
|
||||
|
||||
// sort on distance to eye because of transparency
|
||||
void SGNewCloud::sortSprite( sgVec3 eye ) {
|
||||
list_of_spriteDef::iterator iSprite;
|
||||
|
||||
// compute distance from sprite to eye
|
||||
for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
|
||||
sgVec3 dist;
|
||||
sgSubVec3( dist, iSprite->pos, eye );
|
||||
iSprite->dist = -(dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2]);
|
||||
}
|
||||
sort( list_spriteDef.begin(), list_spriteDef.end() );
|
||||
}
|
||||
|
||||
// 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 ) {
|
||||
|
||||
/* int clrank = fadingrank / 10;
|
||||
int clfadeinrank = fadingrank - clrank * 10;*/
|
||||
|
||||
|
||||
GLint previousTexture = -1, thisTexture;
|
||||
list_of_spriteDef::iterator iSprite;
|
||||
for( iSprite = list_spriteDef.begin() ; iSprite != list_spriteDef.end() ; iSprite++ ) {
|
||||
// choose texture to use depending on sprite type
|
||||
switch(iSprite->sprite_type) {
|
||||
case CLbox_stratus:
|
||||
thisTexture = CLTexture_stratus;
|
||||
break;
|
||||
default:
|
||||
thisTexture = CLTexture_cumulus;
|
||||
break;
|
||||
}
|
||||
// in practice there is no texture switch (atm)
|
||||
if( previousTexture != thisTexture ) {
|
||||
previousTexture = thisTexture;
|
||||
glBindTexture(GL_TEXTURE_2D, cloudTextures[thisTexture]->getHandle());
|
||||
}
|
||||
|
||||
sgVec3 translate;
|
||||
if( drawBB ) {
|
||||
sgCopyVec3( translate, iSprite->pos);
|
||||
sgSubVec3( translate, iSprite->pos, deltaPos );
|
||||
}
|
||||
else
|
||||
sgSubVec3( translate, iSprite->pos, deltaPos);
|
||||
|
||||
|
||||
// flipx and flipy are random texture flip flags, this gives more random clouds
|
||||
float flipx = (float) ( iSprite->rank & 1 );
|
||||
float flipy = (float) ( (iSprite->rank >> 1) & 1 );
|
||||
// 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 )
|
||||
flipy = 0.0f;
|
||||
if( iSprite->sprite_type == CLbox_stratus )
|
||||
flipx = 0.0f;
|
||||
// adjust colors depending on cloud type
|
||||
// TODO : rewrite that later, still experimental
|
||||
switch(iSprite->sprite_type) {
|
||||
case CLbox_cumulus:
|
||||
// dark bottom
|
||||
sgScaleVec3(iSprite->l0, 0.6f);
|
||||
sgScaleVec3(iSprite->l1, 0.6f);
|
||||
break;
|
||||
case CLbox_stratus:
|
||||
// usually dark grey
|
||||
sgScaleVec3(iSprite->l0, 0.8f);
|
||||
sgScaleVec3(iSprite->l1, 0.8f);
|
||||
sgScaleVec3(iSprite->l2, 0.8f);
|
||||
sgScaleVec3(iSprite->l3, 0.8f);
|
||||
break;
|
||||
default:
|
||||
// darker bottom than top
|
||||
sgScaleVec3(iSprite->l0, 0.8f);
|
||||
sgScaleVec3(iSprite->l1, 0.8f);
|
||||
break;
|
||||
}
|
||||
float r = iSprite->r * 0.5f;
|
||||
|
||||
sgVec4 l0, l1, l2, l3;
|
||||
sgCopyVec4 ( l0, iSprite->l0 );
|
||||
sgCopyVec4 ( l1, iSprite->l1 );
|
||||
sgCopyVec4 ( l2, iSprite->l2 );
|
||||
sgCopyVec4 ( l3, iSprite->l3 );
|
||||
if( ! drawBB ) {
|
||||
// blend clouds with sky based on distance to limit the contrast of distant cloud
|
||||
// TODO:use cloudfield vis, not hardcoded value
|
||||
float t = 1.0f - dist_center / (15000.0f * 2.0 );
|
||||
if ( t < 0.0f )
|
||||
t = 0.0f; // no, it should have been culled
|
||||
// now clouds at the far plane are half blended
|
||||
sgScaleVec4( l0, t );
|
||||
sgScaleVec4( l1, t );
|
||||
sgScaleVec4( l2, t );
|
||||
sgScaleVec4( l3, t );
|
||||
}
|
||||
// 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);
|
||||
sgNormaliseVec3(x);
|
||||
sgScaleVec3(x, r);
|
||||
sgVectorProductVec3(y, x, translate);
|
||||
sgNormaliseVec3(y);
|
||||
sgScaleVec3(y, r);
|
||||
|
||||
sgVec3 left, right;
|
||||
if( drawBB )
|
||||
sgSetVec3( left, iSprite->pos[SG_X], iSprite->pos[SG_Z], iSprite->pos[SG_Y]);
|
||||
else
|
||||
sgCopyVec3( left, pos );
|
||||
sgSubVec3 (left, y);
|
||||
sgAddVec3 (right, left, x);
|
||||
sgSubVec3 (left, x);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glColor4fv(l0);
|
||||
glTexCoord2f(flipx, 1.0f - flipy);
|
||||
glVertex3fv(left);
|
||||
glColor4fv(l1);
|
||||
glTexCoord2f(1.0f - flipx, 1.0f - flipy);
|
||||
glVertex3fv(right);
|
||||
sgScaleVec3( y, 2.0 );
|
||||
sgAddVec3( left, y);
|
||||
sgAddVec3( right, y);
|
||||
glColor4fv(l2);
|
||||
glTexCoord2f(1.0f - flipx, flipy);
|
||||
glVertex3fv(right);
|
||||
glColor4fv(l3);
|
||||
glTexCoord2f(flipx, flipy);
|
||||
glVertex3fv(left);
|
||||
|
||||
glEnd();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// compute rotations so that a quad is facing the camera
|
||||
// TODO:change obsolete code because we dont use glrotate anymore
|
||||
void SGNewCloud::CalcAngles(sgVec3 refpos, sgVec3 FakeEyePos, float *angleY, float *angleX) {
|
||||
sgVec3 upAux, lookAt, objToCamProj, objToCam;
|
||||
float angle, angle2;
|
||||
|
||||
sgSetVec3(objToCamProj, -FakeEyePos[SG_X] + refpos[SG_X], -FakeEyePos[SG_Z] + refpos[SG_Z], 0.0f);
|
||||
sgNormaliseVec3(objToCamProj);
|
||||
|
||||
sgSetVec3(lookAt, 0.0f, 1.0f, 0.0f);
|
||||
sgVectorProductVec3(upAux, lookAt, objToCamProj);
|
||||
angle = sgScalarProductVec3(lookAt, objToCamProj);
|
||||
if( (angle < 0.9999f) && (angle > -0.9999f) ) {
|
||||
angle = acos(angle) * 180.0f / SG_PI;
|
||||
if( upAux[2] < 0.0f )
|
||||
angle = -angle;
|
||||
} else
|
||||
angle = 0.0f;
|
||||
|
||||
sgSetVec3(objToCam, -FakeEyePos[SG_X] + refpos[SG_X], -FakeEyePos[SG_Z] + refpos[SG_Z], -FakeEyePos[SG_Y] + refpos[SG_Y]);
|
||||
sgNormaliseVec3(objToCam);
|
||||
|
||||
angle2 = sgScalarProductVec3(objToCamProj, objToCam);
|
||||
if( (angle2 < 0.9999f) && (angle2 > -0.9999f) ) {
|
||||
angle2 = -acos(angle2) * 180.0f / SG_PI;
|
||||
if( objToCam[2] > 0.0f )
|
||||
angle2 = -angle2;
|
||||
} else
|
||||
angle2 = 0.0f;
|
||||
|
||||
angle2 += 90.0f;
|
||||
|
||||
*angleY = angle;
|
||||
*angleX = angle2;
|
||||
}
|
||||
|
||||
// draw a cloud but this time we use the impostor texture
|
||||
void SGNewCloud::RenderBB(sgVec3 deltaPos, float angleY, float angleX, float dist_center) {
|
||||
// TODO:glrotate is not needed
|
||||
glPushMatrix();
|
||||
glTranslatef(center[SG_X] - deltaPos[SG_X], center[SG_Z] - deltaPos[SG_Z], center[SG_Y] - deltaPos[SG_Y]);
|
||||
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
|
||||
// TODO:use cloudfield vis, not hardcoded value
|
||||
float t = 1.0f - dist_center / (15000.0f * 2.0 );
|
||||
// err the alpha value is not good for impostor, debug that
|
||||
t *= 1.65;
|
||||
if ( t < 0.0f )
|
||||
t = 0.0f;
|
||||
|
||||
glColor4f(t, t, t, t);
|
||||
float r = radius;
|
||||
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);
|
||||
glVertex2f(-r, -r);
|
||||
glEnd();
|
||||
|
||||
#if 1 // debug only
|
||||
int age = cldCache->queryImpostorAge(bbId);
|
||||
// draw a red border for the newly generated BBs else draw a white border
|
||||
if( age < 200 )
|
||||
glColor3f(1, 0, 0);
|
||||
else
|
||||
glColor3f(1, 1, 1);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(-r, -r);
|
||||
glVertex2f(r, -r);
|
||||
glVertex2f(r, r);
|
||||
glVertex2f(-r, r);
|
||||
glEnd();
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
#endif
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
|
||||
// determine if it is a good idea to use an impostor to render the cloud
|
||||
bool SGNewCloud::isBillboardable(float dist) {
|
||||
|
||||
if( dist <= ( 2.1f * radius ) ) {
|
||||
// inside cloud
|
||||
return false;
|
||||
}
|
||||
if( (dist-radius) <= nearRadius ) {
|
||||
// near clouds we don't want to use BB
|
||||
return false;
|
||||
}
|
||||
// return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// render the cloud, fakepos is a relative position inside the cloud field
|
||||
void SGNewCloud::Render(sgVec3 fakepos) {
|
||||
sgVec3 eyePos, FakeEyePos;
|
||||
sgVec3 dist;
|
||||
|
||||
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
|
||||
// obsolete code
|
||||
sgCopyVec3( eyePos, fakepos );
|
||||
|
||||
sgCopyVec3( FakeEyePos, fakepos);
|
||||
sgVec3 deltaPos;
|
||||
// sgSubVec3( deltaPos, eyePos, FakeEyePos);
|
||||
sgCopyVec3( deltaPos, FakeEyePos);
|
||||
sgSubVec3( dist, center, FakeEyePos);
|
||||
float dist_center = sgLengthVec3(dist);
|
||||
|
||||
// eeeek don't do that so early, perhaps we will use an impostor
|
||||
computeSimpleLight( FakeEyePos );
|
||||
|
||||
// view point sort, we sort because of transparency
|
||||
// eeeek don't do that so early, perhaps we will use an impostor
|
||||
sortSprite( FakeEyePos );
|
||||
|
||||
|
||||
if( !isBillboardable(dist_center) ) {
|
||||
// not a good candidate for impostors, draw a real cloud
|
||||
Render3Dcloud(false, FakeEyePos, deltaPos, dist_center);
|
||||
} else {
|
||||
GLuint texID = 0;
|
||||
// lets use our impostor
|
||||
if( bbId >= 0)
|
||||
texID = cldCache->QueryTexID(cloudId, bbId);
|
||||
|
||||
// ok someone took our impostor, so allocate a new one
|
||||
if( texID == 0 ) {
|
||||
// allocate a new Impostor
|
||||
bbId = cldCache->alloc(cloudId);
|
||||
texID = cldCache->QueryTexID(cloudId, bbId);
|
||||
}
|
||||
if( texID == 0 ) {
|
||||
// no more free texture in the pool
|
||||
Render3Dcloud(false, FakeEyePos, deltaPos, dist_center);
|
||||
} else {
|
||||
float angleX, angleY;
|
||||
CalcAngles(center, FakeEyePos, &angleY, &angleX);
|
||||
if( ! cldCache->isBbValid( cloudId, bbId, angleY, angleX) ) {
|
||||
// we must build or rebuild this billboard
|
||||
// start render to texture
|
||||
cldCache->beginCapture();
|
||||
// set transformation matrices
|
||||
cldCache->setRadius(radius, dist_center);
|
||||
gluLookAt(FakeEyePos[SG_X], FakeEyePos[SG_Z], FakeEyePos[SG_Y], center[SG_X], center[SG_Z], center[SG_Y], 0.0, 0.0, 1.0);
|
||||
// draw into texture
|
||||
Render3Dcloud(true, FakeEyePos, deltaPos, dist_center);
|
||||
// save rotation angles for later use
|
||||
// TODO:this is not ok
|
||||
cldCache->setReference(cloudId, bbId, angleY, angleX);
|
||||
// save the rendered cloud into the cache
|
||||
cldCache->setTextureData( bbId );
|
||||
// finish render to texture and go back into standard context
|
||||
cldCache->endCapture();
|
||||
}
|
||||
// draw the newly built BB or an old one
|
||||
glBindTexture(GL_TEXTURE_2D, texID);
|
||||
RenderBB(deltaPos, angleY, angleX, dist_center);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
147
simgear/scene/sky/newcloud.hxx
Normal file
147
simgear/scene/sky/newcloud.hxx
Normal file
@@ -0,0 +1,147 @@
|
||||
// 3D cloud class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _NEWCLOUD_HXX
|
||||
#define _NEWCLOUD_HXX
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <simgear/compiler.h>
|
||||
#include STL_STRING
|
||||
#include <vector>
|
||||
|
||||
#include "bbcache.hxx"
|
||||
|
||||
SG_USING_STD(string);
|
||||
SG_USING_STD(vector);
|
||||
|
||||
class SGNewCloud {
|
||||
|
||||
public:
|
||||
SGNewCloud();
|
||||
~SGNewCloud();
|
||||
|
||||
enum CLbox_type {
|
||||
CLbox_standard = 0,
|
||||
CLbox_sc = 1,
|
||||
CLbox_cumulus = 2,
|
||||
CLbox_stratus = 3
|
||||
};
|
||||
|
||||
enum CLTexture_type {
|
||||
CLTexture_cumulus = 1,
|
||||
CLTexture_stratus = 2,
|
||||
CLTexture_max
|
||||
};
|
||||
private:
|
||||
|
||||
class spriteDef {
|
||||
public:
|
||||
sgVec3 pos;
|
||||
float r;
|
||||
CLbox_type sprite_type;
|
||||
sgVec4 l0, l1, l2, l3;
|
||||
int rank;
|
||||
int box;
|
||||
float dist; // distance used during sort
|
||||
bool operator<(const spriteDef &b) const {
|
||||
return this->dist < b.dist;
|
||||
}
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
sgVec3 pos;
|
||||
float r;
|
||||
// the type defines how the sprites can be positioned inside the box, their size, etc
|
||||
CLbox_type cont_type;
|
||||
sgVec3 center;
|
||||
} spriteContainer;
|
||||
|
||||
typedef vector<spriteDef> list_of_spriteDef;
|
||||
typedef vector<spriteContainer> list_of_spriteContainer;
|
||||
|
||||
void computeSimpleLight(sgVec3 eyePos);
|
||||
void addSprite(float x, float y, float z, float r, CLbox_type type, int box);
|
||||
|
||||
// sort on distance to eye because of transparency
|
||||
void sortSprite( sgVec3 eyePos );
|
||||
|
||||
// render the cloud on screen or on the RTT texture to build the impostor
|
||||
void Render3Dcloud( bool drawBB, sgVec3 eyePos, sgVec3 deltaPos, float dist_center );
|
||||
|
||||
// compute rotations so that a quad is facing the camera
|
||||
void CalcAngles(sgVec3 refpos, sgVec3 eyePos, float *angleY, float *angleX);
|
||||
|
||||
// draw a cloud but this time we use the impostor texture
|
||||
void RenderBB(sgVec3 deltaPos, float angleY, float angleX, float dist_center);
|
||||
|
||||
// determine if it is a good idea to use an impostor to render the cloud
|
||||
bool isBillboardable(float dist);
|
||||
|
||||
int cloudId, bbId;
|
||||
// int rank;
|
||||
sgVec3 cloudpos, center;
|
||||
list_of_spriteDef list_spriteDef;
|
||||
list_of_spriteContainer list_spriteContainer;
|
||||
float minx, maxx, miny, maxy, minz, maxz;
|
||||
float radius;
|
||||
|
||||
// fading data
|
||||
bool direction, fadeActive;
|
||||
float duration, pauseLength;
|
||||
// need timer here
|
||||
|
||||
public:
|
||||
// add a new box to the cloud
|
||||
void addContainer(float x, float y, float z, float r, CLbox_type type);
|
||||
|
||||
// generate all sprite with defined boxes
|
||||
void genSprites(void);
|
||||
|
||||
// debug only, define a cumulus
|
||||
void new_cu(void);
|
||||
|
||||
// debug only
|
||||
void drawContainers(void);
|
||||
|
||||
// define the new position of the cloud (inside the cloud field, not on sphere)
|
||||
void SetPos(sgVec3 newPos);
|
||||
|
||||
// render the cloud, fakepos is a relative position inside the cloud field
|
||||
void Render(sgVec3 fakepos);
|
||||
|
||||
//
|
||||
void startFade(bool direction, float duration, float pauseLength);
|
||||
void setFade(float howMuch);
|
||||
|
||||
inline float getRadius() { return radius; }
|
||||
|
||||
// load all textures used to draw cloud sprites
|
||||
static void loadTextures( const string &tex_path );
|
||||
static sgVec3 modelSunDir;
|
||||
static sgVec3 sunlight, ambLight;
|
||||
static bool useAnisotropic;
|
||||
static float nearRadius;
|
||||
static bool lowQuality;
|
||||
static SGBbCache *cldCache;
|
||||
};
|
||||
|
||||
#endif // _NEWCLOUD_HXX
|
||||
Reference in New Issue
Block a user