Compare commits
106 Commits
RELEASE_0_
...
RELEASE_0_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a2ee54389 | ||
|
|
ab69c03698 | ||
|
|
fab1f4e7a0 | ||
|
|
41eed484c1 | ||
|
|
7d18f9bdde | ||
|
|
3a48c3de7a | ||
|
|
d769a9936b | ||
|
|
1697cb3b1a | ||
|
|
62aa32a417 | ||
|
|
a0d0852838 | ||
|
|
2f479cae69 | ||
|
|
4820d57fa8 | ||
|
|
04e3b0b3c1 | ||
|
|
a7f78b9f68 | ||
|
|
f3d8eb4665 | ||
|
|
090f79b951 | ||
|
|
88c0dbf661 | ||
|
|
9e3822ceaf | ||
|
|
007b0a8fe6 | ||
|
|
7f0ebf8871 | ||
|
|
5414e94a1a | ||
|
|
461dee8657 | ||
|
|
297b6193fe | ||
|
|
4b74e40a5f | ||
|
|
5a9b08dec2 | ||
|
|
5e6f9f79a2 | ||
|
|
e2f93e6ae1 | ||
|
|
93314b59fb | ||
|
|
29269c6686 | ||
|
|
3c84b6e2f6 | ||
|
|
04fb708543 | ||
|
|
df302f277c | ||
|
|
5e63e663bb | ||
|
|
ca10cb2d37 | ||
|
|
c9854153f8 | ||
|
|
129e3c6326 | ||
|
|
66996711ae | ||
|
|
8fe37cea51 | ||
|
|
de64b6f267 | ||
|
|
9a9d9c7cc1 | ||
|
|
a191e9762a | ||
|
|
a7b35c6e22 | ||
|
|
5034346b67 | ||
|
|
661f64b902 | ||
|
|
bbc83f721c | ||
|
|
01f4541331 | ||
|
|
0e4a894f62 | ||
|
|
1c135a9b5b | ||
|
|
e65c85ce73 | ||
|
|
26b58991f9 | ||
|
|
8390df37ca | ||
|
|
371fc73f24 | ||
|
|
921dae5444 | ||
|
|
9b3abbec89 | ||
|
|
6935baba5b | ||
|
|
dec1e32f96 | ||
|
|
710c2ccfcd | ||
|
|
8e66e534ae | ||
|
|
0f5f30b993 | ||
|
|
b199f733f7 | ||
|
|
0cdcf3a3e0 | ||
|
|
8e09486e82 | ||
|
|
0c24b78573 | ||
|
|
1436be9699 | ||
|
|
0489ad7c62 | ||
|
|
c553570533 | ||
|
|
bda112297f | ||
|
|
331a4e4406 | ||
|
|
a9faf8ceff | ||
|
|
2866d1ace9 | ||
|
|
11a74f7a31 | ||
|
|
634a2035ee | ||
|
|
ffada9257d | ||
|
|
e09164e5b3 | ||
|
|
de1a5f3034 | ||
|
|
86e83faef3 | ||
|
|
9f06c8df76 | ||
|
|
6e511de7db | ||
|
|
e34aae9982 | ||
|
|
675b388b8e | ||
|
|
7d239fe4ac | ||
|
|
edd92caba1 | ||
|
|
5c3b4abf42 | ||
|
|
d3a3466b14 | ||
|
|
4399383781 | ||
|
|
bb383998bb | ||
|
|
ffeb174ca1 | ||
|
|
a90d74dde8 | ||
|
|
9d7fd79e76 | ||
|
|
6f29d234eb | ||
|
|
6f5517f602 | ||
|
|
cc43c745b2 | ||
|
|
db8d961b27 | ||
|
|
a0bdec2846 | ||
|
|
5bbcd386fa | ||
|
|
7657632024 | ||
|
|
ab29063a97 | ||
|
|
c06ef23eb1 | ||
|
|
7b2f7aa827 | ||
|
|
7113c10f4b | ||
|
|
14033946e5 | ||
|
|
6e0e056ca7 | ||
|
|
7aa4f0ccdb | ||
|
|
4b04450fa6 | ||
|
|
ad81560be5 | ||
|
|
5c26faa20e |
@@ -8,3 +8,12 @@ config.log
|
||||
config.status
|
||||
configure
|
||||
do-config.sh
|
||||
.cdtproject
|
||||
.project
|
||||
config.guess
|
||||
config.sub
|
||||
depcomp
|
||||
INSTALL
|
||||
install-sh
|
||||
missing
|
||||
mkinstalldirs
|
||||
|
||||
2
Doxyfile
2
Doxyfile
@@ -22,7 +22,7 @@ PROJECT_NAME = SimGear
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER = 0.3.5
|
||||
PROJECT_NUMBER = 0.3.7
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
EXTRA_DIST = \
|
||||
acinclude.m4 \
|
||||
autogen.sh \
|
||||
DoxygenMain.cxx
|
||||
DoxygenMain.cxx \
|
||||
README.MSVC \
|
||||
README.metakit \
|
||||
README.zlib \
|
||||
SimGear.dsp \
|
||||
SimGear.dsw
|
||||
@@ -11,7 +10,7 @@ EXTRA_DIST = \
|
||||
SUBDIRS = src-libs simgear
|
||||
|
||||
dist-hook:
|
||||
(cd $(top_srcdir); $(HOME)/projects/FlightGear-0.9/admin/am2dsp.pl)
|
||||
(cd $(top_srcdir); $(HOME)/Projects/FlightGear-0.9/admin/am2dsp.pl)
|
||||
|
||||
#
|
||||
# Rule to build RPM distribution package
|
||||
|
||||
25
NEWS
25
NEWS
@@ -1,3 +1,28 @@
|
||||
New in 0.3.7
|
||||
* October 12, 2004
|
||||
|
||||
* Add support for parsing xml from an in memory buffer, not just a file.
|
||||
* Don't reduce visibility for a "clear" cloud layer.
|
||||
* Add support for audio orientation (direction and cone) for internal
|
||||
view and tower view.
|
||||
* Add support for drawing from display lists rather than in immediate mode.
|
||||
This provides a big performance improvement on many systems.
|
||||
|
||||
|
||||
New in 0.3.6
|
||||
* July 29, 2004
|
||||
|
||||
* Better MinGW support
|
||||
* A bit better handling of OpenAL under Cygwin
|
||||
* Switched audio system from plib's "sl/sm" to OpenAL.
|
||||
* Add support for scaling an object based on distance. The scaling
|
||||
factor is determined by a lookup table based on distance.
|
||||
* Add a "flash" animation type.
|
||||
* Fix cloud positioning/animation bugs.
|
||||
* Fix an off-by-one error in props_io.cxx
|
||||
* Clip audio gain (volume) to 1.0
|
||||
|
||||
|
||||
New in 0.3.5
|
||||
* March 26, 2004
|
||||
|
||||
|
||||
49
SimGear.dsp
49
SimGear.dsp
@@ -1094,6 +1094,21 @@ SOURCE=.\simgear\scene\model\animation.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\custtrans.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgmodel"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgmodel"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\location.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
@@ -1139,6 +1154,21 @@ SOURCE=.\simgear\scene\model\modellib.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\personality.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgmodel"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgmodel"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\placement.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
@@ -2363,7 +2393,7 @@ SOURCE=.\simgear\serial\serial.cxx
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\sound\sound.cxx
|
||||
SOURCE=.\simgear\sound\sample_openal.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
@@ -2378,7 +2408,22 @@ SOURCE=.\simgear\sound\sound.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\sound\soundmgr.cxx
|
||||
SOURCE=.\simgear\sound\soundmgr_openal.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgsound"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgsound"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\sound\xmlsound.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
|
||||
31
configure.ac
31
configure.ac
@@ -10,7 +10,7 @@ dnl Require at least automake 2.52
|
||||
AC_PREREQ(2.52)
|
||||
|
||||
dnl Initialize the automake stuff
|
||||
AM_INIT_AUTOMAKE(SimGear, 0.3.5)
|
||||
AM_INIT_AUTOMAKE(SimGear, 0.3.7)
|
||||
|
||||
dnl Specify KAI C++ compiler and flags.
|
||||
dnl Borrowed with slight modification from blitz distribution.
|
||||
@@ -270,7 +270,35 @@ esac
|
||||
opengl_LIBS="$LIBS"
|
||||
LIBS="$base_LIBS"
|
||||
|
||||
dnl check for OpenAL libraries
|
||||
case "${host}" in
|
||||
*-*-cygwin* | *-*-mingw32*)
|
||||
dnl CygWin under Windoze.
|
||||
|
||||
AC_SEARCH_LIBS(alGenBuffers, openal32)
|
||||
AC_SEARCH_LIBS(alutInit, [ openal32 ALut ] )
|
||||
LIBS="$LIBS -lwinmm -ldsound -ldxguid -lole32"
|
||||
;;
|
||||
|
||||
*-apple-darwin*)
|
||||
dnl Mac OS X
|
||||
|
||||
LIBS="$LIBS -framework IOKit -framework OpenAL"
|
||||
;;
|
||||
|
||||
*)
|
||||
dnl default unix style machines
|
||||
|
||||
AC_SEARCH_LIBS(alGenBuffers, openal)
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
openal_LIBS="$LIBS"
|
||||
LIBS="$base_LIBS"
|
||||
|
||||
AC_SUBST(base_LIBS)
|
||||
AC_SUBST(openal_LIBS)
|
||||
AC_SUBST(opengl_LIBS)
|
||||
AC_SUBST(thread_LIBS)
|
||||
AC_SUBST(network_LIBS)
|
||||
@@ -389,6 +417,7 @@ AC_CONFIG_FILES([ \
|
||||
simgear/props/Makefile \
|
||||
simgear/route/Makefile \
|
||||
simgear/scene/Makefile \
|
||||
simgear/scene/fgsg/Makefile \
|
||||
simgear/scene/material/Makefile \
|
||||
simgear/scene/model/Makefile \
|
||||
simgear/scene/sky/Makefile \
|
||||
|
||||
@@ -257,14 +257,16 @@ public:
|
||||
// Informational methods.
|
||||
|
||||
/**
|
||||
* @return the lon of the lower left corner of this tile.
|
||||
* @return the lon of the lower left corner of
|
||||
* the 1x1 chunk containing this tile.
|
||||
*/
|
||||
inline int get_lon() const { return lon; }
|
||||
inline int get_chunk_lon() const { return lon; }
|
||||
|
||||
/**
|
||||
* @return the lat of the lower left corner of this tile.
|
||||
* @return the lat of the lower left corner of
|
||||
* the 1x1 chunk containing this tile.
|
||||
*/
|
||||
inline int get_lat() const { return lat; }
|
||||
inline int get_chunk_lat() const { return lat; }
|
||||
|
||||
/**
|
||||
* @return the x coord within the 1x1 degree chunk this tile.
|
||||
|
||||
@@ -149,13 +149,6 @@
|
||||
|
||||
#endif // __GNUC__
|
||||
|
||||
#if defined( __MINGW32__ )
|
||||
# define bcopy(from, to, n) memcpy(to, from, n)
|
||||
# define FG_MEM_COPY(to,from,n) memcpy(to, from, n)
|
||||
# define isnan _isnan
|
||||
# define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
/* KAI C++ */
|
||||
#if defined(__KCC)
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ public:
|
||||
|
||||
// calculate the center of a list of points, by taking the halfway
|
||||
// point between the min and max points.
|
||||
static Point3D calc_center( point_list& wgs84_nodes ) {
|
||||
Point3D sgCalcCenter( point_list& wgs84_nodes ) {
|
||||
Point3D p, min, max;
|
||||
|
||||
if ( wgs84_nodes.size() ) {
|
||||
@@ -1145,7 +1145,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
for ( i = start; i < end; ++i ) {
|
||||
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
||||
group_nodes.push_back( wgs84_nodes[ tris_v[i][j] ] );
|
||||
bs_center = calc_center( group_nodes );
|
||||
bs_center = sgCalcCenter( group_nodes );
|
||||
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
|
||||
}
|
||||
}
|
||||
@@ -1196,7 +1196,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
for ( i = start; i < end; ++i ) {
|
||||
for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
|
||||
group_nodes.push_back( wgs84_nodes[ strips_v[i][j] ] );
|
||||
bs_center = calc_center( group_nodes );
|
||||
bs_center = sgCalcCenter( group_nodes );
|
||||
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +221,16 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \relates SGBinObject
|
||||
* Calculate the center of a list of points, by taking the halfway
|
||||
* point between the min and max points.
|
||||
* @param wgs84_nodes list of points in wgs84 coordinates
|
||||
* @return center point
|
||||
*/
|
||||
Point3D sgCalcCenter( point_list& wgs84_nodes );
|
||||
|
||||
|
||||
/**
|
||||
* \relates SGBinObject
|
||||
* Calculate the bounding sphere of a set of nodes.
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include STL_IOSTREAM
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "sg_socket.hxx"
|
||||
|
||||
@@ -9,9 +9,17 @@
|
||||
* IDSIA, Lugano, Switzerland
|
||||
* http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf
|
||||
*
|
||||
* Base-2 exp, Laurent de Soras
|
||||
* http://www.musicdsp.org/archive.php?classid=5#106
|
||||
*
|
||||
* Fast log() Function, by Laurent de Soras:
|
||||
* http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-Fastlogfunction&forum=totd&id=-1
|
||||
*
|
||||
* Sin, Cos, Tan approximation
|
||||
* http://www.musicdsp.org/showArchiveComment.php?ArchiveID=115
|
||||
*
|
||||
* fast floating point power computation:
|
||||
* http://playstation2-linux.com/download/adam/power.c
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -21,6 +29,7 @@
|
||||
|
||||
|
||||
#include "fastmath.hxx"
|
||||
#define SGD_PI_2 1.57079632679489661923
|
||||
|
||||
/**
|
||||
* This function is on avarage 9 times faster than the system exp() function
|
||||
@@ -41,11 +50,76 @@ double fast_exp(double val) {
|
||||
const double a = 1048576/M_LN2;
|
||||
const double b_c = 1072632447; /* 1072693248 - 60801 */
|
||||
|
||||
_eco.n.i = a*val + b_c;
|
||||
_eco.n.i = (int)(a*val + b_c);
|
||||
|
||||
return _eco.d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Linear approx. between 2 integer values of val. Uses 32-bit integers.
|
||||
* Not very efficient but faster than exp()
|
||||
*/
|
||||
double fast_exp2( const double val )
|
||||
{
|
||||
int e;
|
||||
double ret;
|
||||
|
||||
if (val >= 0) {
|
||||
e = int (val);
|
||||
ret = val - (e - 1);
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
((*((int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
|
||||
#else
|
||||
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
|
||||
#endif
|
||||
} else {
|
||||
e = int (val + 1023);
|
||||
ret = val - (e - 1024);
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
((*((int *) &ret)) &= ~(2047 << 20)) += e << 20;
|
||||
#else
|
||||
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += e << 20;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
float _fast_log2(const float val)
|
||||
{
|
||||
float result, tmp;
|
||||
float mp = 0.346607f;
|
||||
|
||||
result = *(int*)&val;
|
||||
result *= 1.0/(1<<23);
|
||||
result = result - 127;
|
||||
|
||||
tmp = result - floor(result);
|
||||
tmp = (tmp - tmp*tmp) * mp;
|
||||
return tmp + result;
|
||||
}
|
||||
|
||||
float _fast_pow2(const float val)
|
||||
{
|
||||
float result;
|
||||
|
||||
float mp = 0.33971f;
|
||||
float tmp = val - floor(val);
|
||||
tmp = (tmp - tmp*tmp) * mp;
|
||||
|
||||
result = val + 127 - tmp;
|
||||
result *= (1<<23);
|
||||
*(int*)&result = (int)result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* While we're on the subject, someone might have use for these as well?
|
||||
@@ -63,3 +137,155 @@ void fast_BSR(float &x, register unsigned long shiftAmount) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fastpow(f,n) gives a rather *rough* estimate of a float number f to the
|
||||
* power of an integer number n (y=f^n). It is fast but result can be quite a
|
||||
* bit off, since we directly mess with the floating point exponent.
|
||||
*
|
||||
* Use it only for getting rough estimates of the values and where precision
|
||||
* is not that important.
|
||||
*/
|
||||
float fast_pow(const float f, const int n)
|
||||
{
|
||||
long *lp,l;
|
||||
lp=(long*)(&f);
|
||||
l=*lp;l-=0x3F800000l;l<<=(n-1);l+=0x3F800000l;
|
||||
*lp=l;
|
||||
return f;
|
||||
}
|
||||
|
||||
float fast_root(const float f, const int n)
|
||||
{
|
||||
long *lp,l;
|
||||
lp=(long*)(&f);
|
||||
l=*lp;l-=0x3F800000l;l>>=(n-1);l+=0x3F800000l;
|
||||
*lp=l;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Code for approximation of cos, sin, tan and inv sin, etc.
|
||||
* Surprisingly accurate and very usable.
|
||||
*
|
||||
* Domain:
|
||||
* Sin/Cos [0, pi/2]
|
||||
* Tan [0,pi/4]
|
||||
* InvSin/Cos [0, 1]
|
||||
* InvTan [-1, 1]
|
||||
*/
|
||||
|
||||
float fast_sin(const float val)
|
||||
{
|
||||
float fASqr = val*val;
|
||||
float fResult = -2.39e-08f;
|
||||
fResult *= fASqr;
|
||||
fResult += 2.7526e-06f;
|
||||
fResult *= fASqr;
|
||||
fResult -= 1.98409e-04f;
|
||||
fResult *= fASqr;
|
||||
fResult += 8.3333315e-03f;
|
||||
fResult *= fASqr;
|
||||
fResult -= 1.666666664e-01f;
|
||||
fResult *= fASqr;
|
||||
fResult += 1.0f;
|
||||
fResult *= val;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
float fast_cos(const float val)
|
||||
{
|
||||
float fASqr = val*val;
|
||||
float fResult = -2.605e-07f;
|
||||
fResult *= fASqr;
|
||||
fResult += 2.47609e-05f;
|
||||
fResult *= fASqr;
|
||||
fResult -= 1.3888397e-03f;
|
||||
fResult *= fASqr;
|
||||
fResult += 4.16666418e-02f;
|
||||
fResult *= fASqr;
|
||||
fResult -= 4.999999963e-01f;
|
||||
fResult *= fASqr;
|
||||
fResult += 1.0f;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
float fast_tan(const float val)
|
||||
{
|
||||
float fASqr = val*val;
|
||||
float fResult = 9.5168091e-03f;
|
||||
fResult *= fASqr;
|
||||
fResult += 2.900525e-03f;
|
||||
fResult *= fASqr;
|
||||
fResult += 2.45650893e-02f;
|
||||
fResult *= fASqr;
|
||||
fResult += 5.33740603e-02f;
|
||||
fResult *= fASqr;
|
||||
fResult += 1.333923995e-01f;
|
||||
fResult *= fASqr;
|
||||
fResult += 3.333314036e-01f;
|
||||
fResult *= fASqr;
|
||||
fResult += 1.0f;
|
||||
fResult *= val;
|
||||
|
||||
return fResult;
|
||||
|
||||
}
|
||||
|
||||
float fast_asin(float val)
|
||||
{
|
||||
float fRoot = sqrt(1.0f-val);
|
||||
float fResult = -0.0187293f;
|
||||
fResult *= val;
|
||||
fResult += 0.0742610f;
|
||||
fResult *= val;
|
||||
fResult -= 0.2121144f;
|
||||
fResult *= val;
|
||||
fResult += 1.5707288f;
|
||||
fResult = SGD_PI_2 - fRoot*fResult;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
float fast_acos(float val)
|
||||
{
|
||||
float fRoot = sqrt(1.0f-val);
|
||||
float fResult = -0.0187293f;
|
||||
fResult *= val;
|
||||
fResult += 0.0742610f;
|
||||
fResult *= val;
|
||||
fResult -= 0.2121144f;
|
||||
fResult *= val;
|
||||
fResult += 1.5707288f;
|
||||
fResult *= fRoot;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
float fast_atan(float val)
|
||||
{
|
||||
float fVSqr = val*val;
|
||||
float fResult = 0.0028662257f;
|
||||
fResult *= fVSqr;
|
||||
fResult -= 0.0161657367f;
|
||||
fResult *= fVSqr;
|
||||
fResult += 0.0429096138f;
|
||||
fResult *= fVSqr;
|
||||
fResult -= 0.0752896400f;
|
||||
fResult *= fVSqr;
|
||||
fResult += 0.1065626393f;
|
||||
fResult *= fVSqr;
|
||||
fResult -= 0.1420889944f;
|
||||
fResult *= fVSqr;
|
||||
fResult += 0.1999355085f;
|
||||
fResult *= fVSqr;
|
||||
fResult -= 0.3333314528f;
|
||||
fResult *= fVSqr;
|
||||
fResult += 1.0f;
|
||||
fResult *= val;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
@@ -32,24 +32,41 @@
|
||||
|
||||
|
||||
double fast_exp(double val);
|
||||
double fast_exp2(const double val);
|
||||
|
||||
float fast_pow(const float val1, const float val2);
|
||||
float fast_log2(const float cal);
|
||||
float fast_root(const float f, const int n);
|
||||
|
||||
float _fast_pow2(const float cal);
|
||||
float _fast_log2(const float val);
|
||||
|
||||
float fast_sin(const float val);
|
||||
float fast_cos(const float val);
|
||||
float fast_tan(const float val);
|
||||
float fast_asin(const float val);
|
||||
float fast_acos(const float val);
|
||||
float fast_atan(const float val);
|
||||
|
||||
void fast_BSL(float &x, register unsigned long shiftAmount);
|
||||
void fast_BSR(float &x, register unsigned long shiftAmount);
|
||||
|
||||
|
||||
inline float fast_log2 (float val)
|
||||
{
|
||||
int * const exp_ptr = reinterpret_cast <int *> (&val);
|
||||
int x = *exp_ptr;
|
||||
const int log_2 = ((x >> 23) & 255) - 128;
|
||||
x &= ~(255 << 23);
|
||||
x += 127 << 23;
|
||||
*exp_ptr = x;
|
||||
int * const exp_ptr = reinterpret_cast <int *> (&val);
|
||||
int x = *exp_ptr;
|
||||
const int log_2 = ((x >> 23) & 255) - 128;
|
||||
x &= ~(255 << 23);
|
||||
x += 127 << 23;
|
||||
*exp_ptr = x;
|
||||
|
||||
val = ((-1.0f/3) * val + 2) * val - 2.0f/3; // (1)
|
||||
val = ((-1.0f/3) * val + 2) * val - 2.0f/3; // (1)
|
||||
|
||||
return (val + log_2);
|
||||
return (val + log_2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is about 3 times faster than the system log() function
|
||||
* and has an error of about 0.01%
|
||||
@@ -65,5 +82,36 @@ inline float fast_log10 (const float &val)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is about twice as fast as the system pow(x,y) function
|
||||
*/
|
||||
inline float fast_pow(const float val1, const float val2)
|
||||
{
|
||||
return _fast_pow2(val2 * _fast_log2(val1));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Haven't seen this elsewhere, probably because it is too obvious?
|
||||
* Anyway, these functions are intended for 32-bit floating point numbers
|
||||
* only and should work a bit faster than the regular ones.
|
||||
*/
|
||||
inline float fast_abs(float f)
|
||||
{
|
||||
int i=((*(int*)&f)&0x7fffffff);
|
||||
return (*(float*)&i);
|
||||
}
|
||||
|
||||
inline float fast_neg(float f)
|
||||
{
|
||||
int i=((*(int*)&f)^0x80000000);
|
||||
return (*(float*)&i);
|
||||
}
|
||||
|
||||
inline int fast_sgn(float f)
|
||||
{
|
||||
return 1+(((*(int*)&f)>>31)<<1);
|
||||
}
|
||||
|
||||
#endif // !_SG_FMATH_HXX
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ static double seaLevelRadius(double r, double z)
|
||||
// starts making very poor guesses as to latitude. As altitude
|
||||
// approaches infinity, it should be guessing with geocentric
|
||||
// coordinates, not "local geodetic up" ones.
|
||||
void sgCartToGeod(double* xyz, double* lat, double* lon, double* alt)
|
||||
void sgCartToGeod(const double* xyz, double* lat, double* lon, double* alt)
|
||||
{
|
||||
// The error is expressed as a radian angle, and we want accuracy
|
||||
// to 1 part in 2^50 (an IEEE double has between 51 and 52
|
||||
|
||||
@@ -42,7 +42,7 @@ void sgGeodToGeoc(double lat_geod, double alt,
|
||||
* @param lon (out) Longitude, in radians
|
||||
* @param alt (out) Altitude, in meters above the WGS84 ellipsoid
|
||||
*/
|
||||
void sgCartToGeod(double* xyz, double* lat, double* lon, double* alt);
|
||||
void sgCartToGeod(const double* xyz, double* lat, double* lon, double* alt);
|
||||
|
||||
/**
|
||||
* Convert a cartesian point to a geodetic lat/lon/altitude.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -43,7 +43,7 @@ static const char sgDirPathSep = '/';
|
||||
static const char sgDirPathSepBad = '\\';
|
||||
#endif
|
||||
|
||||
#if defined( WIN32 )
|
||||
#if defined( WIN32 ) && !defined(__CYGWIN__)
|
||||
static const char sgSearchPathSep = ';';
|
||||
#else
|
||||
static const char sgSearchPathSep = ':';
|
||||
@@ -112,6 +112,11 @@ void SGPath::append( const string& p ) {
|
||||
fix();
|
||||
}
|
||||
|
||||
//add a new path component to the existing path string
|
||||
void SGPath::add( const string& p ) {
|
||||
append( sgSearchPathSep+p );
|
||||
}
|
||||
|
||||
|
||||
// concatenate a string to the end of the path without inserting a
|
||||
// path separator
|
||||
@@ -149,7 +154,7 @@ string SGPath::dir() const {
|
||||
// get the base part of the path (everything but the extension.)
|
||||
string SGPath::base() const {
|
||||
int index = path.rfind(".");
|
||||
if (index >= 0) {
|
||||
if ((index >= 0) && (path.find("/", index) == string::npos)) {
|
||||
return path.substr(0, index);
|
||||
} else {
|
||||
return "";
|
||||
@@ -157,9 +162,11 @@ string SGPath::base() const {
|
||||
}
|
||||
|
||||
// get the extention (everything after the final ".")
|
||||
// but make sure no "/" follows the "." character (otherwise it
|
||||
// is has to be a directory name containing a ".").
|
||||
string SGPath::extension() const {
|
||||
int index = path.rfind(".");
|
||||
if (index >= 0) {
|
||||
if ((index >= 0) && (path.find("/", index) == string::npos)) {
|
||||
return path.substr(index + 1);
|
||||
} else {
|
||||
return "";
|
||||
|
||||
@@ -79,6 +79,12 @@ public:
|
||||
* @param p additional path component */
|
||||
void append( const string& p );
|
||||
|
||||
/**
|
||||
* Append a new piece to the existing path. Inserts a search path
|
||||
* separator to the existing path and the new patch component.
|
||||
* @param p additional path component */
|
||||
void add( const string& p );
|
||||
|
||||
/**
|
||||
* Concatenate a string to the end of the path without inserting a
|
||||
* path separator.
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include STL_STRING
|
||||
|
||||
#include <ctype.h> // isspace()
|
||||
|
||||
#ifdef SG_HAVE_STD_INCLUDES
|
||||
|
||||
@@ -561,7 +561,7 @@ public:
|
||||
* Property value types.
|
||||
*/
|
||||
enum Type {
|
||||
NONE,
|
||||
NONE = 0,
|
||||
ALIAS,
|
||||
BOOL,
|
||||
INT,
|
||||
|
||||
@@ -133,7 +133,6 @@ checkFlag (const char * flag, bool defaultState = true)
|
||||
void
|
||||
PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
||||
{
|
||||
State &st = state();
|
||||
const char * attval;
|
||||
|
||||
if (_level == 0) {
|
||||
@@ -160,6 +159,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
||||
}
|
||||
|
||||
else {
|
||||
State &st = state();
|
||||
// Get the index.
|
||||
attval = atts.getValue("n");
|
||||
int index = 0;
|
||||
@@ -322,6 +322,23 @@ readProperties (const string &file, SGPropertyNode * start_node)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read properties from an in-memory buffer.
|
||||
*
|
||||
* @param buf A character buffer containing the xml data.
|
||||
* @param size The size/length of the buffer in bytes
|
||||
* @param start_node The root node for reading properties.
|
||||
* @return true if the read succeeded, false otherwise.
|
||||
*/
|
||||
void readProperties (const char *buf, const int size,
|
||||
SGPropertyNode * start_node)
|
||||
{
|
||||
PropsVisitor visitor(start_node, "");
|
||||
readXML(buf, size, visitor);
|
||||
if (visitor.hasException())
|
||||
throw visitor.getException();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Property list writer.
|
||||
|
||||
@@ -41,6 +41,13 @@ void readProperties (istream &input, SGPropertyNode * start_node,
|
||||
void readProperties (const string &file, SGPropertyNode * start_node);
|
||||
|
||||
|
||||
/**
|
||||
* Read properties from an in-memory buffer.
|
||||
*/
|
||||
void readProperties (const char *buf, const int size,
|
||||
SGPropertyNode * start_node);
|
||||
|
||||
|
||||
/**
|
||||
* Write properties to an XML output stream.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
includedir = @includedir@/scene
|
||||
|
||||
SUBDIRS = material model sky tgdb
|
||||
SUBDIRS = fgsg material model sky tgdb
|
||||
|
||||
# lib_LIBRARIES = libsgscene.a
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
||||
{
|
||||
// Gather the path(s) to the texture(s)
|
||||
vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
|
||||
for (int i = 0; i < textures.size(); i++)
|
||||
for (unsigned int i = 0; i < textures.size(); i++)
|
||||
{
|
||||
string tname = textures[i]->getStringValue();
|
||||
if (tname == "") {
|
||||
@@ -227,7 +227,7 @@ SGMaterial::build_ssg_state( bool defer_tex_load )
|
||||
{
|
||||
GLenum shade_model = GL_SMOOTH;
|
||||
|
||||
for (int i = 0; i < _status.size(); i++)
|
||||
for (unsigned int i = 0; i < _status.size(); i++)
|
||||
{
|
||||
ssgSimpleState *state = new ssgSimpleState();
|
||||
state->ref();
|
||||
|
||||
@@ -217,7 +217,7 @@ private:
|
||||
vector<_internal_state> _status;
|
||||
|
||||
// Round-robin counter
|
||||
int _current_ptr;
|
||||
unsigned int _current_ptr;
|
||||
|
||||
// texture size
|
||||
double xsize, ysize;
|
||||
|
||||
@@ -174,56 +174,6 @@ static int gen_taxiway_dir_light_map( int r, int g, int b, int alpha ) {
|
||||
}
|
||||
|
||||
|
||||
// generate the directional vasi light environment texture map
|
||||
static int gen_vasi_light_map_old() {
|
||||
const int env_tex_res = 256;
|
||||
int half_res = env_tex_res / 2;
|
||||
|
||||
static unsigned char env_map[env_tex_res][env_tex_res][4];
|
||||
GLuint tex_name;
|
||||
|
||||
for ( int i = 0; i < env_tex_res; ++i ) {
|
||||
for ( int j = 0; j < env_tex_res; ++j ) {
|
||||
double x = (i - half_res) / (double)half_res;
|
||||
double y = (j - half_res) / (double)half_res;
|
||||
double dist = sqrt(x*x + y*y);
|
||||
if ( dist > 1.0 ) { dist = 1.0; }
|
||||
double bright = cos( dist * SGD_PI_2 );
|
||||
|
||||
// top half white, bottom half red
|
||||
env_map[i][j][0] = 255;
|
||||
if ( i > half_res ) {
|
||||
// white
|
||||
env_map[i][j][1] = 255;
|
||||
env_map[i][j][2] = 255;
|
||||
} else if ( i == half_res - 1 || i == half_res ) {
|
||||
// pink
|
||||
env_map[i][j][1] = 127;
|
||||
env_map[i][j][2] = 127;
|
||||
} else {
|
||||
// red
|
||||
env_map[i][j][1] = 0;
|
||||
env_map[i][j][2] = 0;
|
||||
}
|
||||
env_map[i][j][3] = (int)(bright * 255);
|
||||
}
|
||||
}
|
||||
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
glGenTextures( 1, &tex_name );
|
||||
glBindTexture( GL_TEXTURE_2D, tex_name );
|
||||
|
||||
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_LINEAR );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
|
||||
|
||||
return tex_name;
|
||||
}
|
||||
|
||||
|
||||
// Load a library of material properties
|
||||
bool SGMaterialLib::load( const string &fg_root, const string& mpath ) {
|
||||
|
||||
|
||||
@@ -126,6 +126,22 @@ SGMatModel::get_model_count( SGModelLib *modellib,
|
||||
return _models.size();
|
||||
}
|
||||
|
||||
static void
|
||||
setAlphaClampToBranch( ssgBranch *b, float clamp )
|
||||
{
|
||||
int nb = b->getNumKids();
|
||||
for (int i = 0; i<nb; i++) {
|
||||
ssgEntity *e = b->getKid(i);
|
||||
if (e->isAKindOf(ssgTypeLeaf())) {
|
||||
ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
|
||||
s->enable( GL_ALPHA_TEST );
|
||||
s->setAlphaClamp( clamp );
|
||||
} else if (e->isAKindOf(ssgTypeBranch())) {
|
||||
setAlphaClampToBranch( (ssgBranch*)e, clamp );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
SGMatModel::load_models ( SGModelLib *modellib,
|
||||
const string &fg_root,
|
||||
@@ -147,6 +163,14 @@ SGMatModel::load_models ( SGModelLib *modellib,
|
||||
lod->ref();
|
||||
lod->setRanges(ranges, 2);
|
||||
if (_heading_type == HEADING_BILLBOARD) {
|
||||
// if the model is a billboard, it is likely :
|
||||
// 1. a branch with only leaves,
|
||||
// 2. a tree or a non rectangular shape faked by transparency
|
||||
// We add alpha clamp then
|
||||
if ( entity->isAKindOf(ssgTypeBranch()) ) {
|
||||
ssgBranch *b = (ssgBranch *)entity;
|
||||
setAlphaClampToBranch( b, 0.01f );
|
||||
}
|
||||
ssgCutout * cutout = new ssgCutout(false);
|
||||
cutout->addKid(entity);
|
||||
lod->addKid(cutout);
|
||||
|
||||
@@ -6,16 +6,20 @@ noinst_HEADERS =
|
||||
|
||||
include_HEADERS = \
|
||||
animation.hxx \
|
||||
custtrans.hxx \
|
||||
location.hxx \
|
||||
model.hxx \
|
||||
modellib.hxx \
|
||||
personality.hxx \
|
||||
placement.hxx
|
||||
|
||||
libsgmodel_a_SOURCES = \
|
||||
animation.cxx \
|
||||
custtrans.cxx \
|
||||
location.cxx \
|
||||
model.cxx \
|
||||
modellib.cxx \
|
||||
personality.cxx \
|
||||
placement.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
#include <simgear/math/interpolater.hxx>
|
||||
#include <simgear/props/condition.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
|
||||
#include "animation.hxx"
|
||||
|
||||
#include "custtrans.hxx"
|
||||
#include "personality.hxx"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -174,11 +176,17 @@ read_interpolation_table (SGPropertyNode_ptr props)
|
||||
|
||||
// Initialize the static data member
|
||||
double SGAnimation::sim_time_sec = 0.0;
|
||||
SGPersonalityBranch *SGAnimation::current_object = 0;
|
||||
|
||||
SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
|
||||
: _branch(branch)
|
||||
{
|
||||
_branch->setName(props->getStringValue("name", 0));
|
||||
if ( props->getBoolValue( "enable-hot", true ) ) {
|
||||
_branch->setTraversalMaskBits( SSGTRAV_HOT );
|
||||
} else {
|
||||
_branch->clrTraversalMaskBits( SSGTRAV_HOT );
|
||||
}
|
||||
}
|
||||
|
||||
SGAnimation::~SGAnimation ()
|
||||
@@ -190,8 +198,14 @@ SGAnimation::init ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGAnimation::update()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
SGAnimation::restore()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -219,12 +233,16 @@ SGNullAnimation::~SGNullAnimation ()
|
||||
SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props)
|
||||
: SGAnimation(props, new ssgRangeSelector),
|
||||
_min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0)
|
||||
|
||||
_min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0),
|
||||
_condition(0)
|
||||
{
|
||||
SGPropertyNode_ptr node = props->getChild("condition");
|
||||
if (node != 0)
|
||||
_condition = sgReadCondition(prop_root, node);
|
||||
|
||||
float ranges[2];
|
||||
|
||||
SGPropertyNode_ptr node = props->getChild( "min-factor" );
|
||||
node = props->getChild( "min-factor" );
|
||||
if (node != 0) {
|
||||
_min_factor = props->getFloatValue("min-factor", 1.0);
|
||||
}
|
||||
@@ -255,26 +273,27 @@ SGRangeAnimation::~SGRangeAnimation ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGRangeAnimation::update()
|
||||
{
|
||||
float ranges[2];
|
||||
bool upd = false;
|
||||
float ranges[2];
|
||||
if ( _condition == 0 || _condition->test() ) {
|
||||
if (_min_prop != 0) {
|
||||
ranges[0] = _min_prop->getFloatValue() * _min_factor;
|
||||
upd = true;
|
||||
ranges[0] = _min_prop->getFloatValue() * _min_factor;
|
||||
} else {
|
||||
ranges[0] = _min * _min_factor;
|
||||
ranges[0] = _min * _min_factor;
|
||||
}
|
||||
if (_max_prop != 0) {
|
||||
ranges[1] = _max_prop->getFloatValue() * _max_factor;
|
||||
upd = true;
|
||||
ranges[1] = _max_prop->getFloatValue() * _max_factor;
|
||||
} else {
|
||||
ranges[1] = _max * _max_factor;
|
||||
}
|
||||
if (upd) {
|
||||
((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
|
||||
ranges[1] = _max * _max_factor;
|
||||
}
|
||||
} else {
|
||||
ranges[0] = 0.f;
|
||||
ranges[1] = 1000000000.f;
|
||||
}
|
||||
((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -313,13 +332,14 @@ SGSelectAnimation::~SGSelectAnimation ()
|
||||
delete _condition;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGSelectAnimation::update()
|
||||
{
|
||||
if (_condition != 0 && _condition->test())
|
||||
((ssgSelector *)_branch)->select(0xffff);
|
||||
else
|
||||
((ssgSelector *)_branch)->select(0x0000);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -335,8 +355,13 @@ SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
|
||||
_prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
|
||||
_factor(props->getDoubleValue("factor", 1.0)),
|
||||
_position_deg(props->getDoubleValue("starting-position-deg", 0)),
|
||||
_last_time_sec( sim_time_sec )
|
||||
_last_time_sec( sim_time_sec ),
|
||||
_condition(0)
|
||||
{
|
||||
SGPropertyNode_ptr node = props->getChild("condition");
|
||||
if (node != 0)
|
||||
_condition = sgReadCondition(prop_root, node);
|
||||
|
||||
_center[0] = 0;
|
||||
_center[1] = 0;
|
||||
_center[2] = 0;
|
||||
@@ -372,20 +397,23 @@ SGSpinAnimation::~SGSpinAnimation ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGSpinAnimation::update()
|
||||
{
|
||||
double dt = sim_time_sec - _last_time_sec;
|
||||
_last_time_sec = sim_time_sec;
|
||||
if ( _condition == 0 || _condition->test() ) {
|
||||
double dt = sim_time_sec - _last_time_sec;
|
||||
_last_time_sec = sim_time_sec;
|
||||
|
||||
float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
|
||||
_position_deg += (dt * velocity_rpms * 360);
|
||||
while (_position_deg < 0)
|
||||
_position_deg += 360.0;
|
||||
while (_position_deg >= 360.0)
|
||||
_position_deg -= 360.0;
|
||||
set_rotation(_matrix, _position_deg, _center, _axis);
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
|
||||
_position_deg += (dt * velocity_rpms * 360);
|
||||
while (_position_deg < 0)
|
||||
_position_deg += 360.0;
|
||||
while (_position_deg >= 360.0)
|
||||
_position_deg -= 360.0;
|
||||
set_rotation(_matrix, _position_deg, _center, _axis);
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -396,10 +424,28 @@ SGSpinAnimation::update()
|
||||
|
||||
SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
|
||||
: SGAnimation(props, new ssgSelector),
|
||||
_use_personality( props->getBoolValue("use-personality",false) ),
|
||||
_duration_sec(props->getDoubleValue("duration-sec", 1.0)),
|
||||
_last_time_sec(0),
|
||||
_step(-1)
|
||||
_last_time_sec( sim_time_sec ),
|
||||
_total_duration_sec( 0 ),
|
||||
_step( 0 )
|
||||
|
||||
{
|
||||
vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
|
||||
size_t nb = nodes.size();
|
||||
for ( size_t i = 0; i < nb; i++ ) {
|
||||
size_t ind = nodes[ i ]->getIndex();
|
||||
while ( ind >= _branch_duration_specs.size() ) {
|
||||
_branch_duration_specs.push_back( DurationSpec( _duration_sec ) );
|
||||
}
|
||||
SGPropertyNode_ptr rNode = nodes[ i ]->getChild("random");
|
||||
if ( rNode == 0 ) {
|
||||
_branch_duration_specs[ ind ] = DurationSpec( nodes[ i ]->getDoubleValue() );
|
||||
} else {
|
||||
_branch_duration_specs[ ind ] = DurationSpec( rNode->getDoubleValue( "min", 0.0 ),
|
||||
rNode->getDoubleValue( "max", 1.0 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SGTimedAnimation::~SGTimedAnimation ()
|
||||
@@ -407,15 +453,91 @@ SGTimedAnimation::~SGTimedAnimation ()
|
||||
}
|
||||
|
||||
void
|
||||
SGTimedAnimation::init()
|
||||
{
|
||||
if ( !_use_personality ) {
|
||||
for ( int i = 0; i < getBranch()->getNumKids(); i++ ) {
|
||||
double v;
|
||||
if ( i < (int)_branch_duration_specs.size() ) {
|
||||
DurationSpec &sp = _branch_duration_specs[ i ];
|
||||
v = sp._min + sg_random() * ( sp._max - sp._min );
|
||||
} else {
|
||||
v = _duration_sec;
|
||||
}
|
||||
_branch_duration_sec.push_back( v );
|
||||
_total_duration_sec += v;
|
||||
}
|
||||
// Sanity check : total duration shouldn't equal zero
|
||||
if ( _total_duration_sec < 0.01 ) {
|
||||
_total_duration_sec = 0.01;
|
||||
}
|
||||
}
|
||||
((ssgSelector *)getBranch())->selectStep(_step);
|
||||
}
|
||||
|
||||
int
|
||||
SGTimedAnimation::update()
|
||||
{
|
||||
if ((sim_time_sec - _last_time_sec) >= _duration_sec) {
|
||||
_last_time_sec = sim_time_sec;
|
||||
_step++;
|
||||
if (_step >= getBranch()->getNumKids())
|
||||
_step = 0;
|
||||
((ssgSelector *)getBranch())->selectStep(_step);
|
||||
if ( _use_personality ) {
|
||||
SGPersonalityBranch *key = current_object;
|
||||
if ( !key->getIntValue( this, INIT ) ) {
|
||||
double total = 0;
|
||||
double offset = 1.0;
|
||||
for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
|
||||
DurationSpec &sp = _branch_duration_specs[ i ];
|
||||
double v = sp._min + sg_random() * ( sp._max - sp._min );
|
||||
key->setDoubleValue( v, this, BRANCH_DURATION_SEC, i );
|
||||
if ( i == 0 )
|
||||
offset = v;
|
||||
total += v;
|
||||
}
|
||||
// Sanity check : total duration shouldn't equal zero
|
||||
if ( total < 0.01 ) {
|
||||
total = 0.01;
|
||||
}
|
||||
offset *= sg_random();
|
||||
key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC );
|
||||
key->setDoubleValue( total, this, TOTAL_DURATION_SEC );
|
||||
key->setIntValue( 0, this, STEP );
|
||||
key->setIntValue( 1, this, INIT );
|
||||
}
|
||||
|
||||
_step = key->getIntValue( this, STEP );
|
||||
_last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC );
|
||||
_total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC );
|
||||
while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
|
||||
_last_time_sec += _total_duration_sec;
|
||||
}
|
||||
double duration = _duration_sec;
|
||||
if ( _step < (int)_branch_duration_specs.size() ) {
|
||||
duration = key->getDoubleValue( this, BRANCH_DURATION_SEC, _step );
|
||||
}
|
||||
if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
|
||||
_last_time_sec += duration;
|
||||
_step += 1;
|
||||
if ( _step >= getBranch()->getNumKids() )
|
||||
_step = 0;
|
||||
}
|
||||
((ssgSelector *)getBranch())->selectStep( _step );
|
||||
key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC );
|
||||
key->setIntValue( _step, this, STEP );
|
||||
} else {
|
||||
while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
|
||||
_last_time_sec += _total_duration_sec;
|
||||
}
|
||||
double duration = _duration_sec;
|
||||
if ( _step < (int)_branch_duration_sec.size() ) {
|
||||
duration = _branch_duration_sec[ _step ];
|
||||
}
|
||||
if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
|
||||
_last_time_sec += duration;
|
||||
_step += 1;
|
||||
if ( _step >= getBranch()->getNumKids() )
|
||||
_step = 0;
|
||||
((ssgSelector *)getBranch())->selectStep( _step );
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -435,8 +557,13 @@ SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
|
||||
_min_deg(props->getDoubleValue("min-deg")),
|
||||
_has_max(props->hasValue("max-deg")),
|
||||
_max_deg(props->getDoubleValue("max-deg")),
|
||||
_position_deg(props->getDoubleValue("starting-position-deg", 0))
|
||||
_position_deg(props->getDoubleValue("starting-position-deg", 0)),
|
||||
_condition(0)
|
||||
{
|
||||
SGPropertyNode_ptr node = props->getChild("condition");
|
||||
if (node != 0)
|
||||
_condition = sgReadCondition(prop_root, node);
|
||||
|
||||
_center[0] = 0;
|
||||
_center[1] = 0;
|
||||
_center[2] = 0;
|
||||
@@ -473,20 +600,23 @@ SGRotateAnimation::~SGRotateAnimation ()
|
||||
delete _table;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGRotateAnimation::update()
|
||||
{
|
||||
if (_table == 0) {
|
||||
_position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
|
||||
if (_has_min && _position_deg < _min_deg)
|
||||
_position_deg = _min_deg;
|
||||
if (_has_max && _position_deg > _max_deg)
|
||||
_position_deg = _max_deg;
|
||||
} else {
|
||||
_position_deg = _table->interpolate(_prop->getDoubleValue());
|
||||
if (_condition == 0 || _condition->test()) {
|
||||
if (_table == 0) {
|
||||
_position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
|
||||
if (_has_min && _position_deg < _min_deg)
|
||||
_position_deg = _min_deg;
|
||||
if (_has_max && _position_deg > _max_deg)
|
||||
_position_deg = _max_deg;
|
||||
} else {
|
||||
_position_deg = _table->interpolate(_prop->getDoubleValue());
|
||||
}
|
||||
set_rotation(_matrix, _position_deg, _center, _axis);
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
}
|
||||
set_rotation(_matrix, _position_deg, _center, _axis);
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -498,14 +628,14 @@ SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props )
|
||||
: SGAnimation(props, new ssgTransform),
|
||||
_prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
|
||||
_table(read_interpolation_table(props)),
|
||||
_prev_value(1.0),
|
||||
_offset(props->getDoubleValue("offset", 0.0)),
|
||||
_factor(props->getDoubleValue("factor", 1.0)),
|
||||
_table(read_interpolation_table(props)),
|
||||
_has_min(props->hasValue("min")),
|
||||
_min(props->getDoubleValue("min", 0.0)),
|
||||
_has_max(props->hasValue("max")),
|
||||
_max(props->getDoubleValue("max", 1.0)),
|
||||
_prev_value(1.0)
|
||||
_max(props->getDoubleValue("max", 1.0))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -514,7 +644,7 @@ SGBlendAnimation::~SGBlendAnimation ()
|
||||
delete _table;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGBlendAnimation::update()
|
||||
{
|
||||
double _blend;
|
||||
@@ -534,6 +664,7 @@ SGBlendAnimation::update()
|
||||
_prev_value = _blend;
|
||||
change_alpha( _branch, _blend );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -553,8 +684,13 @@ SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
|
||||
_min_m(props->getDoubleValue("min-m")),
|
||||
_has_max(props->hasValue("max-m")),
|
||||
_max_m(props->getDoubleValue("max-m")),
|
||||
_position_m(props->getDoubleValue("starting-position-m", 0))
|
||||
_position_m(props->getDoubleValue("starting-position-m", 0)),
|
||||
_condition(0)
|
||||
{
|
||||
SGPropertyNode_ptr node = props->getChild("condition");
|
||||
if (node != 0)
|
||||
_condition = sgReadCondition(prop_root, node);
|
||||
|
||||
_axis[0] = props->getFloatValue("axis/x", 0);
|
||||
_axis[1] = props->getFloatValue("axis/y", 0);
|
||||
_axis[2] = props->getFloatValue("axis/z", 0);
|
||||
@@ -566,20 +702,23 @@ SGTranslateAnimation::~SGTranslateAnimation ()
|
||||
delete _table;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGTranslateAnimation::update()
|
||||
{
|
||||
if (_table == 0) {
|
||||
_position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
|
||||
if (_has_min && _position_m < _min_m)
|
||||
_position_m = _min_m;
|
||||
if (_has_max && _position_m > _max_m)
|
||||
_position_m = _max_m;
|
||||
} else {
|
||||
_position_m = _table->interpolate(_prop->getDoubleValue());
|
||||
if (_condition == 0 || _condition->test()) {
|
||||
if (_table == 0) {
|
||||
_position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
|
||||
if (_has_min && _position_m < _min_m)
|
||||
_position_m = _min_m;
|
||||
if (_has_max && _position_m > _max_m)
|
||||
_position_m = _max_m;
|
||||
} else {
|
||||
_position_m = _table->interpolate(_prop->getDoubleValue());
|
||||
}
|
||||
set_translation(_matrix, _position_m, _axis);
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
}
|
||||
set_translation(_matrix, _position_m, _axis);
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -619,7 +758,7 @@ SGScaleAnimation::~SGScaleAnimation ()
|
||||
delete _table;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGScaleAnimation::update()
|
||||
{
|
||||
if (_table == 0) {
|
||||
@@ -654,6 +793,7 @@ SGScaleAnimation::update()
|
||||
|
||||
set_scale(_matrix, _x_scale, _y_scale, _z_scale );
|
||||
((ssgTransform *)_branch)->setTransform(_matrix);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -688,7 +828,7 @@ SGTexRotateAnimation::~SGTexRotateAnimation ()
|
||||
delete _table;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGTexRotateAnimation::update()
|
||||
{
|
||||
if (_table == 0) {
|
||||
@@ -702,6 +842,7 @@ SGTexRotateAnimation::update()
|
||||
}
|
||||
set_rotation(_matrix, _position_deg, _center, _axis);
|
||||
((ssgTexTrans *)_branch)->setTransform(_matrix);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -735,7 +876,7 @@ SGTexTranslateAnimation::~SGTexTranslateAnimation ()
|
||||
delete _table;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGTexTranslateAnimation::update()
|
||||
{
|
||||
if (_table == 0) {
|
||||
@@ -749,6 +890,7 @@ SGTexTranslateAnimation::update()
|
||||
}
|
||||
set_translation(_matrix, _position, _axis);
|
||||
((ssgTexTrans *)_branch)->setTransform(_matrix);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -821,11 +963,10 @@ SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
|
||||
|
||||
SGTexMultipleAnimation::~SGTexMultipleAnimation ()
|
||||
{
|
||||
// delete _table;
|
||||
delete _transform;
|
||||
delete [] _transform;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
SGTexMultipleAnimation::update()
|
||||
{
|
||||
int i;
|
||||
@@ -866,6 +1007,7 @@ SGTexMultipleAnimation::update()
|
||||
}
|
||||
}
|
||||
((ssgTexTrans *)_branch)->setTransform(tmatrix);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -904,4 +1046,135 @@ void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGFlashAnimation
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
|
||||
: SGAnimation( props, new SGCustomTransform )
|
||||
{
|
||||
_axis[0] = props->getFloatValue("axis/x", 0);
|
||||
_axis[1] = props->getFloatValue("axis/y", 0);
|
||||
_axis[2] = props->getFloatValue("axis/z", 1);
|
||||
|
||||
_center[0] = props->getFloatValue("center/x-m", 0);
|
||||
_center[1] = props->getFloatValue("center/y-m", 0);
|
||||
_center[2] = props->getFloatValue("center/z-m", 0);
|
||||
|
||||
_offset = props->getFloatValue("offset", 0.0);
|
||||
_factor = props->getFloatValue("factor", 1.0);
|
||||
_power = props->getFloatValue("power", 1.0);
|
||||
_two_sides = props->getBoolValue("two-sides", false);
|
||||
|
||||
_min_v = props->getFloatValue("min", 0.0);
|
||||
_max_v = props->getFloatValue("max", 1.0);
|
||||
|
||||
((SGCustomTransform *)_branch)->setTransCallback( &SGFlashAnimation::flashCallback, this );
|
||||
}
|
||||
|
||||
SGFlashAnimation::~SGFlashAnimation()
|
||||
{
|
||||
}
|
||||
|
||||
void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
|
||||
{
|
||||
((SGFlashAnimation *)d)->flashCallback( r, f, m );
|
||||
}
|
||||
|
||||
void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
|
||||
{
|
||||
sgVec3 transformed_axis;
|
||||
sgXformVec3( transformed_axis, _axis, m );
|
||||
sgNormalizeVec3( transformed_axis );
|
||||
|
||||
sgVec3 view;
|
||||
sgFullXformPnt3( view, _center, m );
|
||||
sgNormalizeVec3( view );
|
||||
|
||||
float cos_angle = -sgScalarProductVec3( transformed_axis, view );
|
||||
float scale_factor = 0.f;
|
||||
if ( _two_sides && cos_angle < 0 )
|
||||
scale_factor = _factor * (float)pow( -cos_angle, _power ) + _offset;
|
||||
else if ( cos_angle > 0 )
|
||||
scale_factor = _factor * (float)pow( cos_angle, _power ) + _offset;
|
||||
|
||||
if ( scale_factor < _min_v )
|
||||
scale_factor = _min_v;
|
||||
if ( scale_factor > _max_v )
|
||||
scale_factor = _max_v;
|
||||
|
||||
sgMat4 transform;
|
||||
sgMakeIdentMat4( transform );
|
||||
transform[0][0] = scale_factor;
|
||||
transform[1][1] = scale_factor;
|
||||
transform[2][2] = scale_factor;
|
||||
transform[3][0] = _center[0] * ( 1 - scale_factor );
|
||||
transform[3][1] = _center[1] * ( 1 - scale_factor );
|
||||
transform[3][2] = _center[2] * ( 1 - scale_factor );
|
||||
|
||||
sgCopyMat4( r, m );
|
||||
sgPreMultMat4( r, transform );
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of SGDistScaleAnimation
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
|
||||
: SGAnimation( props, new SGCustomTransform ),
|
||||
_factor(props->getFloatValue("factor", 1.0)),
|
||||
_offset(props->getFloatValue("offset", 0.0)),
|
||||
_min_v(props->getFloatValue("min", 0.0)),
|
||||
_max_v(props->getFloatValue("max", 1.0)),
|
||||
_has_min(props->hasValue("min")),
|
||||
_has_max(props->hasValue("max")),
|
||||
_table(read_interpolation_table(props))
|
||||
{
|
||||
_center[0] = props->getFloatValue("center/x-m", 0);
|
||||
_center[1] = props->getFloatValue("center/y-m", 0);
|
||||
_center[2] = props->getFloatValue("center/z-m", 0);
|
||||
|
||||
((SGCustomTransform *)_branch)->setTransCallback( &SGDistScaleAnimation::distScaleCallback, this );
|
||||
}
|
||||
|
||||
SGDistScaleAnimation::~SGDistScaleAnimation()
|
||||
{
|
||||
}
|
||||
|
||||
void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
|
||||
{
|
||||
((SGDistScaleAnimation *)d)->distScaleCallback( r, f, m );
|
||||
}
|
||||
|
||||
void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
|
||||
{
|
||||
sgVec3 view;
|
||||
sgFullXformPnt3( view, _center, m );
|
||||
|
||||
float scale_factor = sgLengthVec3( view );
|
||||
if (_table == 0) {
|
||||
scale_factor = _factor * scale_factor + _offset;
|
||||
if ( _has_min && scale_factor < _min_v )
|
||||
scale_factor = _min_v;
|
||||
if ( _has_max && scale_factor > _max_v )
|
||||
scale_factor = _max_v;
|
||||
} else {
|
||||
scale_factor = _table->interpolate( scale_factor );
|
||||
}
|
||||
|
||||
sgMat4 transform;
|
||||
sgMakeIdentMat4( transform );
|
||||
transform[0][0] = scale_factor;
|
||||
transform[1][1] = scale_factor;
|
||||
transform[2][2] = scale_factor;
|
||||
transform[3][0] = _center[0] * ( 1 - scale_factor );
|
||||
transform[3][1] = _center[1] * ( 1 - scale_factor );
|
||||
transform[3][2] = _center[2] * ( 1 - scale_factor );
|
||||
|
||||
sgCopyMat4( r, m );
|
||||
sgPreMultMat4( r, transform );
|
||||
}
|
||||
|
||||
// end of animation.cxx
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
SG_USING_STD(map);
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
@@ -25,6 +27,7 @@ SG_USING_STD(vector);
|
||||
// Don't pull in the headers, since we don't need them here.
|
||||
class SGInterpTable;
|
||||
class SGCondition;
|
||||
class SGPersonalityBranch;
|
||||
|
||||
|
||||
// Has anyone done anything *really* stupid, like making min and max macros?
|
||||
@@ -65,7 +68,12 @@ public:
|
||||
/**
|
||||
* Update the animation.
|
||||
*/
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
|
||||
/**
|
||||
* Restore the state after the animation.
|
||||
*/
|
||||
virtual void restore();
|
||||
|
||||
/**
|
||||
* Set the value of sim_time_sec. This needs to be called every
|
||||
@@ -73,6 +81,12 @@ public:
|
||||
*/
|
||||
static void set_sim_time_sec( double val ) { sim_time_sec = val; }
|
||||
|
||||
/**
|
||||
* Current personality branch : enable animation to behave differently
|
||||
* for similar objects
|
||||
*/
|
||||
static SGPersonalityBranch *current_object;
|
||||
|
||||
protected:
|
||||
|
||||
static double sim_time_sec;
|
||||
@@ -102,7 +116,7 @@ public:
|
||||
SGRangeAnimation (SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props);
|
||||
virtual ~SGRangeAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _min_prop;
|
||||
SGPropertyNode_ptr _max_prop;
|
||||
@@ -110,6 +124,7 @@ private:
|
||||
float _max;
|
||||
float _min_factor;
|
||||
float _max_factor;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
|
||||
@@ -133,7 +148,7 @@ public:
|
||||
SGSelectAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGSelectAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
SGCondition * _condition;
|
||||
};
|
||||
@@ -151,7 +166,7 @@ public:
|
||||
SGPropertyNode_ptr props,
|
||||
double sim_time_sec );
|
||||
virtual ~SGSpinAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _factor;
|
||||
@@ -160,6 +175,7 @@ private:
|
||||
sgMat4 _matrix;
|
||||
sgVec3 _center;
|
||||
sgVec3 _axis;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
|
||||
@@ -171,11 +187,22 @@ class SGTimedAnimation : public SGAnimation
|
||||
public:
|
||||
SGTimedAnimation (SGPropertyNode_ptr props);
|
||||
virtual ~SGTimedAnimation ();
|
||||
virtual void update();
|
||||
virtual void init();
|
||||
virtual int update();
|
||||
private:
|
||||
bool _use_personality;
|
||||
enum PersonalityVar { INIT, LAST_TIME_SEC, TOTAL_DURATION_SEC, BRANCH_DURATION_SEC, STEP };
|
||||
double _duration_sec;
|
||||
double _last_time_sec;
|
||||
double _total_duration_sec;
|
||||
int _step;
|
||||
struct DurationSpec {
|
||||
DurationSpec( double m = 0.0 ) : _min(m), _max(m) {}
|
||||
DurationSpec( double m1, double m2 ) : _min(m1), _max(m2) {}
|
||||
double _min, _max;
|
||||
};
|
||||
vector<DurationSpec> _branch_duration_specs;
|
||||
vector<double> _branch_duration_sec;
|
||||
};
|
||||
|
||||
|
||||
@@ -189,7 +216,7 @@ class SGRotateAnimation : public SGAnimation
|
||||
public:
|
||||
SGRotateAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props );
|
||||
virtual ~SGRotateAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _offset_deg;
|
||||
@@ -203,6 +230,7 @@ private:
|
||||
sgMat4 _matrix;
|
||||
sgVec3 _center;
|
||||
sgVec3 _axis;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
|
||||
@@ -215,7 +243,7 @@ public:
|
||||
SGTranslateAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGTranslateAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _offset_m;
|
||||
@@ -228,6 +256,7 @@ private:
|
||||
double _position_m;
|
||||
sgMat4 _matrix;
|
||||
sgVec3 _axis;
|
||||
SGCondition * _condition;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -239,7 +268,7 @@ public:
|
||||
SGBlendAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGBlendAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
SGInterpTable * _table;
|
||||
@@ -261,7 +290,7 @@ public:
|
||||
SGScaleAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGScaleAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _x_factor;
|
||||
@@ -299,7 +328,7 @@ class SGTexRotateAnimation : public SGAnimation
|
||||
public:
|
||||
SGTexRotateAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props );
|
||||
virtual ~SGTexRotateAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _offset_deg;
|
||||
@@ -325,7 +354,7 @@ public:
|
||||
SGTexTranslateAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGTexTranslateAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
SGPropertyNode_ptr _prop;
|
||||
double _offset;
|
||||
@@ -354,7 +383,7 @@ public:
|
||||
SGTexMultipleAnimation( SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr props );
|
||||
virtual ~SGTexMultipleAnimation ();
|
||||
virtual void update();
|
||||
virtual int update();
|
||||
private:
|
||||
class TexTransform
|
||||
{
|
||||
@@ -382,7 +411,7 @@ private:
|
||||
|
||||
|
||||
/**
|
||||
* An animation to enable the alpha test
|
||||
* An "animation" to enable the alpha test
|
||||
*/
|
||||
class SGAlphaTestAnimation : public SGAnimation
|
||||
{
|
||||
@@ -396,4 +425,45 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An "animation" that compute a scale according to
|
||||
* the angle between an axis and the view direction
|
||||
*/
|
||||
class SGFlashAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGFlashAnimation(SGPropertyNode_ptr props);
|
||||
virtual ~SGFlashAnimation ();
|
||||
|
||||
static void flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d );
|
||||
void flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m );
|
||||
|
||||
private:
|
||||
sgVec3 _axis, _center;
|
||||
float _power, _factor, _offset, _min_v, _max_v;
|
||||
bool _two_sides;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An animation that compute a scale according to
|
||||
* the distance from a point and the viewer
|
||||
*/
|
||||
class SGDistScaleAnimation : public SGAnimation
|
||||
{
|
||||
public:
|
||||
SGDistScaleAnimation(SGPropertyNode_ptr props);
|
||||
virtual ~SGDistScaleAnimation ();
|
||||
|
||||
static void distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d );
|
||||
void distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m );
|
||||
|
||||
private:
|
||||
sgVec3 _center;
|
||||
float _factor, _offset, _min_v, _max_v;
|
||||
bool _has_min, _has_max;
|
||||
SGInterpTable * _table;
|
||||
};
|
||||
|
||||
|
||||
#endif // _SG_ANIMATION_HXX
|
||||
|
||||
61
simgear/scene/model/custtrans.cxx
Executable file
61
simgear/scene/model/custtrans.cxx
Executable file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "plib/ssg.h"
|
||||
#include "custtrans.hxx"
|
||||
void _ssgPushMatrix ( sgMat4 m );
|
||||
void _ssgPopMatrix ();
|
||||
void _ssgReadInt ( FILE *fd, int *var );
|
||||
void _ssgWriteInt ( FILE *fd, const int var );
|
||||
extern sgMat4 _ssgOpenGLAxisSwapMatrix;
|
||||
|
||||
void SGCustomTransform::copy_from( SGCustomTransform *src, int clone_flags )
|
||||
{
|
||||
ssgBranch::copy_from( src, clone_flags );
|
||||
_callback = src->_callback;
|
||||
_data = src->_data;
|
||||
}
|
||||
|
||||
ssgBase *SGCustomTransform::clone( int clone_flags )
|
||||
{
|
||||
SGCustomTransform *b = new SGCustomTransform;
|
||||
b -> copy_from( this, clone_flags );
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
SGCustomTransform::SGCustomTransform()
|
||||
: _callback(0),_data(0)
|
||||
{
|
||||
type = ssgTypeBranch();
|
||||
}
|
||||
|
||||
SGCustomTransform::~SGCustomTransform()
|
||||
{
|
||||
}
|
||||
|
||||
void SGCustomTransform::cull( sgFrustum *f, sgMat4 m, int test_needed )
|
||||
{
|
||||
if ( ! preTravTests( &test_needed, SSGTRAV_CULL ) )
|
||||
return;
|
||||
|
||||
if ( _callback ) {
|
||||
sgMat4 tmp;
|
||||
_callback( tmp, f, m, _data );
|
||||
|
||||
_ssgPushMatrix( tmp );
|
||||
glPushMatrix();
|
||||
glLoadMatrixf( (float *) tmp );
|
||||
|
||||
for ( ssgEntity *e = getKid ( 0 ); e != NULL; e = getNextKid() )
|
||||
e -> cull( f, tmp, test_needed );
|
||||
|
||||
glPopMatrix();
|
||||
_ssgPopMatrix();
|
||||
}
|
||||
postTravTests( SSGTRAV_CULL );
|
||||
}
|
||||
|
||||
|
||||
const char *SGCustomTransform::getTypeName (void) { return "SGCustomTransform"; }
|
||||
32
simgear/scene/model/custtrans.hxx
Executable file
32
simgear/scene/model/custtrans.hxx
Executable file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _SG_CUSTOM_TRANSFORM_HXX
|
||||
#define _SG_CUSTOM_TRANSFORM_HXX 1
|
||||
|
||||
class SGCustomTransform : public ssgBranch
|
||||
{
|
||||
public:
|
||||
typedef void (*TransCallback)( sgMat4 r, sgFrustum *f, sgMat4 m, void *d );
|
||||
virtual ssgBase *clone( int clone_flags = 0 );
|
||||
SGCustomTransform();
|
||||
virtual ~SGCustomTransform(void);
|
||||
|
||||
void setTransCallback( TransCallback c, void *d ) {
|
||||
_callback = c;
|
||||
_data = d;
|
||||
}
|
||||
|
||||
virtual const char *getTypeName(void);
|
||||
virtual void cull( sgFrustum *f, sgMat4 m, int test_needed );
|
||||
|
||||
protected:
|
||||
virtual void copy_from( SGCustomTransform *src, int clone_flags );
|
||||
|
||||
private:
|
||||
TransCallback _callback;
|
||||
void *_data;
|
||||
};
|
||||
|
||||
#endif // _SG_CUSTOM_TRANSFORM_HXX
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <string.h> // for strcmp()
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
@@ -26,21 +27,44 @@
|
||||
#include "model.hxx"
|
||||
|
||||
SG_USING_STD(vector);
|
||||
SG_USING_STD(set);
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Global state
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
static bool
|
||||
model_filter = true;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Static utility functions.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int
|
||||
model_filter_callback (ssgEntity * entity, int mask)
|
||||
{
|
||||
return model_filter ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to update an animation.
|
||||
*/
|
||||
static int
|
||||
animation_callback (ssgEntity * entity, int mask)
|
||||
{
|
||||
((SGAnimation *)entity->getUserData())->update();
|
||||
return true;
|
||||
return ((SGAnimation *)entity->getUserData())->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to restore the state after an animation.
|
||||
*/
|
||||
static int
|
||||
restore_callback (ssgEntity * entity, int mask)
|
||||
{
|
||||
((SGAnimation *)entity->getUserData())->restore();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,8 +124,10 @@ sgMakeAnimation( ssgBranch * model,
|
||||
vector<SGPropertyNode_ptr> &name_nodes,
|
||||
SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr node,
|
||||
double sim_time_sec )
|
||||
double sim_time_sec,
|
||||
set<ssgBranch *> &ignore_branches )
|
||||
{
|
||||
bool ignore = false;
|
||||
SGAnimation * animation = 0;
|
||||
const char * type = node->getStringValue("type", "none");
|
||||
if (!strcmp("none", type)) {
|
||||
@@ -130,8 +156,13 @@ sgMakeAnimation( ssgBranch * model,
|
||||
animation = new SGTexMultipleAnimation(prop_root, node);
|
||||
} else if (!strcmp("blend", type)) {
|
||||
animation = new SGBlendAnimation(prop_root, node);
|
||||
ignore = true;
|
||||
} else if (!strcmp("alpha-test", type)) {
|
||||
animation = new SGAlphaTestAnimation(node);
|
||||
} else if (!strcmp("flash", type)) {
|
||||
animation = new SGFlashAnimation(node);
|
||||
} else if (!strcmp("dist-scale", type)) {
|
||||
animation = new SGDistScaleAnimation(node);
|
||||
} else {
|
||||
animation = new SGNullAnimation(node);
|
||||
SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);
|
||||
@@ -144,7 +175,7 @@ sgMakeAnimation( ssgBranch * model,
|
||||
if (name_nodes.size() > 0) {
|
||||
object = find_named_node(model, name_nodes[0]->getStringValue());
|
||||
if (object == 0) {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "Object " << name_nodes[0]->getStringValue()
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Object " << name_nodes[0]->getStringValue()
|
||||
<< " not found");
|
||||
delete animation;
|
||||
animation = 0;
|
||||
@@ -163,21 +194,41 @@ sgMakeAnimation( ssgBranch * model,
|
||||
const char * name = name_nodes[i]->getStringValue();
|
||||
object = find_named_node(model, name);
|
||||
if (object == 0) {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "Object " << name << " not found");
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Object " << name << " not found");
|
||||
delete animation;
|
||||
animation = 0;
|
||||
} else {
|
||||
ssgBranch * oldParent = object->getParent(0);
|
||||
branch->addKid(object);
|
||||
oldParent->removeKid(object);
|
||||
}
|
||||
ssgBranch * oldParent = object->getParent(0);
|
||||
branch->addKid(object);
|
||||
oldParent->removeKid(object);
|
||||
}
|
||||
|
||||
animation->init();
|
||||
branch->setUserData(animation);
|
||||
branch->setTravCallback(SSG_CALLBACK_PRETRAV, animation_callback);
|
||||
if ( animation != 0 ) {
|
||||
animation->init();
|
||||
branch->setUserData(animation);
|
||||
branch->setTravCallback(SSG_CALLBACK_PRETRAV, animation_callback);
|
||||
branch->setTravCallback(SSG_CALLBACK_POSTTRAV, restore_callback);
|
||||
if ( ignore ) {
|
||||
ignore_branches.insert( branch );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void makeDList( ssgBranch *b, const set<ssgBranch *> &ignore )
|
||||
{
|
||||
int nb = b->getNumKids();
|
||||
for (int i = 0; i<nb; i++) {
|
||||
ssgEntity *e = b->getKid(i);
|
||||
if (e->isAKindOf(ssgTypeLeaf())) {
|
||||
((ssgLeaf*)e)->makeDList();
|
||||
} else if (e->isAKindOf(ssgTypeBranch()) && ignore.find((ssgBranch *)e) == ignore.end()) {
|
||||
makeDList( (ssgBranch*)e, ignore );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -187,17 +238,17 @@ sgMakeAnimation( ssgBranch * model,
|
||||
ssgBranch *
|
||||
sgLoad3DModel( const string &fg_root, const string &path,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
double sim_time_sec, ssgEntity *(*load_panel)(SGPropertyNode *) )
|
||||
{
|
||||
ssgBranch * model = 0;
|
||||
SGPropertyNode props;
|
||||
|
||||
// Load the 3D aircraft object itself
|
||||
SGPath modelpath = path;
|
||||
SGPath modelpath = path, texturepath = path;
|
||||
if ( !ulIsAbsolutePathName( path.c_str() ) ) {
|
||||
SGPath tmp = fg_root;
|
||||
tmp.append(modelpath.str());
|
||||
modelpath = tmp;
|
||||
modelpath = texturepath = tmp;
|
||||
}
|
||||
|
||||
// Check for an XML wrapper
|
||||
@@ -206,6 +257,10 @@ sgLoad3DModel( const string &fg_root, const string &path,
|
||||
if (props.hasValue("/path")) {
|
||||
modelpath = modelpath.dir();
|
||||
modelpath.append(props.getStringValue("/path"));
|
||||
if (props.hasValue("/texture-path")) {
|
||||
texturepath = texturepath.dir();
|
||||
texturepath.append(props.getStringValue("/texture-path"));
|
||||
}
|
||||
} else {
|
||||
if (model == 0)
|
||||
model = new ssgBranch;
|
||||
@@ -215,14 +270,18 @@ sgLoad3DModel( const string &fg_root, const string &path,
|
||||
// Assume that textures are in
|
||||
// the same location as the XML file.
|
||||
if (model == 0) {
|
||||
ssgTexturePath((char *)modelpath.dir().c_str());
|
||||
if (texturepath.extension() != "")
|
||||
texturepath = texturepath.dir();
|
||||
|
||||
ssgTexturePath((char *)texturepath.c_str());
|
||||
model = (ssgBranch *)ssgLoad((char *)modelpath.c_str());
|
||||
if (model == 0)
|
||||
throw sg_exception("Failed to load 3D model");
|
||||
}
|
||||
|
||||
// Set up the alignment node
|
||||
ssgTransform * alignmainmodel = new ssgTransform;
|
||||
if ( load_panel == 0 )
|
||||
alignmainmodel->setTravCallback( SSG_CALLBACK_PRETRAV, model_filter_callback );
|
||||
alignmainmodel->addKid(model);
|
||||
sgMat4 res_matrix;
|
||||
sgMakeOffsetsMatrix(&res_matrix,
|
||||
@@ -252,24 +311,51 @@ sgLoad3DModel( const string &fg_root, const string &path,
|
||||
align->setTransform(res_matrix);
|
||||
|
||||
ssgBranch * kid = sgLoad3DModel( fg_root, node->getStringValue("path"),
|
||||
prop_root, sim_time_sec );
|
||||
prop_root, sim_time_sec, load_panel );
|
||||
align->addKid(kid);
|
||||
align->setName(node->getStringValue("name", ""));
|
||||
model->addKid(align);
|
||||
}
|
||||
|
||||
// Load animations
|
||||
set<ssgBranch *> ignore_branches;
|
||||
vector<SGPropertyNode_ptr> animation_nodes = props.getChildren("animation");
|
||||
for (i = 0; i < animation_nodes.size(); i++) {
|
||||
const char * name = animation_nodes[i]->getStringValue("name", 0);
|
||||
vector<SGPropertyNode_ptr> name_nodes =
|
||||
animation_nodes[i]->getChildren("object-name");
|
||||
sgMakeAnimation( model, name, name_nodes, prop_root, animation_nodes[i],
|
||||
sim_time_sec);
|
||||
sim_time_sec, ignore_branches);
|
||||
}
|
||||
|
||||
#if PLIB_VERSION > 183
|
||||
if ( model != 0 ) {
|
||||
makeDList( model, ignore_branches );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( load_panel ) {
|
||||
// Load panels
|
||||
vector<SGPropertyNode_ptr> panel_nodes = props.getChildren("panel");
|
||||
for (i = 0; i < panel_nodes.size(); i++) {
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Loading a panel");
|
||||
ssgEntity * panel = load_panel(panel_nodes[i]);
|
||||
if (panel_nodes[i]->hasValue("name"))
|
||||
panel->setName((char *)panel_nodes[i]->getStringValue("name"));
|
||||
model->addKid(panel);
|
||||
}
|
||||
}
|
||||
|
||||
return alignmainmodel;
|
||||
}
|
||||
|
||||
bool
|
||||
sgSetModelFilter( bool filter )
|
||||
{
|
||||
bool old = model_filter;
|
||||
model_filter = filter;
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
// end of model.cxx
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
SG_USING_STD(set);
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
@@ -43,7 +45,8 @@ SG_USING_STD(vector);
|
||||
*/
|
||||
ssgBranch *
|
||||
sgLoad3DModel( const string& fg_root, const string &path,
|
||||
SGPropertyNode *prop_root, double sim_time_sec );
|
||||
SGPropertyNode *prop_root, double sim_time_sec,
|
||||
ssgEntity *(*load_panel)(SGPropertyNode *) = 0 );
|
||||
|
||||
|
||||
/**
|
||||
@@ -62,7 +65,13 @@ sgMakeAnimation( ssgBranch * model,
|
||||
vector<SGPropertyNode_ptr> &name_nodes,
|
||||
SGPropertyNode *prop_root,
|
||||
SGPropertyNode_ptr node,
|
||||
double sim_time_sec );
|
||||
double sim_time_sec,
|
||||
set<ssgBranch *> &ignore_branches );
|
||||
|
||||
/**
|
||||
* Set the filter state on models
|
||||
*/
|
||||
bool
|
||||
sgSetModelFilter( bool filter );
|
||||
|
||||
#endif // __MODEL_HXX
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include "model.hxx"
|
||||
#include "animation.hxx"
|
||||
#include "personality.hxx"
|
||||
|
||||
#include "modellib.hxx"
|
||||
|
||||
@@ -60,6 +62,21 @@ SGModelLib::flush1()
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
personality_pretrav_callback(ssgEntity * entity, int mask)
|
||||
{
|
||||
((SGPersonalityBranch *)entity)->_old_current = SGAnimation::current_object;
|
||||
SGAnimation::current_object = (SGPersonalityBranch *)entity;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
personality_posttrav_callback(ssgEntity * entity, int mask)
|
||||
{
|
||||
SGAnimation::current_object = ((SGPersonalityBranch *)entity)->_old_current;
|
||||
((SGPersonalityBranch *)entity)->_old_current = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssgEntity *
|
||||
SGModelLib::load_model( const string &fg_root,
|
||||
@@ -67,6 +84,10 @@ SGModelLib::load_model( const string &fg_root,
|
||||
SGPropertyNode *prop_root,
|
||||
double sim_time_sec )
|
||||
{
|
||||
ssgBranch *personality_branch = new SGPersonalityBranch;
|
||||
personality_branch->setTravCallback(SSG_CALLBACK_PRETRAV, personality_pretrav_callback);
|
||||
personality_branch->setTravCallback(SSG_CALLBACK_POSTTRAV, personality_posttrav_callback);
|
||||
|
||||
// FIXME: normalize path to
|
||||
// avoid duplicates.
|
||||
map<string, ssgBase *>::iterator it = _table.find(path);
|
||||
@@ -75,10 +96,11 @@ SGModelLib::load_model( const string &fg_root,
|
||||
sim_time_sec );
|
||||
model->ref();
|
||||
_table[path] = model; // add one reference to keep it around
|
||||
return model;
|
||||
personality_branch->addKid( model );
|
||||
} else {
|
||||
return (ssgEntity *)it->second;
|
||||
personality_branch->addKid( (ssgEntity *)it->second );
|
||||
}
|
||||
return personality_branch;
|
||||
}
|
||||
|
||||
|
||||
|
||||
37
simgear/scene/model/personality.cxx
Executable file
37
simgear/scene/model/personality.cxx
Executable file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "personality.hxx"
|
||||
|
||||
void SGPersonalityBranch::setDoubleValue( double value, SGAnimation *anim, int var_id, int var_num )
|
||||
{
|
||||
_doubleValues[ Key( anim, var_id, var_num ) ] = value;
|
||||
}
|
||||
|
||||
void SGPersonalityBranch::setIntValue( int value, SGAnimation *anim, int var_id, int var_num )
|
||||
{
|
||||
_intValues[ Key( anim, var_id, var_num ) ] = value;
|
||||
}
|
||||
|
||||
double SGPersonalityBranch::getDoubleValue( SGAnimation *anim, int var_id, int var_num ) const
|
||||
{
|
||||
map<Key,double>::const_iterator it = _doubleValues.find( Key( anim, var_id, var_num ) );
|
||||
if ( it != _doubleValues.end() ) {
|
||||
return it->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int SGPersonalityBranch::getIntValue( SGAnimation *anim, int var_id, int var_num ) const
|
||||
{
|
||||
map<Key,int>::const_iterator it = _intValues.find( Key( anim, var_id, var_num ) );
|
||||
if ( it != _intValues.end() ) {
|
||||
return it->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
41
simgear/scene/model/personality.hxx
Executable file
41
simgear/scene/model/personality.hxx
Executable file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _SG_PERSONALITY_HXX
|
||||
#define _SG_PERSONALITY_HXX 1
|
||||
|
||||
#include <map>
|
||||
|
||||
SG_USING_STD(map);
|
||||
|
||||
#include <plib/ssg.h>
|
||||
|
||||
class SGAnimation;
|
||||
|
||||
class SGPersonalityBranch : public ssgBranch {
|
||||
public:
|
||||
void setDoubleValue( double value, SGAnimation *anim, int var_id, int var_num = 0 );
|
||||
void setIntValue( int value, SGAnimation *anim, int var_id, int var_num = 0 );
|
||||
double getDoubleValue( SGAnimation *anim, int var_id, int var_num = 0 ) const;
|
||||
int getIntValue( SGAnimation *anim, int var_id, int var_num = 0 ) const;
|
||||
|
||||
SGPersonalityBranch *_old_current;
|
||||
|
||||
private:
|
||||
struct Key {
|
||||
Key( SGAnimation *a, int i, int n = 0 ) : anim(a), var_id(i), var_num(n) {}
|
||||
SGAnimation *anim;
|
||||
int var_id;
|
||||
int var_num;
|
||||
bool operator<( const Key &r ) const {
|
||||
return anim < r.anim ||
|
||||
( anim == r.anim && ( var_id < r.var_id ||
|
||||
( var_id == r.var_id && var_num < r.var_num ) ) );
|
||||
}
|
||||
};
|
||||
map<Key,double> _doubleValues;
|
||||
map<Key,int> _intValues;
|
||||
};
|
||||
|
||||
#endif // _SG_PERSONALITY_HXX
|
||||
File diff suppressed because it is too large
Load Diff
@@ -167,13 +167,29 @@ public:
|
||||
double dt = 0.0 );
|
||||
|
||||
/** draw the cloud layer */
|
||||
void draw();
|
||||
void draw( bool top );
|
||||
|
||||
static bool enable_bump_mapping;
|
||||
|
||||
private:
|
||||
|
||||
struct CloudVertex {
|
||||
sgVec3 position;
|
||||
sgVec2 texCoord;
|
||||
sgVec3 tangentSpLight;
|
||||
sgVec3 sTangent;
|
||||
sgVec3 tTangent;
|
||||
sgVec3 normal;
|
||||
sgVec4 color;
|
||||
};
|
||||
|
||||
CloudVertex *vertices;
|
||||
unsigned int *indices;
|
||||
|
||||
ssgRoot *layer_root;
|
||||
ssgTransform *layer_transform;
|
||||
ssgLeaf *layer[4];
|
||||
ssgStateSelector *state_sel;
|
||||
|
||||
ssgColourArray *cl[4];
|
||||
ssgVertexArray *vl[4];
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
#include "sphere.hxx"
|
||||
#include "oursun.hxx"
|
||||
|
||||
static double sun_exp2_punch_through;
|
||||
|
||||
// Set up sun rendering call backs
|
||||
static int sgSunOrbPreDraw( ssgEntity *e ) {
|
||||
/* cout << endl << "Sun orb pre draw" << endl << "----------------"
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
static double sun_exp2_punch_through;
|
||||
|
||||
class SGSun {
|
||||
|
||||
ssgTransform *sun_transform;
|
||||
|
||||
@@ -171,12 +171,6 @@ bool SGSky::reposition( SGSkyState &st, double dt )
|
||||
void SGSky::preDraw( float alt, float fog_exp2_density ) {
|
||||
ssgCullAndDraw( pre_root );
|
||||
|
||||
// FIXME: This should not be needed, but at this time (08/15/2003)
|
||||
// certain NVidia drivers don't seem to implement
|
||||
// glPushAttrib(FG_FOG_BIT) properly. The result is that
|
||||
// there is not fog when looking at the sun.
|
||||
glFogf ( GL_FOG_DENSITY, fog_exp2_density );
|
||||
|
||||
// if we are closer than this to a cloud layer, don't draw clouds
|
||||
static const float slop = 5.0;
|
||||
int i;
|
||||
@@ -207,10 +201,18 @@ void SGSky::preDraw( float alt, float fog_exp2_density ) {
|
||||
++cur_layer_pos;
|
||||
}
|
||||
|
||||
// FIXME: This should not be needed, but at this time (08/15/2003)
|
||||
// certain NVidia drivers don't seem to implement
|
||||
// glPushAttrib(FG_FOG_BIT) properly. The result is that
|
||||
// there is not fog when looking at the sun.
|
||||
glFogf ( GL_FOG_DENSITY, fog_exp2_density );
|
||||
}
|
||||
|
||||
void SGSky::drawUpperClouds( ) {
|
||||
// draw the cloud layers that are above us, top to bottom
|
||||
for ( i = (int)cloud_layers.size() - 1; i >= cur_layer_pos; --i ) {
|
||||
for ( int i = (int)cloud_layers.size() - 1; i >= cur_layer_pos; --i ) {
|
||||
if ( i != in_cloud ) {
|
||||
cloud_layers[i]->draw();
|
||||
cloud_layers[i]->draw( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,13 +220,12 @@ void SGSky::preDraw( float alt, float fog_exp2_density ) {
|
||||
|
||||
// draw translucent clouds ... do this after you've drawn all the
|
||||
// oapaque elements of your scene.
|
||||
void SGSky::postDraw( float alt ) {
|
||||
void SGSky::drawLowerClouds() {
|
||||
|
||||
// draw the cloud layers that are below us, bottom to top
|
||||
|
||||
for ( int i = 0; i < cur_layer_pos; ++i ) {
|
||||
if ( i != in_cloud ) {
|
||||
cloud_layers[i]->draw();
|
||||
cloud_layers[i]->draw( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,7 +266,10 @@ void SGSky::modify_vis( float alt, float time_factor ) {
|
||||
|
||||
double ratio = 1.0;
|
||||
|
||||
if ( alt < asl - transition ) {
|
||||
if ( cloud_layers[i]->getCoverage() == SGCloudLayer::SG_CLOUD_CLEAR ) {
|
||||
// clear layer
|
||||
ratio = 1.0;
|
||||
} else if ( alt < asl - transition ) {
|
||||
// below cloud layer
|
||||
ratio = 1.0;
|
||||
} else if ( alt < asl ) {
|
||||
|
||||
@@ -143,22 +143,27 @@ typedef struct {
|
||||
|
||||
* Rendering the Sky
|
||||
|
||||
* The sky is designed to be rendered in two stages. The first stage
|
||||
* The sky is designed to be rendered in three stages. The first stage
|
||||
* renders the parts that form your back drop - the sky dome, the
|
||||
* stars and planets, the sun, and the moon. These should be rendered
|
||||
* before the rest of your scene by calling the preDraw() method. The
|
||||
* second stage renders the clouds which are likely to be translucent
|
||||
* (depending on type) and should be drawn after your scene has been
|
||||
* rendered. Use the postDraw() method to draw the second stage of
|
||||
* the sky.
|
||||
* second stage renders the clouds that are above the viewer. This stage
|
||||
* is done before translucent objects in the main scene are drawn. It
|
||||
* is seperated from the preDraw routine to enable to implement a
|
||||
* multi passes technique and is located in the drawUpperClouds() method.
|
||||
* The third stage renders the clouds that are below the viewer an which
|
||||
* are likely to be translucent (depending on type) and should be drawn
|
||||
* after your scene has been rendered. Use the drawLowerClouds() method
|
||||
* to draw the second stage of the sky.
|
||||
|
||||
* A typical application might do the following:
|
||||
|
||||
* <li> thesky->preDraw();
|
||||
* <li> thesky->preDraw( my_altitude );
|
||||
* <li> thesky->drawUpperClouds();
|
||||
* <li> ssgCullAndDraw ( myscene ) ;
|
||||
* <li> thesky->postDraw( my_altitude );
|
||||
* <li> thesky->drawLowerClouds();
|
||||
|
||||
* The current altitude in meters is passed to the postDraw() method
|
||||
* The current altitude in meters is passed to the preDraw() method
|
||||
* so the clouds layers can be rendered correction from most distant
|
||||
* to closest.
|
||||
|
||||
@@ -332,12 +337,19 @@ public:
|
||||
void preDraw( float alt, float fog_exp2_density );
|
||||
|
||||
/**
|
||||
* Draw translucent clouds ... do this after you've drawn all the
|
||||
* oapaque elements of your scene. See discussion in detailed
|
||||
* class description.
|
||||
* @param alt current altitude
|
||||
* Draw upper translucent clouds ... do this before you've drawn
|
||||
* all the translucent elements of your scene. See discussion in
|
||||
* detailed class description.
|
||||
* @param fog_exp2_density fog density of the current cloud layer
|
||||
*/
|
||||
void postDraw( float alt );
|
||||
void drawUpperClouds();
|
||||
|
||||
/**
|
||||
* Draw lower translucent clouds ... do this after you've drawn
|
||||
* all the opaque elements of your scene. See discussion in detailed
|
||||
* class description.
|
||||
*/
|
||||
void drawLowerClouds();
|
||||
|
||||
/**
|
||||
* Specify the texture path (optional, defaults to current directory)
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
#include STL_STRING
|
||||
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
@@ -44,6 +46,12 @@
|
||||
#include "obj.hxx"
|
||||
|
||||
SG_USING_STD(string);
|
||||
SG_USING_STD(list);
|
||||
|
||||
struct Leaf {
|
||||
GLenum type;
|
||||
int index;
|
||||
};
|
||||
|
||||
|
||||
// Generate an ocean tile
|
||||
@@ -169,7 +177,6 @@ bool sgGenTile( const string& path, SGBucket b,
|
||||
new ssgVtxTable ( GL_TRIANGLE_FAN, vl, nl, tl, cl );
|
||||
|
||||
leaf->setState( state );
|
||||
|
||||
geometry->addKid( leaf );
|
||||
|
||||
return true;
|
||||
@@ -327,6 +334,10 @@ bool sgBinObjLoad( const string& path, const bool is_base,
|
||||
return false;
|
||||
}
|
||||
|
||||
ssgBranch *local_terrain = new ssgBranch;
|
||||
local_terrain->setName( "LocalTerrain" );
|
||||
geometry->addKid( local_terrain );
|
||||
|
||||
geometry->setName( (char *)path.c_str() );
|
||||
|
||||
// reference point (center offset/bounding sphere)
|
||||
@@ -375,7 +386,7 @@ bool sgBinObjLoad( const string& path, const bool is_base,
|
||||
nodes, normals, texcoords,
|
||||
pts_v[i], pts_n[i], tex_index,
|
||||
false, ground_lights );
|
||||
geometry->addKid( leaf );
|
||||
local_terrain->addKid( leaf );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,82 +403,102 @@ bool sgBinObjLoad( const string& path, const bool is_base,
|
||||
object_lod->addKid(random_object_branch);
|
||||
}
|
||||
|
||||
// generate triangles
|
||||
typedef map<string,list<Leaf> > LeafMap;
|
||||
LeafMap leafMap;
|
||||
Leaf leaf;
|
||||
leaf.type = GL_TRIANGLES;
|
||||
string_list const& tri_materials = obj.get_tri_materials();
|
||||
group_list const& tris_v = obj.get_tris_v();
|
||||
group_list const& tris_n = obj.get_tris_n();
|
||||
group_list const& tris_tc = obj.get_tris_tc();
|
||||
for ( i = 0; i < tris_v.size(); ++i ) {
|
||||
ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLES, matlib,
|
||||
tri_materials[i],
|
||||
nodes, normals, texcoords,
|
||||
tris_v[i], tris_n[i], tris_tc[i],
|
||||
is_base, ground_lights );
|
||||
|
||||
if ( use_random_objects ) {
|
||||
SGMaterial *mat = matlib->find( tri_materials[i] );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_INPUT, SG_ALERT,
|
||||
"Unknown material for random surface objects = "
|
||||
<< tri_materials[i] );
|
||||
} else {
|
||||
gen_random_surface_objects( leaf, random_object_branch,
|
||||
center, mat );
|
||||
}
|
||||
}
|
||||
geometry->addKid( leaf );
|
||||
for ( i = 0; i < tris_v.size(); i++ ) {
|
||||
leaf.index = i;
|
||||
leafMap[ tri_materials[i] ].push_back( leaf );
|
||||
}
|
||||
|
||||
// generate strips
|
||||
leaf.type = GL_TRIANGLE_STRIP;
|
||||
string_list const& strip_materials = obj.get_strip_materials();
|
||||
group_list const& strips_v = obj.get_strips_v();
|
||||
group_list const& strips_n = obj.get_strips_n();
|
||||
group_list const& strips_tc = obj.get_strips_tc();
|
||||
for ( i = 0; i < strips_v.size(); ++i ) {
|
||||
ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_STRIP,
|
||||
matlib, strip_materials[i],
|
||||
nodes, normals, texcoords,
|
||||
strips_v[i], strips_n[i], strips_tc[i],
|
||||
is_base, ground_lights );
|
||||
|
||||
if ( use_random_objects ) {
|
||||
SGMaterial *mat = matlib->find( strip_materials[i] );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_INPUT, SG_ALERT,
|
||||
"Unknown material for random surface objects = "
|
||||
<< strip_materials[i] );
|
||||
} else {
|
||||
gen_random_surface_objects( leaf, random_object_branch,
|
||||
center, mat );
|
||||
}
|
||||
}
|
||||
geometry->addKid( leaf );
|
||||
for ( i = 0; i < strips_v.size(); i++ ) {
|
||||
leaf.index = i;
|
||||
leafMap[ strip_materials[i] ].push_back( leaf );
|
||||
}
|
||||
|
||||
// generate fans
|
||||
leaf.type = GL_TRIANGLE_FAN;
|
||||
string_list const& fan_materials = obj.get_fan_materials();
|
||||
group_list const& fans_v = obj.get_fans_v();
|
||||
group_list const& fans_n = obj.get_fans_n();
|
||||
group_list const& fans_tc = obj.get_fans_tc();
|
||||
for ( i = 0; i < fans_v.size(); ++i ) {
|
||||
ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_FAN,
|
||||
matlib, fan_materials[i],
|
||||
nodes, normals, texcoords,
|
||||
fans_v[i], fans_n[i], fans_tc[i],
|
||||
is_base, ground_lights );
|
||||
if ( use_random_objects ) {
|
||||
SGMaterial *mat = matlib->find( fan_materials[i] );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_INPUT, SG_ALERT,
|
||||
"Unknown material for random surface objects = "
|
||||
<< fan_materials[i] );
|
||||
} else {
|
||||
gen_random_surface_objects( leaf, random_object_branch,
|
||||
center, mat );
|
||||
}
|
||||
}
|
||||
for ( i = 0; i < fans_v.size(); i++ ) {
|
||||
leaf.index = i;
|
||||
leafMap[ fan_materials[i] ].push_back( leaf );
|
||||
}
|
||||
|
||||
geometry->addKid( leaf );
|
||||
LeafMap::iterator lmi = leafMap.begin();
|
||||
while ( lmi != leafMap.end() ) {
|
||||
list<Leaf> &leaf_list = lmi->second;
|
||||
list<Leaf>::iterator li = leaf_list.begin();
|
||||
while ( li != leaf_list.end() ) {
|
||||
Leaf &leaf = *li;
|
||||
int ind = leaf.index;
|
||||
if ( leaf.type == GL_TRIANGLES ) {
|
||||
ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLES, matlib,
|
||||
tri_materials[ind],
|
||||
nodes, normals, texcoords,
|
||||
tris_v[ind], tris_n[ind], tris_tc[ind],
|
||||
is_base, ground_lights );
|
||||
if ( use_random_objects ) {
|
||||
SGMaterial *mat = matlib->find( tri_materials[ind] );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_INPUT, SG_ALERT,
|
||||
"Unknown material for random surface objects = "
|
||||
<< tri_materials[ind] );
|
||||
} else {
|
||||
gen_random_surface_objects( leaf, random_object_branch,
|
||||
center, mat );
|
||||
}
|
||||
}
|
||||
local_terrain->addKid( leaf );
|
||||
} else if ( leaf.type == GL_TRIANGLE_STRIP ) {
|
||||
ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_STRIP,
|
||||
matlib, strip_materials[ind],
|
||||
nodes, normals, texcoords,
|
||||
strips_v[ind], strips_n[ind], strips_tc[ind],
|
||||
is_base, ground_lights );
|
||||
if ( use_random_objects ) {
|
||||
SGMaterial *mat = matlib->find( strip_materials[ind] );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_INPUT, SG_ALERT,
|
||||
"Unknown material for random surface objects = "
|
||||
<< strip_materials[ind] );
|
||||
} else {
|
||||
gen_random_surface_objects( leaf, random_object_branch,
|
||||
center, mat );
|
||||
}
|
||||
}
|
||||
local_terrain->addKid( leaf );
|
||||
} else {
|
||||
ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_FAN,
|
||||
matlib, fan_materials[ind],
|
||||
nodes, normals, texcoords,
|
||||
fans_v[ind], fans_n[ind], fans_tc[ind],
|
||||
is_base, ground_lights );
|
||||
if ( use_random_objects ) {
|
||||
SGMaterial *mat = matlib->find( fan_materials[ind] );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_INPUT, SG_ALERT,
|
||||
"Unknown material for random surface objects = "
|
||||
<< fan_materials[ind] );
|
||||
} else {
|
||||
gen_random_surface_objects( leaf, random_object_branch,
|
||||
center, mat );
|
||||
}
|
||||
}
|
||||
local_terrain->addKid( leaf );
|
||||
}
|
||||
++li;
|
||||
}
|
||||
++lmi;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "extensions.hxx"
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
static bool SGSearchExtensionsString(char *extString, char *extName) {
|
||||
// Returns GL_TRUE if the *extName string appears in the *extString string,
|
||||
@@ -59,8 +60,7 @@ bool SGIsOpenGLExtensionSupported(char *extName) {
|
||||
// The *extName string must follow the OpenGL extensions naming scheme
|
||||
// (ie: "GL_type_extension", like GL_EXT_convolution)
|
||||
|
||||
return SGSearchExtensionsString((char *)glGetString(GL_EXTENSIONS),
|
||||
extName);
|
||||
return SGSearchExtensionsString((char *)glGetString(GL_EXTENSIONS),extName);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
@@ -96,4 +96,30 @@ void* macosxGetGLProcAddress(const char *func) {
|
||||
return function;
|
||||
}
|
||||
|
||||
#elif !defined( WIN32 )
|
||||
|
||||
void *SGGetGLProcAddress(const char *func) {
|
||||
static void *libHandle = NULL;
|
||||
void *fptr = NULL;
|
||||
|
||||
/*
|
||||
* Clear the error buffer
|
||||
*/
|
||||
dlerror();
|
||||
|
||||
if (libHandle == NULL)
|
||||
libHandle = dlopen("libGL.so", RTLD_LAZY);
|
||||
|
||||
if (libHandle != NULL) {
|
||||
fptr = dlsym(libHandle, func);
|
||||
|
||||
char *error = dlerror();
|
||||
if (error)
|
||||
SG_LOG(SG_GENERAL, SG_INFO, error);
|
||||
}
|
||||
|
||||
return fptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#ifndef __SG_EXTENSIONS_HXX
|
||||
#define __SG_EXTENSIONS_HXX 1
|
||||
|
||||
#if defined(__CYGWIN__) /* && !defined(USING_X) */
|
||||
#if defined(__CYGWIN__) && !defined(WIN32) /* && !defined(USING_X) */
|
||||
#define WIN32
|
||||
#endif
|
||||
|
||||
@@ -53,6 +53,11 @@ bool SGIsOpenGLExtensionSupported(char *extName);
|
||||
#ifdef __APPLE__
|
||||
// don't use an inline function for symbol lookup, since it is too big
|
||||
void* macosxGetGLProcAddress(const char *func);
|
||||
|
||||
#elif !defined( WIN32 )
|
||||
|
||||
void *SGGetGLProcAddress(const char *func);
|
||||
|
||||
#endif
|
||||
|
||||
inline void (*SGLookupFunction(const char *func))()
|
||||
@@ -65,19 +70,32 @@ inline void (*SGLookupFunction(const char *func))()
|
||||
|
||||
#else // UNIX
|
||||
|
||||
// If the target system s UNIX and the ARB_get_proc_address
|
||||
// GLX extension is *not* guaranteed to be supported. An alternative
|
||||
// dlsym-based approach will be used instead.
|
||||
|
||||
void *libHandle;
|
||||
void (*fptr)();
|
||||
libHandle = dlopen("libGL.so", RTLD_LAZY);
|
||||
fptr = (void (*)()) dlsym(libHandle, func);
|
||||
dlclose(libHandle);
|
||||
return fptr;
|
||||
return (void (*)()) SGGetGLProcAddress(func);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* OpenGL 1.2 and 1.3 enumerants
|
||||
*/
|
||||
|
||||
#ifndef GL_VERSION_1_2
|
||||
#define GL_CLAMP_TO_EDGE 0x812F
|
||||
#define GL_TEXTURE_WRAP_R 0x8072
|
||||
#define GL_BLEND_EQUATION 0x8009
|
||||
#define GL_MIN 0x8007
|
||||
#define GL_MAX 0x8008
|
||||
#define GL_FUNC_ADD 0x8006
|
||||
#define GL_FUNC_SUBTRACT 0x800A
|
||||
#define GL_FUNC_REVERSE_SUBTRACT 0x800B
|
||||
#define GL_BLEND_COLOR 0x8005
|
||||
#define GL_CONSTANT_COLOR 0x8001
|
||||
#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
|
||||
#define GL_CONSTANT_ALPHA 0x8003
|
||||
#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
|
||||
#endif
|
||||
|
||||
typedef void (APIENTRY * glBlendEquationProc) (GLenum mode );
|
||||
typedef void (APIENTRY * glBlendColorProc) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
|
||||
|
||||
|
||||
/* OpenGL extension declarations */
|
||||
@@ -144,6 +162,7 @@ typedef void (APIENTRY * glPointParameterfvProc)(GLenum pname, const GLfloat *pa
|
||||
#endif
|
||||
|
||||
typedef void (APIENTRY * glActiveTextureProc)(GLenum texture);
|
||||
typedef void (APIENTRY * glClientActiveTextureProc)(GLenum texture);
|
||||
|
||||
/*
|
||||
* GL_EXT_separate_specular_color
|
||||
@@ -155,6 +174,65 @@ typedef void (APIENTRY * glActiveTextureProc)(GLenum texture);
|
||||
#define GL_SEPARATE_SPECULAR_COLOR 0x81FA
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GL_ARB_texture_cube_map
|
||||
*/
|
||||
|
||||
#ifndef GL_ARB_texture_cube_map
|
||||
#define GL_ARB_texture_cube_map 1
|
||||
#define GL_NORMAL_MAP_ARB 0x8511
|
||||
#define GL_REFLECTION_MAP_ARB 0x8512
|
||||
#define GL_TEXTURE_CUBE_MAP_ARB 0x8513
|
||||
#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514
|
||||
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515
|
||||
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516
|
||||
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517
|
||||
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518
|
||||
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519
|
||||
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A
|
||||
#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B
|
||||
#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GL_ARB_texture_env_combine
|
||||
*/
|
||||
|
||||
#ifndef GL_ARB_texture_env_combine
|
||||
#define GL_ARB_texture_env_combine 1
|
||||
#define GL_COMBINE_ARB 0x8570
|
||||
#define GL_COMBINE_RGB_ARB 0x8571
|
||||
#define GL_COMBINE_ALPHA_ARB 0x8572
|
||||
#define GL_RGB_SCALE_ARB 0x8573
|
||||
#define GL_ADD_SIGNED_ARB 0x8574
|
||||
#define GL_INTERPOLATE_ARB 0x8575
|
||||
#define GL_CONSTANT_ARB 0x8576
|
||||
#define GL_PRIMARY_COLOR_ARB 0x8577
|
||||
#define GL_PREVIOUS_ARB 0x8578
|
||||
#define GL_SOURCE0_RGB_ARB 0x8580
|
||||
#define GL_SOURCE1_RGB_ARB 0x8581
|
||||
#define GL_SOURCE2_RGB_ARB 0x8582
|
||||
#define GL_SOURCE0_ALPHA_ARB 0x8588
|
||||
#define GL_SOURCE1_ALPHA_ARB 0x8589
|
||||
#define GL_SOURCE2_ALPHA_ARB 0x858A
|
||||
#define GL_OPERAND0_RGB_ARB 0x8590
|
||||
#define GL_OPERAND1_RGB_ARB 0x8591
|
||||
#define GL_OPERAND2_RGB_ARB 0x8592
|
||||
#define GL_OPERAND0_ALPHA_ARB 0x8598
|
||||
#define GL_OPERAND1_ALPHA_ARB 0x8599
|
||||
#define GL_OPERAND2_ALPHA_ARB 0x859A
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GL_ARB_texture_env_dot3
|
||||
*/
|
||||
|
||||
#ifndef GL_ARB_texture_env_dot3
|
||||
#define GL_ARB_texture_env_dot3 1
|
||||
#define GL_DOT3_RGB_ARB 0x86AE
|
||||
#define GL_DOT3_RGBA_ARB 0x86AF
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -57,8 +57,7 @@ typedef struct {
|
||||
|
||||
typedef my_destination_mgr * my_dest_ptr;
|
||||
|
||||
/* Where should this go <simgear/screen/tr.h> ?? */
|
||||
extern void trRenderFrame( void );
|
||||
void (*jpgRenderFrame)(void) = NULL;
|
||||
|
||||
trJpgFactory::trJpgFactory() {
|
||||
imageWidth = imageHeight = 0;
|
||||
@@ -233,7 +232,7 @@ int trJpgFactory::compress()
|
||||
|
||||
int trJpgFactory::render()
|
||||
{
|
||||
if( !tr ) {
|
||||
if( !tr || !jpgRenderFrame ) {
|
||||
printf("!! NO tr !!\n trJpgFactory::render()\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -253,7 +252,7 @@ int trJpgFactory::render()
|
||||
|
||||
// printf("\ttrBeginTile(tr)\n");
|
||||
trBeginTile(tr);
|
||||
trRenderFrame();
|
||||
jpgRenderFrame();
|
||||
trEndTile(tr);
|
||||
|
||||
/* just to be safe */
|
||||
|
||||
@@ -36,6 +36,9 @@ extern "C" {
|
||||
|
||||
#include <simgear/screen/tr.h>
|
||||
|
||||
|
||||
extern void (*jpgRenderFrame)(void);
|
||||
|
||||
/* should look at how VNC does this */
|
||||
class trJpgFactory {
|
||||
private:
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
// $Id$
|
||||
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
/**
|
||||
* Dump the screen buffer to a ppm file.
|
||||
* @param filename name of file
|
||||
|
||||
@@ -193,6 +193,7 @@ SGTexture::read_alpha_texture(const char *name)
|
||||
}
|
||||
|
||||
texture_data = new GLubyte[ image->xsize * image->ysize ];
|
||||
num_colors = 1;
|
||||
if (!texture_data)
|
||||
return;
|
||||
|
||||
@@ -227,6 +228,7 @@ SGTexture::read_rgb_texture(const char *name)
|
||||
}
|
||||
|
||||
texture_data = new GLubyte[ image->xsize * image->ysize * 3 ];
|
||||
num_colors = 3;
|
||||
rbuf = new GLubyte[ image->xsize ];
|
||||
gbuf = new GLubyte[ image->xsize ];
|
||||
bbuf = new GLubyte[ image->xsize ];
|
||||
@@ -290,6 +292,7 @@ SGTexture::read_rgba_texture(const char *name)
|
||||
}
|
||||
|
||||
texture_data = new GLubyte[ image->xsize * image->ysize * 4 ];
|
||||
num_colors = 4;
|
||||
rbuf = new GLubyte[ image->xsize ];
|
||||
gbuf = new GLubyte[ image->xsize ];
|
||||
bbuf = new GLubyte[ image->xsize ];
|
||||
|
||||
@@ -109,9 +109,9 @@ public:
|
||||
|
||||
void bind();
|
||||
inline void select(bool keep_data = false) {
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB,
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, num_colors,
|
||||
texture_width, texture_height, 0,
|
||||
GL_RGB, GL_UNSIGNED_BYTE, texture_data );
|
||||
(num_colors==1)?GL_LUMINANCE:(num_colors==3)?GL_RGB:GL_RGBA, GL_UNSIGNED_BYTE, texture_data );
|
||||
|
||||
if (!keep_data) {
|
||||
delete[] texture_data;
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
inline bool is_resident() {
|
||||
GLboolean is_res;
|
||||
glAreTexturesResident(1, &texture_id, &is_res);
|
||||
return is_res;
|
||||
return is_res != 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
openal_test1
|
||||
openal_test2
|
||||
|
||||
@@ -1,11 +1,35 @@
|
||||
includedir = @includedir@/sound
|
||||
|
||||
EXTRA_DIST = jet.wav
|
||||
|
||||
lib_LIBRARIES = libsgsound.a
|
||||
|
||||
noinst_HEADERS =
|
||||
|
||||
include_HEADERS = sound.hxx soundmgr.hxx
|
||||
include_HEADERS = \
|
||||
sample_openal.hxx \
|
||||
soundmgr_openal.hxx \
|
||||
xmlsound.hxx
|
||||
|
||||
libsgsound_a_SOURCES = sound.cxx soundmgr.cxx
|
||||
libsgsound_a_SOURCES = \
|
||||
sample_openal.cxx \
|
||||
soundmgr_openal.cxx \
|
||||
xmlsound.cxx
|
||||
|
||||
noinst_PROGRAMS = openal_test1 openal_test2
|
||||
|
||||
openal_test1_SOURCES = openal_test1.cxx
|
||||
openal_test2_SOURCES = openal_test2.cxx
|
||||
|
||||
openal_test1_LDADD = \
|
||||
$(top_builddir)/simgear/debug/libsgdebug.a \
|
||||
$(openal_LIBS)
|
||||
|
||||
openal_test2_LDADD = \
|
||||
$(top_builddir)/simgear/sound/libsgsound.a \
|
||||
$(top_builddir)/simgear/debug/libsgdebug.a \
|
||||
$(top_builddir)/simgear/misc/libsgmisc.a \
|
||||
$(top_builddir)/simgear/structure/libsgstructure.a \
|
||||
$(openal_LIBS)
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
BIN
simgear/sound/jet.wav
Normal file
BIN
simgear/sound/jet.wav
Normal file
Binary file not shown.
144
simgear/sound/openal_test1.cxx
Normal file
144
simgear/sound/openal_test1.cxx
Normal file
@@ -0,0 +1,144 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// This is broken, but allows the file to compile without a POSIX
|
||||
// environment.
|
||||
static unsigned int sleep(unsigned int secs) { return 0; }
|
||||
#else
|
||||
#include <unistd.h> // sleep()
|
||||
#endif
|
||||
|
||||
#if defined( __APPLE__ )
|
||||
# define AL_ILLEGAL_ENUM AL_INVALID_ENUM
|
||||
# define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
|
||||
# include <OpenAL/al.h>
|
||||
# include <OpenAL/alut.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
# include <AL/alut.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
static void print_openal_error( ALuint error ) {
|
||||
if ( error == AL_INVALID_NAME ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_NAME" );
|
||||
} else if ( error == AL_ILLEGAL_ENUM ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_ENUM" );
|
||||
} else if ( error == AL_INVALID_VALUE ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_VALUE" );
|
||||
} else if ( error == AL_ILLEGAL_COMMAND ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_COMMAND" );
|
||||
} else if ( error == AL_OUT_OF_MEMORY ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_OUT_OF_MEMORY" );
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Unhandled error code = " << error );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char *argv[] ) {
|
||||
// initialize OpenAL
|
||||
alutInit( 0, NULL );
|
||||
alGetError();
|
||||
if ( alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
|
||||
}
|
||||
|
||||
// Position of the listener.
|
||||
ALfloat listener_pos[3];
|
||||
|
||||
// Velocity of the listener.
|
||||
ALfloat listener_vel[3];
|
||||
|
||||
// Orientation of the listener. (first 3 elements are "at", second
|
||||
// 3 are "up")
|
||||
ALfloat listener_ori[6];
|
||||
|
||||
listener_pos[0] = 0.0;
|
||||
listener_pos[1] = 0.0;
|
||||
listener_pos[2] = 0.0;
|
||||
|
||||
listener_vel[0] = 0.0;
|
||||
listener_vel[1] = 0.0;
|
||||
listener_vel[2] = 0.0;
|
||||
|
||||
listener_ori[0] = 0.0;
|
||||
listener_ori[1] = 0.0;
|
||||
listener_ori[2] = -1.0;
|
||||
listener_ori[3] = 0.0;
|
||||
listener_ori[4] = 1.0;
|
||||
listener_ori[5] = 0.0;
|
||||
|
||||
alListenerfv( AL_POSITION, listener_pos );
|
||||
alListenerfv( AL_VELOCITY, listener_vel );
|
||||
alListenerfv( AL_ORIENTATION, listener_ori );
|
||||
|
||||
// Buffers hold sound data.
|
||||
ALuint buffer;
|
||||
|
||||
// Sources are points emitting sound.
|
||||
ALuint source;
|
||||
|
||||
// Position of the source sound.
|
||||
ALfloat source_pos[3];
|
||||
|
||||
// Velocity of the source sound.
|
||||
ALfloat source_vel[3];
|
||||
|
||||
// configuration values
|
||||
ALenum format;
|
||||
ALsizei size;
|
||||
ALvoid* data;
|
||||
ALsizei freq;
|
||||
ALboolean loop;
|
||||
|
||||
source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0;
|
||||
source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0;
|
||||
|
||||
// create an OpenAL buffer handle
|
||||
alGenBuffers(1, &buffer);
|
||||
ALuint error = alGetError();
|
||||
if ( error != AL_NO_ERROR ) {
|
||||
print_openal_error( error );
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to gen OpenAL buffer." );
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Buffer created ok!" );
|
||||
}
|
||||
|
||||
// Load the sample file
|
||||
#if defined (__APPLE__)
|
||||
alutLoadWAVFile( (ALbyte *)"jet.wav", &format, &data, &size, &freq );
|
||||
#else
|
||||
alutLoadWAVFile( (ALbyte *)"jet.wav", &format, &data, &size, &freq, &loop );
|
||||
#endif
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to load wav file.");
|
||||
}
|
||||
|
||||
// Copy data to the internal OpenAL buffer
|
||||
alBufferData( buffer, format, data, size, freq );
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to buffer data.");
|
||||
}
|
||||
|
||||
alutUnloadWAV( format, data, size, freq );
|
||||
|
||||
alGenSources(1, &source);
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
print_openal_error( error );
|
||||
}
|
||||
|
||||
alSourcei( source, AL_BUFFER, buffer );
|
||||
alSourcef( source, AL_PITCH, 1.0 );
|
||||
alSourcef( source, AL_GAIN, 1.0 );
|
||||
alSourcefv( source, AL_POSITION, source_pos );
|
||||
alSourcefv( source, AL_VELOCITY, source_vel );
|
||||
alSourcei( source, AL_LOOPING, loop );
|
||||
|
||||
alSourcePlay( source );
|
||||
|
||||
sleep(10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
54
simgear/sound/openal_test2.cxx
Normal file
54
simgear/sound/openal_test2.cxx
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <stdio.h>
|
||||
#ifdef __MINGW32__
|
||||
// This is broken, but allows the file to compile without a POSIX
|
||||
// environment.
|
||||
static unsigned int sleep(unsigned int secs) { return 0; }
|
||||
#else
|
||||
#include <unistd.h> // sleep()
|
||||
#endif
|
||||
|
||||
#include "sample_openal.hxx"
|
||||
#include "soundmgr_openal.hxx"
|
||||
|
||||
|
||||
int main( int argc, char *argv[] ) {
|
||||
SGSoundMgr sm;
|
||||
|
||||
SGSoundSample sample1( ".", "jet.wav", true );
|
||||
sample1.set_volume(0.5);
|
||||
sample1.set_volume(0.2);
|
||||
sample1.play_looped();
|
||||
sleep(1);
|
||||
|
||||
SGSoundSample sample2( ".", "jet.wav", true );
|
||||
sample2.set_volume(0.5);
|
||||
sample2.set_pitch(0.4);
|
||||
sample2.play_looped();
|
||||
sleep(1);
|
||||
|
||||
SGSoundSample sample3( ".", "jet.wav", true );
|
||||
sample3.set_volume(0.5);
|
||||
sample3.set_pitch(0.8);
|
||||
sample3.play_looped();
|
||||
sleep(1);
|
||||
|
||||
SGSoundSample sample4( ".", "jet.wav", true );
|
||||
sample4.set_volume(0.5);
|
||||
sample4.set_pitch(1.2);
|
||||
sample4.play_looped();
|
||||
sleep(1);
|
||||
|
||||
SGSoundSample sample5( ".", "jet.wav", true );
|
||||
sample5.set_volume(0.5);
|
||||
sample5.set_pitch(1.6);
|
||||
sample5.play_looped();
|
||||
sleep(1);
|
||||
|
||||
SGSoundSample sample6( ".", "jet.wav", true );
|
||||
sample6.set_volume(0.5);
|
||||
sample6.set_pitch(2.0);
|
||||
sample6.play_looped();
|
||||
sleep(1);
|
||||
|
||||
sleep(10);
|
||||
}
|
||||
239
simgear/sound/sample_openal.cxx
Normal file
239
simgear/sound/sample_openal.cxx
Normal file
@@ -0,0 +1,239 @@
|
||||
// sample.cxx -- Sound sample encapsulation class
|
||||
//
|
||||
// Written by Curtis Olson, started April 2004.
|
||||
//
|
||||
// Copyright (C) 2004 Curtis L. Olson - curt@flightgear.org
|
||||
//
|
||||
// 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
#if defined( __APPLE__ )
|
||||
# define AL_ILLEGAL_ENUM AL_INVALID_ENUM
|
||||
# define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
|
||||
# include <OpenAL/al.h>
|
||||
# include <OpenAL/alut.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
# include <AL/alut.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include "sample_openal.hxx"
|
||||
|
||||
|
||||
//
|
||||
// SGSoundSample
|
||||
//
|
||||
|
||||
|
||||
static void print_openal_error( ALuint error ) {
|
||||
if ( error == AL_INVALID_NAME ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_NAME" );
|
||||
} else if ( error == AL_ILLEGAL_ENUM ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_ENUM" );
|
||||
} else if ( error == AL_INVALID_VALUE ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_VALUE" );
|
||||
} else if ( error == AL_ILLEGAL_COMMAND ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_COMMAND" );
|
||||
} else if ( error == AL_OUT_OF_MEMORY ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "AL_OUT_OF_MEMORY" );
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Unhandled error code = " << error );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// constructor
|
||||
SGSoundSample::SGSoundSample( const char *path, const char *file,
|
||||
bool cleanup ) :
|
||||
data(NULL),
|
||||
pitch(1.0),
|
||||
volume(1.0),
|
||||
reference_dist(500.0),
|
||||
max_dist(3000.),
|
||||
loop(AL_FALSE)
|
||||
{
|
||||
SGPath samplepath( path );
|
||||
if ( strlen(file) ) {
|
||||
samplepath.append( file );
|
||||
}
|
||||
|
||||
sample_name = samplepath.str();
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "From file sounds sample = "
|
||||
<< samplepath.str() );
|
||||
|
||||
source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0;
|
||||
offset_pos[0] = 0.0; offset_pos[1] = 0.0; offset_pos[2] = 0.0;
|
||||
source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0;
|
||||
direction[0] = 0.0; direction[1] = 0.0; direction[2] = 0.0;
|
||||
inner = outer = 360.0; outergain = 0.0;
|
||||
|
||||
// clear errors from elsewhere?
|
||||
alGetError();
|
||||
|
||||
// create an OpenAL buffer handle
|
||||
alGenBuffers(1, &buffer);
|
||||
ALuint error = alGetError();
|
||||
if ( error != AL_NO_ERROR ) {
|
||||
print_openal_error( error );
|
||||
throw sg_exception("Failed to gen OpenAL buffer.");
|
||||
}
|
||||
|
||||
// Load the sample file
|
||||
#if defined (__APPLE__)
|
||||
alutLoadWAVFile( (ALbyte *)samplepath.c_str(),
|
||||
&format, &data, &size, &freq );
|
||||
#else
|
||||
alutLoadWAVFile( (ALbyte *)samplepath.c_str(),
|
||||
&format, &data, &size, &freq, &loop );
|
||||
#endif
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
throw sg_exception("Failed to load wav file.");
|
||||
}
|
||||
|
||||
// Copy data to the internal OpenAL buffer
|
||||
alBufferData( buffer, format, data, size, freq );
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
throw sg_exception("Failed to buffer data.");
|
||||
}
|
||||
|
||||
if ( cleanup ) {
|
||||
alutUnloadWAV( format, data, size, freq );
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
// Bind buffer with a source.
|
||||
alGenSources(1, &source);
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
throw sg_exception("Failed to gen source.");
|
||||
}
|
||||
|
||||
alSourcei( source, AL_BUFFER, buffer );
|
||||
alSourcef( source, AL_PITCH, pitch );
|
||||
alSourcef( source, AL_GAIN, volume );
|
||||
alSourcefv( source, AL_POSITION, source_pos );
|
||||
alSourcefv( source, AL_DIRECTION, direction );
|
||||
alSourcef( source, AL_CONE_INNER_ANGLE, inner );
|
||||
alSourcef( source, AL_CONE_OUTER_ANGLE, outer );
|
||||
alSourcef( source, AL_CONE_OUTER_GAIN, outergain);
|
||||
alSourcefv( source, AL_VELOCITY, source_vel );
|
||||
alSourcei( source, AL_LOOPING, loop );
|
||||
|
||||
alSourcei( source, AL_SOURCE_RELATIVE, AL_TRUE );
|
||||
alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist );
|
||||
alSourcef( source, AL_MAX_DISTANCE, max_dist );
|
||||
}
|
||||
|
||||
|
||||
// constructor
|
||||
SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq,
|
||||
bool cleanup) :
|
||||
data(NULL),
|
||||
pitch(1.0),
|
||||
volume(1.0),
|
||||
reference_dist(500.0),
|
||||
max_dist(3000.),
|
||||
loop(AL_FALSE)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "In memory sounds sample" );
|
||||
|
||||
sample_name = "unknown, generated from data";
|
||||
|
||||
source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0;
|
||||
offset_pos[0] = 0.0; offset_pos[1] = 0.0; offset_pos[2] = 0.0;
|
||||
source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0;
|
||||
direction[0] = 0.0; direction[1] = 0.0; direction[2] = 0.0;
|
||||
inner = outer = 360.0; outergain = 0.0;
|
||||
|
||||
// clear errors from elsewhere?
|
||||
alGetError();
|
||||
|
||||
// Load wav data into a buffer.
|
||||
alGenBuffers(1, &buffer);
|
||||
ALuint error = alGetError();
|
||||
if ( error != AL_NO_ERROR ) {
|
||||
print_openal_error( error );
|
||||
throw sg_exception("Failed to gen buffer." );
|
||||
return;
|
||||
}
|
||||
|
||||
format = AL_FORMAT_MONO8;
|
||||
size = len;
|
||||
data = _data;
|
||||
freq = _freq;
|
||||
|
||||
alBufferData( buffer, format, data, size, freq );
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
throw sg_exception("Failed to buffer data.");
|
||||
}
|
||||
|
||||
if ( cleanup ) {
|
||||
alutUnloadWAV( format, data, size, freq );
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
// Bind buffer with a source.
|
||||
alGenSources(1, &source);
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
throw sg_exception("Failed to gen source.");
|
||||
}
|
||||
|
||||
alSourcei( source, AL_BUFFER, buffer );
|
||||
alSourcef( source, AL_PITCH, pitch );
|
||||
alSourcef( source, AL_GAIN, volume );
|
||||
alSourcefv( source, AL_POSITION, source_pos );
|
||||
alSourcefv( source, AL_DIRECTION, direction );
|
||||
alSourcef( source, AL_CONE_INNER_ANGLE, inner );
|
||||
alSourcef( source, AL_CONE_OUTER_ANGLE, outer );
|
||||
alSourcef( source, AL_CONE_OUTER_GAIN, outergain );
|
||||
alSourcefv( source, AL_VELOCITY, source_vel );
|
||||
alSourcei( source, AL_LOOPING, loop );
|
||||
|
||||
alSourcei( source, AL_SOURCE_RELATIVE, AL_TRUE );
|
||||
alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist );
|
||||
alSourcef( source, AL_MAX_DISTANCE, max_dist );
|
||||
}
|
||||
|
||||
|
||||
// destructor
|
||||
SGSoundSample::~SGSoundSample() {
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "Deleting a sample" );
|
||||
alDeleteSources(1, &source);
|
||||
alDeleteBuffers(1, &buffer);
|
||||
}
|
||||
|
||||
|
||||
// play the sample
|
||||
void SGSoundSample::play( bool _loop ) {
|
||||
loop = _loop;
|
||||
|
||||
// make sure sound isn't already playing
|
||||
alSourceStop( source );
|
||||
|
||||
alSourcei( source, AL_LOOPING, loop );
|
||||
alSourcePlay( source );
|
||||
}
|
||||
|
||||
|
||||
// stop playing the sample
|
||||
void SGSoundSample::stop() {
|
||||
alSourceStop( source );
|
||||
}
|
||||
295
simgear/sound/sample_openal.hxx
Normal file
295
simgear/sound/sample_openal.hxx
Normal file
@@ -0,0 +1,295 @@
|
||||
// sample.hxx -- Sound sample encapsulation class
|
||||
//
|
||||
// Written by Curtis Olson, started April 2004.
|
||||
//
|
||||
// Copyright (C) 2004 Curtis L. Olson - curt@flightgear.org
|
||||
//
|
||||
// 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/**
|
||||
* \file sample.hxx
|
||||
* Provides a sound sample encapsulation
|
||||
*/
|
||||
|
||||
#ifndef _SG_SAMPLE_HXX
|
||||
#define _SG_SAMPLE_HXX 1
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include STL_STRING
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <plib/sg.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define AL_ILLEGAL_ENUM AL_INVALID_ENUM
|
||||
# define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
|
||||
# include <OpenAL/al.h>
|
||||
# include <OpenAL/alut.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
# include <AL/alut.h>
|
||||
#endif
|
||||
|
||||
SG_USING_STD(string);
|
||||
|
||||
/**
|
||||
* manages everything we need to know for an individual sound sample
|
||||
*/
|
||||
|
||||
class SGSoundSample {
|
||||
|
||||
private:
|
||||
|
||||
string sample_name;
|
||||
|
||||
// Buffers hold sound data.
|
||||
ALuint buffer;
|
||||
|
||||
// Sources are points emitting sound.
|
||||
ALuint source;
|
||||
|
||||
// Position of the source sound.
|
||||
ALfloat source_pos[3];
|
||||
|
||||
// A constant offset to be applied to the final source_pos
|
||||
ALfloat offset_pos[3];
|
||||
|
||||
// The orientation of the sound (direction and cut-off angles)
|
||||
ALfloat direction[3];
|
||||
ALfloat inner, outer, outergain;
|
||||
|
||||
// Velocity of the source sound.
|
||||
ALfloat source_vel[3];
|
||||
|
||||
// configuration values
|
||||
ALenum format;
|
||||
ALsizei size;
|
||||
ALvoid* data;
|
||||
ALsizei freq;
|
||||
|
||||
double pitch;
|
||||
double volume;
|
||||
double reference_dist;
|
||||
double max_dist;
|
||||
ALboolean loop;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param path Path name to sound
|
||||
* @param file File name of sound
|
||||
* @param cleanup Request clean up the intermediate data (this
|
||||
should usually be true unless you want to manipulate the data
|
||||
later.)
|
||||
*/
|
||||
SGSoundSample( const char *path, const char *file, bool cleanup );
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param _data Pointer to a memory buffer containing the sample data
|
||||
* @param len Byte length of array
|
||||
* @param _freq Frequency of the provided data (bytes per second)
|
||||
* @param cleanup Request clean up the intermediate data (this
|
||||
should usually be true unless you want to manipulate the data
|
||||
later.)
|
||||
*/
|
||||
SGSoundSample( unsigned char *_data, int len, int _freq, bool cleanup );
|
||||
|
||||
~SGSoundSample();
|
||||
|
||||
/**
|
||||
* Start playing this sample.
|
||||
*
|
||||
* @param _loop Define wether the sound should be played in a loop.
|
||||
*/
|
||||
void play( bool _loop );
|
||||
|
||||
/**
|
||||
* Stop playing this sample.
|
||||
*
|
||||
* @param sched A pointer to the appropriate scheduler.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Play this sample once.
|
||||
* @see #play
|
||||
*/
|
||||
inline void play_once() { play(false); }
|
||||
|
||||
/**
|
||||
* Play this sample looped.
|
||||
* @see #play
|
||||
*/
|
||||
inline void play_looped() { play(true); }
|
||||
|
||||
/**
|
||||
* Test if a sample is curretnly playing.
|
||||
* @return true if is is playing, false otherwise.
|
||||
*/
|
||||
inline bool is_playing( ) {
|
||||
ALint result;
|
||||
alGetSourcei( source, AL_SOURCE_STATE, &result );
|
||||
if ( alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Oops AL error in sample is_playing(): " << sample_name );
|
||||
}
|
||||
return (result == AL_PLAYING) ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current pitch setting of this sample.
|
||||
*/
|
||||
inline double get_pitch() const { return pitch; }
|
||||
|
||||
/**
|
||||
* Set the pitch of this sample.
|
||||
*/
|
||||
inline void set_pitch( double p ) {
|
||||
// clamp in the range of 0.01 to 2.0
|
||||
if ( p < 0.01 ) { p = 0.01; }
|
||||
if ( p > 2.0 ) { p = 2.0; }
|
||||
pitch = p;
|
||||
alSourcef( source, AL_PITCH, pitch );
|
||||
if ( alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Oops AL error in sample set_pitch()! " << p
|
||||
<< " for " << sample_name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current volume setting of this sample.
|
||||
*/
|
||||
inline double get_volume() const { return volume; }
|
||||
|
||||
/**
|
||||
* Set the volume of this sample.
|
||||
*/
|
||||
inline void set_volume( double v ) {
|
||||
volume = v;
|
||||
alSourcef( source, AL_GAIN, volume );
|
||||
if ( alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Oops AL error in sample set_volume()! " << v
|
||||
<< " for " << sample_name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the sounds sample
|
||||
*/
|
||||
inline int get_size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pointer to the raw data
|
||||
*/
|
||||
inline char *get_data() {
|
||||
return (char *)data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set position of sound source (uses same coordinate system as opengl)
|
||||
*/
|
||||
inline void set_source_pos( ALfloat *pos ) {
|
||||
source_pos[0] = pos[0];
|
||||
source_pos[1] = pos[1];
|
||||
source_pos[2] = pos[2];
|
||||
|
||||
sgVec3 final_pos;
|
||||
sgAddVec3( final_pos, source_pos, offset_pos );
|
||||
|
||||
alSourcefv( source, AL_POSITION, final_pos );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set "constant" offset position of sound source (uses same
|
||||
* coordinate system as opengl)
|
||||
*/
|
||||
inline void set_offset_pos( ALfloat *pos ) {
|
||||
offset_pos[0] = pos[0];
|
||||
offset_pos[1] = pos[1];
|
||||
offset_pos[2] = pos[2];
|
||||
|
||||
sgVec3 final_pos;
|
||||
sgAddVec3( final_pos, source_pos, offset_pos );
|
||||
|
||||
alSourcefv( source, AL_POSITION, final_pos );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the orientation of the sound source, both for direction
|
||||
* and audio cut-off angles.
|
||||
*/
|
||||
inline void set_orientation( ALfloat *dir, ALfloat inner_angle=360.0,
|
||||
ALfloat outer_angle=360.0,
|
||||
ALfloat outer_gain=0.0)
|
||||
{
|
||||
inner = inner_angle;
|
||||
outer = outer_angle;
|
||||
outergain = outer_gain;
|
||||
alSourcefv( source, AL_DIRECTION, dir);
|
||||
alSourcef( source, AL_CONE_INNER_ANGLE, inner );
|
||||
alSourcef( source, AL_CONE_OUTER_ANGLE, outer );
|
||||
alSourcef( source, AL_CONE_OUTER_GAIN, outergain );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set velocity of sound source (uses same coordinate system as opengl)
|
||||
*/
|
||||
inline void set_source_vel( ALfloat *vel ) {
|
||||
source_vel[0] = vel[0];
|
||||
source_vel[1] = vel[1];
|
||||
source_vel[2] = vel[2];
|
||||
alSourcefv( source, AL_VELOCITY, source_vel );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set reference distance of sound (the distance where the gain
|
||||
* will be half.)
|
||||
*/
|
||||
inline void set_reference_dist( ALfloat dist ) {
|
||||
reference_dist = dist;
|
||||
alSourcef( source, AL_REFERENCE_DISTANCE, reference_dist );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set maximume distance of sound (the distance where the sound is
|
||||
* no longer audible.
|
||||
*/
|
||||
inline void set_max_dist( ALfloat dist ) {
|
||||
max_dist = dist;
|
||||
alSourcef( source, AL_MAX_DISTANCE, max_dist );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // _SG_SAMPLE_HXX
|
||||
|
||||
|
||||
@@ -1,416 +0,0 @@
|
||||
// soundmgr.cxx -- Sound effect management class
|
||||
//
|
||||
// Sound manager initially written by David Findlay
|
||||
// <david_j_findlay@yahoo.com.au> 2001
|
||||
//
|
||||
// C++-ified by Curtis Olson, started March 2001.
|
||||
//
|
||||
// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
|
||||
//
|
||||
// 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include "soundmgr.hxx"
|
||||
|
||||
#define SOUND_SAFETY_MULT 3
|
||||
#define MAX_SOUND_SAFETY ( 1.0 / SOUND_SAFETY_MULT )
|
||||
|
||||
//
|
||||
// SGSimpleSound
|
||||
//
|
||||
|
||||
// constructor
|
||||
SGSimpleSound::SGSimpleSound( const char *path, const char *file )
|
||||
: sample(NULL),
|
||||
pitch_envelope(NULL),
|
||||
volume_envelope(NULL),
|
||||
pitch(1.0),
|
||||
volume(1.0)
|
||||
{
|
||||
SGPath slfile( path );
|
||||
if ( file )
|
||||
slfile.append( file );
|
||||
|
||||
sample = new slSample ( slfile.c_str() );
|
||||
pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
||||
volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
||||
pitch_envelope->setStep ( 0, 0.01, 1.0 );
|
||||
volume_envelope->setStep ( 0, 0.01, 1.0 );
|
||||
}
|
||||
|
||||
SGSimpleSound::SGSimpleSound( unsigned char *buffer, int len )
|
||||
: pitch(1.0),
|
||||
volume(1.0)
|
||||
{
|
||||
sample = new slSample ( buffer, len );
|
||||
pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
||||
volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
|
||||
pitch_envelope->setStep ( 0, 0.01, 1.0 );
|
||||
volume_envelope->setStep ( 0, 0.01, 1.0 );
|
||||
}
|
||||
|
||||
// destructor
|
||||
SGSimpleSound::~SGSimpleSound() {
|
||||
delete pitch_envelope;
|
||||
delete volume_envelope;
|
||||
delete sample;
|
||||
}
|
||||
|
||||
void SGSimpleSound::play( slScheduler *sched, bool looped ) {
|
||||
|
||||
// make sure sound isn't already playing
|
||||
if ( sample->getPlayCount() > 0 ) {
|
||||
sched->stopSample(sample);
|
||||
// return;
|
||||
}
|
||||
|
||||
if ( looped ) {
|
||||
sched->loopSample(sample);
|
||||
} else {
|
||||
sched->playSample(sample);
|
||||
}
|
||||
|
||||
sched->addSampleEnvelope(sample, 0, 0, pitch_envelope, SL_PITCH_ENVELOPE);
|
||||
sched->addSampleEnvelope(sample, 0, 1, volume_envelope, SL_VOLUME_ENVELOPE);
|
||||
}
|
||||
|
||||
void SGSimpleSound::stop( slScheduler *sched ) {
|
||||
|
||||
sched->stopSample( sample );
|
||||
}
|
||||
|
||||
//
|
||||
// Sound Manager
|
||||
//
|
||||
|
||||
// constructor
|
||||
SGSoundMgr::SGSoundMgr() {
|
||||
audio_sched = new slScheduler( 8000 );
|
||||
if ( audio_sched->notWorking() ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
|
||||
} else {
|
||||
audio_sched -> setMaxConcurrent ( SL_MAX_MIXERINPUTS );
|
||||
|
||||
audio_mixer = new smMixer;
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_INFO,
|
||||
"Rate = " << audio_sched->getRate()
|
||||
<< " Bps = " << audio_sched->getBps()
|
||||
<< " Stereo = " << audio_sched->getStereo() );
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
|
||||
SGSoundMgr::~SGSoundMgr() {
|
||||
|
||||
//
|
||||
// Remove the samples from the sample manager.
|
||||
//
|
||||
sample_map_iterator sample_current = samples.begin();
|
||||
sample_map_iterator sample_end = samples.end();
|
||||
for ( ; sample_current != sample_end; ++sample_current ) {
|
||||
sample_ref *sr = sample_current->second;
|
||||
|
||||
audio_sched->stopSample(sr->sample);
|
||||
delete sr->sample;
|
||||
delete sr;
|
||||
}
|
||||
|
||||
//
|
||||
// Remove the sounds from the sound manager.
|
||||
//
|
||||
sound_map_iterator sound_current = sounds.begin();
|
||||
sound_map_iterator sound_end = sounds.end();
|
||||
for ( ; sound_current != sound_end; ++sound_current ) {
|
||||
SGSimpleSound *s = sound_current->second;
|
||||
|
||||
audio_sched->stopSample(s->get_sample());
|
||||
delete s->get_sample();
|
||||
delete s;
|
||||
}
|
||||
|
||||
delete audio_sched;
|
||||
delete audio_mixer;
|
||||
}
|
||||
|
||||
|
||||
// initialize the sound manager
|
||||
void SGSoundMgr::init() {
|
||||
safety = MAX_SOUND_SAFETY;
|
||||
|
||||
// audio_mixer -> setMasterVolume ( 80 ) ; /* 80% of max volume. */
|
||||
audio_sched -> setSafetyMargin ( SOUND_SAFETY_MULT * safety ) ;
|
||||
|
||||
|
||||
//
|
||||
// Remove the samples from the sample manager.
|
||||
//
|
||||
sample_map_iterator sample_current = samples.begin();
|
||||
sample_map_iterator sample_end = samples.end();
|
||||
for ( ; sample_current != sample_end; ++sample_current ) {
|
||||
sample_ref *sr = sample_current->second;
|
||||
|
||||
audio_sched->stopSample(sr->sample);
|
||||
delete sr->sample;
|
||||
delete sr;
|
||||
}
|
||||
samples.clear();
|
||||
|
||||
//
|
||||
// Remove the sounds from the sound manager.
|
||||
//
|
||||
sound_map_iterator sound_current = sounds.begin();
|
||||
sound_map_iterator sound_end = sounds.end();
|
||||
for ( ; sound_current != sound_end; ++sound_current ) {
|
||||
SGSimpleSound *s = sound_current->second;
|
||||
|
||||
audio_sched->stopSample(s->get_sample());
|
||||
delete s->get_sample();
|
||||
delete s;
|
||||
}
|
||||
sounds.clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SGSoundMgr::bind ()
|
||||
{
|
||||
// no properties yet
|
||||
}
|
||||
|
||||
|
||||
void SGSoundMgr::unbind ()
|
||||
{
|
||||
// no properties yet
|
||||
}
|
||||
|
||||
|
||||
// run the audio scheduler
|
||||
void SGSoundMgr::update( double dt ) {
|
||||
if ( dt > safety ) {
|
||||
safety = dt;
|
||||
} else {
|
||||
safety = safety * 0.99 + dt * 0.01;
|
||||
}
|
||||
if ( safety > MAX_SOUND_SAFETY ) {
|
||||
safety = MAX_SOUND_SAFETY;
|
||||
}
|
||||
// cout << "safety = " << safety << endl;
|
||||
audio_sched -> setSafetyMargin ( SOUND_SAFETY_MULT * safety ) ;
|
||||
|
||||
if ( !audio_sched->not_working() )
|
||||
audio_sched -> update();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SGSoundMgr::pause ()
|
||||
{
|
||||
audio_sched->pauseSample(0, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SGSoundMgr::resume ()
|
||||
{
|
||||
audio_sched->resumeSample(0, 0);
|
||||
}
|
||||
|
||||
|
||||
// add a sound effect, return true if successful
|
||||
bool SGSoundMgr::add( SGSimpleSound *sound, const string& refname ) {
|
||||
|
||||
sound_map_iterator sound_it = sounds.find( refname );
|
||||
if ( sound_it != sounds.end() ) {
|
||||
// sound already exists
|
||||
return false;
|
||||
}
|
||||
|
||||
sample_map_iterator sample_it = samples.find( refname );
|
||||
if ( sample_it != samples.end() ) {
|
||||
// this sound has existed in the past and it's sample is still
|
||||
// here, delete the sample so we can replace it.
|
||||
samples.erase( sample_it );
|
||||
}
|
||||
|
||||
sample_ref *sr = new sample_ref;
|
||||
|
||||
sr->n=1;
|
||||
sr->sample = sound->get_sample();
|
||||
samples[refname] = sr;
|
||||
|
||||
sounds[refname] = sound;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// add a sound from a file, return the sample if successful, else return NULL
|
||||
SGSimpleSound *SGSoundMgr::add( const string &refname,
|
||||
const char *path, const char *file ) {
|
||||
SGSimpleSound *sound;
|
||||
|
||||
SGPath slfile( path );
|
||||
if ( file )
|
||||
slfile.append( file );
|
||||
|
||||
if ( slfile.str().empty() )
|
||||
return NULL;
|
||||
|
||||
sample_map_iterator it = samples.find(slfile.str());
|
||||
if (it == samples.end()) {
|
||||
|
||||
sound = new SGSimpleSound(slfile.c_str());
|
||||
sounds[refname] = sound;
|
||||
|
||||
sample_ref *sr = new sample_ref;
|
||||
|
||||
sr->n=1;
|
||||
sr->sample = sound->get_sample();
|
||||
samples[slfile.str()] = sr;
|
||||
|
||||
} else {
|
||||
sample_ref *sr = it->second;
|
||||
|
||||
sr->n++;
|
||||
sound =
|
||||
new SGSimpleSound(sr->sample->getBuffer(), sr->sample->getLength());
|
||||
sounds[refname] = sound;
|
||||
|
||||
}
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
|
||||
// remove a sound effect, return true if successful
|
||||
bool SGSoundMgr::remove( const string &refname ) {
|
||||
|
||||
sound_map_iterator it = sounds.find( refname );
|
||||
if ( it != sounds.end() ) {
|
||||
// first stop the sound from playing (so we don't bomb the
|
||||
// audio scheduler)
|
||||
SGSimpleSound *sample = it->second;
|
||||
|
||||
// cout << "Playing " << sample->get_sample()->getPlayCount()
|
||||
// << " instances!" << endl;
|
||||
|
||||
audio_sched->stopSample( sample->get_sample() );
|
||||
audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0,
|
||||
NULL,
|
||||
SL_PITCH_ENVELOPE );
|
||||
audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1,
|
||||
NULL,
|
||||
SL_VOLUME_ENVELOPE );
|
||||
|
||||
// must call audio_sched->update() after stopping the sound
|
||||
// but before deleting it.
|
||||
audio_sched -> update();
|
||||
// cout << "Still playing " << sample->get_sample()->getPlayCount()
|
||||
// << " instances!" << endl;
|
||||
|
||||
//
|
||||
// FIXME:
|
||||
// Due to the change in the sound manager, samples live
|
||||
// until the sound manager gets removed.
|
||||
//
|
||||
// delete sample;
|
||||
sounds.erase( it );
|
||||
|
||||
// cout << "sndmgr: removed -> " << refname << endl;
|
||||
return true;
|
||||
} else {
|
||||
// cout << "sndmgr: failed remove -> " << refname << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// return true of the specified sound exists in the sound manager system
|
||||
bool SGSoundMgr::exists( const string &refname ) {
|
||||
sound_map_iterator it = sounds.find( refname );
|
||||
if ( it != sounds.end() ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// return a pointer to the SGSimpleSound if the specified sound exists
|
||||
// in the sound manager system, otherwise return NULL
|
||||
SGSimpleSound *SGSoundMgr::find( const string &refname ) {
|
||||
sound_map_iterator it = sounds.find( refname );
|
||||
if ( it != sounds.end() ) {
|
||||
return it->second;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// tell the scheduler to play the indexed sample in a continuous
|
||||
// loop
|
||||
bool SGSoundMgr::play_looped( const string &refname ) {
|
||||
SGSimpleSound *sample;
|
||||
|
||||
if ((sample = find( refname )) == NULL)
|
||||
return false;
|
||||
|
||||
sample->play(audio_sched, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// tell the scheduler to play the indexed sample once
|
||||
bool SGSoundMgr::play_once( const string& refname ) {
|
||||
SGSimpleSound *sample;
|
||||
|
||||
if ((sample = find( refname )) == NULL)
|
||||
return false;
|
||||
|
||||
sample->play(audio_sched, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// return true of the specified sound is currently being played
|
||||
bool SGSoundMgr::is_playing( const string& refname ) {
|
||||
SGSimpleSound *sample;
|
||||
|
||||
if ((sample = find( refname )) == NULL)
|
||||
return false;
|
||||
|
||||
return (sample->get_sample()->getPlayCount() > 0 );
|
||||
}
|
||||
|
||||
|
||||
// immediate stop playing the sound
|
||||
bool SGSoundMgr::stop( const string& refname ) {
|
||||
SGSimpleSound *sample;
|
||||
|
||||
if ((sample = find( refname )) == NULL)
|
||||
return false;
|
||||
|
||||
audio_sched->stopSample( sample->get_sample() );
|
||||
return true;
|
||||
}
|
||||
@@ -1,296 +0,0 @@
|
||||
// soundmgr.hxx -- Sound effect management class
|
||||
//
|
||||
// Sound manager initially written by David Findlay
|
||||
// <david_j_findlay@yahoo.com.au> 2001
|
||||
//
|
||||
// C++-ified by Curtis Olson, started March 2001.
|
||||
//
|
||||
// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
|
||||
//
|
||||
// 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/**
|
||||
* \file soundmgr.hxx
|
||||
* Provides a sound manager class to keep track of
|
||||
* multiple sounds and manage playing them with different effects and
|
||||
* timings.
|
||||
*/
|
||||
|
||||
#ifndef _SG_SOUNDMGR_HXX
|
||||
#define _SG_SOUNDMGR_HXX 1
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
|
||||
#include STL_STRING
|
||||
#include <map>
|
||||
|
||||
#include <plib/sl.h>
|
||||
#include <plib/sm.h>
|
||||
|
||||
SG_USING_STD(map);
|
||||
SG_USING_STD(string);
|
||||
|
||||
|
||||
/**
|
||||
* manages everything we need to know for an individual sound sample
|
||||
*/
|
||||
class SGSimpleSound {
|
||||
|
||||
private:
|
||||
|
||||
slSample *sample;
|
||||
slEnvelope *pitch_envelope;
|
||||
slEnvelope *volume_envelope;
|
||||
double pitch;
|
||||
double volume;
|
||||
|
||||
public:
|
||||
|
||||
SGSimpleSound( const char *path, const char *file = NULL );
|
||||
SGSimpleSound( unsigned char *buffer, int len );
|
||||
~SGSimpleSound();
|
||||
|
||||
/**
|
||||
* Start playing this sample.
|
||||
*
|
||||
* @param sched A pointer to the appropriate scheduler.
|
||||
* @param looped Define wether the sound should be played in a loop.
|
||||
*/
|
||||
void play( slScheduler *sched, bool looped );
|
||||
|
||||
/**
|
||||
* Stop playing this sample.
|
||||
*
|
||||
* @param sched A pointer to the appropriate scheduler.
|
||||
*/
|
||||
void stop( slScheduler *sched );
|
||||
|
||||
/**
|
||||
* Play this sample once.
|
||||
* @see #play
|
||||
*/
|
||||
inline void play_once( slScheduler *sched ) { play( sched, false); }
|
||||
|
||||
/**
|
||||
* Play this sample looped.
|
||||
* @see #play
|
||||
*/
|
||||
inline void play_looped( slScheduler *sched ) { play( sched, true); }
|
||||
|
||||
/**
|
||||
* Test if a sample is curretnly playing.
|
||||
* @return true if is is playing, false otherwise.
|
||||
*/
|
||||
inline bool is_playing( ) {
|
||||
return ( sample->getPlayCount() > 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current pitch setting of this sample.
|
||||
*/
|
||||
inline double get_pitch() const { return pitch; }
|
||||
|
||||
/**
|
||||
* Set the pitch of this sample.
|
||||
*/
|
||||
inline void set_pitch( double p ) {
|
||||
pitch = p;
|
||||
pitch_envelope->setStep( 0, 0.01, pitch );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current volume setting of this sample.
|
||||
*/
|
||||
inline double get_volume() const { return volume; }
|
||||
|
||||
/**
|
||||
* Set the volume of this sample.
|
||||
*/
|
||||
inline void set_volume( double v ) {
|
||||
volume = v;
|
||||
volume_envelope->setStep( 0, 0.01, volume );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a refference to the raw sample.
|
||||
*/
|
||||
inline slSample *get_sample() { return sample; }
|
||||
|
||||
/**
|
||||
* Get the pitch envelope setting of this sample.
|
||||
*/
|
||||
inline slEnvelope *get_pitch_envelope() { return pitch_envelope; }
|
||||
|
||||
/**
|
||||
* Get the volume envelope setting of this sample.
|
||||
*/
|
||||
inline slEnvelope *get_volume_envelope() { return volume_envelope; }
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
int n;
|
||||
slSample *sample;
|
||||
} sample_ref;
|
||||
|
||||
typedef map < string, sample_ref * > sample_map;
|
||||
typedef sample_map::iterator sample_map_iterator;
|
||||
typedef sample_map::const_iterator const_sample_map_iterator;
|
||||
|
||||
typedef map < string, SGSimpleSound * > sound_map;
|
||||
typedef sound_map::iterator sound_map_iterator;
|
||||
typedef sound_map::const_iterator const_sound_map_iterator;
|
||||
|
||||
|
||||
/**
|
||||
* Manage a collection of SGSimpleSound instances
|
||||
*/
|
||||
class SGSoundMgr
|
||||
{
|
||||
|
||||
slScheduler *audio_sched;
|
||||
smMixer *audio_mixer;
|
||||
|
||||
sound_map sounds;
|
||||
sample_map samples;
|
||||
|
||||
double safety;
|
||||
|
||||
public:
|
||||
|
||||
SGSoundMgr();
|
||||
~SGSoundMgr();
|
||||
|
||||
|
||||
/**
|
||||
* (re) initialize the sound manager.
|
||||
*/
|
||||
void init();
|
||||
|
||||
|
||||
/**
|
||||
* Bind properties for the sound manager.
|
||||
*/
|
||||
void bind ();
|
||||
|
||||
|
||||
/**
|
||||
* Unbind properties for the sound manager.
|
||||
*/
|
||||
void unbind ();
|
||||
|
||||
|
||||
/**
|
||||
* Run the audio scheduler.
|
||||
*/
|
||||
void update(double dt);
|
||||
|
||||
|
||||
/**
|
||||
* Pause all sounds.
|
||||
*/
|
||||
void pause ();
|
||||
|
||||
|
||||
/**
|
||||
* Resume all sounds.
|
||||
*/
|
||||
void resume ();
|
||||
|
||||
|
||||
/**
|
||||
* is audio working?
|
||||
*/
|
||||
inline bool is_working() const { return !audio_sched->notWorking(); }
|
||||
|
||||
/**
|
||||
* reinitialize the sound manager
|
||||
*/
|
||||
inline void reinit() { init(); }
|
||||
|
||||
/**
|
||||
* add a sound effect, return true if successful
|
||||
*/
|
||||
bool add( SGSimpleSound *sound, const string& refname);
|
||||
|
||||
/**
|
||||
* Add a sound file to the sound manager.
|
||||
*
|
||||
* The advantage of using this function over the previous one is that
|
||||
* it doesn't load a sample if it already is in memory, but instead it
|
||||
* uses the already loaded sample data.
|
||||
*
|
||||
* @param refname A refference name to make a distincion between samples.
|
||||
* @param path The path or full filename of the sample to load.
|
||||
* @param file An optional filename which will be appended to the path.
|
||||
* @return An instance of the sound for further manipulation.
|
||||
*/
|
||||
SGSimpleSound *add( const string& refname,
|
||||
const char *path, const char *file = NULL );
|
||||
|
||||
/**
|
||||
* remove a sound effect, return true if successful
|
||||
*/
|
||||
bool remove( const string& refname );
|
||||
|
||||
/**
|
||||
* return true of the specified sound exists in the sound manager system
|
||||
*/
|
||||
bool exists( const string& refname );
|
||||
|
||||
/**
|
||||
* return a pointer to the SGSimpleSound if the specified sound
|
||||
* exists in the sound manager system, otherwise return NULL
|
||||
*/
|
||||
SGSimpleSound *find( const string& refname );
|
||||
|
||||
/**
|
||||
* tell the scheduler to play the indexed sample in a continuous
|
||||
* loop
|
||||
*/
|
||||
bool play_looped( const string& refname );
|
||||
|
||||
/**
|
||||
* tell the scheduler to play the indexed sample once
|
||||
*/
|
||||
bool play_once( const string& refname );
|
||||
|
||||
/**
|
||||
* return true of the specified sound is currently being played
|
||||
*/
|
||||
bool is_playing( const string& refname );
|
||||
|
||||
/**
|
||||
* immediate stop playing the sound
|
||||
*/
|
||||
bool stop( const string& refname );
|
||||
|
||||
/**
|
||||
* return the audio scheduler
|
||||
*/
|
||||
inline slScheduler *get_scheduler( ) { return audio_sched; };
|
||||
};
|
||||
|
||||
|
||||
#endif // _SG_SOUNDMGR_HXX
|
||||
|
||||
|
||||
318
simgear/sound/soundmgr_openal.cxx
Normal file
318
simgear/sound/soundmgr_openal.cxx
Normal file
@@ -0,0 +1,318 @@
|
||||
// soundmgr.cxx -- Sound effect management class
|
||||
//
|
||||
// Sound manager initially written by David Findlay
|
||||
// <david_j_findlay@yahoo.com.au> 2001
|
||||
//
|
||||
// C++-ified by Curtis Olson, started March 2001.
|
||||
//
|
||||
// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
|
||||
//
|
||||
// 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <OpenAL/al.h>
|
||||
# include <OpenAL/alut.h>
|
||||
# include <OpenAL/alc.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
# include <AL/alut.h>
|
||||
# include <AL/alc.h>
|
||||
#endif
|
||||
|
||||
#if defined (__APPLE__)
|
||||
// any C++ header file undefines isinf and isnan
|
||||
// so this should be included before <iostream>
|
||||
inline int (isinf)(double r) { return isinf(r); }
|
||||
inline int (isnan)(double r) { return isnan(r); }
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
#define isnan(x) _isnan(x)
|
||||
#endif
|
||||
|
||||
#include STL_IOSTREAM
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include "soundmgr_openal.hxx"
|
||||
|
||||
|
||||
//
|
||||
// Sound Manager
|
||||
//
|
||||
|
||||
// constructor
|
||||
SGSoundMgr::SGSoundMgr() {
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "Initializing OpenAL sound manager" );
|
||||
|
||||
// initialize OpenAL
|
||||
alutInit( 0, NULL );
|
||||
alGetError();
|
||||
if ( alGetError() == AL_NO_ERROR) {
|
||||
working = true;
|
||||
} else {
|
||||
working = false;
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
|
||||
}
|
||||
|
||||
listener_pos[0] = 0.0;
|
||||
listener_pos[1] = 0.0;
|
||||
listener_pos[2] = 0.0;
|
||||
|
||||
listener_vel[0] = 0.0;
|
||||
listener_vel[1] = 0.0;
|
||||
listener_vel[2] = 0.0;
|
||||
|
||||
listener_ori[0] = 0.0;
|
||||
listener_ori[1] = 0.0;
|
||||
listener_ori[2] = -1.0;
|
||||
listener_ori[3] = 0.0;
|
||||
listener_ori[4] = 1.0;
|
||||
listener_ori[5] = 0.0;
|
||||
|
||||
alListenerfv( AL_POSITION, listener_pos );
|
||||
alListenerfv( AL_VELOCITY, listener_vel );
|
||||
alListenerfv( AL_ORIENTATION, listener_ori );
|
||||
alGetError();
|
||||
if ( alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Oops AL error after audio initialization!" );
|
||||
}
|
||||
|
||||
// exaggerate the ear candy?
|
||||
alDopplerFactor(1.0);
|
||||
alDopplerVelocity(340.0); // speed of sound in meters per second.
|
||||
}
|
||||
|
||||
// destructor
|
||||
|
||||
SGSoundMgr::~SGSoundMgr() {
|
||||
|
||||
//
|
||||
// Remove the samples from the sample manager.
|
||||
//
|
||||
sample_map_iterator sample_current = samples.begin();
|
||||
sample_map_iterator sample_end = samples.end();
|
||||
for ( ; sample_current != sample_end; ++sample_current ) {
|
||||
SGSoundSample *sample = sample_current->second;
|
||||
delete sample;
|
||||
}
|
||||
|
||||
alutExit();
|
||||
}
|
||||
|
||||
|
||||
// initialize the sound manager
|
||||
void SGSoundMgr::init() {
|
||||
//
|
||||
// Remove the samples from the sample manager.
|
||||
//
|
||||
sample_map_iterator sample_current = samples.begin();
|
||||
sample_map_iterator sample_end = samples.end();
|
||||
for ( ; sample_current != sample_end; ++sample_current ) {
|
||||
SGSoundSample *sample = sample_current->second;
|
||||
delete sample;
|
||||
}
|
||||
samples.clear();
|
||||
}
|
||||
|
||||
|
||||
void SGSoundMgr::bind ()
|
||||
{
|
||||
// no properties
|
||||
}
|
||||
|
||||
|
||||
void SGSoundMgr::unbind ()
|
||||
{
|
||||
// no properties
|
||||
}
|
||||
|
||||
|
||||
// run the audio scheduler
|
||||
void SGSoundMgr::update( double dt ) {
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SGSoundMgr::pause ()
|
||||
{
|
||||
ALCcontext *pCurContext = alcGetCurrentContext();
|
||||
alcSuspendContext( pCurContext );
|
||||
if ( alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Oops AL error after soundmgr pause()!" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SGSoundMgr::resume ()
|
||||
{
|
||||
ALCcontext *pCurContext = alcGetCurrentContext();
|
||||
alcProcessContext( pCurContext );
|
||||
if ( alGetError() != AL_NO_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Oops AL error after soundmgr resume()!" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add a sound effect, return true if successful
|
||||
bool SGSoundMgr::add( SGSoundSample *sound, const string& refname ) {
|
||||
|
||||
sample_map_iterator sample_it = samples.find( refname );
|
||||
if ( sample_it != samples.end() ) {
|
||||
// sound already exists
|
||||
return false;
|
||||
}
|
||||
|
||||
samples[refname] = sound;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// remove a sound effect, return true if successful
|
||||
bool SGSoundMgr::remove( const string &refname ) {
|
||||
|
||||
sample_map_iterator sample_it = samples.find( refname );
|
||||
if ( sample_it != samples.end() ) {
|
||||
// first stop the sound from playing (so we don't bomb the
|
||||
// audio scheduler)
|
||||
SGSoundSample *sample = sample_it->second;
|
||||
delete sample;
|
||||
samples.erase( sample_it );
|
||||
|
||||
// cout << "sndmgr: removed -> " << refname << endl;
|
||||
return true;
|
||||
} else {
|
||||
// cout << "sndmgr: failed remove -> " << refname << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// return true of the specified sound exists in the sound manager system
|
||||
bool SGSoundMgr::exists( const string &refname ) {
|
||||
sample_map_iterator sample_it = samples.find( refname );
|
||||
if ( sample_it != samples.end() ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// return a pointer to the SGSoundSample if the specified sound exists
|
||||
// in the sound manager system, otherwise return NULL
|
||||
SGSoundSample *SGSoundMgr::find( const string &refname ) {
|
||||
sample_map_iterator sample_it = samples.find( refname );
|
||||
if ( sample_it != samples.end() ) {
|
||||
return sample_it->second;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// tell the scheduler to play the indexed sample in a continuous
|
||||
// loop
|
||||
bool SGSoundMgr::play_looped( const string &refname ) {
|
||||
SGSoundSample *sample;
|
||||
|
||||
if ( (sample = find( refname )) == NULL ) {
|
||||
return false;
|
||||
} else {
|
||||
sample->play( true );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// tell the scheduler to play the indexed sample once
|
||||
bool SGSoundMgr::play_once( const string& refname ) {
|
||||
SGSoundSample *sample;
|
||||
|
||||
if ( (sample = find( refname )) == NULL ) {
|
||||
return false;
|
||||
} else {
|
||||
sample->play( false );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// return true of the specified sound is currently being played
|
||||
bool SGSoundMgr::is_playing( const string& refname ) {
|
||||
SGSoundSample *sample;
|
||||
|
||||
if ( (sample = find( refname )) == NULL ) {
|
||||
return false;
|
||||
} else {
|
||||
return ( sample->is_playing() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// immediate stop playing the sound
|
||||
bool SGSoundMgr::stop( const string& refname ) {
|
||||
SGSoundSample *sample;
|
||||
|
||||
if ( (sample = find( refname )) == NULL ) {
|
||||
return false;
|
||||
} else {
|
||||
sample->stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// set source position of all managed sounds
|
||||
void SGSoundMgr::set_source_pos_all( ALfloat *pos ) {
|
||||
if ( isnan(pos[0]) || isnan(pos[1]) || isnan(pos[2]) ) {
|
||||
// bail if a bad position is passed in
|
||||
return;
|
||||
}
|
||||
|
||||
sample_map_iterator sample_current = samples.begin();
|
||||
sample_map_iterator sample_end = samples.end();
|
||||
for ( ; sample_current != sample_end; ++sample_current ) {
|
||||
SGSoundSample *sample = sample_current->second;
|
||||
sample->set_source_pos( pos );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// set source velocity of all managed sounds
|
||||
void SGSoundMgr::set_source_vel_all( ALfloat *vel ) {
|
||||
if ( isnan(vel[0]) || isnan(vel[1]) || isnan(vel[2]) ) {
|
||||
// bail if a bad velocity is passed in
|
||||
return;
|
||||
}
|
||||
|
||||
sample_map_iterator sample_current = samples.begin();
|
||||
sample_map_iterator sample_end = samples.end();
|
||||
for ( ; sample_current != sample_end; ++sample_current ) {
|
||||
SGSoundSample *sample = sample_current->second;
|
||||
sample->set_source_vel( vel );
|
||||
}
|
||||
}
|
||||
242
simgear/sound/soundmgr_openal.hxx
Normal file
242
simgear/sound/soundmgr_openal.hxx
Normal file
@@ -0,0 +1,242 @@
|
||||
// soundmgr.hxx -- Sound effect management class
|
||||
//
|
||||
// Sound manager initially written by David Findlay
|
||||
// <david_j_findlay@yahoo.com.au> 2001
|
||||
//
|
||||
// C++-ified by Curtis Olson, started March 2001.
|
||||
//
|
||||
// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
|
||||
//
|
||||
// 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/**
|
||||
* \file soundmgr.hxx
|
||||
* Provides a sound manager class to keep track of
|
||||
* multiple sounds and manage playing them with different effects and
|
||||
* timings.
|
||||
*/
|
||||
|
||||
#ifndef _SG_SOUNDMGR_OPENAL_HXX
|
||||
#define _SG_SOUNDMGR_OPENAL_HXX 1
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include STL_STRING
|
||||
#include <map>
|
||||
|
||||
#if defined( __APPLE__ )
|
||||
# include <OpenAL/al.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
#endif
|
||||
|
||||
#include "sample_openal.hxx"
|
||||
|
||||
SG_USING_STD(map);
|
||||
SG_USING_STD(string);
|
||||
|
||||
|
||||
typedef map < string, SGSoundSample * > sample_map;
|
||||
typedef sample_map::iterator sample_map_iterator;
|
||||
typedef sample_map::const_iterator const_sample_map_iterator;
|
||||
|
||||
|
||||
/**
|
||||
* Manage a collection of SGSoundSample instances
|
||||
*/
|
||||
class SGSoundMgr
|
||||
{
|
||||
|
||||
// Position of the listener.
|
||||
ALfloat listener_pos[3];
|
||||
|
||||
// Velocity of the listener.
|
||||
ALfloat listener_vel[3];
|
||||
|
||||
// Orientation of the listener. (first 3 elements are "at", second
|
||||
// 3 are "up")
|
||||
ALfloat listener_ori[6];
|
||||
|
||||
sample_map samples;
|
||||
|
||||
bool working;
|
||||
double safety;
|
||||
|
||||
public:
|
||||
|
||||
SGSoundMgr();
|
||||
~SGSoundMgr();
|
||||
|
||||
|
||||
/**
|
||||
* (re) initialize the sound manager.
|
||||
*/
|
||||
void init();
|
||||
|
||||
|
||||
/**
|
||||
* Bind properties for the sound manager.
|
||||
*/
|
||||
void bind();
|
||||
|
||||
|
||||
/**
|
||||
* Unbind properties for the sound manager.
|
||||
*/
|
||||
void unbind();
|
||||
|
||||
|
||||
/**
|
||||
* Run the audio scheduler.
|
||||
*/
|
||||
void update(double dt);
|
||||
|
||||
|
||||
/**
|
||||
* Pause all sounds.
|
||||
*/
|
||||
void pause();
|
||||
|
||||
|
||||
/**
|
||||
* Resume all sounds.
|
||||
*/
|
||||
void resume();
|
||||
|
||||
|
||||
/**
|
||||
* is audio working?
|
||||
*/
|
||||
inline bool is_working() const { return working; }
|
||||
|
||||
/**
|
||||
* reinitialize the sound manager
|
||||
*/
|
||||
inline void reinit() { init(); }
|
||||
|
||||
/**
|
||||
* add a sound effect, return true if successful
|
||||
*/
|
||||
bool add( SGSoundSample *sound, const string& refname);
|
||||
|
||||
/**
|
||||
* remove a sound effect, return true if successful
|
||||
*/
|
||||
bool remove( const string& refname );
|
||||
|
||||
/**
|
||||
* return true of the specified sound exists in the sound manager system
|
||||
*/
|
||||
bool exists( const string& refname );
|
||||
|
||||
/**
|
||||
* return a pointer to the SGSoundSample if the specified sound
|
||||
* exists in the sound manager system, otherwise return NULL
|
||||
*/
|
||||
SGSoundSample *find( const string& refname );
|
||||
|
||||
/**
|
||||
* tell the scheduler to play the indexed sample in a continuous
|
||||
* loop
|
||||
*/
|
||||
bool play_looped( const string& refname );
|
||||
|
||||
/**
|
||||
* tell the scheduler to play the indexed sample once
|
||||
*/
|
||||
bool play_once( const string& refname );
|
||||
|
||||
/**
|
||||
* return true of the specified sound is currently being played
|
||||
*/
|
||||
bool is_playing( const string& refname );
|
||||
|
||||
/**
|
||||
* immediate stop playing the sound
|
||||
*/
|
||||
bool stop( const string& refname );
|
||||
|
||||
/**
|
||||
* set overall volume for the application.
|
||||
* @param vol 1.0 is default, must be greater than 0
|
||||
*/
|
||||
inline void set_volume( const ALfloat vol ) {
|
||||
if ( vol > 0.0 ) {
|
||||
alListenerf( AL_GAIN, vol );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the position of the listener (in opengl coordinates)
|
||||
*/
|
||||
inline void set_listener_pos( ALfloat *pos ) {
|
||||
listener_pos[0] = pos[0];
|
||||
listener_pos[1] = pos[1];
|
||||
listener_pos[2] = pos[2];
|
||||
alListenerfv( AL_POSITION, listener_pos );
|
||||
}
|
||||
|
||||
/**
|
||||
* set the velocity of the listener (in opengl coordinates)
|
||||
*/
|
||||
inline void set_listener_vel( ALfloat *vel ) {
|
||||
listener_vel[0] = vel[0];
|
||||
listener_vel[1] = vel[1];
|
||||
listener_vel[2] = vel[2];
|
||||
alListenerfv( AL_VELOCITY, listener_vel );
|
||||
}
|
||||
|
||||
/**
|
||||
* set the orientation of the listener (in opengl coordinates)
|
||||
*
|
||||
* Description: ORIENTATION is a pair of 3-tuples representing the
|
||||
* 'at' direction vector and 'up' direction of the Object in
|
||||
* Cartesian space. AL expects two vectors that are orthogonal to
|
||||
* each other. These vectors are not expected to be normalized. If
|
||||
* one or more vectors have zero length, implementation behavior
|
||||
* is undefined. If the two vectors are linearly dependent,
|
||||
* behavior is undefined.
|
||||
*/
|
||||
inline void set_listener_orientation( ALfloat *ori ) {
|
||||
listener_ori[0] = ori[0];
|
||||
listener_ori[1] = ori[1];
|
||||
listener_ori[2] = ori[2];
|
||||
listener_ori[3] = ori[3];
|
||||
listener_ori[4] = ori[4];
|
||||
listener_ori[5] = ori[5];
|
||||
alListenerfv( AL_ORIENTATION, listener_ori );
|
||||
}
|
||||
|
||||
/**
|
||||
* set the positions of all managaged sound sources
|
||||
*/
|
||||
void set_source_pos_all( ALfloat *pos );
|
||||
|
||||
/**
|
||||
* set the velocities of all managaged sound sources
|
||||
*/
|
||||
void set_source_vel_all( ALfloat *pos );
|
||||
};
|
||||
|
||||
|
||||
#endif // _SG_SOUNDMGR_OPENAL_HXX
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <simgear/math/fastmath.hxx>
|
||||
|
||||
|
||||
#include "sound.hxx"
|
||||
#include "xmlsound.hxx"
|
||||
|
||||
|
||||
// static double _snd_lin(double v) { return v; }
|
||||
@@ -62,13 +62,13 @@ static const struct {
|
||||
{"", NULL}
|
||||
};
|
||||
|
||||
SGSound::SGSound()
|
||||
SGXmlSound::SGXmlSound()
|
||||
: _sample(NULL),
|
||||
_condition(NULL),
|
||||
_property(NULL),
|
||||
_active(false),
|
||||
_name(""),
|
||||
_mode(SGSound::ONCE),
|
||||
_mode(SGXmlSound::ONCE),
|
||||
_prev_value(0),
|
||||
_dt_play(0.0),
|
||||
_dt_stop(0.0),
|
||||
@@ -76,24 +76,24 @@ SGSound::SGSound()
|
||||
{
|
||||
}
|
||||
|
||||
SGSound::~SGSound()
|
||||
SGXmlSound::~SGXmlSound()
|
||||
{
|
||||
_mgr->get_scheduler()->stopSample(_sample->get_sample());
|
||||
_sample->stop();
|
||||
|
||||
if (_property)
|
||||
delete _property;
|
||||
if (_property)
|
||||
delete _property;
|
||||
|
||||
if (_condition)
|
||||
delete _condition;
|
||||
if (_condition)
|
||||
delete _condition;
|
||||
|
||||
_volume.clear();
|
||||
_pitch.clear();
|
||||
delete _sample;
|
||||
_volume.clear();
|
||||
_pitch.clear();
|
||||
delete _sample;
|
||||
}
|
||||
|
||||
void
|
||||
SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
|
||||
const string &path)
|
||||
SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
|
||||
const string &path)
|
||||
{
|
||||
|
||||
//
|
||||
@@ -105,13 +105,13 @@ SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
|
||||
|
||||
const char *mode_str = node->getStringValue("mode", "");
|
||||
if ( !strcmp(mode_str, "looped") ) {
|
||||
_mode = SGSound::LOOPED;
|
||||
_mode = SGXmlSound::LOOPED;
|
||||
|
||||
} else if ( !strcmp(mode_str, "in-transit") ) {
|
||||
_mode = SGSound::IN_TRANSIT;
|
||||
_mode = SGXmlSound::IN_TRANSIT;
|
||||
|
||||
} else {
|
||||
_mode = SGSound::ONCE;
|
||||
_mode = SGXmlSound::ONCE;
|
||||
|
||||
if ( strcmp(mode_str, "") )
|
||||
SG_LOG(SG_GENERAL,SG_INFO, " Unknown sound mode, default to 'once'");
|
||||
@@ -132,7 +132,7 @@ SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
|
||||
unsigned int i;
|
||||
float v = 0.0;
|
||||
vector<SGPropertyNode_ptr> kids = node->getChildren("volume");
|
||||
for (i = 0; (i < kids.size()) && (i < SGSound::MAXPROP); i++) {
|
||||
for (i = 0; (i < kids.size()) && (i < SGXmlSound::MAXPROP); i++) {
|
||||
_snd_prop volume = {NULL, NULL, NULL, 1.0, 0.0, 0.0, 0.0, false};
|
||||
|
||||
if (strcmp(kids[i]->getStringValue("property"), ""))
|
||||
@@ -180,13 +180,15 @@ SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
|
||||
|
||||
}
|
||||
|
||||
|
||||
float reference_dist = node->getDoubleValue("reference-dist", 500.0);
|
||||
float max_dist = node->getDoubleValue("max-dist", 3000.0);
|
||||
|
||||
//
|
||||
// set pitch properties
|
||||
//
|
||||
float p = 0.0;
|
||||
kids = node->getChildren("pitch");
|
||||
for (i = 0; (i < kids.size()) && (i < SGSound::MAXPROP); i++) {
|
||||
for (i = 0; (i < kids.size()) && (i < SGXmlSound::MAXPROP); i++) {
|
||||
_snd_prop pitch = {NULL, NULL, NULL, 1.0, 1.0, 0.0, 0.0, false};
|
||||
|
||||
if (strcmp(kids[i]->getStringValue("property", ""), ""))
|
||||
@@ -233,19 +235,59 @@ SGSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
|
||||
p += pitch.offset;
|
||||
}
|
||||
|
||||
//
|
||||
// Relative position
|
||||
//
|
||||
sgVec3 offset_pos;
|
||||
sgSetVec3( offset_pos, 0.0, 0.0, 0.0 );
|
||||
SGPropertyNode_ptr pos = node->getChild("position");
|
||||
if ( pos != NULL ) {
|
||||
offset_pos[0] = pos->getDoubleValue("x", 0.0);
|
||||
offset_pos[1] = pos->getDoubleValue("y", 0.0);
|
||||
offset_pos[2] = pos->getDoubleValue("z", 0.0);
|
||||
}
|
||||
|
||||
//
|
||||
// Orientation
|
||||
//
|
||||
sgVec3 dir;
|
||||
float inner, outer, outer_gain;
|
||||
sgSetVec3( dir, 0.0, 0.0, 0.0 );
|
||||
inner = outer = 360.0;
|
||||
outer_gain = 0.0;
|
||||
pos = node->getChild("orientation");
|
||||
if ( pos != NULL ) {
|
||||
dir[0] = pos->getDoubleValue("x", 0.0);
|
||||
dir[1] = pos->getDoubleValue("y", 0.0);
|
||||
dir[2] = pos->getDoubleValue("z", 0.0);
|
||||
inner = pos->getDoubleValue("inner-angle", 360.0);
|
||||
outer = pos->getDoubleValue("outer-angle", 360.0);
|
||||
outer_gain = pos->getDoubleValue("outer-gain", 0.0);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Initialize the sample
|
||||
//
|
||||
_mgr = sndmgr;
|
||||
if ((_sample = _mgr->find(_name)) == NULL)
|
||||
_sample = _mgr->add(_name, path.c_str(), node->getStringValue("path", ""));
|
||||
if ( (_sample = _mgr->find(_name)) == NULL ) {
|
||||
_sample = new SGSoundSample( path.c_str(),
|
||||
node->getStringValue("path", ""),
|
||||
true );
|
||||
|
||||
_mgr->add( _sample, _name );
|
||||
}
|
||||
|
||||
_sample->set_offset_pos( offset_pos );
|
||||
_sample->set_orientation(dir, inner, outer, outer_gain);
|
||||
_sample->set_volume(v);
|
||||
_sample->set_reference_dist( reference_dist );
|
||||
_sample->set_max_dist( max_dist );
|
||||
_sample->set_pitch(p);
|
||||
}
|
||||
|
||||
void
|
||||
SGSound::update (double dt)
|
||||
SGXmlSound::update (double dt)
|
||||
{
|
||||
double curr_value = 0.0;
|
||||
|
||||
@@ -260,17 +302,17 @@ SGSound::update (double dt)
|
||||
(!_condition && _property &&
|
||||
(
|
||||
!curr_value ||
|
||||
( (_mode == SGSound::IN_TRANSIT) && (curr_value == _prev_value) )
|
||||
( (_mode == SGXmlSound::IN_TRANSIT) && (curr_value == _prev_value) )
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
if ((_mode != SGSound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME)) {
|
||||
if ((_mode != SGXmlSound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME)) {
|
||||
if (_sample->is_playing()) {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "Stopping audio after " << _dt_play
|
||||
<< " sec: " << _name );
|
||||
|
||||
_sample->stop( _mgr->get_scheduler() );
|
||||
_sample->stop();
|
||||
}
|
||||
|
||||
_active = false;
|
||||
@@ -287,7 +329,7 @@ SGSound::update (double dt)
|
||||
// If the mode is ONCE and the sound is still playing,
|
||||
// we have nothing to do anymore.
|
||||
//
|
||||
if (_active && (_mode == SGSound::ONCE)) {
|
||||
if (_active && (_mode == SGXmlSound::ONCE)) {
|
||||
|
||||
if (!_sample->is_playing()) {
|
||||
_dt_stop += dt;
|
||||
@@ -384,7 +426,14 @@ SGSound::update (double dt)
|
||||
// Change sample state
|
||||
//
|
||||
_sample->set_pitch( pitch_offset + pitch );
|
||||
_sample->set_volume( volume_offset + volume );
|
||||
if ((volume_offset + volume ) > 1.0)
|
||||
{
|
||||
_sample->set_volume( 1.0 );
|
||||
SG_LOG(SG_GENERAL, SG_WARN,
|
||||
"Volume larger than 1.0 in configuration for '" << _name
|
||||
<< "', clipping.");
|
||||
} else
|
||||
_sample->set_volume( volume_offset + volume );
|
||||
|
||||
|
||||
//
|
||||
@@ -392,11 +441,11 @@ SGSound::update (double dt)
|
||||
//
|
||||
if (!_active) {
|
||||
|
||||
if (_mode == SGSound::ONCE)
|
||||
_sample->play(_mgr->get_scheduler(), false);
|
||||
if (_mode == SGXmlSound::ONCE)
|
||||
_sample->play(false);
|
||||
|
||||
else
|
||||
_sample->play(_mgr->get_scheduler(), true);
|
||||
_sample->play(true);
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "Playing audio after " << _dt_stop
|
||||
<< " sec: " << _name);
|
||||
@@ -36,7 +36,8 @@
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/props/condition.hxx>
|
||||
|
||||
#include "soundmgr.hxx"
|
||||
#include "sample_openal.hxx"
|
||||
#include "soundmgr_openal.hxx"
|
||||
|
||||
static const double MAX_TRANSIT_TIME = 0.1; // 100 ms.
|
||||
|
||||
@@ -49,13 +50,13 @@ static const double MAX_TRANSIT_TIME = 0.1; // 100 ms.
|
||||
* settings, setting up its internal states, and managing sound
|
||||
* playback whenever such an event happens.
|
||||
*/
|
||||
class SGSound
|
||||
class SGXmlSound
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
SGSound();
|
||||
virtual ~SGSound();
|
||||
SGXmlSound();
|
||||
virtual ~SGXmlSound();
|
||||
|
||||
/**
|
||||
* Initialize the sound event.
|
||||
@@ -117,7 +118,7 @@ protected:
|
||||
enum { ONCE=0, LOOPED, IN_TRANSIT };
|
||||
enum { LEVEL=0, INVERTED, FLIPFLOP };
|
||||
|
||||
// SGSound properties
|
||||
// SGXmlSound properties
|
||||
typedef struct {
|
||||
SGPropertyNode * prop;
|
||||
double (*fn)(double);
|
||||
@@ -132,7 +133,7 @@ protected:
|
||||
private:
|
||||
|
||||
SGSoundMgr * _mgr;
|
||||
SGSimpleSound * _sample;
|
||||
SGSoundSample * _sample;
|
||||
|
||||
SGCondition * _condition;
|
||||
SGPropertyNode * _property;
|
||||
@@ -59,7 +59,14 @@ SGTimerQueue::SGTimerQueue(int size)
|
||||
|
||||
SGTimerQueue::~SGTimerQueue()
|
||||
{
|
||||
for(int i=0; i<_numEntries; i++) {
|
||||
delete _table[i].timer;
|
||||
_table[i].timer = 0;
|
||||
}
|
||||
_numEntries = 0;
|
||||
delete[] _table;
|
||||
_table = 0;
|
||||
_tableSize = 0;
|
||||
}
|
||||
|
||||
void SGTimerQueue::update(double deltaSecs)
|
||||
|
||||
@@ -63,6 +63,7 @@ class SGEventMgr : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
SGEventMgr() { _freezeProp = 0; }
|
||||
~SGEventMgr() { _freezeProp = 0; }
|
||||
|
||||
virtual void init() {}
|
||||
virtual void update(double delta_time_sec);
|
||||
|
||||
@@ -61,6 +61,13 @@ public:
|
||||
*/
|
||||
virtual T pop() = 0;
|
||||
|
||||
/**
|
||||
* Query the size of the queue
|
||||
*
|
||||
* @return size_t size of queue.
|
||||
*/
|
||||
virtual size_t size() = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
*
|
||||
@@ -93,7 +100,7 @@ public:
|
||||
*/
|
||||
virtual bool empty() {
|
||||
SGGuard<SGLOCK> g(mutex);
|
||||
return fifo.empty();
|
||||
return this->fifo.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +110,7 @@ public:
|
||||
*/
|
||||
virtual void push( const T& item ) {
|
||||
SGGuard<SGLOCK> g(mutex);
|
||||
fifo.push( item );
|
||||
this->fifo.push( item );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,8 +120,8 @@ public:
|
||||
*/
|
||||
virtual T front() {
|
||||
SGGuard<SGLOCK> g(mutex);
|
||||
assert( ! fifo.empty() );
|
||||
T item = fifo.front();
|
||||
assert( ! this->fifo.empty() );
|
||||
T item = this->fifo.front();
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -126,16 +133,27 @@ public:
|
||||
virtual T pop() {
|
||||
SGGuard<SGLOCK> g(mutex);
|
||||
//if (fifo.empty()) throw NoSuchElementException();
|
||||
assert( ! fifo.empty() );
|
||||
assert( ! this->fifo.empty() );
|
||||
// if (fifo.empty())
|
||||
// {
|
||||
// mutex.unlock();
|
||||
// pthread_exit( PTHREAD_CANCELED );
|
||||
// }
|
||||
T item = fifo.front();
|
||||
fifo.pop();
|
||||
T item = this->fifo.front();
|
||||
this->fifo.pop();
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the size of the queue
|
||||
*
|
||||
* @return size_t size of queue.
|
||||
*/
|
||||
virtual size_t size() {
|
||||
SGGuard<SGLOCK> g(mutex);
|
||||
return this->fifo.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
@@ -172,7 +190,7 @@ public:
|
||||
*/
|
||||
virtual bool empty() {
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
return fifo.empty();
|
||||
return this->fifo.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,7 +200,7 @@ public:
|
||||
*/
|
||||
virtual void push( const T& item ) {
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
fifo.push( item );
|
||||
this->fifo.push( item );
|
||||
not_empty.signal();
|
||||
}
|
||||
|
||||
@@ -195,10 +213,10 @@ public:
|
||||
virtual T front() {
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
|
||||
assert(fifo.empty() != true);
|
||||
assert(this->fifo.empty() != true);
|
||||
//if (fifo.empty()) throw ??
|
||||
|
||||
T item = fifo.front();
|
||||
T item = this->fifo.front();
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -211,17 +229,27 @@ public:
|
||||
virtual T pop() {
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
|
||||
while (fifo.empty())
|
||||
while (this->fifo.empty())
|
||||
not_empty.wait(mutex);
|
||||
|
||||
assert(fifo.empty() != true);
|
||||
assert(this->fifo.empty() != true);
|
||||
//if (fifo.empty()) throw ??
|
||||
|
||||
T item = fifo.front();
|
||||
fifo.pop();
|
||||
T item = this->fifo.front();
|
||||
this->fifo.pop();
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the size of the queue
|
||||
*
|
||||
* @return size_t size of queue.
|
||||
*/
|
||||
virtual size_t size() {
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
return this->fifo.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "xmlparse.h"
|
||||
|
||||
#include STL_FSTREAM
|
||||
#include STL_IOSTREAM
|
||||
|
||||
SG_USING_STD(ifstream);
|
||||
|
||||
@@ -273,4 +274,27 @@ readXML (const string &path, XMLVisitor &visitor)
|
||||
input.close();
|
||||
}
|
||||
|
||||
void
|
||||
readXML (const char *buf, const int size, XMLVisitor &visitor)
|
||||
{
|
||||
XML_Parser parser = XML_ParserCreate(0);
|
||||
XML_SetUserData(parser, &visitor);
|
||||
XML_SetElementHandler(parser, start_element, end_element);
|
||||
XML_SetCharacterDataHandler(parser, character_data);
|
||||
XML_SetProcessingInstructionHandler(parser, processing_instruction);
|
||||
|
||||
visitor.startXML();
|
||||
|
||||
if (!XML_Parse(parser, buf, size, false)) {
|
||||
XML_ParserFree(parser);
|
||||
throw sg_io_exception(XML_ErrorString(XML_GetErrorCode(parser)),
|
||||
sg_location("In-memory XML buffer",
|
||||
XML_GetCurrentLineNumber(parser),
|
||||
XML_GetCurrentColumnNumber(parser)),
|
||||
"SimGear XML Parser");
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
|
||||
// end of easyxml.cxx
|
||||
|
||||
@@ -401,5 +401,27 @@ extern void readXML (istream &input, XMLVisitor &visitor,
|
||||
extern void readXML (const string &path, XMLVisitor &visitor);
|
||||
|
||||
|
||||
/**
|
||||
* @relates XMLVisitor
|
||||
* Read an XML document.
|
||||
*
|
||||
* This function reads an XML document from the buffer provided,
|
||||
* and invokes the callback methods in the visitor object to pass the
|
||||
* parsing events back to the application. When this function
|
||||
* returns, the parser will have reported all of the data in the XML
|
||||
* document to the application through the visitor callback methods,
|
||||
* and XML processing will be complete.
|
||||
*
|
||||
* @param buf The xml data buffer.
|
||||
* @param size The size of the data buffer in bytes
|
||||
* @param visitor An object that contains callbacks for XML parsing
|
||||
* events.
|
||||
* @exception Throws sg_io_exception or sg_xml_exception if there
|
||||
* is a problem reading the file.
|
||||
* @see XMLVisitor
|
||||
*/
|
||||
extern void readXML (const char *buf, const int size, XMLVisitor &visitor);
|
||||
|
||||
|
||||
#endif // __EASYXML_HXX
|
||||
|
||||
|
||||
Reference in New Issue
Block a user