Compare commits

...

106 Commits

Author SHA1 Message Date
curt
9a2ee54389 Final 0.3.7 changes. 2004-10-12 14:35:42 +00:00
ehofman
ab69c03698 Fix a typo. 2004-10-11 07:56:08 +00:00
ehofman
fab1f4e7a0 Frederic: Ignore display lists when using the blend animation. 2004-10-11 07:37:42 +00:00
ehofman
41eed484c1 Adding the panel was a step too far for Linux, causing a segfault. 2004-10-10 19:38:46 +00:00
ehofman
7d18f9bdde Remove a phantom makeDList call (probably an old one from my code. 2004-10-10 19:16:25 +00:00
ehofman
3a48c3de7a Check for the plib version when using display lists, just to be sure. 2004-10-10 19:05:25 +00:00
ehofman
d769a9936b Frederic: Include FGPanelNode in the display list generation process. 2004-10-10 18:43:11 +00:00
ehofman
1697cb3b1a Frederic: Use display lists for 3d models also. 2004-10-10 17:49:27 +00:00
ehofman
62aa32a417 Reverse the declaration order. jpgRenderFrame (formerly known as trRenderFrame) is now declared as a NULL function pointer and assignment of the proper function is now done in FlightGear (jpgRenderFrame=FGRenderer::update). 2004-10-06 09:57:31 +00:00
ehofman
a0d0852838 David Luff:
The one-liner removes a lot of re-definition warnings on Cygwin.
2004-09-30 09:43:11 +00:00
ehofman
2f479cae69 Small update for future use. 2004-09-19 09:08:12 +00:00
curt
4820d57fa8 Expose the size() method for locked and blocking thread queues. 2004-09-15 15:28:58 +00:00
curt
04e3b0b3c1 Fix another case where the direction vector is not initialized which can
lead to openal "inrange" assertions, crashing FlightGear.
2004-09-15 15:28:14 +00:00
curt
a7f78b9f68 direction vector needs to be initialized, otherwise garbage data could cause
openal to generate an assertion, aborting the top level app.
2004-09-10 20:44:42 +00:00
curt
f3d8eb4665 Tweaks for 0.3.7-pre1 2004-09-10 18:16:06 +00:00
curt
090f79b951 Add support for parsing an xml stream from an in memory buffer, rather than
just from a specified file name.
2004-09-10 15:57:52 +00:00
ehofman
88c0dbf661 Add support for audio orientation: direction and cone definition. This currently only works for internal view and tower view because those set the listener position correctly. 2004-09-08 11:15:57 +00:00
ehofman
9e3822ceaf Remove a left over of ancient times. 2004-08-19 12:18:20 +00:00
ehofman
007b0a8fe6 this simple patch will enable the direct use of Point3D::get_n() instead of making duplications to call sgCartToGeod 2004-08-17 08:31:51 +00:00
ehofman
7f0ebf8871 this simple patch will prevent to have fog in Clear cload layers. 2004-08-17 08:28:35 +00:00
ehofman
5414e94a1a change the log level of the initialization of OpenAL. This prevent a console popup for no reason on Windows. 2004-08-15 09:24:12 +00:00
curt
461dee8657 Tweaks for official 0.3.6 release. 2004-07-29 21:36:41 +00:00
ehofman
297b6193fe Make gcc 2.95.* compile again. 2004-07-29 08:30:10 +00:00
ehofman
4b74e40a5f Use the SimGear default notation. 2004-07-28 14:13:16 +00:00
ehofman
5a9b08dec2 IRIX fixes (at least). 2004-07-28 13:59:57 +00:00
ehofman
5e6f9f79a2 IRIX fix (at least). 2004-07-28 13:16:54 +00:00
curt
e2f93e6ae1 Tweaks for 0.3.6-pre3 2004-07-27 21:18:14 +00:00
curt
93314b59fb Fix a minor warning message. 2004-07-24 19:21:15 +00:00
ehofman
29269c6686 Correct a typo that produces segfault during cleanup on some systems. 2004-07-22 08:04:18 +00:00
curt
3c84b6e2f6 Tweaks for 0.3.6-pre2 2004-07-21 21:22:21 +00:00
ehofman
04fb708543 Frederic Bouvier:
I just discovered this : state() is not valid when _level==0,
because it is doing:
{ return _state_stack[_state_stack.size() - 1]; }
and is returning a wrong index fetch ( 0 - 1 ) == -1

Moreover, st is not used when _level==0 so the line can be moved
to a safer place.
2004-07-21 10:52:40 +00:00
ehofman
df302f277c Test for alutInit in libopenal.so and in libalut.so for Cygwin builds. 2004-07-19 14:59:51 +00:00
ehofman
5e63e663bb alut is now part of libopenal.so 2004-07-17 14:01:00 +00:00
ehofman
ca10cb2d37 Weak excuse, but it's getting late. Do clipping right this time. 2004-07-16 21:00:46 +00:00
ehofman
c9854153f8 Clip to volume to 1.0 if necessary. 2004-07-16 20:36:01 +00:00
curt
129e3c6326 Tweaks in preparation for the 0.3.6-pre1 release. 2004-07-14 22:01:15 +00:00
ehofman
66996711ae Make sure that a directory name containing a '.' doesn't screw up the ::base() and ::extension() functions. 2004-07-05 16:39:02 +00:00
ehofman
8fe37cea51 Remove the need to append a trailing / to the texture-path string. 2004-07-05 13:40:37 +00:00
ehofman
de64b6f267 Allow the use of a <texture-path/> tag to specify the directory containing the textures for this model. 2004-07-05 11:42:19 +00:00
ehofman
9a9d9c7cc1 Use #elif instead of #else if 2004-07-03 11:16:53 +00:00
ehofman
a191e9762a Frederic Bouvier:
I have 3 issues that are fixed by this set of patches.

1. In extensions.cxx
  #else if !defined( WIN32 )  must be changed by
  #elif !defined( WIN32 ) because the text after #else
  seems to be ignored

2. banner is not available on windows, only cygwin

3. ANSI escape sequences are not interpreted on the
   windows console. We just have garbage that is hard
   to read.
2004-07-03 10:59:00 +00:00
curt
a7b35c6e22 If we pass in a position or velocity of nan, openal will generate an assertion.
Under rare circumstances we could encounter a non-cooperative external fdm
that could trigger this condition.  This patch catches the problem and returns
rather than letting FG get killed.
2004-07-01 19:05:37 +00:00
ehofman
5034346b67 Some small updates. 2004-06-27 08:09:56 +00:00
ehofman
661f64b902 Work around a broken dlopen/dlclose Linux implementation. 2004-06-27 07:49:40 +00:00
ehofman
bbc83f721c Frederic Bouvier:
this patch correct the cloud repositionning that
made them going against the wind. Now the clouds
and the windsock show the same direction.
2004-06-25 10:59:59 +00:00
david
01f4541331 Ignore generated files. 2004-06-15 12:47:52 +00:00
ehofman
0e4a894f62 Be a bit anoying (and a tad more descriptive) about OpenAL volume errors for some time. 2004-06-13 11:59:36 +00:00
ehofman
1c135a9b5b Frederic Bouvier:
Do state sorting by material before adding primitives
in the tile branch. I thought I could see a bit of
improvement in framerate but it is not the case on my setup.
I don't see a degradation though
2004-06-12 21:03:45 +00:00
ehofman
e65c85ce73 Frederic Bouvier:
I am still experimenting with the
code. Here is so far the best I could achieve. The
dark aspect of clouds at dusk or dawn is far better
than the problems of transparency of the previous
version.
2004-06-07 18:49:32 +00:00
ehofman
26b58991f9 MingW fix. 2004-06-07 12:43:29 +00:00
ehofman
8390df37ca Add an 'add(str)' function that adds a search path separator and appends the str. 2004-06-07 09:50:32 +00:00
ehofman
371fc73f24 Tweak the doppler effect. 2004-06-04 16:59:12 +00:00
ehofman
921dae5444 Revert the previous patch. There was already a class availble that allows for that. It's just that the description doesn't explain too much. 2004-05-28 08:42:59 +00:00
ehofman
9b3abbec89 Tweak the bump-mapped 2d cloud color a bit. 2004-05-27 18:00:03 +00:00
ehofman
6935baba5b Add the possibillity to parse a user data pointer to getter and satter functions. This adds a convenient way to get the 'this' pointer to the static functions. 2004-05-27 13:03:01 +00:00
ehofman
dec1e32f96 Use a different coloring scheme. 2004-05-25 07:58:33 +00:00
ehofman
710c2ccfcd MacOSX fix that never got applied before. 2004-05-21 16:27:16 +00:00
ehofman
8e66e534ae mingw32 fix 2004-05-21 15:07:25 +00:00
ehofman
0f5f30b993 Updates from Frederic to use 2 texture units and a color blend function rather than 3 texture units. 2004-05-21 14:50:49 +00:00
ehofman
b199f733f7 Frederic Bouvier:
Melchior spotted a problem where we can crash an airplane into the
beacon's beam. The patch below enable to mask out a branch from HOT
traversal, whatever the animation.

The beacon.xml file is also included. It has a
<enable-hot type="bool">false</enable-hot> in a halo branch
2004-05-20 14:18:15 +00:00
ehofman
0cdcf3a3e0 Make sure there will be no previous declaration errors. 2004-05-20 14:02:40 +00:00
ehofman
8e09486e82 Patch from Frederic. Adds support for bump-mapped (multi textured) 2d clouds, includeing support code. 2004-05-20 13:24:48 +00:00
ehofman
0c24b78573 Fred: include more check against null pointers and a raise in log level for missing objects. 2004-05-15 12:45:51 +00:00
ehofman
1436be9699 Solve the endless loop problem for the DC-3 and prevent a potential segmentation fault. 2004-05-14 19:46:12 +00:00
curt
0489ad7c62 Add a function to globally set volume (aka AL_GAIN) 2004-05-14 15:47:01 +00:00
curt
c553570533 Oops, fix a typo. 2004-05-11 22:39:21 +00:00
curt
bda112297f Frederic Bouvier:
I was not very happy with the size of the halo, so
I created a new animation to control it. Now we can
control the scale value with the distance from the
viewer to the object. The towers are now beginning to
look good. They might need some tuning though. If
you want to play, locate in radio-*.xml this code :

 <animation>
  <type>dist-scale</type>
  <object-name>RedLight.2</object-name>
  <interpolation>
   <entry><ind>0</ind><dep>0.1</dep></entry>
   <entry><ind>500</ind><dep>0.3</dep></entry>
   <entry><ind>16000</ind><dep>3</dep></entry>
  </interpolation>
 </animation>

You get the idea ? ind is the distance, dep is the
resulting scale value.
The medium tower appears brighter than the tall one,
because the lights are closer to each other. Maybe
they need a smaller scale factor at distance. Feel
free to modify these values if you find a better
setup.

About the code : I renamed flash to custtrans because the
ssg branch is now less specialized. It needs a callback
to compute the so called 'custom transformation'. It can
be used for the SGFlashAnimation and the new
SGDistScaleAnimation. So please cvs remove flash.[ch]xx and
add custtrans.[ch]xx. I also undo some of the code I send
you yesterday that was totally useless. It is replaced by
something simpler and that works.

There is also a patch to matmodel.cxx. This is not related
and was something I forgot. Its purpose is to set the
alpha test on material billboard models that are likely to
be trees to lessen a transparency weird effect with clouds.
2004-05-11 22:21:24 +00:00
curt
331a4e4406 I had overlooked a few memory allocation/deallocation issues for audio buffers.
Hopefully this helps clean those up.
2004-05-10 21:22:50 +00:00
curt
a9faf8ceff Frederic Bouvier:
I modified the included animation.cxx to have a randomly displaced
time origin, to break the unison. And the flashing period is also
random as you noticed. I also put all the flashing light of the pole
in the same animation so they flash in the same rhythm.
2004-05-10 20:27:30 +00:00
curt
2866d1ace9 Frederic Bouvier:
Fix a memory leak, and brownian animation, if not motion.

I have 2 new files : personality.[ch]xx . They store the personality
data that would be deleted when the object is destroyed, instead
of staying in the animation maps. I also manage the current animation
step better and the towers are not flashing randomly now.
Makefile.am is updated.
2004-05-10 14:59:02 +00:00
curt
11a74f7a31 Frederic Bouvier:
modellib.cxx :
  Add a branch between the model and its transformation to add
 a unique identifier for the model. I called it "personality
 branch" and it maintains a "current_object" in SGAnimation.
 Animations specifically written to support it ( currently only
 the timed animation ) can add a degree of variety among the
 occurrences of the same model that would look otherwise cloned.

flash.[ch]xx :
  Better compute the view vector. The flash is now syncronized with
 its axis even at the edge of the screen.

animation.[ch]xx :
  Lots of changes :
 - add a condition to 'rotate', 'spin', 'translate' and 'range'.
  When a condition is specified *and* it evaluates to false, the
  animation becomes a no-op. Possible usage : no rotation during
  daylight, LOD range variable along the day, ...

 - use different durations for each branch in the timed animation.
  Enable the use of multiple <branch-duration-sec>, one for each
  <object-name> specified. Usage : strobes with flash light.

 - allow randomization of the <branch-duration-sec>, by using
  <random><min>_min_value_</min><max>_max_value_</max></random>.
  The value computed once is between _min_value_ and _max_value_.

 - implement model personality in timed animation. If
  <use-personality type="bool">true</use-personality> is specified,
  a different set of duration is created for every model in the
  scenegraph using this animation. Best if used with randomization.
  When using strobes where the population of the same object is
  dense, it avoids the "cheasy" clone effect.
2004-05-10 14:35:58 +00:00
ehofman
634a2035ee Add fast functions for exp2, pow, log2, root, sin/cos/tan, asin/acos/atan along with abs, neg and sgn. 2004-05-08 12:58:29 +00:00
ehofman
ffada9257d Frederic Bouvier:
this patch introduce a new kind of animation and ssg branch.
I called them flash animation, because they help me to
enhance the look of the rotating beacon and possible future
lighthouse. It computes the cosine of the angle between an
arbitrary axis, transformed by the current modelview matrix,
and the view direction. No trig involved, just a dot/scalar
product.

The computed value can be modified by three parameters,
power, factor and offset, according to the formulae :

 value = factor * pow( cosine, power ) + offset.

It is clamped between a minimum and a maximum.
This value is then used as the scale factor of a matrix
transformation applied to the children of the SGFlash
branch.

The xml syntax, with default values, is :

<animation>
 <type>flash</type>
 <object-name>HaloObject</object-name>
 <center>
  <x-m>0</x-m>
  <y-m>0</y-m>
  <z-m>0</z-m>
 </center>
 <axis>
  <x>0</x>
  <y>0</y>
  <z>1</z>
 </axis>
 <power>1</power>
 <factor>1</factor>
 <offset>0</offset>
 <min>0</min>
 <max>1</max>
 <two-sides>false</two-sides>
</animation>
2004-05-07 16:42:59 +00:00
andy
e09164e5b3 Robustify the SGTimerQueue destructor. There have been reports of
crashes on deletion.
2004-05-03 18:43:53 +00:00
andy
de1a5f3034 Add a destructor for SGEventMgr. We don't own the pointer, so we
can't free it.  Just zero it out.
2004-05-03 18:39:25 +00:00
andy
86e83faef3 Changes to get SimGear to configure and compile out-of-the-box on
a MinGW target:

Link against alut.dll in addition to openal32.dll.

Remove some preprocessor defines from compiler.h that were
confusing the mingw and/or libstdc++ headers (I put the _isnan
one back in the only file it was used).

Hack a broken sleep() call into the OpenAL sample programs so
that they will compile (but not work) in a non-POSIX environment.

Change the header file ordering in sample_openal.hxx to get
around some really weird interactions between MinGW's windows.h
and the gcc iostream header.
2004-04-30 00:44:04 +00:00
curt
9f06c8df76 Hopefully fix a chicken/egg linking problem for people who've never built
or installed simgear before.
2004-04-29 21:14:44 +00:00
curt
6e511de7db Add support for specifying a positional offset relative to the listener.
This allows us to "place" cockpit sounds.  For example, we can make left
engine sound come out of the left speaker, right engine out the right
speaker, etc.
2004-04-28 20:37:49 +00:00
curt
e34aae9982 Add default openal libs for cygwin. 2004-04-28 19:19:05 +00:00
curt
675b388b8e Lower verbosity level. 2004-04-28 03:59:10 +00:00
curt
7d239fe4ac Expose the ability to specify how the sound volume fades relative to
distance from the listener.  This let's us configure "interior" cockpit
sounds versus "exterior" engine type sounds.
2004-04-28 03:57:13 +00:00
curt
edd92caba1 Tweak default source audio parameters. 2004-04-27 21:11:21 +00:00
curt
5c3b4abf42 Expose some of the positional components of the OpenAL API. 2004-04-27 20:45:58 +00:00
ehofman
d3a3466b14 Make sure the prototype definition of sleep() is found (at least for IRIX). 2004-04-27 08:59:31 +00:00
curt
4399383781 Oops, one addtional tweak. 2004-04-26 22:07:19 +00:00
curt
bb383998bb Update the SoundSample api so we can request that a copy of the sample be
kept in memory and accessible.
2004-04-26 22:02:14 +00:00
curt
ffeb174ca1 Give these two methods slightly less misleading names. 2004-04-26 16:17:21 +00:00
curt
a90d74dde8 David Luff:
Fix comments for two functions.
2004-04-26 15:55:29 +00:00
curt
9d7fd79e76 Missed one fix for Mac OS. 2004-04-26 14:55:27 +00:00
curt
6f29d234eb Lower the verbosity in a couple other spots. 2004-04-25 02:30:52 +00:00
curt
6f5517f602 Lower verbosity. 2004-04-25 02:02:35 +00:00
curt
cc43c745b2 Add support for the MacOS variations of OpenAL. 2004-04-25 01:48:08 +00:00
curt
db8d961b27 Add correct openal libs for MacOS. 2004-04-25 01:41:24 +00:00
curt
a0bdec2846 Clamp pitch values rather than just dumping an error message. 2004-04-24 19:47:42 +00:00
curt
5bbcd386fa Rewrite the entire audio support library on top of OpenAL rather than plib's
sound manager.  The interface was simplified and cleaned up a bit, and I
haven't back ported these changes to the plib sound wrappers ... we could
I suppose if someone really had a problem, but I haven't seen anything so
far that would indicate the extra effort is worth it.
2004-04-24 19:02:29 +00:00
curt
7657632024 Bernie Bright:
gcc 3.4 has changed the rules for unqualified template name lookup.  This
affects SGQueue.hxx.  The changes I've made are backwards compatible with
earlier gcc versions.  Everything else compiles pretty much okay except for a
few warnings.  The resultant executable seems a bit faster too.
2004-04-22 12:39:16 +00:00
ehofman
ab29063a97 Frederic: The state selector was not referenced and got deleted as soon as the sky was rebuilt a second time with the metar code. 2004-04-04 15:35:28 +00:00
david
c06ef23eb1 Added more generated files. 2004-04-04 14:24:06 +00:00
ehofman
7b2f7aa827 Make sure GLuint is known. 2004-04-04 13:46:26 +00:00
ehofman
7113c10f4b Frederic Bouvier:
This is a new patch that allow to define a different
texture for top and bottom of clouds. It uses the
overcast_top.rgb you made for me last time.

What the patch do is to install a ssgStateSelector
instead of a ssgSimpleState for each layer.
The SGCloudLayer::draw method is modified to accept
a boolean that will select the proper state: 0/false
for bottom, 1/true for top.

Then, in SGSky::drawUpperClouds and SGSky::drawLowerClouds,
SGCloudLayer::draw is called with false and true because
we see the bottom of upper clouds and the top of
lower clouds.

Only overcast has 2 textures, the other types share the
same state for top and bottom, but that could be modified
in SGCloudLayer::rebuild.
2004-04-04 13:41:53 +00:00
ehofman
14033946e5 Plib is willing callbacks to return 0, 1 or 2 and not simply a boolean 2004-04-02 19:48:50 +00:00
ehofman
6e0e056ca7 Fix an NVidia problem by moving the hack to another location. 2004-04-02 19:44:04 +00:00
ehofman
7aa4f0ccdb Frederic Bouvier:
Move the rendering stage for upper clouds from preDraw
 to drawUpperClouds. Rename postDraw to drawLowerClouds.
2004-04-02 14:39:42 +00:00
ehofman
4b04450fa6 Frederic Bouvier:
put all leaf is a seperated branch so that it is
 possible to use a pretrav callback to cull out
 terrain without culling out light or dynamic
 objects. It appears that plib is not calling the
 pretrav callback for leaves.
2004-04-02 14:39:19 +00:00
ehofman
ad81560be5 Frederic Bouvier:
add an optional parameter that would be called to
 build the aircraft panel, so that flightgear's
 model_panel no longer duplicate code.

 add a pretrav callback to models so that we can
 filter out models when calling ssgCullAndDraw on
 the global scene.
 sgSetModelFilter( true ) means that we want to draw
 the models. Use false to cull them out.
2004-04-02 14:38:57 +00:00
curt
5c26faa20e Clean up several stray warnings that have accumulated. 2004-04-01 13:47:02 +00:00
69 changed files with 3763 additions and 1240 deletions

View File

@@ -8,3 +8,12 @@ config.log
config.status
configure
do-config.sh
.cdtproject
.project
config.guess
config.sub
depcomp
INSTALL
install-sh
missing
mkinstalldirs

View File

@@ -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.

View File

@@ -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
View File

@@ -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

View File

@@ -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"

View File

@@ -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 \

View File

@@ -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.

View File

@@ -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)

