Compare commits

...
Author SHA1 Message Date
curt 4a4e703f16 Changes for v0.3.9 (final). 2005-11-17 20:54:06 +00:00
curt 61984730ac Add a small accessor function to expose local timezone offset. 2005-11-17 15:30:07 +00:00
curt f196d3bab8 Fix a small spelling mistake. 2005-11-15 21:43:34 +00:00
ehofman 7da45cb49e Revert to the original (0.9.8) version, it causes more problems than it solves (did actually solve any?) 2005-11-14 18:25:17 +00:00
ehofman e994305da6 Put in public domain, Curtis wants it (because net_fdm.hxx depends on it) and I created the other functions. 2005-11-13 09:42:38 +00:00
ehofman 2af37b484e Let the application free the buffer data. 2005-11-12 12:22:23 +00:00
ehofman faf41f7d96 Prevent a possible memory leak. 2005-11-12 12:17:04 +00:00
ehofman 7629e29397 add a missing character. 2005-11-12 10:55:22 +00:00
ehofman 1cff7fcfea Make a clear separation between loading a sound file into main memroy and sending it to the driver. This prevents data to be loaded into the main memory (or onto the soundcard's memory) when it's not needed. 2005-11-12 10:26:21 +00:00
ehofman 694cf6e958 Expose some internals. 2005-11-11 13:19:58 +00:00
curt 0e12fbb2a0 v0.3.9-pre3 updates. 2005-11-11 00:44:59 +00:00
ehofman 450ad45882 MSVC fix. 2005-11-10 09:57:58 +00:00
ehofman d674e50591 gcc 4.0 fix. 2005-11-10 09:55:57 +00:00
andy 61f2f4b761 Architectural fix allowing the "tip" popups (FOV, view name, etc...)
to pop themselves down while the simulator is paused.

The problem was with the "real time" queue in the event manager,
causing the third argument of Nasal's settimer() (a flag for "sim
time") to be ignored.  Inverts the default sense of the argument, as
there are lots of uses of settimer() in the current code, almost none
of which want to use real time.

Note this fix introduces a header file incompatibility in SimGear --
be sure to update.
2005-11-09 20:34:14 +00:00
curt baa2f49b14 v0.9.9-pre2 changes. 2005-11-09 18:47:40 +00:00
curt 8c0bd234d8 v0.9.9-pre2 changes (just the version number!) 2005-11-09 18:41:49 +00:00
curt c4fd41562f Spelling fixes and other small corrections. 2005-11-05 20:32:45 +00:00
curt a1d1b4e49f Some pre-release updates. 2005-11-05 19:30:52 +00:00
curt 96fb7a45f7 Add a code comment for future thought. 2005-11-05 18:47:29 +00:00
ehofman d5eedd2c65 Move Curt's ssgEntityArray experiment over to SimGear. 2005-11-01 09:45:10 +00:00
ehofman fe4f907099 Remove some unused code. 2005-10-30 15:02:58 +00:00
ehofman 1b45eaf3de Mathias Fröhlich:
I guess the most important memory leaks are plugged now.
Just by inspection: An other memory leak in Simgear.
2005-10-27 08:21:58 +00:00
ehofman cfbc0a1579 MSVC fix. 2005-10-27 08:21:00 +00:00
ehofman db1b99d8dd Back out the shared mutex code since it only works when the mutex is in shared
memory[1], something we don't support anyhow.
This also fixes a FreeBSD compile problem.

[1] http://hypermail.linklord.com/new-httpd.old/2002/Jan/0557.html
2005-10-26 11:19:58 +00:00
ehofman 65a880e9fa Oops, ALUT 1.0 requires a little more work than expected. 2005-10-25 18:05:23 +00:00
ehofman 37b4005d3e Alex Romosan:
* Use "const string&" rather than "string" in function calls when appropriate.
* Use "const Point3D&" instead of "Pint3D" in function calls when appropriate.
* Improved course calculation in calc_gc_course_dist()
* Safer thread handling code.

Vassilii Khachaturov:

Dont use "const Point3D&" for return types unless you're absolutely sure.

Erik Hofman:

* Use SGD_(2)PI(_[24]) as defined in simgear/constants.h rather than
  calculating it by hand every time.
2005-10-25 13:48:58 +00:00
ehofman 70faa252e7 Prepare for ALUT version 1.0 2005-10-25 13:06:25 +00:00
ehofman 3620be8dbc Cosmetic updates. 2005-10-23 14:04:42 +00:00
ehofman 21c64dd60f Slightly update the seasonal texture support code. 2005-10-23 13:47:46 +00:00
ehofman fb69d790ce Add support for seasons. 2005-10-23 13:31:13 +00:00
ehofman debd066edd Melchior FRANZ:
The attached patch makes remove_child() available as removeChild(pos, keep).
That's consistent with getChild. Only renamed remove_child to removeChild and
added a check for validity of the pos argument.

removeChildren() will be used in input.cxx, and a lot in the upcoming
dynamic new_gui dialogs, which are aiming at replacing the hard-coded
dialogs. I'll discuss them on the list once the infrastructure is
in place. (The <hide> gui property was one part of it.)
2005-10-23 11:55:48 +00:00
ehofman f58d81b1e9 Harald JOHSEN: the sky color now fades to black with altitude 2005-10-23 11:46:41 +00:00
ehofman 8d507f161b Remove some dead code. 2005-10-22 11:07:00 +00:00
ehofman b015f7c801 Harald JOHNSEN:
I have corrected a few bugs with the owner draw gauge, weather radar code and heat-haze effect.

- shadanim.cxx :
  the heat/haze effect was showing artifacts when using a screen resolution >
  1024 pixels.
2005-10-16 17:23:59 +00:00
ehofman 80abe952ba Ima Sudonim remembered me there is still one problem for gcc Vs. 3.4 or later under Cygwin. This fixes it. 2005-10-15 14:59:02 +00:00
andy c12162407c Fix memory leak discovered by Mathias Froehlich 2005-10-14 16:42:32 +00:00
ehofman 7f5c3b223a Mathias Fröhlich:
This one, removes some virtual qualifiers at a private member class of
SGPropertyNode. These virtual qualifiers are really useless and stop the
compiler from inlineing these functions. I gain a single frame with my
favourite aircraft per second!
2005-10-14 16:27:06 +00:00
ehofman 2f3e4ebf39 Mathias Fröhlich:
I have done a valgrind run in flightgear. Just start it up and close it at the
fist change I had about half an hour later.

property-leak.diff:
   A leak in the property system which I could even notice in top.

texture-leak.diff:
    minor one, but fixed is fixed ...
2005-10-14 16:21:57 +00:00
curt 2c14f8587e Use an unsigned vs. signed short to double our element capacity for higher
resolution scenery.
2005-10-12 16:43:26 +00:00
ehofman 42224052e2 Martin Spott:
make GCC on Solaris8 happy.
2005-10-12 08:59:39 +00:00
curt a8dd5aa0fc Fix a small typo. 2005-10-11 18:56:45 +00:00
ehofman f3d0a9bc3f David Luff:
The following patch needs to be applied to fix the errors that Georg
Vollnhals was getting whilst attempting to compile SimGear with gcc-3.4.x
2005-10-09 09:37:35 +00:00
ehofman d629b9e36a Harald JOHNSEN:
- shadanim.cxx, animation.hxx :
  new chrome (sphere mapping) shading ;
  disabled the loading of the fresnel VP until it is fixed ;
2005-10-08 11:52:48 +00:00
ehofman 4d54ba2200 Another Solaris fix. 2005-10-06 14:39:12 +00:00
ehofman 0035ef9194 Martin Spott: Use standardized Sun directive. 2005-10-06 11:06:27 +00:00
ehofman fcb20296d7 MSYS fix. 2005-10-06 09:45:36 +00:00
ehofman 6bb9080017 MSVC fixes. Frederic: MSVC has no ssize_t type 2005-10-06 08:25:14 +00:00
ehofman bbde16dc08 Remove a leftover. 2005-10-04 11:49:24 +00:00
ehofman ac9716f193 Cygwin fixes(?), it's a good idea to do it this way anyhow. 2005-10-01 11:41:59 +00:00
ehofman 8a2bc1c21b Cygwin fixes. 2005-09-29 12:05:22 +00:00
ehofman 942b474ad7 Fix an oops. 2005-09-28 08:03:44 +00:00
ehofman f3ef9b671f Back out a patch from Sept. 25th. Setting the *factor* to 0.0 by default isn't generally a good idea. 2005-09-28 08:00:33 +00:00
curt 3538631e8e Make some adjustment to low level serial port configuration flags for unix. 2005-09-26 21:01:17 +00:00
ehofman 1577ab04e1 Vivian Meazza:
Correct the bug in the translate animation where the offset was part of the
multiplication. It now behaves like all other animations:
out = (prop * factor) + offset

I feel strongly that the existing is wrong and must be corrected - it is non-op
if the offset is zero as I have found to my cost! It is just a typo I expect.

The diff also provides non-op default values for the scale animation.

I've also included Harald's latest eye-candy animation which allows us to
have a very smart heat-haze for exhausts. They have been tested by me and
others on Linux and Cygwin. You might like to upload these - I have a
revised Hunter ready to go as soon as they are uploaded.
2005-09-25 07:44:50 +00:00
curt 7f2dfaa5b4 Add eof() support to SGIOChannel/SGFile. 2005-09-24 12:28:14 +00:00
curt fd126746f7 Add an eof() method to SGFile. 2005-09-23 20:13:43 +00:00
ehofman 63f7e9feb0 AMD64 and sgi fixes. 2005-09-23 12:30:25 +00:00
ehofman 5eb380e103 Platform compatibility fix. 2005-09-22 13:43:09 +00:00
ehofman 832e821919 Add some linefeeds. 2005-09-22 09:15:10 +00:00
ehofman 197e3f144d Create our own stdint.h(xx) implementation and use it where needed. 2005-09-22 09:11:27 +00:00
ehofman 056b5b41e2 Prepare for Openal 1.1 and a separate alut library 2005-09-21 09:22:51 +00:00
andy 15d40fd64a Oops, Frederic caught an inline declaration that had snuck into the code. 2005-09-20 21:38:08 +00:00
andy 979d3da69c Sneak a Nasal update in before the next release. This version
*appears* to work correctly on all systems to which I have access
(i386 linux/win32, x86_64 linux, powerpc OS X, Sparc Solaris 10), but
not all systems are capable of running fgfs.  Beyond that, multiple
threading bugs were fixed, and the naCall() API changed slightly to
support named function arguments.

NOTE: this introduces a change in the external API, and therefore this
change *must* be compiled against current FlightGear code.
2005-09-20 21:09:34 +00:00
ehofman 72984cc4a8 Don't refference simgear_config.h because this header gets installed :-( 2005-09-18 21:05:04 +00:00
ehofman 0a7a815124 int64_t is in stdint.h by default. 2005-09-18 09:21:54 +00:00
ehofman 1ce68a49c6 MSVC fix. 2005-09-18 09:19:07 +00:00
ehofman b1b6abf285 Use inttypes.h specified types. This is the standard and fixes some 64-bit problems. 2005-09-15 17:06:31 +00:00
ehofman 9dfd6970f1 Better XML error catching, proposed by Richard Harrison. 2005-09-15 16:54:27 +00:00
ehofman 3583c13339 Vivian Meazza:
After much trial and tribulation, Harald came up with a fix for the bug
which has been plaguing Cygwin for a couple of weeks now.

It's only a couple of lines. I've tested it exhaustively, and it seems to
cure the problem of Cygwin failing to start.
2005-09-05 13:30:38 +00:00
ehofman 00ab198c9f Mathias Fröhlich:
There was a patch from Manuel Masing a few months ago which cleaned up
SGLocation's way depending on input values. That means that with that patch
SGLocation does no longer have calls with unneeded input arguments.
I took his patch and integrated that into flightgear and made maximum use of
that changes.
2005-09-05 13:23:55 +00:00
ehofman 669d9a89ca Mathias Fröhlich:
just a few split out patches from my zoo of local work ...

The patch to simgear-glxproc.diff changes dlopen to not open a specific library.
If it is used with a NULL argument, we just get a handle to the current running
binary including all loaded libraries. This has the advantage that we do not
rely on the name of libGL on the specific platform.
Also a user can link with his own different named libGL or with a static libGL.a

Then the render texture again ...

glxQueryVersion turns out to return the  minimum of the client libraries glx
version and the servers glx version. *All* Xorg servers return 1.2 here.
So we never get the glxPBuffer functions  which are the only ones working with
ati's drivers ...
Reverted back to checking the required functions and just use them if they are
there. Still prefering the glx standard variants since they work on ati's
drivers ...
2005-09-05 09:02:56 +00:00
ehofman 9c54603726 Add some more defines as specified in FlightGear/src/Network/net_fdm_mini.hxx 2005-09-05 08:22:30 +00:00
ehofman dc09a50472 Mac OS X fixes from Markus Morawitz
stdint.h replacement defines for Windows and Sun from Frederic et all.
2005-09-05 08:17:37 +00:00
ehofman 68eb7031e2 Harald JOHNSEN:
- model.cxx :
  load the 2.5D panels before the animations so that the panels can be used in
  animations his solve the problem of 2.5D panels visible outside of the
  aircraft (one can add a null animation to put the panel at the top of the
  aircraft graph so it is drawn first) and this adds the possibility to have
  billboarded/popup panels.

- newcloud.cxx :
  removed 'this' pointer cast for amd64 compiler.
2005-08-22 17:44:35 +00:00
ehofman 19623cac21 Cygwin fix. 2005-08-10 08:04:39 +00:00
ehofman 4ca25ca533 Harald JOHNSEN:
added a cull test on fields
2005-07-31 08:56:27 +00:00
ehofman 178c49a430 Fix a problem with systems that don't define GLXPbufferSGIX or GLXFBConfigSGIX 2005-07-31 08:46:37 +00:00
ehofman 32e2cd9f06 Harald JOHNSEN:
This is the low level shader class for Simgear.
It's the code from Roman Grigoriev with a few adaptations.
2005-07-31 07:59:08 +00:00
ehofman 7aa514d9ba MacOS-X fixes. 2005-07-27 08:02:11 +00:00
andy 7c2575d723 Josh discovered a bug parsing negative numbers with leading zeros
("-0.3") which also affected ones of the form "-.3".  This got
introduced a few months back, I'm not sure how it went undetected for
so long...
2005-07-21 23:03:26 +00:00
ehofman f93ea20d5e Harald JOHSEN:
Changes
=======

- shadowvolume.cxx, renderer.cxx :
  - reduced the polygon offset a bit to eliminate some artifact ;
  - changed again the cleanup code for objects inside a tile because it could crash on rare occasion ;
  - the culling of shadow casters has been rewritten to traverse the scene graph, it should be
    a bit faster when there is a lot of objects ;
  - the range selector was not correctly handled, sometimes the wrong LOD was casting shadows.
  - added the option to display aircraft's transparent objects after the shadows, this will
    reduce the problem of shadows being hidden by the transparent object (propeller disk,
    rotor, etc). A side effect is that aircraft's transparent objects won't receive shadows
    anymore. This is usually a good thing except when the aircraft use a 'transparent'
    texture where it should not. A transparent texture in the plib context is a texture
    with an alpha channel or a material with alpha <= 0.99.

- model.cxx, animation.cxx, shadowvolume.cxx :
  - added an optional <condition> under the <noshadow> animation

- tower.cxx
  - correct a rare bug where all occurences of the aircraft are not deleted from the
  departure list causing a crash in FGTower::CheckDepartureList function.
2005-07-18 16:57:20 +00:00
ehofman 73cb6ff00d Adjustments to better support GLX1.3 and ATI drivers. 2005-07-13 12:00:30 +00:00
ehofman 72267fa60b Harald JOHNSEN:
Melchior has found another bug, I tried to skip some computation for a few
frames but that introduced some bad rendering bug with the aircraft moving
parts.
I corrected that and reduced a bit the cpu usage for ground objects.
2005-07-06 08:44:25 +00:00
ehofman 6b6a27e849 Another update, the previous one could crash if you leave the surrounding tiles (try Set aircraft in air and choose a distant airport). 2005-07-05 18:53:16 +00:00
ehofman daea10121c Somehow gcc allows function overriding but MIPSpro doesn't. Fix this. 2005-07-05 18:00:58 +00:00
ehofman 999a1e514b Harald JOHNSEN:
- shadow volume vertex are now shared, using DrawElements instead of repeated
  calls to glVertex, this can improve performance on some systems.
- added a rendering path that use the alpha channel instead of the stencill
  buffer.
- releasing memory when tiles objects are destroyed
- objects sub parts will not cast shadows if their name begins with "noshadow"
  or if they are in a <noshadow> animation

- bbcache.cxx :
   don't ask for a 32 bits context when the primary context is only 16 bits

- RenderTexture.cpp :
   corrected a crash when asking for a second rendering context
   on win32 and extensions not being supported

- model.cxx, animation.cxx :
   added a <noshadow> animation, added an animation type needed by the shadow
   code.
2005-07-05 17:08:27 +00:00
ehofman be30960366 Make sure it works with the lates version of OpenAL. 2005-07-04 09:20:11 +00:00
ehofman 38e5084018 Restore the old behavior. Additions are likely. 2005-06-30 19:10:18 +00:00
ehofman fdd9bb1af6 Melchior FRANZ:
- check for isTied() and refcount has to be made *before* we go into
  recursion, so as to pertain subtrees of refcounted nodes, even if there
  are no refcounted/tied nodes *in* this tree
- return value inverted, because it's more logical to say
  removeChildren() == true --> everything removed;  false --> failed
- further cleanup
2005-06-29 09:41:07 +00:00
ehofman 81546820ab Frederic: Also copy the attributes over to the new tree. 2005-06-28 11:19:41 +00:00
ehofman 84e87f0e8a Due to a misunderstanding of what removeChild() actually does, some used it to detach a subtree from the main tree. The previous patch broke that behaviour so a new function call detchChild() is now added. 2005-06-28 11:19:09 +00:00
ehofman 901592a88e fix return value 2005-06-27 17:48:13 +00:00
ehofman 24f908d9be Melchior FRANZ:
- introduce removeChildren() and removeChildren(name)  to remove all children
  or all with a given name
- let removeChild() and removeChildren() also remove child trees, and let them
  return a "dirty" boolean that indicates if one or more subnodes had to be
  kept because of refcounting (removeChild returned a SGPropertyNode_ptr before)
- make alias/unalias increase/decrease the refcounter
- don't remove refcounted or tied nodes

This patch makes the SGPropertyNode_ptr actually useful. Until today, they did
proper refcounting (except for aliases), but no other part did check this counter.

But SGPropertyNode_ptr aren't only useful for the first time, they are now
highly recommended for every place that relies on a node address, and wants
to "lock" it (so that removeChild(ren) will never try to remove them). This
is not guaranteed for SGPropertyNode* (and never was). Of course, that's not
an imminent problem, as only four places currently use removeChild(ren) and
these are careful to only remove their own data.
2005-06-27 13:49:28 +00:00
ehofman f62ff0ad66 Harald JOHNSEN:
Changes
=======

New volumetric shadows for FlightGear.

There is now two new checkboxes in the rendering dialog to enable/disable shadows
for the user aircraft and for static scenery objects (ie those defined in the .stg files).
AI and random objects are not handled for the moment.


known bugs
==========
- ghost objects
2005-06-26 17:16:45 +00:00
ehofman 8e0ecbeb8f Remove the 'old' 3D clouds code. 2005-06-25 11:22:06 +00:00
ehofman 095367f760 Melchior: Make the (lack of) axis or center location definitions more consistent. 2005-06-12 11:23:28 +00:00
ehofman 5d34eb12e0 Melchior FRANZ:
This is the more elegant solution that Andy had proposed in a response
to my RFC on Nasal initialization code in joystick configuration files.
As Nasal is initialized last (for good reason), subsystem can currently
not use it for initializing. postinit() is called on all subsystems
after all have been initialized.
2005-06-11 08:39:26 +00:00
ehofman d4e760efe1 fix a coredump situation, discovered by Melchior. 2005-06-08 14:07:53 +00:00
ehofman 75ab8e697b Harald JOHSEN:
Changes
=======

- changed the rotation of sprites, they don't rotate strangely when we
  approach them now
- corrected the strange movement of clouds when banking quickly
- it no more rain above cloud layers
- add a radar echo container used by the weather radar instrument
2005-05-30 09:04:57 +00:00
andy f4b05d46ed Fix two crash conditions Ampere found. These are just temporary
patches; my private version has rewritten both of these functions
(ironically fixing these bugs in the process) to handle negative
offsets meaning "from the end".
2005-05-29 16:13:48 +00:00
ehofman 04c5f2c36a Melchior FRANZ:
Turn the material animation's <transparency> property into a group, with
members <alpha-prop>/<alpha>, <offset-prop>/<offset>, <factor-prop>/<factor>,
<min>, and <max>. The "material" animation can now fully replace "blend" and
"alpha-test" (--> <threshold>) animations, with enhanced possibilities:
The "material" animation can be used for one or more explicit objects (like
"blend"), but also for all objects that share one material (<global>), which
avoids problems with objects being forced together into one tree. Also, an
object doesn't have to be semitransparent or textured with a semitransparent
texture to make blending work. Unlike the "blend" animation, the "material"
animation also makes fully opaque and untextured objects transparent. (This
fixes the bo105's formerly semi-transparent rotor.)

Erik:
The blend animation and alpha-test animation are depreciated as of now.
2005-05-24 08:13:09 +00:00
ehofman db50f95482 Melchior FRANZ:
Currently, the material animation sets glColorMaterial(GL_AMBIENT_AND_DIFFUSE)
for all material properties. This breaks emission-only (e.g. cockpit lighting
for the p51d) or specular-only animation. ==> set glColorMaterial only where
it is really required.
2005-05-23 16:35:00 +00:00
ehofman 0e52a08a47 MSVC fix. 2005-05-22 09:18:56 +00:00
ehofman 7b5d49ef60 Harald JOHSNEN:
Changes
=======

- correct the transparency probleme when old 3d clouds were enabled
 (rendering context with an alpha channel)
- changed rain cone orientation, it can now be viewed from helicopter or chase
  view (still not tower view)
- clouds are a bit more yellow/red at dawn/dusk
- weather data is now correctly propagated to the interpolator, this correct
  visibility, wind, etc
- the 'metar' weather scenario now immedialty reuse the real metar data
- real metar no more overwrite custom weather scenario
2005-05-22 08:09:08 +00:00
ehofman 430ba60b33 MSVC fix. 2005-05-22 07:35:39 +00:00
ehofman 3af1f3bc63 Make removeChild() work (again?) 2005-05-17 09:56:08 +00:00
ehofman bdcb94af81 gcc fix. 2005-05-15 09:34:04 +00:00
ehofman 2ea9e723c2 Harald JOHNSEN:
This is another update for the cloud code, a lot of lines but this time I have started to add the doxygen doc.

Misc
====

- corrected a bug when RTT is not available, the current rendering context was
  altered
- if RTT is not available then 3d clouds are not drawn at all
- impostors lighting is now recomputed when the sun changes position
- distant objects are no more seen in front of clouds
- blending of distant clouds is a bit better now
- litle optimization of code (uses a less cpu time)
- use layer wind speed and direction (no more hardcoded wind)
- fov is no more hardcoded

Changes
=======

- clouds (cu only) are dissipating/reforming (experimental)
- compute a turbulence factor that depends on surrounding clouds and type of
  clouds (experimental)
- clouds shapes are defined in cloudlayers.xml
- type of clouds present in a layer is also defined in cloudlayers.xml
- cloud layers are generated from metar and other misc. data (in progress)
- added a rain effect around the viewer (enabled in the rendering dialog and
  when the metar property says so)
- added a lightning effect (enabled in the rendering dialog) : cb clouds spawn
  new lightnings
- added a dialog to select from different weather source : metar/property,
  a 'fair weather' environment and a 'thunderstorm' environment.
2005-05-15 09:27:00 +00:00
ehofman e19091d809 Melchior: Only change types when explicitly requested. 2005-05-09 16:18:41 +00:00
ehofman 64ab59c0e0 Melchior FRANZ:
Vivian pointed out that a redefined Ctrl-U key binding didn't work
correctly. I found out that this is, because the definition in
$FG_ROOT/keyboard.xml sets <value type="bool"> for binding[1],
and ... [better sit down first!] ... and assigning <value type="double">
in a *-set.xml file doesn't *really* set "double" as new type!

Instead, the boolean is kept, and a double sqeezed into it. In other
words: once tainted as bool, you can throw all doubles in the universe
on a property node, and all it will accept is 0 and 1. Without warning!

BTW: I changed the patch: I was overly cautious: clear_value() does already
care for ties and for setting NONE, so we just need to make that public as
clearValue(), and use that. Makes the patch a bit more verbose, though.  :-/
2005-05-09 14:31:41 +00:00
ehofman 4707b363aa Solaris fix. 2005-05-07 08:46:04 +00:00
andy 1a72245c15 Properly release the mod lock when returning from a runtime error.
Ampere discovered that the interpreter would deadlock at runtime if it
hit such a condition during initialization.
2005-05-04 20:17:28 +00:00
ehofman dea7b9050d Phil Cazzola:
This is a minor bug fix for sgBucketDiff().
If you crossed the bucket size boundary, the answer for dx could be wrong.

E.g.
 going from   0:0, 21:7  to 0:7, 21:7   would give you dx = 7 (correct)
 but going from 0:0, 21:7 to 0:3, 22:0 would give you dx = 6 (instead of 7)

Previously it differenced the center longitudes of the buckets.  When you
cross a boundary, the center point of the larger bucket now lies on the edge of the smaller bucket.

The result was a dx with an integer + 1/2 bucket, which rint() was rounding to the nearest even int.

This function only seems to be used in TerraGear.
2005-05-01 08:50:39 +00:00
ehofman 3bd810fedc Make use of the repeatable sg_random() function so display systems can synchronize 3d clouds too. 2005-04-30 10:00:16 +00:00
ehofman f9cbf8361d Add a seed function that gives the same random seed within a ten minute period of time. This should be useful for synchronizing display systems. 2005-04-30 09:59:12 +00:00
ehofman eccd4d0325 Mathias:
I have done a patch to eliminate the jitter of 3D-objects near the viewpoint
(for example 3D cockpit objects).
The problem is the roundoff accuracy of the float values used in the
scenegraph together with the transforms of the eyepoint relative to the
scenery center.

The solution will be to move the scenery center near the view point.
This way floats relative accuracy is enough to show a stable picture.

To get that right I have introduced a transform node for the scenegraph which
is responsible for that shift and uses double values as long as possible.
The scenery subsystem now has a list of all those transforms required to place
objects in the world and will tell all those transforms that the scenery
center has changed when the set_scenery_center() of the scenery subsystem is
called.
The problem was not solvable by SGModelPlacement and SGLocation, since not all
objects, especially the scenery, are placed using these classes.

The first approach was to have the scenery center exactly at the eyepoint.
This works well for the cockpit.
But then the ground jitters a bit below the aircraft. With our default views
you can't see that, but that F-18 has a camera view below the left engine
intake with the nose gear and the ground in its field of view, here I could
see that.
Having the scenery center constant will still have this roundoff problems, but
like it is now too, the roundoff error here is exactly the same in each
frame, so you will not notice any jitter.

The real solution is now to keep the scenery center constant as long as it is
in a ball of 30m radius around the view point. If the scenery center is
outside this ball, just put it at the view point.

As a sideeffect of now beeing able to switch the scenery center in the whole
scenegraph with one function call, I was able to remove a one half of a
problem when switching views, where the scenery center was far off for one or
two frames past switching from one view to the next. Also included is a fix
to the other half of this problem, where the view position was not yet copied
into a view when it is switched (at least under glut). This was responsible
for the 'Error: ...' messages of the cloud subsystem when views were
switched.
2005-04-29 14:37:27 +00:00
ehofman e0decf1233 Mathias:
have done a patch to eliminate the jitter of 3D-objects near the viewpoint
(for example 3D cockpit objects).
The problem is the roundoff accuracy of the float values used in the
scenegraph together with the transforms of the eyepoint relative to the
scenery center.

The solution will be to move the scenery center near the view point.
This way floats relative accuracy is enough to show a stable picture.

To get that right I have introduced a transform node for the scenegraph which
is responsible for that shift and uses double values as long as possible.
The scenery subsystem now has a list of all those transforms required to place
objects in the world and will tell all those transforms that the scenery
center has changed when the set_scenery_center() of the scenery subsystem is
called.
The problem was not solvable by SGModelPlacement and SGLocation, since not all
objects, especially the scenery, are placed using these classes.

The first approach was to have the scenery center exactly at the eyepoint.
This works well for the cockpit.
But then the ground jitters a bit below the aircraft. With our default views
you can't see that, but that F-18 has a camera view below the left engine
intake with the nose gear and the ground in its field of view, here I could
see that.
Having the scenery center constant will still have this roundoff problems, but
like it is now too, the roundoff error here is exactly the same in each
frame, so you will not notice any jitter.

The real solution is now to keep the scenery center constant as long as it is
in a ball of 30m radius around the view point. If the scenery center is
outside this ball, just put it at the view point.

As a sideeffect of now beeing able to switch the scenery center in the whole
scenegraph with one function call, I was able to remove a one half of a
problem when switching views, where the scenery center was far off for one or
two frames past switching from one view to the next. Also included is a fix
to the other half of this problem, where the view position was not yet copied
into a view when it is switched (at least under glut). This was responsible
for the 'Error: ...' messages of the cloud subsystem when views were
switched.
2005-04-29 14:36:50 +00:00
ehofman 100927f16c Harald Johnsen: Fix a 'terrible' bug with culling of the clouds. 2005-04-26 20:14:37 +00:00
ehofman bb670f6658 IRIX fixes. 2005-04-26 09:08:58 +00:00
ehofman d37992aaf9 Harald Johnson:
Changes
=======

- corrected some strange behavior when playing with the render dialog options
- the density slider is now working : if you are fps limited and still want to see clouds in
  the distance you should play with that
- added the choice for texture resolution, its more comprehensible now (before it was
  wrongly allways choosing 64x64 textures)
- changed the initial texture size : you now have 64 texture of 64x64, this uses 1Mo of
  texture memory (before it was 20 texture of  256x256, that took more memory and there was
  not enought impostors)
- sun vector is now right so the lighting is a bit better
- removed useless sort and light computations for impostors, this should save a lot of cpu
- blending of distant cloud is more accurate now
- clouds are now positioned correctly, they don't try to escape you anymore
- no more red/white boxes around cloud
- textures are now filtered (no more big pixels)

known bugs
==========

- distant objects are seen in front of clouds
2005-04-26 08:30:38 +00:00
ehofman 9048ee533d Don't refference GLUT but GLU instead. 2005-04-24 13:55:20 +00:00
ehofman 2b1e5927ca This one time I did a commit using Linux. <sigh> 2005-04-24 11:45:34 +00:00
ehofman b5e03030d1 Harald Johnson:
- new and updated sources for the new volumetric clouds
- 2 new textures for the clouds
- an update to the render dialog to enable/disable and change a few parameters
  for the new clouds
2005-04-24 11:16:50 +00:00
andy 65056bfa72 Support for a "forindex(idx; list) {...}" construct analagous to
foreach, except that the variable gets the index instead of the list
element.  Should be useful, and took almost no code to implement.

Support for operator/assignment syntax: +=, -=, *=, /= and ~= now do
what you think they should.

Library support for a bind() function (see the docs Andy is still
writing), allowing runtime modifications to function lexical
environments.
2005-04-22 21:54:16 +00:00
andy c50bb90374 Fix clamping of the minimum hash size, because the Melchior discovered
that the column math goes wacky when lgalloced is allowed to be
  zero.
Augment the find() function to take a starting index.
Fix strc() to use a default index of zero.
Fix parser precedence of TOK_MINUS, so that "a-b-1" means (a-b)-1 and
  not a-(b-1).
2005-04-19 14:19:46 +00:00
ehofman ec4fc265e0 Non gcc fixes. 2005-04-19 12:30:12 +00:00
andy 8ea41af5c4 Fix crash in the code generator when compiling a (now illegal, because
"var" is a reserved word) expresssion of the vorm "var=<expr>".
2005-04-18 20:43:29 +00:00
andy 966331dac7 Upgrade to nasal 1.0 test candidate 2005-04-18 19:48:47 +00:00
andy cf056bace7 Fix boolean semantics so that the empty string evaluates to false, and
numeric strings are false if their numeric values are false.
2005-03-30 18:45:01 +00:00
ehofman 405a455906 Melchior FRANZ:
Re-organisation: <diffuse>, <ambient>, <emission>, <specular> are
now groups with members <red>, <green>, <blue>, <factor>, <offset>,
and their <*-prop> forms. Additionally, there's an option <property-base>
that can be used to set a path that is prepended to all <*-prop> paths.
It defaults to an empty string. Rationale: see model-howto.html.
2005-03-28 09:13:45 +00:00
andy 3a8b431a5b Don't parse a single "e" or "E" as a numerical zero. You need a
numerical prefix to use the 1.0e12 notation, "e" alone is not enough.
2005-03-22 20:28:47 +00:00
ehofman 3ce0c17237 Melchior FRANZ:
here is the promised material animation. It looks a bit longish, but that
wasn't avoidable -- there are simply too many parameters to consider. I tried
hard, though, to make the animation fast by only doing the necessary stuff.
It doesn't affect the frame rate here with my test model. The animation is
heavily based on Jim's "material-emission" animation.

* implementation of the "material" animation (this required to make the
  texture path available) + documentation update ($FG_ROOT/Docs/)
* fix some more return values (texture animations, and select) for the
  shadow problem (and some in anticipation of other problems  :-)
* fix compiler warning
2005-03-22 13:12:51 +00:00
ehofman 61a2e0f104 Melchior FRANZ:
the cause for the disappearing shadows is, that SimGear doesn't tell plib
to call the pre-traversal-callback function on culled objects. These calls,
however, are necessary to execute the transform animation that does, for
example, translate a shadow back into the frustum! Curretnly, the callback
is only executed, and the shadow only magically pops up again, when the object
enters the frustum because the view has changed significantly.

The plib documentation does only talk about TRUE and FALSE for possible
return values from the pre-traversal-callback. But src/ssgEntity.cxx reads
like this:

   int ssgEntity::preTravTests ( int *test_needed, int which )
   ...
       int result = (*preTravCB)(this,which) ;

       if ( result == 0 ) return FALSE ;
       if ( result == 2 ) *test_needed = 0 ;
   ...

So the return value needs to be 2 to bypass the cull test for pretraversal,
and get the pretraversal in any case. I only changed the return values in
four animations: scale, rotate, translate, and range, because these are
the most likely to move an object out of the frustum. It's not necessary
for blend/alpha/texture manipulation etc. Of course, this is a bit more work
for plib, but the performance will probably not be affected, because:

* these four animations are mainly used for the aircraft model (the spin
  and billboard (trees!) animations are not affected)

* the number of extra nodes to process is quite low

* a part of the time spent for the extra nodes to be processed, was before
  used for workarounds that are now not necessary any more

I didn't observe a frame rate drop, at least.
2005-03-19 10:19:30 +00:00
andy 7c44251216 Oops, fixed the wrong test 2005-03-12 15:51:37 +00:00
andy 26e70664d6 Off by one error when printing exact poweres of ten 2005-03-12 15:49:53 +00:00
andy 8ac27cc798 Fix an infinite loop (due to an overflow condition) when printing some
very large numbers.
2005-03-11 21:49:31 +00:00
andy d314164fed Fix the fixes. Note that "." had the same problem as "+" and "-", and
that we can still match non-identical constants if they are both
strings with the same numerical value.
2005-03-11 20:39:07 +00:00
andy d2cbed151b Don't parse the strings "+" and "-" as numerical zeros. Also fix the
code generation of constant objects to use real identity and not Nasal
equality, so (e.g.) the constants 1 (number) and "1.0" (string) do not
get turned into the same object in the generated code.
2005-03-11 19:07:06 +00:00
ehofman fc06ae58b2 Ima Sudonim:
I have (hopefully) generated a patch for a previously mentioned simgear  problem for a hang condition in mac os x.  Mentioned in  <http://baron.flightgear.org/pipermail/flightgear-devel/2005-February/ 035004.html>
2005-03-10 08:58:48 +00:00
ehofman a8768c78a2 automake 1.8+ fixes 2005-02-15 18:13:15 +00:00
ehofman ee8763f60d More MacOS X fixes 2005-02-12 12:44:46 +00:00
ehofman db633330fe Fixes from Norman for users running Cugwin with the XServer package installed. 2005-02-11 15:19:04 +00:00
ehofman c1ffafd663 MacOS X fix(?) 2005-02-11 15:07:22 +00:00
ehofman 72f35dc914 Comment out GLX code for MacOS and (hopefully) add some MacOS AGL compattible code. More needs to be done though. 2005-02-01 10:35:43 +00:00
ehofman e5f82f53b9 MacOS doesn't have glx.h 2005-01-31 18:29:38 +00:00
ehofman e39e6893e0 Jim Wilson:
Fix a couple of loose ends and missed edits on the earlier patch.  For the
most part no change in functionality.
2005-01-31 18:21:12 +00:00
ehofman 9ab77d65f4 Cygwin fixes 2005-01-31 18:07:40 +00:00
ehofman 8ed96cad1d Windows fixes. 2005-01-29 11:44:01 +00:00
ehofman 7795eb8239 Jim Wilson:
This patch adds support to the model animation system for modifying emissive
states on the fly so that it is possible to make "lights" appear to dimm.

This is an example of a configuration entry which should explain how it is used:


 <animation>
  <type>material-emission</type>
  <object-name>Face</object-name>
  <property>/controls/lighting/instruments-norm</property>
  <emiss-red>1.0</emiss-red>
  <emiss-green>0.8</emiss-green>
  <emiss-blue>0.5</emiss-blue>
 </animation>

Note the color entries are the emissive colors when the "property" value is
1.0.  They are useful for tinting the light.   The "property" itself must be
float or double and is clamped to values between 0 ~ 1.0 inclusively.   The
"property" value is multiplied against the colors to get the actual material
properties.  Thus property value 0.0 = darkest, and 1.0 = brightest.
2005-01-29 10:31:25 +00:00
ehofman 207c7ab1e0 MSVC fix. 2005-01-28 15:23:26 +00:00
ehofman 27af79684f Frederic Bouvier:
code.c is C code ( according to the file extension ), so variables should be declared at the beginning of the function.
2005-01-28 15:21:29 +00:00
ehofman 6b61a8eed1 use a proper delete[] 2005-01-28 15:15:23 +00:00
ehofman 181e6eac75 MSVC fixes 2005-01-28 09:32:57 +00:00
ehofman fd1979857c Fix an NVIDIA problem. 2005-01-27 17:49:22 +00:00
ehofman 448bc3facd Add a RenderTexture test program. 2005-01-27 10:56:22 +00:00
ehofman 97cabadb88 Melchior FRANZ:
If alcOpenDevice( NULL ) is NULL, then context is never assigned a
value, and it's pointless to ask for it in the next "if". But as the
ALCcontext that context points to doesn't seem to be fully defined
(OpenAL bug), valgrind still complains ...


Erik Hofman:
Extend this some further and define context=0 otherwise and check for
context != 0 before using it.
2005-01-27 10:47:09 +00:00
ehofman 8e284a70b7 Melchior FRANZ:
Trying to find the bug in tower.cxx (that crashes fgfs quite frequently
for me!), I'm playing with valgrind again. Until I'm in the ATC subsystem
there will be some other bugs and nitpicking along the way.

valgrind doesn't like that imgage->tmp is once allocated with new and
once with new[], sometimes with malloc() (via map), and sometimes freed
with delete (not delete[]!) and sometimes with free(). With simple types
such as GLubyte this shouldn't really make a difference, but anyway.

Also, I promised that I'd send patches for "if (foo) delete foo;" as
I'm making other changes to concerned files. texture.cxx is one with a
few occurrences thereof. (Remember: C++ explicitly allows to delete
null-pointers, so this check is redundant, and hence not tolerated in
other projects, such as KDE. Doesn't have to impress us, of course.  :-)

Also, fixes 4 signed/unsigned warnings (gcc 3.3.4)
2005-01-27 10:42:31 +00:00
ehofman 73f9febe06 Add Mark Haris' RenderTexture class based on SimGear's extesion support files. 2005-01-27 10:39:15 +00:00
andy 6a6cc22e9c Move error handling in setupFuncall above the stack frame creation.
The error properly belongs to the enclosing scope, not the called
(non-)function.  This bug was fixed a few months back in my private
tree, but Melchior just discovered that the new Concorde scripts
tickle it.  I really need to re-synchronize SimGear with my own Nasal
tree...
2005-01-25 22:37:22 +00:00
ehofman b293639b76 Add a bunch of extensions in preparation of render-to-texture support. 2005-01-25 18:33:59 +00:00
curt f06036be09 Frederic Bouvier:
The Beaver triggered a problem ( uninitialized variable ). Here is the updated
code.
2005-01-24 21:46:12 +00:00
curt 867571af78 Frederic Bouvier:
this is the animation code that do randomisation of the spin animation. The XML tags are modified to support the syntax below :

  <use-personality type="bool">true</use-personality>
  <factor>
    <random>
      <min>1.8</min>
      <max>2.2</max>
    </random>
  </factor>
  <starting-pos-deg>
    <random>
      <min>0</min>
      <max>360</max>
    </random>
  </starting-pos-deg>

instead of usual :

  <factor>1.42</factor>
  <starting-deg-pos>42.0</starting-deg-pos>
2005-01-24 19:49:35 +00:00
ehofman f6314d3124 Erik Hofman
1. Remove the dependency on alut  which (on certein platforms) might pose
   some restrictuons on commercial use.

2. Create a sound source just prior to playing the sound and destroy it
   again when the sound has stopped. This should greatly reduce the
   error reports from Windows users.
2005-01-24 15:51:37 +00:00
ehofman 1e87dd7903 Melchior FRANZ:
The following patches to SimGear & FlightGear ...

- create an FGMetar abstraction layer, whose purpose is:
  * provide defaults for unset values
  * interpolate/randomize data (GREATER_THAN)
  * derive additional values (time, age, snow cover)
  * consider minimum identifier (CAVOK, mil. color codes)
- add rain/hail/snow/snowcover support on the METAR side
- add max age of METAR data handling (currently set to
- add support for an external METAR cache proxy server
- add CAVOK handling
- set missing year/month in regular METAR messages
- fix a small bug in metar.cxx (wrong return value)
2005-01-20 09:28:04 +00:00
203 changed files with 14427 additions and 28725 deletions
+1 -1
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.8
PROJECT_NUMBER = 0.3.9
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
+1 -1
View File
@@ -10,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/admin/am2dsp.pl)
#
# Rule to build RPM distribution package
+37 -10
View File
@@ -1,7 +1,34 @@
New in 0.3.9
* November 17, 2005
* Add support for OpenAL 1.1 (with a separate alut library.)
* Add support for volumetric shadows. Aircraft can cast shadows on themselves
as well as onto the ground (by Harald Johnsen.)
* New 3d volumetric clouds by Harald Johnsen (along with several rounds of
followup fixes and improvements.)
* Remove Mark Harris's old 3d clouds because they were never properly
integrated. And we now have new 3d clouds.
* Add support for seasonal textures (with a set of winter textures added
to FlightGear.)
* Updated Nasal scripting system. Adds several new syntax convenience
features, fixes parser bugs, fixes several internal bugs.
* Our 3d cockpit jitter problem is fixed (woohoo!)
* Add code to support rendering to a texture.
* Allow "tip" popups to pop themselves down after the appropriate
timeout, even if the sim time is paused.
* Various low model level animation fixes and additions ... color,
transparency, 'chrome' effects, randomized spin, etc.
* Create our own portable stdint.h implementation.
* Fixed several memory leaks.
* removeChildren() added to the property system.
* Fix many cases of 'const'.
* Fixes for cygwin, solaris/sun, Mac OS X, MSVC, gcc-3.4.x.
New in 0.3.8
* January 18, 2005
* Configure script does a sanity check for the existance of openal.
* Configure script does a sanity check for the existence of openal.
* Better pthreads detection for FreeBSD.
* Abstract out the location of gl.h, glu.h, and glut.h so we can more
easily support MacOS which puts these in an oddball location.
@@ -15,7 +42,7 @@ New in 0.3.8
* Fixes to property tree loading and saving.
* Make volume inaudible at startup.
* Solaris fixes.
* For low density cloud coverages, blend the layer to nothing as we pass
* For low density cloud coverage, blend the layer to nothing as we pass
through instead of fully engulfing the aircraft in the cloud.
* Add several new capabilities to the texture management code for building
normal maps and doing some simple on-the-fly effects on textures.
@@ -58,7 +85,7 @@ New in 0.3.5
* Support VASI/PAPI lights correctly.
* Fixes to cloud animation.
* Updates to sky dome coloring as well as sun/moon coloring.
* Vary environment lighting with visibility (subtlely.)
* Vary environment lighting with visibility (subtlety.)
* Support control of alpha test in model animation.
* Complete rewrite of the event manager.
* Updates to low level socket code to make it more flexible.
@@ -109,7 +136,7 @@ New in 0.3.2
management, basic model and model animation management, sky
rendering, and low level loaders for the "TerraGear" tile object format.
* Removed support of the flat shaded and non-textured material
property varients. You can still do these things, but extra states
property variants. You can still do these things, but extra states
are no longer set up automatically.
* Removed 3d clouds from the default build ... these need a maintainer
or better yet, a complete plib-based rewrite.
@@ -154,7 +181,7 @@ New in 0.2.0
* Removed efence support (in favor of valgrind.)
* Added a javascript interpreter.
* SGSocket reimplimented on top of plib/net libs.
* SGSocket reimplemented on top of plib/net libs.
* Added a new random number generation algorithm.
* Total rewrite of the strutils package.
@@ -164,7 +191,7 @@ New in 0.2.0
* Mac OS X fixes.
* Irix fixes.
* Code clean ups to remove warning messages.
* Optimizations in sg_binobj to reduce the amout of memory copying
* Optimizations in sg_binobj to reduce the amount of memory copying
needed when loading a binobj format file.
* Fixed a couple places where variables could be used before they were
initialized.
@@ -184,7 +211,7 @@ New in 0.0.18
* Upgrade to metakit-2.4.2-32.tar.gz (latest upstream release)
* Added support for point objects in the scenery file format.
* Additions to the binary file format to make it *much* more flexible.
For each major primative type: points, triangles, fans, and strips, you
For each major primitive type: points, triangles, fans, and strips, you
can specify an index list of vertices, normals, colors, and texture
coordinates. You can skip any of these you like to save on space.
* Added support for new file features in the binary -> ascii scenery file
@@ -235,7 +262,7 @@ New in 0.0.17pre1
New in 0.0.16
* July 12, 2001
* Various changes to the property manager implimentation to better support
* Various changes to the property manager implementation to better support
dumping out the desired portions of the property tree to file.
* Don't compile the metakit demos by default (causes problems for Irix)'
* Other various tweaks for Irix.
@@ -278,7 +305,7 @@ New in 0.0.15
read/write routines.
* Added doxygen comments for all public interface code. Documentation
can be accessed via the SimGear web page.
* Many FG -> SG name space changes for better consistancy throughout
* Many FG -> SG name space changes for better consistency throughout
this package.
* Added property aliases, repeated name tags, and a general xml
inclusion facilities. Many other property manager clean ups
@@ -369,4 +396,4 @@ New in 0.0.4
New in 0.0.3
* Release that conincides with FlightGear-0.7.2
* Release that coincides with FlightGear-0.7.2
+129 -917
View File
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -3,7 +3,7 @@ dnl originally from ncftp 2.3.0
dnl added wi_EXTRA_PDIR and wi_ANSI_C
dnl $Id$
dnl
AC_DEFUN(wi_EXTRA_IDIR, [
AC_DEFUN([wi_EXTRA_IDIR], [
incdir="$1"
if test -r $incdir ; then
case "$CPPFLAGS" in
@@ -25,7 +25,7 @@ dnl
dnl
dnl
dnl
AC_DEFUN(wi_EXTRA_LDIR, [
AC_DEFUN([wi_EXTRA_LDIR], [
mylibdir="$1"
if test -r $mylibdir ; then
case "$LDFLAGS" in
@@ -47,7 +47,7 @@ dnl
dnl __FP__
dnl
dnl
AC_DEFUN(wi_EXTRA_PDIR, [
AC_DEFUN([wi_EXTRA_PDIR], [
progdir="$1"
if test -r $progdir ; then
case "$PATH" in
@@ -76,7 +76,7 @@ dnl
dnl If you want to look for subdirectories in include/lib directories,
dnl you pass the names in argument 3, otherwise pass a dash.
dnl
AC_DEFUN(wi_EXTRA_DIRS, [echo "checking for extra include and lib directories..." 1>&6
AC_DEFUN([wi_EXTRA_DIRS], [echo "checking for extra include and lib directories..." 1>&6
ifelse([$1], yes, [dnl
b1=`cd .. ; pwd`
b2=`cd ../.. ; pwd`
@@ -111,7 +111,7 @@ done
dnl
dnl
dnl
AC_DEFUN(wi_HPUX_CFLAGS,
AC_DEFUN([wi_HPUX_CFLAGS],
[AC_MSG_CHECKING(if HP-UX ansi C compiler flags are needed)
AC_REQUIRE([AC_PROG_CC])
os=`uname -s | tr '[A-Z]' '[a-z]'`
@@ -144,7 +144,7 @@ AC_MSG_RESULT($ac_cv_hpux_flags)
dnl
dnl
dnl
AC_DEFUN(wi_CFLAGS, [AC_REQUIRE([AC_PROG_CC])
AC_DEFUN([wi_CFLAGS], [AC_REQUIRE([AC_PROG_CC])
wi_HPUX_CFLAGS
if test "$CFLAGS" = "" ; then
CFLAGS="-O"
@@ -165,7 +165,7 @@ wi_HPUX_CFLAGS
dnl
dnl
dnl
AC_DEFUN(wi_PROTOTYPES, [
AC_DEFUN([wi_PROTOTYPES], [
AC_MSG_CHECKING(if the compiler supports function prototypes)
AC_TRY_COMPILE(,[extern void exit(int status);],[wi_cv_prototypes=yes
AC_DEFINE(PROTOTYPES)],wi_cv_prototypes=no)
@@ -174,7 +174,7 @@ AC_MSG_RESULT($wi_cv_prototypes)
dnl
dnl
dnl
AC_DEFUN(wi_ANSI_C, [
AC_DEFUN([wi_ANSI_C], [
AC_MSG_CHECKING(ANSI-style function definitions)
AC_TRY_COMPILE(,[int blubb(int x) { return 0; }],[wi_cv_ansi_funcs=yes
AC_DEFINE(ANSI_FUNCS)],wi_cv_ansi_funcs=no)
@@ -183,7 +183,7 @@ AC_MSG_RESULT($wi_cv_ansi_funcs)
dnl
dnl
dnl
AC_DEFUN(wi_HEADER_SYS_SELECT_H, [
AC_DEFUN([wi_HEADER_SYS_SELECT_H], [
# See if <sys/select.h> is includable after <sys/time.h>
if test "$ac_cv_header_sys_time_h" = no ; then
AC_CHECK_HEADERS(sys/time.h sys/select.h)
@@ -211,7 +211,7 @@ fi
dnl
dnl
dnl
AC_DEFUN(wi_LIB_RESOLV, [
AC_DEFUN([wi_LIB_RESOLV], [
# See if we could access two well-known sites without help of any special
# libraries, like resolv.
@@ -244,7 +244,7 @@ dnl
dnl
dnl
AC_DEFUN(wi_LIB_NSL, [
AC_DEFUN([wi_LIB_NSL], [
AC_MSG_CHECKING(if we can use -lnsl)
ac_save_LIBS="$LIBS";
LIBS="$LIBS -lnsl";
@@ -261,7 +261,7 @@ dnl
dnl
dnl
AC_DEFUN(nc_PATH_PROG_ZCAT, [
AC_DEFUN([nc_PATH_PROG_ZCAT], [
AC_PATH_PROG(GZCAT,gzcat)
AC_PATH_PROG(ZCAT,zcat)
if test "x$GZCAT" = x ; then
@@ -287,7 +287,7 @@ fi
dnl
dnl
dnl
AC_DEFUN(wi_SYSV_EXTRA_DIRS, [
AC_DEFUN([wi_SYSV_EXTRA_DIRS], [
# Use System V because their curses extensions are required. This must
# be done early so we use the -I and -L in the library checks also.
# This is mostly a Solaris/SunOS hack. Note that doing this will also
@@ -305,7 +305,7 @@ fi
dnl
dnl
dnl
AC_DEFUN(wi_DEFINE_UNAME, [
AC_DEFUN([wi_DEFINE_UNAME], [
# Get first 127 chars of all uname information. Some folks have
# way too much stuff there, so grab only the first 127.
unam=`uname -a 2>/dev/null | cut -c1-127`
@@ -316,7 +316,7 @@ fi
dnl
dnl
dnl
AC_DEFUN(wi_READLINE_WITH_NCURSES, [
AC_DEFUN([wi_READLINE_WITH_NCURSES], [
# Readline and Ncurses could both define "backspace".
# Warn about this if we have both things in our definitions list.
@@ -352,7 +352,7 @@ dnl
dnl AC_EXT_DAYLIGHT
dnl Check for an external variable daylight. Stolen from w3c-libwww.
AC_DEFUN(AC_EXT_DAYLIGHT,
AC_DEFUN([AC_EXT_DAYLIGHT],
[ AC_MSG_CHECKING(int daylight variable)
AC_TRY_COMPILE([#include <time.h>], [return daylight;],
have_daylight=yes,
@@ -362,7 +362,7 @@ AC_MSG_RESULT($have_daylight)
dnl AC_EXT_TIMEZONE
dnl Check for an external variable timezone. Stolen from tcl-8.0.
AC_DEFUN(AC_EXT_TIMEZONE,
AC_DEFUN([AC_EXT_TIMEZONE],
[
#
# Its important to include time.h in this check, as some systems (like convex)
@@ -395,7 +395,7 @@ fi
## AC_BZ_SET_COMPILER: Addition by Theodore Papadopoulo
## Patch by Jim McKelvey: change sed -e 's/ /@/g' to sed -e 's/ /@/'
AC_DEFUN(AC_SG_SET_COMPILER,
AC_DEFUN([AC_SG_SET_COMPILER],
[cxxwith=`echo $1 | sed -e 's/ /@/'`
case "$cxxwith" in
*:*@*) # Full initialization syntax
+6 -6
View File
@@ -8,7 +8,7 @@ dnl Require at least automake 2.52
AC_PREREQ(2.52)
dnl Initialize the automake stuff
AM_INIT_AUTOMAKE(SimGear, 0.3.8)
AM_INIT_AUTOMAKE(SimGear, 0.3.9)
dnl Specify KAI C++ compiler and flags.
dnl Borrowed with slight modification from blitz distribution.
@@ -121,7 +121,7 @@ fi
dnl Determine an extra directories to add to include/lib search paths
case "${host}" in
*-apple-darwin* | *-*-mingw32*)
*-apple-darwin* | *-*-cygwin* | *-*-mingw32*)
echo no EXTRA_DIRS for $host
;;
@@ -170,7 +170,7 @@ if test "x$ac_cv_header_pthread_h" = "xyes"; then
if test "x$ac_cv_search_pthread_exit" = "x-lc_r"; then
CXXFLAGS="-pthread $CXXFLAGS"
CFLAGS="-pthread $FLAGS"
CFLAGS="-pthread $CFLAGS"
fi
fi
@@ -258,7 +258,8 @@ OPENAL_OK="no"
case "${host}" in
*-*-cygwin* | *-*-mingw32*)
dnl CygWin under Windoze.
INCLUDES="$INCLUDES -I/usr/local/include"
LIBS="$LIBS -L/usr/local/lib"
AC_SEARCH_LIBS(alGenBuffers, openal32)
AC_SEARCH_LIBS(alutInit, [ openal32 ALut ] )
LIBS="$LIBS -lwinmm -ldsound -ldxguid -lole32"
@@ -281,6 +282,7 @@ case "${host}" in
save_LIBS=$LIBS
LIBS="$LIBS $thread_LIBS"
AC_SEARCH_LIBS(alGenBuffers, openal)
AC_SEARCH_LIBS(alutInit, [ alut openal ] )
OPENAL_OK="$ac_cv_search_alGenBuffers"
openal_LIBS="$LIBS"
LIBS=$save_LIBS
@@ -424,7 +426,6 @@ AC_CONFIG_FILES([ \
simgear/scene/material/Makefile \
simgear/scene/model/Makefile \
simgear/scene/sky/Makefile \
simgear/scene/sky/clouds3d/Makefile \
simgear/scene/tgdb/Makefile \
simgear/screen/Makefile \
simgear/serial/Makefile \
@@ -432,7 +433,6 @@ AC_CONFIG_FILES([ \
simgear/structure/Makefile \
simgear/threads/Makefile \
simgear/timing/Makefile \
simgear/xgl/Makefile \
simgear/xml/Makefile \
])
AC_OUTPUT
+1 -2
View File
@@ -32,7 +32,6 @@ SUBDIRS = \
serial \
sound \
$(SGTHREAD_DIR) \
timing \
xgl
timing
DIST_SUBDIRS = $(SUBDIRS) compatibility threads
+23 -7
View File
@@ -208,7 +208,7 @@ double SGBucket::get_width_m() const {
double clat_rad = clat * SGD_DEGREES_TO_RADIANS;
double cos_lat = cos( clat_rad );
double local_radius = cos_lat * SG_EQUATORIAL_RADIUS_M;
double local_perimeter = 2.0 * local_radius * SGD_PI;
double local_perimeter = local_radius * SGD_2PI;
double degree_width = local_perimeter / 360.0;
return sg_bucket_span( get_center_lat() ) * degree_width;
@@ -217,7 +217,7 @@ double SGBucket::get_width_m() const {
// return height of the tile in meters
double SGBucket::get_height_m() const {
double perimeter = 2.0 * SG_EQUATORIAL_RADIUS_M * SGD_PI;
double perimeter = SG_EQUATORIAL_RADIUS_M * SGD_2PI;
double degree_height = perimeter / 360.0;
return SG_BUCKET_SPAN * degree_height;
@@ -271,16 +271,32 @@ void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) {
#endif
// longitude difference
double c1_lon = b1.get_center_lon();
double c2_lon = b2.get_center_lon();
double diff_lon = c2_lon - c1_lon;
double span;
if ( sg_bucket_span(c1_lat) <= sg_bucket_span(c2_lat) ) {
double diff_lon=0.0;
double span=0.0;
SGBucket tmp_bucket;
// To handle crossing the bucket size boundary
// we need to account for different size buckets.
if ( sg_bucket_span(c1_lat) <= sg_bucket_span(c2_lat) )
{
span = sg_bucket_span(c1_lat);
} else {
span = sg_bucket_span(c2_lat);
}
diff_lon = b2.get_center_lon() - b1.get_center_lon();
if (diff_lon <0.0)
{
diff_lon -= b1.get_width()*0.5 + b2.get_width()*0.5 - span;
}
else
{
diff_lon += b1.get_width()*0.5 + b2.get_width()*0.5 - span;
}
#ifdef HAVE_RINT
*dx = (int)rint( diff_lon / span );
#else
+6 -1
View File
@@ -324,7 +324,7 @@
#endif // Native SGI compilers
#if defined ( sun )
#if defined (__sun)
# include <strings.h>
# include <memory.h>
# if defined ( __cplusplus )
@@ -372,11 +372,15 @@
#ifdef __APPLE__
# define SG_GL_H <OpenGL/gl.h>
# define SG_GLX_H <AGL/agl.h>
# define SG_GLU_H <OpenGL/glu.h>
# define SG_GLEXT_H <OpenGL/glext.h>
# define SG_GLUT_H <GLUT/glut.h>
inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
#else
# define SG_GL_H <GL/gl.h>
# define SG_GLX_H <GL/glx.h>
# define SG_GLU_H <GL/glu.h>
# define SG_GLEXT_H <GL/glext.h>
# define SG_GLUT_H <GL/glut.h>
@@ -464,3 +468,4 @@ inline const_mem_fun_ref_t<_Ret,_Tp> mem_fun_ref(_Ret (_Tp::*__f)() const)
#endif // SG_INCOMPLETE_FUNCTIONAL
#endif // _SG_COMPILER_H
+3
View File
@@ -32,6 +32,9 @@
#include <simgear/compiler.h>
#ifdef _MSC_VER
# define _USE_MATH_DEFINES
#endif
#ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
#else
+1 -1
View File
@@ -185,7 +185,7 @@ inline logbuf::int_type
logbuf::overflow( int c )
{
#ifdef _MSC_VER
static has_console = false;
static bool has_console = false;
if ( logging_enabled ) {
if ( !has_console ) {
AllocConsole();
+2 -2
View File
@@ -2,8 +2,8 @@ includedir = @includedir@/environment
lib_LIBRARIES = libsgenvironment.a
include_HEADERS = metar.hxx
include_HEADERS = metar.hxx visual_enviro.hxx
libsgenvironment_a_SOURCES = metar.cxx
libsgenvironment_a_SOURCES = metar.cxx visual_enviro.cxx
INCLUDES = -I$(top_srcdir)
+86 -24
View File
@@ -26,6 +26,7 @@
*/
#include <string>
#include <time.h>
#include <simgear/io/sg_socket.hxx>
#include <simgear/debug/logstream.hxx>
@@ -59,8 +60,10 @@
* double d = n.getDewpoint_C();
* @endcode
*/
SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const string& auth) :
SGMetar::SGMetar(const string& m, const string& proxy, const string& port,
const string& auth, const time_t time) :
_grpcount(0),
_x_proxy(false),
_year(-1),
_month(-1),
_day(-1),
@@ -74,13 +77,17 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const
_wind_range_to(-1),
_temp(NaN),
_dewp(NaN),
_pressure(NaN)
_pressure(NaN),
_rain(false),
_hail(false),
_snow(false),
_cavok(false)
{
if (m.length() == 4 && isalnum(m[0]) && isalnum(m[1]) && isalnum(m[2]) && isalnum(m[3])) {
for (int i = 0; i < 4; i++)
_icao[i] = toupper(m[i]);
_icao[4] = '\0';
_data = loadData(_icao, proxy, port, auth);
_data = loadData(_icao, proxy, port, auth, time);
} else {
_data = new char[m.length() + 2]; // make room for " \0"
strcpy(_data, m.c_str());
@@ -92,7 +99,8 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const
_icao[0] = '\0';
// NOAA preample
scanPreambleDate();
if (!scanPreambleDate())
useCurrentDate();
scanPreambleTime();
// METAR header
@@ -127,6 +135,7 @@ SGMetar::SGMetar(const string& m, const string& proxy, const string& port, const
delete[] _data;
throw sg_io_exception("metar data incomplete (" + _url + ')');
}
_url = "";
}
@@ -143,6 +152,20 @@ SGMetar::~SGMetar()
}
void SGMetar::useCurrentDate()
{
struct tm now;
time_t now_sec = time(0);
#if defined( _MSC_VER ) || defined ( __MINGW32__ )
now = *gmtime(&now_sec);
#else
gmtime_r(&now_sec, &now);
#endif
_year = now.tm_year + 1900;
_month = now.tm_mon + 1;
}
/**
* If called with "KSFO" loads data from
* @code
@@ -157,10 +180,15 @@ SGMetar::~SGMetar()
* @return pointer to Metar data string, allocated by new char[].
* @see rfc2068.txt for proxy spec ("Proxy-Authorization")
*/
char *SGMetar::loadData(const char *id, const string& proxy, const string& port, const string& auth)
char *SGMetar::loadData(const char *id, const string& proxy, const string& port,
const string& auth, time_t time)
{
const int buflen = 512;
char buf[2 * buflen];
string host = proxy.empty() ? "weather.noaa.gov" : proxy;
string path = "/pub/data/observations/metar/stations/";
path += string(id) + ".TXT";
_url = "http://weather.noaa.gov" + path;
@@ -174,24 +202,25 @@ char *SGMetar::loadData(const char *id, const string& proxy, const string& port,
string get = "GET ";
if (!proxy.empty())
get += "http://weather.noaa.gov";
get += path + " HTTP/1.0\r\n";
sprintf(buf, "%ld", time);
get += path + " HTTP/1.0\015\012X-Time: " + buf + "\015\012";
if (!auth.empty())
get += "Proxy-Authorization: " + auth + "\015\012";
get += "\015\012";
sock->writestring(get.c_str());
if (!auth.empty()) {
get = "Proxy-Authorization: " + auth + "\r\n";
sock->writestring(get.c_str());
}
sock->writestring("\r\n");
int i;
const int buflen = 512;
char buf[2 * buflen];
// skip HTTP header
while ((i = sock->readline(buf, buflen)))
while ((i = sock->readline(buf, buflen))) {
if (i <= 2 && isspace(buf[0]) && (!buf[1] || isspace(buf[1])))
break;
if (!strncmp(buf, "X-MetarProxy: ", 9))
_x_proxy = true;
}
if (i) {
i = sock->readline(buf, buflen);
if (i)
@@ -392,7 +421,7 @@ bool SGMetar::scanWind()
if (gust != NaN)
_gust_speed = gust * factor;
_grpcount++;
return false;
return true;
}
@@ -643,14 +672,15 @@ bool SGMetar::scanWeather()
}
string pre, post;
int intensity = 0;
if (*m == '-')
m++, pre = "light ";
m++, pre = "light ", intensity = 1;
else if (*m == '+')
m++, pre = "heavy ";
m++, pre = "heavy ", intensity = 3;
else if (!strncmp(m, "VC", 2))
m += 2, post = "in the vicinity ";
else
pre = "moderate ";
pre = "moderate ", intensity = 2;
int i;
for (i = 0; i < 3; i++) {
@@ -662,6 +692,12 @@ bool SGMetar::scanWeather()
if (!(a = scanToken(&m, phenomenon)))
break;
weather += string(a->text) + " ";
if (!strcmp(a->id, "RA"))
_rain = intensity;
else if (!strcmp(a->id, "HA"))
_hail = intensity;
else if (!strcmp(a->id, "SN"))
_snow = intensity;
}
if (!weather.length())
return false;
@@ -714,8 +750,13 @@ bool SGMetar::scanSkyCondition()
m += i;
if (!scanBoundary(&m))
return false;
cl._coverage = 0;
_clouds.push_back(cl);
if (i == 3) {
cl._coverage = 0;
_clouds.push_back(cl);
} else {
_cavok = true;
}
_m = m;
return true;
}
@@ -907,10 +948,11 @@ bool SGMetar::scanRunwayReport()
if (!strncmp(m, "CLRD", 4)) {
m += 4; // runway cleared
r._deposit = "cleared";
r._deposit_string = "cleared";
} else {
if (scanNumber(&m, &i, 1)) {
r._deposit = runway_deposit[i];
r._deposit = i;
r._deposit_string = runway_deposit[i];
} else if (*m == '/')
m++;
else
@@ -1137,4 +1179,24 @@ const struct Token *SGMetar::scanToken(char **str, const struct Token *list)
return longest;
}
void SGMetarCloud::set(double alt, int cov)
{
_altitude = alt;
if (cov != -1)
_coverage = cov;
}
void SGMetarVisibility::set(double dist, int dir, int mod, int tend)
{
_distance = dist;
if (dir != -1)
_direction = dir;
if (mod != -1)
_modifier = mod;
if (tend != 1)
_tendency = tend;
}
#undef NaN
+35 -14
View File
@@ -67,6 +67,8 @@ public:
DECREASING
};
void set(double dist, int dir = -1, int mod = -1, int tend = -1);
inline double getVisibility_m() const { return _distance; }
inline double getVisibility_ft() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_FEET; }
inline double getVisibility_sm() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_SM; }
@@ -87,7 +89,8 @@ class SGMetarRunway {
friend class SGMetar;
public:
SGMetarRunway() :
_deposit(0),
_deposit(-1),
_deposit_string(0),
_extent(-1),
_extent_string(0),
_depth(NaN),
@@ -96,7 +99,8 @@ public:
_comment(0),
_wind_shear(false) {}
inline const char *getDeposit() const { return _deposit; }
inline int getDeposit() const { return _deposit; }
inline const char *getDepositString() const { return _deposit_string; }
inline double getExtent() const { return _extent; }
inline const char *getExtentString() const { return _extent_string; }
inline double getDepth() const { return _depth; }
@@ -104,13 +108,14 @@ public:
inline const char *getFrictionString() const { return _friction_string; }
inline const char *getComment() const { return _comment; }
inline const bool getWindShear() const { return _wind_shear; }
inline SGMetarVisibility getMinVisibility() const { return _min_visibility; }
inline SGMetarVisibility getMaxVisibility() const { return _max_visibility; }
inline const SGMetarVisibility& getMinVisibility() const { return _min_visibility; }
inline const SGMetarVisibility& getMaxVisibility() const { return _max_visibility; }
protected:
SGMetarVisibility _min_visibility;
SGMetarVisibility _max_visibility;
const char *_deposit;
int _deposit;
const char *_deposit_string;
int _extent;
const char *_extent_string;
double _depth;
@@ -131,6 +136,8 @@ public:
_type(0),
_type_long(0) {}
void set(double alt, int cov = -1);
inline int getCoverage() const { return _coverage; }
inline double getAltitude_m() const { return _altitude; }
inline double getAltitude_ft() const { return _altitude == NaN ? NaN : _altitude * SG_METER_TO_FEET; }
@@ -147,7 +154,8 @@ protected:
class SGMetar {
public:
SGMetar(const string& m, const string& proxy = "", const string& port = "", const string &auth = "");
SGMetar(const string& m, const string& proxy = "", const string& port = "",
const string &auth = "", const time_t time = 0);
~SGMetar();
enum ReportType {
@@ -159,6 +167,7 @@ public:
inline const char *getData() const { return _data; }
inline const char *getUnusedData() const { return _m; }
inline const bool getProxy() const { return _x_proxy; }
inline const char *getId() const { return _icao; }
inline int getYear() const { return _year; }
inline int getMonth() const { return _month; }
@@ -181,10 +190,10 @@ public:
inline int getWindRangeFrom() const { return _wind_range_from; }
inline int getWindRangeTo() const { return _wind_range_to; }
inline SGMetarVisibility& getMinVisibility() { return _min_visibility; }
inline SGMetarVisibility& getMaxVisibility() { return _max_visibility; }
inline SGMetarVisibility& getVertVisibility() { return _vert_visibility; }
inline SGMetarVisibility *getDirVisibility() { return _dir_visibility; }
inline const SGMetarVisibility& getMinVisibility() const { return _min_visibility; }
inline const SGMetarVisibility& getMaxVisibility() const { return _max_visibility; }
inline const SGMetarVisibility& getVertVisibility() const { return _vert_visibility; }
inline const SGMetarVisibility *getDirVisibility() const { return _dir_visibility; }
inline double getTemperature_C() const { return _temp; }
inline double getTemperature_F() const { return _temp == NaN ? NaN : 1.8 * _temp + 32; }
@@ -193,15 +202,21 @@ public:
inline double getPressure_hPa() const { return _pressure == NaN ? NaN : _pressure / 100; }
inline double getPressure_inHg() const { return _pressure == NaN ? NaN : _pressure * SG_PA_TO_INHG; }
inline int getRain() const { return _rain; }
inline int getHail() const { return _hail; }
inline int getSnow() const { return _snow; }
inline bool getCAVOK() const { return _cavok; }
double getRelHumidity() const;
inline vector<SGMetarCloud>& getClouds() { return _clouds; }
inline map<string, SGMetarRunway>& getRunways() { return _runways; }
inline vector<string>& getWeather() { return _weather; }
inline const vector<SGMetarCloud>& getClouds() const { return _clouds; }
inline const map<string, SGMetarRunway>& getRunways() const { return _runways; }
inline const vector<string>& getWeather() const { return _weather; }
protected:
string _url;
int _grpcount;
bool _x_proxy;
char *_data;
char *_m;
char _icao[5];
@@ -219,6 +234,10 @@ protected:
double _temp;
double _dewp;
double _pressure;
int _rain;
int _hail;
int _snow;
bool _cavok;
SGMetarVisibility _min_visibility;
SGMetarVisibility _max_visibility;
@@ -230,6 +249,7 @@ protected:
bool scanPreambleDate();
bool scanPreambleTime();
void useCurrentDate();
bool scanType();
bool scanId();
@@ -253,7 +273,8 @@ protected:
int scanNumber(char **str, int *num, int min, int max = 0);
bool scanBoundary(char **str);
const struct Token *scanToken(char **str, const struct Token *list);
char *loadData(const char *id, const string& proxy, const string& port, const string &auth);
char *loadData(const char *id, const string& proxy, const string& port,
const string &auth, time_t time);
void normalizeData();
};
+698
View File
@@ -0,0 +1,698 @@
// Visual environment helper class
//
// Written by Harald JOHNSEN, started April 2005.
//
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
//
//
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <plib/sg.h>
#include <simgear/constants.h>
#include <simgear/math/sg_random.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/point3d.hxx>
#include <simgear/math/polar3d.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/scene/sky/cloudfield.hxx>
#include <simgear/scene/sky/newcloud.hxx>
#include "visual_enviro.hxx"
#include <vector>
SG_USING_STD(vector);
typedef struct {
Point3D pt;
int depth;
int prev;
} lt_tree_seg;
#define MAX_RAIN_SLICE 200
static float rainpos[MAX_RAIN_SLICE];
#define MAX_LT_TREE_SEG 400
/**
* A class to render lightnings.
*/
class SGLightning {
public:
/**
* Build a new lightning.
* The lightning has a limited life time. It will also play a thunder sounder once.
* @param lon lon longitude in degree
* @param lat lat latitude in degree
* @param alt asl of top of lightning
*/
SGLightning(double lon, double lat, double alt);
~SGLightning();
void lt_Render(void);
void lt_build(void);
void lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize);
// contains all the segments of the lightning
lt_tree_seg lt_tree[MAX_LT_TREE_SEG];
// segment count
int nb_tree;
// position of lightning
double lon, lat, alt;
int sequence_count;
// time to live
double age;
};
typedef vector<SGLightning *> list_of_lightning;
static list_of_lightning lightnings;
SGEnviro sgEnviro;
SGEnviro::SGEnviro(void) :
view_in_cloud(false),
turbulence_enable_state(false),
precipitation_enable_state(true),
lightning_enable_state(false),
soundMgr(NULL),
snd_active(false),
snd_dist(0.0),
last_cloud_turbulence(0.0),
cloud_turbulence(0.0),
elapsed_time(0.0),
dt(0.0),
min_time_before_lt(0.0),
fov_width(55.0),
fov_height(55.0),
precipitation_max_alt(0.0),
precipitation_density(100.0)
{
for(int i = 0; i < MAX_RAIN_SLICE ; i++)
rainpos[i] = sg_random();
radarEcho.reserve(100);
}
SGEnviro::~SGEnviro(void) {
list_of_lightning::iterator iLightning;
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
delete (*iLightning);
}
lightnings.clear();
}
void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) {
view_in_cloud = false;
// ask the impostor cache to do some cleanup
if(SGNewCloud::cldCache)
SGNewCloud::cldCache->startNewFrame();
last_cloud_turbulence = cloud_turbulence;
cloud_turbulence = 0.0;
elapsed_time += delta_time;
min_time_before_lt -= delta_time;
dt = delta_time;
sgMat4 T1, LON, LAT;
sgVec3 axis;
sgMakeTransMat4( T1, p );
sgSetVec3( axis, 0.0, 0.0, 1.0 );
sgMakeRotMat4( LON, lon, axis );
sgSetVec3( axis, 0.0, 1.0, 0.0 );
sgMakeRotMat4( LAT, 90.0 - lat, axis );
sgMat4 TRANSFORM;
sgCopyMat4( TRANSFORM, T1 );
sgPreMultMat4( TRANSFORM, LON );
sgPreMultMat4( TRANSFORM, LAT );
sgCoord pos;
sgSetCoord( &pos, TRANSFORM );
sgMakeCoordMat4( transform, &pos );
last_lon = lon;
last_lat = lat;
last_alt = alt;
radarEcho.clear();
precipitation_max_alt = 400.0;
}
void SGEnviro::endOfFrame(void) {
}
double SGEnviro::get_cloud_turbulence(void) const {
return last_cloud_turbulence;
}
// this can be queried to add some turbulence for example
bool SGEnviro::is_view_in_cloud(void) const {
return view_in_cloud;
}
void SGEnviro::set_view_in_cloud(bool incloud) {
view_in_cloud = incloud;
}
int SGEnviro::get_CacheResolution(void) const {
return SGCloudField::get_CacheResolution();
}
int SGEnviro::get_clouds_CacheSize(void) const {
return SGCloudField::get_CacheSize();
}
float SGEnviro::get_clouds_visibility(void) const {
return SGCloudField::get_CloudVis();
}
float SGEnviro::get_clouds_density(void) const {
return SGCloudField::get_density();
}
bool SGEnviro::get_clouds_enable_state(void) const {
return SGCloudField::get_enable3dClouds();
}
bool SGEnviro::get_turbulence_enable_state(void) const {
return turbulence_enable_state;
}
void SGEnviro::set_CacheResolution(int resolutionPixels) {
SGCloudField::set_CacheResolution(resolutionPixels);
}
void SGEnviro::set_clouds_CacheSize(int sizeKb) {
SGCloudField::set_CacheSize(sizeKb);
}
void SGEnviro::set_clouds_visibility(float distance) {
SGCloudField::set_CloudVis(distance);
}
void SGEnviro::set_clouds_density(float density) {
SGCloudField::set_density(density);
}
void SGEnviro::set_clouds_enable_state(bool enable) {
SGCloudField::set_enable3dClouds(enable);
}
void SGEnviro::set_turbulence_enable_state(bool enable) {
turbulence_enable_state = enable;
}
// rain/snow
float SGEnviro::get_precipitation_density(void) const {
return precipitation_density;
}
bool SGEnviro::get_precipitation_enable_state(void) const {
return precipitation_enable_state;
}
void SGEnviro::set_precipitation_density(float density) {
precipitation_density = density;
}
void SGEnviro::set_precipitation_enable_state(bool enable) {
precipitation_enable_state = enable;
}
// others
bool SGEnviro::get_lightning_enable_state(void) const {
return lightning_enable_state;
}
void SGEnviro::set_lightning_enable_state(bool enable) {
lightning_enable_state = enable;
if( ! enable ) {
// TODO:cleanup
}
}
void SGEnviro::setLight(sgVec4 adj_fog_color) {
sgCopyVec4( fog_color, adj_fog_color );
if( false ) {
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
}
}
void SGEnviro::callback_cloud(float heading, float alt, float radius, int familly, float dist, int cloudId) {
// send data to wx radar
// compute turbulence
// draw precipitation
// draw lightning
// compute illumination
// http://www.pilotfriend.com/flight_training/weather/THUNDERSTORM%20HAZARDS1.htm
double turbulence = 0.0;
if( dist < radius * radius * 2.25f ) {
switch(familly) {
case SGNewCloud::CLFamilly_st:
turbulence = 0.2;
break;
case SGNewCloud::CLFamilly_ci:
case SGNewCloud::CLFamilly_cs:
case SGNewCloud::CLFamilly_cc:
case SGNewCloud::CLFamilly_ac:
case SGNewCloud::CLFamilly_as:
turbulence = 0.1;
break;
case SGNewCloud::CLFamilly_sc:
turbulence = 0.3;
break;
case SGNewCloud::CLFamilly_ns:
turbulence = 0.4;
break;
case SGNewCloud::CLFamilly_cu:
turbulence = 0.5;
break;
case SGNewCloud::CLFamilly_cb:
turbulence = 0.6;
break;
}
// full turbulence inside cloud, half in the vicinity
if( dist > radius * radius )
turbulence *= 0.5;
if( turbulence > cloud_turbulence )
cloud_turbulence = turbulence;
// we can do 'local' precipitations too
}
// convert to LWC for radar (experimental)
// http://www-das.uwyo.edu/~geerts/cwx/notes/chap08/moist_cloud.html
double LWC = 0.0;
switch(familly) {
case SGNewCloud::CLFamilly_st:
LWC = 0.29;
break;
case SGNewCloud::CLFamilly_cu:
LWC = 0.27;
break;
case SGNewCloud::CLFamilly_cb:
LWC = 2.0;
break;
case SGNewCloud::CLFamilly_sc:
LWC = 0.44;
break;
case SGNewCloud::CLFamilly_ci:
LWC = 0.03;
break;
// no data
case SGNewCloud::CLFamilly_cs:
case SGNewCloud::CLFamilly_cc:
case SGNewCloud::CLFamilly_ac:
case SGNewCloud::CLFamilly_as:
LWC = 0.03;
break;
case SGNewCloud::CLFamilly_ns:
LWC = 0.29*2.0;
break;
}
// add to the list for the wxRadar instrument
if( LWC > 0.0 )
radarEcho.push_back( SGWxRadarEcho ( heading, alt, radius, dist, LWC, false, cloudId ) );
// NB:data valid only from cockpit view
// spawn a new lightning
if(lightning_enable_state && min_time_before_lt <= 0.0 && (familly == SGNewCloud::CLFamilly_cb) &&
dist < 15000.0 * 15000.0 && sg_random() > 0.9f) {
double lat, lon;
Point3D orig, dest;
orig.setlat(last_lat * SG_DEGREES_TO_RADIANS );
orig.setlon(last_lon * SG_DEGREES_TO_RADIANS );
orig.setelev(0.0);
dist = sgSqrt(dist);
dest = calc_gc_lon_lat(orig, heading, dist);
lon = dest.lon() * SG_RADIANS_TO_DEGREES;
lat = dest.lat() * SG_RADIANS_TO_DEGREES;
addLightning( lon, lat, alt );
// reset timer
min_time_before_lt = 5.0 + sg_random() * 30;
// DEBUG only
// min_time_before_lt = 5.0;
}
if( (alt - radius * 0.1) > precipitation_max_alt )
switch(familly) {
case SGNewCloud::CLFamilly_st:
case SGNewCloud::CLFamilly_cu:
case SGNewCloud::CLFamilly_cb:
case SGNewCloud::CLFamilly_ns:
case SGNewCloud::CLFamilly_sc:
precipitation_max_alt = alt - radius * 0.1;
break;
}
}
list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
return &radarEcho;
}
// precipitation rendering code
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
sgVec3 light;
sgVec3 min_light = {0.35, 0.35, 0.35};
sgAddVec3( light, fog_color, min_light );
float da = SG_PI * 2.0f / (float) slices;
// low number = faster
float speedf = 2.5f - speed / 200.0;
if( speedf < 1.0f )
speedf = 1.0f;
float lenf = 0.03f + speed / 2000.0;
if( lenf > 0.10f )
lenf = 0.10f;
float t = fmod((float) elapsed_time, speedf) / speedf;
// t = 0.1f;
if( !down )
t = 1.0f - t;
float angle = 0.0f;
glColor4f(1.0f, 0.7f, 0.7f, 0.9f);
glBegin(GL_LINES);
int rainpos_indice = 0;
for( int i = 0 ; i < slices ; i++ ) {
float x = cos(angle) * baseRadius;
float y = sin(angle) * baseRadius;
angle += da;
sgVec3 dir = {x, -height, y};
// rain drops at 2 different speed to simulate depth
float t1 = (i & 1 ? t : t + t) + rainpos[rainpos_indice];
if(t1 > 1.0f) t1 -= 1.0f;
if(t1 > 1.0f) t1 -= 1.0f;
// distant raindrops are more transparent
float c = (i & 1 ? t1 * 0.5f : t1 * 0.9f);
glColor4f(c * light[0], c * light[1], c * light[2], c);
sgVec3 p1, p2;
sgScaleVec3(p1, dir, t1);
// distant raindrops are shorter
float t2 = t1 + (i & 1 ? lenf : lenf+lenf);
sgScaleVec3(p2, dir, t2);
glVertex3f(p1[0], p1[1] + height, p1[2]);
glVertex3f(p2[0], p2[1] + height, p2[2]);
if( ++rainpos_indice >= MAX_RAIN_SLICE )
rainpos_indice = 0;
}
glEnd();
}
void SGEnviro::drawRain(double pitch, double roll, double heading, double speed, double rain_norm) {
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
glDisable( GL_FOG );
glDisable(GL_LIGHTING);
int slice_count = (40.0 + rain_norm*150.0)* precipitation_density / 100.0;
float angle = speed;
if( angle > 90.0 )
angle = 90.0;
glPushMatrix();
// TODO:find the real view orientation, not the AC one
// the cone rotate with speed
angle = -pitch - angle;
glRotatef(angle, 1.0, 0.0, 0.0);
glRotatef(roll, 0.0, 1.0, 0.0);
glRotatef(heading, 0.0, 0.0, 1.0);
// up cone
DrawCone2(15.0, 30.0, slice_count, true, rain_norm, speed);
// down cone (usually not visible)
if(angle > 0.0 || heading != 0.0)
DrawCone2(15.0, -30.0, slice_count, false, rain_norm, speed);
glPopMatrix();
glEnable(GL_LIGHTING);
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
glEnable( GL_FOG );
glEnable(GL_DEPTH_TEST);
}
void SGEnviro::set_soundMgr(SGSoundMgr *mgr) {
soundMgr = mgr;
}
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double speed) {
if( precipitation_enable_state && rain_norm > 0.0)
if( precipitation_max_alt >= last_alt )
drawRain(pitch, roll, heading, speed, rain_norm);
}
SGLightning::SGLightning(double _lon, double _lat, double _alt) :
lon(_lon),
lat(_lat),
alt(_alt),
age(1.0 + sg_random() * 4.0),
nb_tree(0)
{
// sequence_count = 1 + sg_random() * 5.0;
lt_build();
}
SGLightning::~SGLightning() {
}
// lightning rendering code
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
sgVec3 dir, newdir;
int nseg = 0;
Point3D pt = start;
if( nbseg == 50 )
sgSetVec3( dir, 0.0, -1.0, 0.0 );
else {
sgSetVec3( dir, sg_random() - 0.5f, sg_random() - 0.5f, sg_random() - 0.5f);
sgNormaliseVec3(dir);
}
if( nb_tree >= MAX_LT_TREE_SEG )
return;
lt_tree[nb_tree].depth = tree_nr;
nseg = 0;
lt_tree[nb_tree].pt = pt;
lt_tree[nb_tree].prev = -1;
nb_tree ++;
// TODO:check agl
while(nseg < nbseg && pt.y() > 0.0) {
int prev = nb_tree - 1;
nseg++;
// add a branch
if( energy * sg_random() > 0.8f )
lt_build_tree_branch(tree_nr + 1, pt, energy * 0.9f, nbseg == 50 ? 10 : nbseg * 0.4f, segsize * 0.7f);
if( nb_tree >= MAX_LT_TREE_SEG )
return;
sgSetVec3(newdir, (sg_random() - 0.5f), (sg_random() - 0.5f) - (nbseg == 50 ? 0.5f : 0.0), (sg_random() - 0.5f));
sgNormaliseVec3(newdir);
sgAddVec3( dir, newdir);
sgNormaliseVec3(dir);
sgVec3 scaleDir;
sgScaleVec3( scaleDir, dir, segsize * energy * 0.5f );
pt[PX] += scaleDir[0];
pt[PY] += scaleDir[1];
pt[PZ] += scaleDir[2];
lt_tree[nb_tree].depth = tree_nr;
lt_tree[nb_tree].pt = pt;
lt_tree[nb_tree].prev = prev;
nb_tree ++;
}
}
void SGLightning::lt_build(void) {
Point3D top;
nb_tree = 0;
top[PX] = 0 ;
top[PY] = alt;
top[PZ] = 0;
lt_build_tree_branch(0, top, 1.0, 50, top[PY] / 8.0);
if( ! sgEnviro.soundMgr )
return;
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
double course = 0.0, dist = 0.0;
calc_gc_course_dist( dest, start, &course, &dist );
if( dist < 10000.0 && ! sgEnviro.snd_playing && (dist < sgEnviro.snd_dist || ! sgEnviro.snd_active) ) {
sgEnviro.snd_timer = 0.0;
sgEnviro.snd_wait = dist / 340;
sgEnviro.snd_dist = dist;
sgEnviro.snd_pos_lat = lat;
sgEnviro.snd_pos_lon = lon;
sgEnviro.snd_active = true;
sgEnviro.snd_playing = false;
}
}
void SGLightning::lt_Render(void) {
float flash = 0.5;
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
flash = sg_random() * 0.75f + 0.25f;
float h = lt_tree[0].pt[PY];
sgVec4 col={0.62f, 0.83f, 1.0f, 1.0f};
sgVec4 c;
#define DRAW_SEG() \
{glBegin(GL_LINES); \
glColor4fv(c); \
glVertex3f(lt_tree[n].pt[PX], lt_tree[n].pt[PZ], lt_tree[n].pt[PY]); \
glVertex3f(lt_tree[lt_tree[n].prev].pt[PX], lt_tree[lt_tree[n].prev].pt[PZ], lt_tree[lt_tree[n].prev].pt[PY]); \
glEnd();}
glDepthMask( GL_FALSE );
glEnable(GL_BLEND);
glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_LIGHTING);
glDisable( GL_FOG );
glPushMatrix();
sgMat4 modelview, tmp;
ssgGetModelviewMatrix( modelview );
sgCopyMat4( tmp, sgEnviro.transform );
sgPostMultMat4( tmp, modelview );
ssgLoadModelviewMatrix( tmp );
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
double course = 0.0, dist = 0.0;
calc_gc_course_dist( dest, start, &course, &dist );
double ax = 0.0, ay = 0.0;
ax = cos(course) * dist;
ay = sin(course) * dist;
glTranslatef( ax, ay, -sgEnviro.last_alt );
sgEnviro.radarEcho.push_back( SGWxRadarEcho ( course, 0.0, 0.0, dist, age, true, 0 ) );
for( int n = 0 ; n < nb_tree ; n++ ) {
if( lt_tree[n].prev < 0 )
continue;
float t1 = sgLerp(0.5, 1.0, lt_tree[n].pt[PY] / h);
t1 *= flash;
if( lt_tree[n].depth >= 2 ) {
glLineWidth(3);
sgScaleVec4(c, col, t1 * 0.6f);
DRAW_SEG();
} else {
if( lt_tree[n].depth == 0 ) {
glLineWidth(12);
sgScaleVec4(c, col, t1 * 0.5f);
DRAW_SEG();
glLineWidth(6);
sgScaleVec4(c, col, t1);
DRAW_SEG();
} else {
glLineWidth(6);
sgScaleVec4(c, col, t1 * 0.7f);
DRAW_SEG();
}
if( lt_tree[n].depth == 0 )
glLineWidth(3);
else
glLineWidth(2);
sgSetVec4(c, t1, t1, t1, t1);
DRAW_SEG();
}
}
glLineWidth(1);
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
glPopMatrix();
glDepthMask( GL_TRUE );
glEnable( GL_FOG );
glEnable(GL_LIGHTING);
}
void SGEnviro::addLightning(double lon, double lat, double alt) {
if( lightnings.size() > 10)
return;
SGLightning *lt= new SGLightning(lon, lat, alt);
lightnings.push_back(lt);
}
void SGEnviro::drawLightning(void) {
list_of_lightning::iterator iLightning;
// play 'thunder' for lightning
if( snd_active )
if( !snd_playing ) {
// wait until sound has reached us
snd_timer += dt;
if( snd_timer >= snd_wait ) {
snd_playing = true;
// compute relative position of lightning
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
Point3D dest( snd_pos_lon*SG_DEGREES_TO_RADIANS, snd_pos_lat*SG_DEGREES_TO_RADIANS, 0.0 );
double course = 0.0, dist = 0.0;
calc_gc_course_dist( dest, start, &course, &dist );
double ax = 0.0, ay = 0.0;
ax = cos(course) * dist;
ay = sin(course) * dist;
SGSoundSample *snd = soundMgr->find("thunder");
if( snd ) {
ALfloat pos[3]={ax, ay, -sgEnviro.last_alt };
snd->set_source_pos(pos);
snd->play_once();
}
}
} else {
if( !soundMgr->is_playing("thunder") ) {
snd_active = false;
snd_playing = false;
}
}
if( ! lightning_enable_state )
return;
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
if( dt )
if( sg_random() > 0.95f )
(*iLightning)->lt_build();
(*iLightning)->lt_Render();
(*iLightning)->age -= dt;
if( (*iLightning)->age < 0.0 ) {
delete (*iLightning);
lightnings.erase( iLightning );
break;
}
}
}
void SGEnviro::setFOV( float w, float h ) {
fov_width = w;
fov_height = h;
}
void SGEnviro::getFOV( float &w, float &h ) {
w = fov_width;
h = fov_height;
}
+228
View File
@@ -0,0 +1,228 @@
// Visual environment helper class
//
// Written by Harald JOHNSEN, started April 2005.
//
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
//
//
#ifndef _VISUAL_ENVIRO_HXX
#define _VISUAL_ENVIRO_HXX
#include <simgear/compiler.h>
#include STL_STRING
#include <vector>
SG_USING_STD(vector);
SG_USING_STD(string);
class SGLightning;
class SGSoundMgr;
/**
* Simulate some echo on a weather radar.
* Container class for the wx radar instrument.
*/
class SGWxRadarEcho {
public:
SGWxRadarEcho(float _heading, float _alt, float _radius, float _dist, double _LWC, bool _lightning, int _cloudId) :
heading( _heading ),
alt ( _alt ),
radius ( _radius ),
dist ( _dist ),
LWC ( _LWC ),
lightning ( _lightning ),
cloudId ( _cloudId )
{}
/** the heading in radian is versus north */
float heading;
float alt, radius, dist;
/** reflectivity converted to liquid water content. */
double LWC;
/** if true then this data is for a lightning else it is for water echo. */
bool lightning;
/** Unique identifier of cloud */
int cloudId;
};
typedef vector<SGWxRadarEcho> list_of_SGWxRadarEcho;
/**
* Visual environment helper class.
*/
class SGEnviro {
friend class SGLightning;
private:
void DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed);
void lt_update(void);
bool view_in_cloud;
bool precipitation_enable_state;
float precipitation_density;
float precipitation_max_alt;
bool turbulence_enable_state;
double last_cloud_turbulence, cloud_turbulence;
bool lightning_enable_state;
double elapsed_time, dt;
sgVec4 fog_color;
sgMat4 transform;
double last_lon, last_lat, last_alt;
SGSoundMgr *soundMgr;
bool snd_active, snd_playing;
double snd_timer, snd_wait, snd_pos_lat, snd_pos_lon, snd_dist;
double min_time_before_lt;
float fov_width, fov_height;
/** a list of all the radar echo. */
list_of_SGWxRadarEcho radarEcho;
public:
SGEnviro();
~SGEnviro();
/**
* Forward a few states used for renderings.
*/
void startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time);
void endOfFrame(void);
/**
* Whenever a cloud is drawn we check his 'impact' on the environment.
* @param heading direction of cloud in radians
* @param alt asl of cloud in meters
* @param radius radius of cloud in meters
* @param familly cloud familly
* @param dist squared dist to cloud in meters
*/
void callback_cloud(float heading, float alt, float radius, int familly, float dist, int cloudId);
void drawRain(double pitch, double roll, double heading, double speed, double rain_norm);
/**
* Draw rain or snow precipitation around the viewer.
* @param rain_norm rain normalized intensity given by metar class
* @param snow_norm snow normalized intensity given by metar class
* @param hail_norm hail normalized intensity given by metar class
* @param pitch pitch rotation of viewer
* @param roll roll rotation of viewer
* @param speed moving speed of viewer in kt
*/
void drawPrecipitation(double rain_norm, double snow_norm, double hail_norm,
double pitch, double roll, double heading, double speed);
/**
* Draw the lightnings spawned by cumulo nimbus.
*/
void drawLightning(void);
/**
* Forward the fog color used by the rain rendering.
* @param adj_fog_color color of the fog
*/
void setLight(sgVec4 adj_fog_color);
// this can be queried to add some turbulence for example
bool is_view_in_cloud(void) const;
void set_view_in_cloud(bool incloud);
double get_cloud_turbulence(void) const;
// Clouds
// return the size of the memory pool used by texture impostors
int get_clouds_CacheSize(void) const;
int get_CacheResolution(void) const;
float get_clouds_visibility(void) const;
float get_clouds_density(void) const;
bool get_clouds_enable_state(void) const;
bool get_turbulence_enable_state(void) const;
/**
* Set the size of the impostor texture cache for 3D clouds.
* @param sizeKb size of the texture pool in Kb
*/
void set_clouds_CacheSize(int sizeKb);
/**
* Set the resolution of the impostor texture for 3D clouds.
* @param resolutionPixels size of each texture in pixels (64|128|256)
*/
void set_CacheResolution(int resolutionPixels);
/**
* Set the maximum range used when drawing clouds.
* Clouds are blended from totaly transparent at max range to totaly opaque around the viewer
* @param distance in meters
*/
void set_clouds_visibility(float distance);
/**
* Set the proportion of clouds that will be rendered to limit drop in FPS.
* @param density 0..100 no clouds drawn when density == 0, all are drawn when density == 100
*/
void set_clouds_density(float density);
/**
* Enable or disable the use of 3D clouds.
* @param enable when false we draw the 2D layers
*/
void set_clouds_enable_state(bool enable);
/**
* Enable or disable the use of proximity cloud turbulence.
* @param enable when true the turbulence is computed based on type of cloud around the AC
*/
void set_turbulence_enable_state(bool enable);
// rain/snow
float get_precipitation_density(void) const;
bool get_precipitation_enable_state(void) const;
void set_precipitation_density(float density);
/**
* Enable or disable the rendering of precipitation around the viewer.
* @param enable when true we will draw precipitation depending on metar data
*/
void set_precipitation_enable_state(bool enable);
// others
bool get_lightning_enable_state(void) const;
/**
* Enable or disable the rendering of lightning and the thunder sound.
* @param enable when true we will draw lightning spwaned by cumulonimbus
*/
void set_lightning_enable_state(bool enable);
/**
* Spawn a new lighning at specified lon/lat.
* @param lon position of the new lightning
* @param lat position of the new lightning
* @param alt asl of the starting point of the lightning in meters
*/
void addLightning(double lon, double lat, double alt);
/**
* Forward the sound manager instance to be able to play samples.
* @param mgr a running sound manager
*/
void set_soundMgr(SGSoundMgr *mgr);
void setFOV( float w, float h );
void getFOV( float &w, float &h );
list_of_SGWxRadarEcho *get_radar_echo(void);
sgMat4 *get_transform(void) { return &transform; }
};
extern SGEnviro sgEnviro;
#endif // _VISUAL_ENVIRO_HXX
+3
View File
@@ -22,6 +22,9 @@
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <iostream>
+1 -1
View File
@@ -172,7 +172,7 @@ void MoonPos::updatePosition(double mjd, double lst, double lat, Star *ourSun)
// SG_LOG( SG_GENERAL, SG_INFO, "rho = " << rho );
if (geoRa < 0)
geoRa += (2*SGD_PI);
geoRa += SGD_2PI;
HA = lst - (3.8197186 * geoRa);
/* SG_LOG( SG_GENERAL, SG_INFO, "t->getLst() = " << t->getLst()
+1 -1
View File
@@ -80,7 +80,7 @@ void Star::updatePosition(double mjd)
double
actTime, eccAnom,
xv, yv, v, r,
xe, ye, ze, ecl;
xe, ecl;
updateOrbElements(mjd);
+13
View File
@@ -35,6 +35,7 @@ class Star : public CelestialBody
private:
double xs, ys; // the sun's rectangular geocentric coordinates
double ye, ze; // the sun's rectangularequatorial rectangular geocentric coordinates
double distance; // the sun's distance to the earth
public:
@@ -47,6 +48,8 @@ public:
double getw();
double getxs();
double getys();
double getye();
double getze();
double getDistance();
};
@@ -71,6 +74,16 @@ inline double Star::getys()
return ys;
}
inline double Star::getye()
{
return ye;
}
inline double Star::getze()
{
return ze;
}
inline double Star::getDistance()
{
return distance;
+3
View File
@@ -21,6 +21,9 @@
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx>
+4
View File
@@ -1,3 +1,7 @@
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>
#include <unistd.h>
+6
View File
@@ -70,3 +70,9 @@ int SGIOChannel::writestring( const char *str ) {
bool SGIOChannel::close() {
return false;
}
// dummy eof routine
bool SGIOChannel::eof() {
return false;
}
+8
View File
@@ -152,6 +152,14 @@ public:
*/
virtual bool close();
/**
* The eof() method returns true if end of file has been reached
* in a context where that makes sense. Otherwise it returns
* false.
* @return result of eof check
*/
virtual bool eof();
inline void set_type( SGChannelType t ) { type = t; }
inline SGChannelType get_type() const { return type; }
+38 -38
View File
@@ -59,7 +59,7 @@ void sgReadFloat ( gzFile fd, float *var )
read_error = true ;
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int*)var);
sgEndianSwap( (uint32_t *)var);
}
}
@@ -67,7 +67,7 @@ void sgReadFloat ( gzFile fd, float *var )
void sgWriteFloat ( gzFile fd, const float var )
{
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int*)&var);
sgEndianSwap( (uint32_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(float) ) != sizeof(float) ) {
write_error = true ;
@@ -81,7 +81,7 @@ void sgReadDouble ( gzFile fd, double *var )
read_error = true ;
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint64*)var);
sgEndianSwap( (uint64_t *)var);
}
}
@@ -89,7 +89,7 @@ void sgReadDouble ( gzFile fd, double *var )
void sgWriteDouble ( gzFile fd, const double var )
{
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint64*)&var);
sgEndianSwap( (uint64_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(double) ) != sizeof(double) ) {
write_error = true ;
@@ -103,7 +103,7 @@ void sgReadUInt ( gzFile fd, unsigned int *var )
read_error = true ;
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int*)var);
sgEndianSwap( (uint32_t *)var);
}
}
@@ -111,7 +111,7 @@ void sgReadUInt ( gzFile fd, unsigned int *var )
void sgWriteUInt ( gzFile fd, const unsigned int var )
{
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int*)&var);
sgEndianSwap( (uint32_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned int) )
!= sizeof(unsigned int) )
@@ -127,7 +127,7 @@ void sgReadInt ( gzFile fd, int *var )
read_error = true ;
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int*)var);
sgEndianSwap( (uint32_t *)var);
}
}
@@ -135,7 +135,7 @@ void sgReadInt ( gzFile fd, int *var )
void sgWriteInt ( gzFile fd, const int var )
{
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int*)&var);
sgEndianSwap( (uint32_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(int) ) != sizeof(int) ) {
write_error = true ;
@@ -143,48 +143,48 @@ void sgWriteInt ( gzFile fd, const int var )
}
void sgReadLong ( gzFile fd, long int *var )
void sgReadLong ( gzFile fd, int32_t *var )
{
if ( gzread ( fd, var, sizeof(long int) ) != sizeof(long int) ) {
if ( gzread ( fd, var, sizeof(int32_t) ) != sizeof(int32_t) ) {
read_error = true ;
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int*)var);
sgEndianSwap( (uint32_t *)var);
}
}
void sgWriteLong ( gzFile fd, const long int var )
void sgWriteLong ( gzFile fd, const int32_t var )
{
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int*)&var);
sgEndianSwap( (uint32_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(long int) )
!= sizeof(long int) )
if ( gzwrite ( fd, (void *)(&var), sizeof(int32_t) )
!= sizeof(int32_t) )
{
write_error = true ;
}
}
void sgReadLongLong ( gzFile fd, int64 *var )
void sgReadLongLong ( gzFile fd, int64_t *var )
{
if ( gzread ( fd, var, sizeof(int64) ) != sizeof(int64) ) {
if ( gzread ( fd, var, sizeof(int64_t) ) != sizeof(int64_t) ) {
read_error = true ;
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint64*)var);
sgEndianSwap( (uint64_t *)var);
}
}
void sgWriteLongLong ( gzFile fd, const int64 var )
void sgWriteLongLong ( gzFile fd, const int64_t var )
{
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint64*)&var);
sgEndianSwap( (uint64_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(int64) )
!= sizeof(int64) )
if ( gzwrite ( fd, (void *)(&var), sizeof(int64_t) )
!= sizeof(int64_t) )
{
write_error = true ;
}
@@ -197,7 +197,7 @@ void sgReadUShort ( gzFile fd, unsigned short *var )
read_error = true ;
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned short int*)var);
sgEndianSwap( (uint16_t *)var);
}
}
@@ -205,7 +205,7 @@ void sgReadUShort ( gzFile fd, unsigned short *var )
void sgWriteUShort ( gzFile fd, const unsigned short var )
{
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned short*)&var);
sgEndianSwap( (uint16_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned short) )
!= sizeof(unsigned short) )
@@ -221,7 +221,7 @@ void sgReadShort ( gzFile fd, short *var )
read_error = true ;
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned short int*)var);
sgEndianSwap( (uint16_t *)var);
}
}
@@ -229,7 +229,7 @@ void sgReadShort ( gzFile fd, short *var )
void sgWriteShort ( gzFile fd, const short var )
{
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned short*)&var);
sgEndianSwap( (uint16_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(short) ) != sizeof(short) ) {
write_error = true ;
@@ -244,7 +244,7 @@ void sgReadFloat ( gzFile fd, const unsigned int n, float *var )
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned int*)var++);
sgEndianSwap( (uint32_t *)var++);
}
}
}
@@ -257,7 +257,7 @@ void sgWriteFloat ( gzFile fd, const unsigned int n, const float *var )
float *ptr = swab;
memcpy( swab, var, sizeof(float) * n );
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned int*)ptr++);
sgEndianSwap( (uint32_t *)ptr++);
}
var = swab;
}
@@ -275,7 +275,7 @@ void sgReadDouble ( gzFile fd, const unsigned int n, double *var )
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (uint64*)var++);
sgEndianSwap( (uint64_t *)var++);
}
}
}
@@ -288,7 +288,7 @@ void sgWriteDouble ( gzFile fd, const unsigned int n, const double *var )
double *ptr = swab;
memcpy( swab, var, sizeof(double) * n );
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (uint64*)ptr++);
sgEndianSwap( (uint64_t *)ptr++);
}
var = swab;
}
@@ -325,7 +325,7 @@ void sgReadUShort ( gzFile fd, const unsigned int n, unsigned short *var )
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned short int*)var++);
sgEndianSwap( (uint16_t *)var++);
}
}
}
@@ -338,7 +338,7 @@ void sgWriteUShort ( gzFile fd, const unsigned int n, const unsigned short *var
unsigned short *ptr = swab;
memcpy( swab, var, sizeof(unsigned short) * n );
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned short*)ptr++);
sgEndianSwap( (uint16_t *)ptr++);
}
var = swab;
}
@@ -360,7 +360,7 @@ void sgReadShort ( gzFile fd, const unsigned int n, short *var )
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned short int*)var++);
sgEndianSwap( (uint16_t *)var++);
}
}
}
@@ -373,7 +373,7 @@ void sgWriteShort ( gzFile fd, const unsigned int n, const short *var )
short *ptr = swab;
memcpy( swab, var, sizeof(short) * n );
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned short*)ptr++);
sgEndianSwap( (uint16_t *)ptr++);
}
var = swab;
}
@@ -394,7 +394,7 @@ void sgReadUInt ( gzFile fd, const unsigned int n, unsigned int *var )
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned int*)var++);
sgEndianSwap( (uint32_t *)var++);
}
}
}
@@ -407,7 +407,7 @@ void sgWriteUInt ( gzFile fd, const unsigned int n, const unsigned int *var )
unsigned int *ptr = swab;
memcpy( swab, var, sizeof(unsigned int) * n );
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned int*)ptr++);
sgEndianSwap( (uint32_t *)ptr++);
}
var = swab;
}
@@ -429,7 +429,7 @@ void sgReadInt ( gzFile fd, const unsigned int n, int *var )
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned int*)var++);
sgEndianSwap( (uint32_t *)var++);
}
}
}
@@ -442,7 +442,7 @@ void sgWriteInt ( gzFile fd, const unsigned int n, const int *var )
int *ptr = swab;
memcpy( swab, var, sizeof(int) * n );
for ( unsigned int i = 0; i < n; ++i ) {
sgEndianSwap( (unsigned int*)ptr++);
sgEndianSwap( (uint32_t *)ptr++);
}
var = swab;
}
+6 -60
View File
@@ -27,19 +27,13 @@
#ifndef _SG_LOWLEVEL_HXX
#define _SG_LOWLEVEL_HXX
#include <stdio.h>
#include <zlib.h>
#include <plib/sg.h>
#ifdef _MSC_VER
typedef __int64 int64;
typedef __int64 uint64;
#else
typedef long long int64;
typedef unsigned long long uint64;
#endif
#include <simgear/compiler.h>
#include <simgear/misc/stdint.hxx>
// Note that output is written in little endian form (and converted as
// necessary for big endian machines)
@@ -54,10 +48,10 @@ void sgReadUInt ( gzFile fd, unsigned int *var ) ;
void sgWriteUInt ( gzFile fd, const unsigned int var ) ;
void sgReadInt ( gzFile fd, int *var ) ;
void sgWriteInt ( gzFile fd, const int var ) ;
void sgReadLong ( gzFile fd, long int *var ) ;
void sgWriteLong ( gzFile fd, const long int var ) ;
void sgReadLongLong ( gzFile fd, int64 *var ) ;
void sgWriteLongLong ( gzFile fd, const int64 var ) ;
void sgReadLong ( gzFile fd, int32_t *var ) ;
void sgWriteLong ( gzFile fd, const int32_t var ) ;
void sgReadLongLong ( gzFile fd, int64_t *var ) ;
void sgWriteLongLong ( gzFile fd, const int64_t var ) ;
void sgReadUShort ( gzFile fd, unsigned short *var ) ;
void sgWriteUShort ( gzFile fd, const unsigned short var ) ;
void sgReadShort ( gzFile fd, short *var ) ;
@@ -121,52 +115,4 @@ void sgClearWriteError();
int sgReadError();
int sgWriteError();
inline bool sgIsLittleEndian() {
static const int sgEndianTest = 1;
return (*((char *) &sgEndianTest ) != 0);
}
inline bool sgIsBigEndian() {
static const int sgEndianTest = 1;
return (*((char *) &sgEndianTest ) == 0);
}
inline void sgEndianSwap(unsigned short *x) {
*x =
(( *x >> 8 ) & 0x00FF ) |
(( *x << 8 ) & 0xFF00 ) ;
}
inline void sgEndianSwap(unsigned int *x) {
*x =
(( *x >> 24 ) & 0x000000FF ) |
(( *x >> 8 ) & 0x0000FF00 ) |
(( *x << 8 ) & 0x00FF0000 ) |
(( *x << 24 ) & 0xFF000000 ) ;
}
inline void sgEndianSwap(uint64 *x) {
#ifndef _MSC_VER
*x =
(( *x >> 56 ) & 0x00000000000000FFULL ) |
(( *x >> 40 ) & 0x000000000000FF00ULL ) |
(( *x >> 24 ) & 0x0000000000FF0000ULL ) |
(( *x >> 8 ) & 0x00000000FF000000ULL ) |
(( *x << 8 ) & 0x000000FF00000000ULL ) |
(( *x << 24 ) & 0x0000FF0000000000ULL ) |
(( *x << 40 ) & 0x00FF000000000000ULL ) |
(( *x << 56 ) & 0xFF00000000000000ULL ) ;
#else
*x =
(( *x >> 56 ) & 0x00000000000000FF ) |
(( *x >> 40 ) & 0x000000000000FF00 ) |
(( *x >> 24 ) & 0x0000000000FF0000 ) |
(( *x >> 8 ) & 0x00000000FF000000 ) |
(( *x << 8 ) & 0x000000FF00000000 ) |
(( *x << 24 ) & 0x0000FF0000000000 ) |
(( *x << 40 ) & 0x00FF000000000000 ) |
(( *x << 56 ) & 0xFF00000000000000 ) ;
#endif
}
#endif // _SG_LOWLEVEL_HXX
+6 -6
View File
@@ -25,22 +25,22 @@ int main() {
short s = 1111;
cout << "short s = " << s << endl;
sgEndianSwap((unsigned short *)&s);
sgEndianSwap((uint16_t *)&s);
cout << "short s = " << s << endl;
sgEndianSwap((unsigned short *)&s);
sgEndianSwap((uint16_t *)&s);
cout << "short s = " << s << endl;
int i = 1111111;
cout << "int i = " << i << endl;
sgEndianSwap((unsigned int *)&i);
sgEndianSwap((uint32_t *)&i);
cout << "int i = " << i << endl;
sgEndianSwap((unsigned int *)&i);
sgEndianSwap((uint32_t *)&i);
cout << "int i = " << i << endl;
double x = 1111111111;
cout << "double x = " << x << endl;
sgEndianSwap((unsigned long long *)&x);
sgEndianSwap((uint64_t *)&x);
cout << "double x = " << x << endl;
sgEndianSwap((unsigned long long *)&x);
sgEndianSwap((uint64_t *)&x);
cout << "double x = " << x << endl;
}
+17 -17
View File
@@ -240,8 +240,8 @@ static void read_object( gzFile fp,
if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (idx_size * sizeof(short));
short *sptr = (short *)ptr;
int count = nbytes / (idx_size * sizeof(unsigned short));
unsigned short *sptr = (unsigned short *)ptr;
int_list vs; vs.clear();
int_list ns; ns.clear();
int_list cs; cs.clear();
@@ -249,7 +249,7 @@ static void read_object( gzFile fp,
for ( k = 0; k < count; ++k ) {
if ( sgIsBigEndian() ) {
for ( idx = 0; idx < idx_size; ++idx ) {
sgEndianSwap( (unsigned short *)&(sptr[idx]) );
sgEndianSwap( (uint16_t *)&(sptr[idx]) );
}
}
idx = 0;
@@ -403,9 +403,9 @@ bool SGBinObject::read_bin( const string& file ) {
double *dptr = (double *)ptr;
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint64 *)&(dptr[0]) );
sgEndianSwap( (uint64 *)&(dptr[1]) );
sgEndianSwap( (uint64 *)&(dptr[2]) );
sgEndianSwap( (uint64_t *)&(dptr[0]) );
sgEndianSwap( (uint64_t *)&(dptr[1]) );
sgEndianSwap( (uint64_t *)&(dptr[2]) );
}
gbs_center = Point3D( dptr[0], dptr[1], dptr[2] );
// cout << "Center = " << gbs_center << endl;
@@ -413,7 +413,7 @@ bool SGBinObject::read_bin( const string& file ) {
float *fptr = (float *)ptr;
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int *)fptr );
sgEndianSwap( (uint32_t *)fptr );
}
gbs_radius = fptr[0];
// cout << "Bounding radius = " << gbs_radius << endl;
@@ -443,9 +443,9 @@ bool SGBinObject::read_bin( const string& file ) {
wgs84_nodes.reserve( count );
for ( k = 0; k < count; ++k ) {
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int *)&(fptr[0]) );
sgEndianSwap( (unsigned int *)&(fptr[1]) );
sgEndianSwap( (unsigned int *)&(fptr[2]) );
sgEndianSwap( (uint32_t *)&(fptr[0]) );
sgEndianSwap( (uint32_t *)&(fptr[1]) );
sgEndianSwap( (uint32_t *)&(fptr[2]) );
}
wgs84_nodes.push_back( Point3D(fptr[0], fptr[1], fptr[2]) );
fptr += 3;
@@ -476,10 +476,10 @@ bool SGBinObject::read_bin( const string& file ) {
colors.reserve(count);
for ( k = 0; k < count; ++k ) {
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int *)&(fptr[0]) );
sgEndianSwap( (unsigned int *)&(fptr[1]) );
sgEndianSwap( (unsigned int *)&(fptr[2]) );
sgEndianSwap( (unsigned int *)&(fptr[3]) );
sgEndianSwap( (uint32_t *)&(fptr[0]) );
sgEndianSwap( (uint32_t *)&(fptr[1]) );
sgEndianSwap( (uint32_t *)&(fptr[2]) );
sgEndianSwap( (uint32_t *)&(fptr[3]) );
}
colors.push_back( Point3D( fptr[0], fptr[1], fptr[2] ) );
fptr += 4;
@@ -544,8 +544,8 @@ bool SGBinObject::read_bin( const string& file ) {
texcoords.reserve(count);
for ( k = 0; k < count; ++k ) {
if ( sgIsBigEndian() ) {
sgEndianSwap( (unsigned int *)&(fptr[0]) );
sgEndianSwap( (unsigned int *)&(fptr[1]) );
sgEndianSwap( (uint32_t *)&(fptr[0]) );
sgEndianSwap( (uint32_t *)&(fptr[1]) );
}
texcoords.push_back( Point3D( fptr[0], fptr[1], 0 ) );
fptr += 2;
@@ -656,7 +656,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
// write header magic
sgWriteUInt( fp, SG_FILE_MAGIC_NUMBER );
time_t calendar_time = time(NULL);
sgWriteLong( fp, (long int)calendar_time );
sgWriteLong( fp, (int32_t)calendar_time );
// calculate and write number of top level objects
string material;
+13 -2
View File
@@ -29,6 +29,7 @@
# include <io.h>
#endif
#include <simgear/misc/stdint.hxx>
#include <simgear/debug/logstream.hxx>
#include "sg_file.hxx"
@@ -39,6 +40,7 @@ SG_USING_STD(string);
SGFile::SGFile( const string &file) {
set_type( sgFileType );
file_name = file;
eof_flag = true;
}
@@ -70,6 +72,7 @@ bool SGFile::open( const SGProtocolDir d ) {
return false;
}
eof_flag = false;
return true;
}
@@ -77,7 +80,11 @@ bool SGFile::open( const SGProtocolDir d ) {
// read a block of data of specified size
int SGFile::read( char *buf, int length ) {
// read a chunk
return ::read( fp, buf, length );
ssize_t result = ::read( fp, buf, length );
if ( length > 0 && result == 0 ) {
eof_flag = true;
}
return result;
}
@@ -87,7 +94,10 @@ int SGFile::readline( char *buf, int length ) {
int pos = lseek( fp, 0, SEEK_CUR );
// read a chunk
int result = ::read( fp, buf, length );
ssize_t result = ::read( fp, buf, length );
if ( length > 0 && result == 0 ) {
eof_flag = true;
}
// find the end of line and reset position
int i;
@@ -130,5 +140,6 @@ bool SGFile::close() {
return false;
}
eof_flag = true;
return true;
}
+4
View File
@@ -54,6 +54,7 @@ class SGFile : public SGIOChannel {
string file_name;
int fp;
bool eof_flag;
public:
@@ -89,6 +90,9 @@ public:
/** @return the name of the file being manipulated. */
inline string get_file_name() const { return file_name; }
/** @return true of eof conditions exists */
inline bool eof() const { return eof_flag; };
};
+3
View File
@@ -20,6 +20,9 @@
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>
+1 -1
View File
@@ -27,9 +27,9 @@
*/
#include <simgear/constants.h>
#include "fastmath.hxx"
#define SGD_PI_2 1.57079632679489661923
/**
* This function is on avarage 9 times faster than the system exp() function
+5 -1
View File
@@ -185,7 +185,11 @@ operator<< ( ostream& out, const Point3D& p )
// CONSTRUCTORS
inline Point3D::Point3D() {}
inline Point3D::Point3D()
{
n[PX] = n[PY] = 0.0;
n[PZ] = -9999.0;
}
inline Point3D::Point3D(const double x, const double y, const double z)
{
+228 -4
View File
@@ -30,10 +30,14 @@
#include "polar3d.hxx"
// Find the Altitude above the Ellipsoid (WGS84) given the Earth
// Centered Cartesian coordinate vector Distances are specified in
// meters.
double fgGeodAltFromCart(const Point3D& cp)
/**
* Find the Altitude above the Ellipsoid (WGS84) given the Earth
* Centered Cartesian coordinate vector Distances are specified in
* meters.
* @param cp point specified in cartesian coordinates
* @return altitude above the (wgs84) earth in meters
*/
double sgGeodAltFromCart(const Point3D& cp)
{
double t_lat, x_alpha, mu_alpha;
double lat_geoc, radius;
@@ -59,4 +63,224 @@ double fgGeodAltFromCart(const Point3D& cp)
return(result);
}
/**
* Convert a polar coordinate to a cartesian coordinate. Lon and Lat
* must be specified in radians. The SG convention is for distances
* to be specified in meters
* @param p point specified in polar coordinates
* @return the same point in cartesian coordinates
*/
Point3D sgPolarToCart3d(const Point3D& p) {
double tmp = cos( p.lat() ) * p.radius();
return Point3D( cos( p.lon() ) * tmp,
sin( p.lon() ) * tmp,
sin( p.lat() ) * p.radius() );
}
/**
* Convert a cartesian coordinate to polar coordinates (lon/lat
* specified in radians. Distances are specified in meters.
* @param cp point specified in cartesian coordinates
* @return the same point in polar coordinates
*/
Point3D sgCartToPolar3d(const Point3D& cp) {
return Point3D( atan2( cp.y(), cp.x() ),
SGD_PI_2 -
atan2( sqrt(cp.x()*cp.x() + cp.y()*cp.y()), cp.z() ),
sqrt(cp.x()*cp.x() + cp.y()*cp.y() + cp.z()*cp.z()) );
}
/**
* Calculate new lon/lat given starting lon/lat, and offset radial, and
* distance. NOTE: starting point is specifed in radians, distance is
* specified in meters (and converted internally to radians)
* ... assumes a spherical world.
* @param orig specified in polar coordinates
* @param course offset radial
* @param dist offset distance
* @return destination point in polar coordinates
*/
Point3D calc_gc_lon_lat( const Point3D& orig, double course,
double dist ) {
Point3D result;
// lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
// IF (cos(lat)=0)
// lon=lon1 // endpoint a pole
// ELSE
// lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
// ENDIF
// printf("calc_lon_lat() offset.theta = %.2f offset.dist = %.2f\n",
// offset.theta, offset.dist);
dist *= SG_METER_TO_NM * SG_NM_TO_RAD;
result.sety( asin( sin(orig.y()) * cos(dist) +
cos(orig.y()) * sin(dist) * cos(course) ) );
if ( cos(result.y()) < SG_EPSILON ) {
result.setx( orig.x() ); // endpoint a pole
} else {
result.setx(
fmod(orig.x() - asin( sin(course) * sin(dist) /
cos(result.y()) )
+ SGD_PI, SGD_2PI) - SGD_PI );
}
return result;
}
/**
* Calculate course/dist given two spherical points.
* @param start starting point
* @param dest ending point
* @param course resulting course
* @param dist resulting distance
*/
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
double *course, double *dist )
{
if ( start == dest) {
*dist=0;
*course=0;
return;
}
// d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
// cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
double cos_start_y = cos( start.y() );
double tmp1 = sin( (start.y() - dest.y()) * 0.5 );
double tmp2 = sin( (start.x() - dest.x()) * 0.5 );
double d = 2.0 * asin( sqrt( tmp1 * tmp1 +
cos_start_y * cos(dest.y()) * tmp2 * tmp2));
*dist = d * SG_RAD_TO_NM * SG_NM_TO_METER;
#if 1
double c1 = atan2(
cos(dest.y())*sin(dest.x()-start.x()),
cos(start.y())*sin(dest.y())-
sin(start.y())*cos(dest.y())*cos(dest.x()-start.x()));
if (c1 >= 0)
*course = SGD_2PI-c1;
else
*course = -c1;
#else
// We obtain the initial course, tc1, (at point 1) from point 1 to
// point 2 by the following. The formula fails if the initial
// point is a pole. We can special case this with:
//
// IF (cos(lat1) < EPS) // EPS a small number ~ machine precision
// IF (lat1 > 0)
// tc1= pi // starting from N pole
// ELSE
// tc1= 0 // starting from S pole
// ENDIF
// ENDIF
//
// For starting points other than the poles:
//
// IF sin(lon2-lon1)<0
// tc1=acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ELSE
// tc1=2*pi-acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ENDIF
// if ( cos(start.y()) < SG_EPSILON ) {
// doing it this way saves a transcendental call
double sin_start_y = sin( start.y() );
if ( fabs(1.0-sin_start_y) < SG_EPSILON ) {
// EPS a small number ~ machine precision
if ( start.y() > 0 ) {
*course = SGD_PI; // starting from N pole
} else {
*course = 0; // starting from S pole
}
} else {
// For starting points other than the poles:
// double tmp3 = sin(d)*cos_start_y);
// double tmp4 = sin(dest.y())-sin(start.y())*cos(d);
// double tmp5 = acos(tmp4/tmp3);
// Doing this way gaurentees that the temps are
// not stored into memory
double tmp5 = acos( (sin(dest.y()) - sin_start_y * cos(d)) /
(sin(d) * cos_start_y) );
// if ( sin( dest.x() - start.x() ) < 0 ) {
// the sin of the negative angle is just the opposite sign
// of the sin of the angle so tmp2 will have the opposite
// sign of sin( dest.x() - start.x() )
if ( tmp2 >= 0 ) {
*course = tmp5;
} else {
*course = SGD_2PI - tmp5;
}
}
#endif
}
#if 0
/**
* Calculate course/dist given two spherical points.
* @param start starting point
* @param dest ending point
* @param course resulting course
* @param dist resulting distance
*/
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
double *course, double *dist ) {
// d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
// cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
double tmp1 = sin( (start.y() - dest.y()) / 2 );
double tmp2 = sin( (start.x() - dest.x()) / 2 );
double d = 2.0 * asin( sqrt( tmp1 * tmp1 +
cos(start.y()) * cos(dest.y()) * tmp2 * tmp2));
// We obtain the initial course, tc1, (at point 1) from point 1 to
// point 2 by the following. The formula fails if the initial
// point is a pole. We can special case this with:
//
// IF (cos(lat1) < EPS) // EPS a small number ~ machine precision
// IF (lat1 > 0)
// tc1= pi // starting from N pole
// ELSE
// tc1= 0 // starting from S pole
// ENDIF
// ENDIF
//
// For starting points other than the poles:
//
// IF sin(lon2-lon1)<0
// tc1=acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ELSE
// tc1=2*pi-acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ENDIF
double tc1;
if ( cos(start.y()) < SG_EPSILON ) {
// EPS a small number ~ machine precision
if ( start.y() > 0 ) {
tc1 = SGD_PI; // starting from N pole
} else {
tc1 = 0; // starting from S pole
}
}
// For starting points other than the poles:
double tmp3 = sin(d)*cos(start.y());
double tmp4 = sin(dest.y())-sin(start.y())*cos(d);
double tmp5 = acos(tmp4/tmp3);
if ( sin( dest.x() - start.x() ) < 0 ) {
tc1 = tmp5;
} else {
tc1 = SGD_2PI - tmp5;
}
*course = tc1;
*dist = d * SG_RAD_TO_NM * SG_NM_TO_METER;
}
#endif // 0
+8 -162
View File
@@ -57,13 +57,7 @@ double sgGeodAltFromCart(const Point3D& cp);
* @param p point specified in polar coordinates
* @return the same point in cartesian coordinates
*/
inline Point3D sgPolarToCart3d(const Point3D& p) {
double tmp = cos( p.lat() ) * p.radius();
return Point3D( cos( p.lon() ) * tmp,
sin( p.lon() ) * tmp,
sin( p.lat() ) * p.radius() );
}
Point3D sgPolarToCart3d(const Point3D& p);
/**
@@ -72,12 +66,7 @@ inline Point3D sgPolarToCart3d(const Point3D& p) {
* @param cp point specified in cartesian coordinates
* @return the same point in polar coordinates
*/
inline Point3D sgCartToPolar3d(const Point3D& cp) {
return Point3D( atan2( cp.y(), cp.x() ),
SGD_PI_2 -
atan2( sqrt(cp.x()*cp.x() + cp.y()*cp.y()), cp.z() ),
sqrt(cp.x()*cp.x() + cp.y()*cp.y() + cp.z()*cp.z()) );
}
Point3D sgCartToPolar3d(const Point3D& cp);
/**
@@ -90,36 +79,7 @@ inline Point3D sgCartToPolar3d(const Point3D& cp) {
* @param dist offset distance
* @return destination point in polar coordinates
*/
inline Point3D calc_gc_lon_lat( const Point3D& orig, double course,
double dist ) {
Point3D result;
// lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
// IF (cos(lat)=0)
// lon=lon1 // endpoint a pole
// ELSE
// lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
// ENDIF
// printf("calc_lon_lat() offset.theta = %.2f offset.dist = %.2f\n",
// offset.theta, offset.dist);
dist *= SG_METER_TO_NM * SG_NM_TO_RAD;
result.sety( asin( sin(orig.y()) * cos(dist) +
cos(orig.y()) * sin(dist) * cos(course) ) );
if ( cos(result.y()) < SG_EPSILON ) {
result.setx( orig.x() ); // endpoint a pole
} else {
result.setx(
fmod(orig.x() - asin( sin(course) * sin(dist) /
cos(result.y()) )
+ SGD_PI, SGD_2PI) - SGD_PI );
}
return result;
}
Point3D calc_gc_lon_lat( const Point3D& orig, double course, double dist );
/**
@@ -129,71 +89,8 @@ inline Point3D calc_gc_lon_lat( const Point3D& orig, double course,
* @param course resulting course
* @param dist resulting distance
*/
inline void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
double *course, double *dist )
{
// d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
// cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
double cos_start_y = cos( start.y() );
volatile double tmp1 = sin( (start.y() - dest.y()) * 0.5 );
volatile double tmp2 = sin( (start.x() - dest.x()) * 0.5 );
double d = 2.0 * asin( sqrt( tmp1 * tmp1 +
cos_start_y * cos(dest.y()) * tmp2 * tmp2));
*dist = d * SG_RAD_TO_NM * SG_NM_TO_METER;
// We obtain the initial course, tc1, (at point 1) from point 1 to
// point 2 by the following. The formula fails if the initial
// point is a pole. We can special case this with:
//
// IF (cos(lat1) < EPS) // EPS a small number ~ machine precision
// IF (lat1 > 0)
// tc1= pi // starting from N pole
// ELSE
// tc1= 0 // starting from S pole
// ENDIF
// ENDIF
//
// For starting points other than the poles:
//
// IF sin(lon2-lon1)<0
// tc1=acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ELSE
// tc1=2*pi-acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ENDIF
// if ( cos(start.y()) < SG_EPSILON ) {
// doing it this way saves a transcendental call
double sin_start_y = sin( start.y() );
if ( fabs(1.0-sin_start_y) < SG_EPSILON ) {
// EPS a small number ~ machine precision
if ( start.y() > 0 ) {
*course = SGD_PI; // starting from N pole
} else {
*course = 0; // starting from S pole
}
} else {
// For starting points other than the poles:
// double tmp3 = sin(d)*cos_start_y);
// double tmp4 = sin(dest.y())-sin(start.y())*cos(d);
// double tmp5 = acos(tmp4/tmp3);
// Doing this way gaurentees that the temps are
// not stored into memory
double tmp5 = acos( (sin(dest.y()) - sin_start_y * cos(d)) /
(sin(d) * cos_start_y) );
// if ( sin( dest.x() - start.x() ) < 0 ) {
// the sin of the negative angle is just the opposite sign
// of the sin of the angle so tmp2 will have the opposite
// sign of sin( dest.x() - start.x() )
if ( tmp2 >= 0 ) {
*course = tmp5;
} else {
*course = 2 * SGD_PI - tmp5;
}
}
}
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
double *course, double *dist );
#if 0
/**
@@ -203,60 +100,9 @@ inline void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
* @param course resulting course
* @param dist resulting distance
*/
inline void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
double *course, double *dist ) {
// d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
// cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
double tmp1 = sin( (start.y() - dest.y()) / 2 );
double tmp2 = sin( (start.x() - dest.x()) / 2 );
double d = 2.0 * asin( sqrt( tmp1 * tmp1 +
cos(start.y()) * cos(dest.y()) * tmp2 * tmp2));
// We obtain the initial course, tc1, (at point 1) from point 1 to
// point 2 by the following. The formula fails if the initial
// point is a pole. We can special case this with:
//
// IF (cos(lat1) < EPS) // EPS a small number ~ machine precision
// IF (lat1 > 0)
// tc1= pi // starting from N pole
// ELSE
// tc1= 0 // starting from S pole
// ENDIF
// ENDIF
//
// For starting points other than the poles:
//
// IF sin(lon2-lon1)<0
// tc1=acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ELSE
// tc1=2*pi-acos((sin(lat2)-sin(lat1)*cos(d))/(sin(d)*cos(lat1)))
// ENDIF
double tc1;
if ( cos(start.y()) < SG_EPSILON ) {
// EPS a small number ~ machine precision
if ( start.y() > 0 ) {
tc1 = SGD_PI; // starting from N pole
} else {
tc1 = 0; // starting from S pole
}
}
// For starting points other than the poles:
double tmp3 = sin(d)*cos(start.y());
double tmp4 = sin(dest.y())-sin(start.y())*cos(d);
double tmp5 = acos(tmp4/tmp3);
if ( sin( dest.x() - start.x() ) < 0 ) {
tc1 = tmp5;
} else {
tc1 = 2 * SGD_PI - tmp5;
}
*course = tc1;
*dist = d * SG_RAD_TO_NM * SG_NM_TO_METER;
}
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
double *course, double *dist );
#endif // 0
#endif // _POLAR3D_HXX
+7
View File
@@ -134,6 +134,13 @@ void sg_srandom_time() {
init_genrand(time(NULL));
}
// Seed the random number generater with time() in 10 minute intervals
// so we get the same sequence within 10 minutes interval.
// This is useful for synchronizing two display systems.
void sg_srandom_time_10() {
init_genrand(time(NULL) / 600);
}
// Seed the random number generater with your own seed so can set up
// repeatable randomization.
+7
View File
@@ -40,6 +40,13 @@ extern "C" {
*/
void sg_srandom_time();
/**
* Seed the random number generater with time() in 10 minute intervals
* so we get the same sequence within 10 minutes interval.
* This is useful for synchronizing two display systems.
*/
void sg_srandom_time_10();
/**
* Seed the random number generater with your own seed so can set up
* repeatable randomization.
+5 -2
View File
@@ -10,7 +10,8 @@ include_HEADERS = \
tabbed_values.hxx \
texcoord.hxx \
zfstream.hxx \
interpolator.hxx
interpolator.hxx \
stdint.hxx
libsgmisc_a_SOURCES = \
sg_path.cxx \
@@ -21,7 +22,7 @@ libsgmisc_a_SOURCES = \
zfstream.cxx \
interpolator.cxx
noinst_PROGRAMS = tabbed_value_test
noinst_PROGRAMS = tabbed_value_test swap_test
tabbed_value_test_SOURCES = tabbed_values_test.cxx
tabbed_value_test_LDADD = \
@@ -29,4 +30,6 @@ tabbed_value_test_LDADD = \
$(top_builddir)/simgear/xml/libsgxml.a \
$(top_builddir)/simgear/debug/libsgdebug.a
swap_test_SOURCES = swap_test.cpp
INCLUDES = -I$(top_srcdir)
+94
View File
@@ -0,0 +1,94 @@
#ifndef _STDINT_HXX
#define _STDINT_HXX 1
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// Written by Curtis Olson - http://www.flightgear.org/~curt
// Started September 2001.
//
// This file is in the Public Domain, and comes with no warranty.
//
// $Id$
//////////////////////////////////////////////////////////////////////
//
// There are many sick systems out there:
//
// check for sizeof(float) and sizeof(double)
// if sizeof(float) != 4 this code must be patched
// if sizeof(double) != 8 this code must be patched
//
// Those are comments I fetched out of glibc source:
// - s390 is big-endian
// - Sparc is big-endian, but v9 supports endian conversion
// on loads/stores and GCC supports such a mode. Be prepared.
// - The MIPS architecture has selectable endianness.
// - x86_64 is little-endian.
// - CRIS is little-endian.
// - m68k is big-endian.
// - Alpha is little-endian.
// - PowerPC can be little or big endian.
// - SH is bi-endian but with a big-endian FPU.
// - hppa1.1 big-endian.
// - ARM is (usually) little-endian but with a big-endian FPU.
//
//////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed __int64 int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
typedef int ssize_t;
#elif defined(sgi) || defined(__sun)
# include <sys/types.h>
#else
# include <stdint.h>
#endif
inline uint16_t sg_bswap_16(uint16_t x) {
x = (x >> 8) | (x << 8);
return x;
}
inline uint32_t sg_bswap_32(uint32_t x) {
x = ((x >> 8) & 0x00FF00FFL) | ((x << 8) & 0xFF00FF00L);
x = (x >> 16) | (x << 16);
return x;
}
inline uint64_t sg_bswap_64(uint64_t x) {
x = ((x >> 8) & 0x00FF00FF00FF00FFLL) | ((x << 8) & 0xFF00FF00FF00FF00LL);
x = ((x >> 16) & 0x0000FFFF0000FFFFLL) | ((x << 16) & 0xFFFF0000FFFF0000LL);
x = (x >> 32) | (x << 32);
return x;
}
inline bool sgIsLittleEndian() {
static const int sgEndianTest = 1;
return (*((char *) &sgEndianTest ) != 0);
}
inline bool sgIsBigEndian() {
static const int sgEndianTest = 1;
return (*((char *) &sgEndianTest ) == 0);
}
inline void sgEndianSwap(uint16_t *x) { *x = sg_bswap_16(*x); }
inline void sgEndianSwap(uint32_t *x) { *x = sg_bswap_32(*x); }
inline void sgEndianSwap(uint64_t *x) { *x = sg_bswap_64(*x); }
#endif // !_STDINT_HXX
+3 -3
View File
@@ -41,14 +41,14 @@ namespace simgear {
while (i < len)
{
while (i < len && isspace(str[i]))
while (i < len && isspace((unsigned char)str[i]))
{
++i;
}
j = i;
while (i < len && !isspace(str[i]))
while (i < len && !isspace((unsigned char)str[i]))
{
++i;
}
@@ -57,7 +57,7 @@ namespace simgear {
{
result.push_back( str.substr(j, i-j) );
++countsplit;
while (i < len && isspace(str[i]))
while (i < len && isspace((unsigned char)str[i]))
{
++i;
}
+20
View File
@@ -0,0 +1,20 @@
#include <stdio.h>
#include "stdint.hxx"
int main()
{
uint16_t sui16, ui16 = 0x0123;
uint32_t sui32, ui32 = 0x01234567;
uint64_t sui64, ui64 = 0x0123456789ABCDEFLL;
sui16 = ui16; sgEndianSwap(&sui16);
sui32 = ui32; sgEndianSwap(&sui32);
sui64 = ui64; sgEndianSwap(&sui64);
printf("\nUI16: %x (normal)\t\t %x (swapped)\n", ui16, sui16 );
printf("UI32: %x (normal)\t\t %x (swapped)\n", ui32, sui32 );
printf("UI64: %llx (normal)\t %llx (swapped)\n\n", ui64, sui64 );
return 0;
}
+2 -2
View File
@@ -189,7 +189,7 @@ point_list sgCalcTexCoords( const SGBucket& b, const point_list& geod_nodes,
double clat_rad = clat * SGD_DEGREES_TO_RADIANS;
double cos_lat = cos( clat_rad );
double local_radius = cos_lat * SG_EQUATORIAL_RADIUS_M;
double local_perimeter = 2.0 * local_radius * SGD_PI;
double local_perimeter = local_radius * SGD_2PI;
double degree_width = local_perimeter / 360.0;
// cout << "clat = " << clat << endl;
@@ -199,7 +199,7 @@ point_list sgCalcTexCoords( const SGBucket& b, const point_list& geod_nodes,
// cout << "local_perimeter = " << local_perimeter << endl;
// cout << "degree_width = " << degree_width << endl;
double perimeter = 2.0 * SG_EQUATORIAL_RADIUS_M * SGD_PI;
double perimeter = SG_EQUATORIAL_RADIUS_M * SGD_2PI;
double degree_height = perimeter / 360.0;
// cout << "degree_height = " << degree_height << endl;
+3 -2
View File
@@ -8,7 +8,6 @@ libsgnasal_a_SOURCES = \
code.c code.h \
codegen.c \
data.h \
debug.c \
gc.c \
hash.c \
lex.c \
@@ -18,6 +17,8 @@ libsgnasal_a_SOURCES = \
nasal.h \
parse.c parse.h \
string.c \
vector.c
vector.c \
thread-posix.c \
thread-win32.c
INCLUDES = -I$(top_srcdir)
+498 -356
View File
File diff suppressed because it is too large Load Diff
+74 -21
View File
@@ -5,33 +5,66 @@
#include "nasal.h"
#include "data.h"
#define MAX_STACK_DEPTH 1024
#define MAX_STACK_DEPTH 512
#define MAX_RECURSION 128
#define MAX_MARK_DEPTH 32
#define MAX_MARK_DEPTH 128
// Number of objects (per pool per thread) asked for using naGC_get().
// Testing with fib.nas shows that this gives the best performance,
// without too much per-thread overhead.
#define OBJ_CACHE_SZ 128
enum {
OP_AND, OP_OR, OP_NOT, OP_MUL, OP_PLUS, OP_MINUS, OP_DIV, OP_NEG,
OP_CAT, OP_LT, OP_LTE, OP_GT, OP_GTE, OP_EQ, OP_NEQ, OP_EACH,
OP_JMP, OP_JIFNOT, OP_JIFNIL, OP_FCALL, OP_MCALL, OP_RETURN,
OP_JMP, OP_JMPLOOP, OP_JIFNOT, OP_JIFNIL, OP_FCALL, OP_MCALL, OP_RETURN,
OP_PUSHCONST, OP_PUSHONE, OP_PUSHZERO, OP_PUSHNIL, OP_POP,
OP_DUP, OP_XCHG, OP_INSERT, OP_EXTRACT, OP_MEMBER, OP_SETMEMBER,
OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND, OP_NEWHASH, OP_HAPPEND,
OP_LINE, OP_MARK, OP_UNMARK, OP_BREAK
OP_MARK, OP_UNMARK, OP_BREAK, OP_FTAIL, OP_MTAIL, OP_SETSYM, OP_DUP2,
OP_INDEX
};
struct Frame {
naRef func; // naFunc object
naRef locals; // local per-call namespace
naRef args; // vector of arguments
int ip; // instruction pointer into code
int bp; // opStack pointer to start of frame
int line; // current line number
};
struct Globals {
// Garbage collecting allocators:
struct naPool pools[NUM_NASAL_TYPES];
int allocCount;
// Dead blocks waiting to be freed when it is safe
void** deadBlocks;
int deadsz;
int ndead;
// Threading stuff
int nThreads;
int waitCount;
int needGC;
int bottleneck;
void* sem;
void* lock;
// Constants
naRef meRef;
naRef argRef;
naRef parentsRef;
// A hash of symbol names
naRef symbols;
naRef save;
struct Context* freeContexts;
struct Context* allContexts;
};
struct Context {
// Garbage collecting allocators:
struct naPool pools[NUM_NASAL_TYPES];
// Stack(s)
struct Frame fStack[MAX_RECURSION];
int fTop;
@@ -39,26 +72,46 @@ struct Context {
int opTop;
int markStack[MAX_MARK_DEPTH];
int markTop;
int done;
// Constants
naRef meRef;
naRef argRef;
naRef parentsRef;
// Free object lists, cached from the global GC
struct naObj** free[NUM_NASAL_TYPES];
int nfree[NUM_NASAL_TYPES];
// GC-findable reference point for objects that may live on the
// processor ("real") stack during execution. naNew() places them
// here, and clears the array each instruction
struct naObj** temps;
int ntemps;
int tempsz;
// Error handling
jmp_buf jumpHandle;
char* error;
naRef dieArg;
// GC-findable reference point for objects that may live on the
// processor ("real") stack during execution. naNew() places them
// here, and clears the array each time we return from a C
// function.
naRef temps;
// Sub-call lists
struct Context* callParent;
struct Context* callChild;
naRef save;
// Linked list pointers in globals
struct Context* nextFree;
struct Context* nextAll;
};
void printRefDEBUG(naRef r);
#define globals nasal_globals
extern struct Globals* globals;
// Threading low-level functions
void* naNewLock();
void naLock(void* lock);
void naUnlock(void* lock);
void* naNewSem();
void naSemDown(void* sem);
void naSemUpAll(void* sem, int count);
void naCheckBottleneck();
#define LOCK() naLock(globals->lock)
#define UNLOCK() naUnlock(globals->lock)
#endif // _CODE_H
+281 -84
View File
@@ -1,6 +1,8 @@
#include "parse.h"
#include "code.h"
#define MAX_FUNARGS 32
// These are more sensical predicate names in most contexts in this file
#define LEFT(tok) ((tok)->children)
#define RIGHT(tok) ((tok)->lastChild)
@@ -9,24 +11,24 @@
// Forward references for recursion
static void genExpr(struct Parser* p, struct Token* t);
static void genExprList(struct Parser* p, struct Token* t);
static naRef newLambda(struct Parser* p, struct Token* t);
static void emit(struct Parser* p, int byte)
static void emit(struct Parser* p, int val)
{
if(p->cg->nBytes >= p->cg->codeAlloced) {
if(p->cg->codesz >= p->cg->codeAlloced) {
int i, sz = p->cg->codeAlloced * 2;
unsigned char* buf = naParseAlloc(p, sz);
unsigned short* buf = naParseAlloc(p, sz*sizeof(unsigned short));
for(i=0; i<p->cg->codeAlloced; i++) buf[i] = p->cg->byteCode[i];
p->cg->byteCode = buf;
p->cg->codeAlloced = sz;
}
p->cg->byteCode[p->cg->nBytes++] = (unsigned char)byte;
p->cg->byteCode[p->cg->codesz++] = (unsigned short)val;
}
static void emitImmediate(struct Parser* p, int byte, int arg)
static void emitImmediate(struct Parser* p, int val, int arg)
{
emit(p, byte);
emit(p, arg >> 8);
emit(p, arg & 0xff);
emit(p, val);
emit(p, arg);
}
static void genBinOp(int op, struct Parser* p, struct Token* t)
@@ -40,91 +42,218 @@ static void genBinOp(int op, struct Parser* p, struct Token* t)
static int newConstant(struct Parser* p, naRef c)
{
int i = p->cg->nConsts++;
int i;
naVec_append(p->cg->consts, c);
i = naVec_size(p->cg->consts) - 1;
if(i > 0xffff) naParseError(p, "too many constants in code block", 0);
naHash_set(p->cg->consts, naNum(i), c);
return i;
}
static naRef getConstant(struct Parser* p, int idx)
{
naRef c;
naHash_get(p->cg->consts, naNum(idx), &c);
return c;
return naVec_get(p->cg->consts, idx);
}
// Interns a scalar (!) constant and returns its index
static int internConstant(struct Parser* p, naRef c)
{
naRef r;
naHash_get(p->cg->interned, c, &r);
if(!IS_NIL(r)) {
return (int)r.num;
int i, n = naVec_size(p->cg->consts);
if(IS_CODE(c)) return newConstant(p, c);
for(i=0; i<n; i++) {
naRef b = naVec_get(p->cg->consts, i);
if(IS_NUM(b) && IS_NUM(c) && b.num == c.num) return i;
else if(IS_NIL(b) && IS_NIL(c)) return i;
else if(naStrEqual(b, c)) return i;
}
return newConstant(p, c);
}
naRef naInternSymbol(naRef sym)
{
naRef result;
if(naHash_get(globals->symbols, sym, &result))
return result;
naHash_set(globals->symbols, sym, sym);
return sym;
}
static int findConstantIndex(struct Parser* p, struct Token* t)
{
naRef c, dummy;
if(t->type == TOK_NIL) c = naNil();
else if(t->str) {
c = naStr_fromdata(naNewString(p->context), t->str, t->strlen);
naHash_get(globals->symbols, c, &dummy); // noop, make c immutable
if(t->type == TOK_SYMBOL) c = naInternSymbol(c);
} else if(t->type == TOK_FUNC) c = newLambda(p, t);
else if(t->type == TOK_LITERAL) c = naNum(t->num);
else naParseError(p, "invalid/non-constant constant", t->line);
return internConstant(p, c);
}
static int lastExprInBlock(struct Token* t)
{
if(!t->parent) return 1;
if(t->parent->type == TOK_TOP || t->parent->type == TOK_LCURL) return 1;
if(t->parent->type == TOK_SEMI)
if(!t->next || t->next->type == TOK_EMPTY)
return 1;
return 0;
}
// Returns true if the node is in "tail context" -- either a child of
// a return, the last child of a func block, or else the
// last child of an if/elsif/if that is itself in tail context.
static int tailContext(struct Token* t)
{
if(t->parent && t->parent->type == TOK_RETURN)
return 1;
else if(!lastExprInBlock(t))
return 0;
// Walk up the tree. It is ok to see semicolons, else's, elsifs
// and curlies. If we reach the top or a func, then we are in
// tail context. If we hit an if, then we are in tail context
// only if the "if" node is.
while((t = t->parent) != 0)
switch(t->type) {
case TOK_SEMI: case TOK_LCURL: break;
case TOK_ELSE: case TOK_ELSIF: break;
case TOK_TOP: case TOK_FUNC: return 1;
case TOK_IF: return tailContext(t);
default: return 0;
}
return 0;
}
static int genScalarConstant(struct Parser* p, struct Token* t)
{
// These opcodes are for special-case use in other constructs, but
// we might as well use them here to save a few bytes in the
// instruction stream.
if(t->str == 0 && t->num == 1) {
emit(p, OP_PUSHONE);
} else if(t->str == 0 && t->num == 0) {
emit(p, OP_PUSHZERO);
} else {
int idx = newConstant(p, c);
naHash_set(p->cg->interned, c, naNum(idx));
int idx = findConstantIndex(p, t);
emitImmediate(p, OP_PUSHCONST, idx);
return idx;
}
return 0;
}
static void genScalarConstant(struct Parser* p, struct Token* t)
{
naRef c = (t->str
? naStr_fromdata(naNewString(p->context), t->str, t->strlen)
: naNum(t->num));
int idx = internConstant(p, c);
emitImmediate(p, OP_PUSHCONST, idx);
}
static int genLValue(struct Parser* p, struct Token* t)
static int genLValue(struct Parser* p, struct Token* t, int* cidx)
{
if(t->type == TOK_LPAR) {
return genLValue(p, LEFT(t)); // Handle stuff like "(a) = 1"
return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1"
} else if(t->type == TOK_SYMBOL) {
genScalarConstant(p, t);
return OP_SETLOCAL;
*cidx = genScalarConstant(p, t);
return OP_SETSYM;
} else if(t->type == TOK_DOT && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
genExpr(p, LEFT(t));
genScalarConstant(p, RIGHT(t));
*cidx = genScalarConstant(p, RIGHT(t));
return OP_SETMEMBER;
} else if(t->type == TOK_LBRA) {
genExpr(p, LEFT(t));
genExpr(p, RIGHT(t));
return OP_INSERT;
} else if(t->type == TOK_VAR && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
*cidx = genScalarConstant(p, RIGHT(t));
return OP_SETLOCAL;
} else {
naParseError(p, "bad lvalue", t->line);
return -1;
}
}
static void genLambda(struct Parser* p, struct Token* t)
static void genEqOp(int op, struct Parser* p, struct Token* t)
{
int cidx, setop = genLValue(p, LEFT(t), &cidx);
if(setop == OP_SETMEMBER) {
emit(p, OP_DUP2);
emit(p, OP_POP);
emitImmediate(p, OP_MEMBER, cidx);
} else if(setop == OP_INSERT) {
emit(p, OP_DUP2);
emit(p, OP_EXTRACT);
} else // OP_SETSYM, OP_SETLOCAL
emitImmediate(p, OP_LOCAL, cidx);
genExpr(p, RIGHT(t));
emit(p, op);
emit(p, setop);
}
static int defArg(struct Parser* p, struct Token* t)
{
if(t->type == TOK_LPAR) return defArg(p, RIGHT(t));
return findConstantIndex(p, t);
}
static void genArgList(struct Parser* p, struct naCode* c, struct Token* t)
{
naRef sym;
if(t->type == TOK_EMPTY) return;
if(!IDENTICAL(c->restArgSym, globals->argRef))
naParseError(p, "remainder must be last", t->line);
if(t->type == TOK_ELLIPSIS) {
if(LEFT(t)->type != TOK_SYMBOL)
naParseError(p, "bad function argument expression", t->line);
sym = naStr_fromdata(naNewString(p->context),
LEFT(t)->str, LEFT(t)->strlen);
c->restArgSym = naInternSymbol(sym);
c->needArgVector = 1;
} else if(t->type == TOK_ASSIGN) {
if(LEFT(t)->type != TOK_SYMBOL)
naParseError(p, "bad function argument expression", t->line);
c->optArgSyms[c->nOptArgs] = findConstantIndex(p, LEFT(t));
c->optArgVals[c->nOptArgs++] = defArg(p, RIGHT(t));
} else if(t->type == TOK_SYMBOL) {
if(c->nOptArgs)
naParseError(p, "optional arguments must be last", t->line);
if(c->nArgs >= MAX_FUNARGS)
naParseError(p, "too many named function arguments", t->line);
c->argSyms[c->nArgs++] = findConstantIndex(p, t);
} else if(t->type == TOK_COMMA) {
genArgList(p, c, LEFT(t));
genArgList(p, c, RIGHT(t));
} else
naParseError(p, "bad function argument expression", t->line);
}
static naRef newLambda(struct Parser* p, struct Token* t)
{
int idx;
struct CodeGenerator* cgSave;
naRef codeObj;
if(LEFT(t)->type != TOK_LCURL)
struct Token* arglist;
if(RIGHT(t)->type != TOK_LCURL)
naParseError(p, "bad function definition", t->line);
// Save off the generator state while we do the new one
cgSave = p->cg;
codeObj = naCodeGen(p, LEFT(LEFT(t)));
arglist = LEFT(t)->type == TOK_LPAR ? LEFT(LEFT(t)) : 0;
codeObj = naCodeGen(p, LEFT(RIGHT(t)), arglist);
p->cg = cgSave;
idx = newConstant(p, codeObj);
emitImmediate(p, OP_PUSHCONST, idx);
return codeObj;
}
static void genList(struct Parser* p, struct Token* t)
static void genLambda(struct Parser* p, struct Token* t)
{
emitImmediate(p, OP_PUSHCONST, newConstant(p, newLambda(p, t)));
}
static int genList(struct Parser* p, struct Token* t, int doAppend)
{
if(t->type == TOK_COMMA) {
genExpr(p, LEFT(t));
emit(p, OP_VAPPEND);
genList(p, RIGHT(t));
if(doAppend) emit(p, OP_VAPPEND);
return 1 + genList(p, RIGHT(t), doAppend);
} else if(t->type == TOK_EMPTY) {
return;
return 0;
} else {
genExpr(p, t);
emit(p, OP_VAPPEND);
if(doAppend) emit(p, OP_VAPPEND);
return 1;
}
}
@@ -154,18 +283,19 @@ static void genHash(struct Parser* p, struct Token* t)
static void genFuncall(struct Parser* p, struct Token* t)
{
int op = OP_FCALL;
int nargs = 0;
if(LEFT(t)->type == TOK_DOT) {
genExpr(p, LEFT(LEFT(t)));
emit(p, OP_DUP);
genScalarConstant(p, RIGHT(LEFT(t)));
emit(p, OP_MEMBER);
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(LEFT(t))));
op = OP_MCALL;
} else {
genExpr(p, LEFT(t));
}
emit(p, OP_NEWVEC);
if(RIGHT(t)) genList(p, RIGHT(t));
emit(p, op);
if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
if(tailContext(t))
op = op == OP_FCALL ? OP_FTAIL : OP_MTAIL;
emitImmediate(p, op, nargs);
}
static void pushLoop(struct Parser* p, struct Token* label)
@@ -191,17 +321,15 @@ static int emitJump(struct Parser* p, int op)
{
int ip;
emit(p, op);
ip = p->cg->nBytes;
emit(p, 0xff); // dummy address
emit(p, 0xff);
ip = p->cg->codesz;
emit(p, 0xffff); // dummy address
return ip;
}
// Points a previous jump instruction at the current "end-of-bytecode"
static void fixJumpTarget(struct Parser* p, int spot)
{
p->cg->byteCode[spot] = p->cg->nBytes >> 8;
p->cg->byteCode[spot+1] = p->cg->nBytes & 0xff;
p->cg->byteCode[spot] = p->cg->codesz;
}
static void genShortCircuit(struct Parser* p, struct Token* t)
@@ -240,6 +368,20 @@ static void genIfElse(struct Parser* p, struct Token* t)
genIf(p, t, t->children->next->next);
}
static void genQuestion(struct Parser* p, struct Token* t)
{
int jumpNext, jumpEnd;
if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
naParseError(p, "invalid ?: expression", t->line);
genExpr(p, LEFT(t)); // the test
jumpNext = emitJump(p, OP_JIFNOT);
genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
jumpEnd = emitJump(p, OP_JMP);
fixJumpTarget(p, jumpNext);
genExpr(p, RIGHT(RIGHT(t))); // the "else" expr
fixJumpTarget(p, jumpEnd);
}
static int countSemis(struct Token* t)
{
if(!t || t->type != TOK_SEMI) return 0;
@@ -255,7 +397,7 @@ static void genLoop(struct Parser* p, struct Token* body,
p->cg->loops[p->cg->loopTop-1].breakIP = jumpEnd-1;
jumpOverContinue = emitJump(p, OP_JMP);
p->cg->loops[p->cg->loopTop-1].contIP = p->cg->nBytes;
p->cg->loops[p->cg->loopTop-1].contIP = p->cg->codesz;
cont = emitJump(p, OP_JMP);
fixJumpTarget(p, jumpOverContinue);
@@ -263,7 +405,7 @@ static void genLoop(struct Parser* p, struct Token* body,
emit(p, OP_POP);
fixJumpTarget(p, cont);
if(update) { genExpr(p, update); emit(p, OP_POP); }
emitImmediate(p, OP_JMP, loopTop);
emitImmediate(p, OP_JMPLOOP, loopTop);
fixJumpTarget(p, jumpEnd);
popLoop(p);
emit(p, OP_PUSHNIL); // Leave something on the stack
@@ -276,7 +418,7 @@ static void genForWhile(struct Parser* p, struct Token* init,
int loopTop, jumpEnd;
if(init) { genExpr(p, init); emit(p, OP_POP); }
pushLoop(p, label);
loopTop = p->cg->nBytes;
loopTop = p->cg->codesz;
genExpr(p, test);
jumpEnd = emitJump(p, OP_JIFNOT);
genLoop(p, body, update, label, loopTop, jumpEnd);
@@ -322,7 +464,7 @@ static void genFor(struct Parser* p, struct Token* t)
static void genForEach(struct Parser* p, struct Token* t)
{
int loopTop, jumpEnd, assignOp;
int loopTop, jumpEnd, assignOp, dummy;
struct Token *elem, *body, *vec, *label=0;
struct Token *h = LEFT(LEFT(t));
int semis = countSemis(h);
@@ -341,10 +483,10 @@ static void genForEach(struct Parser* p, struct Token* t)
pushLoop(p, label);
genExpr(p, vec);
emit(p, OP_PUSHZERO);
loopTop = p->cg->nBytes;
emit(p, OP_EACH);
loopTop = p->cg->codesz;
emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
jumpEnd = emitJump(p, OP_JIFNIL);
assignOp = genLValue(p, elem);
assignOp = genLValue(p, elem, &dummy);
emit(p, OP_XCHG);
emit(p, assignOp);
emit(p, OP_POP);
@@ -382,18 +524,34 @@ static void genBreakContinue(struct Parser* p, struct Token* t)
emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
}
static void genExpr(struct Parser* p, struct Token* t)
static void newLineEntry(struct Parser* p, int line)
{
int i;
if(t == 0)
naParseError(p, "BUG: null subexpression", -1);
if(p->cg->nextLineIp >= p->cg->nLineIps) {
int nsz = p->cg->nLineIps*2 + 1;
unsigned short* n = naParseAlloc(p, sizeof(unsigned short)*2*nsz);
for(i=0; i<(p->cg->nextLineIp*2); i++)
n[i] = p->cg->lineIps[i];
p->cg->lineIps = n;
p->cg->nLineIps = nsz;
}
p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) p->cg->codesz;
p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) line;
}
static void genExpr(struct Parser* p, struct Token* t)
{
int i, dummy;
if(t->line != p->cg->lastLine)
emitImmediate(p, OP_LINE, t->line);
newLineEntry(p, t->line);
p->cg->lastLine = t->line;
switch(t->type) {
case TOK_IF:
genIfElse(p, t);
break;
case TOK_QUESTION:
genQuestion(p, t);
break;
case TOK_WHILE:
genWhile(p, t);
break;
@@ -401,6 +559,7 @@ static void genExpr(struct Parser* p, struct Token* t)
genFor(p, t);
break;
case TOK_FOREACH:
case TOK_FORINDEX:
genForEach(p, t);
break;
case TOK_BREAK: case TOK_CONTINUE:
@@ -421,7 +580,7 @@ static void genExpr(struct Parser* p, struct Token* t)
genBinOp(OP_EXTRACT, p, t); // a[i]
} else {
emit(p, OP_NEWVEC);
genList(p, LEFT(t));
genList(p, LEFT(t), 1);
}
break;
case TOK_LCURL:
@@ -429,13 +588,14 @@ static void genExpr(struct Parser* p, struct Token* t)
genHash(p, LEFT(t));
break;
case TOK_ASSIGN:
i = genLValue(p, LEFT(t));
i = genLValue(p, LEFT(t), &dummy);
genExpr(p, RIGHT(t));
emit(p, i); // use the op appropriate to the lvalue
break;
case TOK_RETURN:
if(RIGHT(t)) genExpr(p, RIGHT(t));
else emit(p, OP_PUSHNIL);
for(i=0; i<p->cg->loopTop; i++) emit(p, OP_UNMARK);
emit(p, OP_RETURN);
break;
case TOK_NOT:
@@ -443,8 +603,7 @@ static void genExpr(struct Parser* p, struct Token* t)
emit(p, OP_NOT);
break;
case TOK_SYMBOL:
genScalarConstant(p, t);
emit(p, OP_LOCAL);
emitImmediate(p, OP_LOCAL, findConstantIndex(p, t));
break;
case TOK_LITERAL:
genScalarConstant(p, t);
@@ -468,8 +627,7 @@ static void genExpr(struct Parser* p, struct Token* t)
genExpr(p, LEFT(t));
if(RIGHT(t)->type != TOK_SYMBOL)
naParseError(p, "object field not symbol", RIGHT(t)->line);
genScalarConstant(p, RIGHT(t));
emit(p, OP_MEMBER);
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
break;
case TOK_EMPTY: case TOK_NIL:
emit(p, OP_PUSHNIL); break; // *NOT* a noop!
@@ -486,6 +644,11 @@ static void genExpr(struct Parser* p, struct Token* t)
case TOK_NEQ: genBinOp(OP_NEQ, p, t); break;
case TOK_GT: genBinOp(OP_GT, p, t); break;
case TOK_GTE: genBinOp(OP_GTE, p, t); break;
case TOK_PLUSEQ: genEqOp(OP_PLUS, p, t); break;
case TOK_MINUSEQ: genEqOp(OP_MINUS, p, t); break;
case TOK_MULEQ: genEqOp(OP_MUL, p, t); break;
case TOK_DIVEQ: genEqOp(OP_DIV, p, t); break;
case TOK_CATEQ: genEqOp(OP_CAT, p, t); break;
default:
naParseError(p, "parse error", t->line);
};
@@ -504,7 +667,7 @@ static void genExprList(struct Parser* p, struct Token* t)
}
}
naRef naCodeGen(struct Parser* p, struct Token* t)
naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
{
int i;
naRef codeObj;
@@ -513,28 +676,62 @@ naRef naCodeGen(struct Parser* p, struct Token* t)
cg.lastLine = 0;
cg.codeAlloced = 1024; // Start fairly big, this is a cheap allocation
cg.byteCode = naParseAlloc(p, cg.codeAlloced);
cg.nBytes = 0;
cg.consts = naNewHash(p->context);
cg.interned = naNewHash(p->context);
cg.nConsts = 0;
cg.byteCode = naParseAlloc(p, cg.codeAlloced *sizeof(unsigned short));
cg.codesz = 0;
cg.consts = naNewVector(p->context);
cg.loopTop = 0;
cg.lineIps = 0;
cg.nLineIps = 0;
cg.nextLineIp = 0;
p->cg = &cg;
genExprList(p, t);
genExprList(p, block);
emit(p, OP_RETURN);
// Now make a code object
codeObj = naNewCode(p->context);
code = codeObj.ref.ptr.code;
code->nBytes = cg.nBytes;
code->byteCode = naAlloc(cg.nBytes);
for(i=0; i < cg.nBytes; i++)
// Parse the argument list, if any
code->restArgSym = globals->argRef;
code->nArgs = code->nOptArgs = 0;
code->argSyms = code->optArgSyms = code->optArgVals = 0;
code->needArgVector = 1;
if(arglist) {
code->argSyms = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
code->optArgSyms = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
code->optArgVals = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
code->needArgVector = 0;
genArgList(p, code, arglist);
if(code->nArgs) {
int i, *nsyms;
nsyms = naAlloc(sizeof(int) * code->nArgs);
for(i=0; i<code->nArgs; i++) nsyms[i] = code->argSyms[i];
code->argSyms = nsyms;
} else code->argSyms = 0;
if(code->nOptArgs) {
int i, *nsyms, *nvals;
nsyms = naAlloc(sizeof(int) * code->nOptArgs);
nvals = naAlloc(sizeof(int) * code->nOptArgs);
for(i=0; i<code->nOptArgs; i++) nsyms[i] = code->optArgSyms[i];
for(i=0; i<code->nOptArgs; i++) nvals[i] = code->optArgVals[i];
code->optArgSyms = nsyms;
code->optArgVals = nvals;
} else code->optArgSyms = code->optArgVals = 0;
}
code->codesz = cg.codesz;
code->byteCode = naAlloc(cg.codesz * sizeof(unsigned short));
for(i=0; i < cg.codesz; i++)
code->byteCode[i] = cg.byteCode[i];
code->nConstants = cg.nConsts;
code->nConstants = naVec_size(cg.consts);
code->constants = naAlloc(code->nConstants * sizeof(naRef));
code->srcFile = p->srcFile;
for(i=0; i<code->nConstants; i++)
code->constants[i] = getConstant(p, i);
code->nLines = p->cg->nextLineIp;
code->lineIps = naAlloc(sizeof(unsigned short)*p->cg->nLineIps*2);
for(i=0; i<p->cg->nLineIps*2; i++)
code->lineIps[i] = p->cg->lineIps[i];
return codeObj;
}
+46 -34
View File
@@ -3,27 +3,27 @@
#include "nasal.h"
// Notes: A CODE object is a compiled set of bytecode instructions.
// What actually gets executed at runtime is a bound FUNC object,
// which combines the raw code with a pointer to a CLOSURE chain of
// namespaces.
enum { T_STR, T_VEC, T_HASH, T_CODE, T_CLOSURE, T_FUNC, T_CCODE, T_GHOST,
enum { T_STR, T_VEC, T_HASH, T_CODE, T_FUNC, T_CCODE, T_GHOST,
NUM_NASAL_TYPES }; // V. important that this come last!
#define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG)
#define IS_NUM(r) ((r).ref.reftag != NASAL_REFTAG)
#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0)
//#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0 && (((r).ref.ptr.obj->type == 123) ? *(int*)0 : 1))
#define IS_NIL(r) (IS_REF((r)) && (r).ref.ptr.obj == 0)
#define IS_STR(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_STR)
#define IS_VEC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_VEC)
#define IS_HASH(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_HASH)
#define IS_CODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CODE)
#define IS_FUNC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_FUNC)
#define IS_CLOSURE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CLOSURE)
#define IS_CCODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CCODE)
#define IS_GHOST(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_GHOST)
#define IS_CONTAINER(r) (IS_VEC(r)||IS_HASH(r))
#define IS_SCALAR(r) (IS_NUM((r)) || IS_STR((r)))
#define IDENTICAL(a, b) (IS_REF(a) && IS_REF(b) \
&& a.ref.ptr.obj == b.ref.ptr.obj)
#define MUTABLE(r) (IS_STR(r) && (r).ref.ptr.str->hashcode == 0)
// This is a macro instead of a separate struct to allow compilers to
// avoid padding. GCC on x86, at least, will always padd the size of
@@ -41,13 +41,18 @@ struct naStr {
GC_HEADER;
int len;
unsigned char* data;
unsigned int hashcode;
};
struct VecRec {
int size;
int alloced;
naRef array[];
};
struct naVec {
GC_HEADER;
int size;
int alloced;
naRef* array;
struct VecRec* rec;
};
struct HashNode {
@@ -56,32 +61,40 @@ struct HashNode {
struct HashNode* next;
};
struct naHash {
GC_HEADER;
struct HashRec {
int size;
int dels;
int lgalloced;
struct HashNode* nodes;
struct HashNode** table;
int nextnode;
struct HashNode* table[];
};
struct naHash {
GC_HEADER;
struct HashRec* rec;
};
struct naCode {
GC_HEADER;
unsigned char* byteCode;
int nBytes;
unsigned char nArgs;
unsigned char nOptArgs;
unsigned char needArgVector;
unsigned short nConstants;
unsigned short nLines;
unsigned short codesz;
unsigned short* byteCode;
naRef* constants;
int nConstants;
int* argSyms; // indices into constants
int* optArgSyms;
int* optArgVals;
unsigned short* lineIps; // pairs of {ip, line}
naRef srcFile;
naRef restArgSym; // The "..." vector name, defaults to "arg"
};
struct naFunc {
GC_HEADER;
naRef code;
naRef closure;
};
struct naClosure {
GC_HEADER;
naRef namespace;
naRef next; // parent closure
};
@@ -100,40 +113,39 @@ struct naGhost {
struct naPool {
int type;
int elemsz;
int nblocks;
struct Block* blocks;
int nfree; // number of entries in the free array
int freesz; // size of the free array
void** free; // pointers to usable elements
void** free0; // pointer to the alloced buffer
int freesz; // size of the alloced buffer
void** free; // current "free frame"
int nfree; // down-counting index within the free frame
int freetop; // curr. top of the free list
};
void naFree(void* m);
void* naAlloc(int n);
void* naRealloc(void* buf, int sz);
void naBZero(void* m, int n);
int naTypeSize(int type);
void naGarbageCollect();
naRef naObj(int type, struct naObj* o);
naRef naNew(naContext c, int type);
naRef naNewCode(naContext c);
naRef naNewClosure(naContext c, naRef namespace, naRef next);
int naStr_equal(naRef s1, naRef s2);
naRef naStr_fromnum(naRef dest, double num);
int naStr_numeric(naRef str);
int naStr_parsenum(char* str, int len, double* result);
int naStr_tonum(naRef str, double* out);
void naVec_init(naRef vec);
naRef naStr_buf(naRef str, int len);
int naHash_tryset(naRef hash, naRef key, naRef val); // sets if exists
void naHash_init(naRef hash);
int naHash_sym(struct naHash* h, struct naStr* sym, naRef* out);
void naHash_newsym(struct naHash* h, naRef* sym, naRef* val);
void naGC_init(struct naPool* p, int type);
struct naObj* naGC_get(struct naPool* p);
int naGC_size(struct naPool* p);
void naGC_mark(naRef r);
void naGC_reap(struct naPool* p);
struct naObj** naGC_get(struct naPool* p, int n, int* nout);
void naGC_swapfree(void** target, void* val);
void naGC_freedead();
void naStr_gcclean(struct naStr* s);
void naVec_gcclean(struct naVec* s);
-211
View File
@@ -1,211 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nasal.h"
#include "parse.h"
#include "code.h"
// Bytecode operator to string
char* opStringDEBUG(int op)
{
static char buf[256];
switch(op) {
case OP_AND: return "AND";
case OP_OR: return "OR";
case OP_NOT: return "NOT";
case OP_MUL: return "MUL";
case OP_PLUS: return "PLUS";
case OP_MINUS: return "MINUS";
case OP_DIV: return "DIV";
case OP_NEG: return "NEG";
case OP_CAT: return "CAT";
case OP_LT: return "LT";
case OP_LTE: return "LTE";
case OP_GT: return "GT";
case OP_GTE: return "GTE";
case OP_EQ: return "EQ";
case OP_NEQ: return "NEQ";
case OP_EACH: return "EACH";
case OP_JMP: return "JMP";
case OP_JIFNOT: return "JIFNOT";
case OP_JIFNIL: return "JIFNIL";
case OP_FCALL: return "FCALL";
case OP_MCALL: return "MCALL";
case OP_RETURN: return "RETURN";
case OP_PUSHCONST: return "PUSHCONST";
case OP_PUSHONE: return "PUSHONE";
case OP_PUSHZERO: return "PUSHZERO";
case OP_PUSHNIL: return "PUSHNIL";
case OP_POP: return "POP";
case OP_DUP: return "DUP";
case OP_XCHG: return "XCHG";
case OP_INSERT: return "INSERT";
case OP_EXTRACT: return "EXTRACT";
case OP_MEMBER: return "MEMBER";
case OP_SETMEMBER: return "SETMEMBER";
case OP_LOCAL: return "LOCAL";
case OP_SETLOCAL: return "SETLOCAL";
case OP_NEWVEC: return "NEWVEC";
case OP_VAPPEND: return "VAPPEND";
case OP_NEWHASH: return "NEWHASH";
case OP_HAPPEND: return "HAPPEND";
case OP_LINE: return "LINE";
case OP_MARK: return "MARK";
case OP_UNMARK: return "UNMARK";
case OP_BREAK: return "BREAK";
}
sprintf(buf, "<bad opcode: %d>\n", op);
return buf;
}
// Print a bytecode operator
void printOpDEBUG(int ip, int op)
{
printf("IP: %d OP: %s\n", ip, opStringDEBUG(op));
}
// Print a naRef
void printRefDEBUG(naRef r)
{
int i;
if(IS_NUM(r)) {
printf("%f\n", r.num);
} else if(IS_NIL(r)) {
printf("<nil>\n");
} else if(IS_STR(r)) {
printf("\"");
for(i=0; i<r.ref.ptr.str->len; i++)
printf("%c", r.ref.ptr.str->data[i]);
printf("\"\n");
} else if(IS_VEC(r)) {
printf("<vec>\n");
} else if(IS_HASH(r)) {
printf("<hash>\n");
} else if(IS_FUNC(r)) {
printf("<func>\n");
} else if(IS_CLOSURE(r)) {
printf("DEBUG: closure object on stack!\n");
} else if(IS_CODE(r)) {
printf("DEBUG: code object on stack!\n");
} else printf("DEBUG ACK\n");
}
// Print the operand stack of the specified context
void printStackDEBUG(struct Context* ctx)
{
int i;
printf("\n");
for(i=ctx->opTop-1; i>=0; i--) {
printf("] ");
printRefDEBUG(ctx->opStack[i]);
}
printf("\n");
}
// Token type to string
char* tokString(int tok)
{
switch(tok) {
case TOK_TOP: return "TOK_TOP";
case TOK_AND: return "TOK_AND";
case TOK_OR: return "TOK_OR";
case TOK_NOT: return "TOK_NOT";
case TOK_LPAR: return "TOK_LPAR";
case TOK_RPAR: return "TOK_RPAR";
case TOK_LBRA: return "TOK_LBRA";
case TOK_RBRA: return "TOK_RBRA";
case TOK_LCURL: return "TOK_LCURL";
case TOK_RCURL: return "TOK_RCURL";
case TOK_MUL: return "TOK_MUL";
case TOK_PLUS: return "TOK_PLUS";
case TOK_MINUS: return "TOK_MINUS";
case TOK_NEG: return "TOK_NEG";
case TOK_DIV: return "TOK_DIV";
case TOK_CAT: return "TOK_CAT";
case TOK_COLON: return "TOK_COLON";
case TOK_DOT: return "TOK_DOT";
case TOK_COMMA: return "TOK_COMMA";
case TOK_SEMI: return "TOK_SEMI";
case TOK_ASSIGN: return "TOK_ASSIGN";
case TOK_LT: return "TOK_LT";
case TOK_LTE: return "TOK_LTE";
case TOK_EQ: return "TOK_EQ";
case TOK_NEQ: return "TOK_NEQ";
case TOK_GT: return "TOK_GT";
case TOK_GTE: return "TOK_GTE";
case TOK_IF: return "TOK_IF";
case TOK_ELSIF: return "TOK_ELSIF";
case TOK_ELSE: return "TOK_ELSE";
case TOK_FOR: return "TOK_FOR";
case TOK_FOREACH: return "TOK_FOREACH";
case TOK_WHILE: return "TOK_WHILE";
case TOK_RETURN: return "TOK_RETURN";
case TOK_BREAK: return "TOK_BREAK";
case TOK_CONTINUE: return "TOK_CONTINUE";
case TOK_FUNC: return "TOK_FUNC";
case TOK_SYMBOL: return "TOK_SYMBOL";
case TOK_LITERAL: return "TOK_LITERAL";
case TOK_EMPTY: return "TOK_EMPTY";
case TOK_NIL: return "TOK_NIL";
}
return 0;
}
// Diagnostic: check all list pointers for sanity
void ack()
{
printf("Bad token list!\n");
exit(1);
}
void checkList(struct Token* start, struct Token* end)
{
struct Token* t = start;
while(t) {
if(t->next && t->next->prev != t) ack();
if(t->next==0 && t != end) ack();
t = t->next;
}
t = end;
while(t) {
if(t->prev && t->prev->next != t) ack();
if(t->prev==0 && t != start) ack();
t = t->prev;
};
}
// Prints a single parser token to stdout
void printToken(struct Token* t, char* prefix)
{
int i;
printf("%sline %d %s ", prefix, t->line, tokString(t->type));
if(t->type == TOK_LITERAL || t->type == TOK_SYMBOL) {
if(t->str) {
printf("\"");
for(i=0; i<t->strlen; i++) printf("%c", t->str[i]);
printf("\" (len: %d)", t->strlen);
} else {
printf("%f ", t->num);
}
}
printf("\n");
}
// Prints a parse tree to stdout
void dumpTokenList(struct Token* t, int prefix)
{
char prefstr[128];
int i;
prefstr[0] = 0;
for(i=0; i<prefix; i++)
strcat(prefstr, ". ");
while(t) {
printToken(t, prefstr);
dumpTokenList(t->children, prefix+1);
t = t->next;
}
}
+219 -104
View File
@@ -1,44 +1,131 @@
#include "nasal.h"
#include "data.h"
#include "code.h"
#define MIN_BLOCK_SIZE 256
// "type" for an object freed by the collector
#define T_GCFREED 123 // DEBUG
static void reap(struct naPool* p);
static void mark(naRef r);
struct Block {
int size;
char* block;
struct Block* next;
};
// Decremented every allocation. When it reaches zero, we do a
// garbage collection. The value is reset to 1/2 of the total object
// count each collection, which is sane: it ensures that no more than
// 50% growth can happen between collections, and ensures that garbage
// collection work is constant with allocation work (i.e. that O(N)
// work is done only every O(1/2N) allocations).
static int GlobalAllocCount = 256;
static void appendfree(struct naPool*p, struct naObj* o)
// Must be called with the giant exclusive lock!
static void freeDead()
{
// Need more space?
if(p->freesz <= p->nfree) {
int i, n = 1+((3*p->nfree)>>1);
void** newf = naAlloc(n * sizeof(void*));
for(i=0; i<p->nfree; i++)
newf[i] = p->free[i];
naFree(p->free);
p->free = newf;
p->freesz = n;
int i;
for(i=0; i<globals->ndead; i++)
naFree(globals->deadBlocks[i]);
globals->ndead = 0;
}
static void marktemps(struct Context* c)
{
int i;
naRef r = naNil();
for(i=0; i<c->ntemps; i++) {
r.ref.ptr.obj = c->temps[i];
mark(r);
}
}
// Must be called with the big lock!
static void garbageCollect()
{
int i;
struct Context* c;
globals->allocCount = 0;
c = globals->allContexts;
while(c) {
for(i=0; i<NUM_NASAL_TYPES; i++)
c->nfree[i] = 0;
for(i=0; i < c->fTop; i++) {
mark(c->fStack[i].func);
mark(c->fStack[i].locals);
}
for(i=0; i < c->opTop; i++)
mark(c->opStack[i]);
mark(c->dieArg);
marktemps(c);
c = c->nextAll;
}
p->free[p->nfree++] = o;
mark(globals->save);
mark(globals->symbols);
mark(globals->meRef);
mark(globals->argRef);
mark(globals->parentsRef);
// Finally collect all the freed objects
for(i=0; i<NUM_NASAL_TYPES; i++)
reap(&(globals->pools[i]));
// Make enough space for the dead blocks we need to free during
// execution. This works out to 1 spot for every 2 live objects,
// which should be limit the number of bottleneck operations
// without imposing an undue burden of extra "freeable" memory.
if(globals->deadsz < globals->allocCount) {
globals->deadsz = globals->allocCount;
if(globals->deadsz < 256) globals->deadsz = 256;
naFree(globals->deadBlocks);
globals->deadBlocks = naAlloc(sizeof(void*) * globals->deadsz);
}
globals->needGC = 0;
}
void naModLock()
{
LOCK();
globals->nThreads++;
UNLOCK();
naCheckBottleneck();
}
void naModUnlock()
{
LOCK();
globals->nThreads--;
UNLOCK();
}
// Must be called with the main lock. Engages the "bottleneck", where
// all threads will block so that one (the last one to call this
// function) can run alone. This is done for GC, and also to free the
// list of "dead" blocks when it gets full (which is part of GC, if
// you think about it).
static void bottleneck()
{
struct Globals* g = globals;
g->bottleneck = 1;
while(g->bottleneck && g->waitCount < g->nThreads - 1) {
g->waitCount++;
UNLOCK(); naSemDown(g->sem); LOCK();
g->waitCount--;
}
if(g->waitCount >= g->nThreads - 1) {
freeDead();
if(g->needGC) garbageCollect();
if(g->waitCount) naSemUpAll(g->sem, g->waitCount);
g->bottleneck = 0;
}
}
void naCheckBottleneck()
{
if(globals->bottleneck) { LOCK(); bottleneck(); UNLOCK(); }
}
static void naCode_gcclean(struct naCode* o)
{
naFree(o->byteCode); o->byteCode = 0;
naFree(o->constants); o->constants = 0;
naFree(o->byteCode); o->byteCode = 0;
naFree(o->constants); o->constants = 0;
naFree(o->argSyms); o->argSyms = 0;
naFree(o->optArgSyms); o->optArgSyms = 0;
naFree(o->optArgVals); o->optArgVals = 0;
naFree(o->lineIps); o->lineIps = 0;
}
static void naGhost_gcclean(struct naGhost* g)
@@ -49,9 +136,6 @@ static void naGhost_gcclean(struct naGhost* g)
static void freeelem(struct naPool* p, struct naObj* o)
{
// Mark the object as "freed" for debugging purposes
o->type = T_GCFREED; // DEBUG
// Free any intrinsic (i.e. non-garbage collected) storage the
// object might have
switch(p->type) {
@@ -73,77 +157,100 @@ static void freeelem(struct naPool* p, struct naObj* o)
}
// And add it to the free list
appendfree(p, o);
p->free[p->nfree++] = o;
}
static void newBlock(struct naPool* p, int need)
{
int i;
char* buf;
struct Block* newblocks;
struct Block* newb;
if(need < MIN_BLOCK_SIZE)
need = MIN_BLOCK_SIZE;
if(need < MIN_BLOCK_SIZE) need = MIN_BLOCK_SIZE;
newb = naAlloc(sizeof(struct Block));
newb->block = naAlloc(need * p->elemsz);
newb->size = need;
newb->next = p->blocks;
p->blocks = newb;
naBZero(newb->block, need * p->elemsz);
newblocks = naAlloc((p->nblocks+1) * sizeof(struct Block));
for(i=0; i<p->nblocks; i++) newblocks[i] = p->blocks[i];
naFree(p->blocks);
p->blocks = newblocks;
buf = naAlloc(need * p->elemsz);
naBZero(buf, need * p->elemsz);
p->blocks[p->nblocks].size = need;
p->blocks[p->nblocks].block = buf;
p->nblocks++;
for(i=0; i<need; i++) {
struct naObj* o = (struct naObj*)(buf + i*p->elemsz);
if(need > p->freesz - p->freetop) need = p->freesz - p->freetop;
p->nfree = 0;
p->free = p->free0 + p->freetop;
for(i=0; i < need; i++) {
struct naObj* o = (struct naObj*)(newb->block + i*p->elemsz);
o->mark = 0;
o->type = p->type;
appendfree(p, o);
p->free[p->nfree++] = o;
}
p->freetop += need;
}
void naGC_init(struct naPool* p, int type)
{
p->type = type;
p->elemsz = naTypeSize(type);
p->nblocks = 0;
p->blocks = 0;
p->nfree = 0;
p->freesz = 0;
p->free = 0;
naGC_reap(p);
p->free0 = p->free = 0;
p->nfree = p->freesz = p->freetop = 0;
reap(p);
}
int naGC_size(struct naPool* p)
static int poolsize(struct naPool* p)
{
int i, total=0;
for(i=0; i<p->nblocks; i++)
total += ((struct Block*)(p->blocks + i))->size;
int total = 0;
struct Block* b = p->blocks;
while(b) { total += b->size; b = b->next; }
return total;
}
struct naObj* naGC_get(struct naPool* p)
struct naObj** naGC_get(struct naPool* p, int n, int* nout)
{
// Collect every GlobalAllocCount allocations.
// This gets set to ~50% of the total object count each
// collection (it's incremented in naGC_reap()).
if(--GlobalAllocCount < 0) {
GlobalAllocCount = 0;
naGarbageCollect();
struct naObj** result;
naCheckBottleneck();
LOCK();
while(globals->allocCount < 0 || (p->nfree == 0 && p->freetop >= p->freesz)) {
globals->needGC = 1;
bottleneck();
}
// If we're out, then allocate an extra 12.5%
if(p->nfree == 0)
newBlock(p, naGC_size(p)/8);
return p->free[--p->nfree];
newBlock(p, poolsize(p)/8);
n = p->nfree < n ? p->nfree : n;
*nout = n;
p->nfree -= n;
globals->allocCount -= n;
result = (struct naObj**)(p->free + p->nfree);
UNLOCK();
return result;
}
static void markvec(naRef r)
{
int i;
struct VecRec* vr = r.ref.ptr.vec->rec;
if(!vr) return;
for(i=0; i<vr->size; i++)
mark(vr->array[i]);
}
static void markhash(naRef r)
{
int i;
struct HashRec* hr = r.ref.ptr.hash->rec;
if(!hr) return;
for(i=0; i < (1<<hr->lgalloced); i++) {
struct HashNode* hn = hr->table[i];
while(hn) {
mark(hn->key);
mark(hn->val);
hn = hn->next;
}
}
}
// Sets the reference bit on the object, and recursively on all
// objects reachable from it. Clumsy: uses C stack recursion, which
// is slower than it need be and may cause problems on some platforms
// due to the very large stack depths that result.
void naGC_mark(naRef r)
// objects reachable from it. Uses the processor stack for recursion...
static void mark(naRef r)
{
int i;
@@ -153,62 +260,48 @@ void naGC_mark(naRef r)
if(r.ref.ptr.obj->mark == 1)
return;
// Verify that the object hasn't been freed incorrectly:
if(r.ref.ptr.obj->type == T_GCFREED) *(int*)0=0; // DEBUG
r.ref.ptr.obj->mark = 1;
switch(r.ref.ptr.obj->type) {
case T_VEC:
for(i=0; i<r.ref.ptr.vec->size; i++)
naGC_mark(r.ref.ptr.vec->array[i]);
break;
case T_HASH:
if(r.ref.ptr.hash->table == 0)
break;
for(i=0; i < (1<<r.ref.ptr.hash->lgalloced); i++) {
struct HashNode* hn = r.ref.ptr.hash->table[i];
while(hn) {
naGC_mark(hn->key);
naGC_mark(hn->val);
hn = hn->next;
}
}
break;
case T_VEC: markvec(r); break;
case T_HASH: markhash(r); break;
case T_CODE:
naGC_mark(r.ref.ptr.code->srcFile);
mark(r.ref.ptr.code->srcFile);
for(i=0; i<r.ref.ptr.code->nConstants; i++)
naGC_mark(r.ref.ptr.code->constants[i]);
break;
case T_CLOSURE:
naGC_mark(r.ref.ptr.closure->namespace);
naGC_mark(r.ref.ptr.closure->next);
mark(r.ref.ptr.code->constants[i]);
break;
case T_FUNC:
naGC_mark(r.ref.ptr.func->code);
naGC_mark(r.ref.ptr.func->closure);
mark(r.ref.ptr.func->code);
mark(r.ref.ptr.func->namespace);
mark(r.ref.ptr.func->next);
break;
}
}
// Collects all the unreachable objects into a free list, and
// allocates more space if needed.
void naGC_reap(struct naPool* p)
static void reap(struct naPool* p)
{
int i, elem, total = 0;
struct Block* b;
int elem, freesz, total = poolsize(p);
p->nfree = 0;
for(i=0; i<p->nblocks; i++) {
struct Block* b = p->blocks + i;
total += b->size;
freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total;
freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ);
if(p->freesz < freesz) {
naFree(p->free0);
p->freesz = freesz;
p->free = p->free0 = naAlloc(sizeof(void*) * p->freesz);
}
for(b = p->blocks; b; b = b->next)
for(elem=0; elem < b->size; elem++) {
struct naObj* o = (struct naObj*)(b->block + elem * p->elemsz);
if(o->mark == 0)
freeelem(p, o);
o->mark = 0;
}
}
// Add 50% of our total to the global count
GlobalAllocCount += total/2;
// allocs of this type until the next collection
globals->allocCount += total/2;
// Allocate more if necessary (try to keep 25-50% of the objects
// available)
@@ -219,5 +312,27 @@ void naGC_reap(struct naPool* p)
if(need > 0)
newBlock(p, need);
}
p->freetop = p->nfree;
}
// Does the swap, returning the old value
static void* doswap(void** target, void* val)
{
void* old = *target;
*target = val;
return old;
}
// Atomically replaces target with a new pointer, and adds the old one
// to the list of blocks to free the next time something holds the
// giant lock.
void naGC_swapfree(void** target, void* val)
{
void* old;
LOCK();
old = doswap(target, val);
while(globals->ndead >= globals->deadsz)
bottleneck();
globals->deadBlocks[globals->ndead++] = old;
UNLOCK();
}
+142 -113
View File
@@ -1,42 +1,22 @@
#include "nasal.h"
#include "data.h"
static void realloc(naRef hash)
{
struct naHash* h = hash.ref.ptr.hash;
int i, sz, oldsz = h->size;
int oldcols = h->table ? 1 << h->lgalloced : 0;
#define MIN_HASH_SIZE 4
// Keep a handle to our original objects
struct HashNode* oldnodes = h->nodes;
struct HashNode** oldtable = h->table;
#define EQUAL(a, b) (((a).ref.reftag == (b).ref.reftag \
&& (a).ref.ptr.obj == (b).ref.ptr.obj) \
|| naEqual(a, b))
// Figure out how big we need to be (start with a minimum size of
// 16 entries)
for(i=3; 1<<i < oldsz; i++);
h->lgalloced = i+1;
// Allocate new ones (note that all the records are allocated in a
// single chunk, to avoid zillions of tiny node allocations)
sz = 1<<h->lgalloced;
h->nodes = naAlloc(sz * (sizeof(struct HashNode) + sizeof(void*)));
h->table = (struct HashNode**)(((char*)h->nodes) + sz*sizeof(struct HashNode));
naBZero(h->table, sz * sizeof(void*));
h->nextnode = 0;
h->size = 0;
#define HASH_MAGIC 2654435769u
// Re-insert everything from scratch
for(i=0; i<oldcols; i++) {
struct HashNode* hn = oldtable[i];
while(hn) {
naHash_set(hash, hn->key, hn->val);
hn = hn->next;
}
}
// Free the old memory
naFree(oldnodes);
}
#define INSERT(hh, hkey, hval, hcol) do { \
unsigned int cc = (hcol), iidx=(hh)->size++; \
if(iidx < (1<<(hh)->lgalloced)) { \
struct HashNode* hnn = &(hh)->nodes[iidx]; \
hnn->key = (hkey); hnn->val = (hval); \
hnn->next = (hh)->table[cc]; \
(hh)->table[cc] = hnn; \
}} while(0)
// Computes a hash code for a given scalar
static unsigned int hashcode(naRef r)
@@ -48,61 +28,107 @@ static unsigned int hashcode(naRef r)
// 2*sizeof(int).
unsigned int* p = (unsigned int*)&(r.num);
return p[0] ^ p[1];
} else if(r.ref.ptr.str->hashcode) {
return r.ref.ptr.str->hashcode;
} else {
// This is Daniel Bernstein's djb2 hash function that I found
// on the web somewhere. It appears to work pretty well.
unsigned int i, hash = 5831;
for(i=0; i<r.ref.ptr.str->len; i++)
hash = (hash * 33) ^ r.ref.ptr.str->data[i];
r.ref.ptr.str->hashcode = hash;
return hash;
}
}
// Which column in a given hash does the key correspond to.
static unsigned int hashcolumn(struct naHash* h, naRef key)
static unsigned int hashcolumn(struct HashRec* h, naRef key)
{
// Multiply by a big number, and take the top N bits. Note
// assumption that sizeof(unsigned int) == 4.
return (2654435769u * hashcode(key)) >> (32 - h->lgalloced);
return (HASH_MAGIC * hashcode(key)) >> (32 - h->lgalloced);
}
struct HashNode* find(struct naHash* h, naRef key)
static struct HashRec* realloc(struct naHash* hash)
{
struct HashNode* hn;
if(h->table == 0)
return 0;
hn = h->table[hashcolumn(h, key)];
while(hn) {
if(naEqual(key, hn->key))
return hn;
hn = hn->next;
struct HashRec *h, *h0 = hash->rec;
int lga, cols, need = h0 ? h0->size - h0->dels : MIN_HASH_SIZE;
if(need < MIN_HASH_SIZE) need = MIN_HASH_SIZE;
for(lga=0; 1<<lga <= need; lga++);
cols = 1<<lga;
h = naAlloc(sizeof(struct HashRec) +
cols * (sizeof(struct HashNode*) + sizeof(struct HashNode)));
naBZero(h, sizeof(struct HashRec) + cols * sizeof(struct HashNode*));
h->lgalloced = lga;
h->nodes = (struct HashNode*)(((char*)h)
+ sizeof(struct HashRec)
+ cols * sizeof(struct HashNode*));
for(lga=0; h0 != 0 && lga<(1<<h0->lgalloced); lga++) {
struct HashNode* hn = h0->table[lga];
while(hn) {
INSERT(h, hn->key, hn->val, hashcolumn(h, hn->key));
hn = hn->next;
}
}
naGC_swapfree((void**)&hash->rec, h);
return h;
}
// Special, optimized version of naHash_get for the express purpose of
// looking up symbols in the local variables hash (OP_LOCAL is by far
// the most common opcode and deserves some special case
// optimization). Elides all the typing checks that are normally
// required, presumes that the key is a string and has had its
// hashcode precomputed, checks only for object identity, and inlines
// the column computation.
int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
{
struct HashRec* h = hash->rec;
if(h) {
int col = (HASH_MAGIC * sym->hashcode) >> (32 - h->lgalloced);
struct HashNode* hn = h->table[col];
while(hn) {
if(hn->key.ref.ptr.str == sym) {
*out = hn->val;
return 1;
}
hn = hn->next;
}
}
return 0;
}
void naHash_init(naRef hash)
static struct HashNode* find(struct naHash* hash, naRef key)
{
struct naHash* h = hash.ref.ptr.hash;
h->size = 0;
h->lgalloced = 0;
h->table = 0;
h->nodes = 0;
struct HashRec* h = hash->rec;
if(h) {
struct HashNode* hn = h->table[hashcolumn(h, key)];
while(hn) {
if(EQUAL(key, hn->key))
return hn;
hn = hn->next;
}
}
return 0;
}
// Make a temporary string on the stack
static naRef tmpStr(struct naStr* str, char* key)
static void tmpStr(naRef* out, struct naStr* str, char* key)
{
char* p = key;
while(*p) { p++; }
str->len = p - key;
str->data = key;
return naObj(T_STR, (struct naObj*)str);
str->len = 0;
str->data = (unsigned char*)key;
while(key[str->len]) str->len++;
*out = naNil();
out->ref.ptr.str = str;
}
naRef naHash_cget(naRef hash, char* key)
{
struct naStr str;
naRef result, key2 = tmpStr(&str, key);
naRef result, key2;
tmpStr(&key2, &str, key);
if(naHash_get(hash, key2, &result))
return result;
return naNil();
@@ -111,80 +137,86 @@ naRef naHash_cget(naRef hash, char* key)
void naHash_cset(naRef hash, char* key, naRef val)
{
struct naStr str;
naRef key2 = tmpStr(&str, key);
naRef key2;
tmpStr(&key2, &str, key);
naHash_tryset(hash, key2, val);
}
int naHash_get(naRef hash, naRef key, naRef* out)
{
struct naHash* h = hash.ref.ptr.hash;
struct HashNode* n;
if(!IS_HASH(hash)) return 0;
n = find(h, key);
if(n) {
*out = n->val;
return 1;
} else {
*out = naNil();
return 0;
if(IS_HASH(hash)) {
struct HashNode* n = find(hash.ref.ptr.hash, key);
if(n) { *out = n->val; return 1; }
}
return 0;
}
// Simpler version. Don't create a new node if the value isn't there
int naHash_tryset(naRef hash, naRef key, naRef val)
{
struct HashNode* n;
if(!IS_HASH(hash)) return 0;
n = find(hash.ref.ptr.hash, key);
if(n) n->val = val;
return n != 0;
if(IS_HASH(hash)) {
struct HashNode* n = find(hash.ref.ptr.hash, key);
if(n) n->val = val;
return n != 0;
}
return 0;
}
// Special purpose optimization for use in function call setups. Sets
// a value that is known *not* to be present in the hash table. As
// for naHash_sym, the key must be a string with a precomputed hash
// code.
void naHash_newsym(struct naHash* hash, naRef* sym, naRef* val)
{
int col;
struct HashRec* h = hash->rec;
while(!h || h->size >= 1<<h->lgalloced)
h = realloc(hash);
col = (HASH_MAGIC * sym->ref.ptr.str->hashcode) >> (32 - h->lgalloced);
INSERT(h, *sym, *val, col);
}
// The cycle check is an integrity requirement for multithreading,
// where raced inserts can potentially cause cycles. This ensures
// that the "last" thread to hold a reference to an inserted node
// breaks any cycles that might have happened (at the expense of
// potentially dropping items out of the hash). Under normal
// circumstances, chains will be very short and this will be fast.
static void chkcycle(struct HashNode* node, int count)
{
struct HashNode* hn = node;
while(hn && (hn = hn->next) != 0)
if(count-- <= 0) { node->next = 0; return; }
}
void naHash_set(naRef hash, naRef key, naRef val)
{
struct naHash* h = hash.ref.ptr.hash;
unsigned int col;
int col;
struct HashRec* h;
struct HashNode* n;
if(!IS_HASH(hash)) return;
n = find(h, key);
if(n) {
n->val = val;
return;
}
if(h->size+1 >= 1<<h->lgalloced)
realloc(hash);
if((n = find(hash.ref.ptr.hash, key))) { n->val = val; return; }
h = hash.ref.ptr.hash->rec;
while(!h || h->size >= 1<<h->lgalloced)
h = realloc(hash.ref.ptr.hash);
col = hashcolumn(h, key);
n = h->nodes + h->nextnode++;
n->key = key;
n->val = val;
n->next = h->table[col];
h->table[col] = n;
h->size++;
INSERT(h, key, val, hashcolumn(h, key));
chkcycle(h->table[col], h->size - h->dels);
}
// FIXME: this implementation does a realloc() after each delete, and
// is therefore needlessly O(N). (The reason is that this avoids the
// need to keep a free list around for the much more common case of
// adding a new value. Modifying an existing value is O(1), of
// course.)
void naHash_delete(naRef hash, naRef key)
{
struct naHash* h = hash.ref.ptr.hash;
struct HashRec* h = hash.ref.ptr.hash->rec;
int col;
struct HashNode *last=0, *hn;
if(!IS_HASH(hash)) return;
if(!IS_HASH(hash) || !h) return;
col = hashcolumn(h, key);
hn = h->table[col];
while(hn) {
if(naEqual(hn->key, key)) {
if(EQUAL(hn->key, key)) {
if(last == 0) h->table[col] = hn->next;
else last->next = hn->next;
h->size--;
realloc(hash);
h->dels++;
return;
}
last = hn;
@@ -194,9 +226,9 @@ void naHash_delete(naRef hash, naRef key)
void naHash_keys(naRef dst, naRef hash)
{
struct naHash* h = hash.ref.ptr.hash;
int i;
if(!IS_HASH(hash) || !h->table) return;
struct HashRec* h = hash.ref.ptr.hash->rec;
if(!IS_HASH(hash) || !h) return;
for(i=0; i<(1<<h->lgalloced); i++) {
struct HashNode* hn = h->table[i];
while(hn) {
@@ -206,18 +238,15 @@ void naHash_keys(naRef dst, naRef hash)
}
}
int naHash_size(naRef h)
int naHash_size(naRef hash)
{
if(!IS_HASH(h)) return 0;
return h.ref.ptr.hash->size;
struct HashRec* h = hash.ref.ptr.hash->rec;
if(!IS_HASH(hash) || !h) return 0;
return h->size - h->dels;
}
void naHash_gcclean(struct naHash* h)
{
naFree(h->nodes);
h->nodes = 0;
h->size = 0;
h->lgalloced = 0;
h->table = 0;
h->nextnode = 0;
naFree(h->rec);
h->rec = 0;
}
+51 -17
View File
@@ -40,7 +40,16 @@ struct Lexeme {
{"return", TOK_RETURN},
{"break", TOK_BREAK},
{"continue", TOK_CONTINUE},
{"func", TOK_FUNC}
{"func", TOK_FUNC},
{"...", TOK_ELLIPSIS},
{"?", TOK_QUESTION},
{"var", TOK_VAR},
{"+=", TOK_PLUSEQ},
{"-=", TOK_MINUSEQ},
{"*=", TOK_MULEQ},
{"/=", TOK_DIVEQ},
{"~=", TOK_CATEQ},
{"forindex", TOK_FORINDEX},
};
// Build a table of where each line ending is
@@ -127,14 +136,19 @@ static void newToken(struct Parser* p, int pos, int type,
p->tree.lastChild = tok;
}
// Parse a hex nibble
static int hexc(char c, struct Parser* p, int index)
static int hex(char c)
{
if(c >= '0' && c <= '9') return c - '0';
if(c >= 'A' && c <= 'F') return c - 'A' + 10;
if(c >= 'a' && c <= 'f') return c - 'a' + 10;
error(p, "bad hex constant", index);
return 0;
return -1;
}
static int hexc(char c, struct Parser* p, int index)
{
int n = hex(c);
if(n < 0) error(p, "bad hex constant", index);
return n;
}
// Escape and returns a single backslashed expression in a single
@@ -177,13 +191,19 @@ static void dqEscape(char* buf, int len, int index, struct Parser* p,
}
}
// FIXME: should handle UTF8 too
static void charLiteral(struct Parser* p, int index, char* s, int len)
{
if(len != 1) error(p, "character constant not single character", index);
newToken(p, index, TOK_LITERAL, 0, 0, *s);
}
// Read in a string literal
static int lexStringLiteral(struct Parser* p, int index, int singleQuote)
static int lexStringLiteral(struct Parser* p, int index, char q)
{
int i, j, len, iteration;
char* out = 0;
char* buf = p->buf;
char endMark = singleQuote ? '\'' : '"';
for(iteration = 0; iteration<2; iteration++) {
i = index+1;
@@ -191,11 +211,10 @@ static int lexStringLiteral(struct Parser* p, int index, int singleQuote)
while(i < p->len) {
char c = buf[i];
int eaten = 1;
if(c == endMark)
break;
if(c == q) break;
if(c == '\\') {
if(singleQuote) sqEscape(buf+i, p->len-i, i, p, &c, &eaten);
else dqEscape(buf+i, p->len-i, i, p, &c, &eaten);
if(q == '\'') sqEscape(buf+i, p->len-i, i, p, &c, &eaten);
else dqEscape(buf+i, p->len-i, i, p, &c, &eaten);
}
if(iteration == 1) out[j++] = c;
i += eaten;
@@ -204,16 +223,31 @@ static int lexStringLiteral(struct Parser* p, int index, int singleQuote)
// Finished stage one -- allocate the buffer for stage two
if(iteration == 0) out = naParseAlloc(p, len);
}
newToken(p, index, TOK_LITERAL, out, len, 0);
if(q == '`') charLiteral(p, index, out, len);
else newToken(p, index, TOK_LITERAL, out, len, 0);
return i+1;
}
static int lexHexLiteral(struct Parser* p, int index)
{
int nib, i = index;
double d = 0;
while(i < p->len && (nib = hex(p->buf[i])) >= 0) {
d = d*16 + nib;
i++;
}
newToken(p, index, TOK_LITERAL, 0, 0, d);
return i;
}
static int lexNumLiteral(struct Parser* p, int index)
{
int len = p->len, i = index;
unsigned char* buf = p->buf;
unsigned char* buf = (unsigned char*)p->buf;
double d;
if(i+1<len && buf[i+1] == 'x') return lexHexLiteral(p, index+2);
while(i<len && buf[i] >= '0' && buf[i] <= '9') i++;
if(i<len && buf[i] == '.') {
i++;
@@ -300,12 +334,12 @@ void naLex(struct Parser* p)
case '#':
i = lineEnd(p, getLine(p, i));
break;
case '\'': case '"':
i = lexStringLiteral(p, i, (c=='"' ? 0 : 1));
case '\'': case '"': case '`':
i = lexStringLiteral(p, i, c);
break;
default:
if(c >= '0' && c <= '9') i = lexNumLiteral(p, i);
else handled = 0;
else handled = 0;
}
// Lexemes and symbols are a little more complicated. Pick
@@ -315,7 +349,7 @@ void naLex(struct Parser* p)
// symbol (e.g. "orchid"). If neither match, we have a bad
// character in the mix.
if(!handled) {
int symlen=0, lexlen=0, lexeme;
int symlen=0, lexlen=0, lexeme=-1;
lexlen = tryLexemes(p, i, &lexeme);
if((c>='A' && c<='Z') || (c>='a' && c<='z') || (c=='_'))
symlen = trySymbol(p, i);
+387 -81
View File
@@ -1,68 +1,72 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#ifdef _MSC_VER // sigh...
#define vsnprintf _vsnprintf
#endif
#include "nasal.h"
#include "code.h"
// No need to include <string.h> just for this:
// It needs a funny name because MSVC wants to treat "strlen" as a
// special symbol. Ugh...
static int StrLen(char* s)
{
char* s0 = s;
while(*s) s++;
return s - s0;
}
#define NEWSTR(c, s, l) naStr_fromdata(naNewString(c), s, l)
#define NEWCSTR(c, s) NEWSTR(c, s, strlen(s))
static naRef size(naContext c, naRef args)
static naRef size(naContext c, naRef me, int argc, naRef* args)
{
naRef r;
if(naVec_size(args) == 0) return naNil();
r = naVec_get(args, 0);
if(naIsString(r)) return naNum(naStr_len(r));
if(naIsVector(r)) return naNum(naVec_size(r));
if(naIsHash(r)) return naNum(naHash_size(r));
if(argc == 0) return naNil();
if(naIsString(args[0])) return naNum(naStr_len(args[0]));
if(naIsVector(args[0])) return naNum(naVec_size(args[0]));
if(naIsHash(args[0])) return naNum(naHash_size(args[0]));
naRuntimeError(c, "object has no size()");
return naNil();
}
static naRef keys(naContext c, naRef args)
static naRef keys(naContext c, naRef me, int argc, naRef* args)
{
naRef v, h = naVec_get(args, 0);
naRef v, h = args[0];
if(!naIsHash(h)) return naNil();
v = naNewVector(c);
naHash_keys(v, h);
return v;
}
static naRef append(naContext c, naRef args)
{
naRef v = naVec_get(args, 0);
naRef e = naVec_get(args, 1);
if(!naIsVector(v)) return naNil();
naVec_append(v, e);
return v;
}
static naRef pop(naContext c, naRef args)
{
naRef v = naVec_get(args, 0);
if(!naIsVector(v)) return naNil();
return naVec_removelast(v);
}
static naRef setsize(naContext c, naRef args)
{
naRef v = naVec_get(args, 0);
int sz = (int)naNumValue(naVec_get(args, 1)).num;
if(!naIsVector(v)) return naNil();
naVec_setsize(v, sz);
return v;
}
static naRef subvec(naContext c, naRef args)
static naRef append(naContext c, naRef me, int argc, naRef* args)
{
int i;
naRef nlen, result, v = naVec_get(args, 0);
int len = 0, start = (int)naNumValue(naVec_get(args, 1)).num;
nlen = naNumValue(naVec_get(args, 2));
if(argc < 2) return naNil();
if(!naIsVector(args[0])) return naNil();
for(i=1; i<argc; i++) naVec_append(args[0], args[i]);
return args[0];
}
static naRef pop(naContext c, naRef me, int argc, naRef* args)
{
if(argc < 1 || !naIsVector(args[0])) return naNil();
return naVec_removelast(args[0]);
}
static naRef setsize(naContext c, naRef me, int argc, naRef* args)
{
int sz;
if(argc < 2) return naNil();
sz = (int)naNumValue(args[1]).num;
if(!naIsVector(args[0])) return naNil();
naVec_setsize(args[0], sz);
return args[0];
}
static naRef subvec(naContext c, naRef me, int argc, naRef* args)
{
int i;
naRef nlen, result, v = args[0];
int len = 0, start = (int)naNumValue(args[1]).num;
if(argc < 2) return naNil();
nlen = argc > 2 ? naNumValue(args[2]) : naNil();
if(!naIsNil(nlen))
len = (int)naNumValue(naVec_get(args, 2)).num;
len = (int)nlen.num;
if(!naIsVector(v) || start < 0 || start >= naVec_size(v) || len < 0)
return naNil();
if(len == 0 || len > naVec_size(v) - start) len = naVec_size(v) - start;
@@ -73,51 +77,64 @@ static naRef subvec(naContext c, naRef args)
return result;
}
static naRef delete(naContext c, naRef args)
static naRef delete(naContext c, naRef me, int argc, naRef* args)
{
naRef h = naVec_get(args, 0);
naRef k = naVec_get(args, 1);
if(naIsHash(h)) naHash_delete(h, k);
if(argc > 1 && naIsHash(args[0])) naHash_delete(args[0], args[1]);
return naNil();
}
static naRef intf(naContext c, naRef args)
static naRef intf(naContext c, naRef me, int argc, naRef* args)
{
naRef n = naNumValue(naVec_get(args, 0));
if(!naIsNil(n)) n.num = (int)n.num;
return n;
if(argc > 0) {
naRef n = naNumValue(args[0]);
if(naIsNil(n)) return n;
if(n.num < 0) n.num = -floor(-n.num);
else n.num = floor(n.num);
return n;
} else return naNil();
}
static naRef num(naContext c, naRef args)
static naRef num(naContext c, naRef me, int argc, naRef* args)
{
return naNumValue(naVec_get(args, 0));
return argc > 0 ? naNumValue(args[0]) : naNil();
}
static naRef streq(naContext c, naRef args)
static naRef streq(naContext c, naRef me, int argc, naRef* args)
{
int i;
naRef a = naVec_get(args, 0);
naRef b = naVec_get(args, 1);
if(!naIsString(a) || !naIsString(b)) return naNil();
if(naStr_len(a) != naStr_len(b)) return naNum(0);
for(i=0; i<naStr_len(a); i++)
if(naStr_data(a)[i] != naStr_data(b)[i])
return naNum(0);
return naNum(1);
return argc > 1 ? naNum(naStrEqual(args[0], args[1])) : naNil();
}
static naRef substr(naContext c, naRef args)
static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
{
naRef src = naVec_get(args, 0);
naRef startR = naVec_get(args, 1);
naRef lenR = naVec_get(args, 2);
char *a, *b;
int i, len;
if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1]))
naRuntimeError(c, "bad argument to cmp");
a = naStr_data(args[0]);
b = naStr_data(args[1]);
len = naStr_len(args[0]);
if(naStr_len(args[1]) < len)
len = naStr_len(args[1]);
for(i=0; i<len; i++) {
int diff = a - b;
if(diff < 0) return naNum(-1);
else if(diff > 0) return naNum(1);
}
return naNum(0);
}
static naRef substr(naContext c, naRef me, int argc, naRef* args)
{
naRef src = argc > 1 ? args[0] : naNil();
naRef startR = argc > 1 ? naNumValue(args[1]) : naNil();
naRef lenR = argc > 2 ? naNumValue(args[2]) : naNil();
int start, len;
if(!naIsString(src)) return naNil();
startR = naNumValue(startR);
if(naIsNil(startR)) return naNil();
start = (int)startR.num;
if(naIsNil(lenR)) {
len = naStr_len(src) - start;
if(len < 0) return naNil();
} else {
lenR = naNumValue(lenR);
if(naIsNil(lenR)) return naNil();
@@ -126,18 +143,27 @@ static naRef substr(naContext c, naRef args)
return naStr_substr(naNewString(c), src, start, len);
}
static naRef contains(naContext c, naRef args)
static naRef f_chr(naContext c, naRef me, int argc, naRef* args)
{
naRef hash = naVec_get(args, 0);
naRef key = naVec_get(args, 1);
char chr[1];
naRef cr = argc ? naNumValue(args[0]) : naNil();
if(IS_NIL(cr)) naRuntimeError(c, "chr argument not string");
chr[0] = (char)cr.num;
return NEWSTR(c, chr, 1);
}
static naRef contains(naContext c, naRef me, int argc, naRef* args)
{
naRef hash = argc > 0 ? args[0] : naNil();
naRef key = argc > 1 ? args[1] : naNil();
if(naIsNil(hash) || naIsNil(key)) return naNil();
if(!naIsHash(hash)) return naNil();
return naHash_get(hash, key, &key) ? naNum(1) : naNum(0);
}
static naRef typeOf(naContext c, naRef args)
static naRef typeOf(naContext c, naRef me, int argc, naRef* args)
{
naRef r = naVec_get(args, 0);
naRef r = argc > 0 ? args[0] : naNil();
char* t = "unknown";
if(naIsNil(r)) t = "nil";
else if(naIsNum(r)) t = "scalar";
@@ -146,10 +172,278 @@ static naRef typeOf(naContext c, naRef args)
else if(naIsHash(r)) t = "hash";
else if(naIsFunc(r)) t = "func";
else if(naIsGhost(r)) t = "ghost";
r = naStr_fromdata(naNewString(c), t, StrLen(t));
r = NEWCSTR(c, t);
return r;
}
static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
{
int errLine;
naRef script, code, fname;
script = argc > 0 ? args[0] : naNil();
if(!naIsString(script)) return naNil();
fname = NEWCSTR(c, "<compile>");
code = naParseCode(c, fname, 1,
naStr_data(script), naStr_len(script), &errLine);
if(!naIsCode(code)) return naNil(); // FIXME: export error to caller...
return naBindToContext(c, code);
}
static naRef f_call(naContext c, naRef me, int argc, naRef* args)
{
naContext subc;
naRef callargs, callme, callns, result;
struct VecRec* vr;
callargs = argc > 1 ? args[1] : naNil();
callme = argc > 2 ? args[2] : naNil(); // Might be nil, that's OK
callns = argc > 3 ? args[3] : naNil(); // ditto
if(!IS_HASH(callme)) callme = naNil();
if(!IS_HASH(callns)) callns = naNil();
if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
naRuntimeError(c, "bad argument to call()");
subc = naNewContext();
subc->callParent = c;
c->callChild = subc;
vr = IS_NIL(callargs) ? 0 : callargs.ref.ptr.vec->rec;
result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
callme, callns);
c->callChild = 0;
if(argc > 2 && IS_VEC(args[argc-1])) {
if(!IS_NIL(subc->dieArg)) naVec_append(args[argc-1], subc->dieArg);
else if(naGetError(subc))
naVec_append(args[argc-1], NEWCSTR(subc, naGetError(subc)));
}
naFreeContext(subc);
return result;
}
static naRef f_die(naContext c, naRef me, int argc, naRef* args)
{
c->dieArg = argc > 0 ? args[0] : naNil();
naRuntimeError(c, "__die__");
return naNil(); // never executes
}
// Wrapper around vsnprintf, iteratively increasing the buffer size
// until it fits. Returned buffer should be freed by the caller.
char* dosprintf(char* f, ...)
{
char* buf;
va_list va;
int len = 16;
while(1) {
buf = naAlloc(len);
va_start(va, f);
if(vsnprintf(buf, len, f, va) < len) {
va_end(va);
return buf;
}
va_end(va);
naFree(buf);
len *= 2;
}
}
// Inspects a printf format string f, and finds the next "%..." format
// specifier. Stores the start of the specifier in out, the length in
// len, and the type in type. Returns a pointer to the remainder of
// the format string, or 0 if no format string was found. Recognizes
// all of ANSI C's syntax except for the "length modifier" feature.
// Note: this does not validate the format character returned in
// "type". That is the caller's job.
static char* nextFormat(naContext ctx, char* f, char** out, int* len, char* type)
{
// Skip to the start of the format string
while(*f && *f != '%') f++;
if(!*f) return 0;
*out = f++;
while(*f && (*f=='-' || *f=='+' || *f==' ' || *f=='0' || *f=='#')) f++;
// Test for duplicate flags. This is pure pedantry and could
// be removed on all known platforms, but just to be safe...
{ char *p1, *p2;
for(p1 = *out + 1; p1 < f; p1++)
for(p2 = p1+1; p2 < f; p2++)
if(*p1 == *p2)
naRuntimeError(ctx, "duplicate flag in format string"); }
while(*f && *f >= '0' && *f <= '9') f++;
if(*f && *f == '.') f++;
while(*f && *f >= '0' && *f <= '9') f++;
if(!*f) naRuntimeError(ctx, "invalid format string");
*type = *f++;
*len = f - *out;
return f;
}
#define ERR(m) naRuntimeError(ctx, m)
#define APPEND(r) result = naStr_concat(naNewString(ctx), result, r)
static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
{
char t, nultmp, *fstr, *next, *fout=0, *s;
int flen, argn=1;
naRef format, arg, result = naNewString(ctx);
if(argc < 1) ERR("not enough arguments to sprintf");
format = naStringValue(ctx, argc > 0 ? args[0] : naNil());
if(naIsNil(format)) ERR("bad format string in sprintf");
s = naStr_data(format);
while((next = nextFormat(ctx, s, &fstr, &flen, &t))) {
APPEND(NEWSTR(ctx, s, fstr-s)); // stuff before the format string
if(flen == 2 && fstr[1] == '%') {
APPEND(NEWSTR(ctx, "%", 1));
s = next;
continue;
}
if(argn >= argc) ERR("not enough arguments to sprintf");
arg = args[argn++];
nultmp = fstr[flen]; // sneaky nul termination...
fstr[flen] = 0;
if(t == 's') {
arg = naStringValue(ctx, arg);
if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
else fout = dosprintf(fstr, naStr_data(arg));
} else {
arg = naNumValue(arg);
if(naIsNil(arg))
fout = dosprintf(fstr, "nil");
else if(t=='d' || t=='i' || t=='c')
fout = dosprintf(fstr, (int)naNumValue(arg).num);
else if(t=='o' || t=='u' || t=='x' || t=='X')
fout = dosprintf(fstr, (unsigned int)naNumValue(arg).num);
else if(t=='e' || t=='E' || t=='f' || t=='F' || t=='g' || t=='G')
fout = dosprintf(fstr, naNumValue(arg).num);
else
ERR("invalid sprintf format type");
}
fstr[flen] = nultmp;
APPEND(NEWSTR(ctx, fout, strlen(fout)));
naFree(fout);
s = next;
}
APPEND(NEWSTR(ctx, s, strlen(s)));
return result;
}
// FIXME: handle ctx->callParent frames too!
static naRef f_caller(naContext ctx, naRef me, int argc, naRef* args)
{
int fidx;
struct Frame* frame;
naRef result, fr = argc ? naNumValue(args[0]) : naNum(1);
if(IS_NIL(fr)) naRuntimeError(ctx, "non numeric argument to caller()");
fidx = (int)fr.num;
if(fidx > ctx->fTop - 1) return naNil();
frame = &ctx->fStack[ctx->fTop - 1 - fidx];
result = naNewVector(ctx);
naVec_append(result, frame->locals);
naVec_append(result, frame->func);
naVec_append(result, frame->func.ref.ptr.func->code.ref.ptr.code->srcFile);
naVec_append(result, naNum(naGetLine(ctx, fidx)));
return result;
}
static naRef f_closure(naContext ctx, naRef me, int argc, naRef* args)
{
int i;
naRef func, idx;
struct naFunc* f;
func = argc > 0 ? args[0] : naNil();
idx = argc > 1 ? naNumValue(args[1]) : naNil();
if(!IS_FUNC(func) || IS_NIL(idx))
naRuntimeError(ctx, "bad arguments to closure()");
i = (int)idx.num;
f = func.ref.ptr.func;
while(i > 0 && f) { i--; f = f->next.ref.ptr.func; }
if(!f) return naNil();
return f->namespace;
}
static int match(unsigned char* a, unsigned char* b, int l)
{
int i;
for(i=0; i<l; i++) if(a[i] != b[i]) return 0;
return 1;
}
static int find(unsigned char* a, int al, unsigned char* s, int sl, int start)
{
int i;
if(al == 0) return 0;
for(i=start; i<sl-al+1; i++) if(match(a, s+i, al)) return i;
return -1;
}
static naRef f_find(naContext ctx, naRef me, int argc, naRef* args)
{
int start = 0;
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
naRuntimeError(ctx, "bad/missing argument to find");
if(argc > 2) start = (int)(naNumValue(args[2]).num);
return naNum(find(args[0].ref.ptr.str->data, args[0].ref.ptr.str->len,
args[1].ref.ptr.str->data, args[1].ref.ptr.str->len,
start));
}
static naRef f_split(naContext ctx, naRef me, int argc, naRef* args)
{
int sl, dl, i;
char *s, *d, *s0;
naRef result;
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
naRuntimeError(ctx, "bad/missing argument to split");
d = naStr_data(args[0]); dl = naStr_len(args[0]);
s = naStr_data(args[1]); sl = naStr_len(args[1]);
result = naNewVector(ctx);
if(dl == 0) { // special case zero-length delimiter
for(i=0; i<sl; i++) naVec_append(result, NEWSTR(ctx, s+i, 1));
return result;
}
s0 = s;
for(i=0; i <= sl-dl; i++) {
if(match((unsigned char*)(s+i), (unsigned char*)d, dl)) {
naVec_append(result, NEWSTR(ctx, s0, s+i-s0));
s0 = s + i + dl;
i += dl - 1;
}
}
if(s0 - s <= sl) naVec_append(result, NEWSTR(ctx, s0, s+sl-s0));
return result;
}
// This is a comparatively weak RNG, based on the C library's rand()
// function, which is usually not threadsafe and often of limited
// precision. The 5x loop guarantees that we get a full double worth
// of precision even for 15 bit (Win32...) rand() implementations.
static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args)
{
int i;
double r = 0;
if(argc) {
if(!IS_NUM(args[0])) naRuntimeError(ctx, "rand() seed not number");
srand((unsigned int)args[0].num);
return naNil();
}
for(i=0; i<5; i++) r = (r + rand()) * (1.0/(RAND_MAX+1.0));
return naNum(r);
}
static naRef f_bind(naContext ctx, naRef me, int argc, naRef* args)
{
naRef func = argc > 0 ? args[0] : naNil();
naRef hash = argc > 1 ? args[1] : naNewHash(ctx);
naRef next = argc > 2 ? args[2] : naNil();
if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash))
naRuntimeError(ctx, "bad argument to bind");
func = naNewFunc(ctx, func.ref.ptr.func->code);
func.ref.ptr.func->namespace = hash;
func.ref.ptr.func->next = next;
return func;
}
struct func { char* name; naCFunction func; };
static struct func funcs[] = {
{ "size", size },
@@ -162,9 +456,21 @@ static struct func funcs[] = {
{ "int", intf },
{ "num", num },
{ "streq", streq },
{ "cmp", f_cmp },
{ "substr", substr },
{ "chr", f_chr },
{ "contains", contains },
{ "typeof", typeOf },
{ "compile", f_compile },
{ "call", f_call },
{ "die", f_die },
{ "sprintf", f_sprintf },
{ "caller", f_caller },
{ "closure", f_closure },
{ "find", f_find },
{ "split", f_split },
{ "rand", f_rand },
{ "bind", f_bind },
};
naRef naStdLib(naContext c)
@@ -173,8 +479,8 @@ naRef naStdLib(naContext c)
int i, n = sizeof(funcs)/sizeof(struct func);
for(i=0; i<n; i++) {
naRef code = naNewCCode(c, funcs[i].func);
naRef name = naStr_fromdata(naNewString(c),
funcs[i].name, StrLen(funcs[i].name));
naRef name = NEWSTR(c, funcs[i].name, strlen(funcs[i].name));
name = naInternSymbol(name);
naHash_set(namespace, name, naNewFunc(c, code));
}
return namespace;
+18 -16
View File
@@ -7,55 +7,55 @@
#include "nasal.h"
static naRef f_sin(naContext c, naRef args)
static naRef f_sin(naContext c, naRef me, int argc, naRef* args)
{
naRef a = naNumValue(naVec_get(args, 0));
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
if(naIsNil(a))
naRuntimeError(c, "non numeric argument to sin()");
a.num = sin(a.num);
return a;
}
static naRef f_cos(naContext c, naRef args)
static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
{
naRef a = naNumValue(naVec_get(args, 0));
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
if(naIsNil(a))
naRuntimeError(c, "non numeric argument to cos()");
a.num = cos(a.num);
return a;
}
static naRef f_exp(naContext c, naRef args)
static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
{
naRef a = naNumValue(naVec_get(args, 0));
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
if(naIsNil(a))
naRuntimeError(c, "non numeric argument to exp()");
a.num = exp(a.num);
return a;
}
static naRef f_ln(naContext c, naRef args)
static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
{
naRef a = naNumValue(naVec_get(args, 0));
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
if(naIsNil(a))
naRuntimeError(c, "non numeric argument to ln()");
a.num = log(a.num);
return a;
}
static naRef f_sqrt(naContext c, naRef args)
static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
{
naRef a = naNumValue(naVec_get(args, 0));
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
if(naIsNil(a))
naRuntimeError(c, "non numeric argument to sqrt()");
a.num = sqrt(a.num);
return a;
}
static naRef f_atan2(naContext c, naRef args)
static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
{
naRef a = naNumValue(naVec_get(args, 0));
naRef b = naNumValue(naVec_get(args, 1));
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
naRef b = naNumValue(argc > 1 ? args[1] : naNil());
if(naIsNil(a) || naIsNil(b))
naRuntimeError(c, "non numeric argument to atan2()");
a.num = atan2(a.num, b.num);
@@ -82,12 +82,14 @@ naRef naMathLib(naContext c)
naHash_set(namespace, name, naNewFunc(c, code));
}
// Set up constants for math.pi and math.e
// Set up constants for math.pi and math.e. Can't use M_PI or
// M_E, becuase those aren't technically part of the C standard. Sigh.
name = naStr_fromdata(naNewString(c), "pi", 2);
naHash_set(namespace, name, naNum(M_PI));
naHash_set(namespace, name, naNum(3.14159265358979323846));
name = naStr_fromdata(naNewString(c), "e", 1);
naHash_set(namespace, name, naNum(M_E));
name = naInternSymbol(name);
naHash_set(namespace, name, naNum(2.7182818284590452354));
return namespace;
}
+51 -63
View File
@@ -7,8 +7,25 @@
void naFree(void* m) { free(m); }
void* naAlloc(int n) { return malloc(n); }
void* naRealloc(void* b, int n) { return realloc(b, n); }
void naBZero(void* m, int n) { memset(m, 0, n); }
void naTempSave(naContext c, naRef r)
{
int i;
if(!IS_OBJ(r)) return;
if(c->ntemps >= c->tempsz) {
struct naObj** newtemps;
c->tempsz *= 2;
newtemps = naAlloc(c->tempsz * sizeof(struct naObj*));
for(i=0; i<c->ntemps; i++)
newtemps[i] = c->temps[i];
naFree(c->temps);
c->temps = newtemps;
}
c->temps[c->ntemps++] = r.ref.ptr.obj;
}
naRef naObj(int type, struct naObj* o)
{
naRef r;
@@ -49,8 +66,12 @@ naRef naStringValue(naContext c, naRef r)
naRef naNew(struct Context* c, int type)
{
naRef result = naObj(type, naGC_get(&(c->pools[type])));
naVec_append(c->temps, result);
naRef result;
if(c->nfree[type] == 0)
c->free[type] = naGC_get(&globals->pools[type],
OBJ_CACHE_SZ, &c->nfree[type]);
result = naObj(type, c->free[type][--c->nfree[type]]);
naTempSave(c, result);
return result;
}
@@ -59,20 +80,21 @@ naRef naNewString(struct Context* c)
naRef s = naNew(c, T_STR);
s.ref.ptr.str->len = 0;
s.ref.ptr.str->data = 0;
s.ref.ptr.str->hashcode = 0;
return s;
}
naRef naNewVector(struct Context* c)
{
naRef r = naNew(c, T_VEC);
naVec_init(r);
r.ref.ptr.vec->rec = 0;
return r;
}
naRef naNewHash(struct Context* c)
{
naRef r = naNew(c, T_HASH);
naHash_init(r);
r.ref.ptr.hash->rec = 0;
return r;
}
@@ -92,18 +114,11 @@ naRef naNewFunc(struct Context* c, naRef code)
{
naRef func = naNew(c, T_FUNC);
func.ref.ptr.func->code = code;
func.ref.ptr.func->closure = naNil();
func.ref.ptr.func->namespace = naNil();
func.ref.ptr.func->next = naNil();
return func;
}
naRef naNewClosure(struct Context* c, naRef namespace, naRef next)
{
naRef closure = naNew(c, T_CLOSURE);
closure.ref.ptr.closure->namespace = namespace;
closure.ref.ptr.closure->next = next;
return closure;
}
naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
{
naRef ghost = naNew(c, T_GHOST);
@@ -162,6 +177,19 @@ int naEqual(naRef a, naRef b)
return na == nb ? 1 : 0;
}
int naStrEqual(naRef a, naRef b)
{
int i;
if(!(IS_STR(a) && IS_STR(b)))
return 0;
if(a.ref.ptr.str->len != b.ref.ptr.str->len)
return 0;
for(i=0; i<a.ref.ptr.str->len; i++)
if(a.ref.ptr.str->data[i] != b.ref.ptr.str->data[i])
return 0;
return 1;
}
int naTypeSize(int type)
{
switch(type) {
@@ -170,59 +198,19 @@ int naTypeSize(int type)
case T_HASH: return sizeof(struct naHash);
case T_CODE: return sizeof(struct naCode);
case T_FUNC: return sizeof(struct naFunc);
case T_CLOSURE: return sizeof(struct naClosure);
case T_CCODE: return sizeof(struct naCCode);
case T_GHOST: return sizeof(struct naGhost);
};
return 0x7fffffff; // Make sure the answer is nonsense :)
}
int naIsNil(naRef r)
{
return IS_NIL(r);
}
int naIsNum(naRef r)
{
return IS_NUM(r);
}
int naIsString(naRef r)
{
return (!IS_NIL(r))&&IS_STR(r);
}
int naIsScalar(naRef r)
{
return IS_SCALAR(r);
}
int naIsVector(naRef r)
{
return (!IS_NIL(r))&&IS_VEC(r);
}
int naIsHash(naRef r)
{
return (!IS_NIL(r))&&IS_HASH(r);
}
int naIsFunc(naRef r)
{
return (!IS_NIL(r))&&IS_FUNC(r);
}
int naIsCode(naRef r)
{
return IS_CODE(r);
}
int naIsCCode(naRef r)
{
return IS_CCODE(r);
}
int naIsGhost(naRef r)
{
return IS_GHOST(r);
}
int naIsNil(naRef r) { return IS_NIL(r); }
int naIsNum(naRef r) { return IS_NUM(r); }
int naIsString(naRef r) { return IS_STR(r); }
int naIsScalar(naRef r) { return IS_SCALAR(r); }
int naIsVector(naRef r) { return IS_VEC(r); }
int naIsHash(naRef r) { return IS_HASH(r); }
int naIsFunc(naRef r) { return IS_FUNC(r); }
int naIsCode(naRef r) { return IS_CODE(r); }
int naIsCCode(naRef r) { return IS_CCODE(r); }
int naIsGhost(naRef r) { return IS_GHOST(r); }
+33 -4
View File
@@ -62,7 +62,6 @@ typedef union {
struct naHash* hash;
struct naCode* code;
struct naFunc* func;
struct naClosure* closure;
struct naCCode* ccode;
struct naGhost* ghost;
} ptr;
@@ -75,15 +74,21 @@ typedef union {
typedef struct Context* naContext;
// The function signature for an extension function:
typedef naRef (*naCFunction)(naContext ctx, naRef args);
typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args);
// All Nasal code runs under the watch of a naContext:
naContext naNewContext();
void naFreeContext(naContext c);
// Save this object in the context, preventing it (and objects
// referenced by it) from being garbage collected.
void naSave(naContext ctx, naRef obj);
// Similar, but the object is automatically released when the
// context next runs native bytecode. Useful for saving off C-space
// temporaries to protect them before passing back into a naCall.
void naTempSave(naContext c, naRef r);
// Parse a buffer in memory into a code object.
naRef naParseCode(naContext c, naRef srcFile, int firstLine,
char* buf, int len, int* errLine);
@@ -95,10 +100,14 @@ naRef naParseCode(naContext c, naRef srcFile, int firstLine,
// information from function objects.
naRef naBindFunction(naContext ctx, naRef code, naRef closure);
// Similar, but it binds to the current context's closure (i.e. the
// namespace at the top of the current call stack).
naRef naBindToContext(naContext ctx, naRef code);
// Call a code or function object with the specifed arguments "on" the
// specified object and using the specified hash for the local
// variables. Any of args, obj or locals may be nil.
naRef naCall(naContext ctx, naRef func, naRef args, naRef obj, naRef locals);
naRef naCall(naContext ctx, naRef func, int argc, naRef* args, naRef obj, naRef locals);
// Throw an error from the current call stack. This function makes a
// longjmp call to a handler in naCall() and DOES NOT RETURN. It is
@@ -115,8 +124,12 @@ naRef naMethod(naContext ctx, naRef func, naRef object);
// Useful for passing as a namespace to an initial function call
naRef naStdLib(naContext c);
// Ditto, with math functions
// Ditto, for other core libraries
naRef naMathLib(naContext c);
naRef naBitsLib(naContext c);
naRef naIOLib(naContext c);
naRef naRegexLib(naContext c);
naRef naUnixLib(naContext c);
// Current line number & error message
int naStackDepth(naContext ctx);
@@ -146,6 +159,7 @@ naRef naNewCCode(naContext c, naCFunction fptr);
// Some useful conversion/comparison routines
int naEqual(naRef a, naRef b);
int naStrEqual(naRef a, naRef b);
int naTrue(naRef b);
naRef naNumValue(naRef n);
naRef naStringValue(naContext c, naRef n);
@@ -156,6 +170,7 @@ char* naStr_data(naRef s);
naRef naStr_fromdata(naRef dst, char* data, int len);
naRef naStr_concat(naRef dest, naRef s1, naRef s2);
naRef naStr_substr(naRef dest, naRef str, int start, int len);
naRef naInternSymbol(naRef sym);
// Vector utilities:
int naVec_size(naRef v);
@@ -183,6 +198,20 @@ naGhostType* naGhost_type(naRef ghost);
void* naGhost_ptr(naRef ghost);
int naIsGhost(naRef r);
// Acquires a "modification lock" on a context, allowing the C code to
// modify Nasal data without fear that such data may be "lost" by the
// garbage collector (the C stack is not examined in GC!). This
// disallows garbage collection until the current thread can be
// blocked. The lock should be acquired whenever modifications to
// Nasal objects are made. It need not be acquired when only read
// access is needed. It MUST NOT be acquired by naCFunction's, as
// those are called with the lock already held; acquiring two locks
// for the same thread will cause a deadlock when the GC is invoked.
// It should be UNLOCKED by naCFunction's when they are about to do
// any long term non-nasal processing and/or blocking I/O.
void naModLock();
void naModUnlock();
#ifdef __cplusplus
} // extern "C"
#endif
+24 -11
View File
@@ -6,20 +6,23 @@
// (tight binding, do last).
enum { PREC_BINARY, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
#define MAX_PREC_TOKS 5
#define MAX_PREC_TOKS 6
struct precedence {
int toks[MAX_PREC_TOKS];
int rule;
} PRECEDENCE[] = {
{ { TOK_SEMI, TOK_COMMA }, PREC_REVERSE },
{ { TOK_COLON }, PREC_BINARY },
{ { TOK_ELLIPSIS }, PREC_SUFFIX },
{ { TOK_RETURN, TOK_BREAK, TOK_CONTINUE }, PREC_PREFIX },
{ { TOK_ASSIGN }, PREC_REVERSE },
{ { TOK_ASSIGN, TOK_PLUSEQ, TOK_MINUSEQ,
TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ }, PREC_REVERSE },
{ { TOK_COLON, TOK_QUESTION }, PREC_REVERSE },
{ { TOK_VAR }, PREC_PREFIX },
{ { TOK_OR }, PREC_BINARY },
{ { TOK_AND }, PREC_BINARY },
{ { TOK_EQ, TOK_NEQ }, PREC_BINARY },
{ { TOK_LT, TOK_LTE, TOK_GT, TOK_GTE }, PREC_BINARY },
{ { TOK_PLUS, TOK_MINUS, TOK_CAT }, PREC_REVERSE },
{ { TOK_PLUS, TOK_MINUS, TOK_CAT }, PREC_BINARY },
{ { TOK_MUL, TOK_DIV }, PREC_BINARY },
{ { TOK_MINUS, TOK_NEG, TOK_NOT }, PREC_PREFIX },
{ { TOK_LPAR, TOK_LBRA }, PREC_SUFFIX },
@@ -210,14 +213,22 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
t = start;
while(t) {
switch(t->type) {
case TOK_ELSE: case TOK_FUNC:
case TOK_FUNC:
// Slurp an optional paren block containing an arglist, then
// fall through to parse the curlies...
if(t->next && t->next->type == TOK_LPAR) {
c = t->next;
addNewChild(t, c);
fixBlockStructure(p, c);
}
case TOK_ELSE: // and TOK_FUNC!
// These guys precede a single curly block
if(!t->next || t->next->type != TOK_LCURL) oops(p, t);
c = t->next;
addNewChild(t, c);
fixBlockStructure(p, c);
break;
case TOK_FOR: case TOK_FOREACH: case TOK_WHILE:
case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
case TOK_IF: case TOK_ELSIF:
// Expect a paren and then a curly
if(!t->next || t->next->type != TOK_LPAR) oops(p, t);
@@ -268,7 +279,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
|| t->prev->type == TOK_LCURL)
addSemi = 1;
break;
case TOK_FOR: case TOK_FOREACH: case TOK_WHILE:
case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
addSemi = 1;
break;
case TOK_FUNC:
@@ -276,6 +287,8 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
addSemi = 1;
break;
}
if(t->next && t->next->type == TOK_SEMI)
addSemi = 0; // don't bother if it's already there!
if(addSemi) {
struct Token* semi = emptyToken(p);
semi->type = TOK_SEMI;
@@ -311,7 +324,7 @@ static int isBlock(int t)
{
return t == TOK_IF || t == TOK_ELSIF || t == TOK_ELSE
|| t == TOK_FOR || t == TOK_FOREACH || t == TOK_WHILE
|| t == TOK_FUNC;
|| t == TOK_FUNC || t == TOK_FORINDEX;
}
static void precChildren(struct Parser* p, struct Token* t);
@@ -490,7 +503,7 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
struct Parser p;
// Protect from garbage collection
naVec_append(c->temps, srcFile);
naTempSave(c, srcFile);
// Catch parser errors here.
*errLine = 0;
@@ -519,11 +532,11 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
p.tree.lastChild = t;
// Generate code!
codeObj = naCodeGen(&p, &(p.tree));
codeObj = naCodeGen(&p, &(p.tree), 0);
// Clean up our mess
naParseDestroy(&p);
naVec_append(c->temps, codeObj);
naTempSave(c, codeObj);
return codeObj;
}
+13 -8
View File
@@ -14,7 +14,9 @@ enum {
TOK_ASSIGN, TOK_LT, TOK_LTE, TOK_EQ, TOK_NEQ, TOK_GT, TOK_GTE,
TOK_IF, TOK_ELSIF, TOK_ELSE, TOK_FOR, TOK_FOREACH, TOK_WHILE,
TOK_RETURN, TOK_BREAK, TOK_CONTINUE, TOK_FUNC, TOK_SYMBOL,
TOK_LITERAL, TOK_EMPTY, TOK_NIL
TOK_LITERAL, TOK_EMPTY, TOK_NIL, TOK_ELLIPSIS, TOK_QUESTION, TOK_VAR,
TOK_PLUSEQ, TOK_MINUSEQ, TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ,
TOK_FORINDEX
};
struct Token {
@@ -58,7 +60,7 @@ struct Parser {
// Computed line number table for the lexer
int* lines;
int nLines;
struct CodeGenerator* cg;
};
@@ -66,10 +68,15 @@ struct CodeGenerator {
int lastLine;
// Accumulated byte code array
unsigned char* byteCode;
int nBytes;
unsigned short* byteCode;
int codesz;
int codeAlloced;
// Inst. -> line table, stores pairs of {ip, line}
unsigned short* lineIps;
int nLineIps; // number of pairs
int nextLineIp;
// Stack of "loop" frames for break/continue statements
struct {
int breakIP;
@@ -79,9 +86,7 @@ struct CodeGenerator {
int loopTop;
// Dynamic storage for constants, to be compiled into a static table
naRef consts; // index -> naRef
naRef interned; // naRef -> index (scalars only!)
int nConsts;
naRef consts;
};
void naParseError(struct Parser* p, char* msg, int line);
@@ -89,7 +94,7 @@ void naParseInit(struct Parser* p);
void* naParseAlloc(struct Parser* p, int bytes);
void naParseDestroy(struct Parser* p);
void naLex(struct Parser* p);
naRef naCodeGen(struct Parser* p, struct Token* tok);
naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist);
void naParse(struct Parser* p);
+45 -30
View File
@@ -8,11 +8,6 @@
// double.
#define DIGITS 16
// The minimum size we'll allocate for a string. Since a string
// structure is already 12 bytes, and each naRef that points to it is
// 8, there isn't much point in being stingy.
#define MINLEN 16
static int tonum(unsigned char* s, int len, double* result);
static int fromnum(double val, unsigned char* s);
@@ -25,21 +20,22 @@ int naStr_len(naRef s)
char* naStr_data(naRef s)
{
if(!IS_STR(s)) return 0;
return s.ref.ptr.str->data;
return (char*)s.ref.ptr.str->data;
}
static void setlen(struct naStr* s, int sz)
{
int currSz, waste;
sz += 1; // Allow for an extra nul terminator
currSz = s->len+1 < MINLEN ? MINLEN : s->len+1;
waste = currSz - sz; // how much extra if we don't reallocate?
if(s->data == 0 || waste < 0 || waste > MINLEN) {
naFree(s->data);
s->data = naAlloc(sz < MINLEN ? MINLEN : sz);
}
s->len = sz - 1;
s->data[s->len] = 0; // nul terminate
if(s->data) naFree(s->data);
s->len = sz;
s->data = naAlloc(sz+1);
s->data[sz] = 0; // nul terminate
}
naRef naStr_buf(naRef dst, int len)
{
setlen(dst.ref.ptr.str, len);
naBZero(dst.ref.ptr.str->data, len);
return dst;
}
naRef naStr_fromdata(naRef dst, char* data, int len)
@@ -94,7 +90,7 @@ naRef naStr_fromnum(naRef dest, double num)
int naStr_parsenum(char* str, int len, double* result)
{
return tonum(str, len, result);
return tonum((unsigned char*)str, len, result);
}
int naStr_tonum(naRef str, double* out)
@@ -110,10 +106,8 @@ int naStr_numeric(naRef str)
void naStr_gcclean(struct naStr* str)
{
if(str->len > MINLEN) {
naFree(str->data);
str->data = 0;
}
naFree(str->data);
str->data = 0;
str->len = 0;
}
@@ -147,17 +141,21 @@ static int readdec(unsigned char* s, int len, int i, double* v)
// Reads a signed integer out of the string starting at i, stores it
// in v, and returns the next index to start at. Zero-length
// decimal numbers (and length-1 strings like '+') are allowed, and
// are returned as zero.
// decimal numbers are allowed, and are returned as zero.
static int readsigned(unsigned char* s, int len, int i, double* v)
{
int i0 = i, i2;
double sgn=1, val;
if(i >= len) { *v = 0; return len; }
if(s[i] == '+') { i++; }
else if(s[i] == '-') { i++; sgn = -1; }
i = readdec(s, len, i, &val);
i2 = readdec(s, len, i, &val);
if(i0 == i && i2 == i) {
*v = 0;
return i0; // don't successfully parse bare "+" or "-"
}
*v = sgn*val;
return i;
return i2;
}
@@ -180,6 +178,17 @@ static int tonum(unsigned char* s, int len, double* result)
int i=0, fraclen=0;
double sgn=1, val, frac=0, exp=0;
// Special case, "." is not a number, even though "1." and ".0" are.
if(len == 1 && s[0] == '.')
return 0;
// Strip off the leading negative sign first, so we can correctly
// parse things like -.xxx which would otherwise confuse
// readsigned.
if(len > 1 && s[0] == '-' && s[1] != '-') {
sgn = -1; s++; len--;
}
// Read the integer part
i = readsigned(s, len, i, &val);
if(val < 0) { sgn = -1; val = -val; }
@@ -191,9 +200,15 @@ static int tonum(unsigned char* s, int len, double* result)
i += fraclen;
}
// Nothing so far? Then the parse failed.
if(i == 0) return 0;
// Read the exponent, if any
if(i < len && (s[i] == 'e' || s[i] == 'E'))
if(i < len && (s[i] == 'e' || s[i] == 'E')) {
int i0 = i+1;
i = readsigned(s, len, i+1, &exp);
if(i == i0) return 0; // Must have a number after the "e"
}
// compute the result
*result = sgn * (val + frac * decpow(-fraclen)) * decpow(exp);
@@ -205,13 +220,13 @@ static int tonum(unsigned char* s, int len, double* result)
// Very simple positive (!) integer print routine. Puts the result in
// s and returns the number of characters written. Does not null
// terminate the result.
// terminate the result. Presumes at least a 32 bit integer, and
// cannot print integers larger than 9999999999.
static int decprint(int val, unsigned char* s)
{
int p=1, i=0;
if(val == 0) { *s = '0'; return 1; }
while(p <= val) p *= 10;
p /= 10;
while(p <= 999999999 && p*10 <= val) p *= 10;
while(p > 0) {
int count = 0;
while(val >= p) { val -= p; count++; }
@@ -270,7 +285,7 @@ static int fromnum(double val, unsigned char* s)
if(raw[i] != '0') break;
digs = i+1;
if(exp > 0 || exp < -(DIGITS+2)) {
if(exp > 0 || exp < -(DIGITS+3)) {
// Standard scientific notation
exp += DIGITS-1;
*ptr++ = raw[0];
+59
View File
@@ -0,0 +1,59 @@
#ifndef _WIN32
#include <pthread.h>
#include "code.h"
void* naNewLock()
{
pthread_mutex_t* lock = naAlloc(sizeof(pthread_mutex_t));
pthread_mutex_init(lock, 0);
return lock;
}
void naLock(void* lock)
{
pthread_mutex_lock((pthread_mutex_t*)lock);
}
void naUnlock(void* lock)
{
pthread_mutex_unlock((pthread_mutex_t*)lock);
}
struct naSem {
pthread_mutex_t lock;
pthread_cond_t cvar;
int count;
};
void* naNewSem()
{
struct naSem* sem = naAlloc(sizeof(struct naSem));
pthread_mutex_init(&sem->lock , 0);
pthread_cond_init(&sem->cvar, 0);
sem->count = 0;
return sem;
}
void naSemDown(void* sh)
{
struct naSem* sem = (struct naSem*)sh;
pthread_mutex_lock(&sem->lock);
while(sem->count <= 0)
pthread_cond_wait(&sem->cvar, &sem->lock);
sem->count--;
pthread_mutex_unlock(&sem->lock);
}
void naSemUpAll(void* sh, int count)
{
struct naSem* sem = (struct naSem*)sh;
pthread_mutex_lock(&sem->lock);
sem->count = count;
pthread_cond_broadcast(&sem->cvar);
pthread_mutex_unlock(&sem->lock);
}
#endif
extern int GccWarningWorkaround_IsoCForbidsAnEmptySourceFile;
+22
View File
@@ -0,0 +1,22 @@
#ifdef _WIN32
#include <windows.h>
#define MAX_SEM_COUNT 1024 // What are the tradeoffs with this value?
void* naNewLock()
{
LPCRITICAL_SECTION lock = malloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSection(lock);
return lock;
}
void naLock(void* lock) { EnterCriticalSection((LPCRITICAL_SECTION)lock); }
void naUnlock(void* lock) { LeaveCriticalSection((LPCRITICAL_SECTION)lock); }
void* naNewSem() { return CreateSemaphore(0, 0, MAX_SEM_COUNT, 0); }
void naSemDown(void* sem) { WaitForSingleObject((HANDLE)sem, INFINITE); }
void naSemUpAll(void* sem, int count) { ReleaseSemaphore(sem, count, 0); }
#endif
extern int GccWarningWorkaround_IsoCForbidsAnEmptySourceFile;
+59 -45
View File
@@ -1,84 +1,98 @@
#include "nasal.h"
#include "data.h"
static void realloc(struct naVec* v)
static struct VecRec* newvecrec(struct VecRec* old)
{
int i, newsz = 1 + ((v->size*3)>>1);
naRef* na = naAlloc(sizeof(naRef) * newsz);
v->alloced = newsz;
for(i=0; i<v->size; i++)
na[i] = v->array[i];
naFree(v->array);
v->array = na;
int i, oldsz = old ? old->size : 0, newsz = 1 + ((oldsz*3)>>1);
struct VecRec* vr = naAlloc(sizeof(struct VecRec) + sizeof(naRef) * newsz);
if(oldsz > newsz) oldsz = newsz; // race protection
vr->alloced = newsz;
vr->size = oldsz;
for(i=0; i<oldsz; i++)
vr->array[i] = old->array[i];
return vr;
}
void naVec_init(naRef vec)
static void realloc(struct naVec* v)
{
struct naVec* v = vec.ref.ptr.vec;
v->array = 0;
v->size = 0;
v->alloced = 0;
struct VecRec* vr = newvecrec(v->rec);
naGC_swapfree((void**)&(v->rec), vr);
}
void naVec_gcclean(struct naVec* v)
{
naFree(v->array);
v->size = 0;
v->alloced = 0;
v->array = 0;
naFree(v->rec);
v->rec = 0;
}
naRef naVec_get(naRef v, int i)
{
if(!IS_VEC(v)) return naNil();
if(i >= v.ref.ptr.vec->size) return naNil();
return v.ref.ptr.vec->array[i];
if(IS_VEC(v)) {
struct VecRec* r = v.ref.ptr.vec->rec;
if(r) {
if(i < 0) i += r->size;
if(i >= 0 && i < r->size) return r->array[i];
}
}
return naNil();
}
void naVec_set(naRef vec, int i, naRef o)
{
struct naVec* v = vec.ref.ptr.vec;
if(!IS_VEC(vec) || i >= v->size) return;
v->array[i] = o;
if(IS_VEC(vec)) {
struct VecRec* r = vec.ref.ptr.vec->rec;
if(r && i >= r->size) return;
r->array[i] = o;
}
}
int naVec_size(naRef v)
{
if(!IS_VEC(v)) return 0;
return v.ref.ptr.vec->size;
if(IS_VEC(v)) {
struct VecRec* r = v.ref.ptr.vec->rec;
return r ? r->size : 0;
}
return 0;
}
int naVec_append(naRef vec, naRef o)
{
struct naVec* v = vec.ref.ptr.vec;
if(!IS_VEC(vec)) return 0;
if(v->size >= v->alloced)
realloc(v);
v->array[v->size] = o;
return v->size++;
if(IS_VEC(vec)) {
struct VecRec* r = vec.ref.ptr.vec->rec;
while(!r || r->size >= r->alloced) {
realloc(vec.ref.ptr.vec);
r = vec.ref.ptr.vec->rec;
}
r->array[r->size] = o;
return r->size++;
}
return 0;
}
void naVec_setsize(naRef vec, int sz)
{
int i;
struct naVec* v = vec.ref.ptr.vec;
naRef* na = naAlloc(sizeof(naRef) * sz);
struct VecRec* v = vec.ref.ptr.vec->rec;
struct VecRec* nv = naAlloc(sizeof(struct VecRec) + sizeof(naRef) * sz);
nv->size = sz;
nv->alloced = sz;
for(i=0; i<sz; i++)
na[i] = (i < v->size) ? v->array[i] : naNil();
naFree(v->array);
v->array = na;
v->size = sz;
v->alloced = sz;
nv->array[i] = (v && i < v->size) ? v->array[i] : naNil();
naFree(v);
vec.ref.ptr.vec->rec = nv;
}
naRef naVec_removelast(naRef vec)
{
naRef o;
struct naVec* v = vec.ref.ptr.vec;
if(!IS_VEC(vec) || v->size == 0) return naNil();
o = v->array[v->size - 1];
v->size--;
if(v->size < (v->alloced >> 1))
realloc(v);
return o;
if(IS_VEC(vec)) {
struct VecRec* v = vec.ref.ptr.vec->rec;
if(!v || v->size == 0) return naNil();
o = v->array[v->size - 1];
v->size--;
if(v->size < (v->alloced >> 1))
realloc(vec.ref.ptr.vec);
return o;
}
return naNil();
}
+99 -36
View File
@@ -275,7 +275,7 @@ find_node (SGPropertyNode * current,
// Success! This is the one we want.
else if (position >= (int)components.size()) {
return current;
return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
}
// Empty component means root.
@@ -471,7 +471,7 @@ SGPropertyNode::set_string (const char * val)
}
void
SGPropertyNode::clear_value ()
SGPropertyNode::clearValue ()
{
switch (_type) {
case NONE:
@@ -762,7 +762,7 @@ SGPropertyNode::~SGPropertyNode ()
delete [] _display_name;
delete [] _path;
delete _path_cache;
clear_value();
clearValue();
delete _listeners;
}
@@ -775,7 +775,7 @@ SGPropertyNode::alias (SGPropertyNode * target)
{
if (target == 0 || _type == ALIAS || _tied)
return false;
clear_value();
clearValue();
_value.alias = target;
_type = ALIAS;
return true;
@@ -911,6 +911,32 @@ SGPropertyNode::getChildren (const char * name) const
}
/**
* Remove child by position.
*/
SGPropertyNode_ptr
SGPropertyNode::removeChild (int pos, bool keep)
{
SGPropertyNode_ptr node;
if (pos < 0 || pos >= _children.size())
return node;
vector<SGPropertyNode_ptr>::iterator it = _children.begin();
it += pos;
node = _children[pos];
_children.erase(it);
if (keep) {
_removedChildren.push_back(node);
}
if (_path_cache)
_path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account!
node->setAttribute(REMOVED, true);
node->clearValue();
fireChildRemoved(node);
return node;
}
/**
* Remove a child node
*/
@@ -919,22 +945,29 @@ SGPropertyNode::removeChild (const char * name, int index, bool keep)
{
SGPropertyNode_ptr ret;
int pos = find_child(name, index, _children);
if (pos >= 0) {
vector<SGPropertyNode_ptr>::iterator it = _children.begin();
it += pos;
SGPropertyNode_ptr node = _children[pos];
_children.erase(it);
if (keep) {
_removedChildren.push_back(node);
}
node->setAttribute(REMOVED, true);
ret = node;
fireChildRemoved(node);
}
if (pos >= 0)
ret = removeChild(pos, keep);
return ret;
}
/**
* Remove all children with the specified name.
*/
vector<SGPropertyNode_ptr>
SGPropertyNode::removeChildren (const char * name, bool keep)
{
vector<SGPropertyNode_ptr> children;
for (int pos = _children.size() - 1; pos >= 0; pos--)
if (compare_strings(_children[pos]->getName(), name))
children.push_back(removeChild(pos, keep));
sort(children.begin(), children.end(), CompareIndices());
return children;
}
const char *
SGPropertyNode::getDisplayName (bool simplify) const
{
@@ -1168,7 +1201,7 @@ SGPropertyNode::setBoolValue (bool value)
bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
clearValue();
_tied = false;
_type = BOOL;
}
@@ -1216,7 +1249,7 @@ SGPropertyNode::setIntValue (int value)
bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
clearValue();
_type = INT;
_local_val.int_val = 0;
}
@@ -1267,7 +1300,7 @@ SGPropertyNode::setLongValue (long value)
bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
clearValue();
_type = LONG;
_local_val.long_val = 0L;
}
@@ -1318,7 +1351,7 @@ SGPropertyNode::setFloatValue (float value)
bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
clearValue();
_type = FLOAT;
_local_val.float_val = 0;
}
@@ -1369,7 +1402,7 @@ SGPropertyNode::setDoubleValue (double value)
bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
clearValue();
_local_val.double_val = value;
_type = DOUBLE;
}
@@ -1420,7 +1453,7 @@ SGPropertyNode::setStringValue (const char * value)
bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
clearValue();
_type = STRING;
}
@@ -1464,7 +1497,7 @@ SGPropertyNode::setUnspecifiedValue (const char * value)
bool result = false;
TEST_WRITE;
if (_type == NONE) {
clear_value();
clearValue();
_type = UNSPECIFIED;
}
@@ -1513,7 +1546,7 @@ SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
if (useDefault)
old_val = getBoolValue();
clear_value();
clearValue();
_type = BOOL;
_tied = true;
_value.bool_val = rawValue.clone();
@@ -1535,7 +1568,7 @@ SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
if (useDefault)
old_val = getIntValue();
clear_value();
clearValue();
_type = INT;
_tied = true;
_value.int_val = rawValue.clone();
@@ -1557,7 +1590,7 @@ SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
if (useDefault)
old_val = getLongValue();
clear_value();
clearValue();
_type = LONG;
_tied = true;
_value.long_val = rawValue.clone();
@@ -1579,7 +1612,7 @@ SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
if (useDefault)
old_val = getFloatValue();
clear_value();
clearValue();
_type = FLOAT;
_tied = true;
_value.float_val = rawValue.clone();
@@ -1601,7 +1634,7 @@ SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
if (useDefault)
old_val = getDoubleValue();
clear_value();
clearValue();
_type = DOUBLE;
_tied = true;
_value.double_val = rawValue.clone();
@@ -1624,7 +1657,7 @@ SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
if (useDefault)
old_val = getStringValue();
clear_value();
clearValue();
_type = STRING;
_tied = true;
_value.string_val = rawValue.clone();
@@ -1644,35 +1677,35 @@ SGPropertyNode::untie ()
switch (_type) {
case BOOL: {
bool val = getBoolValue();
clear_value();
clearValue();
_type = BOOL;
_local_val.bool_val = val;
break;
}
case INT: {
int val = getIntValue();
clear_value();
clearValue();
_type = INT;
_local_val.int_val = val;
break;
}
case LONG: {
long val = getLongValue();
clear_value();
clearValue();
_type = LONG;
_local_val.long_val = val;
break;
}
case FLOAT: {
float val = getFloatValue();
clear_value();
clearValue();
_type = FLOAT;
_local_val.float_val = val;
break;
}
case DOUBLE: {
double val = getDoubleValue();
clear_value();
clearValue();
_type = DOUBLE;
_local_val.double_val = val;
break;
@@ -1680,7 +1713,7 @@ SGPropertyNode::untie ()
case STRING:
case UNSPECIFIED: {
string val = getStringValue();
clear_value();
clearValue();
_type = STRING;
_local_val.string_val = copy_string(val.c_str());
break;
@@ -1736,7 +1769,7 @@ SGPropertyNode::getNode (const char * relative_path, int index, bool create)
vector<PathComponent> components;
parse_path(relative_path, components);
if (components.size() > 0)
components[components.size()-1].index = index;
components.back().index = index;
return find_node(this, components, 0, create);
}
@@ -2140,6 +2173,7 @@ SGPropertyNode::hash_table::bucket::~bucket ()
{
for (int i = 0; i < _length; i++)
delete _entries[i];
delete [] _entries;
}
SGPropertyNode::hash_table::entry *
@@ -2166,6 +2200,23 @@ SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
}
}
void
SGPropertyNode::hash_table::bucket::erase (const char * key)
{
int i;
for (i = 0; i < _length; i++) {
if (!strcmp(_entries[i]->get_key(), key))
break;
}
if (i < _length) {
for (++i; i < _length; i++) {
_entries[i-1] = _entries[i];
}
_length--;
}
}
SGPropertyNode::hash_table::hash_table ()
: _data_length(0),
@@ -2177,6 +2228,7 @@ SGPropertyNode::hash_table::~hash_table ()
{
for (unsigned int i = 0; i < _data_length; i++)
delete _data[i];
delete [] _data;
}
SGPropertyNode *
@@ -2211,6 +2263,17 @@ SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
e->set_value(value);
}
void
SGPropertyNode::hash_table::erase (const char * key)
{
if (_data_length == 0)
return;
unsigned int index = hashcode(key) % _data_length;
if (_data[index] == 0)
return;
_data[index]->erase(key);
}
unsigned int
SGPropertyNode::hash_table::hashcode (const char * key)
{
+30 -16
View File
@@ -706,12 +706,24 @@ public:
vector<SGPropertyNode_ptr> getChildren (const char * name) const;
/**
* Remove child by position.
*/
SGPropertyNode_ptr removeChild (int pos, bool keep = true);
/**
* Remove a child node
*/
SGPropertyNode_ptr removeChild (const char * name, int index = 0,
bool keep = true);
/**
* Remove all children with the specified name.
*/
vector<SGPropertyNode_ptr> removeChildren (const char * name,
bool keep = true);
//
// Alias support.
@@ -1172,6 +1184,12 @@ public:
void fireChildRemoved (SGPropertyNode * child);
/**
* Clear any existing value and set the type to NONE.
*/
void clearValue ();
protected:
void fireValueChanged (SGPropertyNode * node);
@@ -1203,12 +1221,6 @@ private:
bool set_string (const char * value);
/**
* Clear any existing value and set the type to NONE.
*/
void clear_value ();
/**
* Get the value as a string.
*/
@@ -1293,11 +1305,11 @@ private:
class entry {
public:
entry ();
virtual ~entry ();
virtual const char * get_key () { return _key; }
virtual void set_key (const char * key);
virtual SGPropertyNode * get_value () { return _value; }
virtual void set_value (SGPropertyNode * value);
~entry ();
const char * get_key () { return _key; }
void set_key (const char * key);
SGPropertyNode * get_value () { return _value; }
void set_value (SGPropertyNode * value);
private:
char * _key;
SGPropertyNode * _value;
@@ -1310,8 +1322,9 @@ private:
class bucket {
public:
bucket ();
virtual ~bucket ();
virtual entry * get_entry (const char * key, bool create = false);
~bucket ();
entry * get_entry (const char * key, bool create = false);
void erase(const char * key);
private:
int _length;
entry ** _entries;
@@ -1320,9 +1333,10 @@ private:
friend class bucket;
hash_table ();
virtual ~hash_table ();
virtual SGPropertyNode * get (const char * key);
virtual void put (const char * key, SGPropertyNode * value);
~hash_table ();
SGPropertyNode * get (const char * key);
void put (const char * key, SGPropertyNode * value);
void erase(const char * key);
private:
unsigned int hashcode (const char * key);
+7 -1
View File
@@ -214,7 +214,10 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
}
}
push_state(node, atts.getValue("type"), mode);
const char *type = atts.getValue("type");
if (type)
node->clearValue();
push_state(node, type, mode);
}
}
@@ -588,6 +591,9 @@ copyProperties (const SGPropertyNode *in, SGPropertyNode *out)
}
}
// copy the attributes.
out->setAttributes( in->getAttributes() );
// Next, copy the children.
int nChildren = in->nChildren();
for (int i = 0; i < nChildren; i++) {
+2 -2
View File
@@ -153,10 +153,10 @@ public:
inline void set_distance( double d ) { distance = d; }
/** @return waypoint id */
inline string get_id() const { return id; }
inline const string& get_id() const { return id; }
/** @return waypoint name */
inline string get_name() const { return name; }
inline const string& get_name() const { return name; }
};
+11 -3
View File
@@ -27,6 +27,7 @@
#include <simgear/compiler.h>
#include <string.h>
#include <map>
SG_USING_STD(map);
@@ -48,10 +49,10 @@ SG_USING_STD(map);
////////////////////////////////////////////////////////////////////////
SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props )
SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props, const char *season )
{
init();
read_properties( fg_root, props );
read_properties( fg_root, props, season );
build_ssg_state( false );
}
@@ -86,13 +87,20 @@ SGMaterial::~SGMaterial (void)
////////////////////////////////////////////////////////////////////////
void
SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props )
SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props, const char *season )
{
// Gather the path(s) to the texture(s)
vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
for (unsigned int i = 0; i < textures.size(); i++)
{
string tname = textures[i]->getStringValue();
string otname = tname;
if (season && strncmp(season, "summer", 6))
{
if (tname.substr(0,7) == "Terrain")
tname.insert(7,"."+string(season));
}
if (tname == "") {
tname = "unknown.rgb";
}
+2 -2
View File
@@ -71,7 +71,7 @@ public:
* state information for the material. This node is usually
* loaded from the $FG_ROOT/materials.xml file.
*/
SGMaterial( const string &fg_root, const SGPropertyNode *props );
SGMaterial( const string &fg_root, const SGPropertyNode *props, const char *season );
/**
@@ -249,7 +249,7 @@ private:
SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented
void read_properties( const string &fg_root, const SGPropertyNode *props );
void read_properties( const string &fg_root, const SGPropertyNode *props, const char *season );
void build_ssg_state( bool defer_tex_load );
void set_ssg_state( ssgSimpleState *s );
+2 -2
View File
@@ -175,7 +175,7 @@ static int gen_taxiway_dir_light_map( int r, int g, int b, int alpha ) {
// Load a library of material properties
bool SGMaterialLib::load( const string &fg_root, const string& mpath ) {
bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) {
SGPropertyNode materials;
@@ -192,7 +192,7 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath ) {
for (int i = 0; i < nMaterials; i++) {
const SGPropertyNode * node = materials.getChild(i);
if (!strcmp(node->getName(), "material")) {
SGMaterial *m = new SGMaterial( fg_root, node );
SGMaterial *m = new SGMaterial( fg_root, node, season );
vector<SGPropertyNode_ptr>names = node->getChildren("name");
for ( unsigned int j = 0; j < names.size(); j++ ) {
+1 -1
View File
@@ -64,7 +64,7 @@ public:
SGMaterialLib ( void );
// Load a library of material properties
bool load( const string &fg_root, const string& mpath );
bool load( const string &fg_root, const string& mpath, const char *season );
// Add the named texture with default properties
bool add_item( const string &tex_path );
+1 -1
View File
@@ -110,7 +110,7 @@ SGMatModel::~SGMatModel ()
{
for (unsigned int i = 0; i < _models.size(); i++) {
if (_models[i] != 0) {
_models[i]->deRef();
ssgDeRefDelete(_models[i]);
_models[i] = 0;
}
}
+7 -2
View File
@@ -11,7 +11,9 @@ include_HEADERS = \
model.hxx \
modellib.hxx \
personality.hxx \
placement.hxx
placement.hxx \
placementtrans.hxx \
shadowvolume.hxx
libsgmodel_a_SOURCES = \
animation.cxx \
@@ -20,6 +22,9 @@ libsgmodel_a_SOURCES = \
model.cxx \
modellib.cxx \
personality.cxx \
placement.cxx
placement.cxx \
placementtrans.cxx \
shadowvolume.cxx \
shadanim.cxx
INCLUDES = -I$(top_srcdir)
+407 -47
View File
@@ -179,7 +179,8 @@ double SGAnimation::sim_time_sec = 0.0;
SGPersonalityBranch *SGAnimation::current_object = 0;
SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
: _branch(branch)
: _branch(branch),
animation_type(0)
{
_branch->setName(props->getStringValue("name", 0));
if ( props->getBoolValue( "enable-hot", true ) ) {
@@ -293,7 +294,7 @@ SGRangeAnimation::update()
ranges[1] = 1000000000.f;
}
((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
return 1;
return 2;
}
@@ -339,7 +340,7 @@ SGSelectAnimation::update()
((ssgSelector *)_branch)->select(0xffff);
else
((ssgSelector *)_branch)->select(0x0000);
return 1;
return 2;
}
@@ -352,9 +353,8 @@ SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props,
double sim_time_sec )
: SGAnimation(props, new ssgTransform),
_use_personality( props->getBoolValue("use-personality",false) ),
_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 ),
_condition(0)
{
@@ -391,6 +391,38 @@ SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
_center[2] = props->getFloatValue("center/z-m", 0);
}
sgNormalizeVec3(_axis);
//_factor(props->getDoubleValue("factor", 1.0)),
_factor = 1.0;
_factor_min = 1.0;
_factor_max = 1.0;
SGPropertyNode_ptr factor_n = props->getNode( "factor" );
if ( factor_n != 0 ) {
SGPropertyNode_ptr rand_n = factor_n->getNode( "random" );
if ( rand_n != 0 ) {
_factor_min = rand_n->getDoubleValue( "min", 0.0 );
_factor_max = rand_n->getDoubleValue( "max", 1.0 );
_factor = _factor_min + sg_random() * ( _factor_max - _factor_min );
} else {
_factor = _factor_min = _factor_max = props->getDoubleValue("factor", 1.0);
}
}
//_position_deg(props->getDoubleValue("starting-position-deg", 0)),
_position_deg = 0.0;
_position_deg_min = 0.0;
_position_deg_max = 0.0;
SGPropertyNode_ptr position_deg_n = props->getNode( "starting-position-deg" );
if ( position_deg_n != 0 ) {
SGPropertyNode_ptr rand_n = position_deg_n->getNode( "random" );
if ( rand_n != 0 ) {
_position_deg_min = rand_n->getDoubleValue( "min", 0.0 );
_position_deg_max = rand_n->getDoubleValue( "max", 1.0 );
_position_deg = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
} else {
_position_deg = _position_deg_min = _position_deg_max =
props->getDoubleValue("starting-position-deg", 1.0);
}
}
}
SGSpinAnimation::~SGSpinAnimation ()
@@ -401,15 +433,47 @@ int
SGSpinAnimation::update()
{
if ( _condition == 0 || _condition->test() ) {
double dt = sim_time_sec - _last_time_sec;
_last_time_sec = sim_time_sec;
double dt;
float velocity_rpms;
if ( _use_personality ) {
SGPersonalityBranch *key = current_object;
if ( !key->getIntValue( this, INIT_SPIN ) ) {
double v = _factor_min + sg_random() * ( _factor_max - _factor_min );
key->setDoubleValue( v, this, FACTOR_SPIN );
key->setDoubleValue( sim_time_sec, this, LAST_TIME_SEC_SPIN );
key->setIntValue( 1, this, INIT_SPIN );
v = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
key->setDoubleValue( v, this, POSITION_DEG_SPIN );
}
_factor = key->getDoubleValue( this, FACTOR_SPIN );
_position_deg = key->getDoubleValue( this, POSITION_DEG_SPIN );
_last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_SPIN );
dt = sim_time_sec - _last_time_sec;
_last_time_sec = sim_time_sec;
key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_SPIN );
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;
key->setDoubleValue( _position_deg, this, POSITION_DEG_SPIN );
} else {
dt = sim_time_sec - _last_time_sec;
_last_time_sec = sim_time_sec;
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;
}
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);
}
@@ -480,13 +544,13 @@ SGTimedAnimation::update()
{
if ( _use_personality ) {
SGPersonalityBranch *key = current_object;
if ( !key->getIntValue( this, INIT ) ) {
if ( !key->getIntValue( this, INIT_TIMED ) ) {
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 );
key->setDoubleValue( v, this, BRANCH_DURATION_SEC_TIMED, i );
if ( i == 0 )
offset = v;
total += v;
@@ -496,21 +560,21 @@ SGTimedAnimation::update()
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 );
key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC_TIMED );
key->setDoubleValue( total, this, TOTAL_DURATION_SEC_TIMED );
key->setIntValue( 0, this, STEP_TIMED );
key->setIntValue( 1, this, INIT_TIMED );
}
_step = key->getIntValue( this, STEP );
_last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC );
_total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC );
_step = key->getIntValue( this, STEP_TIMED );
_last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_TIMED );
_total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC_TIMED );
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 );
duration = key->getDoubleValue( this, BRANCH_DURATION_SEC_TIMED, _step );
}
if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
_last_time_sec += duration;
@@ -519,8 +583,8 @@ SGTimedAnimation::update()
_step = 0;
}
((ssgSelector *)getBranch())->selectStep( _step );
key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC );
key->setIntValue( _step, this, STEP );
key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_TIMED );
key->setIntValue( _step, this, STEP_TIMED );
} else {
while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
_last_time_sec += _total_duration_sec;
@@ -567,14 +631,18 @@ SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
_center[0] = 0;
_center[1] = 0;
_center[2] = 0;
if (props->hasValue("axis/x1-m")) {
if (props->hasValue("axis/x") || props->hasValue("axis/y") || props->hasValue("axis/z")) {
_axis[0] = props->getFloatValue("axis/x", 0);
_axis[1] = props->getFloatValue("axis/y", 0);
_axis[2] = props->getFloatValue("axis/z", 0);
} else {
double x1,y1,z1,x2,y2,z2;
x1 = props->getFloatValue("axis/x1-m");
y1 = props->getFloatValue("axis/y1-m");
z1 = props->getFloatValue("axis/z1-m");
x2 = props->getFloatValue("axis/x2-m");
y2 = props->getFloatValue("axis/y2-m");
z2 = props->getFloatValue("axis/z2-m");
x1 = props->getFloatValue("axis/x1-m", 0);
y1 = props->getFloatValue("axis/y1-m", 0);
z1 = props->getFloatValue("axis/z1-m", 0);
x2 = props->getFloatValue("axis/x2-m", 0);
y2 = props->getFloatValue("axis/y2-m", 0);
z2 = props->getFloatValue("axis/z2-m", 0);
_center[0] = (x1+x2)/2;
_center[1]= (y1+y2)/2;
_center[2] = (z1+z2)/2;
@@ -582,15 +650,12 @@ SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
_axis[0] = (x2-x1)/vector_length;
_axis[1] = (y2-y1)/vector_length;
_axis[2] = (z2-z1)/vector_length;
} else {
_axis[0] = props->getFloatValue("axis/x", 0);
_axis[1] = props->getFloatValue("axis/y", 0);
_axis[2] = props->getFloatValue("axis/z", 0);
}
if (props->hasValue("center/x-m")) {
_center[0] = props->getFloatValue("center/x-m", 0);
_center[1] = props->getFloatValue("center/y-m", 0);
_center[2] = props->getFloatValue("center/z-m", 0);
if (props->hasValue("center/x-m") || props->hasValue("center/y-m")
|| props->hasValue("center/z-m")) {
_center[0] = props->getFloatValue("center/x-m", 0);
_center[1] = props->getFloatValue("center/y-m", 0);
_center[2] = props->getFloatValue("center/z-m", 0);
}
sgNormalizeVec3(_axis);
}
@@ -616,7 +681,7 @@ SGRotateAnimation::update()
set_rotation(_matrix, _position_deg, _center, _axis);
((ssgTransform *)_branch)->setTransform(_matrix);
}
return 1;
return 2;
}
@@ -707,7 +772,7 @@ SGTranslateAnimation::update()
{
if (_condition == 0 || _condition->test()) {
if (_table == 0) {
_position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
_position_m = (_prop->getDoubleValue() * _factor) + _offset_m;
if (_has_min && _position_m < _min_m)
_position_m = _min_m;
if (_has_max && _position_m > _max_m)
@@ -718,7 +783,7 @@ SGTranslateAnimation::update()
set_translation(_matrix, _position_m, _axis);
((ssgTransform *)_branch)->setTransform(_matrix);
}
return 1;
return 2;
}
@@ -793,7 +858,7 @@ SGScaleAnimation::update()
set_scale(_matrix, _x_scale, _y_scale, _z_scale );
((ssgTransform *)_branch)->setTransform(_matrix);
return 1;
return 2;
}
@@ -842,7 +907,7 @@ SGTexRotateAnimation::update()
}
set_rotation(_matrix, _position_deg, _center, _axis);
((ssgTexTrans *)_branch)->setTransform(_matrix);
return 1;
return 2;
}
@@ -890,7 +955,7 @@ SGTexTranslateAnimation::update()
}
set_translation(_matrix, _position, _axis);
((ssgTexTrans *)_branch)->setTransform(_matrix);
return 1;
return 2;
}
@@ -1007,7 +1072,7 @@ SGTexMultipleAnimation::update()
}
}
((ssgTexTrans *)_branch)->setTransform(tmatrix);
return 1;
return 2;
}
@@ -1047,6 +1112,266 @@ void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGMaterialAnimation
////////////////////////////////////////////////////////////////////////
SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props, const SGPath &texture_path)
: SGAnimation(props, new ssgBranch),
_prop_root(prop_root),
_prop_base(""),
_texture_base(texture_path),
_cached_material(0),
_cloned_material(0),
_read(0),
_update(0),
_global(props->getBoolValue("global", false))
{
SGPropertyNode_ptr n;
n = props->getChild("condition");
_condition = n ? sgReadCondition(_prop_root, n) : 0;
n = props->getChild("property-base");
if (n) {
_prop_base = n->getStringValue();
if (!_prop_base.empty() && _prop_base.end()[-1] != '/')
_prop_base += '/';
}
initColorGroup(props->getChild("diffuse"), &_diff, DIFFUSE);
initColorGroup(props->getChild("ambient"), &_amb, AMBIENT);
initColorGroup(props->getChild("emission"), &_emis, EMISSION);
initColorGroup(props->getChild("specular"), &_spec, SPECULAR);
_shi = props->getFloatValue("shininess", -1.0);
if (_shi >= 0.0)
_update |= SHININESS;
SGPropertyNode_ptr group = props->getChild("transparency");
if (group) {
_trans.value = group->getFloatValue("alpha", -1.0);
_trans.factor = group->getFloatValue("factor", 1.0);
_trans.offset = group->getFloatValue("offset", 0.0);
_trans.min = group->getFloatValue("min", 0.0);
if (_trans.min < 0.0)
_trans.min = 0.0;
_trans.max = group->getFloatValue("max", 1.0);
if (_trans.max > 1.0)
_trans.max = 1.0;
if (_trans.dirty())
_update |= TRANSPARENCY;
n = group->getChild("alpha-prop");
_trans.value_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
n = group->getChild("factor-prop");
_trans.factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
n = group->getChild("offset-prop");
_trans.offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
if (_trans.live())
_read |= TRANSPARENCY;
}
_thresh = props->getFloatValue("threshold", -1.0);
if (_thresh >= 0.0)
_update |= THRESHOLD;
string _texture_str = props->getStringValue("texture", "");
if (!_texture_str.empty()) {
_texture = _texture_base;
_texture.append(_texture_str);
_update |= TEXTURE;
}
n = props->getChild("shininess-prop");
_shi_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
n = props->getChild("threshold-prop");
_thresh_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
n = props->getChild("texture-prop");
_tex_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
}
void SGMaterialAnimation::initColorGroup(SGPropertyNode_ptr group, ColorSpec *col, int flag)
{
if (!group)
return;
col->red = group->getFloatValue("red", -1.0);
col->green = group->getFloatValue("green", -1.0);
col->blue = group->getFloatValue("blue", -1.0);
col->factor = group->getFloatValue("factor", 1.0);
col->offset = group->getFloatValue("offset", 0.0);
if (col->dirty())
_update |= flag;
SGPropertyNode *n;
n = group->getChild("red-prop");
col->red_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
n = group->getChild("green-prop");
col->green_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
n = group->getChild("blue-prop");
col->blue_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
n = group->getChild("factor-prop");
col->factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
n = group->getChild("offset-prop");
col->offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
if (col->live())
_read |= flag;
}
void SGMaterialAnimation::init()
{
if (!_global)
cloneMaterials(_branch);
}
int SGMaterialAnimation::update()
{
if (_condition && !_condition->test())
return 2;
if (_read & DIFFUSE)
updateColorGroup(&_diff, DIFFUSE);
if (_read & AMBIENT)
updateColorGroup(&_amb, AMBIENT);
if (_read & EMISSION)
updateColorGroup(&_emis, EMISSION);
if (_read & SPECULAR)
updateColorGroup(&_spec, SPECULAR);
float f;
if (_shi_prop) {
f = _shi;
_shi = _shi_prop->getFloatValue();
if (_shi != f)
_update |= SHININESS;
}
if (_read & TRANSPARENCY) {
PropSpec tmp = _trans;
if (_trans.value_prop)
_trans.value = _trans.value_prop->getFloatValue();
if (_trans.factor_prop)
_trans.factor = _trans.factor_prop->getFloatValue();
if (_trans.offset_prop)
_trans.offset = _trans.offset_prop->getFloatValue();
if (_trans != tmp)
_update |= TRANSPARENCY;
}
if (_thresh_prop) {
f = _thresh;
_thresh = _thresh_prop->getFloatValue();
if (_thresh != f)
_update |= THRESHOLD;
}
if (_tex_prop) {
string t = _tex_prop->getStringValue();
if (!t.empty() && t != _texture_str) {
_texture_str = t;
_texture = _texture_base;
_texture.append(t);
_update |= TEXTURE;
}
}
if (_update) {
setMaterialBranch(_branch);
_update = 0;
}
return 2;
}
void SGMaterialAnimation::updateColorGroup(ColorSpec *col, int flag)
{
ColorSpec tmp = *col;
if (col->red_prop)
col->red = col->red_prop->getFloatValue();
if (col->green_prop)
col->green = col->green_prop->getFloatValue();
if (col->blue_prop)
col->blue = col->blue_prop->getFloatValue();
if (col->factor_prop)
col->factor = col->factor_prop->getFloatValue();
if (col->offset_prop)
col->offset = col->offset_prop->getFloatValue();
if (*col != tmp)
_update |= flag;
}
void SGMaterialAnimation::cloneMaterials(ssgBranch *b)
{
for (int i = 0; i < b->getNumKids(); i++)
cloneMaterials((ssgBranch *)b->getKid(i));
if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
return;
ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
if (!_cached_material || _cached_material != s) {
_cached_material = s;
_cloned_material = (ssgSimpleState *)s->clone(SSG_CLONE_STATE);
}
((ssgLeaf *)b)->setState(_cloned_material);
}
void SGMaterialAnimation::setMaterialBranch(ssgBranch *b)
{
for (int i = 0; i < b->getNumKids(); i++)
setMaterialBranch((ssgBranch *)b->getKid(i));
if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
return;
ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
if (_update & DIFFUSE) {
float *v = _diff.rgba();
SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
s->setColourMaterial(GL_DIFFUSE);
s->enable(GL_COLOR_MATERIAL);
s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], alpha);
s->disable(GL_COLOR_MATERIAL);
}
if (_update & AMBIENT) {
s->setColourMaterial(GL_AMBIENT);
s->enable(GL_COLOR_MATERIAL);
s->setMaterial(GL_AMBIENT, _amb.rgba());
s->disable(GL_COLOR_MATERIAL);
}
if (_update & EMISSION)
s->setMaterial(GL_EMISSION, _emis.rgba());
if (_update & SPECULAR)
s->setMaterial(GL_SPECULAR, _spec.rgba());
if (_update & SHININESS)
s->setShininess(clamp(_shi, 0.0, 128.0));
if (_update & TRANSPARENCY) {
SGfloat *v = s->getMaterial(GL_DIFFUSE);
float trans = _trans.value * _trans.factor + _trans.offset;
trans = trans < _trans.min ? _trans.min : trans > _trans.max ? _trans.max : trans;
s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], trans);
}
if (_update & THRESHOLD)
s->setAlphaClamp(clamp(_thresh));
if (_update & TEXTURE)
s->setTexture(_texture.c_str());
if (_update & (TEXTURE|TRANSPARENCY)) {
SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
ssgTexture *tex = s->getTexture();
if ((tex && tex->hasAlpha()) || alpha < 0.999) {
s->setColourMaterial(GL_DIFFUSE);
s->enable(GL_COLOR_MATERIAL);
s->enable(GL_BLEND);
s->enable(GL_ALPHA_TEST);
s->setTranslucent();
s->disable(GL_COLOR_MATERIAL);
} else {
s->disable(GL_BLEND);
s->disable(GL_ALPHA_TEST);
s->setOpaque();
}
}
s->force();
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGFlashAnimation
@@ -1177,4 +1502,39 @@ void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
sgPreMultMat4( r, transform );
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGShadowAnimation
////////////////////////////////////////////////////////////////////////
SGShadowAnimation::SGShadowAnimation ( SGPropertyNode *prop_root,
SGPropertyNode_ptr props )
: SGAnimation(props, new ssgBranch),
_condition(0),
_condition_value(true)
{
animation_type = 1;
SGPropertyNode_ptr node = props->getChild("condition");
if (node != 0) {
_condition = sgReadCondition(prop_root, node);
_condition_value = false;
}
}
SGShadowAnimation::~SGShadowAnimation ()
{
delete _condition;
}
int
SGShadowAnimation::update()
{
if (_condition)
_condition_value = _condition->test();
return 2;
}
bool SGShadowAnimation::get_condition_value(void) {
return _condition_value;
}
// end of animation.cxx
+165 -1
View File
@@ -22,6 +22,7 @@ SG_USING_STD(map);
#include <simgear/math/point3d.hxx>
#include <simgear/props/props.hxx>
#include <simgear/misc/sg_path.hxx>
// Don't pull in the headers, since we don't need them here.
@@ -50,6 +51,10 @@ class SGPersonalityBranch;
class SGAnimation : public ssgBase
{
public:
enum PersonalityVar { INIT_SPIN, LAST_TIME_SEC_SPIN, FACTOR_SPIN,
POSITION_DEG_SPIN, INIT_TIMED, LAST_TIME_SEC_TIMED,
TOTAL_DURATION_SEC_TIMED, BRANCH_DURATION_SEC_TIMED,
STEP_TIMED };
SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch);
@@ -87,12 +92,15 @@ public:
*/
static SGPersonalityBranch *current_object;
int get_animation_type(void) { return animation_type; }
protected:
static double sim_time_sec;
ssgBranch * _branch;
int animation_type;
};
@@ -168,9 +176,14 @@ public:
virtual ~SGSpinAnimation ();
virtual int update();
private:
bool _use_personality;
SGPropertyNode_ptr _prop;
double _factor;
double _factor_min;
double _factor_max;
double _position_deg;
double _position_deg_min;
double _position_deg_max;
double _last_time_sec;
sgMat4 _matrix;
sgVec3 _center;
@@ -191,7 +204,6 @@ public:
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;
@@ -425,6 +437,112 @@ private:
};
/**
* An "animation" to modify material properties
*/
class SGMaterialAnimation : public SGAnimation
{
public:
SGMaterialAnimation(SGPropertyNode *prop_root, SGPropertyNode_ptr props,
const SGPath &texpath);
virtual ~SGMaterialAnimation() {}
virtual void init();
virtual int update();
private:
enum {
DIFFUSE = 1,
AMBIENT = 2,
SPECULAR = 4,
EMISSION = 8,
SHININESS = 16,
TRANSPARENCY = 32,
THRESHOLD = 64,
TEXTURE = 128,
};
struct ColorSpec {
float red, green, blue;
float factor;
float offset;
SGPropertyNode_ptr red_prop;
SGPropertyNode_ptr green_prop;
SGPropertyNode_ptr blue_prop;
SGPropertyNode_ptr factor_prop;
SGPropertyNode_ptr offset_prop;
sgVec4 v;
inline bool dirty() {
return red >= 0.0 || green >= 0.0 || blue >= 0.0;
}
inline bool live() {
return red_prop || green_prop || blue_prop
|| factor_prop || offset_prop;
}
inline bool operator!=(ColorSpec& a) {
return red != a.red || green != a.green || blue != a.blue
|| factor != a.factor || offset != a.offset;
}
sgVec4 &rgba() {
v[0] = clamp(red * factor + offset);
v[1] = clamp(green * factor + offset);
v[2] = clamp(blue * factor + offset);
v[3] = 1.0;
return v;
}
inline float clamp(float val) {
return val < 0.0 ? 0.0 : val > 1.0 ? 1.0 : val;
}
};
struct PropSpec {
float value;
float factor;
float offset;
float min;
float max;
SGPropertyNode_ptr value_prop;
SGPropertyNode_ptr factor_prop;
SGPropertyNode_ptr offset_prop;
inline bool dirty() { return value >= 0.0; }
inline bool live() { return value_prop || factor_prop || offset_prop; }
inline bool operator!=(PropSpec& a) {
return value != a.value || factor != a.factor || offset != a.offset;
}
};
SGCondition *_condition;
SGPropertyNode *_prop_root;
string _prop_base;
SGPath _texture_base;
SGPath _texture;
string _texture_str;
ssgSimpleState* _cached_material;
ssgSimpleState* _cloned_material;
unsigned _read;
unsigned _update;
bool _global;
ColorSpec _diff;
ColorSpec _amb;
ColorSpec _emis;
ColorSpec _spec;
float _shi;
PropSpec _trans;
float _thresh; // alpha_clamp (see man glAlphaFunc)
string _tex;
string _tmpstr;
SGPropertyNode_ptr _shi_prop;
SGPropertyNode_ptr _thresh_prop;
SGPropertyNode_ptr _tex_prop;
void cloneMaterials(ssgBranch *b);
void setMaterialBranch(ssgBranch *b);
void initColorGroup(SGPropertyNode_ptr, ColorSpec *, int flag);
void updateColorGroup(ColorSpec *, int flag);
inline float clamp(float val, float min = 0.0, float max = 1.0) {
return val < min ? min : val > max ? max : val;
}
const char *path(const char *rel) {
return (_tmpstr = _prop_base + rel).c_str();
}
};
/**
* An "animation" that compute a scale according to
* the angle between an axis and the view direction
@@ -465,5 +583,51 @@ private:
SGInterpTable * _table;
};
/**
* An animation to tell wich objects don't cast shadows.
*/
class SGShadowAnimation : public SGAnimation
{
public:
SGShadowAnimation ( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGShadowAnimation ();
virtual int update();
bool get_condition_value(void);
private:
SGCondition * _condition;
bool _condition_value;
};
/**
+ * An "animation" that replace fixed opengl pipeline by shaders
+ */
class SGShaderAnimation : public SGAnimation
{
public:
SGShaderAnimation ( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGShaderAnimation ();
virtual void init();
virtual int update();
bool get_condition_value(void);
private:
SGCondition * _condition;
bool _condition_value;
int _shader_type;
float _param_1;
sgVec4 _param_color;
public:
bool _depth_test;
float _factor;
SGPropertyNode_ptr _factor_prop;
float _speed;
SGPropertyNode_ptr _speed_prop;
ssgTexture *_effectTexture;
unsigned char *_textureData;
GLint _texWidth, _texHeight;
sgVec4 _envColor;
};
#endif // _SG_ANIMATION_HXX
+55 -96
View File
@@ -93,7 +93,6 @@ static void MakeTRANS( sgMat4 dst, const double Theta,
dst[1][3] = SG_ZERO ;
dst[0][3] = SG_ZERO ;
dst[3][3] = SG_ONE ;
}
@@ -103,19 +102,16 @@ static void MakeTRANS( sgMat4 dst, const double Theta,
// Constructor
SGLocation::SGLocation( void ):
_dirty(true),
_position_dirty(true), _orientation_dirty(true),
_lon_deg(-1000),
_lat_deg(0),
_alt_ft(0),
_roll_deg(0),
_pitch_deg(0),
_heading_deg(0),
_cur_elev_m(0),
_tile_center(0)
_cur_elev_m(0)
{
sgdZeroVec3(_absolute_view_pos);
sgZeroVec3(_relative_view_pos);
sgZeroVec3(_zero_elev_view_pos);
sgMakeRotMat4( UP, 0.0, 0.0, 0.0 );
sgMakeRotMat4( TRANS, 0.0, 0.0, 0.0 );
}
@@ -125,25 +121,10 @@ SGLocation::SGLocation( void ):
SGLocation::~SGLocation( void ) {
}
void
SGLocation::init ()
{
}
void
SGLocation::bind ()
{
}
void
SGLocation::unbind ()
{
}
void
SGLocation::setPosition (double lon_deg, double lat_deg, double alt_ft)
{
_dirty = true;
_position_dirty = true;
_lon_deg = lon_deg;
_lat_deg = lat_deg;
_alt_ft = alt_ft;
@@ -152,105 +133,83 @@ SGLocation::setPosition (double lon_deg, double lat_deg, double alt_ft)
void
SGLocation::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
{
_dirty = true;
_orientation_dirty = true;
_roll_deg = roll_deg;
_pitch_deg = pitch_deg;
_heading_deg = heading_deg;
}
double *
SGLocation::get_absolute_view_pos( const Point3D scenery_center )
SGLocation::get_absolute_view_pos()
{
if ( _dirty ) {
recalc( scenery_center );
}
recalcAbsolutePosition();
return _absolute_view_pos;
}
float *
SGLocation::getRelativeViewPos( const Point3D scenery_center )
SGLocation::get_view_pos( const Point3D& scenery_center )
{
if ( _dirty ) {
recalc( scenery_center );
}
recalcAbsolutePosition();
for (int i = 0; i < 3; i++)
_relative_view_pos[i] = _absolute_view_pos[i] - scenery_center[i];
return _relative_view_pos;
}
float *
SGLocation::getZeroElevViewPos( const Point3D scenery_center )
{
if ( _dirty ) {
recalc( scenery_center );
}
return _zero_elev_view_pos;
}
// recalc() is done every time one of the setters is called (making the
// cached data "dirty") on the next "get". It calculates all the outputs
// for viewer.
void
SGLocation::recalc( const Point3D scenery_center )
SGLocation::recalcOrientation() const
{
if (_orientation_dirty) {
// Make sure UP matrix is up-to-date.
recalcAbsolutePosition();
recalcPosition( _lon_deg, _lat_deg, _alt_ft, scenery_center );
// Make the world up rotation matrix for eye positioin...
sgMakeRotMat4( UP, _lon_deg, 0.0, -_lat_deg );
// get the world up radial vector from planet center for output
sgSetVec3( _world_up, UP[0][0], UP[0][1], UP[0][2] );
// Creat local matrix with current geodetic position. Converting
// the orientation (pitch/roll/heading) to vectors.
MakeTRANS( TRANS, _pitch_deg * SG_DEGREES_TO_RADIANS,
// Create local matrix with current geodetic position. Converting
// the orientation (pitch/roll/heading) to vectors.
MakeTRANS( TRANS, _pitch_deg * SG_DEGREES_TO_RADIANS,
_roll_deg * SG_DEGREES_TO_RADIANS,
-_heading_deg * SG_DEGREES_TO_RADIANS,
UP);
// Given a vector pointing straight down (-Z), map into onto the
// local plane representing "horizontal". This should give us the
// local direction for moving "south".
sgVec3 minus_z;
sgSetVec3( minus_z, 0.0, 0.0, -1.0 );
sgmap_vec_onto_cur_surface_plane(_world_up, _relative_view_pos, minus_z,
_surface_south);
sgNormalizeVec3(_surface_south);
// now calculate the surface east vector
sgVec3 world_down;
sgNegateVec3(world_down, _world_up);
sgVectorProductVec3(_surface_east, _surface_south, world_down);
set_clean();
-_heading_deg * SG_DEGREES_TO_RADIANS,
UP );
_orientation_dirty = false;
}
}
/*
* Update values derived from the longitude, latitude and altitude parameters
* of this instance. This encompasses absolute position in cartesian
* coordinates, the local up, east and south vectors and the UP Matrix.
*/
void
SGLocation::recalcPosition( double lon_deg, double lat_deg, double alt_ft,
const Point3D scenery_center ) const
SGLocation::recalcAbsolutePosition() const
{
double lat = lat_deg * SGD_DEGREES_TO_RADIANS;
double lon = lon_deg * SGD_DEGREES_TO_RADIANS;
double alt = alt_ft * SG_FEET_TO_METER;
if (_position_dirty) {
double lat = _lat_deg * SGD_DEGREES_TO_RADIANS;
double lon = _lon_deg * SGD_DEGREES_TO_RADIANS;
double alt = _alt_ft * SG_FEET_TO_METER;
sgGeodToCart(lat, lon, alt, _absolute_view_pos);
sgGeodToCart(lat, lon, alt, _absolute_view_pos);
// Make the world up rotation matrix for eye positioin...
sgMakeRotMat4( UP, _lon_deg, 0.0, -_lat_deg );
int i;
double ground[3];
sgGeodToCart(lat, lon, 0, ground);
for(i=0; i<3; i++)
_zero_elev_view_pos[i] = ground[i] - _tile_center[i];
// get the world up radial vector from planet center for output
sgSetVec3( _world_up, UP[0][0], UP[0][1], UP[0][2] );
// FIXME: view position should ONLY be calculated in the viewer...
// Anything else should calculate their own positions relative to the
// viewer's tile_center.
for(i=0; i<3; i++)
_relative_view_pos[i] = _absolute_view_pos[i] - scenery_center[i];
}
// Calculate the surface east and south vectors using the (normalized)
// partial derivatives of the up vector Could also be fetched and
// normalized from the UP rotation matrix, but I doubt this would
// be more efficient.
float sin_lon = sin(_lon_deg * SGD_DEGREES_TO_RADIANS);
float sin_lat = sin(_lat_deg * SGD_DEGREES_TO_RADIANS);
float cos_lon = cos(_lon_deg * SGD_DEGREES_TO_RADIANS);
float cos_lat = cos(_lat_deg * SGD_DEGREES_TO_RADIANS);
_surface_south[0] = (sin_lat*cos_lon);
_surface_south[1] = (sin_lat*sin_lon);
_surface_south[2] = - cos_lat;
_surface_east[0] = -sin_lon;
_surface_east[1] = cos_lon;
_surface_east[2] = 0.f;
void
SGLocation::update (int dt)
{
_position_dirty = false;
}
}
+34 -57
View File
@@ -41,23 +41,12 @@ class SGLocation
{
public:
// Constructor
SGLocation( void );
// Destructor
virtual ~SGLocation( void );
//////////////////////////////////////////////////////////////////////
// Part 1: standard FGSubsystem implementation.
//////////////////////////////////////////////////////////////////////
virtual void init ();
virtual void bind ();
virtual void unbind ();
void update (int dt);
//////////////////////////////////////////////////////////////////////
// Part 2: user settings.
//////////////////////////////////////////////////////////////////////
@@ -88,47 +77,42 @@ public:
//////////////////////////////////////////////////////////////////////
// Vectors and positions...
// Get zero view_pos
virtual float * get_view_pos() { return _relative_view_pos; }
// Get the absolute view position in fgfs coordinates.
virtual double * get_absolute_view_pos( const Point3D scenery_center );
// Get zero elev
virtual float * get_zero_elev() { return _zero_elev_view_pos; }
//! Get the absolute view position in fgfs coordinates.
virtual double * get_absolute_view_pos( );
//! Return the position relative to the given scenery center.
virtual float * get_view_pos( const Point3D& scenery_center );
// Get world up vector
virtual float *get_world_up() { return _world_up; }
// Get the relative (to scenery center) view position in fgfs coordinates.
virtual float * getRelativeViewPos( const Point3D scenery_center );
// Get the absolute zero-elevation view position in fgfs coordinates.
virtual float * getZeroElevViewPos( const Point3D scenery_center );
virtual float *get_world_up()
{ recalcAbsolutePosition(); return _world_up; }
// Get surface east vector
virtual float *get_surface_east() { return _surface_east; }
virtual float *get_surface_east()
{ recalcAbsolutePosition(); return _surface_east; }
// Get surface south vector
virtual float *get_surface_south() { return _surface_south; }
virtual float *get_surface_south()
{ recalcAbsolutePosition(); return _surface_south; }
// Elevation of ground under location (based on scenery output)...
void set_cur_elev_m ( double elev ) { _cur_elev_m = elev; }
inline double get_cur_elev_m () { return _cur_elev_m; }
// Interface to current buckets for use with tilemgr...
void set_tile_center ( Point3D tile_center ) { _tile_center = tile_center; }
inline Point3D get_tile_center () { return _tile_center; }
void set_cur_elev_m ( double elev ) { _cur_elev_m = elev; }
inline double get_cur_elev_m () { return _cur_elev_m; }
// Matrices...
virtual const sgVec4 *getTransformMatrix( const Point3D scenery_center ) {
if ( _dirty ) {
recalc( scenery_center );
}
return TRANS;
virtual const sgVec4 *getTransformMatrix() {
recalcOrientation();
return TRANS;
}
virtual const sgVec4 *getCachedTransformMatrix() { return TRANS; }
virtual const sgVec4 *getUpMatrix( const Point3D scenery_center ) {
if ( _dirty ) {
recalc( scenery_center );
}
return UP;
virtual const sgVec4 *getUpMatrix(const Point3D& scenery_center) {
recalcAbsolutePosition();
return UP;
}
virtual const sgVec4 *getCachedUpMatrix() { return UP; }
private:
//////////////////////////////////////////////////////////////////
@@ -136,11 +120,10 @@ private:
//////////////////////////////////////////////////////////////////
// flag forcing a recalc of derived view parameters
bool _dirty;
mutable bool _orientation_dirty, _position_dirty;
mutable sgdVec3 _absolute_view_pos;
mutable sgVec3 _relative_view_pos;
mutable sgVec3 _zero_elev_view_pos;
double _lon_deg;
double _lat_deg;
@@ -152,33 +135,27 @@ private:
// elevation of ground under this location...
double _cur_elev_m;
Point3D _tile_center;
// surface vector heading south
sgVec3 _surface_south;
mutable sgVec3 _surface_south;
// surface vector heading east (used to unambiguously align sky
// with sun)
sgVec3 _surface_east;
mutable sgVec3 _surface_east;
// world up vector (normal to the plane tangent to the earth's
// surface at the spot we are directly above
sgVec3 _world_up;
// surface at the spot we are directly above)
mutable sgVec3 _world_up;
// sg versions of our friendly matrices
sgMat4 TRANS, UP;
mutable sgMat4 TRANS, UP;
//////////////////////////////////////////////////////////////////
// private functions //
//////////////////////////////////////////////////////////////////
void recalc( const Point3D scenery_center );
void recalcPosition( double lon_deg, double lat_deg, double alt_ft,
const Point3D scenery_center ) const;
inline void set_dirty() { _dirty = true; }
inline void set_clean() { _dirty = false; }
void recalcOrientation() const;
void recalcAbsolutePosition() const;
};
+30 -18
View File
@@ -19,7 +19,6 @@
#include <plib/ul.h>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
@@ -125,6 +124,7 @@ sgMakeAnimation( ssgBranch * model,
SGPropertyNode *prop_root,
SGPropertyNode_ptr node,
double sim_time_sec,
SGPath &texture_path,
set<ssgBranch *> &ignore_branches )
{
bool ignore = false;
@@ -159,10 +159,16 @@ sgMakeAnimation( ssgBranch * model,
ignore = true;
} else if (!strcmp("alpha-test", type)) {
animation = new SGAlphaTestAnimation(node);
} else if (!strcmp("material", type)) {
animation = new SGMaterialAnimation(prop_root, node, texture_path);
} else if (!strcmp("flash", type)) {
animation = new SGFlashAnimation(node);
} else if (!strcmp("dist-scale", type)) {
animation = new SGDistScaleAnimation(node);
} else if (!strcmp("noshadow", type)) {
animation = new SGShadowAnimation(prop_root, node);
} else if (!strcmp("shader", type)) {
animation = new SGShaderAnimation(prop_root, node);
} else {
animation = new SGNullAnimation(node);
SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);
@@ -222,6 +228,7 @@ static void makeDList( ssgBranch *b, const set<ssgBranch *> &ignore )
for (int i = 0; i<nb; i++) {
ssgEntity *e = b->getKid(i);
if (e->isAKindOf(ssgTypeLeaf())) {
if( ((ssgLeaf*)e)->getNumVertices() > 0)
((ssgLeaf*)e)->makeDList();
} else if (e->isAKindOf(ssgTypeBranch()) && ignore.find((ssgBranch *)e) == ignore.end()) {
makeDList( (ssgBranch*)e, ignore );
@@ -317,23 +324,6 @@ sgLoad3DModel( const string &fg_root, const string &path,
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, ignore_branches);
}
#if PLIB_VERSION > 183
if ( model != 0 && sgUseDisplayList ) {
makeDList( model, ignore_branches );
}
#endif
if ( load_panel ) {
// Load panels
vector<SGPropertyNode_ptr> panel_nodes = props.getChildren("panel");
@@ -345,6 +335,23 @@ sgLoad3DModel( const string &fg_root, const string &path,
model->addKid(panel);
}
}
// 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, texturepath, ignore_branches);
}
#if PLIB_VERSION > 183
if ( model != 0 && sgUseDisplayList ) {
makeDList( model, ignore_branches );
}
#endif
return alignmainmodel;
}
@@ -357,5 +364,10 @@ sgSetModelFilter( bool filter )
return old;
}
bool
sgCheckAnimationBranch (ssgEntity * entity)
{
return entity->getTravCallback(SSG_CALLBACK_PRETRAV) == animation_callback;
}
// end of model.cxx
+8
View File
@@ -19,6 +19,7 @@ SG_USING_STD(set);
#include <plib/sg.h>
#include <plib/ssg.h>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
@@ -66,6 +67,7 @@ sgMakeAnimation( ssgBranch * model,
SGPropertyNode *prop_root,
SGPropertyNode_ptr node,
double sim_time_sec,
SGPath &texture_path,
set<ssgBranch *> &ignore_branches );
/**
@@ -74,6 +76,12 @@ sgMakeAnimation( ssgBranch * model,
bool
sgSetModelFilter( bool filter );
/**
* Check if the ssg node contains an animation
*/
bool
sgCheckAnimationBranch (ssgEntity * entity);
/**
* Enable or disable Display list usage
*/
+2 -2
View File
@@ -23,7 +23,7 @@ SGModelLib::~SGModelLib ()
{
map<string, ssgBase *>::iterator it = _table.begin();
while (it != _table.end()) {
it->second->deRef();
ssgDeRefDelete(it->second);
_table.erase(it);
}
}
@@ -55,7 +55,7 @@ SGModelLib::flush1()
// If there is only one reference, it's
// ours; no one else is using the item.
if (item->getRef() == 1) {
item->deRef();
ssgDeRefDelete(item);
_table.erase(it);
}
it++;
+6 -18
View File
@@ -11,18 +11,15 @@
#include <string.h> // for strcmp()
#include <vector>
#include <plib/sg.h>
#include <plib/ssg.h>
#include <plib/ul.h>
#include "location.hxx"
#include "placementtrans.hxx"
#include "placement.hxx"
SG_USING_STD(vector);
////////////////////////////////////////////////////////////////////////
@@ -37,7 +34,7 @@ SGModelPlacement::SGModelPlacement ()
_pitch_deg(0),
_heading_deg(0),
_selector(new ssgSelector),
_position(new ssgTransform),
_position(new ssgPlacementTransform),
_location(new SGLocation)
{
}
@@ -57,23 +54,14 @@ SGModelPlacement::init( ssgBranch * model )
}
void
SGModelPlacement::update( const Point3D scenery_center )
SGModelPlacement::update()
{
_location->setPosition( _lon_deg, _lat_deg, _elev_ft );
_location->setOrientation( _roll_deg, _pitch_deg, _heading_deg );
sgCopyMat4( POS, _location->getTransformMatrix(scenery_center) );
sgVec3 trans;
sgCopyVec3(trans, _location->get_view_pos());
for(int i = 0; i < 4; i++) {
float tmp = POS[i][3];
for( int j=0; j<3; j++ ) {
POS[i][j] += (tmp * trans[j]);
}
}
_position->setTransform(POS);
sgMat4 rotation;
sgCopyMat4( rotation, _location->getTransformMatrix() );
_position->setTransform(_location->get_absolute_view_pos(), rotation);
}
bool
+7 -21
View File
@@ -11,10 +11,6 @@
# error This library requires C++
#endif
#include <vector>
SG_USING_STD(vector);
#include <plib/sg.h>
#include <plib/ssg.h>
@@ -24,6 +20,7 @@ SG_USING_STD(vector);
// Don't pull in the headers, since we don't need them here.
class SGLocation;
class ssgPlacementTransform;
// Has anyone done anything *really* stupid, like making min and max macros?
@@ -49,12 +46,9 @@ public:
SGModelPlacement ();
virtual ~SGModelPlacement ();
virtual void SGModelPlacement::init( ssgBranch * model );
/* virtual void init( const string &fg_root,
const string &path,
SGPropertyNode *prop_root,
double sim_time_sec, int dummy ); */
virtual void update( const Point3D scenery_center );
virtual void SGModelPlacement::init( ssgBranch * model );
virtual void update();
virtual ssgEntity * getSceneGraph () { return (ssgEntity *)_selector; }
@@ -82,9 +76,8 @@ public:
virtual void setOrientation (double roll_deg, double pitch_deg,
double heading_deg);
// Addition by Diarmuid Tyson for Multiplayer Support
// Allows multiplayer to get players position transform
virtual const sgVec4 *get_POS() { return POS; }
ssgPlacementTransform * getTransform(void)
{ return _position; }
private:
@@ -99,17 +92,10 @@ private:
double _heading_deg;
ssgSelector * _selector;
ssgTransform * _position;
ssgPlacementTransform * _position;
// Location
SGLocation * _location;
// Addition by Diarmuid Tyson for Multiplayer Support
// Moved from update method
// POS for transformation Matrix
sgMat4 POS;
};
#endif // _SG_PLACEMENT_HXX
+98
View File
@@ -0,0 +1,98 @@
// placementtrans.hxx -- class for carrying transforms for placing models in the world
//
// Written by Mathias Froehlich, started April 2005.
//
// Copyright (C) 2005 Mathias Froehlich
//
// 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.
//
#ifndef __cplusplus
# error This library requires C++
#endif
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <plib/sg.h>
#include <plib/ssg.h>
#include "placementtrans.hxx"
ssgPlacementTransform::ssgPlacementTransform(void)
{
}
ssgPlacementTransform::~ssgPlacementTransform(void)
{
}
ssgBase *ssgPlacementTransform::clone(int clone_flags)
{
ssgPlacementTransform *b = new ssgPlacementTransform;
b->copy_from(this, clone_flags);
return b;
}
void
ssgPlacementTransform::copy_from(ssgPlacementTransform *src, int clone_flags)
{
ssgBaseTransform::copy_from(src, clone_flags);
sgdCopyVec3(_placement_offset, src->_placement_offset);
sgdCopyVec3(_scenery_center, src->_scenery_center);
}
void ssgPlacementTransform::setTransform(sgdVec3 off)
{
sgdCopyVec3(_placement_offset, off);
sgdVec3 tmp;
sgdSubVec3(tmp, _placement_offset, _scenery_center);
sgMat4 tmat;
sgZeroVec4(tmat[0]);
tmat[0][0] = 1;
sgZeroVec4(tmat[1]);
tmat[1][1] = 1;
sgZeroVec4(tmat[2]);
tmat[2][2] = 1;
sgSetVec3(tmat[3], tmp);
tmat[3][3] = 1;
ssgTransform::setTransform(tmat);
}
void ssgPlacementTransform::setTransform(sgdVec3 off, sgMat4 rot)
{
sgdCopyVec3(_placement_offset, off);
sgdVec3 tmp;
sgdSubVec3(tmp, _placement_offset, _scenery_center);
sgMat4 tmat;
sgCopyVec4(tmat[0], rot[0]);
sgCopyVec4(tmat[1], rot[1]);
sgCopyVec4(tmat[2], rot[2]);
sgSetVec3(tmat[3], tmp);
tmat[3][3] = 1;
ssgTransform::setTransform(tmat);
}
void ssgPlacementTransform::setSceneryCenter(sgdVec3 xyz)
{
sgdCopyVec3(_scenery_center, xyz);
sgdVec3 tmp;
sgdSubVec3(tmp, _placement_offset, _scenery_center);
sgMat4 tmat;
getTransform(tmat);
sgSetVec3(tmat[3], tmp);
ssgTransform::setTransform(tmat);
}
+71
View File
@@ -0,0 +1,71 @@
// placementtrans.hxx -- class for carrying transforms for placing models in the world
//
// Written by Mathias Froehlich, started April 2005.
//
// Copyright (C) 2005 Mathias Froehlich
//
// 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.
//
#ifndef _SG_PLACEMENTTRANS_HXX
#define _SG_PLACEMENTTRANS_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <plib/sg.h>
#include <plib/ssg.h>
class ssgPlacementTransform : public ssgTransform
{
public:
ssgPlacementTransform(void);
virtual ~ssgPlacementTransform(void);
// using ssgTransform::addKid(ssgEntity*);
virtual ssgBase *clone(int clone_flags);
protected:
void copy_from(ssgPlacementTransform *src, int clone_flags);
private:
// virtual void setTransform(sgVec3 xyz);
// virtual void setTransform(sgCoord *xform);
// virtual void setTransform(sgCoord *xform, float sx, float sy, float sz);
// virtual void setTransform(sgMat4 xform);
public:
void setTransform(sgdVec3 off);
void setTransform(sgdVec3 off, sgMat4 rot);
void setSceneryCenter(sgdVec3 xyz);
private:
//////////////////////////////////////////////////////////////////
// private data //
//////////////////////////////////////////////////////////////////
sgdVec3 _placement_offset;
sgdVec3 _scenery_center;
};
#endif // _SG_LOCATION_HXX
+628
View File
@@ -0,0 +1,628 @@
// non fixed Opengl pipeline rendering
//
// Written by Harald JOHNSEN, started Jully 2005.
//
// Copyright (C) 2005 Harald JOHNSEN
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
//
//
#include <plib/sg.h>
#include <plib/ssg.h>
#include <plib/ul.h>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/screen/extensions.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/screen/shader.h>
#include "animation.hxx"
/*
<animation>
<type>shader</type>
<shader>fresnel</shader>
<object-name>...</object-name>
</animation>
<animation>
<type>shader</type>
<shader>heat-haze</shader>
<object-name>...</object-name>
<speed>...</speed>
<speed-prop>...</speed-prop>
<factor>...</factor>
<factor-prop>...</factor-prop>
</animation>
<animation>
<type>shader</type>
<shader>chrome</shader>
<texture>...</texture>
<object-name>...</object-name>
</animation>
<animation>
<type>shader</type>
<shader></shader>
<object-name>...</object-name>
<depth-test>false</depth-test>
</animation>
*/
static Shader *shFresnel=NULL;
static GLuint texFresnel = 0;
static GLuint texBackground = 0;
static int texBackgroundWidth = 1024, texBackgroundHeight = 1024;
static GLenum texBackgroundTarget = GL_TEXTURE_2D;
static bool isRectangleTextureSupported = false;
static bool istexBackgroundRectangle = false;
static bool initDone = false;
static bool haveBackground = false;
static glActiveTextureProc glActiveTexturePtr = 0;
static double totalTime = 0.0;
static sgMat4 shadIdentMatrix;
static int null_shader_callback( ssgEntity *e ) {
GLuint dlist = 0;
ssgLeaf *leaf = (ssgLeaf *) e;
#ifdef _SSG_USE_DLIST
dlist = leaf->getDListIndex();
if( ! dlist ) {
leaf->makeDList();
dlist = leaf->getDListIndex();
}
#endif
if( ! dlist )
return true;
ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
if ( sst )
sst->apply();
SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
if( ! my_shader->_depth_test )
glDisable( GL_DEPTH_TEST );
glCallList ( dlist ) ;
// restore states
if( ! my_shader->_depth_test )
glEnable( GL_DEPTH_TEST );
// don't draw !
return false;
}
static int heat_haze_shader_callback( ssgEntity *e ) {
GLuint dlist = 0;
ssgLeaf *leaf = (ssgLeaf *) e;
#ifdef _SSG_USE_DLIST
dlist = leaf->getDListIndex();
if( ! dlist ) {
leaf->makeDList();
dlist = leaf->getDListIndex();
}
#endif
if( ! dlist )
return true;
GLint viewport[4];
glGetIntegerv( GL_VIEWPORT, viewport );
const int screen_width = viewport[2];
const int screen_height = viewport[3];
if( ! haveBackground ) {
// store the backbuffer in a texture
if( ! texBackground ) {
// allocate our texture here so we don't waste memory if no model use that effect
// check if we need a rectangle texture and if the card support it
if( (screen_width > 1024 || screen_height > 1024) && isRectangleTextureSupported ) {
// Note that the 3 (same) extensions use the same enumerants
texBackgroundTarget = GL_TEXTURE_RECTANGLE_NV;
istexBackgroundRectangle = true;
texBackgroundWidth = screen_width;
texBackgroundHeight = screen_height;
}
glGenTextures(1, &texBackground);
glEnable(texBackgroundTarget);
glBindTexture(texBackgroundTarget, texBackground);
// trying to match the backbuffer pixel format
GLint internalFormat = GL_RGB8;
GLint colorBits = 0, alphaBits = 0;
glGetIntegerv( GL_BLUE_BITS, &colorBits );
glGetIntegerv( GL_ALPHA_BITS, &alphaBits );
if(colorBits == 5) {
if( alphaBits == 0 )
internalFormat = GL_RGB5;
else
internalFormat = GL_RGB5_A1;
} else {
if( alphaBits != 0 )
internalFormat = GL_RGBA8;
}
glTexImage2D(texBackgroundTarget, 0, internalFormat,
texBackgroundWidth, texBackgroundHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(texBackgroundTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texBackgroundTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(texBackgroundTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(texBackgroundTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glEnable(texBackgroundTarget);
glBindTexture(texBackgroundTarget, texBackground);
// center of texture = center of screen
// obviously we don't have the whole screen if screen_width > texBackgroundWidth
// if rectangle textures are not supported, this give some artifacts on the borders
if( istexBackgroundRectangle ) {
glCopyTexSubImage2D( texBackgroundTarget, 0, 0, 0,
0, 0, texBackgroundWidth, texBackgroundHeight );
} else {
glCopyTexSubImage2D( texBackgroundTarget, 0, 0, 0,
(screen_width - texBackgroundWidth) / 2,
(screen_height - texBackgroundHeight) / 2,
texBackgroundWidth, texBackgroundHeight );
}
haveBackground = true;
glBindTexture(texBackgroundTarget, 0);
glDisable(texBackgroundTarget);
}
ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
if ( sst )
sst->apply();
SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
if( ! my_shader->_depth_test )
glDisable( GL_DEPTH_TEST );
glDepthMask( GL_FALSE );
glDisable( GL_LIGHTING );
if(1) {
// noise texture, tex coord from the model translated by a time factor
glActiveTexturePtr( GL_TEXTURE0_ARB );
glEnable(GL_TEXTURE_2D);
const float noiseDist = fmod(- totalTime * my_shader->_factor * my_shader->_speed, 4.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef( noiseDist, 0.0f, 0.0f );
glMatrixMode(GL_MODELVIEW);
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// background texture
glActiveTexturePtr( GL_TEXTURE1_ARB );
glEnable(texBackgroundTarget);
glBindTexture(texBackgroundTarget, texBackground);
// automatic generation of texture coordinates
// map to screen space
sgMat4 CameraProjM, CameraViewM;
glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *) CameraProjM);
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) CameraViewM);
const float dummy_scale = 1.0f; //0.95f;
const float deltaPos = 0.05f;
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
if( istexBackgroundRectangle ) {
// coords go from 0.0 to n, not from 0.0 to 1.0
glTranslatef( texBackgroundWidth * 0.5f, texBackgroundHeight * 0.5f, 0.0f );
glScalef( texBackgroundWidth * 0.5f,
texBackgroundHeight * 0.5f, 1.0f );
} else {
glTranslatef( 0.5f, 0.5f, 0.0f );
glScalef( float( screen_width ) / float( texBackgroundWidth ) * 0.5f,
float( screen_height ) / float( texBackgroundHeight ) * 0.5f, 1.0f );
}
glMultMatrixf( (GLfloat *) CameraProjM );
glMultMatrixf( (GLfloat *) CameraViewM );
glTranslatef( deltaPos, deltaPos, deltaPos );
glMatrixMode(GL_MODELVIEW);
glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
glTexGenfv( GL_S, GL_EYE_PLANE, shadIdentMatrix[0] );
glTexGenfv( GL_T, GL_EYE_PLANE, shadIdentMatrix[1] );
glTexGenfv( GL_R, GL_EYE_PLANE, shadIdentMatrix[2] );
glTexGenfv( GL_Q, GL_EYE_PLANE, shadIdentMatrix[3] );
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_GEN_T );
glEnable( GL_TEXTURE_GEN_R );
glEnable( GL_TEXTURE_GEN_Q );
sgVec4 enviro = {1.00f, 1.00f, 1.00f, 0.85f};
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, enviro);
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0_ARB);
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PRIMARY_COLOR_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA );
glCallList ( dlist ) ;
glMatrixMode(GL_TEXTURE);
glTranslatef( - deltaPos*2.0f, -deltaPos*2.5f, -deltaPos*2.0f );
glMatrixMode(GL_MODELVIEW);
glCallList ( dlist ) ;
// alter colors only on last rendering
sgVec4 fLight = {0.93f, 0.93f, 1.00f, 0.85f};
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
glMatrixMode(GL_TEXTURE);
glTranslatef( deltaPos*0.7f, deltaPos*1.7f, deltaPos*0.7f );
glMatrixMode(GL_MODELVIEW);
glCallList ( dlist ) ;
glActiveTexturePtr( GL_TEXTURE1_ARB );
glDisable( GL_TEXTURE_GEN_S );
glDisable( GL_TEXTURE_GEN_T );
glDisable( GL_TEXTURE_GEN_R );
glDisable( GL_TEXTURE_GEN_Q );
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glDisable(texBackgroundTarget);
glActiveTexturePtr( GL_TEXTURE0_ARB );
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
// restore states
if( ! my_shader->_depth_test )
glEnable( GL_DEPTH_TEST );
glEnable( GL_LIGHTING );
glDepthMask( GL_TRUE );
if( sst )
sst->force();
// don't draw !
return false;
}
static int fresnel_shader_callback( ssgEntity *e ) {
GLuint dlist = 0;
ssgLeaf *leaf = (ssgLeaf *) e;
#ifdef _SSG_USE_DLIST
dlist = leaf->getDListIndex();
if( ! dlist ) {
leaf->makeDList();
dlist = leaf->getDListIndex();
}
#endif
if( ! dlist )
return true;
ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
if ( sst )
sst->apply();
sgVec4 sunColor, ambientColor;
ssgGetLight( 0 )->getColour(GL_DIFFUSE, sunColor );
ssgGetLight( 0 )->getColour(GL_AMBIENT, ambientColor );
SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
glEnable(GL_BLEND);
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);
if( true ) {
// sgVec4 R = {0.5,0.0,0.0,0.0};
sgVec4 enviro = {1.0,0.0,0.0,1.0};
// sgCopyVec4( enviro, sunColor );
glActiveTexturePtr( GL_TEXTURE0_ARB );
glEnable(GL_TEXTURE_2D);
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glActiveTexturePtr( GL_TEXTURE1_ARB );
glDisable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_1D);
glBindTexture(GL_TEXTURE_1D, texFresnel);
// c = a0 * a2 + a1 * (1-a2)
// glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR );
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, enviro);
shFresnel->enable();
shFresnel->bind();
glCallList ( dlist ) ;
shFresnel->disable();
glActiveTexturePtr( GL_TEXTURE1_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glDisable(GL_TEXTURE_1D);
glActiveTexturePtr( GL_TEXTURE0_ARB );
glDisable(GL_TEXTURE_1D);
glEnable(GL_TEXTURE_2D);
}
// restore states
// glBindTexture(GL_TEXTURE_2D, 0);
// glDepthFunc(GL_LESS);
// glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
if( sst )
sst->force();
// don't draw !
return false;
}
static int chrome_shader_callback( ssgEntity *e ) {
GLuint dlist = 0;
ssgLeaf *leaf = (ssgLeaf *) e;
#ifdef _SSG_USE_DLIST
dlist = leaf->getDListIndex();
if( ! dlist ) {
leaf->makeDList();
dlist = leaf->getDListIndex();
}
#endif
if( ! dlist )
return true;
ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
if ( sst )
sst->apply();
SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
if( ! my_shader->_depth_test )
glDisable( GL_DEPTH_TEST );
GLint maskTexComponent = 3;
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPONENTS, &maskTexComponent);
// The fake env chrome texture
glActiveTexturePtr( GL_TEXTURE1_ARB );
glEnable(GL_TEXTURE_2D);
{
// No lighting is computed in spherical mapping mode because the environment
// is supposed to be allready lighted. We must reshade our environment texture.
sgVec4 sunColor, ambientColor, envColor;
ssgGetLight( 0 )->getColour(GL_DIFFUSE, sunColor );
ssgGetLight( 0 )->getColour(GL_AMBIENT, ambientColor );
sgAddScaledVec3( envColor, ambientColor, sunColor, 0.4f);
glBindTexture(GL_TEXTURE_2D, my_shader->_effectTexture->getHandle());
sgVec3 delta_light;
sgSubVec3(delta_light, envColor, my_shader->_envColor);
if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) {
sgCopyVec3( my_shader->_envColor, envColor );
// reload the texture data and let the driver reshade it for us
glPixelTransferf( GL_RED_SCALE, envColor[0] );
glPixelTransferf( GL_GREEN_SCALE, envColor[1] );
glPixelTransferf( GL_BLUE_SCALE, envColor[2] );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, my_shader->_texWidth, my_shader->_texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, my_shader->_textureData);
glPixelTransferf( GL_RED_SCALE, 1.0f );
glPixelTransferf( GL_GREEN_SCALE, 1.0f );
glPixelTransferf( GL_BLUE_SCALE, 1.0f );
}
}
if( maskTexComponent == 4 ) {
// c = lerp(model tex, chrome tex, model tex alpha)
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_PREVIOUS_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
} else {
// c = chrome tex
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
// automatic generation of texture coordinates
// from normals
glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_GEN_T );
glCallList ( dlist ) ;
glActiveTexturePtr( GL_TEXTURE1_ARB );
glDisable( GL_TEXTURE_GEN_S );
glDisable( GL_TEXTURE_GEN_T );
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexturePtr( GL_TEXTURE0_ARB );
// restore states
if( ! my_shader->_depth_test )
glEnable( GL_DEPTH_TEST );
if( sst )
sst->force();
// don't draw !
return false;
}
static void init_shaders(void) {
Shader::Init();
if( false && Shader::is_VP_supported() ) {
shFresnel = new Shader("/FlightGear/data/Textures/fresnel_vp.txt", "fresnel_vp");
// shFresnel->bindNames("somedata", 0);
}
glActiveTexturePtr = (glActiveTextureProc) SGLookupFunction("glActiveTextureARB");
const int fresnelSize = 512;
unsigned char imageFresnel[ fresnelSize * 3 ];
for(int i = 0; i < fresnelSize; i++) {
const float R0 = 0.2f;
float NdotV = float( i ) / float( fresnelSize );
float f = R0 + (1.0f-R0)*pow(1.0f - NdotV, 5);
unsigned char ff = (unsigned char) (f * 255.0);
imageFresnel[i*3+0] = imageFresnel[i*3+1] = imageFresnel[i*3+2] = ff;
}
glGenTextures( 1, &texFresnel );
glBindTexture(GL_TEXTURE_1D, texFresnel );
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_GENERATE_MIPMAP_SGIS, true);
glTexImage1D(GL_TEXTURE_1D, 0, 3, fresnelSize, 0, GL_RGB, GL_UNSIGNED_BYTE, imageFresnel);
glBindTexture(GL_TEXTURE_1D, 0 );
sgMakeIdentMat4( shadIdentMatrix );
initDone = true;
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGShaderAnimation
////////////////////////////////////////////////////////////////////////
SGShaderAnimation::SGShaderAnimation ( SGPropertyNode *prop_root,
SGPropertyNode_ptr props )
: SGAnimation(props, new ssgBranch),
_condition(0),
_condition_value(true),
_shader_type(0),
_param_1(props->getFloatValue("param", 1.0f)),
_depth_test(props->getBoolValue("depth-test", true)),
_factor(props->getFloatValue("factor", 1.0f)),
_factor_prop(0),
_speed(props->getFloatValue("speed", 1.0f)),
_speed_prop(0),
_effectTexture(0),
_textureData(0),
_texWidth(0),
_texHeight(0)
{
SGPropertyNode_ptr node = props->getChild("condition");
if (node != 0) {
_condition = sgReadCondition(prop_root, node);
_condition_value = false;
}
node = props->getChild("factor-prop");
if( node )
_factor_prop = prop_root->getNode(node->getStringValue(), true);
node = props->getChild("speed-prop");
if( node )
_speed_prop = prop_root->getNode(node->getStringValue(), true);
sgSetVec4(_envColor, 0.0f, 0.0f, 0.0f, 1.0f);
node = props->getChild("texture");
if( node ) {
_effectTexture = ssgGetCurrentOptions()->createTexture( (char *) node->getStringValue(), 0, 0, 0);
glBindTexture(GL_TEXTURE_2D, _effectTexture->getHandle() );
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &_texWidth);
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &_texHeight);
_textureData = new unsigned char[_texWidth * _texHeight * 3];
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, _textureData);
glBindTexture(GL_TEXTURE_2D, 0 );
}
string shader_name = props->getStringValue("shader");
if( shader_name == "fresnel" || shader_name == "reflection" )
_shader_type = 1;
else if( shader_name == "heat-haze" )
_shader_type = 2;
else if( shader_name == "chrome" && _effectTexture)
_shader_type = 3;
}
static void setCallBack(ssgBranch *branch, ssgBase *user_data, ssgCallback cb) {
for (int i = 0; i < branch->getNumKids(); i++) {
ssgEntity *e = branch->getKid(i);
if( e->isAKindOf( ssgTypeBranch() ) )
setCallBack( (ssgBranch *) e, user_data, cb);
else if( e->isAKindOf( ssgTypeVtxTable() ) ) {
e->setCallback( SSG_CALLBACK_PREDRAW, cb );
e->setUserData( user_data );
}
}
}
void SGShaderAnimation::init()
{
if( ! initDone )
init_shaders();
if( _shader_type == 1 && Shader::is_VP_supported() && shFresnel)
setCallBack( getBranch(), (ssgBase *) this, fresnel_shader_callback );
else if( _shader_type == 2 ) {
// this is the same extension with different names
isRectangleTextureSupported = SGIsOpenGLExtensionSupported("GL_EXT_texture_rectangle") ||
SGIsOpenGLExtensionSupported("GL_ARB_texture_rectangle") ||
SGIsOpenGLExtensionSupported("GL_NV_texture_rectangle");
setCallBack( getBranch(), (ssgBase *) this, heat_haze_shader_callback );
}
else if( _shader_type == 3 )
setCallBack( getBranch(), (ssgBase *) this, chrome_shader_callback );
else
setCallBack( getBranch(), (ssgBase *) this, null_shader_callback );
}
SGShaderAnimation::~SGShaderAnimation()
{
delete _condition;
delete _effectTexture;
delete _textureData;
}
int
SGShaderAnimation::update()
{
if (_condition)
_condition_value = _condition->test();
if( _factor_prop)
_factor = _factor_prop->getFloatValue();
if( _speed_prop)
_speed = _speed_prop->getFloatValue();
return 2;
}
void sgShaderFrameInit(double delta_time_sec) {
haveBackground = false;
totalTime += delta_time_sec;
}
File diff suppressed because it is too large Load Diff
+145
View File
@@ -0,0 +1,145 @@
// Shadow volume class
//
// Written by Harald JOHNSEN, started June 2005.
//
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
//
//
#ifndef _SHADOWVOLUME_HXX
#define _SHADOWVOLUME_HXX
#include <plib/sg.h>
#include <vector>
#include <map>
SG_USING_STD(vector);
SG_USING_STD(map);
class ssgBranch;
class ssgLeaf;
class SGPropertyNode;
/**
* A class wich add shadows in a postprocess stage.
*/
class SGShadowVolume {
public:
SGShadowVolume( ssgBranch *root );
~SGShadowVolume();
typedef enum {
occluderTypeAircraft,
occluderTypeAI,
occluderTypeTileObject
} OccluderType;
void init(SGPropertyNode *sim_rendering_options);
void startOfFrame(void);
void addOccluder(ssgBranch *occluder, OccluderType occluder_type, ssgBranch *tile=0);
void deleteOccluder(ssgBranch *occluder);
void deleteOccluderFromTile(ssgBranch *tile);
void setupShadows(double lon, double lat,
double gst, double SunRightAscension, double SunDeclination, double sunAngle );
void endOfFrame(void);
static int ACpostTravCB( ssgEntity *entity, int traversal_mask );
private:
class ShadowCaster
{
public:
typedef struct {
sgVec4 planeEquations;
int neighbourIndices[3];
bool isSilhouetteEdge[3];
bool isFacingLight;
} triData;
ssgBranch *geometry_leaf;
ssgBranch *scenery_object;
ssgBranch *lib_object;
ssgBranch *first_select;
sgVec3 last_lightpos;
sgMat4 last_transform;
int frameNumber;
int *indices;
int numTriangles;
triData *triangles;
sgVec4 * vertices;
GLushort *silhouetteEdgeIndices;
int lastSilhouetteIndicesCount;
bool isTranslucent;
ShadowCaster( int _num_tri, ssgBranch * _geometry_leaf );
~ShadowCaster();
void addLeaf( int & tri_idx, int & ind_idx, ssgLeaf *_geometry_leaf );
void SetConnectivity();
void CalculateSilhouetteEdges(sgVec3 lightPosition);
void DrawInfiniteShadowVolume(sgVec3 lightPosition, bool drawCaps);
void computeShadows(sgMat4 rotation, sgMat4 rotation_translation, OccluderType occluder_type);
void getNetTransform ( ssgBranch * branch, sgMat4 xform );
bool isSelected ( ssgBranch * branch, float dist);
bool sameVertex(int edge1, int edge2);
};
typedef vector<ShadowCaster *> ShadowCaster_list;
class SceneryObject {
public:
SceneryObject(ssgBranch *_scenery_object, OccluderType _occluder_type);
~SceneryObject();
void computeShadows(void);
void traverseTree(ssgBranch *branch);
void find_trans(void);
ssgBranch *scenery_object;
ssgBranch *lib_object;
ssgBranch *pending_object;
ssgBranch *tile;
ShadowCaster_list parts;
OccluderType occluder_type;
};
typedef map<ssgBranch *, SceneryObject *> SceneryObject_map;
private:
void update_light_view(void);
void computeShadows(void);
void cull ( ssgBranch *b, sgFrustum *f, sgMat4 m, int test_needed );
bool shadows_enabled;
bool shadowsAC_enabled, shadowsAI_enabled, shadowsTO_enabled, shadowsDebug_enabled;
bool shadowsAC_transp_enabled;
bool use_alpha;
bool canDoAlpha, canDoStencil;
SGPropertyNode *sim_rendering;
sgVec3 sunPos;
int frameNumber;
int lastTraverseTreeFrame;
sgMat4 CameraViewM;
double sun_angle;
SceneryObject_map sceneryObjects;
ssgBranch *ssg_root;
bool shadows_rendered;
};
#endif // _SHADOWVOLUME_HXX
+8 -4
View File
@@ -1,7 +1,5 @@
includedir = @includedir@/scene/sky
SUBDIRS = clouds3d
lib_LIBRARIES = libsgsky.a
include_HEADERS = \
@@ -11,7 +9,10 @@ include_HEADERS = \
oursun.hxx \
sky.hxx \
sphere.hxx \
stars.hxx
stars.hxx \
bbcache.hxx \
cloudfield.hxx \
newcloud.hxx
libsgsky_a_SOURCES = \
cloud.cxx \
@@ -20,6 +21,9 @@ libsgsky_a_SOURCES = \
oursun.cxx \
sky.cxx \
sphere.cxx \
stars.cxx
stars.cxx \
bbcache.cxx \
cloudfield.cxx \
newcloud.cxx
INCLUDES = -I$(top_srcdir)
+376
View File
@@ -0,0 +1,376 @@
// Billboard helper class
//
// Written by Harald JOHNSEN, started April 2005.
//
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
//
//
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <plib/sg.h>
#include <plib/ssg.h>
#include <simgear/screen/extensions.hxx>
#include <simgear/screen/RenderTexture.h>
#include SG_GLU_H
#include "bbcache.hxx"
/*
memory usage :
size 1 tex 8 tex 32 tex 64 tex
64x64x4 16k 128k 512k 1Mo
128x128x4 64k 512k 2Mo 4Mo
256x256x4 256k 2Mo 8Mo 16Mo
*/
void SGBbCache::freeTextureMemory(void) {
if( bbListCount ) {
for(int i = 0 ; i < bbListCount ; i++) {
bbList[i].cldID = 0;
if(bbList[i].texID)
glDeleteTextures(1, & bbList[i].texID);
}
delete [] bbList;
}
bbListCount = 0;
cacheSizeKb = 0;
textureWH = 0;
}
bool SGBbCache::allocTextureMemory(int cacheCount, int textureDimension) {
textureWH = textureDimension;
bbListCount = cacheCount;
bbList = new bbInfo[bbListCount];
for(int i = 0 ; i < bbListCount ; i++) {
bbList[i].cldID = 0;
bbList[i].texID = 0;
glGenTextures(1, &bbList[i].texID);
glBindTexture(GL_TEXTURE_2D, bbList[i].texID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
textureDimension, textureDimension, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glBindTexture(GL_TEXTURE_2D, 0);
cacheSizeKb = (textureDimension * textureDimension * 4);
cacheSizeKb *= cacheCount;
cacheSizeKb /= 1024;
if(rtAvailable) {
if( rt->BeginCapture() ) {
glViewport(0, 0, textureDimension, textureDimension);
rt->EndCapture();
}
}
return true;
}
SGBbCache::SGBbCache(void) :
bbListCount(0),
cacheSizeKb(0),
textureWH(0),
builtBBCount(0),
rt(0),
rtAvailable(false),
frameNumber(0),
maxImpostorRegenFrame(20)
{
}
SGBbCache::~SGBbCache(void) {
if(rt)
delete rt;
freeTextureMemory();
}
void SGBbCache::init(int cacheCount) {
GLint colorBits = 0;
glGetIntegerv( GL_BLUE_BITS, &colorBits );
rt = new RenderTexture();
// don't use default rtt on nvidia/win because of poor performance of glCopyTexSubImage2D
// wihtout default pattrib params - see opengl forum
if( colorBits < 8 )
rt->Reset("rgba=5,5,5,1 ctt");
else
rt->Reset("rgba ctt");
// rt->Reset("rgba tex2D ctt");
// rt->Reset("rgba tex2D");
if( rt->Initialize(256, 256, true) ) {
SG_LOG(SG_ALL, SG_INFO, "bbcache:Initialize sucessfull");
if (rt->BeginCapture())
{
SG_LOG(SG_ALL, SG_INFO, "bbcache:BeginCapture sucessfull, RTT available");
rtAvailable = true;
glViewport(0, 0, 256, 256);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 1, 1, 5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glDisable(GL_CULL_FACE);
glDisable(GL_FOG);
glDisable(GL_DEPTH_TEST);
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_TEXTURE_2D);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);
glEnable(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
rt->EndCapture();
} else
SG_LOG(SG_ALL, SG_WARN, "bbcache:BeginCapture failed, RTT not available for 3D clouds");
} else
SG_LOG(SG_ALL, SG_WARN, "bbcache:Initialize failed, RTT not available for 3D clouds");
if( cacheCount )
allocTextureMemory( cacheCount, 64 );
}
bool SGBbCache::setCacheSize(int count, int textureDimension) {
if( count < 0 || count > 500)
return false;
freeTextureMemory();
if( count == 0)
return true;
// only allow some reasonable dimensions
switch(textureDimension) {
case 0:
// default size
textureDimension = 256;
break;
case 64:
case 128:
case 256:
break;
case 512:
// rt is 256 so higher texture size has no meaning
textureDimension = 256;
break;
default:
textureDimension = 128;
break;
}
return allocTextureMemory( count, textureDimension);
}
bool SGBbCache::setCacheSize(int sizeKb) {
if( sizeKb < 0 || sizeKb > 256*1024)
return false;
freeTextureMemory();
if( sizeKb == 0)
return true;
int count = 1;
int textureDimension = 256;
if( sizeKb >= 8*1024 ) {
// more than 32 256x256 textures
textureDimension = 256;
} else if( sizeKb >= 2*1024 ) {
// more than 32 128x128 textures
textureDimension = 128;
} else {
// don't go under 64x64 textures
textureDimension = 64;
}
count = (sizeKb * 1024) / (textureDimension * textureDimension * 4);
if(count == 0)
count = 1;
return allocTextureMemory( count, textureDimension);
}
int SGBbCache::queryCacheSize(void) {
return cacheSizeKb;
}
void SGBbCache::free(int bbId, int cldId) {
if( bbId < 0 || bbId >= bbListCount )
return;
if( bbList[bbId].cldID != cldId )
return;
bbList[bbId].cldID = 0;
}
int SGBbCache::alloc(int cldId) {
// pretend we have no more texture if render to texture is not available
if( ! rtAvailable )
return -1;
for(int i = 0 ; i < bbListCount ; i++) {
if( (bbList[i].cldID == 0) && (bbList[i].texID != 0) ) {
bbList[i].cldID = cldId;
bbList[i].angleX = -999;
bbList[i].angleY = -999;
bbList[i].frameUsed = 0;
bbList[i].needRedraw = true;
return i;
}
}
return -1;
}
GLuint SGBbCache::QueryTexID(int cldId, int bbId) {
if( bbId < 0 || bbId >= bbListCount )
return 0;
if( bbList[bbId].cldID != cldId )
return 0;
return bbList[bbId].texID;
}
int SGBbCache::queryImpostorAge(int bbId) {
if( bbId < 0 || bbId >= bbListCount )
return 0;
return frameNumber - bbList[bbId].frame;
}
void SGBbCache::beginCapture(void) {
rt->BeginCapture();
glClear(GL_COLOR_BUFFER_BIT);
}
void SGBbCache::setRadius(float radius, float dist_center) {
float border;
//set viewport to texture resolution
//glViewport(0, 0, 256, 256);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float near_ = dist_center - radius;
float far_ = dist_center + radius;
if( near_ <= 0 ) {
// we are in trouble
glFrustum(-1, 1, -1, 1, 1, 1 + radius * 2);
} else {
border = (near_ * radius) / sqrt(dist_center * dist_center - radius * radius);
glFrustum(-border, border, -border, border, near_, far_);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void SGBbCache::setTextureData(int bbId) {
if( bbId < 0 || bbId >= bbListCount )
return;
glBindTexture(GL_TEXTURE_2D, bbList[bbId].texID);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, textureWH, textureWH);
// bbList[bbId].angleX = angleX;
// bbList[bbId].angleY = angleY;
bbList[bbId].frame = frameNumber;
bbList[bbId].frameUsed = frameNumber;
bbList[bbId].needRedraw = false;
builtBBCount ++;
builtBBframe ++;
}
void SGBbCache::endCapture(void) {
rt->EndCapture();
// glBindTexture(GL_TEXTURE_2D, rt->GetTextureID() );
}
bool SGBbCache::isBbValid( int cldId, int bbId, float angleY, float angleX) {
if( bbId < 0 || bbId >= bbListCount )
return false;
if( bbList[bbId].cldID != cldId )
return false;
// it was just allocated
if( bbList[bbId].frameUsed == 0)
return false;
// we reuse old impostor to speed up things
if( builtBBframe >= maxImpostorRegenFrame )
return true;
if( bbList[bbId].needRedraw )
return false;
// if( fabs(angleY - bbList[bbId].angleY) >= 4.0 )
// return false;
// if( fabs(angleX - bbList[bbId].angleX) >= 4.0 )
// return false;
bbList[bbId].frameUsed = frameNumber;
return true;
}
// TODO:this is not the right way to handle that
void SGBbCache::setReference( int cldId, int bbId, float angleY, float angleX) {
if( bbId < 0 || bbId >= bbListCount )
return;
if( bbList[bbId].cldID != cldId )
return;
bbList[bbId].angleX = angleX;
bbList[bbId].angleY = angleY;
}
void SGBbCache::startNewFrame(void) {
builtBBframe = 0;
// TOTO:find reasonable value
int minFrameNumber = frameNumber - 100;
frameNumber++;
// cleanup of unused enties
for( int bbId = 0 ; bbId < bbListCount ; bbId++)
if( (bbList[bbId].cldID != 0) && (bbList[bbId].frameUsed < minFrameNumber) ) {
// entry is now free
bbList[bbId].cldID = 0;
}
}
// force all impostors to be rebuilt, this will enventually be done over several frames
void SGBbCache::invalidateCache(void) {
for( int bbId = 0 ; bbId < bbListCount ; bbId++)
// bbList[bbId].cldID = 0;
bbList[bbId].needRedraw = true;
}
// flag the impostor for a lazy update
void SGBbCache::invalidate(int cldId, int bbId) {
if( bbId < 0 || bbId >= bbListCount )
return;
if( bbList[bbId].cldID != cldId )
return;
bbList[bbId].needRedraw = true;
}
+206
View File
@@ -0,0 +1,206 @@
// Billboard helper class
//
// Written by Harald JOHNSEN, started April 2005.
//
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
//
//
#ifndef _BBCACHE_HXX
#define _BBCACHE_HXX
#include <plib/sg.h>
#include <plib/ssg.h>
#include <simgear/screen/extensions.hxx>
#include <simgear/screen/RenderTexture.h>
/**
* Billboard helper class.
*/
class SGBbCache {
private:
/**
* storage class for impostors state.
*/
class bbInfo {
public:
/// the texture used by this impostor
GLuint texID;
/// the cloud owning this impostor
int cldID;
float angleX, angleY;
// creation frame number for debug only
int frame;
/// last time this entry was used
int frameUsed;
/// dirty flag for lazy rebuild of impostor
bool needRedraw;
};
void freeTextureMemory(void);
/**
* Allocate and initialize the texture pool.
* @param count the number of texture to build
* @param textureDimension size in pixel of each texture
*/
bool allocTextureMemory(int count, int textureDimension);
// a list of impostors
bbInfo *bbList;
int bbListCount;
int textureWH;
int cacheSizeKb;
// for debug only, stats
int builtBBCount;
// count of generated BB during the current frame
int builtBBframe;
long frameNumber;
RenderTexture *rt;
bool rtAvailable;
public:
SGBbCache(void);
~SGBbCache(void);
/**
* Call this first to initialize the cache.
* @param cacheCount the number of texture to allocate
*/
void init(int cacheCount);
/**
* Free one cache slot, usualy when the cached object is destroyed.
* @param bbId the impostor slot
* @param cldId the cloud identifier
*/
void free(int bbId, int cldId);
/**
* Allocate a new impostor.
* @param cldId the cloud identifier
* @return an impostor slot
*/
int alloc(int cldId);
/**
* Query the texture name associated with this cloud.
* @param bbId the impostor slot
* @param cldId the cloud identifier
* @return a texture name
*/
GLuint QueryTexID(int cldId, int bbId);
/**
* Save the rendered texture from the current context to a new texture.
* @param bbId the impostor slot
*/
void setTextureData(int bbId);
/**
* Start the rendering of a billboard in the RTT context.
*/
void beginCapture(void);
/**
* Adjust the projection matrix of the RTT context to the size of the object.
* @param radius radius in meters of the object to draw
* @param dist_center distance between viewer and object
*/
void setRadius(float radius, float dist_center);
/**
* Forget the RTT and go back to the previous rendering context.
*/
void endCapture(void);
/**
* For debugging only, give the number of frames since the impostor was built.
* @param bbId the impostor slot
*/
int queryImpostorAge(int bbId);
/**
* Can we still use this impostor ? Check versus view angles and load.
* @param bbId the impostor slot
* @param cloudId the cloud identifier
* @param angleY rotation needed to face the impostor
* @param angleX rotation needed to face the impostor
*/
bool isBbValid( int cloudId, int bbId, float angleY, float angleX);
/**
* Save view angles of this billboard.
* @param bbId the impostor slot
* @param cloudId the cloud identifier
* @param angleY rotation needed to face the impostor
* @param angleX rotation needed to face the impostor
*/
void setReference( int cloudId, int bbId, float angleY, float angleX);
/**
* Prepare the cache for the rendering of a new frame.
* Do some garbage collect of unused impostors
*/
void startNewFrame(void);
/**
* Alloc the impostors texture memory given the size of the memory pool.
* If sizeKb == 0 then the memory pool is freed and impostors are disabled
* @param sizeKb size of the texture pool in K
*/
bool setCacheSize(int sizeKb);
/**
* Alloc the impostors texture memory given the count and size of texture.
* If count == 0 then the memory pool is freed and impostors are disabled
* @param count number of texture to allocate
* @param textureDimension size of each texture in pixels
*/
bool setCacheSize(int count, int textureDimension);
bool isRttAvailable(void) { return rtAvailable; }
/**
* Force all impostors to be rebuilt.
*/
void invalidateCache(void);
/**
* Flag the impostor for a lazy update.
* @param bbId the impostor slot
* @param cldId the cloud identifier
*/
void invalidate(int cldId, int bbId);
/**
* Return the size of the memory pool used by texture impostors.
* @return size of the memory pool in Kb
*/
int queryCacheSize(void);
/**
* Maximum number of impostor to regen each frame.
* If we can't update all of them we will do that in the next frame
*/
int maxImpostorRegenFrame;
};
#endif // _BBCACHE_HXX
+11 -8
View File
@@ -21,13 +21,6 @@
// #include <stdio.h>
#include <math.h>
#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
#include <plib/sg.h>
#include <plib/ssg.h>
@@ -39,6 +32,8 @@ inline int (isnan)(double r) { return isnan(r); }
#include <simgear/screen/extensions.hxx>
#include <simgear/screen/texture.hxx>
#include "newcloud.hxx"
#include "cloudfield.hxx"
#include "cloud.hxx"
#if defined(__MINGW32__)
@@ -57,7 +52,7 @@ inline int (isnan)(double r) { return isnan(r); }
static ssgStateSelector *layer_states[SGCloudLayer::SG_MAX_CLOUD_COVERAGES];
static bool state_initialized = false;
static bool bump_mapping = false;
static int nb_texture_unit = 0;
static GLint nb_texture_unit = 0;
static ssgTexture *normal_map[SGCloudLayer::SG_MAX_CLOUD_COVERAGES][2] = { 0 };
static ssgTexture *color_map[SGCloudLayer::SG_MAX_CLOUD_COVERAGES][2] = { 0 };
static GLuint normalization_cube_map;
@@ -221,12 +216,14 @@ SGCloudLayer::SGCloudLayer( const string &tex_path ) :
layer[0] = layer[1] = layer[2] = layer[3] = NULL;
layer_root->addKid(layer_transform);
layer3D = new SGCloudField;
rebuild();
}
// Destructor
SGCloudLayer::~SGCloudLayer()
{
delete layer3D;
delete vertices;
delete indices;
delete layer_root; // deletes layer_transform and layer as well
@@ -460,6 +457,8 @@ SGCloudLayer::rebuild()
layer_states[SG_CLOUD_CLEAR] = 0;
}
SGNewCloud::loadTextures(texture_path.str());
layer3D->buildTestLayer();
}
if ( bump_mapping ) {
@@ -837,6 +836,7 @@ bool SGCloudLayer::reposition( sgVec3 p, sgVec3 up, double lon, double lat,
last_lat = lat;
}
layer3D->reposition( p, up, lon, lat, alt, dt, direction, speed);
return true;
}
@@ -844,6 +844,9 @@ bool SGCloudLayer::reposition( sgVec3 p, sgVec3 up, double lon, double lat,
void SGCloudLayer::draw( bool top ) {
if ( layer_coverage != SG_CLOUD_CLEAR ) {
if ( SGCloudField::enable3D && layer3D->is3D())
layer3D->Render();
else
if ( bump_mapping && enable_bump_mapping ) {
sgMat4 modelview,
+6
View File
@@ -39,6 +39,7 @@ SG_USING_STD(string);
// SG_USING_STD(cout);
// SG_USING_STD(endl);
class SGCloudField;
/**
* A class layer to model a single cloud layer
@@ -183,6 +184,9 @@ public:
static bool enable_bump_mapping;
/** return the 3D layer cloud associated with this 2D layer */
SGCloudField *get_layer3D(void) { return layer3D; }
private:
struct CloudVertex {
@@ -225,6 +229,8 @@ private:
// position, not view position
// double xoff, yoff;
double last_lon, last_lat, last_course;
SGCloudField *layer3D;
};
+493
View File
@@ -0,0 +1,493 @@
// a layer of 3d clouds
//
// Written by Harald JOHNSEN, started April 2005.
//
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
//
//
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>
#include <plib/sg.h>
#include <plib/ssg.h>
#include <simgear/math/sg_random.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/polar3d.hxx>
#include STL_ALGORITHM
#include <vector>
SG_USING_STD(vector);
#include <simgear/environment/visual_enviro.hxx>
#include "sky.hxx"
#include "newcloud.hxx"
#include "cloudfield.hxx"
#if defined(__MINGW32__)
#define isnan(x) _isnan(x)
#endif
#if defined (__FreeBSD__)
# if __FreeBSD_version < 500000
extern "C" {
inline int isnan(double r) { return !(r <= 0 || r >= 0); }
}
# endif
#endif
extern SGSky *thesky;
static list_of_culledCloud inViewClouds;
// visibility distance for clouds in meters
float SGCloudField::CloudVis = 25000.0f;
bool SGCloudField::enable3D = false;
// fieldSize must be > CloudVis or we can destroy the impostor cache
// a cloud must only be seen once or the impostor will be generated for each of his positions
double SGCloudField::fieldSize = 50000.0;
float SGCloudField::density = 100.0;
double SGCloudField::timer_dt = 0.0;
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
static int last_cache_size = 1*1024;
static int cacheResolution = 64;
static sgVec3 last_sunlight={0.0f, 0.0f, 0.0f};
int SGCloudField::get_CacheResolution(void) {
return cacheResolution;
}
void SGCloudField::set_CacheResolution(int resolutionPixels) {
if(cacheResolution == resolutionPixels)
return;
cacheResolution = resolutionPixels;
if(enable3D) {
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
if(count == 0)
count = 1;
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
}
}
int SGCloudField::get_CacheSize(void) {
return SGNewCloud::cldCache->queryCacheSize();
}
void SGCloudField::set_CacheSize(int sizeKb) {
// apply in rendering option dialog
if(last_cache_size == sizeKb)
return;
if(sizeKb == 0)
return;
if(sizeKb)
last_cache_size = sizeKb;
if(enable3D) {
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
if(count == 0)
count = 1;
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
}
}
void SGCloudField::set_CloudVis(float distance) {
if( distance <= fieldSize )
SGCloudField::CloudVis = distance;
}
void SGCloudField::set_density(float density) {
SGCloudField::density = density;
}
void SGCloudField::set_enable3dClouds(bool enable) {
if(enable3D == enable)
return;
enable3D = enable;
if(enable) {
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
if(count == 0)
count = 1;
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
} else {
SGNewCloud::cldCache->setCacheSize(0);
}
}
// reposition the cloud layer at the specified origin and orientation
void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed) {
sgMat4 T1, LON, LAT;
sgVec3 axis;
sgMakeTransMat4( T1, p );
sgSetVec3( axis, 0.0, 0.0, 1.0 );
sgMakeRotMat4( LON, lon * SGD_RADIANS_TO_DEGREES, axis );
sgSetVec3( axis, 0.0, 1.0, 0.0 );
sgMakeRotMat4( LAT, 90.0 - lat * SGD_RADIANS_TO_DEGREES, axis );
sgMat4 TRANSFORM;
sgCopyMat4( TRANSFORM, T1 );
sgPreMultMat4( TRANSFORM, LON );
sgPreMultMat4( TRANSFORM, LAT );
sgCoord layerpos;
sgSetCoord( &layerpos, TRANSFORM );
sgMakeCoordMat4( transform, &layerpos );
this->alt = alt;
// simulate clouds movement from wind
double sp_dist = speed*dt;
if (sp_dist > 0) {
double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
double by = sin((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
relative_position[SG_X] += bx;
relative_position[SG_Y] += by;
}
if ( lon != last_lon || lat != last_lat || sp_dist != 0 ) {
Point3D start( last_lon, last_lat, 0.0 );
Point3D dest( lon, lat, 0.0 );
double course = 0.0, dist = 0.0;
calc_gc_course_dist( dest, start, &course, &dist );
// if start and dest are too close together,
// calc_gc_course_dist() can return a course of "nan". If
// this happens, lets just use the last known good course.
// This is a hack, and it would probably be better to make
// calc_gc_course_dist() more robust.
if ( isnan(course) ) {
course = last_course;
} else {
last_course = course;
}
// calculate cloud movement due to external forces
double ax = 0.0, ay = 0.0;
if (dist > 0.0) {
ax = cos(course) * dist;
ay = sin(course) * dist;
}
deltax += ax;
deltay += ay;
last_lon = lon;
last_lat = lat;
}
// correct the frustum with the right far plane
ssgContext *context = ssgGetCurrentContext();
frustum = *context->getFrustum();
float w, h;
sgEnviro.getFOV( w, h );
frustum.setFOV( w, h );
frustum.setNearFar(1.0, CloudVis);
timer_dt = dt;
}
SGCloudField::SGCloudField() :
draw_in_3d(true),
last_density(0.0),
deltax(0.0),
deltay(0.0),
last_course(0.0)
{
sgSetVec3( relative_position, 0,0,0);
theField.reserve(200);
inViewClouds.reserve(200);
sg_srandom_time_10();
}
SGCloudField::~SGCloudField() {
list_of_Cloud::iterator iCloud;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
delete iCloud->aCloud;
}
theField.clear();
}
void SGCloudField::clear(void) {
list_of_Cloud::iterator iCloud;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
delete iCloud->aCloud;
}
theField.clear();
// force a recompute of density on first redraw
last_density = 0.0;
// true to come back in set density after layer is built
draw_in_3d = true;
}
// use a table or else we see poping when moving the slider...
static int densTable[][10] = {
{0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0},
{1,0,0,0,1,0,0,0,0,0},
{1,0,0,0,1,0,0,1,0,0}, // 30%
{1,0,1,0,1,0,0,1,0,0},
{1,0,1,0,1,0,1,1,0,0}, // 50%
{1,0,1,0,1,0,1,1,0,1},
{1,0,1,1,1,0,1,1,0,1}, // 70%
{1,1,1,1,1,0,1,1,0,1},
{1,1,1,1,1,0,1,1,1,1}, // 90%
{1,1,1,1,1,1,1,1,1,1}
};
// set the visible flag depending on density
void SGCloudField::applyDensity(void) {
int row = (int) (density / 10.0);
int col = 0;
sgBox fieldBox;
list_of_Cloud::iterator iCloud;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
if(++col > 9)
col = 0;
if( densTable[row][col] ) {
iCloud->visible = true;
fieldBox.extend( *iCloud->aCloud->getCenter() );
} else
iCloud->visible = false;
}
last_density = density;
draw_in_3d = ( theField.size() != 0);
sgVec3 center;
sgSubVec3( center, fieldBox.getMax(), fieldBox.getMin() );
sgScaleVec3( center, 0.5f );
center[1] = 0.0f;
field_sphere.setCenter( center );
field_sphere.setRadius( fieldSize * 0.5f * 1.414f );
}
// add one cloud, data is not copied, ownership given
void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
Cloud cl;
cl.aCloud = cloud;
cl.visible = true;
cloud->SetPos( pos );
sgCopyVec3( cl.pos, *cloud->getCenter() );
theField.push_back( cl );
}
static float Rnd(float n) {
return n * (-0.5f + sg_random());
}
// for debug only
// build a field of cloud of size 25x25 km, its a grid of 11x11 clouds
void SGCloudField::buildTestLayer(void) {
const float s = 2250.0f;
for( int z = -5 ; z <= 5 ; z++) {
for( int x = -5 ; x <= 5 ; x++ ) {
SGNewCloud *cloud = new SGNewCloud(SGNewCloud::CLFamilly_cu);
cloud->new_cu();
sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
addCloud(pos, cloud);
}
}
applyDensity();
}
// cull all clouds of a tiled field
void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) {
list_of_Cloud::iterator iCloud;
sgSphere tile_sphere;
tile_sphere.setRadius( field_sphere.getRadius() );
sgVec3 tile_center;
sgSubVec3( tile_center, field_sphere.getCenter(), eyePos );
tile_sphere.setCenter( tile_center );
tile_sphere.orthoXform(mat);
if( frustum.contains( & tile_sphere ) == SG_OUTSIDE )
return;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
sgVec3 dist;
sgSphere sphere;
if( ! iCloud->visible )
continue;
sgSubVec3( dist, iCloud->pos, eyePos );
sphere.setCenter(dist[0], dist[2], dist[1] + eyePos[1]);
float radius = iCloud->aCloud->getRadius();
sphere.setRadius(radius);
sphere.orthoXform(mat);
if( frustum.contains( & sphere ) != SG_OUTSIDE ) {
float squareDist = dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2];
culledCloud tmp;
tmp.aCloud = iCloud->aCloud;
sgCopyVec3( tmp.eyePos, eyePos );
// save distance for later sort, opposite distance because we want back to front
tmp.dist = - squareDist;
tmp.heading = -SG_PI/2.0 - atan2( dist[0], dist[2] ); // + SG_PI;
tmp.alt = iCloud->pos[1];
inViewClouds.push_back(tmp);
if( squareDist - radius*radius < 100*100 )
sgEnviro.set_view_in_cloud(true);
}
}
}
// Render a cloud field
// because no field can have an infinite size (and we don't want to reach his border)
// we draw this field and adjacent fields.
// adjacent fields are not real, its the same field displaced by some offset
void SGCloudField::Render(void) {
sgVec3 eyePos;
double relx, rely;
if( ! enable3D )
return;
if( last_density != density ) {
last_density = density;
applyDensity();
}
if( ! draw_in_3d )
return;
if( ! SGNewCloud::cldCache->isRttAvailable() )
return;
inViewClouds.clear();
glPushMatrix();
sgMat4 modelview, tmp, invtrans;
// try to find the sun position
sgTransposeNegateMat4( invtrans, transform );
sgVec3 lightVec;
ssgGetLight( 0 )->getPosition( lightVec );
sgXformVec3( lightVec, invtrans );
sgSetVec3( SGNewCloud::modelSunDir, lightVec[0], lightVec[2], lightVec[1]);
// try to find the lighting data (not accurate)
sgVec4 diffuse, ambient;
ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse );
ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient );
// sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 1.0f);
sgScaleVec3 ( SGNewCloud::ambLight, ambient , 1.1f);
// trying something else : clouds are more yellow/red at dawn/dusk
// and added a bit of blue ambient
float *sun_color = thesky->get_sun_color();
sgScaleVec3 ( SGNewCloud::sunlight, sun_color , 0.4f);
SGNewCloud::ambLight[2] += 0.1f;
sgVec3 delta_light;
sgSubVec3(delta_light, last_sunlight, SGNewCloud::sunlight);
if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) {
sgCopyVec3( last_sunlight, SGNewCloud::sunlight );
// force the redraw of all the impostors
SGNewCloud::cldCache->invalidateCache();
}
// voodoo things on the matrix stack
ssgGetModelviewMatrix( modelview );
sgCopyMat4( tmp, transform );
sgPostMultMat4( tmp, modelview );
// cloud fields are tiled on the flat earth
// compute the position in the tile
relx = fmod( deltax + relative_position[SG_X], fieldSize );
rely = fmod( deltay + relative_position[SG_Y], fieldSize );
relx = fmod( relx + fieldSize, fieldSize );
rely = fmod( rely + fieldSize, fieldSize );
sgSetVec3( eyePos, relx, alt, rely);
sgSetVec3( view_X, tmp[0][0], tmp[1][0], tmp[2][0] );
sgSetVec3( view_Y, tmp[0][1], tmp[1][1], tmp[2][1] );
sgSetVec3( view_vec, tmp[0][2], tmp[1][2], tmp[2][2] );
ssgLoadModelviewMatrix( tmp );
/* flat earth
^
|
| FFF
| FoF
| FFF
|
O----------->
o = we are here
F = adjacent fields
*/
for(int x = -1 ; x <= 1 ; x++)
for(int y = -1 ; y <= 1 ; y++ ) {
sgVec3 fieldPos;
// pretend we are not where we are
sgSetVec3(fieldPos, eyePos[0] + x*fieldSize, eyePos[1], eyePos[2] + y*fieldSize);
cullClouds(fieldPos, tmp);
}
// sort all visible clouds back to front (because of transparency)
std::sort( inViewClouds.begin(), inViewClouds.end() );
// TODO:push states
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthMask( GL_FALSE );
glEnable(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_TEXTURE_2D );
glDisable( GL_FOG );
glDisable(GL_LIGHTING);
// test data: field = 11x11 cloud, 9 fields
// depending on position and view direction, perhaps 40 to 60 clouds not culled
list_of_culledCloud::iterator iCloud;
for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) {
// iCloud->aCloud->drawContainers();
iCloud->aCloud->Render(iCloud->eyePos);
sgEnviro.callback_cloud(iCloud->heading, iCloud->alt,
iCloud->aCloud->getRadius(), iCloud->aCloud->getFamilly(), - iCloud->dist, iCloud->aCloud->getId());
}
glBindTexture(GL_TEXTURE_2D, 0);
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
glEnable( GL_FOG );
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
ssgLoadModelviewMatrix( modelview );
glPopMatrix();
}
+128
View File
@@ -0,0 +1,128 @@
// a layer of 3d clouds
//
// Written by Harald JOHNSEN, started April 2005.
//
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
//
//
#ifndef _CLOUDFIELD_HXX
#define _CLOUDFIELD_HXX
#include <plib/sg.h>
#include <simgear/compiler.h>
#include <vector>
SG_USING_STD(vector);
class SGNewCloud;
class culledCloud {
public:
SGNewCloud *aCloud;
sgVec3 eyePos;
float dist;
float heading;
float alt;
bool operator<(const culledCloud &b) const {
return (this->dist < b.dist);
}
};
typedef vector<culledCloud> list_of_culledCloud;
/**
* A layer of 3D clouds.
*/
class SGCloudField {
private:
class Cloud {
public:
SGNewCloud *aCloud;
sgVec3 pos;
bool visible;
};
typedef vector<Cloud> list_of_Cloud;
// cull all clouds of a tiled field
void cullClouds(sgVec3 eyePos, sgMat4 mat);
void applyDensity(void);
list_of_Cloud theField;
// this is a relative position only, with that we can move all clouds at once
sgVec3 relative_position;
// double lon, lat;
sgFrustum frustum;
sgMat4 transform;
double deltax, deltay, alt;
double last_lon, last_lat, last_course;
sgSphere field_sphere;
float last_density;
bool draw_in_3d;
public:
SGCloudField();
~SGCloudField();
void clear(void);
// add one cloud, data is not copied, ownership given
void addCloud( sgVec3 pos, SGNewCloud *cloud);
// for debug only
void buildTestLayer(void);
// Render a cloud field
void Render(void);
// reposition the cloud layer at the specified origin and orientation
void reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed);
bool is3D(void) { return draw_in_3d; }
// visibility distance for clouds in meters
static float CloudVis;
static sgVec3 view_vec, view_X, view_Y;
static float density;
static double timer_dt;
static double fieldSize;
static bool enable3D;
// return the size of the memory pool used by texture impostors
static int get_CacheSize(void);
static int get_CacheResolution(void);
static float get_CloudVis(void) { return CloudVis; }
static float get_density(void) { return density; }
static bool get_enable3dClouds(void) { return enable3D; }
static void set_CacheSize(int sizeKb);
static void set_CacheResolution(int resolutionPixels);
static void set_CloudVis(float distance);
static void set_density(float density);
static void set_enable3dClouds(bool enable);
};
#endif // _CLOUDFIELD_HXX
-3
View File
@@ -1,3 +0,0 @@
.deps
Makefile
Makefile.in
-54
View File
@@ -1,54 +0,0 @@
includedir = @includedir@/scene/sky/clouds3d
# enable the following line once extgl.c get's added to the distro
EXTRA_DIST = extgl.c extgl.h
if EXTGL_NEEDED
EXTGL_SOURCE = extgl.c extgl.h
else
EXTGL_SOURCE =
endif
lib_LIBRARIES = libsgclouds3d.a
include_HEADERS = \
SkySceneLoader.hpp \
SkyUtil.hpp
libsgclouds3d_a_SOURCES = \
$(EXTGL_SOURCE) \
vec3fv.cpp vec3fv.hpp vec3f.hpp vec4f.hpp vec2f.hpp \
mat16fv.cpp mat16fv.hpp \
mat33.hpp mat33impl.hpp \
mat44.hpp mat44impl.hpp \
tri.cpp tri.hpp \
plane.cpp plane.hpp \
camera.cpp camera.hpp \
camutils.cpp camutils.hpp \
glut_shapes.c glut_shapes.h \
minmaxbox.cpp minmaxbox.hpp \
SkyAABBTree.hpp \
SkyArchive.cpp SkyArchive.hpp \
SkyBoundingVolume.hpp \
SkyBVTree.hpp SkyBVTreeSplitter.hpp \
SkyCloud.cpp SkyCloud.hpp \
SkyCloudParticle.hpp \
SkyContext.cpp SkyContext.hpp \
SkyDynamicTextureManager.cpp SkyDynamicTextureManager.hpp \
SkyLight.cpp SkyLight.hpp \
SkyMaterial.cpp SkyMaterial.hpp \
SkyMinMaxBox.cpp SkyMinMaxBox.hpp \
SkyRenderable.hpp \
SkyRenderableInstance.hpp \
SkyRenderableInstanceCloud.cpp SkyRenderableInstanceCloud.hpp \
SkyRenderableInstanceGeneric.hpp \
SkyRenderableInstanceGroup.cpp SkyRenderableInstanceGroup.hpp \
SkySceneLoader.cpp \
SkySceneManager.cpp SkySceneManager.hpp \
SkySingleton.hpp \
SkyTexture.hpp \
SkyTextureManager.cpp SkyTextureManager.hpp \
SkyTextureState.cpp SkyTextureState.hpp \
SkyUtil.cpp
INCLUDES = -I$(top_srcdir)
@@ -1,19 +0,0 @@
//============================================================================
// File : SkyAABBTree.hpp
//
// Author : Wesley Hunt
//
// Content : axis-aligned bounding box tree
//
//============================================================================
#ifndef __SKYAABBTREE_HPP__
#define __SKYAABBTREE_HPP__
#include "SkyBVTree.hpp"
#include "SkyBVTreeSplitter.hpp"
template <class object>
class SkyAABBTree : public SkyBVTree<object, SkyMinMaxBox, SkyAABBTreeSplitter<object> >
{};
#endif //__SKYAABBTREE_HPP__
File diff suppressed because it is too large Load Diff
-243
View File
@@ -1,243 +0,0 @@
//------------------------------------------------------------------------------
// File : SkyArchive.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyArchive.hpp
*
* A hierarchical archive Class for storing data.
*/
#ifndef __SKYARCHIVE_HPP__
#define __SKYARCHIVE_HPP__
// #pragma warning( disable : 4786 )
#include "vec2f.hpp"
#include "vec3f.hpp"
#include "vec4f.hpp"
#include "SkyUtil.hpp"
#include <map> // for std::multimap
//! Types supported by the archive system
enum SkyArchiveTypeCode
{
BOOL_TYPE,
INT8_TYPE,
INT16_TYPE,
INT32_TYPE,
UINT8_TYPE,
UINT16_TYPE,
UINT32_TYPE,
FLOAT32_TYPE,
FLOAT64_TYPE,
STRING_TYPE,
VEC2F_TYPE,
VEC3F_TYPE,
VEC4F_TYPE,
ARCHIVE_TYPE,
ANY_TYPE,
NULL_TYPE
};
struct SkyArchiveEntry;
struct StringLessFunctor
{
bool operator() (const char* p1, const char* p2) const
{
return ::strcmp( p1, p2) < 0;
}
};
//============================================================================
//
// Class : SkyArchive
//
//! A simple hierarchical archive file useful for loading and saving data.
//
/*! SkyArchive bundles information so that an application can store,
manipulate, and retrieve data in a storage-independent manner. Information
stored in an SkyArchive file can be modified without breaking
compatibility with the code that retrieves the data. In essence, it can be
thought of as a very basic database mechanism.
A SkyArchive is simply a container. The class defines methods that allow
you to put information in a SkyArchive, determine the information in a
SkyArchive, and retrieve information from a SkyArchive. It's important
to note that the SkyArchive is a recursive storage mechanism; a
SkyArchive itself can hold one or more other SkyArchives.
Data are added to an archive in fields. The datum in a field is associated
with a name, number of bytes, and a type code. The name can be anything you
choose and is not required to be unique. The number of bytes must be accurate.
The type code must be one of the SkyArchiveTypeCode enums. Several of the Add
functions have been specialized for the common base types. It isn't necessary
to provide the number of bytes when using the specialized functions, since it can be
inferred from the type code.
The functions that retrieve fields from an archive are similar to the ones
that add data, only their roles are reversed. As with the Add functions,
there are several specialized functions for the common base types while
custom information can be retrieved using the generic FindData function.
Querying the contents of an archive is provided through the GetInfo
functions. These functions are important as they allow you to write
code that can intelligently determine how to retrieve information at
run-time: you no longer have to hardcode the order in which you retrieve
data from your files.
archive data fields are held in using an STL multimap. The multimap key
is a QString (field name) and the data is held in a SkyArchiveEntry
structure (see SkyArchive.cpp for details of this structure).
The fields are stored in alphabetical order based on the key names.
*/
class SkyArchive
{
public:
//=========================================================================
// Creation & Destruction
//=========================================================================
// Empty archive: no name, no data fields.
SkyArchive();
// Creates a named archive with no data fields.
SkyArchive( const char* pName);
// Deep copy the contents of one archive to another.
SkyArchive( const SkyArchive& src);
// Deep copy the contents of one archive to another.
SkyArchive& operator=( const SkyArchive& src);
~SkyArchive();
//=========================================================================
// Basic SkyArchive Information
//=========================================================================
// Returns true if the archive contains no data fields.
bool IsEmpty() const;
//! Returns the archive's name.
const char* GetName() const { return _pName; };
//=========================================================================
// Adding Content to SkyArchive
//=========================================================================
// Adds a new datafield to the archive.
SKYRESULT AddData(const char* pName,
SkyArchiveTypeCode eType,
const void* pData,
unsigned int iNumBytes,
unsigned int iNumItems = 1);
SKYRESULT AddBool( const char* pName, bool aBool);
SKYRESULT AddInt8( const char* pName, char anInt8);
SKYRESULT AddInt16( const char* pName, short anInt16);
SKYRESULT AddInt32( const char* pName, int anInt32);
SKYRESULT AddUInt8( const char* pName, unsigned char anUInt8);
SKYRESULT AddUInt16( const char* pName, unsigned short anUInt16);
SKYRESULT AddUInt32( const char* pName, unsigned int anUInt32);
SKYRESULT AddFloat32( const char* pName, float aFloat32);
SKYRESULT AddFloat64( const char* pName, double aFloat64);
SKYRESULT AddString( const char* pName, const char* pString);
SKYRESULT AddArchive( const SkyArchive& anArchive);
// Vector types (MJH:: only supports float versions for now!!!)
SKYRESULT AddVec2f( const char* pName, const Vec2f& aPoint2f);
SKYRESULT AddVec3f( const char* pName, const Vec3f& aPoint3f);
SKYRESULT AddVec4f( const char* pName, const Vec4f& aPoint4f);
//=========================================================================
// Retrieving Content from SkyArchive
//=========================================================================
// Retrieves the specified datafield the archive, if it exists.
SKYRESULT FindData( const char* pName,
SkyArchiveTypeCode eType,
void** const pData,
unsigned int* pNumBytes,
unsigned int index = 0) const;
SKYRESULT FindBool( const char* pName, bool* pBool, unsigned int index = 0) const;
SKYRESULT FindInt8( const char* pName, char* pInt8, unsigned int index = 0) const;
SKYRESULT FindInt16( const char* pName, short* pInt16, unsigned int index = 0) const;
SKYRESULT FindInt32( const char* pName, int* pInt32, unsigned int index = 0) const;
SKYRESULT FindUInt8( const char* pName, unsigned char* pUInt8, unsigned int index = 0) const;
SKYRESULT FindUInt16( const char* pName, unsigned short* pUInt16, unsigned int index = 0) const;
SKYRESULT FindUInt32( const char* pName, unsigned int* pUInt32, unsigned int index = 0) const;
SKYRESULT FindFloat32(const char* pName, float* pFloat32, unsigned int index = 0) const;
SKYRESULT FindFloat64(const char* pName, double* pFloat64, unsigned int index = 0) const;
SKYRESULT FindString( const char* pName, char** const pString, unsigned int index = 0) const;
SKYRESULT FindArchive(const char* pName, SkyArchive* pArchive, unsigned int index = 0) const;
SKYRESULT FindVec2f( const char* pName, Vec2f* pVec2f, unsigned int index = 0) const;
SKYRESULT FindVec3f( const char* pName, Vec3f* pVec3f, unsigned int index = 0) const;
SKYRESULT FindVec4f( const char* pName, Vec4f* pVec4f, unsigned int index = 0) const;
SKYRESULT AccessArchive(const char* pName, SkyArchive** pArchive, unsigned int index = 0) const;
//=========================================================================
// Querying Contents of SkyArchive
//=========================================================================
// Computes the number of fields that contain the given name and type.
SKYRESULT GetInfo(const char* pName,
SkyArchiveTypeCode eType,
unsigned int* pNumFound = NULL) const;
// Returns information about the key at the specified index.
SKYRESULT GetInfo(unsigned int iNameIndex,
char** pNameFound,
SkyArchiveTypeCode* pTypeCode,
unsigned int* pNumFound);
// Computes the number of unique key names in _dataTableable.
unsigned int GetNumUniqueNames() const;
// Remove the contents of the SkyArchive.
SKYRESULT MakeEmpty();
// Loads the contents from a file.
SKYRESULT Load(const char* pFileName);
// Commits the contents of a SkyArchive to file storage.
SKYRESULT Save(const char* pFileName) const;
private:
char* _pName; // this archive's name
//=========================================================================
// Data storage
//=========================================================================
typedef std::multimap<char*, SkyArchiveEntry*, StringLessFunctor> SkyArchiveMMap;
typedef SkyArchiveMMap::const_iterator SkyMMapConstIter;
typedef SkyArchiveMMap::iterator SkyMMapIter;
SkyArchiveMMap _dataTable; // this is where the data reside.
// Performs a deep-copy of one archive's archive_mmap_t to another.
void _CopyDataTable( const SkyArchiveMMap& src);
// Locates an archive entry in _dataTable
const SkyArchiveEntry* _FindEntry( const char* pName,
unsigned int index,
SkyArchiveTypeCode eType) const;
// Saves the archive to a file stream.
SKYRESULT _Save(FILE* pDestFile) const;
// Initializes the archive from a file stream.
SKYRESULT _Load(FILE* pSrcFile);
};
#endif //__SKYARCHIVE_HPP__
-297
View File
@@ -1,297 +0,0 @@
//------------------------------------------------------------------------------
// File : SkyBVTree.hpp
//------------------------------------------------------------------------------
// Empyrean / SkyWorks : Copyright 2002 Mark J. Harris
//------------------------------------------------------------------------------
/**
* @file SkyBVTree.hpp
*
* This source was written by Wesley Hunt. Many thanks to him for providing it.
*/
//-----------------------------------------------------------------------------
// SkyBVTree.hpp
//
// Author: Wesley Hunt (hunt@cs.unc.edu)
// Date: 2000/12/19
//-----------------------------------------------------------------------------
// Overview
// --------
// declare an SkyBVTree with whatever object type and bounding volume type you
// want. The hard part is to pass in a NodeSplitter class that determines how
// to split a node up. See below for a description of its requirements.
// Finally, use that tree like so:
// * BeginTree()
// * AddObject(Object, ObjectBV)
// * ...
// * EndTree()
// < Do whatever you want with GetRoot() >
// < Use GetLeftChild() and GetRightChild() to traverse the nodes >
//
// The class hierarchy is designed for a flexible, simple public interface.
// This pushes some extra complexity into the class hierarchy, but there are two
// main advantages to the final approach:
// 1. There are no interface requirements for the Object and BoundingVolume
// template parameters. This means you don't have to modify your existing
// class interfaces to use them with the tree.
// 2. All the dependent logic for dealing with the bounding volumes is pushed
// into the NodeSplitter class. So there is one centralized location for
// adapting your bounding volume classes to work with the tree. See the
// description of the NodeSplitter template requirements for more details.
//
// Class Descriptions
// ------------------
//
// SkyBaseBVTree
// -------------
// declares the node class that the tree holds. It exposes
// the public functions of the nodes and defines protected accessors that
// the derived tree class can use to manipulate nodes and build the tree.
//
// Node
// ----
// This is the class that gives access to the tree. You can access each
// object and bounding volume owned by a node, along with that node's
// children.
//
// NodeObject
// ----------------
// An aggregation of an object and its associated bounding volume.
// Each node in the tree essentially owns an array of NodeObjects. This
// array is passed to the NodeSplitter class to allow it to examine a
// node's contained objects before making a decision on how to split the
// node up.
//
// SkyBVTree
// ---------
// The main tree class. To use it, supply and object type, a bounding volume
// type, and a NodeSplitter class that is used to split the nodes up during
// tree construction.
//
// Template class requirements
// ---------------------------
//
// Object
// ------
// None
//
// BoundingVolume
// --------------
// None
//
// NodeSplitter
// ------------
// This is the user-supplied class that decides how to split a node during
// tree construction. It is given an array of NodeObjects that the node owns and
// is responsible for determining the node's bounding volume as well as how to
// split the node up into left and right children.
// The required API is as follows:
//
// * a constructor that takes an array of NodeObject and an unsigned int giving
// the size of the array. These are the objects owned by the node to be split.
// * a method GetNodeBV() that returns the BoundingVolume of the node.
// Typically this is the union of the bounding volumes of the objects owned
// by the node.
// * A unary function operator used to partition the objects in the node. The
// operator must take a single NodeObject as a parameter and return as
// a bool whether to place the NodeObject in the left or right child.
// Basically, it should be compatible with std::partition using NodeObjects.
// * A binary function operator used to sort the objects. If a partition fails,
// the nodes are then sorted based on this function and half are sent to each child.
// This operator must define a total ordering of the NodeObjects.
// Basically, it should be compatible with std::sort using NodeObjects.
//
// Example:
// struct NodeSplitter
// {
// NodeSplitter(const NodeObject* objs, unsigned int numObjs);
// BoundingVolume& GetNodeBV() const;
// // Partition predicate
// bool operator()(const NodeObject& obj) const;
// // Sort predicate
// bool operator()(const NodeObject& obj1, const NodeObject& obj2) const;
// };
//
//-----------------------------------------------------------------------------
#ifndef __SKYBVTREE_HPP__
#define __SKYBVTREE_HPP__
#include <algorithm>
#include <vector>
//-----------------------------------------------------------------------------
// SkyBaseBVTree<Object, BoundingVolume>
//-----------------------------------------------------------------------------
// See header description for details.
//-----------------------------------------------------------------------------
template <class Object, class BoundingVolume>
class SkyBaseBVTree
{
public:
typedef BoundingVolume BV;
class NodeObject;
public:
class Node
{
friend class SkyBaseBVTree<Object, BoundingVolume>;
public:
Node() : _pObjs(NULL), _iNumObjs(0) {}
Node(NodeObject* pObjs, unsigned int iNumObjs) : _pObjs(pObjs), _iNumObjs(iNumObjs) {}
// Public interface
const Object& GetObj(unsigned int index) const { assert(_iNumObjs != 0 && _pObjs != NULL && index < _iNumObjs); return _pObjs[index].GetObj(); }
const BV& GetBV(unsigned int index) const { assert(_iNumObjs != 0 && _pObjs != NULL && index < _iNumObjs); return _pObjs[index].GetBV(); }
unsigned int GetNumObjs() const { assert(_iNumObjs != 0 && _pObjs != NULL); return _iNumObjs; }
const BV& GetNodeBV() const { assert(_iNumObjs != 0 && _pObjs != NULL); return _volume; }
const Node* GetLeftChild() const { assert(_iNumObjs != 0 && _pObjs != NULL); return this+1; }
const Node* GetRightChild() const { assert(_iNumObjs != 0 && _pObjs != NULL); return this+(GetLeftChild()->GetNumObjs()<<1); }
bool IsLeaf() const { assert(_iNumObjs != 0 && _pObjs != NULL); return _iNumObjs == 1; }
private:
// List of Objects owned by the node
NodeObject *_pObjs;
unsigned int _iNumObjs;
BV _volume;
};
public:
class NodeObject
{
public:
NodeObject(const Object& o, const BV& v) : _obj(o), _volume(v) {}
const Object& GetObj() const { return _obj; }
const BV& GetBV() const { return _volume; }
private:
Object _obj;
BV _volume;
};
protected:
// Give non-const access to the node for descendant classes to build the tree
BV& GetNodeBV(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode->_volume; }
Node* GetLeftChild(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode+1; }
Node* GetRightChild(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode+(GetLeftChild(pNode)->GetNumObjs()<<1); }
NodeObject* GetObjs(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode->_pObjs; }
// Links a node's children by assigning the given number of objects to each child
// assumes the node has already had it's objects partitioned
void LinkNodeChildren(Node* pNode, unsigned int iLeftNumObjs)
{
assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL);
GetLeftChild(pNode)->_pObjs = pNode->_pObjs;
GetLeftChild(pNode)->_iNumObjs = iLeftNumObjs;
GetRightChild(pNode)->_pObjs = pNode->_pObjs + iLeftNumObjs;
GetRightChild(pNode)->_iNumObjs = pNode->_iNumObjs - iLeftNumObjs;
}
};
//------------------------------------------------------------------------------
// Function : ClearVector
// Description :
//------------------------------------------------------------------------------
/**
* @fn ClearVector(std::vector<T>& vec)
* @brief This utility function uses the std::vector::swap trick to free the memory of a vector
*
* This is necessary since clear() doesn't actually free anything.
*/
template<class T>
void ClearVector(std::vector<T>& vec)
{
std::vector<T>().swap(vec);
}
//-----------------------------------------------------------------------------
// SkyBVTree<Object, BoundingVolume, NodeSplitter>
//-----------------------------------------------------------------------------
// See header description for details.
//-----------------------------------------------------------------------------
template <class Object, class BoundingVolume, class NodeSplitter>
class SkyBVTree : public SkyBaseBVTree<Object, BoundingVolume>
{
public:
typedef SkyBaseBVTree<Object, BoundingVolume> BaseTree;
typedef typename SkyBaseBVTree<Object, BoundingVolume>::BV BV;
typedef typename BaseTree::NodeObject NodeObject;
typedef typename BaseTree::Node Node;
void Clear()
{
BeginTree();
}
void BeginTree(unsigned int iNumObjs = 0)
{
ClearVector(_objList);
ClearVector(_nodes);
if (iNumObjs > 0) _objList.reserve(iNumObjs);
}
void AddObject(const Object &obj, const BV& volume)
{
_objList.push_back(NodeObject(obj, volume));
}
void EndTree()
{
if (_objList.size() == 0) return;
// Initialize the root node with all the objects
_nodes.push_back(Node(&_objList[0], _objList.size()));
// create room for the other nodes. They are initialized in BuildTree().
_nodes.reserve(_objList.size()*2-1);
_nodes.resize(_objList.size()*2-1);
BuildTree(&_nodes[0]);
}
const Node *GetRoot() const { return _nodes.empty() ? NULL : &_nodes[0]; }
// Memory usage info
unsigned int CalcMemUsage() const
{
unsigned int usage = 0;
usage += sizeof(*this);
usage += _objList.capacity() * sizeof(_objList[0]);
usage += _nodes.capacity() * sizeof(_nodes[0]);
return usage;
}
public:
private:
// Does the real work
void BuildTree(Node *pCurNode)
{
int iLeftNumObjs;
{
// Initialize the node splitter with the current node
NodeSplitter splitter(GetObjs(pCurNode), pCurNode->GetNumObjs());
// set the node's bounding volume using the splitter
GetNodeBV(pCurNode) = splitter.GetNodeBV();
// When a node has one object we can stop
if (pCurNode->GetNumObjs() == 1) return;
// Try and partition the objects
iLeftNumObjs = std::partition(GetObjs(pCurNode), &GetObjs(pCurNode)[pCurNode->GetNumObjs()], splitter) - GetObjs(pCurNode);
if ((iLeftNumObjs == 0) || (iLeftNumObjs == pCurNode->GetNumObjs()))
{
// Partition failed. Sort and split again to force a complete tree
std::sort(GetObjs(pCurNode), &GetObjs(pCurNode)[pCurNode->GetNumObjs()], splitter);
iLeftNumObjs = pCurNode->GetNumObjs() / 2;
}
}
LinkNodeChildren(pCurNode, iLeftNumObjs);
BuildTree(GetLeftChild(pCurNode));
BuildTree(GetRightChild(pCurNode));
}
std::vector<Node> _nodes;
std::vector<NodeObject> _objList;
};
#endif //__SKYBVTREE_HPP__
@@ -1,242 +0,0 @@
//============================================================================
// File : SkyBVTreeSplitter.hpp
//
// Author : Wesley Hunt
//
// Content : NodeSplitter classes for SkyBVTrees using SkyBoundingBox or
// SkyBoundingSphere (not implemented).
//
//============================================================================
#ifndef __SKYBVTREESPLITTER_HPP__
#define __SKYBVTREESPLITTER_HPP__
//----------------------------------------------------------------------------
//-- Includes ----------------------------------------------------------------
//----------------------------------------------------------------------------
#include "SkyBVTree.hpp"
#include "SkyMinMaxBox.hpp"
//#include <Mlx/MlxBoundingSphere.hpp>
//#if _MSC_VER == 1200
//#include <Auxlib/AuxCompileTimeChecker.hpp>
//#endif
//----------------------------------------------------------------------------
//-- Forward Declarations ----------------------------------------------------
//----------------------------------------------------------------------------
// A strategy for splitting nodes compatible with bounding boxes and spheres.
template<class Object> class SkyBoundingBoxSplitter;
// SkyBVTree compatible node splitters implemented using the above strategy.
template<class Object> class SkyAABBTreeSplitter;
//template<class Object> class SkySphereTreeSplitter;
//----------------------------------------------------------------------------
//-- Defines, Constants, Enumerated Types ------------------------------------
//----------------------------------------------------------------------------
const float rLongObjectPercentageTolerance = 0.75f;
//----------------------------------------------------------------------------
// SkyBoundingBoxSplitter
//----------------------------------------------------------------------------
// This class defines a NodeSplitter strategy that has the functionality
// required by SkyBVTree's NodeSplitter template class. Can be used with
// SkyMinMaxBox and SkyBoundingSphere.
//
// It defines a two-tiered split strategy:
//
// * First it tries to separate large objects from any smaller objects.
// * If there are no large objects, it splits along the midpoint of the longest
// axis defined by the objects.
// * Finally, if all else fails, it defines a total ordering along the longest
// axis based on the center of each node.
//----------------------------------------------------------------------------
template<class Object>
class SkyBoundingBoxSplitter
{
public:
typedef typename SkyBaseBVTree<Object, SkyMinMaxBox>::NodeObject NodeObjectBox;
//typedef SkyBaseBVTree<Object, SkyBoundingSphere>::NodeObject NodeObjectSphere;
#if _MSC_VER == 1200
// !!! WRH HACK MSVC++6 SP5 Workaround.
// VC6 can't disambiguate this constructor because it doesn't consider the two
// NodeObject templates to be different classes for the purposes of
// overloading. It won't recognize that the second template parameters are
// different. Forcing them to be explicit template specializations fixes
// the problem.
template<class BV>
SkyBoundingBoxSplitter(const SkyBaseBVTree<Object, BV>::NodeObject*, unsigned int)
{
//AUX_STATIC_CHECK(false, VisualC_6_WorkAround); ???
}
template<>
#endif
SkyBoundingBoxSplitter(const NodeObjectBox* pObjs, unsigned int iNumObjs)
{
for (unsigned int i = 0; i < iNumObjs; ++i)
{
_nodeBBox.Union(pObjs[i].GetBV());
}
Init(pObjs, iNumObjs);
}
/*#if _MSC_VER == 1200
template<>
#endif
SkyBoundingBoxSplitter(const NodeObjectSphere* objs,
#ifdef _PLATFORM_XBOX
Int32
#else
UInt32
#endif
numObjs)
{
for (int i=0; i<numObjs; ++i)
{
SkyMinMaxBox box;
box.AddPoint(objs[i].GetBV().GetCenter());
box.Bloat(objs[i].GetBV().GetRadius());
_nodeBBox.Union(box);
}
Init(objs, numObjs);
}*/
template<class nodeObj>
bool SplitLeft(const nodeObj& obj) const
{
if (_bIsolateLongObjects)
return GetSplitAxisLength(obj.GetBV()) < _rMaxObjectLength;
else
return GetSplitAxisCenter(obj.GetBV()) < _rSplitValue;
}
template<class nodeObj>
bool LessThan(const nodeObj& obj1, const nodeObj& obj2) const
{
return GetSplitAxisCenter(obj1.GetBV()) < GetSplitAxisCenter(obj2.GetBV());
}
const SkyMinMaxBox& GetNodeBBox() const { return _nodeBBox; }
private:
template<class nodeObj>
void Init(const nodeObj* pObjs, unsigned int iNumObjs)
{
_iSplitAxis = FindSplitAxis(_nodeBBox);
_rSplitValue = FindSplitValue(_nodeBBox, _iSplitAxis);
_rMaxObjectLength = GetSplitAxisLength(_nodeBBox) * rLongObjectPercentageTolerance;
_bIsolateLongObjects = false;
for (unsigned int i = 0; i < iNumObjs; ++i)
{
if (GetSplitAxisLength(pObjs[i].GetBV()) > _rMaxObjectLength)
{
_bIsolateLongObjects = true;
break;
}
}
}
int FindSplitAxis(const SkyMinMaxBox& bbox)
{
int iAxis = 0, i;
Vec3f vecExt = bbox.GetMax() - bbox.GetMin();
for (i = 1; i < 3; ++i) if (vecExt[i] > vecExt[iAxis]) iAxis = i;
return iAxis;
}
float FindSplitValue(const SkyMinMaxBox& bbox, int iSplitAxis)
{
return (bbox.GetMin()[iSplitAxis] + bbox.GetMax()[iSplitAxis])*0.5f;
}
/*float GetSplitAxisLength(const SkyBoundingSphere& sphere) const
{
return 2.f*sphere.GetRadius();
}*/
float GetSplitAxisLength(const SkyMinMaxBox& bbox) const
{
return bbox.GetMax()[_iSplitAxis] - bbox.GetMin()[_iSplitAxis];
}
float GetSplitAxisCenter(const SkyMinMaxBox& bbox) const
{
return (bbox.GetMin()[_iSplitAxis] + bbox.GetMax()[_iSplitAxis]) * 0.5f;
}
/*float GetSplitAxisCenter(const SkyBoundingSphere& sphere) const
{
return sphere.GetCenter()[SplitAxis];
}*/
int _iSplitAxis;
float _rSplitValue;
bool _bIsolateLongObjects;
float _rMaxObjectLength;
SkyMinMaxBox _nodeBBox;
};
//----------------------------------------------------------------------------
// SkyAABBTreeSplitter
//----------------------------------------------------------------------------
// A NodeSplitter that is compatible with SkyBVTree for SkyMinMaxBox.
// Implemented using the SkyBoundingBoxSplitter strategy.
//----------------------------------------------------------------------------
template<class Object>
class SkyAABBTreeSplitter
{
public:
typedef SkyMinMaxBox BV;
typedef typename SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
SkyAABBTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs) {}
const BV& GetNodeBV() const { return _splitter.GetNodeBBox(); }
bool operator()(const NodeObject& obj) const
{
return _splitter.SplitLeft(obj);
}
bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
{
return _splitter.LessThan(obj1, obj2);
}
private:
SkyBoundingBoxSplitter<Object> _splitter;
};
//----------------------------------------------------------------------------
// SkySphereTreeSplitter
//----------------------------------------------------------------------------
// A NodeSplitter that is compatible with SkyBVTree for SkyBoundingSphere.
// Implemented using the SkyBoundingBoxSplitter strategy.
//----------------------------------------------------------------------------
/*template<class Object>
class SkySphereTreeSplitter
{
public:
typedef SkyBoundingSphere BV;
typedef SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
MlxSphereTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs)
{
_nodeBV = pObjs[0].GetBV();
for (unsigned int i = 1; i < iNumObjs; ++i) _nodeBV.Union(pObjs[i].GetBV());
}
const BV& GetNodeBV() const { return _nodeBV; }
bool operator()(const NodeObject& obj) const
{
return _splitter.SplitLeft(obj);
}
bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
{
return _splitter.LessThan(obj1, obj2);
}
private:
BV _nodeBV;
SkyBoundingBoxSplitter<Object> _splitter;
};*/
#endif //__SKYBVTREESPLITTER_HPP__
@@ -1,151 +0,0 @@
//------------------------------------------------------------------------------
// File : SkyBoundingVolume.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyBoundingVolume.hpp
*
* Base class interface definition for a bounding volume.
*/
#ifndef __SKYBOUNDINGVOLUME_HPP__
#define __SKYBOUNDINGVOLUME_HPP__
#include "vec3f.hpp"
#include "mat44.hpp"
// forward to reduce unnecessary dependencies
class Camera;
//------------------------------------------------------------------------------
/**
* @class SkyBoundingVolume
* @brief An abstract base class for bounding volumes (AABB,OBB,Sphere,etc.)
*
* This base class maintains a center and a radius, so it is effectively a bounding
* sphere. Derived classes may represent other types of bounding volumes, but they
* should be sure to update the radius and center, because some objects will treat
* all bounding volumes as spheres.
*
*/
class SkyBoundingVolume
{
public:
//! Constructor
SkyBoundingVolume() : _vecCenter(0, 0, 0), _rRadius(0) {}
//! Destructor
virtual ~SkyBoundingVolume() {}
//------------------------------------------------------------------------------
// Function : SetCenter
// Description :
//------------------------------------------------------------------------------
/**
* @fn SetCenter(const Vec3f &center)
* @brief Sets the center of the bounding volume.
*/
virtual void SetCenter(const Vec3f &center) { _vecCenter = center; }
//------------------------------------------------------------------------------
// Function : SetRadius
// Description :
//------------------------------------------------------------------------------
/**
* @fn SetRadius(float radius)
* @brief Sets the radius of the bounding volume.
*/
virtual void SetRadius(float radius) { _rRadius = radius; }
//------------------------------------------------------------------------------
// Function : Vec3f& GetCenter
// Description :
//------------------------------------------------------------------------------
/**
* @fn Vec3f& GetCenter() const
* @brief Returns the center of the bounding volume.
*/
virtual const Vec3f& GetCenter() const { return _vecCenter; }
//------------------------------------------------------------------------------
// Function : GetRadius
// Description :
//------------------------------------------------------------------------------
/**
* @fn GetRadius() const
* @brief Returns the radius ofthe bounding volume.
*/
virtual float GetRadius() const { return _rRadius; }
//------------------------------------------------------------------------------
// Function : ViewFrustumCull
// Description :
//------------------------------------------------------------------------------
/**
* @fn ViewFrustumCull( const Camera &cam, const Mat44f &mat )
* @brief Cull a bounding volume.
*
* Returns false if the bounding volume is entirely outside the camera's frustum,
* true otherwise.
*/
virtual bool ViewFrustumCull( const Camera &cam, const Mat44f &mat ) = 0;
//------------------------------------------------------------------------------
// Function : AddPoint
// Description :
//------------------------------------------------------------------------------
/*
* @fn AddPoint( const Vec3f &pt )
* @brief Add a point to a bounding volume.
*
* One way to create a bounding volume is to add points. What should/could happen
* is that the BV will store an object space BV and then when a call to SetPosition
* is called, the stored values will be transformed and stored separately, so that
* the original values always exist.
*
*/
//virtual void AddPoint( const Vec3f &point ) = 0;
//------------------------------------------------------------------------------
// Function : AddPoint
// Description :
//------------------------------------------------------------------------------
/*
* @fn AddPoint( float x, float y, float z )
* @brief Add a point to a bounding volume.
*
* @see AddPoint(const Vec3f &pt)
*/
//virtual void AddPoint( float x, float y, float z ) = 0;
//------------------------------------------------------------------------------
// Function : Clear
// Description :
//------------------------------------------------------------------------------
/*
* @fn Clear()
* @brief Clear all data from the bounding volume.
*/
//virtual void Clear() = 0;
protected:
Vec3f _vecCenter;
float _rRadius;
};
#endif //__SKYBOUNDINGVOLUME_HPP__

Some files were not shown because too many files have changed in this diff Show More