Compare commits
326 Commits
RELEASE_0_
...
RELEASE_0_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a4e703f16 | ||
|
|
61984730ac | ||
|
|
f196d3bab8 | ||
|
|
7da45cb49e | ||
|
|
e994305da6 | ||
|
|
2af37b484e | ||
|
|
faf41f7d96 | ||
|
|
7629e29397 | ||
|
|
1cff7fcfea | ||
|
|
694cf6e958 | ||
|
|
0e12fbb2a0 | ||
|
|
450ad45882 | ||
|
|
d674e50591 | ||
|
|
61f2f4b761 | ||
|
|
baa2f49b14 | ||
|
|
8c0bd234d8 | ||
|
|
c4fd41562f | ||
|
|
a1d1b4e49f | ||
|
|
96fb7a45f7 | ||
|
|
d5eedd2c65 | ||
|
|
fe4f907099 | ||
|
|
1b45eaf3de | ||
|
|
cfbc0a1579 | ||
|
|
db1b99d8dd | ||
|
|
65a880e9fa | ||
|
|
37b4005d3e | ||
|
|
70faa252e7 | ||
|
|
3620be8dbc | ||
|
|
21c64dd60f | ||
|
|
fb69d790ce | ||
|
|
debd066edd | ||
|
|
f58d81b1e9 | ||
|
|
8d507f161b | ||
|
|
b015f7c801 | ||
|
|
80abe952ba | ||
|
|
c12162407c | ||
|
|
7f5c3b223a | ||
|
|
2f3e4ebf39 | ||
|
|
2c14f8587e | ||
|
|
42224052e2 | ||
|
|
a8dd5aa0fc | ||
|
|
f3d0a9bc3f | ||
|
|
d629b9e36a | ||
|
|
4d54ba2200 | ||
|
|
0035ef9194 | ||
|
|
fcb20296d7 | ||
|
|
6bb9080017 | ||
|
|
bbde16dc08 | ||
|
|
ac9716f193 | ||
|
|
8a2bc1c21b | ||
|
|
942b474ad7 | ||
|
|
f3ef9b671f | ||
|
|
3538631e8e | ||
|
|
1577ab04e1 | ||
|
|
7f2dfaa5b4 | ||
|
|
fd126746f7 | ||
|
|
63f7e9feb0 | ||
|
|
5eb380e103 | ||
|
|
832e821919 | ||
|
|
197e3f144d | ||
|
|
056b5b41e2 | ||
|
|
15d40fd64a | ||
|
|
979d3da69c | ||
|
|
72984cc4a8 | ||
|
|
0a7a815124 | ||
|
|
1ce68a49c6 | ||
|
|
b1b6abf285 | ||
|
|
9dfd6970f1 | ||
|
|
3583c13339 | ||
|
|
00ab198c9f | ||
|
|
669d9a89ca | ||
|
|
9c54603726 | ||
|
|
dc09a50472 | ||
|
|
68eb7031e2 | ||
|
|
19623cac21 | ||
|
|
4ca25ca533 | ||
|
|
178c49a430 | ||
|
|
32e2cd9f06 | ||
|
|
7aa514d9ba | ||
|
|
7c2575d723 | ||
|
|
f93ea20d5e | ||
|
|
73cb6ff00d | ||
|
|
72267fa60b | ||
|
|
6b6a27e849 | ||
|
|
daea10121c | ||
|
|
999a1e514b | ||
|
|
be30960366 | ||
|
|
38e5084018 | ||
|
|
fdd9bb1af6 | ||
|
|
81546820ab | ||
|
|
84e87f0e8a | ||
|
|
901592a88e | ||
|
|
24f908d9be | ||
|
|
f62ff0ad66 | ||
|
|
8e0ecbeb8f | ||
|
|
095367f760 | ||
|
|
5d34eb12e0 | ||
|
|
d4e760efe1 | ||
|
|
75ab8e697b | ||
|
|
f4b05d46ed | ||
|
|
04c5f2c36a | ||
|
|
db50f95482 | ||
|
|
0e52a08a47 | ||
|
|
7b5d49ef60 | ||
|
|
430ba60b33 | ||
|
|
3af1f3bc63 | ||
|
|
bdcb94af81 | ||
|
|
2ea9e723c2 | ||
|
|
e19091d809 | ||
|
|
64ab59c0e0 | ||
|
|
4707b363aa | ||
|
|
1a72245c15 | ||
|
|
dea7b9050d | ||
|
|
3bd810fedc | ||
|
|
f9cbf8361d | ||
|
|
eccd4d0325 | ||
|
|
e0decf1233 | ||
|
|
100927f16c | ||
|
|
bb670f6658 | ||
|
|
d37992aaf9 | ||
|
|
9048ee533d | ||
|
|
2b1e5927ca | ||
|
|
b5e03030d1 | ||
|
|
65056bfa72 | ||
|
|
c50bb90374 | ||
|
|
ec4fc265e0 | ||
|
|
8ea41af5c4 | ||
|
|
966331dac7 | ||
|
|
cf056bace7 | ||
|
|
405a455906 | ||
|
|
3a8b431a5b | ||
|
|
3ce0c17237 | ||
|
|
61a2e0f104 | ||
|
|
7c44251216 | ||
|
|
26e70664d6 | ||
|
|
8ac27cc798 | ||
|
|
d314164fed | ||
|
|
d2cbed151b | ||
|
|
fc06ae58b2 | ||
|
|
a8768c78a2 | ||
|
|
ee8763f60d | ||
|
|
db633330fe | ||
|
|
c1ffafd663 | ||
|
|
72f35dc914 | ||
|
|
e5f82f53b9 | ||
|
|
e39e6893e0 | ||
|
|
9ab77d65f4 | ||
|
|
8ed96cad1d | ||
|
|
7795eb8239 | ||
|
|
207c7ab1e0 | ||
|
|
27af79684f | ||
|
|
6b61a8eed1 | ||
|
|
181e6eac75 | ||
|
|
fd1979857c | ||
|
|
448bc3facd | ||
|
|
97cabadb88 | ||
|
|
8e284a70b7 | ||
|
|
73f9febe06 | ||
|
|
6a6cc22e9c | ||
|
|
b293639b76 | ||
|
|
f06036be09 | ||
|
|
867571af78 | ||
|
|
f6314d3124 | ||
|
|
1e87dd7903 | ||
|
|
3b6af2f0c2 | ||
|
|
5bdff41641 | ||
|
|
67e9d105cb | ||
|
|
f1fc99f16f | ||
|
|
f89e359d53 | ||
|
|
77ec170a50 | ||
|
|
34320f5f20 | ||
|
|
a26271e46e | ||
|
|
e2e7466250 | ||
|
|
1e24cc4643 | ||
|
|
dfc23c3528 | ||
|
|
cd11a5dc27 | ||
|
|
899734296b | ||
|
|
7a3a81c152 | ||
|
|
e62a4a05ac | ||
|
|
463ca207ce | ||
|
|
da6e1b31ea | ||
|
|
8c783b1680 | ||
|
|
efce88ff12 | ||
|
|
01608b7e18 | ||
|
|
a5f0e0395a | ||
|
|
0b723174fd | ||
|
|
5d248bf0df | ||
|
|
c039ccdeb0 | ||
|
|
d88fb32a73 | ||
|
|
37ac409586 | ||
|
|
7b24e94c66 | ||
|
|
e12cd2a50c | ||
|
|
98b2ba4fc1 | ||
|
|
2f0afdccc1 | ||
|
|
79734df554 | ||
|
|
c52657fa1a | ||
|
|
9cac8409cd | ||
|
|
18703ce02d | ||
|
|
709a166bd6 | ||
|
|
8048e6297c | ||
|
|
fb0dded103 | ||
|
|
055e969e7a | ||
|
|
f10db8a30e | ||
|
|
c19af3525e | ||
|
|
7c60ccfc35 | ||
|
|
84cba33aab | ||
|
|
a52b1ec64f | ||
|
|
f30c4720ae | ||
|
|
7fc8c02688 | ||
|
|
54a7a0d534 | ||
|
|
8d73160a75 | ||
|
|
ff10602c65 | ||
|
|
ca50fe386d | ||
|
|
39f3c6e41d | ||
|
|
ba1b96e518 | ||
|
|
ef486b2cc6 | ||
|
|
06f3cb4f8e | ||
|
|
074f5ff996 | ||
|
|
8c26f32d5f | ||
|
|
9a2ee54389 | ||
|
|
ab69c03698 | ||
|
|
fab1f4e7a0 | ||
|
|
41eed484c1 | ||
|
|
7d18f9bdde | ||
|
|
3a48c3de7a | ||
|
|
d769a9936b | ||
|
|
1697cb3b1a | ||
|
|
62aa32a417 | ||
|
|
a0d0852838 | ||
|
|
2f479cae69 | ||
|
|
4820d57fa8 | ||
|
|
04e3b0b3c1 | ||
|
|
a7f78b9f68 | ||
|
|
f3d8eb4665 | ||
|
|
090f79b951 | ||
|
|
88c0dbf661 | ||
|
|
9e3822ceaf | ||
|
|
007b0a8fe6 | ||
|
|
7f0ebf8871 | ||
|
|
5414e94a1a | ||
|
|
461dee8657 | ||
|
|
297b6193fe | ||
|
|
4b74e40a5f | ||
|
|
5a9b08dec2 | ||
|
|
5e6f9f79a2 | ||
|
|
e2f93e6ae1 | ||
|
|
93314b59fb | ||
|
|
29269c6686 | ||
|
|
3c84b6e2f6 | ||
|
|
04fb708543 | ||
|
|
df302f277c | ||
|
|
5e63e663bb | ||
|
|
ca10cb2d37 | ||
|
|
c9854153f8 | ||
|
|
129e3c6326 | ||
|
|
66996711ae | ||
|
|
8fe37cea51 | ||
|
|
de64b6f267 | ||
|
|
9a9d9c7cc1 | ||
|
|
a191e9762a | ||
|
|
a7b35c6e22 | ||
|
|
5034346b67 | ||
|
|
661f64b902 | ||
|
|
bbc83f721c | ||
|
|
01f4541331 | ||
|
|
0e4a894f62 | ||
|
|
1c135a9b5b | ||
|
|
e65c85ce73 | ||
|
|
26b58991f9 | ||
|
|
8390df37ca | ||
|
|
371fc73f24 | ||
|
|
921dae5444 | ||
|
|
9b3abbec89 | ||
|
|
6935baba5b | ||
|
|
dec1e32f96 | ||
|
|
710c2ccfcd | ||
|
|
8e66e534ae | ||
|
|
0f5f30b993 | ||
|
|
b199f733f7 | ||
|
|
0cdcf3a3e0 | ||
|
|
8e09486e82 | ||
|
|
0c24b78573 | ||
|
|
1436be9699 | ||
|
|
0489ad7c62 | ||
|
|
c553570533 | ||
|
|
bda112297f | ||
|
|
331a4e4406 | ||
|
|
a9faf8ceff | ||
|
|
2866d1ace9 | ||
|
|
11a74f7a31 | ||
|
|
634a2035ee | ||
|
|
ffada9257d | ||
|
|
e09164e5b3 | ||
|
|
de1a5f3034 | ||
|
|
86e83faef3 | ||
|
|
9f06c8df76 | ||
|
|
6e511de7db | ||
|
|
e34aae9982 | ||
|
|
675b388b8e | ||
|
|
7d239fe4ac | ||
|
|
edd92caba1 | ||
|
|
5c3b4abf42 | ||
|
|
d3a3466b14 | ||
|
|
4399383781 | ||
|
|
bb383998bb | ||
|
|
ffeb174ca1 | ||
|
|
a90d74dde8 | ||
|
|
9d7fd79e76 | ||
|
|
6f29d234eb | ||
|
|
6f5517f602 | ||
|
|
cc43c745b2 | ||
|
|
db8d961b27 | ||
|
|
a0bdec2846 | ||
|
|
5bbcd386fa | ||
|
|
7657632024 | ||
|
|
ab29063a97 | ||
|
|
c06ef23eb1 | ||
|
|
7b2f7aa827 | ||
|
|
7113c10f4b | ||
|
|
14033946e5 | ||
|
|
6e0e056ca7 | ||
|
|
7aa4f0ccdb | ||
|
|
4b04450fa6 | ||
|
|
ad81560be5 | ||
|
|
5c26faa20e | ||
|
|
bd85fa2457 |
@@ -8,3 +8,12 @@ config.log
|
||||
config.status
|
||||
configure
|
||||
do-config.sh
|
||||
.cdtproject
|
||||
.project
|
||||
config.guess
|
||||
config.sub
|
||||
depcomp
|
||||
INSTALL
|
||||
install-sh
|
||||
missing
|
||||
mkinstalldirs
|
||||
|
||||
2
Doxyfile
2
Doxyfile
@@ -22,7 +22,7 @@ PROJECT_NAME = SimGear
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER = 0.3.5
|
||||
PROJECT_NUMBER = 0.3.9
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
EXTRA_DIST = \
|
||||
acinclude.m4 \
|
||||
autogen.sh \
|
||||
DoxygenMain.cxx
|
||||
DoxygenMain.cxx \
|
||||
README.MSVC \
|
||||
README.metakit \
|
||||
README.zlib \
|
||||
SimGear.dsp \
|
||||
SimGear.dsw
|
||||
@@ -11,7 +10,7 @@ EXTRA_DIST = \
|
||||
SUBDIRS = src-libs simgear
|
||||
|
||||
dist-hook:
|
||||
(cd $(top_srcdir); $(HOME)/projects/FlightGear-0.9/admin/am2dsp.pl)
|
||||
(cd $(top_srcdir); $(HOME)/Projects/FlightGear/admin/am2dsp.pl)
|
||||
|
||||
#
|
||||
# Rule to build RPM distribution package
|
||||
|
||||
97
NEWS
97
NEWS
@@ -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
12
README.OpenAL
Normal 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.
|
||||
1095
SimGear.dsp
1095
SimGear.dsp
File diff suppressed because it is too large
Load Diff
4
Thanks
4
Thanks
@@ -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)
|
||||
|
||||
36
acinclude.m4
36
acinclude.m4
@@ -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
|
||||
|
||||
96
configure.ac
96
configure.ac
@@ -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.)"
|
||||
|
||||
@@ -32,7 +32,6 @@ SUBDIRS = \
|
||||
serial \
|
||||
sound \
|
||||
$(SGTHREAD_DIR) \
|
||||
timing \
|
||||
xgl
|
||||
timing
|
||||
|
||||
DIST_SUBDIRS = $(SUBDIRS) compatibility threads
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -185,7 +185,7 @@ inline logbuf::int_type
|
||||
logbuf::overflow( int c )
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
static has_console = false;
|
||||
static bool has_console = false;
|
||||
if ( logging_enabled ) {
|
||||
if ( !has_console ) {
|
||||
AllocConsole();
|
||||
|
||||
@@ -2,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -67,6 +67,8 @@ public:
|
||||
DECREASING
|
||||
};
|
||||
|
||||
void set(double dist, int dir = -1, int mod = -1, int tend = -1);
|
||||
|
||||
inline double getVisibility_m() const { return _distance; }
|
||||
inline double getVisibility_ft() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_FEET; }
|
||||
inline double getVisibility_sm() const { return _distance == NaN ? NaN : _distance * SG_METER_TO_SM; }
|
||||
@@ -87,7 +89,8 @@ class SGMetarRunway {
|
||||
friend class SGMetar;
|
||||
public:
|
||||
SGMetarRunway() :
|
||||
_deposit(0),
|
||||
_deposit(-1),
|
||||
_deposit_string(0),
|
||||
_extent(-1),
|
||||
_extent_string(0),
|
||||
_depth(NaN),
|
||||
@@ -96,7 +99,8 @@ public:
|
||||
_comment(0),
|
||||
_wind_shear(false) {}
|
||||
|
||||
inline const char *getDeposit() const { return _deposit; }
|
||||
inline int getDeposit() const { return _deposit; }
|
||||
inline const char *getDepositString() const { return _deposit_string; }
|
||||
inline double getExtent() const { return _extent; }
|
||||
inline const char *getExtentString() const { return _extent_string; }
|
||||
inline double getDepth() const { return _depth; }
|
||||
@@ -104,13 +108,14 @@ public:
|
||||
inline const char *getFrictionString() const { return _friction_string; }
|
||||
inline const char *getComment() const { return _comment; }
|
||||
inline const bool getWindShear() const { return _wind_shear; }
|
||||
inline SGMetarVisibility getMinVisibility() const { return _min_visibility; }
|
||||
inline SGMetarVisibility getMaxVisibility() const { return _max_visibility; }
|
||||
inline const SGMetarVisibility& getMinVisibility() const { return _min_visibility; }
|
||||
inline const SGMetarVisibility& getMaxVisibility() const { return _max_visibility; }
|
||||
|
||||
protected:
|
||||
SGMetarVisibility _min_visibility;
|
||||
SGMetarVisibility _max_visibility;
|
||||
const char *_deposit;
|
||||
int _deposit;
|
||||
const char *_deposit_string;
|
||||
int _extent;
|
||||
const char *_extent_string;
|
||||
double _depth;
|
||||
@@ -131,6 +136,8 @@ public:
|
||||
_type(0),
|
||||
_type_long(0) {}
|
||||
|
||||
void set(double alt, int cov = -1);
|
||||
|
||||
inline int getCoverage() const { return _coverage; }
|
||||
inline double getAltitude_m() const { return _altitude; }
|
||||
inline double getAltitude_ft() const { return _altitude == NaN ? NaN : _altitude * SG_METER_TO_FEET; }
|
||||
@@ -147,7 +154,8 @@ protected:
|
||||
|
||||
class SGMetar {
|
||||
public:
|
||||
SGMetar(const string& m, const string& proxy = "", const string& port = "", const string &auth = "");
|
||||
SGMetar(const string& m, const string& proxy = "", const string& port = "",
|
||||
const string &auth = "", const time_t time = 0);
|
||||
~SGMetar();
|
||||
|
||||
enum ReportType {
|
||||
@@ -159,6 +167,7 @@ public:
|
||||
|
||||
inline const char *getData() const { return _data; }
|
||||
inline const char *getUnusedData() const { return _m; }
|
||||
inline const bool getProxy() const { return _x_proxy; }
|
||||
inline const char *getId() const { return _icao; }
|
||||
inline int getYear() const { return _year; }
|
||||
inline int getMonth() const { return _month; }
|
||||
@@ -181,10 +190,10 @@ public:
|
||||
inline int getWindRangeFrom() const { return _wind_range_from; }
|
||||
inline int getWindRangeTo() const { return _wind_range_to; }
|
||||
|
||||
inline SGMetarVisibility& getMinVisibility() { return _min_visibility; }
|
||||
inline SGMetarVisibility& getMaxVisibility() { return _max_visibility; }
|
||||
inline SGMetarVisibility& getVertVisibility() { return _vert_visibility; }
|
||||
inline SGMetarVisibility *getDirVisibility() { return _dir_visibility; }
|
||||
inline const SGMetarVisibility& getMinVisibility() const { return _min_visibility; }
|
||||
inline const SGMetarVisibility& getMaxVisibility() const { return _max_visibility; }
|
||||
inline const SGMetarVisibility& getVertVisibility() const { return _vert_visibility; }
|
||||
inline const SGMetarVisibility *getDirVisibility() const { return _dir_visibility; }
|
||||
|
||||
inline double getTemperature_C() const { return _temp; }
|
||||
inline double getTemperature_F() const { return _temp == NaN ? NaN : 1.8 * _temp + 32; }
|
||||
@@ -193,15 +202,21 @@ public:
|
||||
inline double getPressure_hPa() const { return _pressure == NaN ? NaN : _pressure / 100; }
|
||||
inline double getPressure_inHg() const { return _pressure == NaN ? NaN : _pressure * SG_PA_TO_INHG; }
|
||||
|
||||
inline int getRain() const { return _rain; }
|
||||
inline int getHail() const { return _hail; }
|
||||
inline int getSnow() const { return _snow; }
|
||||
inline bool getCAVOK() const { return _cavok; }
|
||||
|
||||
double getRelHumidity() const;
|
||||
|
||||
inline vector<SGMetarCloud>& getClouds() { return _clouds; }
|
||||
inline map<string, SGMetarRunway>& getRunways() { return _runways; }
|
||||
inline vector<string>& getWeather() { return _weather; }
|
||||
inline const vector<SGMetarCloud>& getClouds() const { return _clouds; }
|
||||
inline const map<string, SGMetarRunway>& getRunways() const { return _runways; }
|
||||
inline const vector<string>& getWeather() const { return _weather; }
|
||||
|
||||
protected:
|
||||
string _url;
|
||||
int _grpcount;
|
||||
bool _x_proxy;
|
||||
char *_data;
|
||||
char *_m;
|
||||
char _icao[5];
|
||||
@@ -219,6 +234,10 @@ protected:
|
||||
double _temp;
|
||||
double _dewp;
|
||||
double _pressure;
|
||||
int _rain;
|
||||
int _hail;
|
||||
int _snow;
|
||||
bool _cavok;
|
||||
|
||||
SGMetarVisibility _min_visibility;
|
||||
SGMetarVisibility _max_visibility;
|
||||
@@ -230,6 +249,7 @@ protected:
|
||||
|
||||
bool scanPreambleDate();
|
||||
bool scanPreambleTime();
|
||||
void useCurrentDate();
|
||||
|
||||
bool scanType();
|
||||
bool scanId();
|
||||
@@ -253,7 +273,8 @@ protected:
|
||||
int scanNumber(char **str, int *num, int min, int max = 0);
|
||||
bool scanBoundary(char **str);
|
||||
const struct Token *scanToken(char **str, const struct Token *list);
|
||||
char *loadData(const char *id, const string& proxy, const string& port, const string &auth);
|
||||
char *loadData(const char *id, const string& proxy, const string& port,
|
||||
const string &auth, time_t time);
|
||||
void normalizeData();
|
||||
};
|
||||
|
||||
|
||||
698
simgear/environment/visual_enviro.cxx
Normal file
698
simgear/environment/visual_enviro.cxx
Normal file
@@ -0,0 +1,698 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include <simgear/math/polar3d.hxx>
|
||||
#include <simgear/sound/soundmgr_openal.hxx>
|
||||
#include <simgear/scene/sky/cloudfield.hxx>
|
||||
#include <simgear/scene/sky/newcloud.hxx>
|
||||
#include "visual_enviro.hxx"
|
||||
|
||||
#include <vector>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
|
||||
|
||||
typedef struct {
|
||||
Point3D pt;
|
||||
int depth;
|
||||
int prev;
|
||||
} lt_tree_seg;
|
||||
|
||||
#define MAX_RAIN_SLICE 200
|
||||
static float rainpos[MAX_RAIN_SLICE];
|
||||
#define MAX_LT_TREE_SEG 400
|
||||
|
||||
/**
|
||||
* A class to render lightnings.
|
||||
*/
|
||||
class SGLightning {
|
||||
public:
|
||||
/**
|
||||
* Build a new lightning.
|
||||
* The lightning has a limited life time. It will also play a thunder sounder once.
|
||||
* @param lon lon longitude in degree
|
||||
* @param lat lat latitude in degree
|
||||
* @param alt asl of top of lightning
|
||||
*/
|
||||
SGLightning(double lon, double lat, double alt);
|
||||
~SGLightning();
|
||||
void lt_Render(void);
|
||||
void lt_build(void);
|
||||
void lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize);
|
||||
|
||||
// contains all the segments of the lightning
|
||||
lt_tree_seg lt_tree[MAX_LT_TREE_SEG];
|
||||
// segment count
|
||||
int nb_tree;
|
||||
// position of lightning
|
||||
double lon, lat, alt;
|
||||
int sequence_count;
|
||||
// time to live
|
||||
double age;
|
||||
};
|
||||
|
||||
typedef vector<SGLightning *> list_of_lightning;
|
||||
static list_of_lightning lightnings;
|
||||
|
||||
SGEnviro sgEnviro;
|
||||
|
||||
SGEnviro::SGEnviro(void) :
|
||||
view_in_cloud(false),
|
||||
turbulence_enable_state(false),
|
||||
precipitation_enable_state(true),
|
||||
lightning_enable_state(false),
|
||||
soundMgr(NULL),
|
||||
snd_active(false),
|
||||
snd_dist(0.0),
|
||||
last_cloud_turbulence(0.0),
|
||||
cloud_turbulence(0.0),
|
||||
elapsed_time(0.0),
|
||||
dt(0.0),
|
||||
min_time_before_lt(0.0),
|
||||
fov_width(55.0),
|
||||
fov_height(55.0),
|
||||
precipitation_max_alt(0.0),
|
||||
precipitation_density(100.0)
|
||||
|
||||
{
|
||||
for(int i = 0; i < MAX_RAIN_SLICE ; i++)
|
||||
rainpos[i] = sg_random();
|
||||
radarEcho.reserve(100);
|
||||
}
|
||||
|
||||
SGEnviro::~SGEnviro(void) {
|
||||
list_of_lightning::iterator iLightning;
|
||||
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
||||
delete (*iLightning);
|
||||
}
|
||||
lightnings.clear();
|
||||
}
|
||||
|
||||
void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) {
|
||||
view_in_cloud = false;
|
||||
// ask the impostor cache to do some cleanup
|
||||
if(SGNewCloud::cldCache)
|
||||
SGNewCloud::cldCache->startNewFrame();
|
||||
last_cloud_turbulence = cloud_turbulence;
|
||||
cloud_turbulence = 0.0;
|
||||
elapsed_time += delta_time;
|
||||
min_time_before_lt -= delta_time;
|
||||
dt = delta_time;
|
||||
|
||||
sgMat4 T1, LON, LAT;
|
||||
sgVec3 axis;
|
||||
|
||||
sgMakeTransMat4( T1, p );
|
||||
|
||||
sgSetVec3( axis, 0.0, 0.0, 1.0 );
|
||||
sgMakeRotMat4( LON, lon, axis );
|
||||
|
||||
sgSetVec3( axis, 0.0, 1.0, 0.0 );
|
||||
sgMakeRotMat4( LAT, 90.0 - lat, axis );
|
||||
|
||||
sgMat4 TRANSFORM;
|
||||
|
||||
sgCopyMat4( TRANSFORM, T1 );
|
||||
sgPreMultMat4( TRANSFORM, LON );
|
||||
sgPreMultMat4( TRANSFORM, LAT );
|
||||
|
||||
sgCoord pos;
|
||||
sgSetCoord( &pos, TRANSFORM );
|
||||
|
||||
sgMakeCoordMat4( transform, &pos );
|
||||
last_lon = lon;
|
||||
last_lat = lat;
|
||||
last_alt = alt;
|
||||
|
||||
radarEcho.clear();
|
||||
precipitation_max_alt = 400.0;
|
||||
}
|
||||
|
||||
void SGEnviro::endOfFrame(void) {
|
||||
}
|
||||
|
||||
double SGEnviro::get_cloud_turbulence(void) const {
|
||||
return last_cloud_turbulence;
|
||||
}
|
||||
|
||||
// this can be queried to add some turbulence for example
|
||||
bool SGEnviro::is_view_in_cloud(void) const {
|
||||
return view_in_cloud;
|
||||
}
|
||||
void SGEnviro::set_view_in_cloud(bool incloud) {
|
||||
view_in_cloud = incloud;
|
||||
}
|
||||
|
||||
int SGEnviro::get_CacheResolution(void) const {
|
||||
return SGCloudField::get_CacheResolution();
|
||||
}
|
||||
|
||||
int SGEnviro::get_clouds_CacheSize(void) const {
|
||||
return SGCloudField::get_CacheSize();
|
||||
}
|
||||
float SGEnviro::get_clouds_visibility(void) const {
|
||||
return SGCloudField::get_CloudVis();
|
||||
}
|
||||
float SGEnviro::get_clouds_density(void) const {
|
||||
return SGCloudField::get_density();
|
||||
}
|
||||
bool SGEnviro::get_clouds_enable_state(void) const {
|
||||
return SGCloudField::get_enable3dClouds();
|
||||
}
|
||||
|
||||
bool SGEnviro::get_turbulence_enable_state(void) const {
|
||||
return turbulence_enable_state;
|
||||
}
|
||||
|
||||
void SGEnviro::set_CacheResolution(int resolutionPixels) {
|
||||
SGCloudField::set_CacheResolution(resolutionPixels);
|
||||
}
|
||||
|
||||
void SGEnviro::set_clouds_CacheSize(int sizeKb) {
|
||||
SGCloudField::set_CacheSize(sizeKb);
|
||||
}
|
||||
void SGEnviro::set_clouds_visibility(float distance) {
|
||||
SGCloudField::set_CloudVis(distance);
|
||||
}
|
||||
void SGEnviro::set_clouds_density(float density) {
|
||||
SGCloudField::set_density(density);
|
||||
}
|
||||
void SGEnviro::set_clouds_enable_state(bool enable) {
|
||||
SGCloudField::set_enable3dClouds(enable);
|
||||
}
|
||||
void SGEnviro::set_turbulence_enable_state(bool enable) {
|
||||
turbulence_enable_state = enable;
|
||||
}
|
||||
// rain/snow
|
||||
float SGEnviro::get_precipitation_density(void) const {
|
||||
return precipitation_density;
|
||||
}
|
||||
bool SGEnviro::get_precipitation_enable_state(void) const {
|
||||
return precipitation_enable_state;
|
||||
}
|
||||
|
||||
void SGEnviro::set_precipitation_density(float density) {
|
||||
precipitation_density = density;
|
||||
}
|
||||
void SGEnviro::set_precipitation_enable_state(bool enable) {
|
||||
precipitation_enable_state = enable;
|
||||
}
|
||||
|
||||
// others
|
||||
bool SGEnviro::get_lightning_enable_state(void) const {
|
||||
return lightning_enable_state;
|
||||
}
|
||||
|
||||
void SGEnviro::set_lightning_enable_state(bool enable) {
|
||||
lightning_enable_state = enable;
|
||||
if( ! enable ) {
|
||||
// TODO:cleanup
|
||||
}
|
||||
}
|
||||
|
||||
void SGEnviro::setLight(sgVec4 adj_fog_color) {
|
||||
sgCopyVec4( fog_color, adj_fog_color );
|
||||
if( false ) {
|
||||
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
|
||||
}
|
||||
}
|
||||
|
||||
void SGEnviro::callback_cloud(float heading, float alt, float radius, int familly, float dist, int cloudId) {
|
||||
// send data to wx radar
|
||||
// compute turbulence
|
||||
// draw precipitation
|
||||
// draw lightning
|
||||
// compute illumination
|
||||
|
||||
// http://www.pilotfriend.com/flight_training/weather/THUNDERSTORM%20HAZARDS1.htm
|
||||
double turbulence = 0.0;
|
||||
if( dist < radius * radius * 2.25f ) {
|
||||
switch(familly) {
|
||||
case SGNewCloud::CLFamilly_st:
|
||||
turbulence = 0.2;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_ci:
|
||||
case SGNewCloud::CLFamilly_cs:
|
||||
case SGNewCloud::CLFamilly_cc:
|
||||
case SGNewCloud::CLFamilly_ac:
|
||||
case SGNewCloud::CLFamilly_as:
|
||||
turbulence = 0.1;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_sc:
|
||||
turbulence = 0.3;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_ns:
|
||||
turbulence = 0.4;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_cu:
|
||||
turbulence = 0.5;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_cb:
|
||||
turbulence = 0.6;
|
||||
break;
|
||||
}
|
||||
// full turbulence inside cloud, half in the vicinity
|
||||
if( dist > radius * radius )
|
||||
turbulence *= 0.5;
|
||||
if( turbulence > cloud_turbulence )
|
||||
cloud_turbulence = turbulence;
|
||||
// we can do 'local' precipitations too
|
||||
}
|
||||
|
||||
// convert to LWC for radar (experimental)
|
||||
// http://www-das.uwyo.edu/~geerts/cwx/notes/chap08/moist_cloud.html
|
||||
double LWC = 0.0;
|
||||
switch(familly) {
|
||||
case SGNewCloud::CLFamilly_st:
|
||||
LWC = 0.29;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_cu:
|
||||
LWC = 0.27;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_cb:
|
||||
LWC = 2.0;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_sc:
|
||||
LWC = 0.44;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_ci:
|
||||
LWC = 0.03;
|
||||
break;
|
||||
// no data
|
||||
case SGNewCloud::CLFamilly_cs:
|
||||
case SGNewCloud::CLFamilly_cc:
|
||||
case SGNewCloud::CLFamilly_ac:
|
||||
case SGNewCloud::CLFamilly_as:
|
||||
LWC = 0.03;
|
||||
break;
|
||||
case SGNewCloud::CLFamilly_ns:
|
||||
LWC = 0.29*2.0;
|
||||
break;
|
||||
}
|
||||
// add to the list for the wxRadar instrument
|
||||
if( LWC > 0.0 )
|
||||
radarEcho.push_back( SGWxRadarEcho ( heading, alt, radius, dist, LWC, false, cloudId ) );
|
||||
|
||||
// NB:data valid only from cockpit view
|
||||
|
||||
// spawn a new lightning
|
||||
if(lightning_enable_state && min_time_before_lt <= 0.0 && (familly == SGNewCloud::CLFamilly_cb) &&
|
||||
dist < 15000.0 * 15000.0 && sg_random() > 0.9f) {
|
||||
double lat, lon;
|
||||
Point3D orig, dest;
|
||||
orig.setlat(last_lat * SG_DEGREES_TO_RADIANS );
|
||||
orig.setlon(last_lon * SG_DEGREES_TO_RADIANS );
|
||||
orig.setelev(0.0);
|
||||
dist = sgSqrt(dist);
|
||||
dest = calc_gc_lon_lat(orig, heading, dist);
|
||||
lon = dest.lon() * SG_RADIANS_TO_DEGREES;
|
||||
lat = dest.lat() * SG_RADIANS_TO_DEGREES;
|
||||
addLightning( lon, lat, alt );
|
||||
|
||||
// reset timer
|
||||
min_time_before_lt = 5.0 + sg_random() * 30;
|
||||
// DEBUG only
|
||||
// min_time_before_lt = 5.0;
|
||||
}
|
||||
if( (alt - radius * 0.1) > precipitation_max_alt )
|
||||
switch(familly) {
|
||||
case SGNewCloud::CLFamilly_st:
|
||||
case SGNewCloud::CLFamilly_cu:
|
||||
case SGNewCloud::CLFamilly_cb:
|
||||
case SGNewCloud::CLFamilly_ns:
|
||||
case SGNewCloud::CLFamilly_sc:
|
||||
precipitation_max_alt = alt - radius * 0.1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
|
||||
return &radarEcho;
|
||||
}
|
||||
|
||||
// precipitation rendering code
|
||||
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
|
||||
|
||||
sgVec3 light;
|
||||
sgVec3 min_light = {0.35, 0.35, 0.35};
|
||||
sgAddVec3( light, fog_color, min_light );
|
||||
float da = SG_PI * 2.0f / (float) slices;
|
||||
// low number = faster
|
||||
float speedf = 2.5f - speed / 200.0;
|
||||
if( speedf < 1.0f )
|
||||
speedf = 1.0f;
|
||||
float lenf = 0.03f + speed / 2000.0;
|
||||
if( lenf > 0.10f )
|
||||
lenf = 0.10f;
|
||||
float t = fmod((float) elapsed_time, speedf) / speedf;
|
||||
// t = 0.1f;
|
||||
if( !down )
|
||||
t = 1.0f - t;
|
||||
float angle = 0.0f;
|
||||
glColor4f(1.0f, 0.7f, 0.7f, 0.9f);
|
||||
glBegin(GL_LINES);
|
||||
int rainpos_indice = 0;
|
||||
for( int i = 0 ; i < slices ; i++ ) {
|
||||
float x = cos(angle) * baseRadius;
|
||||
float y = sin(angle) * baseRadius;
|
||||
angle += da;
|
||||
sgVec3 dir = {x, -height, y};
|
||||
|
||||
// rain drops at 2 different speed to simulate depth
|
||||
float t1 = (i & 1 ? t : t + t) + rainpos[rainpos_indice];
|
||||
if(t1 > 1.0f) t1 -= 1.0f;
|
||||
if(t1 > 1.0f) t1 -= 1.0f;
|
||||
|
||||
// distant raindrops are more transparent
|
||||
float c = (i & 1 ? t1 * 0.5f : t1 * 0.9f);
|
||||
glColor4f(c * light[0], c * light[1], c * light[2], c);
|
||||
sgVec3 p1, p2;
|
||||
sgScaleVec3(p1, dir, t1);
|
||||
// distant raindrops are shorter
|
||||
float t2 = t1 + (i & 1 ? lenf : lenf+lenf);
|
||||
sgScaleVec3(p2, dir, t2);
|
||||
|
||||
glVertex3f(p1[0], p1[1] + height, p1[2]);
|
||||
glVertex3f(p2[0], p2[1] + height, p2[2]);
|
||||
if( ++rainpos_indice >= MAX_RAIN_SLICE )
|
||||
rainpos_indice = 0;
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void SGEnviro::drawRain(double pitch, double roll, double heading, double speed, double rain_norm) {
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glDisable( GL_FOG );
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
int slice_count = (40.0 + rain_norm*150.0)* precipitation_density / 100.0;
|
||||
|
||||
float angle = speed;
|
||||
if( angle > 90.0 )
|
||||
angle = 90.0;
|
||||
|
||||
glPushMatrix();
|
||||
// TODO:find the real view orientation, not the AC one
|
||||
// the cone rotate with speed
|
||||
angle = -pitch - angle;
|
||||
glRotatef(angle, 1.0, 0.0, 0.0);
|
||||
glRotatef(roll, 0.0, 1.0, 0.0);
|
||||
glRotatef(heading, 0.0, 0.0, 1.0);
|
||||
|
||||
// up cone
|
||||
DrawCone2(15.0, 30.0, slice_count, true, rain_norm, speed);
|
||||
// down cone (usually not visible)
|
||||
if(angle > 0.0 || heading != 0.0)
|
||||
DrawCone2(15.0, -30.0, slice_count, false, rain_norm, speed);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
||||
glEnable( GL_FOG );
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
}
|
||||
|
||||
void SGEnviro::set_soundMgr(SGSoundMgr *mgr) {
|
||||
soundMgr = mgr;
|
||||
}
|
||||
|
||||
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double speed) {
|
||||
if( precipitation_enable_state && rain_norm > 0.0)
|
||||
if( precipitation_max_alt >= last_alt )
|
||||
drawRain(pitch, roll, heading, speed, rain_norm);
|
||||
}
|
||||
|
||||
|
||||
SGLightning::SGLightning(double _lon, double _lat, double _alt) :
|
||||
lon(_lon),
|
||||
lat(_lat),
|
||||
alt(_alt),
|
||||
age(1.0 + sg_random() * 4.0),
|
||||
nb_tree(0)
|
||||
{
|
||||
// sequence_count = 1 + sg_random() * 5.0;
|
||||
lt_build();
|
||||
}
|
||||
|
||||
SGLightning::~SGLightning() {
|
||||
}
|
||||
|
||||
// lightning rendering code
|
||||
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
|
||||
|
||||
sgVec3 dir, newdir;
|
||||
int nseg = 0;
|
||||
Point3D pt = start;
|
||||
if( nbseg == 50 )
|
||||
sgSetVec3( dir, 0.0, -1.0, 0.0 );
|
||||
else {
|
||||
sgSetVec3( dir, sg_random() - 0.5f, sg_random() - 0.5f, sg_random() - 0.5f);
|
||||
sgNormaliseVec3(dir);
|
||||
}
|
||||
if( nb_tree >= MAX_LT_TREE_SEG )
|
||||
return;
|
||||
|
||||
lt_tree[nb_tree].depth = tree_nr;
|
||||
nseg = 0;
|
||||
lt_tree[nb_tree].pt = pt;
|
||||
lt_tree[nb_tree].prev = -1;
|
||||
nb_tree ++;
|
||||
|
||||
// TODO:check agl
|
||||
while(nseg < nbseg && pt.y() > 0.0) {
|
||||
int prev = nb_tree - 1;
|
||||
nseg++;
|
||||
// add a branch
|
||||
if( energy * sg_random() > 0.8f )
|
||||
lt_build_tree_branch(tree_nr + 1, pt, energy * 0.9f, nbseg == 50 ? 10 : nbseg * 0.4f, segsize * 0.7f);
|
||||
|
||||
if( nb_tree >= MAX_LT_TREE_SEG )
|
||||
return;
|
||||
sgSetVec3(newdir, (sg_random() - 0.5f), (sg_random() - 0.5f) - (nbseg == 50 ? 0.5f : 0.0), (sg_random() - 0.5f));
|
||||
sgNormaliseVec3(newdir);
|
||||
sgAddVec3( dir, newdir);
|
||||
sgNormaliseVec3(dir);
|
||||
sgVec3 scaleDir;
|
||||
sgScaleVec3( scaleDir, dir, segsize * energy * 0.5f );
|
||||
pt[PX] += scaleDir[0];
|
||||
pt[PY] += scaleDir[1];
|
||||
pt[PZ] += scaleDir[2];
|
||||
|
||||
lt_tree[nb_tree].depth = tree_nr;
|
||||
lt_tree[nb_tree].pt = pt;
|
||||
lt_tree[nb_tree].prev = prev;
|
||||
nb_tree ++;
|
||||
}
|
||||
}
|
||||
|
||||
void SGLightning::lt_build(void) {
|
||||
Point3D top;
|
||||
nb_tree = 0;
|
||||
top[PX] = 0 ;
|
||||
top[PY] = alt;
|
||||
top[PZ] = 0;
|
||||
lt_build_tree_branch(0, top, 1.0, 50, top[PY] / 8.0);
|
||||
if( ! sgEnviro.soundMgr )
|
||||
return;
|
||||
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
double course = 0.0, dist = 0.0;
|
||||
calc_gc_course_dist( dest, start, &course, &dist );
|
||||
if( dist < 10000.0 && ! sgEnviro.snd_playing && (dist < sgEnviro.snd_dist || ! sgEnviro.snd_active) ) {
|
||||
sgEnviro.snd_timer = 0.0;
|
||||
sgEnviro.snd_wait = dist / 340;
|
||||
sgEnviro.snd_dist = dist;
|
||||
sgEnviro.snd_pos_lat = lat;
|
||||
sgEnviro.snd_pos_lon = lon;
|
||||
sgEnviro.snd_active = true;
|
||||
sgEnviro.snd_playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SGLightning::lt_Render(void) {
|
||||
float flash = 0.5;
|
||||
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
|
||||
flash = sg_random() * 0.75f + 0.25f;
|
||||
float h = lt_tree[0].pt[PY];
|
||||
sgVec4 col={0.62f, 0.83f, 1.0f, 1.0f};
|
||||
sgVec4 c;
|
||||
|
||||
#define DRAW_SEG() \
|
||||
{glBegin(GL_LINES); \
|
||||
glColor4fv(c); \
|
||||
glVertex3f(lt_tree[n].pt[PX], lt_tree[n].pt[PZ], lt_tree[n].pt[PY]); \
|
||||
glVertex3f(lt_tree[lt_tree[n].prev].pt[PX], lt_tree[lt_tree[n].prev].pt[PZ], lt_tree[lt_tree[n].prev].pt[PY]); \
|
||||
glEnd();}
|
||||
|
||||
glDepthMask( GL_FALSE );
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable( GL_FOG );
|
||||
glPushMatrix();
|
||||
sgMat4 modelview, tmp;
|
||||
ssgGetModelviewMatrix( modelview );
|
||||
sgCopyMat4( tmp, sgEnviro.transform );
|
||||
sgPostMultMat4( tmp, modelview );
|
||||
ssgLoadModelviewMatrix( tmp );
|
||||
|
||||
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
double course = 0.0, dist = 0.0;
|
||||
calc_gc_course_dist( dest, start, &course, &dist );
|
||||
double ax = 0.0, ay = 0.0;
|
||||
ax = cos(course) * dist;
|
||||
ay = sin(course) * dist;
|
||||
|
||||
glTranslatef( ax, ay, -sgEnviro.last_alt );
|
||||
|
||||
sgEnviro.radarEcho.push_back( SGWxRadarEcho ( course, 0.0, 0.0, dist, age, true, 0 ) );
|
||||
|
||||
for( int n = 0 ; n < nb_tree ; n++ ) {
|
||||
if( lt_tree[n].prev < 0 )
|
||||
continue;
|
||||
|
||||
float t1 = sgLerp(0.5, 1.0, lt_tree[n].pt[PY] / h);
|
||||
t1 *= flash;
|
||||
if( lt_tree[n].depth >= 2 ) {
|
||||
glLineWidth(3);
|
||||
sgScaleVec4(c, col, t1 * 0.6f);
|
||||
DRAW_SEG();
|
||||
} else {
|
||||
if( lt_tree[n].depth == 0 ) {
|
||||
glLineWidth(12);
|
||||
sgScaleVec4(c, col, t1 * 0.5f);
|
||||
DRAW_SEG();
|
||||
|
||||
glLineWidth(6);
|
||||
sgScaleVec4(c, col, t1);
|
||||
DRAW_SEG();
|
||||
} else {
|
||||
glLineWidth(6);
|
||||
sgScaleVec4(c, col, t1 * 0.7f);
|
||||
DRAW_SEG();
|
||||
}
|
||||
|
||||
if( lt_tree[n].depth == 0 )
|
||||
glLineWidth(3);
|
||||
else
|
||||
glLineWidth(2);
|
||||
|
||||
sgSetVec4(c, t1, t1, t1, t1);
|
||||
DRAW_SEG();
|
||||
}
|
||||
|
||||
}
|
||||
glLineWidth(1);
|
||||
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
|
||||
glPopMatrix();
|
||||
glDepthMask( GL_TRUE );
|
||||
glEnable( GL_FOG );
|
||||
glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
void SGEnviro::addLightning(double lon, double lat, double alt) {
|
||||
if( lightnings.size() > 10)
|
||||
return;
|
||||
SGLightning *lt= new SGLightning(lon, lat, alt);
|
||||
lightnings.push_back(lt);
|
||||
}
|
||||
|
||||
void SGEnviro::drawLightning(void) {
|
||||
list_of_lightning::iterator iLightning;
|
||||
// play 'thunder' for lightning
|
||||
if( snd_active )
|
||||
if( !snd_playing ) {
|
||||
// wait until sound has reached us
|
||||
snd_timer += dt;
|
||||
if( snd_timer >= snd_wait ) {
|
||||
snd_playing = true;
|
||||
// compute relative position of lightning
|
||||
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
Point3D dest( snd_pos_lon*SG_DEGREES_TO_RADIANS, snd_pos_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
double course = 0.0, dist = 0.0;
|
||||
calc_gc_course_dist( dest, start, &course, &dist );
|
||||
double ax = 0.0, ay = 0.0;
|
||||
ax = cos(course) * dist;
|
||||
ay = sin(course) * dist;
|
||||
SGSoundSample *snd = soundMgr->find("thunder");
|
||||
if( snd ) {
|
||||
ALfloat pos[3]={ax, ay, -sgEnviro.last_alt };
|
||||
snd->set_source_pos(pos);
|
||||
snd->play_once();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if( !soundMgr->is_playing("thunder") ) {
|
||||
snd_active = false;
|
||||
snd_playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( ! lightning_enable_state )
|
||||
return;
|
||||
|
||||
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
||||
if( dt )
|
||||
if( sg_random() > 0.95f )
|
||||
(*iLightning)->lt_build();
|
||||
(*iLightning)->lt_Render();
|
||||
(*iLightning)->age -= dt;
|
||||
if( (*iLightning)->age < 0.0 ) {
|
||||
delete (*iLightning);
|
||||
lightnings.erase( iLightning );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SGEnviro::setFOV( float w, float h ) {
|
||||
fov_width = w;
|
||||
fov_height = h;
|
||||
}
|
||||
|
||||
void SGEnviro::getFOV( float &w, float &h ) {
|
||||
w = fov_width;
|
||||
h = fov_height;
|
||||
}
|
||||
228
simgear/environment/visual_enviro.hxx
Normal file
228
simgear/environment/visual_enviro.hxx
Normal file
@@ -0,0 +1,228 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
//
|
||||
//
|
||||
#ifndef _VISUAL_ENVIRO_HXX
|
||||
#define _VISUAL_ENVIRO_HXX
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include STL_STRING
|
||||
#include <vector>
|
||||
|
||||
SG_USING_STD(vector);
|
||||
SG_USING_STD(string);
|
||||
|
||||
class SGLightning;
|
||||
class SGSoundMgr;
|
||||
|
||||
/**
|
||||
* Simulate some echo on a weather radar.
|
||||
* Container class for the wx radar instrument.
|
||||
*/
|
||||
class SGWxRadarEcho {
|
||||
public:
|
||||
SGWxRadarEcho(float _heading, float _alt, float _radius, float _dist, double _LWC, bool _lightning, int _cloudId) :
|
||||
heading( _heading ),
|
||||
alt ( _alt ),
|
||||
radius ( _radius ),
|
||||
dist ( _dist ),
|
||||
LWC ( _LWC ),
|
||||
lightning ( _lightning ),
|
||||
cloudId ( _cloudId )
|
||||
{}
|
||||
|
||||
/** the heading in radian is versus north */
|
||||
float heading;
|
||||
float alt, radius, dist;
|
||||
/** reflectivity converted to liquid water content. */
|
||||
double LWC;
|
||||
/** if true then this data is for a lightning else it is for water echo. */
|
||||
bool lightning;
|
||||
/** Unique identifier of cloud */
|
||||
int cloudId;
|
||||
};
|
||||
|
||||
typedef vector<SGWxRadarEcho> list_of_SGWxRadarEcho;
|
||||
|
||||
/**
|
||||
* Visual environment helper class.
|
||||
*/
|
||||
class SGEnviro {
|
||||
friend class SGLightning;
|
||||
private:
|
||||
void DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed);
|
||||
void lt_update(void);
|
||||
|
||||
bool view_in_cloud;
|
||||
bool precipitation_enable_state;
|
||||
float precipitation_density;
|
||||
float precipitation_max_alt;
|
||||
bool turbulence_enable_state;
|
||||
double last_cloud_turbulence, cloud_turbulence;
|
||||
bool lightning_enable_state;
|
||||
double elapsed_time, dt;
|
||||
sgVec4 fog_color;
|
||||
sgMat4 transform;
|
||||
double last_lon, last_lat, last_alt;
|
||||
SGSoundMgr *soundMgr;
|
||||
bool snd_active, snd_playing;
|
||||
double snd_timer, snd_wait, snd_pos_lat, snd_pos_lon, snd_dist;
|
||||
double min_time_before_lt;
|
||||
|
||||
float fov_width, fov_height;
|
||||
|
||||
/** a list of all the radar echo. */
|
||||
list_of_SGWxRadarEcho radarEcho;
|
||||
|
||||
public:
|
||||
SGEnviro();
|
||||
~SGEnviro();
|
||||
|
||||
/**
|
||||
* Forward a few states used for renderings.
|
||||
*/
|
||||
void startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time);
|
||||
|
||||
void endOfFrame(void);
|
||||
|
||||
/**
|
||||
* Whenever a cloud is drawn we check his 'impact' on the environment.
|
||||
* @param heading direction of cloud in radians
|
||||
* @param alt asl of cloud in meters
|
||||
* @param radius radius of cloud in meters
|
||||
* @param familly cloud familly
|
||||
* @param dist squared dist to cloud in meters
|
||||
*/
|
||||
void callback_cloud(float heading, float alt, float radius, int familly, float dist, int cloudId);
|
||||
|
||||
void drawRain(double pitch, double roll, double heading, double speed, double rain_norm);
|
||||
/**
|
||||
* Draw rain or snow precipitation around the viewer.
|
||||
* @param rain_norm rain normalized intensity given by metar class
|
||||
* @param snow_norm snow normalized intensity given by metar class
|
||||
* @param hail_norm hail normalized intensity given by metar class
|
||||
* @param pitch pitch rotation of viewer
|
||||
* @param roll roll rotation of viewer
|
||||
* @param speed moving speed of viewer in kt
|
||||
*/
|
||||
void drawPrecipitation(double rain_norm, double snow_norm, double hail_norm,
|
||||
double pitch, double roll, double heading, double speed);
|
||||
|
||||
/**
|
||||
* Draw the lightnings spawned by cumulo nimbus.
|
||||
*/
|
||||
void drawLightning(void);
|
||||
|
||||
/**
|
||||
* Forward the fog color used by the rain rendering.
|
||||
* @param adj_fog_color color of the fog
|
||||
*/
|
||||
void setLight(sgVec4 adj_fog_color);
|
||||
|
||||
// this can be queried to add some turbulence for example
|
||||
bool is_view_in_cloud(void) const;
|
||||
void set_view_in_cloud(bool incloud);
|
||||
double get_cloud_turbulence(void) const;
|
||||
|
||||
// Clouds
|
||||
// return the size of the memory pool used by texture impostors
|
||||
int get_clouds_CacheSize(void) const;
|
||||
int get_CacheResolution(void) const;
|
||||
float get_clouds_visibility(void) const;
|
||||
float get_clouds_density(void) const;
|
||||
bool get_clouds_enable_state(void) const;
|
||||
bool get_turbulence_enable_state(void) const;
|
||||
|
||||
/**
|
||||
* Set the size of the impostor texture cache for 3D clouds.
|
||||
* @param sizeKb size of the texture pool in Kb
|
||||
*/
|
||||
void set_clouds_CacheSize(int sizeKb);
|
||||
/**
|
||||
* Set the resolution of the impostor texture for 3D clouds.
|
||||
* @param resolutionPixels size of each texture in pixels (64|128|256)
|
||||
*/
|
||||
void set_CacheResolution(int resolutionPixels);
|
||||
/**
|
||||
* Set the maximum range used when drawing clouds.
|
||||
* Clouds are blended from totaly transparent at max range to totaly opaque around the viewer
|
||||
* @param distance in meters
|
||||
*/
|
||||
void set_clouds_visibility(float distance);
|
||||
/**
|
||||
* Set the proportion of clouds that will be rendered to limit drop in FPS.
|
||||
* @param density 0..100 no clouds drawn when density == 0, all are drawn when density == 100
|
||||
*/
|
||||
void set_clouds_density(float density);
|
||||
/**
|
||||
* Enable or disable the use of 3D clouds.
|
||||
* @param enable when false we draw the 2D layers
|
||||
*/
|
||||
void set_clouds_enable_state(bool enable);
|
||||
/**
|
||||
* Enable or disable the use of proximity cloud turbulence.
|
||||
* @param enable when true the turbulence is computed based on type of cloud around the AC
|
||||
*/
|
||||
void set_turbulence_enable_state(bool enable);
|
||||
|
||||
// rain/snow
|
||||
float get_precipitation_density(void) const;
|
||||
bool get_precipitation_enable_state(void) const;
|
||||
|
||||
void set_precipitation_density(float density);
|
||||
/**
|
||||
* Enable or disable the rendering of precipitation around the viewer.
|
||||
* @param enable when true we will draw precipitation depending on metar data
|
||||
*/
|
||||
void set_precipitation_enable_state(bool enable);
|
||||
|
||||
// others
|
||||
bool get_lightning_enable_state(void) const;
|
||||
/**
|
||||
* Enable or disable the rendering of lightning and the thunder sound.
|
||||
* @param enable when true we will draw lightning spwaned by cumulonimbus
|
||||
*/
|
||||
void set_lightning_enable_state(bool enable);
|
||||
|
||||
/**
|
||||
* Spawn a new lighning at specified lon/lat.
|
||||
* @param lon position of the new lightning
|
||||
* @param lat position of the new lightning
|
||||
* @param alt asl of the starting point of the lightning in meters
|
||||
*/
|
||||
void addLightning(double lon, double lat, double alt);
|
||||
|
||||
/**
|
||||
* Forward the sound manager instance to be able to play samples.
|
||||
* @param mgr a running sound manager
|
||||
*/
|
||||
void set_soundMgr(SGSoundMgr *mgr);
|
||||
|
||||
void setFOV( float w, float h );
|
||||
void getFOV( float &w, float &h );
|
||||
|
||||
list_of_SGWxRadarEcho *get_radar_echo(void);
|
||||
|
||||
sgMat4 *get_transform(void) { return &transform; }
|
||||
};
|
||||
|
||||
extern SGEnviro sgEnviro;
|
||||
|
||||
#endif // _VISUAL_ENVIRO_HXX
|
||||
@@ -3,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>
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -80,7 +80,7 @@ void Star::updatePosition(double mjd)
|
||||
double
|
||||
actTime, eccAnom,
|
||||
xv, yv, v, r,
|
||||
xe, ye, ze, ecl;
|
||||
xe, ecl;
|
||||
|
||||
updateOrbElements(mjd);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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; };
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ static double seaLevelRadius(double r, double z)
|
||||
// starts making very poor guesses as to latitude. As altitude
|
||||
// approaches infinity, it should be guessing with geocentric
|
||||
// coordinates, not "local geodetic up" ones.
|
||||
void sgCartToGeod(double* xyz, double* lat, double* lon, double* alt)
|
||||
void sgCartToGeod(const double* xyz, double* lat, double* lon, double* alt)
|
||||
{
|
||||
// The error is expressed as a radian angle, and we want accuracy
|
||||
// to 1 part in 2^50 (an IEEE double has between 51 and 52
|
||||
|
||||
@@ -42,7 +42,7 @@ void sgGeodToGeoc(double lat_geod, double alt,
|
||||
* @param lon (out) Longitude, in radians
|
||||
* @param alt (out) Altitude, in meters above the WGS84 ellipsoid
|
||||
*/
|
||||
void sgCartToGeod(double* xyz, double* lat, double* lon, double* alt);
|
||||
void sgCartToGeod(const double* xyz, double* lat, double* lon, double* alt);
|
||||
|
||||
/**
|
||||
* Convert a cartesian point to a geodetic lat/lon/altitude.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -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)
|
||||
|
||||
@@ -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 "";
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
94
simgear/misc/stdint.hxx
Normal 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
|
||||
|
||||
@@ -41,14 +41,14 @@ namespace simgear {
|
||||
|
||||
while (i < len)
|
||||
{
|
||||
while (i < len && isspace(str[i]))
|
||||
while (i < len && isspace((unsigned char)str[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
j = i;
|
||||
|
||||
while (i < len && !isspace(str[i]))
|
||||
while (i < len && !isspace((unsigned char)str[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ namespace simgear {
|
||||
{
|
||||
result.push_back( str.substr(j, i-j) );
|
||||
++countsplit;
|
||||
while (i < len && isspace(str[i]))
|
||||
while (i < len && isspace((unsigned char)str[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
20
simgear/misc/swap_test.cpp
Normal file
20
simgear/misc/swap_test.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include "stdint.hxx"
|
||||
|
||||
int main()
|
||||
{
|
||||
uint16_t sui16, ui16 = 0x0123;
|
||||
uint32_t sui32, ui32 = 0x01234567;
|
||||
uint64_t sui64, ui64 = 0x0123456789ABCDEFLL;
|
||||
|
||||
sui16 = ui16; sgEndianSwap(&sui16);
|
||||
sui32 = ui32; sgEndianSwap(&sui32);
|
||||
sui64 = ui64; sgEndianSwap(&sui64);
|
||||
|
||||
printf("\nUI16: %x (normal)\t\t %x (swapped)\n", ui16, sui16 );
|
||||
printf("UI32: %x (normal)\t\t %x (swapped)\n", ui32, sui32 );
|
||||
printf("UI64: %llx (normal)\t %llx (swapped)\n\n", ui64, sui64 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2,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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
// double.
|
||||
#define DIGITS 16
|
||||
|
||||
// The minimum size we'll allocate for a string. Since a string
|
||||
// structure is already 12 bytes, and each naRef that points to it is
|
||||
// 8, there isn't much point in being stingy.
|
||||
#define MINLEN 16
|
||||
|
||||
static int tonum(unsigned char* s, int len, double* result);
|
||||
static int fromnum(double val, unsigned char* s);
|
||||
|
||||
@@ -25,21 +20,22 @@ int naStr_len(naRef s)
|
||||
char* naStr_data(naRef s)
|
||||
{
|
||||
if(!IS_STR(s)) return 0;
|
||||
return s.ref.ptr.str->data;
|
||||
return (char*)s.ref.ptr.str->data;
|
||||
}
|
||||
|
||||
static void setlen(struct naStr* s, int sz)
|
||||
{
|
||||
int currSz, waste;
|
||||
sz += 1; // Allow for an extra nul terminator
|
||||
currSz = s->len+1 < MINLEN ? MINLEN : s->len+1;
|
||||
waste = currSz - sz; // how much extra if we don't reallocate?
|
||||
if(s->data == 0 || waste < 0 || waste > MINLEN) {
|
||||
naFree(s->data);
|
||||
s->data = naAlloc(sz < MINLEN ? MINLEN : sz);
|
||||
}
|
||||
s->len = sz - 1;
|
||||
s->data[s->len] = 0; // nul terminate
|
||||
if(s->data) naFree(s->data);
|
||||
s->len = sz;
|
||||
s->data = naAlloc(sz+1);
|
||||
s->data[sz] = 0; // nul terminate
|
||||
}
|
||||
|
||||
naRef naStr_buf(naRef dst, int len)
|
||||
{
|
||||
setlen(dst.ref.ptr.str, len);
|
||||
naBZero(dst.ref.ptr.str->data, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
naRef naStr_fromdata(naRef dst, char* data, int len)
|
||||
@@ -94,7 +90,7 @@ naRef naStr_fromnum(naRef dest, double num)
|
||||
|
||||
int naStr_parsenum(char* str, int len, double* result)
|
||||
{
|
||||
return tonum(str, len, result);
|
||||
return tonum((unsigned char*)str, len, result);
|
||||
}
|
||||
|
||||
int naStr_tonum(naRef str, double* out)
|
||||
@@ -110,10 +106,8 @@ int naStr_numeric(naRef str)
|
||||
|
||||
void naStr_gcclean(struct naStr* str)
|
||||
{
|
||||
if(str->len > MINLEN) {
|
||||
naFree(str->data);
|
||||
str->data = 0;
|
||||
}
|
||||
naFree(str->data);
|
||||
str->data = 0;
|
||||
str->len = 0;
|
||||
}
|
||||
|
||||
@@ -147,17 +141,21 @@ static int readdec(unsigned char* s, int len, int i, double* v)
|
||||
|
||||
// Reads a signed integer out of the string starting at i, stores it
|
||||
// in v, and returns the next index to start at. Zero-length
|
||||
// decimal numbers (and length-1 strings like '+') are allowed, and
|
||||
// are returned as zero.
|
||||
// decimal numbers are allowed, and are returned as zero.
|
||||
static int readsigned(unsigned char* s, int len, int i, double* v)
|
||||
{
|
||||
int i0 = i, i2;
|
||||
double sgn=1, val;
|
||||
if(i >= len) { *v = 0; return len; }
|
||||
if(s[i] == '+') { i++; }
|
||||
else if(s[i] == '-') { i++; sgn = -1; }
|
||||
i = readdec(s, len, i, &val);
|
||||
i2 = readdec(s, len, i, &val);
|
||||
if(i0 == i && i2 == i) {
|
||||
*v = 0;
|
||||
return i0; // don't successfully parse bare "+" or "-"
|
||||
}
|
||||
*v = sgn*val;
|
||||
return i;
|
||||
return i2;
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +178,17 @@ static int tonum(unsigned char* s, int len, double* result)
|
||||
int i=0, fraclen=0;
|
||||
double sgn=1, val, frac=0, exp=0;
|
||||
|
||||
// Special case, "." is not a number, even though "1." and ".0" are.
|
||||
if(len == 1 && s[0] == '.')
|
||||
return 0;
|
||||
|
||||
// Strip off the leading negative sign first, so we can correctly
|
||||
// parse things like -.xxx which would otherwise confuse
|
||||
// readsigned.
|
||||
if(len > 1 && s[0] == '-' && s[1] != '-') {
|
||||
sgn = -1; s++; len--;
|
||||
}
|
||||
|
||||
// Read the integer part
|
||||
i = readsigned(s, len, i, &val);
|
||||
if(val < 0) { sgn = -1; val = -val; }
|
||||
@@ -191,9 +200,15 @@ static int tonum(unsigned char* s, int len, double* result)
|
||||
i += fraclen;
|
||||
}
|
||||
|
||||
// Nothing so far? Then the parse failed.
|
||||
if(i == 0) return 0;
|
||||
|
||||
// Read the exponent, if any
|
||||
if(i < len && (s[i] == 'e' || s[i] == 'E'))
|
||||
if(i < len && (s[i] == 'e' || s[i] == 'E')) {
|
||||
int i0 = i+1;
|
||||
i = readsigned(s, len, i+1, &exp);
|
||||
if(i == i0) return 0; // Must have a number after the "e"
|
||||
}
|
||||
|
||||
// compute the result
|
||||
*result = sgn * (val + frac * decpow(-fraclen)) * decpow(exp);
|
||||
@@ -205,13 +220,13 @@ static int tonum(unsigned char* s, int len, double* result)
|
||||
|
||||
// Very simple positive (!) integer print routine. Puts the result in
|
||||
// s and returns the number of characters written. Does not null
|
||||
// terminate the result.
|
||||
// terminate the result. Presumes at least a 32 bit integer, and
|
||||
// cannot print integers larger than 9999999999.
|
||||
static int decprint(int val, unsigned char* s)
|
||||
{
|
||||
int p=1, i=0;
|
||||
if(val == 0) { *s = '0'; return 1; }
|
||||
while(p <= val) p *= 10;
|
||||
p /= 10;
|
||||
while(p <= 999999999 && p*10 <= val) p *= 10;
|
||||
while(p > 0) {
|
||||
int count = 0;
|
||||
while(val >= p) { val -= p; count++; }
|
||||
@@ -270,7 +285,7 @@ static int fromnum(double val, unsigned char* s)
|
||||
if(raw[i] != '0') break;
|
||||
digs = i+1;
|
||||
|
||||
if(exp > 0 || exp < -(DIGITS+2)) {
|
||||
if(exp > 0 || exp < -(DIGITS+3)) {
|
||||
// Standard scientific notation
|
||||
exp += DIGITS-1;
|
||||
*ptr++ = raw[0];
|
||||
|
||||
59
simgear/nasal/thread-posix.c
Normal file
59
simgear/nasal/thread-posix.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <pthread.h>
|
||||
#include "code.h"
|
||||
|
||||
void* naNewLock()
|
||||
{
|
||||
pthread_mutex_t* lock = naAlloc(sizeof(pthread_mutex_t));
|
||||
pthread_mutex_init(lock, 0);
|
||||
return lock;
|
||||
}
|
||||
|
||||
void naLock(void* lock)
|
||||
{
|
||||
pthread_mutex_lock((pthread_mutex_t*)lock);
|
||||
}
|
||||
|
||||
void naUnlock(void* lock)
|
||||
{
|
||||
pthread_mutex_unlock((pthread_mutex_t*)lock);
|
||||
}
|
||||
|
||||
struct naSem {
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cvar;
|
||||
int count;
|
||||
};
|
||||
|
||||
void* naNewSem()
|
||||
{
|
||||
struct naSem* sem = naAlloc(sizeof(struct naSem));
|
||||
pthread_mutex_init(&sem->lock , 0);
|
||||
pthread_cond_init(&sem->cvar, 0);
|
||||
sem->count = 0;
|
||||
return sem;
|
||||
}
|
||||
|
||||
void naSemDown(void* sh)
|
||||
{
|
||||
struct naSem* sem = (struct naSem*)sh;
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
while(sem->count <= 0)
|
||||
pthread_cond_wait(&sem->cvar, &sem->lock);
|
||||
sem->count--;
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
}
|
||||
|
||||
void naSemUpAll(void* sh, int count)
|
||||
{
|
||||
struct naSem* sem = (struct naSem*)sh;
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
sem->count = count;
|
||||
pthread_cond_broadcast(&sem->cvar);
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extern int GccWarningWorkaround_IsoCForbidsAnEmptySourceFile;
|
||||
22
simgear/nasal/thread-win32.c
Normal file
22
simgear/nasal/thread-win32.c
Normal 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;
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user