View File

@@ -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 );
}
}

View File

@@ -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.

View File

@@ -28,6 +28,8 @@
#include <strings.h>
#endif
#include STL_IOSTREAM
#include <simgear/debug/logstream.hxx>
#include "sg_socket.hxx"

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -1,3 +0,0 @@
.deps
Makefile
Makefile.in

View File

@@ -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 "";

View File

@@ -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.

View File

@@ -21,6 +21,9 @@
//
// $Id$
#include <simgear/compiler.h>
#include STL_STRING
#include <ctype.h> // isspace()
#ifdef SG_HAVE_STD_INCLUDES

View File

@@ -561,7 +561,7 @@ public:
* Property value types.
*/
enum Type {
NONE,
NONE = 0,
ALIAS,
BOOL,
INT,

View File

@@ -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.

View File

@@ -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.
*/

View File

@@ -1,6 +1,6 @@
includedir = @includedir@/scene
SUBDIRS = material model sky tgdb
SUBDIRS = fgsg material model sky tgdb
# lib_LIBRARIES = libsgscene.a

View File

@@ -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();

View File

@@ -217,7 +217,7 @@ private:
vector<_internal_state> _status;
// Round-robin counter
int _current_ptr;
unsigned int _current_ptr;
// texture size
double xsize, ysize;

View File

@@ -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 ) {

View File

@@ -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);

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View 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"; }

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View 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;
}
}

View 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

View File

@@ -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];

View File

@@ -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 << "----------------"

View File

@@ -34,8 +34,6 @@
#include <simgear/misc/sg_path.hxx>
static double sun_exp2_punch_through;
class SGSun {
ssgTransform *sun_transform;

View File

@@ -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 ) {

View File

@@ -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)

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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:

View File

@@ -23,6 +23,8 @@
// $Id$
#include <GL/gl.h>
/**
* Dump the screen buffer to a ppm file.
* @param filename name of file

View 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 ];

View File

@@ -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;
}
};

View File

@@ -1,3 +1,5 @@
.deps
Makefile
Makefile.in
openal_test1
openal_test2

View File

@@ -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

Binary file not shown.

View 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;
}

View 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);
}

View 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 );
}

View 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

View File

@@ -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;
}

View File

@@ -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

View 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 );
}
}

View 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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)

View File

@@ -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);

View File

@@ -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:
/**

View File

@@ -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

View File

@@ -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