Compare commits

...

326 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 Frhlich:
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 Frhlich:
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 Frhlich:
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 Frhlich:
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 Frhlich:
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
curt
3b6af2f0c2 Ready for 0.3.8 release. 2005-01-18 14:34:13 +00:00
curt
5bdff41641 Require plib-1.8.4 2005-01-17 21:48:05 +00:00
ehofman
67e9d105cb Use the double precission pow() function to get Solaris compiling. 2005-01-16 08:52:22 +00:00
ehofman
f1fc99f16f Solaris fix 2005-01-15 14:24:28 +00:00
ehofman
f89e359d53 Solaris fix. 2005-01-15 14:22:56 +00:00
ehofman
77ec170a50 MingW/MSYS fix 2005-01-15 14:18:30 +00:00
ehofman
34320f5f20 Eliminate some compiler warnings about converting float to int. 2005-01-15 11:57:34 +00:00
ehofman
a26271e46e Add a make_bumpmap and a make_maxcolorwindow function, modify the make_normalmap function to maximize the color window before proceding. 2005-01-15 10:48:40 +00:00
ehofman
e2e7466250 Add support for contrast. 2005-01-14 15:52:56 +00:00
ehofman
1e24cc4643 little endian fixes. 2005-01-14 14:27:57 +00:00
ehofman
dfc23c3528 Add a make_grayscale function and call it from make_normalmap automatically, removing the need to do it make_grayscale prior to calling make_normalmap. 2005-01-14 13:36:38 +00:00
ehofman
cd11a5dc27 Fix a mistake. 2005-01-14 13:12:44 +00:00
ehofman
899734296b Add a function to calculate the normalmap from a regular texture. 2005-01-14 13:08:57 +00:00
ehofman
7a3a81c152 RGBA textures can be made monochrome also 2005-01-14 10:12:00 +00:00
ehofman
e62a4a05ac Fix a few bugs and add a make_monochrome() function 2005-01-14 10:09:21 +00:00
ehofman
463ca207ce Some small updates to the saving code. 2005-01-13 18:35:56 +00:00
ehofman
da6e1b31ea Fix a crash situation. 2005-01-13 18:05:46 +00:00
ehofman
8c783b1680 Update the code a bit more, add a function to retreive the last error string and add a function to write SGI texture fils. 2005-01-13 14:47:31 +00:00
curt
efce88ff12 - Fix a couple oops's in cloud.cxx
- In sky.cxx blend low density cloud layers (few/scattered) into nothing (but
  don't touch visibility distance) as we approach them so we can fly through
  clean.
- For high density cloud layers (broken/overcast) we do not fade the layers
  out, but we fade visibility to nearly nothing as we approach the layer.
2005-01-11 16:02:39 +00:00
curt
01608b7e18 Add a method to SGCloudLayer to set overall cloud alpha. This gives us the
capability to slowly fade a cloud layer in or out.

We use this effect in combination with lowering visibility as we approach
a cloud layer to hide the fact that it is simply a 2d textured polygon being
drawn across the sky.
2005-01-11 15:21:58 +00:00
david
a5f0e0395a Do not reduce visibility when passing through a 'few' or 'scattered'
cloud layer (i.e. <50% coverage).  This is a quick hack rather than a
proper fix, but it will at least make it possible to get above a
scattered layer VFR.
2005-01-10 23:34:52 +00:00
ehofman
0b723174fd Add support for binding a thread to a specific CPU (IRIX only at this time). 2005-01-09 10:24:54 +00:00
ehofman
5d248bf0df Frederic Bouvier:
It comes to me that the bulk of all problem reports, especially from Windows users, have it's cause in an obsolete sound driver. These messages should direct them to the right solution before complaining.
2005-01-08 11:47:19 +00:00
curt
c039ccdeb0 Updates for 0.3.8-pre2 release. 2005-01-03 19:05:32 +00:00
ehofman
d88fb32a73 Melchior FRANZ:
My recent fix for the load/save fgfs.sav feature was a bit too ambitious.
While aliases lead to abortion before, I tried to copy them properly,
although this wasn't a requirement. Unfortunately, this seems to have
worked for absolute aliases only, not for relative ones, and hence broke
several panel instruments. The attached patch backs most of the previous
patch out again, and goes a simpler route: just ignore aliases.
2004-12-23 13:32:01 +00:00
ehofman
37ac409586 Melchior FRANZ:
fgLoadFlight() loads a property file ("fgfs.sav") to a new property tree,
and then copies that over to the main tree. copyProperties() didn't know
how to handle type SGPropertyNode::ALIAS and hence threw an exception that
made fgfs abort.

The attached patch adds support for ALIAS to copyProperties(): aliased
nodes are created in the target tree if necessary, and then linked like in
the source tree. It seemed useful to add an optional argument to
props.[ch]xx/getType() that would indeed return the property type "ALIAS"
for aliased nodes, and not the type of the node that it refers to. The patch
also fixes a bug in writeNode() that caused extra lines after alias entries.

If there's resistance to the change to getType() (David?) I can easily use
isAlias(). This just makes copyProperties() a tad uglier, but I can live with
it. It's useful for scanning a tree, though, if an alias node can be treated
exactly like all other nodes, without automatic redirection.
2004-12-19 10:19:14 +00:00
ehofman
7b24e94c66 gcc 4.0 fix. 2004-12-18 10:53:54 +00:00
ehofman
e12cd2a50c Initialize volume to inaudiable at startup. 2004-12-16 13:15:13 +00:00
curt
98b2ba4fc1 More prerelease updates. 2004-12-15 16:45:57 +00:00
curt
2f0afdccc1 Prerelease updates. 2004-12-15 16:34:14 +00:00
ehofman
79734df554 Threads detection code cleanup and FreeBSD fixes. 2004-12-13 20:31:44 +00:00
ehofman
c52657fa1a This was too quick, now pthreads isn't detected on IRIX (and other platforms?) anymore. This needs some more thought. 2004-12-08 15:12:11 +00:00
ehofman
9cac8409cd FreeBSD fix. 2004-12-08 15:00:45 +00:00
ehofman
18703ce02d AIX fix 2004-12-05 09:36:49 +00:00
curt
709a166bd6 Oops, 2nd try ... 2004-12-02 15:08:54 +00:00
curt
8048e6297c Martin Spott: Revised handling of missing isnan() on earlier versions of
FreeBSD.
2004-12-02 15:00:26 +00:00
curt
fb0dded103 Fix a typo for the Mac OSX platform. 2004-12-01 17:37:43 +00:00
curt
055e969e7a Fix a dumb bug. 2004-11-21 21:46:02 +00:00
curt
f10db8a30e Fix a dumb bug for FreeBSD. 2004-11-21 21:45:35 +00:00
ehofman
c19af3525e Melchior FRANZ:
At last I've found the reason why fgfs crashed routinely for me. When I still
used KDE's artsdsp (preloads lib with OSS replacement functions) I saw
this crash only occasionally. After letting OpenAl communicate with artsd
directly (by means of ~/.openalrc setting), I got the crash always when
I left fgfs.

This bug may also have crashed fgfs when running with sound daemons other than
aRts.
2004-11-21 17:05:42 +00:00
curt
7c60ccfc35 I don't understand why FreeBSD doesn't see isnan() after including math.h
but it doesn't.  Trying the apple approach to fixing isnan results in an
infinite loop (making me wonder what happens on OSX?)  This is an alternative
approach to checking isnan() on freebsd ...
2004-11-21 03:13:54 +00:00
curt
84cba33aab FreeBSD fix. 2004-11-20 19:11:08 +00:00
ehofman
a52b1ec64f MSVC fix. 2004-11-20 12:35:28 +00:00
curt
f30c4720ae Update a few more instances of my email address. 2004-11-19 21:47:05 +00:00
curt
7fc8c02688 My old email address is no longer valid ... point to my web page. 2004-11-19 21:44:16 +00:00
curt
54a7a0d534 Ooops, fix an unintentional line wrap. 2004-11-18 19:12:17 +00:00
curt
8d73160a75 Abstract out location of gl.h, glut.h, and glu.h includes so that we can
make the Mac platform happy since they put these in a different place compared
to the rest of the world.
2004-11-18 19:10:34 +00:00
andy
ff10602c65 Make sure that timer delay values are positive-definite, otherwise
user code that wants to use zero delay to mean "next frame" will get
stuck in an infinite loop.
2004-11-17 19:37:45 +00:00
ehofman
ca50fe386d Roy Vegard Ovesen:
I've added two new debug log types for the instrumentation and systems. They
used to use the autopilot debug log, because I couldn't figure out how to
make new log types. Well, now I have figured it out.  ;-)
2004-10-24 09:29:56 +00:00
ehofman
39f3c6e41d Frederic Bouvier:
This is a patch to make display list usage optional. They are on by default.
Use --prop:/sim/rendering/use-display-list=false to use immediate mode.
There is also a change in exception handling in main.cxx and bootstrap.cxx
2004-10-17 17:06:50 +00:00
ehofman
ba1b96e518 Roy Vegard Ovesen:
I'm working on a route manager in the GPS module. So I've added a name
parameter to the waypoint class in Simgear. I use the existing ID parameter
to store the ID, for example KLAX, and the name parameter to store the name,
San Francisco Intl.
2004-10-16 12:23:53 +00:00
ehofman
ef486b2cc6 Remove the refference to fgsg 2004-10-14 13:35:11 +00:00
curt
06f3cb4f8e Fix a couple bugs in openal detection. I should actually generate a new
configure and test it, rather than testing the old configure script.
2004-10-13 20:18:35 +00:00
curt
074f5ff996 Oops, missed a part of the previous change. 2004-10-13 19:52:13 +00:00
curt
8c26f32d5f Add a sanity check for the existance of OpenAL. If not there, bail from
the configure script with an appropriate/helpful message.
2004-10-13 19:51:38 +00:00
curt
9a2ee54389 Final 0.3.7 changes. 2004-10-12 14:35:42 +00:00
ehofman
ab69c03698 Fix a typo. 2004-10-11 07:56:08 +00:00
ehofman
fab1f4e7a0 Frederic: Ignore display lists when using the blend animation. 2004-10-11 07:37:42 +00:00
ehofman
41eed484c1 Adding the panel was a step too far for Linux, causing a segfault. 2004-10-10 19:38:46 +00:00
ehofman
7d18f9bdde Remove a phantom makeDList call (probably an old one from my code. 2004-10-10 19:16:25 +00:00
ehofman
3a48c3de7a Check for the plib version when using display lists, just to be sure. 2004-10-10 19:05:25 +00:00
ehofman
d769a9936b Frederic: Include FGPanelNode in the display list generation process. 2004-10-10 18:43:11 +00:00
ehofman
1697cb3b1a Frederic: Use display lists for 3d models also. 2004-10-10 17:49:27 +00:00
ehofman
62aa32a417 Reverse the declaration order. jpgRenderFrame (formerly known as trRenderFrame) is now declared as a NULL function pointer and assignment of the proper function is now done in FlightGear (jpgRenderFrame=FGRenderer::update). 2004-10-06 09:57:31 +00:00
ehofman
a0d0852838 David Luff:
The one-liner removes a lot of re-definition warnings on Cygwin.
2004-09-30 09:43:11 +00:00
ehofman
2f479cae69 Small update for future use. 2004-09-19 09:08:12 +00:00
curt
4820d57fa8 Expose the size() method for locked and blocking thread queues. 2004-09-15 15:28:58 +00:00
curt
04e3b0b3c1 Fix another case where the direction vector is not initialized which can
lead to openal "inrange" assertions, crashing FlightGear.
2004-09-15 15:28:14 +00:00
curt
a7f78b9f68 direction vector needs to be initialized, otherwise garbage data could cause
openal to generate an assertion, aborting the top level app.
2004-09-10 20:44:42 +00:00
curt
f3d8eb4665 Tweaks for 0.3.7-pre1 2004-09-10 18:16:06 +00:00
curt
090f79b951 Add support for parsing an xml stream from an in memory buffer, rather than
just from a specified file name.
2004-09-10 15:57:52 +00:00
ehofman
88c0dbf661 Add support for audio orientation: direction and cone definition. This currently only works for internal view and tower view because those set the listener position correctly. 2004-09-08 11:15:57 +00:00
ehofman
9e3822ceaf Remove a left over of ancient times. 2004-08-19 12:18:20 +00:00
ehofman
007b0a8fe6 this simple patch will enable the direct use of Point3D::get_n() instead of making duplications to call sgCartToGeod 2004-08-17 08:31:51 +00:00
ehofman
7f0ebf8871 this simple patch will prevent to have fog in Clear cload layers. 2004-08-17 08:28:35 +00:00
ehofman
5414e94a1a change the log level of the initialization of OpenAL. This prevent a console popup for no reason on Windows. 2004-08-15 09:24:12 +00:00
curt
461dee8657 Tweaks for official 0.3.6 release. 2004-07-29 21:36:41 +00:00
ehofman
297b6193fe Make gcc 2.95.* compile again. 2004-07-29 08:30:10 +00:00
ehofman
4b74e40a5f Use the SimGear default notation. 2004-07-28 14:13:16 +00:00
ehofman
5a9b08dec2 IRIX fixes (at least). 2004-07-28 13:59:57 +00:00
ehofman
5e6f9f79a2 IRIX fix (at least). 2004-07-28 13:16:54 +00:00
curt
e2f93e6ae1 Tweaks for 0.3.6-pre3 2004-07-27 21:18:14 +00:00
curt
93314b59fb Fix a minor warning message. 2004-07-24 19:21:15 +00:00
ehofman
29269c6686 Correct a typo that produces segfault during cleanup on some systems. 2004-07-22 08:04:18 +00:00
curt
3c84b6e2f6 Tweaks for 0.3.6-pre2 2004-07-21 21:22:21 +00:00
ehofman
04fb708543 Frederic Bouvier:
I just discovered this : state() is not valid when _level==0,
because it is doing:
{ return _state_stack[_state_stack.size() - 1]; }
and is returning a wrong index fetch ( 0 - 1 ) == -1

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

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

2. banner is not available on windows, only cygwin

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

The xml syntax, with default values, is :

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

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

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

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

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

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

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

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

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

View File

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

View File

@@ -22,7 +22,7 @@ PROJECT_NAME = SimGear
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 0.3.5
PROJECT_NUMBER = 0.3.9
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.

View File

@@ -1,9 +1,8 @@
EXTRA_DIST = \
acinclude.m4 \
autogen.sh \
DoxygenMain.cxx
DoxygenMain.cxx \
README.MSVC \
README.metakit \
README.zlib \
SimGear.dsp \
SimGear.dsw
@@ -11,7 +10,7 @@ EXTRA_DIST = \
SUBDIRS = src-libs simgear
dist-hook:
(cd $(top_srcdir); $(HOME)/projects/FlightGear-0.9/admin/am2dsp.pl)
(cd $(top_srcdir); $(HOME)/Projects/FlightGear/admin/am2dsp.pl)
#
# Rule to build RPM distribution package

97
NEWS
View File

@@ -1,5 +1,82 @@
New in 0.3.5.pre2
* March 23, 2004
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 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.
* Added two new debug output types for instrumentation and systems.
* Add a name parameter to the waypoint class for supporting a route
manager in the flightgear gps module.
* Make display list usage optional.
* Event manager: specifying a zero delay will force event execution in
the next frame rather than entering an infinite loop.
* gcc-4.0 fix.
* Fixes to property tree loading and saving.
* Make volume inaudible at startup.
* Solaris fixes.
* 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.
* Better error message for sound problems.
* Add support for binding a thread to a specific CPU.
New in 0.3.7
* October 12, 2004
* Add support for parsing xml from an in memory buffer, not just a file.
* Don't reduce visibility for a "clear" cloud layer.
* Add support for audio orientation (direction and cone) for internal
view and tower view.
* Add support for drawing from display lists rather than in immediate mode.
This provides a big performance improvement on many systems.
New in 0.3.6
* July 29, 2004
* Better MinGW support
* A bit better handling of OpenAL under Cygwin
* Switched audio system from plib's "sl/sm" to OpenAL.
* Add support for scaling an object based on distance. The scaling
factor is determined by a lookup table based on distance.
* Add a "flash" animation type.
* Fix cloud positioning/animation bugs.
* Fix an off-by-one error in props_io.cxx
* Clip audio gain (volume) to 1.0
New in 0.3.5
* March 26, 2004
* Added Andy's nasal interpreter for small built in scripting tasks.
Nasal integrates nicely with FlightGear's property system.
@@ -8,7 +85,7 @@ New in 0.3.5.pre2
* 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.
@@ -59,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.
@@ -104,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.
@@ -114,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.
@@ -134,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
@@ -185,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.
@@ -228,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
@@ -319,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

12
README.OpenAL Normal file
View File

@@ -0,0 +1,12 @@
[This file is mirrored in both the FlightGear and SimGear packages.]
You *must* have the development components of OpenAL installed on your system
to build FlightGear!" You can get a copy here:
http://www.openal.org
Build notes:
The OpenAL developers do not make "versioned" releases so we recommend that
you pull the latest version via anonymous CVS (follow the instructions at
the OpenAL web site) and build/install that.

File diff suppressed because it is too large Load Diff

4
Thanks
View File

@@ -90,7 +90,7 @@ David Megginson <david@megginson.com>
SimGear property manager/registry
Curt Olson <curt@flightgear.org>
Curt Olson http://www.flightgear.org/~curt/
Curt is responsible for overall project and source code management.
He has his hands in many of the areas.
@@ -175,7 +175,7 @@ NOTE:
----
THIS DOCUMENT WAS INITIALLY WRITTEN BY
Curt L. Olson <curt@flightgear.org>
Curt L. Olson <http://www.flightgear.org/~curt>
05 Jul 2000 Removed non-SimGear entries (CLO)

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

View File

@@ -1,7 +1,5 @@
dnl Process this file with autoget.sh to produce a working configure
dnl script.
dnl
dnl $Id$
AC_INIT
AC_CONFIG_SRCDIR([simgear/bucket/newbucket.cxx])
@@ -10,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.5.pre2)
AM_INIT_AUTOMAKE(SimGear, 0.3.9)
dnl Specify KAI C++ compiler and flags.
dnl Borrowed with slight modification from blitz distribution.
@@ -123,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
;;
@@ -165,33 +163,18 @@ dnl Checks for libraries.
dnl Thread related checks
AC_CHECK_HEADER(pthread.h)
AC_CHECK_LIB(pthread, pthread_exit)
if test "x$ac_cv_lib_pthread_pthread_exit" = "xyes" -a "x$ac_cv_header_pthread_h" = "xyes"; then
AC_SEARCH_LIBS(pthread_exit, [pthread c_r])
if test "x$ac_cv_header_pthread_h" = "xyes"; then
CXXFLAGS="$CXXFLAGS -D_REENTRANT"
CFLAGS="$CFLAGS -D_REENTRANT"
fi
if test "x$ac_cv_lib_pthread_pthread_exit" != "xyes" -a "x$ac_cv_header_pthread_h" = "xyes"; then
dnl FreeBSD: System has pthread.h, but -lpthread library check
dnl fails. See if we need -pthread instead of -lpthread and look
dnl for the functions in libc_r.
save_CXXFLAGS="$CXXFLAGS"
save_CFLAGS="$CFLAGS"
if test "x$ac_cv_search_pthread_exit" = "x-lc_r"; then
CXXFLAGS="-pthread $CXXFLAGS"
CFLAGS="-pthread $FLAGS"
save_LIBS=$LIBS
AC_CHECK_LIB(c_r, pthread_exit)
if test "x$ac_cv_lib_c_r_pthread_exit" != "xyes"; then
CXXFLAGS=$save_CXXFLAGS
CFLAGS=$save_CFLAGS
else
dnl This is cheating a bit. pthread_exit comes with using -pthread, not
-lpthread
ac_cv_lib_pthread_pthread_exit="yes"
fi
LIBS=$save_LIBS
CFLAGS="-pthread $CFLAGS"
fi
fi
AM_CONDITIONAL(HAVE_THREADS, test "x$ac_cv_lib_pthread_pthread_exit" = "xyes" -a "x$ac_cv_header_pthread_h" = "xyes")
AM_CONDITIONAL(HAVE_THREADS, test "x$ac_cv_header_pthread_h" = "xyes")
thread_LIBS="$LIBS"
LIBS=""
@@ -270,7 +253,58 @@ esac
opengl_LIBS="$LIBS"
LIBS="$base_LIBS"
dnl check for OpenAL libraries
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"
openal_LIBS="$LIBS"
OPENAL_OK="$ac_cv_search_alGenBuffers"
;;
*-apple-darwin*)
dnl Mac OS X
LIBS="$LIBS -framework IOKit -framework OpenAL"
openal_LIBS="$LIBS"
# not sure how to test if OpenAL exists on MacOS (does it come by default?)
OPENAL_OK="yes"
;;
*)
dnl default unix style machines
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
;;
esac
if test "$OPENAL_OK" == "no"; then
echo
echo "You *must* have the openal library installed on your system to build"
echo "SimGear!"
echo
echo "Please see README.OpenAL for more details."
echo
echo "configure aborted."
exit
fi
LIBS="$base_LIBS"
AC_SUBST(base_LIBS)
AC_SUBST(openal_LIBS)
AC_SUBST(opengl_LIBS)
AC_SUBST(thread_LIBS)
AC_SUBST(network_LIBS)
@@ -297,11 +331,11 @@ if test "x$ac_cv_header_plib_ul_h" != "xyes"; then
exit
fi
AC_MSG_CHECKING([for plib 1.6.0 or newer])
AC_MSG_CHECKING([for plib 1.8.4 or newer])
AC_TRY_RUN([
#include <plib/ul.h>
#define MIN_PLIB_VERSION 160
#define MIN_PLIB_VERSION 184
int main() {
int major, minor, micro;
@@ -316,7 +350,7 @@ int main() {
],
AC_MSG_RESULT(yes),
[AC_MSG_RESULT(wrong version);
AC_MSG_ERROR([Install plib 1.6.0 or later first...])],
AC_MSG_ERROR([Install plib 1.8.4 or later first...])],
AC_MSG_RESULT(yes)
)
@@ -392,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 \
@@ -400,7 +433,6 @@ AC_CONFIG_FILES([ \
simgear/structure/Makefile \
simgear/threads/Makefile \
simgear/timing/Makefile \
simgear/xgl/Makefile \
simgear/xml/Makefile \
])
AC_OUTPUT
@@ -427,7 +459,7 @@ else
echo "Without JPEG Factory support"
fi
if test "x$ac_cv_lib_pthread_pthread_exit" = "xyes" -a "x$ac_cv_header_pthread_h" = "xyes"; then
if test "x$ac_cv_header_pthread_h" = "xyes"; then
echo "Threads: pthread lib found."
else
echo "Threads: no threads (pthread lib not found.)"

View File

@@ -32,7 +32,6 @@ SUBDIRS = \
serial \
sound \
$(SGTHREAD_DIR) \
timing \
xgl
timing
DIST_SUBDIRS = $(SUBDIRS) compatibility threads

View File

@@ -3,7 +3,7 @@
*
* Written by Curtis L. Olson, started February 1999.
*
* Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
* Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt/
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -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

View File

@@ -3,7 +3,7 @@
*
* Written by Curtis L. Olson, started February 1999.
*
* Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
* Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -257,14 +257,16 @@ public:
// Informational methods.
/**
* @return the lon of the lower left corner of this tile.
* @return the lon of the lower left corner of
* the 1x1 chunk containing this tile.
*/
inline int get_lon() const { return lon; }
inline int get_chunk_lon() const { return lon; }
/**
* @return the lat of the lower left corner of this tile.
* @return the lat of the lower left corner of
* the 1x1 chunk containing this tile.
*/
inline int get_lat() const { return lat; }
inline int get_chunk_lat() const { return lat; }
/**
* @return the x coord within the 1x1 degree chunk this tile.

View File

@@ -121,7 +121,7 @@
# define STL_STRSTREAM <strstream>
# endif
# elif __GNUC__ == 3
# elif __GNUC__ >= 3
// g++-3.0.x
# define SG_EXPLICIT_FUNCTION_TMPL_ARGS
# define SG_NEED_AUTO_PTR
@@ -149,13 +149,6 @@
#endif // __GNUC__
#if defined( __MINGW32__ )
# define bcopy(from, to, n) memcpy(to, from, n)
# define FG_MEM_COPY(to,from,n) memcpy(to, from, n)
# define isnan _isnan
# define snprintf _snprintf
#endif
/* KAI C++ */
#if defined(__KCC)
@@ -331,7 +324,7 @@
#endif // Native SGI compilers
#if defined ( sun )
#if defined (__sun)
# include <strings.h>
# include <memory.h>
# if defined ( __cplusplus )
@@ -343,7 +336,9 @@
extern void *memmove(void *, const void *, size_t);
# endif // __cplusplus
# define SG_COMPILER_STR "Sun compiler version " SG_STRINGIZE(__SUNPRO_CC)
# if !defined( __GNUC__ )
# define SG_COMPILER_STR "Sun compiler version " SG_STRINGIZE(__SUNPRO_CC)
# endif
#endif // sun
@@ -371,6 +366,27 @@
#endif // __ICC
//
// Platform dependent gl.h and glut.h definitions
//
#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>
#endif
//
// No user modifiable definitions beyond here.
//
@@ -452,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

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started February 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt/
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -32,6 +32,9 @@
#include <simgear/compiler.h>
#ifdef _MSC_VER
# define _USE_MATH_DEFINES
#endif
#ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
#else

View File

@@ -25,7 +25,9 @@ typedef enum {
SG_NETWORK = 0x00004000,
SG_ATC = 0x00008000,
SG_NASAL = 0x00010000,
SG_UNDEFD = 0x00020000, // For range checking
SG_INSTR = 0x00020000,
SG_SYSTEMS = 0x00040000,
SG_UNDEFD = 0x00080000, // For range checking
SG_ALL = 0xFFFFFFFF
} sgDebugClass;

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

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)

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

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

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

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

View File

@@ -3,7 +3,7 @@
//
// Written by Curtis Olson, started March 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -22,6 +22,9 @@
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <iostream>

View File

@@ -7,7 +7,7 @@
// All the core code underneath this is written by Durk Talsma. See
// the headers of all the other individual files for details.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -48,7 +48,7 @@
/** Ephemeris class
*
* Written by Durk Talsma <d.talsma@direct.a2000.nl> and Curtis Olson
* <curt@flightgear.org>
* <http://www.flightgear.org/~curt>
*
* Introduction
*

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

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

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;

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started March 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -21,6 +21,9 @@
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx>

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started March 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

View File

@@ -1,3 +1,7 @@
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>
#include <unistd.h>

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -70,3 +70,9 @@ int SGIOChannel::writestring( const char *str ) {
bool SGIOChannel::close() {
return false;
}
// dummy eof routine
bool SGIOChannel::eof() {
return false;
}

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -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; }

View File

@@ -4,7 +4,7 @@
// Shamelessly adapted from plib (plib.sourceforge.net) January 2001
//
// Original version Copyright (C) 2000 the plib team
// Local changes Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Local changes Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// 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
@@ -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;
}

View File

@@ -4,7 +4,7 @@
// Shamelessly adapted from plib January 2001
//
// Original version Copyright (C) 2000 the plib team
// Local changes Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Local changes Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// 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
@@ -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

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

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started January 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// 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
@@ -116,7 +116,7 @@ public:
// calculate the center of a list of points, by taking the halfway
// point between the min and max points.
static Point3D calc_center( point_list& wgs84_nodes ) {
Point3D sgCalcCenter( point_list& wgs84_nodes ) {
Point3D p, min, max;
if ( wgs84_nodes.size() ) {
@@ -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;
@@ -1145,7 +1145,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
for ( i = start; i < end; ++i ) {
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
group_nodes.push_back( wgs84_nodes[ tris_v[i][j] ] );
bs_center = calc_center( group_nodes );
bs_center = sgCalcCenter( group_nodes );
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
}
}
@@ -1196,7 +1196,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
for ( i = start; i < end; ++i ) {
for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
group_nodes.push_back( wgs84_nodes[ strips_v[i][j] ] );
bs_center = calc_center( group_nodes );
bs_center = sgCalcCenter( group_nodes );
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
}
}

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started January 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// 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
@@ -221,6 +221,16 @@ public:
};
/**
* \relates SGBinObject
* Calculate the center of a list of points, by taking the halfway
* point between the min and max points.
* @param wgs84_nodes list of points in wgs84 coordinates
* @return center point
*/
Point3D sgCalcCenter( point_list& wgs84_nodes );
/**
* \relates SGBinObject
* Calculate the bounding sphere of a set of nodes.

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -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;
}

View File

@@ -4,7 +4,7 @@
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -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; };
};

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
// Written by Curtis Olson, started November 1999.
// Modified by Bernie Bright <bbright@bigpond.net.au>, May 2002.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -28,6 +28,8 @@
#include <strings.h>
#endif
#include STL_IOSTREAM
#include <simgear/debug/logstream.hxx>
#include "sg_socket.hxx"

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -20,6 +20,9 @@
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started November 2001.
//
// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started July 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started July 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as

View File

@@ -9,9 +9,17 @@
* IDSIA, Lugano, Switzerland
* http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf
*
* Base-2 exp, Laurent de Soras
* http://www.musicdsp.org/archive.php?classid=5#106
*
* Fast log() Function, by Laurent de Soras:
* http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-Fastlogfunction&forum=totd&id=-1
*
* Sin, Cos, Tan approximation
* http://www.musicdsp.org/showArchiveComment.php?ArchiveID=115
*
* fast floating point power computation:
* http://playstation2-linux.com/download/adam/power.c
*/
/*
@@ -19,6 +27,7 @@
*/
#include <simgear/constants.h>
#include "fastmath.hxx"
@@ -41,11 +50,76 @@ double fast_exp(double val) {
const double a = 1048576/M_LN2;
const double b_c = 1072632447; /* 1072693248 - 60801 */
_eco.n.i = a*val + b_c;
_eco.n.i = (int)(a*val + b_c);
return _eco.d;
}
/*
* Linear approx. between 2 integer values of val. Uses 32-bit integers.
* Not very efficient but faster than exp()
*/
double fast_exp2( const double val )
{
int e;
double ret;
if (val >= 0) {
e = int (val);
ret = val - (e - 1);
#if BYTE_ORDER == BIG_ENDIAN
((*((int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
#else
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
#endif
} else {
e = int (val + 1023);
ret = val - (e - 1024);
#if BYTE_ORDER == BIG_ENDIAN
((*((int *) &ret)) &= ~(2047 << 20)) += e << 20;
#else
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += e << 20;
#endif
}
return ret;
}
/*
*
*/
float _fast_log2(const float val)
{
float result, tmp;
float mp = 0.346607f;
result = *(int*)&val;
result *= 1.0/(1<<23);
result = result - 127;
tmp = result - floor(result);
tmp = (tmp - tmp*tmp) * mp;
return tmp + result;
}
float _fast_pow2(const float val)
{
float result;
float mp = 0.33971f;
float tmp = val - floor(val);
tmp = (tmp - tmp*tmp) * mp;
result = val + 127 - tmp;
result *= (1<<23);
*(int*)&result = (int)result;
return result;
}
/**
* While we're on the subject, someone might have use for these as well?
@@ -63,3 +137,155 @@ void fast_BSR(float &x, register unsigned long shiftAmount) {
}
/*
* fastpow(f,n) gives a rather *rough* estimate of a float number f to the
* power of an integer number n (y=f^n). It is fast but result can be quite a
* bit off, since we directly mess with the floating point exponent.
*
* Use it only for getting rough estimates of the values and where precision
* is not that important.
*/
float fast_pow(const float f, const int n)
{
long *lp,l;
lp=(long*)(&f);
l=*lp;l-=0x3F800000l;l<<=(n-1);l+=0x3F800000l;
*lp=l;
return f;
}
float fast_root(const float f, const int n)
{
long *lp,l;
lp=(long*)(&f);
l=*lp;l-=0x3F800000l;l>>=(n-1);l+=0x3F800000l;
*lp=l;
return f;
}
/*
* Code for approximation of cos, sin, tan and inv sin, etc.
* Surprisingly accurate and very usable.
*
* Domain:
* Sin/Cos [0, pi/2]
* Tan [0,pi/4]
* InvSin/Cos [0, 1]
* InvTan [-1, 1]
*/
float fast_sin(const float val)
{
float fASqr = val*val;
float fResult = -2.39e-08f;
fResult *= fASqr;
fResult += 2.7526e-06f;
fResult *= fASqr;
fResult -= 1.98409e-04f;
fResult *= fASqr;
fResult += 8.3333315e-03f;
fResult *= fASqr;
fResult -= 1.666666664e-01f;
fResult *= fASqr;
fResult += 1.0f;
fResult *= val;
return fResult;
}
float fast_cos(const float val)
{
float fASqr = val*val;
float fResult = -2.605e-07f;
fResult *= fASqr;
fResult += 2.47609e-05f;
fResult *= fASqr;
fResult -= 1.3888397e-03f;
fResult *= fASqr;
fResult += 4.16666418e-02f;
fResult *= fASqr;
fResult -= 4.999999963e-01f;
fResult *= fASqr;
fResult += 1.0f;
return fResult;
}
float fast_tan(const float val)
{
float fASqr = val*val;
float fResult = 9.5168091e-03f;
fResult *= fASqr;
fResult += 2.900525e-03f;
fResult *= fASqr;
fResult += 2.45650893e-02f;
fResult *= fASqr;
fResult += 5.33740603e-02f;
fResult *= fASqr;
fResult += 1.333923995e-01f;
fResult *= fASqr;
fResult += 3.333314036e-01f;
fResult *= fASqr;
fResult += 1.0f;
fResult *= val;
return fResult;
}
float fast_asin(float val)
{
float fRoot = sqrt(1.0f-val);
float fResult = -0.0187293f;
fResult *= val;
fResult += 0.0742610f;
fResult *= val;
fResult -= 0.2121144f;
fResult *= val;
fResult += 1.5707288f;
fResult = SGD_PI_2 - fRoot*fResult;
return fResult;
}
float fast_acos(float val)
{
float fRoot = sqrt(1.0f-val);
float fResult = -0.0187293f;
fResult *= val;
fResult += 0.0742610f;
fResult *= val;
fResult -= 0.2121144f;
fResult *= val;
fResult += 1.5707288f;
fResult *= fRoot;
return fResult;
}
float fast_atan(float val)
{
float fVSqr = val*val;
float fResult = 0.0028662257f;
fResult *= fVSqr;
fResult -= 0.0161657367f;
fResult *= fVSqr;
fResult += 0.0429096138f;
fResult *= fVSqr;
fResult -= 0.0752896400f;
fResult *= fVSqr;
fResult += 0.1065626393f;
fResult *= fVSqr;
fResult -= 0.1420889944f;
fResult *= fVSqr;
fResult += 0.1999355085f;
fResult *= fVSqr;
fResult -= 0.3333314528f;
fResult *= fVSqr;
fResult += 1.0f;
fResult *= val;
return fResult;
}

View File

@@ -32,24 +32,41 @@
double fast_exp(double val);
double fast_exp2(const double val);
float fast_pow(const float val1, const float val2);
float fast_log2(const float cal);
float fast_root(const float f, const int n);
float _fast_pow2(const float cal);
float _fast_log2(const float val);
float fast_sin(const float val);
float fast_cos(const float val);
float fast_tan(const float val);
float fast_asin(const float val);
float fast_acos(const float val);
float fast_atan(const float val);
void fast_BSL(float &x, register unsigned long shiftAmount);
void fast_BSR(float &x, register unsigned long shiftAmount);
inline float fast_log2 (float val)
{
int * const exp_ptr = reinterpret_cast <int *> (&val);
int x = *exp_ptr;
const int log_2 = ((x >> 23) & 255) - 128;
x &= ~(255 << 23);
x += 127 << 23;
*exp_ptr = x;
int * const exp_ptr = reinterpret_cast <int *> (&val);
int x = *exp_ptr;
const int log_2 = ((x >> 23) & 255) - 128;
x &= ~(255 << 23);
x += 127 << 23;
*exp_ptr = x;
val = ((-1.0f/3) * val + 2) * val - 2.0f/3; // (1)
val = ((-1.0f/3) * val + 2) * val - 2.0f/3; // (1)
return (val + log_2);
return (val + log_2);
}
/**
* This function is about 3 times faster than the system log() function
* and has an error of about 0.01%
@@ -65,5 +82,36 @@ inline float fast_log10 (const float &val)
}
/**
* This function is about twice as fast as the system pow(x,y) function
*/
inline float fast_pow(const float val1, const float val2)
{
return _fast_pow2(val2 * _fast_log2(val1));
}
/*
* Haven't seen this elsewhere, probably because it is too obvious?
* Anyway, these functions are intended for 32-bit floating point numbers
* only and should work a bit faster than the regular ones.
*/
inline float fast_abs(float f)
{
int i=((*(int*)&f)&0x7fffffff);
return (*(float*)&i);
}
inline float fast_neg(float f)
{
int i=((*(int*)&f)^0x80000000);
return (*(float*)&i);
}
inline int fast_sgn(float f)
{
return 1+(((*(int*)&f)>>31)<<1);
}
#endif // !_SG_FMATH_HXX

View File

@@ -4,7 +4,7 @@
//
// Written by Curtis Olson, started April 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

View File

@@ -6,7 +6,7 @@
// Written by Curtis Olson, started April 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started September 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started September 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started September 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

View File

@@ -8,7 +8,7 @@
* Adapted from algebra3 by Jean-Francois Doue, started October 1998.
*/
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -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)
{

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started June 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -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

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started June 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -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

View File

@@ -108,7 +108,7 @@ static double seaLevelRadius(double r, double z)
// starts making very poor guesses as to latitude. As altitude
// approaches infinity, it should be guessing with geocentric
// coordinates, not "local geodetic up" ones.
void sgCartToGeod(double* xyz, double* lat, double* lon, double* alt)
void sgCartToGeod(const double* xyz, double* lat, double* lon, double* alt)
{
// The error is expressed as a radian angle, and we want accuracy
// to 1 part in 2^50 (an IEEE double has between 51 and 52

View File

@@ -42,7 +42,7 @@ void sgGeodToGeoc(double lat_geod, double alt,
* @param lon (out) Longitude, in radians
* @param alt (out) Altitude, in meters above the WGS84 ellipsoid
*/
void sgCartToGeod(double* xyz, double* lat, double* lon, double* alt);
void sgCartToGeod(const double* xyz, double* lat, double* lon, double* alt);
/**
* Convert a cartesian point to a geodetic lat/lon/altitude.

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started July 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -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.

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started July 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -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.

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started December 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started December 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

View File

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

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)

View File

@@ -3,7 +3,7 @@
//
// Written by Curtis L. Olson, started April 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -43,7 +43,7 @@ static const char sgDirPathSep = '/';
static const char sgDirPathSepBad = '\\';
#endif
#if defined( WIN32 )
#if defined( WIN32 ) && !defined(__CYGWIN__)
static const char sgSearchPathSep = ';';
#else
static const char sgSearchPathSep = ':';
@@ -112,6 +112,11 @@ void SGPath::append( const string& p ) {
fix();
}
//add a new path component to the existing path string
void SGPath::add( const string& p ) {
append( sgSearchPathSep+p );
}
// concatenate a string to the end of the path without inserting a
// path separator
@@ -149,7 +154,7 @@ string SGPath::dir() const {
// get the base part of the path (everything but the extension.)
string SGPath::base() const {
int index = path.rfind(".");
if (index >= 0) {
if ((index >= 0) && (path.find("/", index) == string::npos)) {
return path.substr(0, index);
} else {
return "";
@@ -157,9 +162,11 @@ string SGPath::base() const {
}
// get the extention (everything after the final ".")
// but make sure no "/" follows the "." character (otherwise it
// is has to be a directory name containing a ".").
string SGPath::extension() const {
int index = path.rfind(".");
if (index >= 0) {
if ((index >= 0) && (path.find("/", index) == string::npos)) {
return path.substr(index + 1);
} else {
return "";

View File

@@ -6,7 +6,7 @@
// Written by Curtis L. Olson, started April 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -79,6 +79,12 @@ public:
* @param p additional path component */
void append( const string& p );
/**
* Append a new piece to the existing path. Inserts a search path
* separator to the existing path and the new patch component.
* @param p additional path component */
void add( const string& p );
/**
* Concatenate a string to the end of the path without inserting a
* path separator.

View File

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

94
simgear/misc/stdint.hxx Normal file
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

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

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

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
@@ -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;

View File

@@ -5,7 +5,7 @@
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public

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)

File diff suppressed because it is too large Load Diff

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

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

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

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

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

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

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

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;

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

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

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

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

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

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

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;

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;

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

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

View File

@@ -561,7 +561,7 @@ public:
* Property value types.
*/
enum Type {
NONE,
NONE = 0,
ALIAS,
BOOL,
INT,
@@ -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);

View File

@@ -133,7 +133,6 @@ checkFlag (const char * flag, bool defaultState = true)
void
PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
{
State &st = state();
const char * attval;
if (_level == 0) {
@@ -160,6 +159,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
}
else {
State &st = state();
// Get the index.
attval = atts.getValue("n");
int index = 0;
@@ -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);
}
}
@@ -322,6 +325,23 @@ readProperties (const string &file, SGPropertyNode * start_node)
}
/**
* Read properties from an in-memory buffer.
*
* @param buf A character buffer containing the xml data.
* @param size The size/length of the buffer in bytes
* @param start_node The root node for reading properties.
* @return true if the read succeeded, false otherwise.
*/
void readProperties (const char *buf, const int size,
SGPropertyNode * start_node)
{
PropsVisitor visitor(start_node, "");
readXML(buf, size, visitor);
if (visitor.hasException())
throw visitor.getException();
}
////////////////////////////////////////////////////////////////////////
// Property list writer.
@@ -466,7 +486,7 @@ writeNode (ostream &output, const SGPropertyNode * node,
}
// If there are children, write them next.
if (nChildren > 0 || node->isAlias()) {
if (nChildren > 0) {
doIndent(output, indent);
output << '<' << name;
writeAtts(output, node);
@@ -563,12 +583,17 @@ copyProperties (const SGPropertyNode *in, SGPropertyNode *out)
retval = false;
break;
default:
if (in->isAlias())
break;
string message = "Unknown internal SGPropertyNode type";
message += in->getType();
throw sg_error(message, "SimGear Property Reader");
}
}
// copy the attributes.
out->setAttributes( in->getAttributes() );
// Next, copy the children.
int nChildren = in->nChildren();
for (int i = 0; i < nChildren; i++) {

View File

@@ -41,6 +41,13 @@ void readProperties (istream &input, SGPropertyNode * start_node,
void readProperties (const string &file, SGPropertyNode * start_node);
/**
* Read properties from an in-memory buffer.
*/
void readProperties (const char *buf, const int size,
SGPropertyNode * start_node);
/**
* Write properties to an XML output stream.
*/

View File

@@ -29,12 +29,13 @@
// Constructor
SGWayPoint::SGWayPoint( const double lon, const double lat, const double alt,
const modetype m, const string s ) {
const modetype m, const string s, const string n ) {
target_lon = lon;
target_lat = lat;
target_alt = alt;
mode = m;
id = s;
name = n;
}

View File

@@ -76,6 +76,7 @@ private:
double distance;
string id;
string name;
public:
@@ -86,10 +87,11 @@ public:
* @param alt target altitude
* @param mode type of coordinates/math to use
* @param s waypoint identifier
* @param n waypoint name
*/
SGWayPoint( const double lon = 0.0, const double lat = 0.0,
const double alt = 0.0, const modetype m = WGS84,
const string s = "" );
const string s = "", const string n = "" );
/** Destructor */
~SGWayPoint();
@@ -151,7 +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 const string& get_name() const { return name; }
};

View File

@@ -2,7 +2,7 @@
//
// Written by Curtis Olson, started May 1998.
//
// Copyright (C) 1998 - 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1998 - 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -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 (int i = 0; i < textures.size(); i++)
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";
}
@@ -227,7 +235,7 @@ SGMaterial::build_ssg_state( bool defer_tex_load )
{
GLenum shade_model = GL_SMOOTH;
for (int i = 0; i < _status.size(); i++)
for (unsigned int i = 0; i < _status.size(); i++)
{
ssgSimpleState *state = new ssgSimpleState();
state->ref();

View File

@@ -4,7 +4,7 @@
// Written by Curtis Olson, started May 1998.
// Overhauled by David Megginson, December 2001
//
// Copyright (C) 1998 - 2000 Curtis L. Olson - curt@flightgear.org
// Copyright (C) 1998 - 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -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 );
/**
@@ -217,7 +217,7 @@ private:
vector<_internal_state> _status;
// Round-robin counter
int _current_ptr;
unsigned int _current_ptr;
// texture size
double xsize, ysize;
@@ -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 );

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