Compare commits

..
Author SHA1 Message Date
mfranz 0bcdf2e4dc easyxml.cxx: add missing endXML visitor call
testEasyXML.cxx: beef it up
2007-06-29 10:46:52 +00:00
mfranz cd5a720211 Vivian MEAZZA: add support for aircraft radar signatures 2007-06-24 08:09:07 +00:00
mfranz 5cb04946b0 don't only complain that the volume is larger than 1.0, but say how much
it actually is
2007-06-23 16:48:01 +00:00
mfranz c8953c6275 Maik JUSTUS: fix/implement directional sound 2007-06-21 21:46:21 +00:00
mfranz e8dc9c9454 d'oh ... beautify the TRACE message that we actually see! :-} 2007-06-19 18:22:32 +00:00
mfranz a0c325681f beautify TRACE message 2007-06-19 18:11:06 +00:00
mfranz 8d3bf19422 sooner than planned: fix "scale" animation offsets (1 -> 0) 2007-06-17 21:01:40 +00:00
fredb 4477867ef4 Update MSVC 7.1 projects 2007-06-16 16:14:23 +00:00
fredb e696c884dc MSVC 7 compilation 2007-06-16 16:13:29 +00:00
mfranz 80bcaa49e6 Nick WARNE: add file name to screenshot info line 2007-06-14 20:20:18 +00:00
mfranz 0096c1bb02 advance tracing messages from SG_INFO to SG_ALERT. If a developer has
demanded tracing, then he shouldn't get these important messages buried
in thousands of lines of meaningless bulk.
2007-06-11 16:09:50 +00:00
mfranz 38b37a068d - allow for (rather unusual) ////// cloud groups
- fix potential use of uninitialized memory: dew
2007-06-09 18:36:56 +00:00
frohlich 0281f31df2 Modified Files:
simgear/scene/material/mat.cxx simgear/scene/material/mat.hxx
	simgear/scene/util/SGSceneFeatures.cxx
	simgear/scene/util/SGSceneFeatures.hxx:
	Olaf Flebbe: Make use of SGSceneFeatues for anisotropic filtering,
	clean up.
2007-06-08 06:50:16 +00:00
frohlich 40b182c550 Removed Files:
simgear/scene/tgdb/leaf.cxx: Now obsolete but not yet removed.
2007-06-08 06:40:56 +00:00
frohlich d1dedc7511 Modified Files:
scene/tgdb/SGOceanTile.cxx: add missing transform for the ocean
	tile.
2007-06-03 18:28:14 +00:00
frohlich 04cd9b3eb6 Modified Files:
simgear/scene/model/model.cxx
	simgear/scene/util/SGSceneFeatures.cxx
	simgear/scene/util/SGSceneFeatures.hxx:
	Make sure textures are shared. Do not rely on a graphics
	context to be available on model loading.
2007-06-03 18:21:04 +00:00
andy de6003367d Sync with Nasal upstream. Mostly fixes to naContinue(), which
FlightGear doesn't use.  Also includes a performance fix for the
call() builtin that should help Melchior, who was measuring lower
performance for the props.Node() interface than the getprop/setprop
API.
2007-05-30 22:49:41 +00:00
frohlich a5f42eeddf Modified Files:
projects/VC8/SimGear.vcproj: Olaf FLebbe win32 build system.
2007-05-30 13:16:53 +00:00
frohlich a8ba041b67 Modified Files:
simgear/scene/model/SGMaterialAnimation.cxx:
	Olaf Flebbe: Use brakets around bitwise operations.
	Greetings from LinuxTag, Berlin ... :)
2007-05-30 13:07:05 +00:00
curt e700fc6f34 I guess we aren't using explicit destructors here. 2007-05-30 12:34:24 +00:00
curt af29d3d257 Make an explicit destructor so the compiler doesn't get confused about
non matching exception types with the implicitely defined destructor.
2007-05-29 19:38:17 +00:00
frohlich 487701a143 Modified Files:
simgear/scene/model/Makefile.am
	simgear/scene/model/animation.cxx
	simgear/scene/model/animation.hxx
Added Files:
	simgear/scene/model/SGRotateTransform.cxx
	simgear/scene/model/SGRotateTransform.hxx
	simgear/scene/model/SGScaleTransform.cxx
	simgear/scene/model/SGScaleTransform.hxx
	simgear/scene/model/SGTranslateTransform.cxx
	simgear/scene/model/SGTranslateTransform.hxx:
	Factor out some useful classes.
2007-05-28 07:13:07 +00:00
frohlich f32e037c58 Modified Files:
simgear/scene/material/mat.cxx simgear/scene/material/mat.hxx:
	Olaf Flebbe: Improoved texture filtering.
2007-05-28 05:13:03 +00:00
frohlich 8bd903dd96 Modified Files:
SGAtomic.hxx: Also use atomic compiler intrinsics on SGI
2007-05-28 05:06:14 +00:00
frohlich 560c100484 Modified Files:
simgear/bucket/newbucket.cxx simgear/bucket/newbucket.hxx
	simgear/io/decode_binobj.cxx simgear/io/sg_binobj.cxx
	simgear/io/sg_binobj.hxx simgear/math/SGVec2.hxx
	simgear/math/SGVec3.hxx simgear/math/SGVec4.hxx
	simgear/scene/material/mat.hxx
	simgear/scene/material/matlib.cxx
	simgear/scene/material/matlib.hxx
	simgear/scene/model/Makefile.am simgear/scene/tgdb/Makefile.am
	simgear/scene/tgdb/obj.cxx simgear/scene/tgdb/obj.hxx
	simgear/scene/tgdb/pt_lights.cxx
	simgear/scene/tgdb/pt_lights.hxx
	simgear/scene/util/Makefile.am
	simgear/scene/util/SGNodeMasks.hxx
	simgear/scene/util/SGTextureStateAttributeVisitor.cxx
Added Files:
	simgear/scene/model/SGOffsetTransform.cxx
	simgear/scene/model/SGOffsetTransform.hxx
	simgear/scene/tgdb/SGDirectionalLightBin.hxx
	simgear/scene/tgdb/SGLightBin.hxx
	simgear/scene/tgdb/SGOceanTile.cxx
	simgear/scene/tgdb/SGOceanTile.hxx
	simgear/scene/tgdb/SGTexturedTriangleBin.hxx
	simgear/scene/tgdb/SGTriangleBin.hxx
	simgear/scene/tgdb/SGVasiDrawable.cxx
	simgear/scene/tgdb/SGVasiDrawable.hxx
	simgear/scene/tgdb/SGVertexArrayBin.hxx
	simgear/scene/util/SGEnlargeBoundingBox.cxx
	simgear/scene/util/SGEnlargeBoundingBox.hxx
	simgear/scene/util/SGSceneFeatures.cxx
	simgear/scene/util/SGSceneFeatures.hxx
Removed Files:
	simgear/scene/tgdb/leaf.hxx simgear/scene/tgdb/vasi.hxx:
	Reorganize tile loaders.
	Build bigger leafs for the tiles.
	Move runway light colors into materials.xml.
	Split out classes that might be useful at other places.
	Avoid static storage on binobject loading.
2007-05-28 05:00:28 +00:00
andy 52444d177b GCC on ppc linux uses a different architecture symbol than the same compiler on OS X 2007-05-25 15:49:10 +00:00
frohlich b4f7ff29ef Modified Files:
SGVec3.hxx: Fix a problem in perpendicular triangle computation.
	Solves problem with invalid triangles in ground picking ...
2007-05-18 07:29:37 +00:00
frohlich f7c6a5bfa2 Modified Files:
SGVec2.hxx SGVec3.hxx SGVec4.hxx point3d.hxx: Provide ordering
	relations for use with std::less in tree bases std:: containers.
2007-05-18 04:46:11 +00:00
curt 6fe14f7a6b Fix a compiler warning. 2007-05-16 16:08:17 +00:00
curt 786e5addd8 Fix various compiler warnings. 2007-05-16 16:07:03 +00:00
mfranz 2e9a15f523 Tim Moore 2007-05-15 22:28:08 +00:00
mfranz bb0d2ddc53 add Mathias and Maik (to make it look less selfish that I add myself :-)
I'm sure I forgot a lot of people, but it's a start.
2007-05-15 22:02:06 +00:00
mfranz 702fb014a5 s/resistence/resistance/ 2007-05-13 11:53:06 +00:00
frohlich 834eab9457 Modified Files:
simgear/bucket/newbucket.hxx simgear/scene/material/mat.cxx
	simgear/scene/material/matlib.cxx
	simgear/scene/material/matlib.hxx
	simgear/scene/model/location.cxx
	simgear/scene/tgdb/apt_signs.cxx simgear/scene/tgdb/leaf.cxx
	simgear/scene/tgdb/leaf.hxx simgear/scene/tgdb/obj.cxx
	simgear/scene/tgdb/obj.hxx
	simgear/scene/util/SGUpdateVisitor.hxx: Reorganize scenegraph to
	simplify top level structure.
2007-05-08 06:11:15 +00:00
mfranz a85da04601 Add method to return the number of attached listeners. Listeners have become
a much more important feature than they were two years or something ago, and
it's helpful for debugging and exploration to get this important node property
shown in property tree dumps or in the property browser (verbose mode).
2007-05-07 14:03:44 +00:00
mfranz 414f1c27e4 - fix bug where a property tree saved with writeProperties() and read back
in with readProperties() would not look the same, because element indices
  of '0' were even dropped when a node has a "secret" value *and* children

- introduce "omit-node" modifier attribute for the "include" attribute.
  This inserts the given file in place of the including node, while the
  node is dropped. This is desirable for multiple includes (which can't
  be done by multiply using the "include" attribute, as this isn't valid
  XML spec syntax)
2007-05-06 17:33:15 +00:00
mfranz c76e2eb900 better warning text for <global> in material animations 2007-05-05 11:16:35 +00:00
frohlich c523e15302 Modified Files:
SGMaterialAnimation.cxx SGMaterialAnimation.hxx:
	Tim Moore: overhaul the material animation.
2007-05-05 09:15:18 +00:00
frohlich 2dc8de295d Modified Files:
simgear/scene/model/animation.hxx
	simgear/scene/model/shadanim.cxx: Tim Moore: the crom shader.
2007-05-03 19:46:13 +00:00
andy d645fd6327 Empty vectors work much better as the result of sorting an empty array
than nil does...
2007-05-02 22:29:35 +00:00
andy 219a7f3a07 Fix crash when sorting newly-allocated empty vectors 2007-05-02 22:24:45 +00:00
mfranz d95e3e0055 don't rely on a compressed scanline being properly closed
(GIMP apparently generates corrupted files)
2007-04-28 23:13:13 +00:00
mfranz 2cc31ff425 SGTexture::read_rgb(a)_texture:
- support greyscale and greyscale/alpha format
- cleanup & make it faster
2007-04-28 12:30:38 +00:00
frohlich 8258fd7d9f Modified Files:
projects/VC8/SimGear.vcproj: Olaf Flebbe: Updates to the win32
	build system.
2007-04-21 12:24:43 +00:00
frohlich 784cca2233 Modified Files:
simgear/scene/material/mat.cxx simgear/scene/material/mat.hxx:
	Olaf Flebbe: make anisotroüpic filtering configurable.
2007-04-21 12:13:16 +00:00
andy 436539a700 Melchior found a bug with negative values in default function arguments 2007-04-06 20:35:38 +00:00
andy dcb3da9f28 sync with Nasal CVS (added a sort() builtin) 2007-04-06 14:52:06 +00:00
mfranz a354c841f1 Csaba HALASZ:
- fix bug that messed up leg distances after inserting and deleting waypoints
  not at the end of the route
- move add_waypoint() and delete_waypoint from hxx to cxx
- beef up routetest
2007-04-06 09:54:35 +00:00
fredb 3824f064cd Update MSVC 7.1 projects 2007-04-03 11:35:19 +00:00
fredb cba6db752b Avoid potential memory leak problems when exceptions are thrown by using reference objects 2007-04-03 11:25:07 +00:00
andy a458e26581 Fix typo in _M_IX86 2007-04-02 21:32:41 +00:00
andy 9d68727a84 Rewrite substr() to properly clamp its argument ranges and handle negative start arguments as offset-from-end values 2007-04-02 18:28:38 +00:00
andy 38b9a874e0 Add missing free functions for win32 2007-04-02 17:34:47 +00:00
andy 7a680fb9f2 Use __FUNCTION__, which works on gcc and MSVC 7/8, instead of
__func__, which while standardized works only with gcc.  I'll wait for
bug reports from VC6 before bothering with fallback code...
2007-04-02 16:14:54 +00:00
andy a5f9262adb Melchior points out that NaN/Inf behavior is not platform-independent.
So toss a runtime error ("floating point error") when any of the math
library functions produce a non-finite value.  Note that these are not
the only locations that can do that (simply dividing by zero will
produce an Inf), but it's still proper behavior.
2007-03-30 16:42:22 +00:00
andy b05e32fa8c Sync with Nasal CVS (soon to become Nasal 1.1). Notable new features:
Nasal now supports calls to "subcontexts" and errors can be thrown
across them, leading to complete stack traces when call() is used,
instead of the truncated ones we now see.

Vectors can now be concatenated using the ~ operator that used to work
only for strings.

Better runtime error messages in general due to a fancier
naRuntimeError() implementation

A big data size shrink on 64 bit systems; the size of a naRef dropped
by a factor of two.

"Braceless code blocks" have been added to the parser, so you can
write expressions like "if(a) b();" just like in C.  Note that there's
still a parser bug in there that fails when you nest a braced block
within a braceless one.

Character constants that appear in Nasal source code can now be
literal multibyte UTF8 characters (this was always supported for
string literals, but character constants were forced to be a single
byte).

New modules: "bits", "thread", "utf8" and (gulp...) "io".  The bits
library might be useful to FlightGear, the utf8 one probably not as
Plib does not support wide character text rendering.  The thread
library will work fine for spawning threads to do Nasal stuff, but
obviously contact with the rest of FlightGear must be
hand-synchronized as FlightGear isn't threadsafe.  The io library is
no doubt the most useful, as it exposes all the basic stdio.h
facilities; it's also frighteningly dangerous when combined with
networked code...
2007-03-29 18:50:12 +00:00
mfranz 53d8cff835 Csaba HALASZ: when a path_cache ceases to exist, unregister from all nodes
that had been told that this node is linking to them

mf: remove old erase-by-key methods; they are now unused and always were
    problematic, so they won't be used in the future either
2007-02-17 10:50:49 +00:00
mfranz 00fe97ff88 - don't leak node in both hash_table::bucket::erase()
- remove bad code from hash_table::bucket::erase(const char *) that was
  introduced with the last patch. (This function isn't used anywhere and
  is scheduled for removal. Leaving it in for now as a reference.)
- remove leaves first in remove_from_path_caches()

- cosmetics: indentation, one trailing space, variable name change, comment
  (Sorrry for mixing that with actual code, but I think it's easy to see.)
2007-02-16 15:32:21 +00:00
andy 607511fd64 Don't crash when destroying a SGBinding object if the property node it
was loaded from lacks a parent.  Patch from ndim on IRC
2007-02-14 23:14:00 +00:00
mfranz 8663c265d8 Maik JUSTUS:
"""
- make every node maintain list of properties that link to it
- add functions to erase node by address from hash bucket/entry in their
  path caches, so that all references can be removed
- if a node is removed, it (and all children, grandchildren, ...) calls
  all linked properties to remove them from their path-cache


This fixes problems with the aerotow over multiplayer and maybe some
other problems, where nodes are queried by name.
"""
2007-02-11 11:05:23 +00:00
andy 6c5d35d6ce "bias" argument to texture animations by Ron Jensen 2007-02-07 19:21:24 +00:00
mfranz 95532cb318 fix error message 2007-02-05 21:41:40 +00:00
frohlich 4d91bc5908 Modified Files:
ephemeris.cxx ephemeris.hxx stardata.cxx:
	one must not do changes just before checkin,
	one most not do changes just before checkin,
	[ last message repeated 100 times ]
2007-02-02 18:16:42 +00:00
frohlich b13900402d Modified Files:
ephemeris.cxx ephemeris.hxx stardata.cxx stardata.hxx: Throw out sg.h
2007-02-02 18:09:27 +00:00
frohlich 1bb6c03bd0 Modified Files:
simgear/scene/util/SGNodeMasks.hxx
	simgear/scene/model/animation.cxx:
	More finegrained cull masks
2007-02-02 07:00:54 +00:00
frohlich 1445949e31 Modified Files:
projects/VC8/SimGear.vcproj: Olaf Flebbe: renenable static build
2007-01-31 21:40:59 +00:00
frohlich 360d3834ca Modified Files:
SGIntersect.hxx SGVec3.hxx SGVec4.hxx: Add convinience methods
2007-01-30 20:12:15 +00:00
fredb aacdcad529 restore 'double checked locking' 2007-01-29 08:19:13 +00:00
frohlich ad9341835f Modified Files:
model.cxx: Better texture sharing, fix problem with rotation order
2007-01-28 20:04:56 +00:00
frohlich b028adb6af Modified Files:
simgear/structure/SGAtomic.cxx: Plug memory leak originating from
	wrong atomic fallback operations.
2007-01-28 20:03:43 +00:00
fredb 39f683b272 Ensure a reference on the cube map texture is always held 2007-01-26 20:30:02 +00:00
ehofman a6c46c89eb *** empty log message *** 2007-01-23 10:07:36 +00:00
fredb d534cf6f02 Better fix for the constant scale factor problem 2007-01-21 11:15:36 +00:00
fredb dd4326f7c4 Support constant scaling factor 2007-01-21 10:33:34 +00:00
fredb 40aecd688e Don't segfault when dir is empty 2007-01-16 21:34:18 +00:00
frohlich 63730a6e2c Modified Files:
animation.cxx: Add a visible configuration option to the pick
	animation.
2007-01-15 19:01:20 +00:00
frohlich 4d4d26aef8 Modified Files:
projects/VC8/SimGear.vcproj: Olaf Flebbe, MSVC8 buildsystem changes.
2007-01-15 17:32:17 +00:00
mfranz de6b32d8c6 writePropeties(): create dir if necessary 2007-01-12 21:24:50 +00:00
fredb a0af7f0524 Update MSVC 7.1 project file and fix win32 compilation 2007-01-09 21:58:04 +00:00
frohlich c043bd3422 Modified Files:
SGSceneUserData.hxx SGSceneUserData.cxx: Remove default argument
2007-01-07 12:25:32 +00:00
frohlich 18ae1d6940 Modified Files:
animation.cxx: Change the pick animation to better handle different
	mouse buttons.
2007-01-07 11:53:21 +00:00
frohlich d6f64f9773 Modified Files:
SGSceneUserData.hxx SGPickCallback.hxx Makefile.am
Added Files:
	SGSceneUserData.cxx: Cleanup and replace the pick callback with
	such a list.
2007-01-07 11:52:19 +00:00
frohlich db99a4cb90 Modified Files:
animation.cxx: Add a button argument to that animation.
	The default is to accept any mouse button.
2007-01-07 08:34:03 +00:00
fredb 108689661f Add a prototype simgear_config.h for MSVC 7.1 and a rule to build it. 2007-01-06 17:01:58 +00:00
fredb d3e00dba8e Add a prototype simgear_config.h for MSVC 7.1 and a rule to build it.
At Olaf requests, add MSVC 8 specific symbols to remove pedantic warnings
2007-01-06 16:52:50 +00:00
fredb fcd33e5035 Remove redundant directory ( projects as a whole is already there ) 2007-01-06 16:47:57 +00:00
frohlich af9082cd9f Modified Files:
moon.cxx: The moo's state like it was with plib
2007-01-06 15:08:40 +00:00
fredb 6a0bb18fca Refresh MSVC6 project file 2007-01-06 14:45:21 +00:00
fredb 8aa8d87781 Fix a typo 2007-01-06 14:44:54 +00:00
fredb 4998af8d7a Add SGBinding.[ch]xx to the MSVC 7.1 project 2007-01-04 22:24:23 +00:00
fredb c6aa95f3f3 std::find is defined in <algorithm> 2007-01-04 22:23:40 +00:00
frohlich 481be29366 Modified Files:
Makefile.am animation.cxx animation.hxx: Add animation to execute
	a command on scenery pick
2007-01-04 12:55:16 +00:00
frohlich 3617b6ad8c Modified Files:
Makefile.am SGNodeMasks.hxx
Added Files:
	SGPickCallback.hxx SGSceneUserData.hxx: Preparations for generic
	scenery picking.
2007-01-04 12:52:50 +00:00
frohlich 3fb8e19a38 Modified Files:
condition.hxx: Also derive from SGReferenced
2007-01-04 12:51:13 +00:00
frohlich 2ea2f1b4f2 Modified Files:
Makefile.am commands.cxx commands.hxx
Added Files:
	SGBinding.cxx SGBinding.hxx: Move FGBinding to SGBinding
2007-01-04 12:47:12 +00:00
frohlich 26cb8ec4f1 Modified Files:
SGIntersect.hxx: Make it compile with win32
2006-12-28 13:25:14 +00:00
frohlich 7fe56bea86 Modified Files:
obj.cxx: Some kind of polygon offset for GL_POINTS.
2006-12-27 10:33:37 +00:00
frohlich 11b16b8a86 Modified Files:
Makefile.am SGReferenced.hxx
Added Files:
	SGAtomic.cxx SGAtomic.hxx:
	Make the reference counts thread safe.
2006-12-27 10:07:19 +00:00
frohlich de020ee695 Modified Files:
Makefile.am SGMathTest.cxx SGQuat.hxx SGVec3.hxx
Added Files:
	SGBox.hxx SGGeometry.hxx SGGeometryFwd.hxx SGGeometryTest.cxx
	SGIntersect.hxx SGLineSegment.hxx SGPlane.hxx SGRay.hxx
	SGSphere.hxx SGTriangle.hxx:
	Small updates to the vector code, new geometry and collision
	classes for use with a bv tree to speed up collission tests.
	Also included is a rought unit test for the collissions.
2006-12-27 09:23:39 +00:00
ehofman 3b83487611 Wether you like it or not, MispPro needs these libraries referenced 2006-12-23 12:15:05 +00:00
fredb 09bab4f162 memcpy needs #include <string.h> 2006-12-17 17:52:15 +00:00
fredb 49fcc799ca Port jpgfactory to OSG 2006-12-16 17:29:16 +00:00
fredb 10bc803775 Project files for MSVC 7.1 aka .NET 2003 2006-12-16 13:12:48 +00:00
frohlich 4f40770fc6 Modified Files:
simgear/math/SGVec3.hxx: fix spelling
2006-12-14 05:24:16 +00:00
frohlich a4495c6ef1 Modified Files:
simgear/scene/sky/bbcache.cxx simgear/scene/sky/bbcache.hxx
	simgear/scene/sky/cloudfield.cxx
2006-12-08 12:22:10 +00:00
frohlich 67d837c4ec Modified Files:
SGVec3.hxx: Generate any perpandicular vector to a given one.
2006-12-08 12:17:30 +00:00
frohlich 138825af6d Modified Files:
point3d.hxx: Add explicit conversion functions to SGVec*
2006-12-08 12:16:56 +00:00
frohlich c093841336 Modified Files:
simgear/scene/model/animation.cxx: Fix a problem of muliple
	texturre transform not finding the correct configuration.
2006-12-05 06:14:41 +00:00
frohlich 2df1da4226 Return void instead of bool. 2006-12-05 05:43:13 +00:00
frohlich 2792d60e2d Modified Files:
simgear/screen/extensions.hxx: Make it compile on macos
2006-12-03 17:44:27 +00:00
frohlich 656a3ace07 Modified Files:
simgear/scene/material/mat.cxx: Put solid scenery into the
	opaque render bin
2006-12-03 17:27:46 +00:00
frohlich aec8e88c14 Modified Files:
simgear/scene/util/SGNodeMasks.hxx: Add pickable bit
2006-12-03 17:02:40 +00:00
frohlich bdd5ca140d Modified Files:
simgear/scene/model/Makefile.am
	simgear/scene/model/animation.cxx
	simgear/scene/model/animation.hxx
	simgear/scene/model/model.cxx
	simgear/scene/model/persparam.cxx
	simgear/scene/model/persparam.hxx
	simgear/scene/model/shadanim.cxx
Added Files:
	simgear/scene/model/SGMaterialAnimation.cxx
	simgear/scene/model/SGMaterialAnimation.hxx
	Big animation overhaul. Improoves animation correctness.
2006-12-03 16:57:20 +00:00
frohlich 8b3b0def03 Modified Files:
SGUpdateVisitor.hxx: Include light information.
2006-12-03 16:46:23 +00:00
frohlich 6440ece177 Modified Files:
SGMisc.hxx: Add clip and periodic normalize functions.
2006-12-02 15:59:23 +00:00
frohlich bd3518637c Modified Files:
SGVec2.hxx SGVec3.hxx SGVec4.hxx: Add inf norm function
2006-12-02 15:57:55 +00:00
frohlich aef2a1c484 Modified Files:
interpolater.cxx interpolater.hxx: Enable reading tables directly
	from our dom like tree.
2006-12-02 15:56:55 +00:00
frohlich a4b28e5737 Modified Files:
simgear/scene/sky/oursun.cxx: Fix the 'sun has wrong size' bug.
	Thanks to Mark Akermann.
2006-11-27 17:11:35 +00:00
frohlich a3bc2eb836 Modified Files:
simgear/math/interpolater.cxx simgear/math/interpolater.hxx
	simgear/props/condition.cxx simgear/props/condition.hxx
	simgear/scene/model/animation.cxx
	simgear/scene/model/animation.hxx: Optimize interpolation table
	lookup by using a std::map.
2006-11-21 18:44:54 +00:00
frohlich 3059da5805 Modified Files:
SGVec2.hxx SGVec3.hxx SGVec4.hxx: Implement min/max for vectors
2006-11-21 18:39:57 +00:00
frohlich 18d5a492c8 Modified Files:
model.cxx: Tweak model optimizations
2006-11-20 18:19:02 +00:00
frohlich 160b0ea7d9 Modified Files:
placementtrans.cxx placementtrans.hxx: Make use of that view
        information in the update visitor
2006-11-20 18:17:56 +00:00
frohlich 4dd1267bea Modified Files:
SGUpdateVisitor.hxx: Store some view imformation in the
	update visitor.
2006-11-20 18:15:34 +00:00
fredb b5c4328682 Mac fix from Ima Sudonim 2006-11-18 18:58:51 +00:00
frohlich 571fc69ef4 Modified Files:
VC8/SimGear.vcproj: Import buildsystem from Olaf Flebbe
2006-11-14 21:15:20 +00:00
frohlich f51595cfc9 Modified Files:
animation.hxx animation.cxx: Improove material/texture/blend animation
2006-11-14 21:09:44 +00:00
frohlich d54aea0036 Modified Files:
animation.cxx animation.hxx: Fix crash on A-10 load
2006-11-12 10:32:42 +00:00
frohlich 51bb2974bc Modified Files:
model.cxx: Leave it to osg when to do mipmapping.
2006-11-12 07:28:59 +00:00
frohlich 7a859061fd Modified Files:
model.cxx: Reset the database path past the whole model is loaded
2006-11-12 07:23:42 +00:00
frohlich cefa9fcd75 Modified Files:
SGQuat.hxx: Make const method const
2006-11-12 07:22:44 +00:00
frohlich d3bacd0b73 Modified Files:
simgear/scene/material/mat.cxx
	simgear/scene/material/matlib.cxx simgear/scene/sky/cloud.cxx
	simgear/scene/sky/dome.cxx simgear/scene/sky/moon.cxx
	simgear/scene/sky/oursun.cxx simgear/scene/sky/sphere.cxx
	simgear/scene/sky/stars.cxx simgear/scene/tgdb/apt_signs.cxx
	simgear/scene/tgdb/leaf.cxx simgear/scene/tgdb/leaf.hxx
	simgear/scene/tgdb/obj.cxx simgear/scene/tgdb/pt_lights.cxx
	simgear/scene/util/SGDebugDrawCallback.hxx
	simgear/screen/Makefile.am: Use color arrays for every geode.
	Just use osg::Material instead of osg::Material and the associated
	mode.
2006-11-10 05:30:37 +00:00
frohlich b94a98fc90 Modified Files:
scene/model/model.cxx: Next step in direction liveries
2006-11-09 05:42:06 +00:00
fredb e0b2687231 copysign is already in compiler.h 2006-11-07 21:31:17 +00:00
frohlich cc6179a4dd Modified Files:
simgear/screen/extensions.cxx simgear/screen/extensions.hxx: Avoid
	the assumption that with glx-1.4 glXGetProcAddress is available -
	use dlsym to get that function.
2006-11-07 17:49:36 +00:00
fredb e947bac4a3 This class is for plib only 2006-11-07 07:22:48 +00:00
frohlich 11ecbb6ca7 Modified Files:
mat.cxx: Fix dark scenery problem.
2006-11-07 06:40:35 +00:00
frohlich 322789cd4c Modified Files:
simgear/Makefile.am: Make 'make distclean' work
2006-11-07 06:02:47 +00:00
frohlich f28464dba0 Modified Files:
projects/VC8/SimGear.vcproj: Olaf Flebbe: updated project files
2006-11-07 05:55:46 +00:00
frohlich 8f6456b1f8 Modified Files:
simgear/scene/util/SGUpdateVisitor.hxx: Only traverse active
	children.
2006-11-07 05:47:00 +00:00
frohlich 1f32786c82 Modified Files:
simgear/scene/util/SGDebugDrawCallback.hxx
	simgear/math/SGQuat.hxx: Olaf Flebbe: Make it compile on some more
	win32 variants.
2006-11-07 05:46:25 +00:00
fredb 829c729ee9 Don't try to load textures when no name is given 2006-11-06 21:59:02 +00:00
fredb 5d3aacb892 Attempt to fix the APIENTRY problem. It looks like a problem in OSG, or a conflict between OSG and plib/pui 2006-11-03 18:08:46 +00:00
fredb 741e9c5ed5 For some reason I don't know yet, the APIENTRY stuff in osg/GL is broken for some files. Include the real windows.h until we find why. 2006-11-03 10:04:58 +00:00
fredb 1408c1b623 add copysign definition for MSVC 2006-11-03 09:57:02 +00:00
fredb c256f8d09e Win32 compilation fix 2006-11-02 17:40:54 +00:00
frohlich 55c018c525 Modified Files:
SGMath.hxx: Attempt to help IRIX builds
2006-11-02 13:37:23 +00:00
frohlich 3fa94b5143 Modified Files:
projects/VC8/SimGear.sln projects/VC8/SimGear.vcproj: Import Olafs
	project files
2006-11-02 06:15:14 +00:00
frohlich 5127e2f89c Modified Files:
Makefile.am SGMath.hxx SGMathFwd.hxx SGMatrix.hxx SGQuat.hxx
Added Files:
	SGVec2.hxx
	Improove the matrix functions. Improove the quaterion functions.
	Add the 2d vector.
2006-11-01 21:25:21 +00:00
mfranz 3175fa3aca + .deps/ 2006-11-01 21:24:24 +00:00
frohlich 5614174b39 Modified Files:
simgear/scene/model/Makefile.am
	simgear/scene/model/animation.cxx
	simgear/scene/model/animation.hxx
	simgear/scene/model/modellib.cxx
	simgear/scene/model/modellib.hxx
Removed Files:
	simgear/scene/model/personality.cxx
	simgear/scene/model/personality.hxx:
	Updates to the animation system.
	Personality can be implemented easier now
2006-10-31 06:26:50 +00:00
frohlich 39fc52fe0a Modified Files:
Makefile.am SGStateAttributeVisitor.hxx
 	SGTextureStateAttributeVisitor.hxx
Added Files:
	SGStateAttributeVisitor.cxx SGTextureStateAttributeVisitor.cxx:
	Move implementation into cxx files
2006-10-31 06:14:38 +00:00
frohlich 81188705b1 Modified Files:
simgear/math/SGQuat.hxx: Initialize with zero not with null pointer
2006-10-31 05:37:45 +00:00
frohlich 63c4873d8a Modified Files:
simgear/screen/extensions.cxx simgear/screen/extensions.hxx:
	use glXGetProcAddress if approriate
2006-10-31 05:36:50 +00:00
frohlich 1a85dcd890 Modified Files:
simgear/timing/timestamp.hxx: Remove reimplemented default
	implementations
2006-10-31 05:33:48 +00:00
frohlich 27470fc504 Modified Files:
configure.ac: Add a configure flag for osg
2006-10-30 19:56:09 +00:00
mfranz 65d18445d3 Makefile(.in) 2006-10-29 20:08:27 +00:00
frohlich 84dd54b33a Modified Files:
configure.ac simgear/environment/visual_enviro.cxx
	simgear/ephemeris/ephemeris.cxx
	simgear/ephemeris/ephemeris.hxx simgear/ephemeris/stardata.cxx
	simgear/ephemeris/stardata.hxx simgear/math/SGMatrix.hxx
	simgear/math/SGQuat.hxx simgear/math/SGVec3.hxx
	simgear/math/SGVec4.hxx simgear/scene/Makefile.am
 	simgear/scene/material/mat.cxx simgear/scene/material/mat.hxx
	simgear/scene/material/matlib.cxx
	simgear/scene/material/matlib.hxx
	simgear/scene/material/matmodel.cxx
	simgear/scene/material/matmodel.hxx
	simgear/scene/model/Makefile.am
	simgear/scene/model/animation.cxx
	simgear/scene/model/animation.hxx
	simgear/scene/model/custtrans.hxx
	simgear/scene/model/model.cxx simgear/scene/model/model.hxx
	simgear/scene/model/modellib.cxx
	simgear/scene/model/modellib.hxx
	simgear/scene/model/personality.cxx
	simgear/scene/model/personality.hxx
	simgear/scene/model/placement.cxx
	simgear/scene/model/placement.hxx
	simgear/scene/model/placementtrans.cxx
	simgear/scene/model/placementtrans.hxx
	simgear/scene/model/shadanim.cxx
	simgear/scene/model/shadowvolume.hxx
	simgear/scene/sky/cloud.cxx simgear/scene/sky/cloud.hxx
	simgear/scene/sky/cloudfield.cxx simgear/scene/sky/dome.cxx
	simgear/scene/sky/dome.hxx simgear/scene/sky/moon.cxx
	simgear/scene/sky/moon.hxx simgear/scene/sky/newcloud.cxx
	simgear/scene/sky/oursun.cxx simgear/scene/sky/oursun.hxx
	simgear/scene/sky/sky.cxx simgear/scene/sky/sky.hxx
	simgear/scene/sky/sphere.cxx simgear/scene/sky/sphere.hxx
	simgear/scene/sky/stars.cxx simgear/scene/sky/stars.hxx
	simgear/scene/tgdb/apt_signs.cxx
	simgear/scene/tgdb/apt_signs.hxx simgear/scene/tgdb/leaf.cxx
	simgear/scene/tgdb/leaf.hxx simgear/scene/tgdb/obj.cxx
	simgear/scene/tgdb/obj.hxx simgear/scene/tgdb/pt_lights.cxx
	simgear/scene/tgdb/pt_lights.hxx
	simgear/scene/tgdb/userdata.cxx
	simgear/scene/tgdb/userdata.hxx simgear/scene/tgdb/vasi.hxx
	simgear/screen/jpgfactory.cxx simgear/screen/tr.cxx
	simgear/structure/Makefile.am simgear/threads/SGThread.hxx
Added Files:
	simgear/scene/util/Makefile.am
	simgear/scene/util/SGDebugDrawCallback.hxx
	simgear/scene/util/SGNodeMasks.hxx
	simgear/scene/util/SGStateAttributeVisitor.hxx
	simgear/scene/util/SGTextureStateAttributeVisitor.hxx
	simgear/scene/util/SGUpdateVisitor.hxx
Removed Files:
	simgear/screen/ssgEntityArray.cxx
	simgear/screen/ssgEntityArray.hxx
	simgear/structure/ssgSharedPtr.hxx
	Big BLOB on the way to OSG.
2006-10-29 19:27:08 +00:00
curt 7c410d36e3 wim van hoydonck:
Updated to World Magnetic Model 2005.
2006-10-28 22:12:48 +00:00
mfranz 98a603a570 - don't need a guarded pointer here
- shorten variable, fix indentation
2006-10-24 20:28:08 +00:00
mfranz 5876052170 allow to switch on/off at runtime a whole imported <model> via <condition>:
<model>
      <path>some/model.xml</path>
      <condition>
          <property>model/switch</property>
      </condition>
  </model>

Of course, one could add "select" animations for all <object-name> in the
<model>, but this is tedious and can hardly be done e.g. for all
objects in all instruments in $FG_ROOT/Aircraft/Instruments-3d/ etc.

The feature will be used in the bo105, so that civilian variants can
have a HSI instrument, where military variants have a TACAN etc.
2006-10-24 19:44:38 +00:00
durk f8303b4623 Compile time fixes needed to build SimGear on recent cygwin versions. 2006-10-22 19:42:17 +00:00
durk 20005a7a22 Make configuration script compatible with "home-built" openal libraries
on cygwin.
2006-10-22 19:41:16 +00:00
mfranz 4f0bfbab21 - // This will come back and remove
- // the current item each time.  Is
- // that OK?

No, it is not OK. This messes up the vector and confuses the iterator.
And it leads to crashes. Better read the vector in reverse order.
2006-10-22 13:08:09 +00:00
curt 811442832e Step #1 towards abandoning the original point lighting scheme in favor of
sprite based lighting.
2006-10-19 03:36:22 +00:00
frohlich 40811311d7 Modified Files:
SimGear.vcproj: Import changes from Olaf
2006-09-30 07:11:16 +00:00
durk 198de211f8 Memory leak fix. 2006-09-30 05:11:25 +00:00
fredb 9f5412fa9d Win32 only : Don't alloc a console when it is not needed 2006-09-27 20:16:32 +00:00
fredb 0dc9de81ae Add a simple program to benchmark SGTimeStamp::stamp() 2006-09-02 11:21:22 +00:00
fredb 5b8f42ce5e Make the SGTimeStamp behave under Windows just like for other environments 2006-08-31 18:26:45 +00:00
fredb 5314274ed6 Use getNodeValue as initially planned 2006-08-28 19:38:23 +00:00
ehofman c831856711 MispPro requires an explicit declaration. 2006-08-28 18:53:36 +00:00
curt 1bade6d796 Frederic Bouvier:
Make line feed behavior consistent between linux/windows.
2006-08-26 14:02:17 +00:00
fredb 629a4a950e Better encapsulation for personality 2006-08-25 19:25:56 +00:00
mfranz aebb1f6ec8 compile (gcc 4.1.0)
("In member function 'T SGPersonalityParameter<T>::shuffle()':
28: error: there are no arguments to 'sg_random' that depend on a template
parameter, so a declaration of 'sg_random' must be available")
2006-08-24 23:03:52 +00:00
fredb 6e42bc55e0 Reorganize personality parameters and add personality to translate, blend and scale animations 2006-08-24 22:46:40 +00:00
frohlich 1235fba7ee Remove duplicate linker line in the resulting Makefile 2006-08-08 05:05:09 +00:00
fredb 7a459db022 Win32 fix 2006-07-30 21:02:36 +00:00
frohlich 607987def5 Remove fastmath funktions like discussed on the list.
Add a new header with forward declarations of the SGMath stuff.
2006-07-30 07:48:06 +00:00
frohlich 397ec62180 Clean up scenery center handling. 2006-07-27 16:34:32 +00:00
durk 9315210fbe Mark's dynamic sun color changes. 2006-07-27 05:15:20 +00:00
curt 5127990a43 Additional functionality for animated point lights (i.e. approach light
rabbits, REIL, VASI/PAPI, etc.)

This allows the calling layer (i.e. FlightGear) better control over the use
of OpenGL point drawing extensions.
2006-07-21 15:45:01 +00:00
curt 40ad2b155a Updated dist content. 2006-07-12 15:08:00 +00:00
mfranz a0412d026c remove the last redundant "delete" check in all of fgfs/sg (except JSBSim) 2006-07-05 09:31:36 +00:00
andy 7d2134c488 The previous update (and, embarassingly, the "nasal 1.0" release I
announced on Freshmeat.net) was broken.  This is the proper
break/continue fix.
2006-07-05 02:52:06 +00:00
andy d894f52b97 Been hacking at Nasal recently:
Fix bug with break/continue inside of a foreach or forindex: Don't pop
the vector/index inside OP_EACH, do it at the end of the loop.

In the process, discovered and fixed a scary corruption issue with
continue; it never really worked right, although simple usage was
likely to get away without crashing.  Both the continue's OP_BREAK and
the cleanup code at the end of a loop would pop the "mark" stack,
leading to an underflow.  Introduced an OP_CONTINUE which adjusts
stack but doesn't change markTop

Re-inline the PUSH macro.  This thing is called all over the place
from the inner loop.  If the problem is intra-expression side effects,
then just use another expression in the macro.

Return an empty vector when requesting zero-length subvec, not nil

Have call() return the call stack in the error vector; see docs on
plausible.org/nasal or ask Andy about this feature.

Default closure()'s level argument to zero, not nil

Add an optional "file name" argument to compile()
2006-07-03 05:13:27 +00:00
mfranz 735f475c24 actually query the <condition> that is already set up in SGShaderAnimation 2006-07-01 20:06:05 +00:00
mfranz 353dd73e24 add knots <-> feet-per-second conversion constants 2006-06-25 11:55:56 +00:00
fredb 49fe06498a Compile again on Win32 platforms 2006-06-17 22:02:32 +00:00
frohlich bc95ec8084 Make at least the header aliasing safe. 2006-06-17 16:04:28 +00:00
frohlich f79906bf16 Make it compile with gcc-3.3.6 2006-06-17 16:04:05 +00:00
fredb b3262fcb80 Compile again on Win32 platforms 2006-06-16 10:03:38 +00:00
mfranz 52b8f924aa add float_to_int() rounding function from Cockpit/hud_opts.hxx. The original
file said "(c) FlightGear Project" and "probably written by Norman Vine".
2006-06-16 09:29:54 +00:00
frohlich 52f57160aa Add dist and distSqr functions 2006-06-15 19:13:24 +00:00
frohlich 6d4f23919c Remove unused extern decls 2006-06-15 19:12:57 +00:00
frohlich 899623f71b Remove deprecated, now unused functions. 2006-06-15 08:52:21 +00:00
frohlich c5d677ac7b Small cleanups to the SGGeo[dc] classes, provide more hooks to use them directly 2006-06-15 08:27:31 +00:00
frohlich c75270a9fc Use function argument in va_start instead of local variable. 2006-06-15 06:14:46 +00:00
frohlich 1588a379eb Remove now unused function 2006-06-11 13:59:59 +00:00
frohlich 72d2075828 Modified Files:
simgear/scene/material/mat.cxx simgear/scene/material/mat.hxx
	simgear/scene/material/matlib.cxx
	simgear/scene/material/matlib.hxx simgear/scene/tgdb/leaf.cxx
	simgear/scene/tgdb/obj.cxx
	Attach userdata to groundtile scenegraph leafs that contains
	a SGMaterial reference to the material of that leaf.
	Add (physical) material properties to the material definitions.
	Plug a memory leak with GlyphSigns.
2006-06-11 13:30:59 +00:00
frohlich e99c682637 Preliminary material lookup hooks - still unoptimized. 2006-06-08 05:54:23 +00:00
mfranz c815f70831 whoops, sorry (Yes, it *was* tested, but then I made another "trivial"
change and ...)
2006-05-24 10:16:09 +00:00
mfranz 0da50eaa79 if we are going to die we better tell all our listeners 2006-05-24 09:37:44 +00:00
mfranz b0af84a549 add optional position argument to SGRoute::add_waypoint(). Default is -1,
which appends the WP like it used to. Valid vector indices insert the WP
at this position.
2006-05-08 11:31:16 +00:00
fredb b9631e8521 Mac fix 2006-05-04 05:58:59 +00:00
fredb f664f7a201 Fix the initial texture path problem. Loaders are setting the one given to ssgLoad as the default one behind our back :-( 2006-04-29 08:09:51 +00:00
fredb f72b3882c3 Redefine the default PLIB loader behavior : don't clear the texture cache after every model load 2006-04-28 18:05:46 +00:00
mfranz ea47a2973c add method to delete any waypoint (last waypoint if n is out of range) 2006-04-28 15:43:13 +00:00
frohlich 04be9ca670 Pigeons remaining fix for the soundmanager crashes. 2006-04-25 18:47:37 +00:00
mfranz 6f0baf6ca9 thanks to Erik's texture map I can now drop empty.rgb altogether and just
specify the same texture in the "foo.lighted" and "foo.unlighted" material
entry. This also allows to drop the state cloning and thereby solves the
most urgent apt_signs.cxx TODO. :-)
2006-04-22 13:41:06 +00:00
ehofman 1f5ec6b8d5 Add a texture cache mechanism. Fortunately this oly seems affective for empty.rgb ... 2006-04-22 09:38:14 +00:00
mfranz a2a91520aa don't allow new command name to overwrite material name 2006-04-20 17:46:40 +00:00
mfranz fd7b5d3de7 - don't use hard-coded emission values for unlighted signs, but load both
states from material.xml (separate <material> entries for now)
- clone state less often: not once per sign element, but once per material
  switch (TODO: clone only once per material)
2006-04-20 16:06:00 +00:00
mfranz 30ea844c43 fix "unknown.rgb" path (the wrong path was the reason why we always only
got plib's lowres red-white chequer-board pattern along with an error
message, and not ours ... which is much prettier, but also bigger.
(Should we downscale it?)
2006-04-20 15:20:40 +00:00
mfranz efac53b121 make headers include headers they depend on, don't rely on the c(xx)
file to do that. (This is a requirement for header precompiling.)
2006-04-17 11:29:01 +00:00
mfranz 73c0ef59c1 rename OBJECT_TAXI_SIGN to OBJECT_SIGN. This isn't about taxi signs any
more, but all sorts of signs. Now is the best time to get rid of a
misleading name.
2006-04-14 14:50:08 +00:00
mfranz 7e65ab2d3b add <condition> support to textranslate & texrotate animation 2006-04-12 20:27:38 +00:00
mfranz fec769f632 set sign orientation such, that when the sign heading=0, one looks straight
on the sign face when looking North
2006-04-12 12:13:03 +00:00
mfranz 90e42642b6 lower signs 2006-04-11 23:04:24 +00:00
mfranz 9d9610a882 add minimalistic backside to signs as a temporary solution 2006-04-11 21:32:15 +00:00
mfranz 1fc81f4b66 re-add hard-coded vertical distance. The coordinates should be surface
points and not add this distance, which depends on the sign housing/hardware,
after all.
2006-04-11 17:34:17 +00:00
mfranz 4f0b1e847c - commands do now have to start with @
- add commands @size, @material, @light
- make "BlackSign" texture default
- make @B, @R, @L, @Y open close their frames automatically (this can be
  avoided by setting the @material manually)
- add number variants for those 4 sign commands: @Y2, @B5, etc (according
  to the spec; defaulting to the respective biggest panel size, i.e. @B = @B3)
(detailed description will be added to $FG_ROOT/Docs/)
2006-04-11 15:57:08 +00:00
mfranz 9567ac32f2 remove obsolete files (on request by Christian Mayer, who has introduced them):
- they are not used anywhere in sg/fgfs
- and are very clearly *not* GPL compatible!
2006-04-10 16:36:52 +00:00
andy 8dd9cfa2a6 Manabu Nishiyama (non-FlightGear Nasal user) discovered an
uninitialized data bug in naHash_cget().  When the hashcode field of
naStr was introduced, I forgot to set it in this function, which
creates a temporary naStr on the stack.
2006-04-10 16:21:17 +00:00
mfranz dbda8ef893 drop xscale member again, and use xsize/ysize instead. (One interface
element less to confuse people.)
2006-04-10 15:32:55 +00:00
mfranz cd143c15d5 rewrite of OBJECT_TAXI_SIGN code. The name is a bit misleading, as this
type can also create runway signs. (/me thinks about changing that ...)
2006-04-09 19:51:00 +00:00
mfranz 509a388ccc support for font textures. They are normal (but rather lenghty) <material>,
but contain <glyph> entries with <name>, <left> and <right>. The latter two
describe where in the texture a letter or symbol begins and where it ends.
(range 0-1). <xscale> defines a horizontal scaling factor.
2006-04-09 19:21:13 +00:00
230 changed files with 17732 additions and 10873 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ EXTRA_DIST = \
DoxygenMain.cxx \ DoxygenMain.cxx \
README.MSVC \ README.MSVC \
README.zlib \ README.zlib \
projects \ projects \
SimGear.dsp \ SimGear.dsp \
SimGear.dsw SimGear.dsw
+67 -33
View File
@@ -556,21 +556,6 @@ SOURCE=.\simgear\math\vector.cxx
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\simgear\math\fastmath.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
# PROP Intermediate_Dir "Release\Lib_sgmath"
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
# PROP Intermediate_Dir "Debug\Lib_sgmath"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\simgear\math\SGGeodesy.cxx SOURCE=.\simgear\math\SGGeodesy.cxx
!IF "$(CFG)" == "SimGear - Win32 Release" !IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1184,21 +1169,6 @@ SOURCE=.\simgear\scene\model\animation.cxx
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\simgear\scene\model\custtrans.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
# PROP Intermediate_Dir "Release\Lib_sgmodel"
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
# PROP Intermediate_Dir "Debug\Lib_sgmodel"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\simgear\scene\model\location.cxx SOURCE=.\simgear\scene\model\location.cxx
!IF "$(CFG)" == "SimGear - Win32 Release" !IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1244,7 +1214,7 @@ SOURCE=.\simgear\scene\model\modellib.cxx
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\simgear\scene\model\personality.cxx SOURCE=.\simgear\scene\model\persparam.cxx
!IF "$(CFG)" == "SimGear - Win32 Release" !IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1289,7 +1259,7 @@ SOURCE=.\simgear\scene\model\placementtrans.cxx
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\simgear\scene\model\shadowvolume.cxx SOURCE=.\simgear\scene\model\shadanim.cxx
!IF "$(CFG)" == "SimGear - Win32 Release" !IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1304,7 +1274,7 @@ SOURCE=.\simgear\scene\model\shadowvolume.cxx
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\simgear\scene\model\shadanim.cxx SOURCE=.\simgear\scene\model\SGMaterialAnimation.cxx
!IF "$(CFG)" == "SimGear - Win32 Release" !IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1549,6 +1519,40 @@ SOURCE=.\simgear\scene\tgdb\userdata.cxx
!ENDIF !ENDIF
# End Source File
# End Group
# Begin Group "Lib_sgutil"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\simgear\scene\util\SGStateAttributeVisitor.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
# PROP Intermediate_Dir "Release\Lib_sgutil"
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
# PROP Intermediate_Dir "Debug\Lib_sgutil"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\simgear\scene\util\SGTextureStateAttributeVisitor.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
# PROP Intermediate_Dir "Release\Lib_sgutil"
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
# PROP Intermediate_Dir "Debug\Lib_sgutil"
!ENDIF
# End Source File # End Source File
# End Group # End Group
# Begin Group "Lib_sgscreen" # Begin Group "Lib_sgscreen"
@@ -1805,6 +1809,36 @@ SOURCE=.\simgear\structure\subsystem_mgr.cxx
!ENDIF !ENDIF
# End Source File
# Begin Source File
SOURCE=.\simgear\structure\SGAtomic.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
# PROP Intermediate_Dir "Release\Lib_sgstructure"
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
# PROP Intermediate_Dir "Debug\Lib_sgstructure"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\simgear\structure\SGBinding.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
# PROP Intermediate_Dir "Release\Lib_sgstructure"
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
# PROP Intermediate_Dir "Debug\Lib_sgstructure"
!ENDIF
# End Source File # End Source File
# End Group # End Group
# Begin Group "Lib_sgtiming" # Begin Group "Lib_sgtiming"
+21
View File
@@ -47,6 +47,18 @@ Jean-Francois Doue
http://www.animats.com/simpleppp/ftp/public_html/topics/developers.html http://www.animats.com/simpleppp/ftp/public_html/topics/developers.html
Melchior Franz
METAR parser and fetcher. "material" animation (based on Jim Wilsons's
"emission" animation). Debugging and extension of property listener
features. Addition of removeChildren.
Mathias Froehlich
Reworked and cleaned up large parts of the infrastructure, of math
files, animations and rendering in preparation of a transition to
the OSG library. Added new handlers for shared and referenced objects.
Bruce Finney <bfinney@gte.net> Bruce Finney <bfinney@gte.net>
MSVC5 compatibility. MSVC5 compatibility.
@@ -71,6 +83,10 @@ Bruce Jackson of NASA <e.b.jackson@larc.nasa.gov>
http://dcb.larc.nasa.gov/www/DCBStaff/ebj/ebj.html http://dcb.larc.nasa.gov/www/DCBStaff/ebj/ebj.html
Maik Justus
Fixed an old bug in the SGPropertyNode class.
Richard Kaszeta <bofh@me.umn.edu> Richard Kaszeta <bofh@me.umn.edu>
Contributed screen buffer to ppm screen shot routine. Contributed screen buffer to ppm screen shot routine.
Rich has also helped in the early development of the Flight Gear "altitude Rich has also helped in the early development of the Flight Gear "altitude
@@ -90,6 +106,11 @@ David Megginson <david@megginson.com>
SimGear property manager/registry SimGear property manager/registry
Tim Moore
Ported the (chrome) "shader" animation to OSG, and helped with porting
the "material" animation.
Curt Olson http://www.flightgear.org/~curt/ Curt Olson http://www.flightgear.org/~curt/
Curt is responsible for overall project and source code management. Curt is responsible for overall project and source code management.
He has his hands in many of the areas. He has his hands in many of the areas.
+12 -3
View File
@@ -119,6 +119,14 @@ if test "x$with_plib" != "x" ; then
EXTRA_DIRS="${EXTRA_DIRS} $with_plib" EXTRA_DIRS="${EXTRA_DIRS} $with_plib"
fi fi
# specify the osg location
AC_ARG_WITH(osg, [ --with-osg=PREFIX Specify the prefix path to osg])
if test "x$with_osg" != "x" ; then
echo "osg prefix is $with_osg"
EXTRA_DIRS="${EXTRA_DIRS} $with_osg"
fi
dnl Determine an extra directories to add to include/lib search paths dnl Determine an extra directories to add to include/lib search paths
case "${host}" in case "${host}" in
*-apple-darwin* | *-*-cygwin* | *-*-mingw32*) *-apple-darwin* | *-*-cygwin* | *-*-mingw32*)
@@ -261,10 +269,10 @@ OPENAL_OK="no"
case "${host}" in case "${host}" in
*-*-cygwin* | *-*-mingw32*) *-*-cygwin* | *-*-mingw32*)
dnl CygWin under Windoze. dnl CygWin under Windoze.
INCLUDES="$INCLUDES -I/usr/local/include" INCLUDES="$INCLUDES -I/usr/local/include/"
LIBS="$LIBS -L/usr/local/lib" LIBS="$LIBS -L/usr/local/lib"
AC_SEARCH_LIBS(alGenBuffers, openal32) AC_SEARCH_LIBS(alGenBuffers, [ openal32 openal ] )
AC_SEARCH_LIBS(alutInit, [ openal32 ALut ] ) AC_SEARCH_LIBS(alutInit, [ openal32 ALut alut ] )
LIBS="$LIBS -lwinmm -ldsound -ldxguid -lole32" LIBS="$LIBS -lwinmm -ldsound -ldxguid -lole32"
openal_LIBS="$LIBS" openal_LIBS="$LIBS"
OPENAL_OK="$ac_cv_search_alGenBuffers" OPENAL_OK="$ac_cv_search_alGenBuffers"
@@ -430,6 +438,7 @@ AC_CONFIG_FILES([ \
simgear/scene/model/Makefile \ simgear/scene/model/Makefile \
simgear/scene/sky/Makefile \ simgear/scene/sky/Makefile \
simgear/scene/tgdb/Makefile \ simgear/scene/tgdb/Makefile \
simgear/scene/util/Makefile \
simgear/screen/Makefile \ simgear/screen/Makefile \
simgear/serial/Makefile \ simgear/serial/Makefile \
simgear/sound/Makefile \ simgear/sound/Makefile \
+4
View File
@@ -0,0 +1,4 @@
Debug
Release
SimGear.ncb
SimGear.suo
+21
View File
@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimGear", "SimGear.vcproj", "{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Debug.ActiveCfg = Debug|Win32
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Debug.Build.0 = Debug|Win32
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Release.ActiveCfg = Release|Win32
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal
+1079
View File
File diff suppressed because it is too large Load Diff
+171 -43
View File
@@ -41,11 +41,11 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../AL/include;&quot;../../../zlib-1.2.3&quot;;&quot;../../../Pre-built.2/include&quot;" AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="1" RuntimeLibrary="3"
UsePrecompiledHeader="0" UsePrecompiledHeader="0"
WarningLevel="3" WarningLevel="3"
Detect64BitPortabilityProblems="false" Detect64BitPortabilityProblems="false"
@@ -103,11 +103,11 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="2" Optimization="2"
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../AL/include;&quot;../../../zlib-1.2.3&quot;;&quot;../../../Pre-built.2/include&quot;" AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
StringPooling="true" StringPooling="true"
MinimalRebuild="true" MinimalRebuild="true"
RuntimeLibrary="0" RuntimeLibrary="2"
FloatingPointModel="2" FloatingPointModel="2"
UsePrecompiledHeader="0" UsePrecompiledHeader="0"
WarningLevel="3" WarningLevel="3"
@@ -215,10 +215,6 @@
RelativePath="..\..\simgear\magvar\coremag.hxx" RelativePath="..\..\simgear\magvar\coremag.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\model\custtrans.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\nasal\data.h" RelativePath="..\..\simgear\nasal\data.h"
> >
@@ -247,10 +243,6 @@
RelativePath="..\..\simgear\screen\extensions.hxx" RelativePath="..\..\simgear\screen\extensions.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\math\fastmath.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\timing\geocoord.h" RelativePath="..\..\simgear\timing\geocoord.h"
> >
@@ -511,6 +503,26 @@
RelativePath="..\..\simgear\math\sg_types.hxx" RelativePath="..\..\simgear\math\sg_types.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\structure\SGAtomic.hxx"
>
</File>
<File
RelativePath="..\..\simgear\structure\SGBinding.hxx"
>
</File>
<File
RelativePath="..\..\simgear\math\SGCMath.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGDebugDrawCallback.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGEnlargeBoundingBox.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\math\SGGeoc.hxx" RelativePath="..\..\simgear\math\SGGeoc.hxx"
> >
@@ -531,10 +543,18 @@
RelativePath="..\..\simgear\math\SGLimits.hxx" RelativePath="..\..\simgear\math\SGLimits.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\model\SGMaterialAnimation.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\math\SGMath.hxx" RelativePath="..\..\simgear\math\SGMath.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\math\SGMathFwd.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\math\SGMatrix.hxx" RelativePath="..\..\simgear\math\SGMatrix.hxx"
> >
@@ -543,6 +563,18 @@
RelativePath="..\..\simgear\math\SGMisc.hxx" RelativePath="..\..\simgear\math\SGMisc.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\util\SGNodeMasks.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\tgdb\SGOceanTile.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGOffsetTransform.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\math\SGQuat.hxx" RelativePath="..\..\simgear\math\SGQuat.hxx"
> >
@@ -555,18 +587,54 @@
RelativePath="..\..\simgear\structure\SGReferenced.hxx" RelativePath="..\..\simgear\structure\SGReferenced.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\model\SGRotateTransform.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGScaleTransform.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGSceneFeatures.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGSceneUserData.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\structure\SGSharedPtr.hxx" RelativePath="..\..\simgear\structure\SGSharedPtr.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\util\SGStateAttributeVisitor.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\misc\sgstream.hxx" RelativePath="..\..\simgear\misc\sgstream.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\threads\SGThread.hxx" RelativePath="..\..\simgear\threads\SGThread.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\model\SGTranslateTransform.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGUpdateVisitor.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\tgdb\SGVasiDrawable.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\math\SGVec3.hxx" RelativePath="..\..\simgear\math\SGVec3.hxx"
> >
@@ -583,20 +651,6 @@
RelativePath="..\..\simgear\scene\model\shadowvolume.hxx" RelativePath="..\..\simgear\scene\model\shadowvolume.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\simgear_config.h"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCustomBuildTool"
Description=""
CommandLine=""
Outputs=""
/>
</FileConfiguration>
</File>
<File <File
RelativePath="..\..\simgear\scene\sky\sky.hxx" RelativePath="..\..\simgear\scene\sky\sky.hxx"
> >
@@ -761,6 +815,10 @@
RelativePath="..\..\simgear\scene\sky\bbcache.cxx" RelativePath="..\..\simgear\scene\sky\bbcache.cxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\nasal\bitslib.c"
>
</File>
<File <File
RelativePath="..\..\simgear\ephemeris\celestialBody.cxx" RelativePath="..\..\simgear\ephemeris\celestialBody.cxx"
> >
@@ -793,10 +851,6 @@
RelativePath="..\..\simgear\magvar\coremag.cxx" RelativePath="..\..\simgear\magvar\coremag.cxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\model\custtrans.cxx"
>
</File>
<File <File
RelativePath="..\..\simgear\scene\sky\dome.cxx" RelativePath="..\..\simgear\scene\sky\dome.cxx"
> >
@@ -821,10 +875,6 @@
RelativePath="..\..\simgear\screen\extensions.cxx" RelativePath="..\..\simgear\screen\extensions.cxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\math\fastmath.cxx"
>
</File>
<File <File
RelativePath="..\..\simgear\nasal\gc.c" RelativePath="..\..\simgear\nasal\gc.c"
> >
@@ -858,11 +908,11 @@
> >
</File> </File>
<File <File
RelativePath="..\..\simgear\ephemeris\jupiter.cxx" RelativePath="..\..\simgear\nasal\iolib.c"
> >
</File> </File>
<File <File
RelativePath="..\..\simgear\scene\tgdb\leaf.cxx" RelativePath="..\..\simgear\ephemeris\jupiter.cxx"
> >
</File> </File>
<File <File
@@ -970,7 +1020,7 @@
> >
</File> </File>
<File <File
RelativePath="..\..\simgear\scene\model\personality.cxx" RelativePath="..\..\simgear\scene\model\persparam.cxx"
> >
</File> </File>
<File <File
@@ -1057,18 +1107,70 @@
RelativePath="..\..\simgear\timing\sg_time.cxx" RelativePath="..\..\simgear\timing\sg_time.cxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\structure\SGBinding.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGEnlargeBoundingBox.cxx"
>
</File>
<File <File
RelativePath="..\..\simgear\math\SGGeodesy.cxx" RelativePath="..\..\simgear\math\SGGeodesy.cxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\model\SGMaterialAnimation.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\tgdb\SGOceanTile.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGOffsetTransform.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGRotateTransform.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGScaleTransform.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGSceneFeatures.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGSceneUserData.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGStateAttributeVisitor.cxx"
>
</File>
<File <File
RelativePath="..\..\simgear\misc\sgstream.cxx" RelativePath="..\..\simgear\misc\sgstream.cxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.cxx"
>
</File>
<File <File
RelativePath="..\..\simgear\threads\SGThread.cxx" RelativePath="..\..\simgear\threads\SGThread.cxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\model\SGTranslateTransform.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\tgdb\SGVasiDrawable.cxx"
>
</File>
<File <File
RelativePath="..\..\simgear\scene\model\shadanim.cxx" RelativePath="..\..\simgear\scene\model\shadanim.cxx"
> >
@@ -1077,10 +1179,6 @@
RelativePath="..\..\simgear\screen\shader.cpp" RelativePath="..\..\simgear\screen\shader.cpp"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\model\shadowvolume.cxx"
>
</File>
<File <File
RelativePath="..\..\simgear\scene\sky\sky.cxx" RelativePath="..\..\simgear\scene\sky\sky.cxx"
> >
@@ -1137,6 +1235,10 @@
RelativePath="..\..\simgear\nasal\thread-win32.c" RelativePath="..\..\simgear\nasal\thread-win32.c"
> >
</File> </File>
<File
RelativePath="..\..\simgear\nasal\threadlib.c"
>
</File>
<File <File
RelativePath="..\..\simgear\timing\timestamp.cxx" RelativePath="..\..\simgear\timing\timestamp.cxx"
> >
@@ -1157,6 +1259,10 @@
RelativePath="..\..\simgear\scene\tgdb\userdata.cxx" RelativePath="..\..\simgear\scene\tgdb\userdata.cxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\nasal\utf8lib.c"
>
</File>
<File <File
RelativePath="..\..\simgear\nasal\vector.c" RelativePath="..\..\simgear\nasal\vector.c"
> >
@@ -1214,6 +1320,28 @@
> >
</File> </File>
</Filter> </Filter>
<File
RelativePath="..\..\simgear\simgear_config.h-msvc71"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCustomBuildTool"
CommandLine="copy &quot;$(InputPath)&quot; &quot;$(InputDir)\$(InputName).h&quot;&#x0D;&#x0A;"
Outputs="&quot;${InputDir}\$(InputName).h&quot;"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCustomBuildTool"
CommandLine="copy &quot;$(InputPath)&quot; &quot;$(InputDir)\$(InputName).h&quot;&#x0D;&#x0A;"
Outputs="${InputDir}\$(InputName).h"
/>
</FileConfiguration>
</File>
</Files> </Files>
<Globals> <Globals>
</Globals> </Globals>
+2 -2
View File
@@ -7,7 +7,7 @@ endif
# METAR_DIRS = # METAR_DIRS =
METAR_DIRS = environment METAR_DIRS = environment
EXTRA_DIST = simgear_config.h.vc5 version.h.in EXTRA_DIST = simgear_config.h.vc5 simgear_config.h-msvc71 version.h.in
include_HEADERS = \ include_HEADERS = \
compiler.h constants.h sg_inlines.h sg_traits.hxx version.h compiler.h constants.h sg_inlines.h sg_traits.hxx version.h
@@ -34,4 +34,4 @@ SUBDIRS = \
$(SGTHREAD_DIR) \ $(SGTHREAD_DIR) \
timing timing
DIST_SUBDIRS = $(SUBDIRS) compatibility threads DIST_SUBDIRS = $(SUBDIRS) compatibility
+8 -5
View File
@@ -44,6 +44,9 @@ SGBucket::SGBucket(const double dlon, const double dlat) {
set_bucket(dlon, dlat); set_bucket(dlon, dlat);
} }
SGBucket::SGBucket(const SGGeod& geod) {
set_bucket(geod);
}
// create an impossible bucket if false // create an impossible bucket if false
SGBucket::SGBucket(const bool is_good) { SGBucket::SGBucket(const bool is_good) {
@@ -73,11 +76,6 @@ SGBucket::SGBucket(const long int bindex) {
} }
// default destructor
SGBucket::~SGBucket() {
}
// Set the bucket params for the specified lat and lon // Set the bucket params for the specified lat and lon
void SGBucket::set_bucket( double *lonlat ) { void SGBucket::set_bucket( double *lonlat ) {
set_bucket( lonlat[0], lonlat[1] ); set_bucket( lonlat[0], lonlat[1] );
@@ -135,6 +133,11 @@ void SGBucket::set_bucket( double dlon, double dlat ) {
} }
void SGBucket::set_bucket(const SGGeod& geod)
{
set_bucket(geod.getLongitudeDeg(), geod.getLatitudeDeg());
}
// Build the path name for this bucket // Build the path name for this bucket
string SGBucket::gen_base_path() const { string SGBucket::gen_base_path() const {
// long int index; // long int index;
+33 -6
View File
@@ -31,6 +31,7 @@
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <simgear/constants.h> #include <simgear/constants.h>
#include <simgear/math/SGMath.hxx>
#ifdef SG_HAVE_STD_INCLUDES #ifdef SG_HAVE_STD_INCLUDES
# include <cmath> # include <cmath>
@@ -133,6 +134,13 @@ public:
*/ */
SGBucket(const double dlon, const double dlat); SGBucket(const double dlon, const double dlat);
/**
* Construct a bucket given a specific location.
* @param dlon longitude specified in degrees
* @param dlat latitude specified in degrees
*/
SGBucket(const SGGeod& geod);
/** Construct a bucket. /** Construct a bucket.
* @param is_good if false, create an invalid bucket. This is * @param is_good if false, create an invalid bucket. This is
* useful * if you are comparing cur_bucket to last_bucket and * useful * if you are comparing cur_bucket to last_bucket and
@@ -146,11 +154,6 @@ public:
*/ */
SGBucket(const long int bindex); SGBucket(const long int bindex);
/**
* Default destructor.
*/
~SGBucket();
/** /**
* Reset a bucket to represent a new lat and lon * Reset a bucket to represent a new lat and lon
* @param dlon longitude specified in degrees * @param dlon longitude specified in degrees
@@ -165,6 +168,13 @@ public:
*/ */
void set_bucket( double *lonlat ); void set_bucket( double *lonlat );
/**
* Reset a bucket to represent a new lat and lon
* @param dlon longitude specified in degrees
* @param dlat latitude specified in degrees
*/
void set_bucket(const SGGeod& geod);
/** /**
* Create an impossible bucket. * Create an impossible bucket.
* This is useful if you are comparing cur_bucket to last_bucket * This is useful if you are comparing cur_bucket to last_bucket
@@ -252,7 +262,24 @@ public:
* @return the height of the tile in meters. * @return the height of the tile in meters.
*/ */
double get_height_m() const; double get_height_m() const;
/**
* @return the center of the bucket in geodetic coordinates.
*/
SGGeod get_center() const
{ return SGGeod::fromDeg(get_center_lon(), get_center_lat()); }
/**
* @return the center of the bucket in geodetic coordinates.
*/
SGGeod get_corner(unsigned num) const
{
double lonFac = ((num + 1) & 2) ? 0.5 : -0.5;
double latFac = ((num ) & 2) ? 0.5 : -0.5;
return SGGeod::fromDeg(get_center_lon() + lonFac*get_width(),
get_center_lat() + latFac*get_height());
}
// Informational methods. // Informational methods.
/** /**
+1
View File
@@ -230,6 +230,7 @@
# define isnan _isnan # define isnan _isnan
# define snprintf _snprintf # define snprintf _snprintf
# define copysign _copysign
# pragma warning(disable: 4786) // identifier was truncated to '255' characters # pragma warning(disable: 4786) // identifier was truncated to '255' characters
# pragma warning(disable: 4244) // conversion from double to float # pragma warning(disable: 4244) // conversion from double to float
+6
View File
@@ -128,6 +128,12 @@
/** Knots to Miles per second */ /** Knots to Miles per second */
#define SG_KT_TO_MPS 0.5144444444444444444 #define SG_KT_TO_MPS 0.5144444444444444444
/** Feet per second to Knots */
#define SG_FPS_TO_KT 0.5924838012958962841
/** Knots to Feet per second */
#define SG_KT_TO_FPS 1.6878098571011956874
/** Miles per second to Miles per hour */ /** Miles per second to Miles per hour */
#define SG_MPS_TO_MPH 2.2369362920544020312 #define SG_MPS_TO_MPH 2.2369362920544020312
+3
View File
@@ -25,6 +25,9 @@
logstream *global_logstream = NULL; logstream *global_logstream = NULL;
bool logbuf::logging_enabled = true; bool logbuf::logging_enabled = true;
#ifdef _MSC_VER
bool logbuf::has_console = true;
#endif
sgDebugClass logbuf::logClass = SG_NONE; sgDebugClass logbuf::logClass = SG_NONE;
sgDebugPriority logbuf::logPriority = SG_INFO; sgDebugPriority logbuf::logPriority = SG_INFO;
streambuf* logbuf::sbuf = NULL; streambuf* logbuf::sbuf = NULL;
+7 -1
View File
@@ -139,6 +139,10 @@ public:
*/ */
void set_sb( streambuf* sb ); void set_sb( streambuf* sb );
#ifdef _MSC_VER
static void has_no_console() { has_console = false; }
#endif
protected: protected:
/** sync/flush */ /** sync/flush */
@@ -154,6 +158,9 @@ private:
static streambuf* sbuf; static streambuf* sbuf;
static bool logging_enabled; static bool logging_enabled;
#ifdef _MSC_VER
static bool has_console;
#endif
static sgDebugClass logClass; static sgDebugClass logClass;
static sgDebugPriority logPriority; static sgDebugPriority logPriority;
@@ -184,7 +191,6 @@ inline logbuf::int_type
logbuf::overflow( int c ) logbuf::overflow( int c )
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
static bool has_console = false;
if ( logging_enabled ) { if ( logging_enabled ) {
if ( !has_console ) { if ( !has_console ) {
AllocConsole(); AllocConsole();
+12 -1
View File
@@ -24,6 +24,9 @@
* @file metar.cxx * @file metar.cxx
* Interface for encoded Meteorological Aerodrome Reports (METAR). * Interface for encoded Meteorological Aerodrome Reports (METAR).
*/ */
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <string> #include <string>
#include <time.h> #include <time.h>
@@ -744,6 +747,14 @@ bool SGMetar::scanSkyCondition()
int i; int i;
SGMetarCloud cl; SGMetarCloud cl;
if (!strncmp(m, "//////", 6)) {
m += 6;
if (!scanBoundary(&m))
return false;
_m = m;
return true;
}
if (!strncmp(m, "CLR", i = 3) // clear if (!strncmp(m, "CLR", i = 3) // clear
|| !strncmp(m, "SKC", i = 3) // sky clear || !strncmp(m, "SKC", i = 3) // sky clear
|| !strncmp(m, "NSC", i = 3) // no significant clouds || !strncmp(m, "NSC", i = 3) // no significant clouds
@@ -833,7 +844,7 @@ bool SGMetar::scanTemperature()
return false; return false;
if (!scanBoundary(&m)) { if (!scanBoundary(&m)) {
if (!strncmp(m, "XX", 2)) // not spec compliant! if (!strncmp(m, "XX", 2)) // not spec compliant!
m += 2, sign = 0; m += 2, sign = 0, dew = temp;
else { else {
sign = 1; sign = 1;
if (*m == 'M') if (*m == 'M')
+34 -7
View File
@@ -1,6 +1,9 @@
// Visual environment helper class // Visual environment helper class
// //
// Written by Harald JOHNSEN, started April 2005. // Written by Harald JOHNSEN, started April 2005.
// Minor changes/additions by Vivian Meazza Apr- May 2007
//
// Ported to OSG by Tim Moore Jun 2007
// //
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net // Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
// //
@@ -23,7 +26,6 @@
# include <simgear_config.h> # include <simgear_config.h>
#endif #endif
#include <plib/sg.h>
#include <simgear/constants.h> #include <simgear/constants.h>
#include <simgear/structure/SGReferenced.hxx> #include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
@@ -190,6 +192,8 @@ SGEnviro::SGEnviro() :
} }
SGEnviro::~SGEnviro(void) { SGEnviro::~SGEnviro(void) {
// OSGFIXME
return;
list_of_lightning::iterator iLightning; list_of_lightning::iterator iLightning;
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) { for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
delete (*iLightning); delete (*iLightning);
@@ -198,6 +202,8 @@ SGEnviro::~SGEnviro(void) {
} }
void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) { void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) {
// OSGFIXME
return;
view_in_cloud = false; view_in_cloud = false;
// ask the impostor cache to do some cleanup // ask the impostor cache to do some cleanup
if(SGNewCloud::cldCache) if(SGNewCloud::cldCache)
@@ -320,13 +326,15 @@ void SGEnviro::set_lightning_enable_state(bool enable) {
} }
void SGEnviro::setLight(sgVec4 adj_fog_color) { void SGEnviro::setLight(sgVec4 adj_fog_color) {
// OSGFIXME
return;
sgCopyVec4( fog_color, adj_fog_color ); sgCopyVec4( fog_color, adj_fog_color );
if( false ) { if( false ) {
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() ); // ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
} }
} }
void SGEnviro::callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId) { void SGEnviro::callback_cloud(float bearing, float alt, float radius, int family, float dist, int cloudId) {
// send data to wx radar // send data to wx radar
// compute turbulence // compute turbulence
// draw precipitation // draw precipitation
@@ -398,9 +406,10 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
LWC = 0.29*2.0; LWC = 0.29*2.0;
break; break;
} }
// add to the list for the wxRadar instrument // add to the list for the wxRadar instrument
if( LWC > 0.0 ) if( LWC > 0.0 )
radarEcho.push_back( SGWxRadarEcho ( heading, alt, radius, dist, LWC, false, cloudId ) ); radarEcho.push_back( SGWxRadarEcho ( bearing, alt, radius, dist, 0.0 , LWC, false, cloudId, false ) );
// NB:data valid only from cockpit view // NB:data valid only from cockpit view
@@ -413,7 +422,7 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
orig.setlon(last_lon * SG_DEGREES_TO_RADIANS ); orig.setlon(last_lon * SG_DEGREES_TO_RADIANS );
orig.setelev(0.0); orig.setelev(0.0);
dist = sgSqrt(dist); dist = sgSqrt(dist);
dest = calc_gc_lon_lat(orig, heading, dist); dest = calc_gc_lon_lat(orig, bearing, dist);
lon = dest.lon() * SG_RADIANS_TO_DEGREES; lon = dest.lon() * SG_RADIANS_TO_DEGREES;
lat = dest.lat() * SG_RADIANS_TO_DEGREES; lat = dest.lat() * SG_RADIANS_TO_DEGREES;
addLightning( lon, lat, alt ); addLightning( lon, lat, alt );
@@ -441,6 +450,8 @@ list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
// precipitation rendering code // precipitation rendering code
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) { void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
// OSGFIXME
return;
sgVec3 light; sgVec3 light;
sgAddVec3( light, fog_color, min_light ); sgAddVec3( light, fog_color, min_light );
float da = SG_PI * 2.0f / (float) slices; float da = SG_PI * 2.0f / (float) slices;
@@ -489,6 +500,8 @@ void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down,
} }
void SGEnviro::drawRain(double pitch, double roll, double heading, double hspeed, double rain_norm) { void SGEnviro::drawRain(double pitch, double roll, double heading, double hspeed, double rain_norm) {
// OSGFIXME
return;
#if 0 #if 0
static int debug_period = 0; static int debug_period = 0;
@@ -558,6 +571,8 @@ void SGEnviro::set_soundMgr(SGSoundMgr *mgr) {
} }
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) { void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) {
// OSGFIXME
return;
if( precipitation_enable_state && rain_norm > 0.0) if( precipitation_enable_state && rain_norm > 0.0)
if( precipitation_max_alt >= last_alt ) if( precipitation_max_alt >= last_alt )
drawRain(pitch, roll, heading, hspeed, rain_norm); drawRain(pitch, roll, heading, hspeed, rain_norm);
@@ -580,6 +595,8 @@ SGLightning::~SGLightning() {
// lightning rendering code // lightning rendering code
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) { void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
// OSGFIXME
return;
sgVec3 dir, newdir; sgVec3 dir, newdir;
int nseg = 0; int nseg = 0;
@@ -627,6 +644,8 @@ void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy
} }
void SGLightning::lt_build(void) { void SGLightning::lt_build(void) {
// OSGFIXME
return;
Point3D top; Point3D top;
nb_tree = 0; nb_tree = 0;
top[PX] = 0 ; top[PX] = 0 ;
@@ -652,6 +671,8 @@ void SGLightning::lt_build(void) {
void SGLightning::lt_Render(void) { void SGLightning::lt_Render(void) {
// OSGFIXME
return;
float flash = 0.5; float flash = 0.5;
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 ) if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
flash = sg_random() * 0.75f + 0.25f; flash = sg_random() * 0.75f + 0.25f;
@@ -676,10 +697,12 @@ void SGLightning::lt_Render(void) {
glDisable( GL_FOG ); glDisable( GL_FOG );
glPushMatrix(); glPushMatrix();
sgMat4 modelview, tmp; sgMat4 modelview, tmp;
ssgGetModelviewMatrix( modelview ); // OSGFIXME
// ssgGetModelviewMatrix( modelview );
sgCopyMat4( tmp, sgEnviro.transform ); sgCopyMat4( tmp, sgEnviro.transform );
sgPostMultMat4( tmp, modelview ); sgPostMultMat4( tmp, modelview );
ssgLoadModelviewMatrix( tmp ); // OSGFIXME
// ssgLoadModelviewMatrix( tmp );
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 ); 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 ); Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
@@ -691,7 +714,7 @@ void SGLightning::lt_Render(void) {
glTranslatef( ax, ay, -sgEnviro.last_alt ); glTranslatef( ax, ay, -sgEnviro.last_alt );
sgEnviro.radarEcho.push_back( SGWxRadarEcho ( course, 0.0, 0.0, dist, age, true, 0 ) ); sgEnviro.radarEcho.push_back( SGWxRadarEcho ( course, 0.0, 0.0, dist, 0.0, age, true, 0, false ) );
for( int n = 0 ; n < nb_tree ; n++ ) { for( int n = 0 ; n < nb_tree ; n++ ) {
if( lt_tree[n].prev < 0 ) if( lt_tree[n].prev < 0 )
@@ -737,6 +760,8 @@ void SGLightning::lt_Render(void) {
} }
void SGEnviro::addLightning(double lon, double lat, double alt) { void SGEnviro::addLightning(double lon, double lat, double alt) {
// OSGFIXME
return;
if( lightnings.size() > 10) if( lightnings.size() > 10)
return; return;
SGLightning *lt= new SGLightning(lon, lat, alt); SGLightning *lt= new SGLightning(lon, lat, alt);
@@ -744,6 +769,8 @@ void SGEnviro::addLightning(double lon, double lat, double alt) {
} }
void SGEnviro::drawLightning(void) { void SGEnviro::drawLightning(void) {
// OSGFIXME
return;
list_of_lightning::iterator iLightning; list_of_lightning::iterator iLightning;
// play 'thunder' for lightning // play 'thunder' for lightning
if( snd_active ) if( snd_active )
+17 -3
View File
@@ -1,6 +1,9 @@
// Visual environment helper class // Visual environment helper class
// //
// Written by Harald JOHNSEN, started April 2005. // Written by Harald JOHNSEN, started April 2005.
// Minor changes/additions by Vivian Meazza Apr- May 2007
//
// Ported to OSG by Tim Moore Jun 2007
// //
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net // Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
// //
@@ -22,6 +25,8 @@
#ifndef _VISUAL_ENVIRO_HXX #ifndef _VISUAL_ENVIRO_HXX
#define _VISUAL_ENVIRO_HXX #define _VISUAL_ENVIRO_HXX
#include <plib/sg.h>
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include STL_STRING #include STL_STRING
#include <vector> #include <vector>
@@ -38,23 +43,32 @@ class SGSoundMgr;
*/ */
class SGWxRadarEcho { class SGWxRadarEcho {
public: public:
SGWxRadarEcho(float _heading, float _alt, float _radius, float _dist, double _LWC, bool _lightning, int _cloudId) : SGWxRadarEcho(float _bearing, float _alt, float _radius, float _dist, float _heading,
double _LWC, bool _lightning, int _cloudId, bool _aircraft) :
bearing (_bearing),
heading( _heading ), heading( _heading ),
alt ( _alt ), alt ( _alt ),
radius ( _radius ), radius ( _radius ),
dist ( _dist ), dist ( _dist ),
LWC ( _LWC ), LWC ( _LWC ),
lightning ( _lightning ), lightning ( _lightning ),
aircraft ( _aircraft ),
cloudId ( _cloudId ) cloudId ( _cloudId )
{} {}
/** the heading in radian is versus north */ /** the heading and bearing in radian are versus north */
float heading; float bearing, heading;
float alt, radius, dist; float alt, radius, dist;
/** reflectivity converted to liquid water content. */ /** reflectivity converted to liquid water content. */
double LWC; double LWC;
/** if true then this data is for a lightning else it is for water echo. */ /** if true then this data is for a lightning else it is for water echo. */
bool lightning; bool lightning;
/** if true then this data is for an aircraft */
bool aircraft;
/** Unique identifier of cloud */ /** Unique identifier of cloud */
int cloudId; int cloudId;
}; };
+3 -4
View File
@@ -31,7 +31,7 @@
// Constructor // Constructor
SGEphemeris::SGEphemeris( const string &path ) { SGEphemeris::SGEphemeris( const std::string &path ) {
our_sun = new Star; our_sun = new Star;
moon = new MoonPos; moon = new MoonPos;
mercury = new Mercury; mercury = new Mercury;
@@ -42,9 +42,8 @@ SGEphemeris::SGEphemeris( const string &path ) {
uranus = new Uranus; uranus = new Uranus;
neptune = new Neptune; neptune = new Neptune;
nplanets = 7; nplanets = 7;
for ( int i = 0; i < nplanets; ++i ) { for ( int i = 0; i < nplanets; ++i )
sgdSetVec3( planets[i], 0.0, 0.0, 0.0 ); planets[i] = SGVec3d::zeros();
}
stars = new SGStarData( SGPath(path) ); stars = new SGStarData( SGPath(path) );
} }
+8 -6
View File
@@ -29,8 +29,7 @@
#ifndef _EPHEMERIS_HXX #ifndef _EPHEMERIS_HXX
#define _EPHEMERIS_HXX #define _EPHEMERIS_HXX
#include <string>
#include <plib/sg.h>
#include <simgear/ephemeris/star.hxx> #include <simgear/ephemeris/star.hxx>
#include <simgear/ephemeris/moonpos.hxx> #include <simgear/ephemeris/moonpos.hxx>
@@ -43,6 +42,9 @@
#include <simgear/ephemeris/neptune.hxx> #include <simgear/ephemeris/neptune.hxx>
#include <simgear/ephemeris/stardata.hxx> #include <simgear/ephemeris/stardata.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/misc/sg_path.hxx>
/** Ephemeris class /** Ephemeris class
* *
@@ -83,7 +85,7 @@ class SGEphemeris {
// planets[i][1] = Declination // planets[i][1] = Declination
// planets[i][2] = Magnitude // planets[i][2] = Magnitude
int nplanets; int nplanets;
sgdVec3 planets[7]; SGVec3d planets[7];
SGStarData *stars; SGStarData *stars;
@@ -95,7 +97,7 @@ public:
* calling the constructor you need to provide a path pointing to * calling the constructor you need to provide a path pointing to
* your star database file. * your star database file.
* @param path path to your star database */ * @param path path to your star database */
SGEphemeris( const string &path ); SGEphemeris( const std::string &path );
/** Destructor */ /** Destructor */
~SGEphemeris( void ); ~SGEphemeris( void );
@@ -155,7 +157,7 @@ public:
* the second is the declination, and the third is the magnitude. * the second is the declination, and the third is the magnitude.
* @return planets array * @return planets array
*/ */
inline sgdVec3 *getPlanets() { return planets; } inline SGVec3d *getPlanets() { return planets; }
/** @return the numbers of defined stars. */ /** @return the numbers of defined stars. */
inline int getNumStars() const { return stars->getNumStars(); } inline int getNumStars() const { return stars->getNumStars(); }
@@ -167,7 +169,7 @@ public:
* third is the magnitude. * third is the magnitude.
* @returns star array * @returns star array
*/ */
inline sgdVec3 *getStars() { return stars->getStars(); } inline SGVec3d *getStars() { return stars->getStars(); }
}; };
+15 -27
View File
@@ -25,6 +25,7 @@
#endif #endif
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sgstream.hxx> #include <simgear/misc/sgstream.hxx>
#include "stardata.hxx" #include "stardata.hxx"
@@ -34,16 +35,9 @@
#endif #endif
// Constructor // Constructor
SGStarData::SGStarData() : SGStarData::SGStarData( const SGPath& path )
nstars(0)
{ {
} load(path);
SGStarData::SGStarData( SGPath path ) :
nstars(0)
{
data_path = SGPath( path );
load();
} }
@@ -52,31 +46,28 @@ SGStarData::~SGStarData() {
} }
bool SGStarData::load() { bool SGStarData::load( const SGPath& path ) {
// -dw- avoid local data > 32k error by dynamic allocation of the _stars.clear();
// array, problem for some compilers
stars = new sgdVec3[SG_MAX_STARS];
// build the full path name to the stars data base file // build the full path name to the stars data base file
data_path.append( "stars" ); SGPath tmp = path;
SG_LOG( SG_ASTRO, SG_INFO, " Loading stars from " << data_path.str() ); tmp.append( "stars" );
SG_LOG( SG_ASTRO, SG_INFO, " Loading stars from " << tmp.str() );
sg_gzifstream in( data_path.str() ); sg_gzifstream in( tmp.str() );
if ( ! in.is_open() ) { if ( ! in.is_open() ) {
SG_LOG( SG_ASTRO, SG_ALERT, "Cannot open star file: " SG_LOG( SG_ASTRO, SG_ALERT, "Cannot open star file: "
<< data_path.str() ); << tmp.str() );
exit(-1); return false;
} }
double ra, dec, mag; double ra, dec, mag;
char c; char c;
string name; string name;
nstars = 0;
// read in each line of the file // read in each line of the file
while ( ! in.eof() && nstars < SG_MAX_STARS ) { while ( ! in.eof() ) {
in >> skipcomment; in >> skipcomment;
getline( in, name, ',' ); getline( in, name, ',' );
@@ -116,13 +107,10 @@ bool SGStarData::load() {
in >> mag; in >> mag;
// cout << " star data = " << ra << " " << dec << " " << mag << endl; // cout << " star data = " << ra << " " << dec << " " << mag << endl;
_stars.push_back(SGVec3d(ra, dec, mag));
sgdSetVec3( stars[nstars], ra, dec, mag );
++nstars;
} }
SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << nstars << " stars" ); SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << _stars.size() << " stars" );
return true; return true;
} }
+10 -19
View File
@@ -24,37 +24,28 @@
#ifndef _SG_STARDATA_HXX #ifndef _SG_STARDATA_HXX
#define _SG_STARDATA_HXX #define _SG_STARDATA_HXX
#include <vector>
#include <simgear/math/SGMath.hxx>
#include <plib/sg.h> class SGPath;
#include <simgear/misc/sg_path.hxx>
#define SG_MAX_STARS 850
class SGStarData { class SGStarData {
int nstars;
sgdVec3 *stars;
SGPath data_path;
public: public:
// Constructor // Constructor
SGStarData(); SGStarData( const SGPath& path );
SGStarData( SGPath path );
// Destructor // Destructor
~SGStarData(); ~SGStarData();
// load the stars database // load the stars database
bool load(); bool load( const SGPath& path );
// stars // stars
inline int getNumStars() const { return nstars; } inline int getNumStars() const { return _stars.size(); }
inline sgdVec3 *getStars() { return stars; } inline SGVec3d *getStars() { return &(_stars[0]); }
private:
std::vector<SGVec3d> _stars;
}; };
+3 -3
View File
@@ -37,14 +37,14 @@ int main( int argc, char **argv ) {
obj.get_gbs_radius()); obj.get_gbs_radius());
cout << endl; cout << endl;
point_list nodes = obj.get_wgs84_nodes(); std::vector<SGVec3d> nodes = obj.get_wgs84_nodes();
cout << "# vertex list" << endl; cout << "# vertex list" << endl;
for ( i = 0; i < (int)nodes.size(); ++i ) { for ( i = 0; i < (int)nodes.size(); ++i ) {
printf("v %.5f %.5f %.5f\n", nodes[i].x(), nodes[i].y(), nodes[i].z() ); printf("v %.5f %.5f %.5f\n", nodes[i].x(), nodes[i].y(), nodes[i].z() );
} }
cout << endl; cout << endl;
point_list normals = obj.get_normals(); std::vector<SGVec3f> normals = obj.get_normals();
cout << "# vertex normal list" << endl; cout << "# vertex normal list" << endl;
for ( i = 0; i < (int)normals.size(); ++i ) { for ( i = 0; i < (int)normals.size(); ++i ) {
printf("vn %.5f %.5f %.5f\n", printf("vn %.5f %.5f %.5f\n",
@@ -52,7 +52,7 @@ int main( int argc, char **argv ) {
} }
cout << endl; cout << endl;
point_list texcoords = obj.get_texcoords(); std::vector<SGVec2f> texcoords = obj.get_texcoords();
cout << "# texture coordinate list" << endl; cout << "# texture coordinate list" << endl;
for ( i = 0; i < (int)texcoords.size(); ++i ) { for ( i = 0; i < (int)texcoords.size(); ++i ) {
printf("vt %.5f %.5f\n", printf("vt %.5f %.5f\n",
+30 -45
View File
@@ -174,7 +174,7 @@ static void read_object( gzFile fp,
int idx_size; int idx_size;
bool do_vertices, do_normals, do_colors, do_texcoords; bool do_vertices, do_normals, do_colors, do_texcoords;
int j, k, idx; int j, k, idx;
static sgSimpleBuffer buf( 32768 ); // 32 Kb sgSimpleBuffer buf( 32768 ); // 32 Kb
char material[256]; char material[256];
// default values // default values
@@ -280,13 +280,13 @@ static void read_object( gzFile fp,
// read a binary file and populate the provided structures. // read a binary file and populate the provided structures.
bool SGBinObject::read_bin( const string& file ) { bool SGBinObject::read_bin( const string& file ) {
Point3D p; SGVec3d p;
int i, j, k; int i, j, k;
unsigned int nbytes; unsigned int nbytes;
static sgSimpleBuffer buf( 32768 ); // 32 Kb sgSimpleBuffer buf( 32768 ); // 32 Kb
// zero out structures // zero out structures
gbs_center = Point3D( 0 ); gbs_center = SGVec3d(0, 0, 0);
gbs_radius = 0.0; gbs_radius = 0.0;
wgs84_nodes.clear(); wgs84_nodes.clear();
@@ -322,7 +322,7 @@ bool SGBinObject::read_bin( const string& file ) {
string filegz = file + ".gz"; string filegz = file + ".gz";
if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) { if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) {
SG_LOG( SG_EVENT, SG_ALERT, SG_LOG( SG_EVENT, SG_ALERT,
"ERROR: opening " << file << " or " << filegz << "for reading!"); "ERROR: opening " << file << " or " << filegz << " for reading!");
return false; return false;
} }
@@ -407,7 +407,7 @@ bool SGBinObject::read_bin( const string& file ) {
sgEndianSwap( (uint64_t *)&(dptr[1]) ); sgEndianSwap( (uint64_t *)&(dptr[1]) );
sgEndianSwap( (uint64_t *)&(dptr[2]) ); sgEndianSwap( (uint64_t *)&(dptr[2]) );
} }
gbs_center = Point3D( dptr[0], dptr[1], dptr[2] ); gbs_center = SGVec3d( dptr[0], dptr[1], dptr[2] );
// cout << "Center = " << gbs_center << endl; // cout << "Center = " << gbs_center << endl;
ptr += sizeof(double) * 3; ptr += sizeof(double) * 3;
@@ -447,7 +447,7 @@ bool SGBinObject::read_bin( const string& file ) {
sgEndianSwap( (uint32_t *)&(fptr[1]) ); sgEndianSwap( (uint32_t *)&(fptr[1]) );
sgEndianSwap( (uint32_t *)&(fptr[2]) ); sgEndianSwap( (uint32_t *)&(fptr[2]) );
} }
wgs84_nodes.push_back( Point3D(fptr[0], fptr[1], fptr[2]) ); wgs84_nodes.push_back( SGVec3d(fptr[0], fptr[1], fptr[2]) );
fptr += 3; fptr += 3;
} }
} }
@@ -481,7 +481,8 @@ bool SGBinObject::read_bin( const string& file ) {
sgEndianSwap( (uint32_t *)&(fptr[2]) ); sgEndianSwap( (uint32_t *)&(fptr[2]) );
sgEndianSwap( (uint32_t *)&(fptr[3]) ); sgEndianSwap( (uint32_t *)&(fptr[3]) );
} }
colors.push_back( Point3D( fptr[0], fptr[1], fptr[2] ) ); SGVec4f color( fptr[0], fptr[1], fptr[2], fptr[3] );
colors.push_back( color );
fptr += 4; fptr += 4;
} }
} }
@@ -508,14 +509,11 @@ bool SGBinObject::read_bin( const string& file ) {
int count = nbytes / 3; int count = nbytes / 3;
normals.reserve( count ); normals.reserve( count );
for ( k = 0; k < count; ++k ) { for ( k = 0; k < count; ++k ) {
sgdVec3 normal; SGVec3f normal((ptr[0]) / 127.5 - 1.0,
sgdSetVec3( normal, (ptr[1]) / 127.5 - 1.0,
(ptr[0]) / 127.5 - 1.0, (ptr[2]) / 127.5 - 1.0);
(ptr[1]) / 127.5 - 1.0,
(ptr[2]) / 127.5 - 1.0 );
sgdNormalizeVec3( normal );
normals.push_back(Point3D(normal[0], normal[1], normal[2])); normals.push_back(normalize(normal));
ptr += 3; ptr += 3;
} }
} }
@@ -547,7 +545,7 @@ bool SGBinObject::read_bin( const string& file ) {
sgEndianSwap( (uint32_t *)&(fptr[0]) ); sgEndianSwap( (uint32_t *)&(fptr[0]) );
sgEndianSwap( (uint32_t *)&(fptr[1]) ); sgEndianSwap( (uint32_t *)&(fptr[1]) );
} }
texcoords.push_back( Point3D( fptr[0], fptr[1], 0 ) ); texcoords.push_back( SGVec2f( fptr[0], fptr[1] ) );
fptr += 2; fptr += 2;
} }
} }
@@ -612,10 +610,6 @@ bool SGBinObject::read_bin( const string& file ) {
bool SGBinObject::write_bin( const string& base, const string& name, bool SGBinObject::write_bin( const string& base, const string& name,
const SGBucket& b ) const SGBucket& b )
{ {
Point3D p;
sgVec2 t;
sgVec3 pt;
sgVec4 color;
int i, j; int i, j;
unsigned char idx_mask; unsigned char idx_mask;
int idx_size; int idx_size;
@@ -738,9 +732,8 @@ bool SGBinObject::write_bin( const string& base, const string& name,
sgWriteShort( fp, 1 ); // nelements sgWriteShort( fp, 1 ); // nelements
sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) { for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
p = wgs84_nodes[i] - gbs_center; SGVec3f p = toVec3f(wgs84_nodes[i] - gbs_center);
sgSetVec3( pt, p.x(), p.y(), p.z() ); sgWriteVec3( fp, p.data() );
sgWriteVec3( fp, pt );
} }
// dump vertex color list // dump vertex color list
@@ -749,12 +742,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
sgWriteShort( fp, 1 ); // nelements sgWriteShort( fp, 1 ); // nelements
sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes
for ( i = 0; i < (int)colors.size(); ++i ) { for ( i = 0; i < (int)colors.size(); ++i ) {
p = colors[i]; sgWriteVec4( fp, colors[i].data() );
// Right now we have a place holder for color alpha but we
// need to update the interface so the calling program can
// provide the info.
sgSetVec4( color, p.x(), p.y(), p.z(), 1.0 );
sgWriteVec4( fp, color );
} }
// dump vertex normal list // dump vertex normal list
@@ -764,7 +752,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
sgWriteUInt( fp, normals.size() * 3 ); // nbytes sgWriteUInt( fp, normals.size() * 3 ); // nbytes
char normal[3]; char normal[3];
for ( i = 0; i < (int)normals.size(); ++i ) { for ( i = 0; i < (int)normals.size(); ++i ) {
p = normals[i]; SGVec3f p = normals[i];
normal[0] = (unsigned char)((p.x() + 1.0) * 127.5); normal[0] = (unsigned char)((p.x() + 1.0) * 127.5);
normal[1] = (unsigned char)((p.y() + 1.0) * 127.5); normal[1] = (unsigned char)((p.y() + 1.0) * 127.5);
normal[2] = (unsigned char)((p.z() + 1.0) * 127.5); normal[2] = (unsigned char)((p.z() + 1.0) * 127.5);
@@ -777,9 +765,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
sgWriteShort( fp, 1 ); // nelements sgWriteShort( fp, 1 ); // nelements
sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes
for ( i = 0; i < (int)texcoords.size(); ++i ) { for ( i = 0; i < (int)texcoords.size(); ++i ) {
p = texcoords[i]; sgWriteVec2( fp, texcoords[i].data() );
sgSetVec2( t, p.x(), p.y() );
sgWriteVec2( fp, t );
} }
// dump point groups if they exist // dump point groups if they exist
@@ -1042,7 +1028,6 @@ bool SGBinObject::write_bin( const string& base, const string& name,
bool SGBinObject::write_ascii( const string& base, const string& name, bool SGBinObject::write_ascii( const string& base, const string& name,
const SGBucket& b ) const SGBucket& b )
{ {
Point3D p;
int i, j; int i, j;
SGPath file = base + "/" + b.gen_base_path() + "/" + name; SGPath file = base + "/" + b.gen_base_path() + "/" + name;
@@ -1084,7 +1069,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
// dump vertex list // dump vertex list
fprintf(fp, "# vertex list\n"); fprintf(fp, "# vertex list\n");
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) { for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
p = wgs84_nodes[i] - gbs_center; SGVec3d p = wgs84_nodes[i] - gbs_center;
fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() ); fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
} }
@@ -1092,7 +1077,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
fprintf(fp, "# vertex normal list\n"); fprintf(fp, "# vertex normal list\n");
for ( i = 0; i < (int)normals.size(); ++i ) { for ( i = 0; i < (int)normals.size(); ++i ) {
p = normals[i]; SGVec3f p = normals[i];
fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() ); fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
} }
fprintf(fp, "\n"); fprintf(fp, "\n");
@@ -1100,7 +1085,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
// dump texture coordinates // dump texture coordinates
fprintf(fp, "# texture coordinate list\n"); fprintf(fp, "# texture coordinate list\n");
for ( i = 0; i < (int)texcoords.size(); ++i ) { for ( i = 0; i < (int)texcoords.size(); ++i ) {
p = texcoords[i]; SGVec2f p = texcoords[i];
fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y() ); fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y() );
} }
fprintf(fp, "\n"); fprintf(fp, "\n");
@@ -1126,13 +1111,13 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
// make a list of points for the group // make a list of points for the group
point_list group_nodes; point_list group_nodes;
group_nodes.clear(); group_nodes.clear();
Point3D bs_center; SGVec3d bs_center;
double bs_radius = 0; double bs_radius = 0;
for ( i = start; i < end; ++i ) { for ( i = start; i < end; ++i ) {
for ( j = 0; j < (int)tris_v[i].size(); ++j ) { for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
group_nodes.push_back( wgs84_nodes[ tris_v[i][j] ] ); group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ tris_v[i][j] ]) );
bs_center = sgCalcCenter( group_nodes ); bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes ); bs_radius = sgCalcBoundingRadius( Point3D::fromSGVec3(bs_center), group_nodes );
} }
} }
@@ -1177,13 +1162,13 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
// make a list of points for the group // make a list of points for the group
point_list group_nodes; point_list group_nodes;
group_nodes.clear(); group_nodes.clear();
Point3D bs_center; SGVec3d bs_center;
double bs_radius = 0; double bs_radius = 0;
for ( i = start; i < end; ++i ) { for ( i = start; i < end; ++i ) {
for ( j = 0; j < (int)strips_v[i].size(); ++j ) { for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
group_nodes.push_back( wgs84_nodes[ strips_v[i][j] ] ); group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ strips_v[i][j] ]) );
bs_center = sgCalcCenter( group_nodes ); bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes ); bs_radius = sgCalcBoundingRadius( Point3D::fromSGVec3(bs_center), group_nodes );
} }
} }
+43 -15
View File
@@ -89,13 +89,13 @@ typedef group_list::const_iterator const_group_list_iterator;
class SGBinObject { class SGBinObject {
unsigned short version; unsigned short version;
Point3D gbs_center; SGVec3d gbs_center;
float gbs_radius; float gbs_radius;
point_list wgs84_nodes; // vertex list std::vector<SGVec3d> wgs84_nodes; // vertex list
point_list colors; // color list std::vector<SGVec4f> colors; // color list
point_list normals; // normal list std::vector<SGVec3f> normals; // normal list
point_list texcoords; // texture coordinate list std::vector<SGVec2f> texcoords; // texture coordinate list
group_list pts_v; // points vertex index group_list pts_v; // points vertex index
group_list pts_n; // points normal index group_list pts_n; // points normal index
@@ -125,23 +125,51 @@ public:
inline unsigned short get_version() const { return version; } inline unsigned short get_version() const { return version; }
inline const Point3D& get_gbs_center() const { return gbs_center; } inline Point3D get_gbs_center() const { return Point3D::fromSGVec3(gbs_center); }
inline void set_gbs_center( const Point3D& p ) { gbs_center = p; } inline void set_gbs_center( const Point3D& p ) { gbs_center = p.toSGVec3d(); }
inline const SGVec3d& get_gbs_center2() const { return gbs_center; }
inline void set_gbs_center( const SGVec3d& p ) { gbs_center = p; }
inline float get_gbs_radius() const { return gbs_radius; } inline float get_gbs_radius() const { return gbs_radius; }
inline void set_gbs_radius( float r ) { gbs_radius = r; } inline void set_gbs_radius( float r ) { gbs_radius = r; }
inline const point_list& get_wgs84_nodes() const { return wgs84_nodes; } inline const std::vector<SGVec3d>& get_wgs84_nodes() const
inline void set_wgs84_nodes( const point_list& n ) { wgs84_nodes = n; } { return wgs84_nodes; }
inline void set_wgs84_nodes( const std::vector<SGVec3d>& n )
{ wgs84_nodes = n; }
inline void set_wgs84_nodes( const point_list& n )
{
wgs84_nodes.resize(n.size());
for (unsigned i = 0; i < wgs84_nodes.size(); ++i)
wgs84_nodes[i] = n[i].toSGVec3d();
}
inline const point_list& get_colors() const { return colors; } inline const std::vector<SGVec4f>& get_colors() const { return colors; }
inline void set_colors( const point_list& c ) { colors = c; } inline void set_colors( const std::vector<SGVec4f>& c ) { colors = c; }
inline void set_colors( const point_list& c )
{
colors.resize(c.size());
for (unsigned i = 0; i < colors.size(); ++i)
colors[i] = SGVec4f(c[i].toSGVec3f(), 1);
}
inline const point_list& get_normals() const { return normals; } inline const std::vector<SGVec3f>& get_normals() const { return normals; }
inline void set_normals( const point_list& n ) { normals = n; } inline void set_normals( const std::vector<SGVec3f>& n ) { normals = n; }
inline void set_normals( const point_list& n )
{
normals.resize(n.size());
for (unsigned i = 0; i < normals.size(); ++i)
normals[i] = n[i].toSGVec3f();
}
inline const point_list& get_texcoords() const { return texcoords; } inline const std::vector<SGVec2f>& get_texcoords() const { return texcoords; }
inline void set_texcoords( const point_list& t ) { texcoords = t; } inline void set_texcoords( const std::vector<SGVec2f>& t ) { texcoords = t; }
inline void set_texcoords( const point_list& t )
{
texcoords.resize(t.size());
for (unsigned i = 0; i < texcoords.size(); ++i)
texcoords[i] = t[i].toSGVec2f();
}
inline const group_list& get_pts_v() const { return pts_v; } inline const group_list& get_pts_v() const { return pts_v; }
inline void set_pts_v( const group_list& g ) { pts_v = g; } inline void set_pts_v( const group_list& g ) { pts_v = g; }
+4
View File
@@ -1,3 +1,7 @@
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <unistd.h> #include <unistd.h>
+73 -61
View File
@@ -23,6 +23,19 @@
// //
// Put in some bullet-proofing to handle magnetic and geographic poles. // Put in some bullet-proofing to handle magnetic and geographic poles.
// 3/28/2000 EAW // 3/28/2000 EAW
//
// Updated coefficient arrays to use the current WMM2005 model,
// (valid between 2005.0 and 2010.0)
// Also removed unused variables and corrected earth radii constants
// to the values for WGS84 and WMM2005.
// Reference:
// McLean, S., S. Macmillan, S. Maus, V. Lesur, A.
// Thomson, and D. Dater, December 2004, The
// US/UK World Magnetic Model for 2005-2010,
// NOAA Technical Report NESDIS/NGDC-1.
//
// 25/10/2006 Wim Van Hoydonck -- wim.van.hoydonck@gmail.com
//
// The routine uses a spherical harmonic expansion of the magnetic // The routine uses a spherical harmonic expansion of the magnetic
// potential up to twelfth order, together with its time variation, as // potential up to twelfth order, together with its time variation, as
@@ -75,74 +88,72 @@
static const double pi = 3.14159265358979; static const double pi = 3.14159265358979;
static const double a = 6378.16; /* major radius (km) IAU66 ellipsoid */ static const double a = 6378.137; /* semi-major axis (equatorial radius) of WGS84 ellipsoid */
static const double f = 1.0 / 298.25; /* inverse flattening IAU66 ellipsoid */ static const double b = 6356.7523142; /* semi-minor axis referenced to the WGS84 ellipsoid */
static const double b = 6378.16 * (1.0 -1.0 / 298.25 ); static const double r_0 = 6371.2; /* standard Earth magnetic reference radius */
/* minor radius b=a*(1-f) */
static const double r_0 = 6371.2; /* "mean radius" for spherical harmonic expansion */
static double gnm_wmm2000[13][13] = static double gnm_wmm2005[13][13] =
{ {
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-29616.0, -1722.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {-29556.8, -1671.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-2266.7, 3070.2, 1677.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {-2340.6, 3046.9, 1657.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{1322.4, -2291.5, 1255.9, 724.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {1335.4, -2305.1, 1246.7, 674.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{932.1, 786.3, 250.6, -401.5, 106.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {919.8, 798.1, 211.3, -379.4, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-211.9, 351.6, 220.8, -134.5, -168.8, -13.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {-227.4, 354.6, 208.7, -136.5, -168.3, -14.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{73.8, 68.2, 74.1, -163.5, -3.8, 17.1, -85.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {73.2, 69.7, 76.7, -151.2, -14.9, 14.6, -86.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{77.4, -73.9, 2.2, 35.7, 7.3, 5.2, 8.4, -1.5, 0.0, 0.0, 0.0, 0.0, 0.0}, {80.1, -74.5, -1.4, 38.5, 12.4, 9.5, 5.7, 1.8, 0.0, 0.0, 0.0, 0.0, 0.0},
{23.3, 7.3, -8.5, -6.6, -16.9, 8.6, 4.9, -7.8, -7.6, 0.0, 0.0, 0.0, 0.0}, {24.9, 7.7, -11.6, -6.9, -18.2, 10.0, 9.2, -11.6, -5.2, 0.0, 0.0, 0.0, 0.0},
{5.7, 8.5, 2.0, -9.8, 7.6, -7.0, -2.0, 9.2, -2.2, -6.6, 0.0, 0.0, 0.0}, {5.6, 9.9, 3.5, -7.0, 5.1, -10.8, -1.3, 8.8, -6.7, -9.1, 0.0, 0.0, 0.0},
{-2.2, -5.7, 1.6, -3.7, -0.6, 4.1, 2.2, 2.2, 4.6, 2.3, 0.1, 0.0, 0.0}, {-2.3, -6.3, 1.6, -2.6, 0.0, 3.1, 0.4, 2.1, 3.9, -0.1, -2.3, 0.0, 0.0},
{3.3, -1.1, -2.4, 2.6, -1.3, -1.7, -0.6, 0.4, 0.7, -0.3, 2.3, 4.2, 0.0}, {2.8, -1.6, -1.7, 1.7, -0.1, 0.1, -0.7, 0.7, 1.8, 0.0, 1.1, 4.1, 0.0},
{-1.5, -0.2, -0.3, 0.5, 0.2, 0.9, -1.4, 0.6, -0.6, -1.0, -0.3, 0.3, 0.4}, {-2.4, -0.4, 0.2, 0.8, -0.3, 1.1, -0.5, 0.4, -0.3, -0.3, -0.1, -0.3, -0.1},
}; };
static double hnm_wmm2000[13][13]= static double hnm_wmm2005[13][13]=
{ {
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 5194.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 5079.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -2484.8, -467.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, -2594.7, -516.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -224.7, 293.0, -486.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, -199.9, 269.3, -524.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 273.3, -227.9, 120.9, -302.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 281.5, -226.0, 145.8, -304.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 42.0, 173.8, -135.0, -38.6, 105.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 42.4, 179.8, -123.0, -19.5, 103.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -17.4, 61.2, 63.2, -62.9, 0.2, 43.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, -20.3, 54.7, 63.6, -63.4, -0.1, 50.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -62.3, -24.5, 8.9, 23.4, 15.0, -27.6, -7.8, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, -61.5, -22.4, 7.2, 25.4, 11.0, -26.4, -5.1, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 12.4, -20.8, 8.4, -21.2, 15.5, 9.1, -15.5, -5.4, 0.0, 0.0, 0.0, 0.0}, {0.0, 11.2, -21.0, 9.6, -19.8, 16.1, 7.7, -12.9, -0.2, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.4, 13.9, 12.0, -6.2, -8.6, 9.4, 5.0, -8.4, 3.2, 0.0, 0.0, 0.0}, {0.0, -20.1, 12.9, 12.6, -6.7, -8.1, 8.0, 2.9, -7.9, 6.0, 0.0, 0.0, 0.0},
{0.0, 0.9, -0.7, 3.9, 4.8, -5.3, -1.0, -2.4, 1.3, -2.3, -6.4, 0.0, 0.0}, {0.0, 2.4, 0.2, 4.4, 4.8, -6.5, -1.1, -3.4, -0.8, -2.3, -7.9, 0.0, 0.0},
{0.0, -1.5, 0.7, -1.1, -2.3, 1.3, -0.6, -2.8, -1.6, -0.1, -1.9, 1.4, 0.0}, {0.0, 0.3, 1.2, -0.8, -2.5, 0.9, -0.6, -2.7, -0.9, -1.3, -2.0, -1.2, 0.0},
{0.0, -1.0, 0.7, 2.2, -2.5, -0.2, 0.0, -0.2, 0.0, 0.2, -0.9, -0.2, 1.0}, {0.0, -0.4, 0.3, 2.4, -2.6, 0.6, 0.3, 0.0, 0.0, 0.3, -0.9, -0.4, 0.8},
}; };
static double gtnm_wmm2000[13][13]= static double gtnm_wmm2005[13][13]=
{ {
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{14.7, 11.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {8.0, 10.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-13.6, -0.7, -1.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {-15.1, -7.8, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.3, -4.3, 0.9, -8.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.4, -2.6, -1.2, -6.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-1.6, 0.9, -7.6, 2.2, -3.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {-2.5, 2.8, -7.0, 6.2, -3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.9, -0.2, -2.5, -2.7, -0.9, 1.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {-2.8, 0.7, -3.2, -1.1, 0.1, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{1.2, 0.2, 1.7, 1.6, -0.1, -0.3, 0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {-0.7, 0.4, -0.3, 2.3, -2.1, -0.6, 1.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.4, -0.8, -0.2, 1.1, 0.4, 0.0, -0.2, -0.2, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.2, -0.1, -0.3, 1.1, 0.6, 0.5, -0.4, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.3, 0.6, -0.8, 0.3, -0.2, 0.5, 0.0, -0.6, 0.1, 0.0, 0.0, 0.0, 0.0}, {0.1, 0.3, -0.4, 0.3, -0.3, 0.2, 0.4, -0.7, 0.4, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
}; };
static double htnm_wmm2000[13][13]= static double htnm_wmm2005[13][13]=
{ {
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, -20.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -21.5, -9.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, -23.2, -14.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 6.4, -1.3, -13.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 5.0, -7.0, -0.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 2.3, 0.7, 3.7, -0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 2.2, 1.6, 5.8, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 2.1, 2.3, 3.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 1.7, 2.1, 4.8, -1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.3, -1.7, -0.9, -1.0, -0.1, 1.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, -0.6, -1.9, -0.4, -0.5, -0.3, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 1.4, 0.2, 0.7, 0.4, -0.3, -0.8, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.6, 0.4, 0.2, 0.3, -0.8, -0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.5, 0.1, -0.2, 0.0, 0.1, -0.1, 0.3, 0.2, 0.0, 0.0, 0.0, 0.0}, {0.0, -0.2, 0.1, 0.3, 0.4, 0.1, -0.2, 0.4, 0.4, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
@@ -186,8 +197,8 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
{ {
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */ /* output field B_r,B_th,B_phi,B_x,B_y,B_z */
int n,m; int n,m;
/* reference dates */ /* reference date for current model is 1 januari 2005 */
long date0_wmm2000 = yymmdd_to_julian_days(0,1,1); long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
double yearfrac,sr,r,theta,c,s,psi,fn,fn_0,B_r,B_theta,B_phi,X,Y,Z; double yearfrac,sr,r,theta,c,s,psi,fn,fn_0,B_r,B_theta,B_phi,X,Y,Z;
double sinpsi, cospsi, inv_s; double sinpsi, cospsi, inv_s;
@@ -272,13 +283,14 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
} }
} }
/* compute gnm, hnm at dat */ /* compute Gauss coefficients gnm and hnm of degree n and order m for the desired time
/* WMM2000 */ achieved by adjusting the coefficients at time t0 for linear secular variation */
yearfrac = (dat - date0_wmm2000) / 365.25; /* WMM2005 */
yearfrac = (dat - date0_wmm2005) / 365.25;
for ( n = 1; n <= nmax; n++ ) { for ( n = 1; n <= nmax; n++ ) {
for ( m = 0; m <= nmax; m++ ) { for ( m = 0; m <= nmax; m++ ) {
gnm[n][m] = gnm_wmm2000[n][m] + yearfrac * gtnm_wmm2000[n][m]; gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
hnm[n][m] = hnm_wmm2000[n][m] + yearfrac * htnm_wmm2000[n][m]; hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
} }
} }
@@ -340,7 +352,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */ /* output field B_r,B_th,B_phi,B_x,B_y,B_z */
int n,m; int n,m;
/* reference dates */ /* reference dates */
long date0_wmm2000 = yymmdd_to_julian_days(0,1,1); long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
double yearfrac,sr,r,theta,c,s,psi,fn,B_r,B_theta,B_phi,X,Y,Z; double yearfrac,sr,r,theta,c,s,psi,fn,B_r,B_theta,B_phi,X,Y,Z;
@@ -397,12 +409,12 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
} }
/* compute gnm, hnm at dat */ /* compute gnm, hnm at dat */
/* WMM2000 */ /* WMM2005 */
yearfrac = (dat - date0_wmm2000) / 365.25; yearfrac = (dat - date0_wmm2005) / 365.25;
for ( n = 1; n <= nmax; n++ ) { for ( n = 1; n <= nmax; n++ ) {
for ( m = 0; m <= nmax; m++ ) { for ( m = 0; m <= nmax; m++ ) {
gnm[n][m] = gnm_wmm2000[n][m] + yearfrac * gtnm_wmm2000[n][m]; gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
hnm[n][m] = hnm_wmm2000[n][m] + yearfrac * htnm_wmm2000[n][m]; hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
} }
} }
+17 -9
View File
@@ -1,12 +1,13 @@
includedir = @includedir@/math includedir = @includedir@/math
noinst_PROGRAMS = SGMathTest check_PROGRAMS = SGMathTest SGGeometryTest
check_PROGRAMS = SGMathTest
TESTS = $(check_PROGRAMS) TESTS = $(check_PROGRAMS)
SGMathTest_SOURCES = SGMathTest.cxx SGMathTest_SOURCES = SGMathTest.cxx
SGMathTest_LDADD = libsgmath.a $(base_LIBS) SGMathTest_LDADD = libsgmath.a $(base_LIBS)
SGGeometryTest_SOURCES = SGGeometryTest.cxx
SGGeometryTest_LDADD = libsgmath.a $(base_LIBS)
lib_LIBRARIES = libsgmath.a lib_LIBRARIES = libsgmath.a
@@ -20,20 +21,28 @@ include_HEADERS = \
sg_random.h \ sg_random.h \
sg_types.hxx \ sg_types.hxx \
vector.hxx \ vector.hxx \
fastmath.hxx \ SGBox.hxx \
SGCMath.hxx \
SGGeoc.hxx \ SGGeoc.hxx \
SGGeod.hxx \ SGGeod.hxx \
SGGeodesy.hxx \ SGGeodesy.hxx \
SGGeometry.hxx \
SGGeometryFwd.hxx \
SGIntersect.hxx \
SGLimits.hxx \ SGLimits.hxx \
SGLineSegment.hxx \
SGMatrix.hxx \ SGMatrix.hxx \
SGMath.hxx \ SGMath.hxx \
SGMathFwd.hxx \
SGMisc.hxx \ SGMisc.hxx \
SGPlane.hxx \
SGQuat.hxx \ SGQuat.hxx \
SGVec4.hxx \ SGRay.hxx \
SGVec3.hxx SGSphere.hxx \
SGTriangle.hxx \
SGVec2.hxx \
EXTRA_DIST = linintp2.h linintp2.inl sphrintp.h sphrintp.inl SGVec3.hxx \
SGVec4.hxx
libsgmath_a_SOURCES = \ libsgmath_a_SOURCES = \
interpolater.cxx \ interpolater.cxx \
@@ -42,7 +51,6 @@ libsgmath_a_SOURCES = \
sg_geodesy.cxx \ sg_geodesy.cxx \
sg_random.c \ sg_random.c \
vector.cxx \ vector.cxx \
fastmath.cxx \
SGGeodesy.cxx SGGeodesy.cxx
INCLUDES = -I$(top_srcdir) INCLUDES = -I$(top_srcdir)
+107
View File
@@ -0,0 +1,107 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGBox_H
#define SGBox_H
template<typename T>
class SGBox {
public:
SGBox() :
_min(SGLimits<T>::max(), SGLimits<T>::max(), SGLimits<T>::max()),
_max(-SGLimits<T>::max(), -SGLimits<T>::max(), -SGLimits<T>::max())
{ }
void setMin(const SGVec3<T>& min)
{ _min = min; }
const SGVec3<T>& getMin() const
{ return _min; }
void setMax(const SGVec3<T>& max)
{ _max = max; }
const SGVec3<T>& getMax() const
{ return _max; }
// Only works for floating point types
SGVec3<T> getCenter() const
{ return T(0.5)*(_min + _max); }
// Only valid for nonempty boxes
SGVec3<T> getSize() const
{ return _max - _min; }
T getVolume() const
{
if (empty())
return 0;
return (_max[0] - _min[0])*(_max[1] - _min[1])*(_max[2] - _min[2]);
}
const bool empty() const
{ return !valid(); }
bool valid() const
{
if (_max[0] < _min[0])
return false;
if (_max[1] < _min[1])
return false;
if (_max[2] < _min[2])
return false;
return true;
}
void clear()
{
_min[0] = SGLimits<T>::max();
_min[1] = SGLimits<T>::max();
_min[2] = SGLimits<T>::max();
_max[0] = -SGLimits<T>::max();
_max[1] = -SGLimits<T>::max();
_max[2] = -SGLimits<T>::max();
}
void expandBy(const SGVec3<T>& v)
{ _min = min(_min, v); _max = max(_max, v); }
void expandBy(const SGBox<T>& b)
{ _min = min(_min, b._min); _max = max(_max, b._max); }
// Note that this only works if the box is nonmepty
unsigned getBroadestAxis() const
{
SGVec3d size = getSize();
if (size[1] <= size[0] && size[2] <= size[0])
return 0;
else if (size[2] <= size[1])
return 1;
else
return 2;
}
private:
SGVec3<T> _min;
SGVec3<T> _max;
};
/// Output to an ostream
template<typename char_type, typename traits_type, typename T>
inline
std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGBox<T>& box)
{ return s << "min = " << box.getMin() << ", max = " << box.getMax(); }
#endif
+31
View File
@@ -0,0 +1,31 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGCMath_H
#define SGCMath_H
#include <simgear/compiler.h>
#ifdef SG_HAVE_STD_INCLUDES
// We have cmath from the standard c++ lib available
#include <cmath>
#else
// We only have math.h with the c89 double functions.
#include <math.h>
#endif
#endif
+27 -20
View File
@@ -27,12 +27,6 @@ class SGGeoc {
public: public:
/// Default constructor, initializes the instance to lat = lon = lat = 0 /// Default constructor, initializes the instance to lat = lon = lat = 0
SGGeoc(void); SGGeoc(void);
/// Initialize from a cartesian vector assumed to be in meters
/// Note that this conversion is relatively expensive to compute
SGGeoc(const SGVec3<double>& cart);
/// Initialize from a geodetic position
/// Note that this conversion is relatively expensive to compute
SGGeoc(const SGGeod& geod);
/// Factory from angular values in radians and radius in ft /// Factory from angular values in radians and radius in ft
static SGGeoc fromRadFt(double lon, double lat, double radius); static SGGeoc fromRadFt(double lon, double lat, double radius);
@@ -42,6 +36,13 @@ public:
static SGGeoc fromRadM(double lon, double lat, double radius); static SGGeoc fromRadM(double lon, double lat, double radius);
/// Factory from angular values in degrees and radius in m /// Factory from angular values in degrees and radius in m
static SGGeoc fromDegM(double lon, double lat, double radius); static SGGeoc fromDegM(double lon, double lat, double radius);
/// Factory to convert position from a cartesian position assumed to be
/// in wgs84 measured in meters
/// Note that this conversion is relatively expensive to compute
static SGGeoc fromCart(const SGVec3<double>& cart);
/// Factory to convert position from a geodetic position
/// Note that this conversion is relatively expensive to compute
static SGGeoc fromGeod(const SGGeod& geod);
/// Return the geocentric longitude in radians /// Return the geocentric longitude in radians
double getLongitudeRad(void) const; double getLongitudeRad(void) const;
@@ -103,20 +104,6 @@ SGGeoc::SGGeoc(double lon, double lat, double radius) :
{ {
} }
inline
SGGeoc::SGGeoc(const SGVec3<double>& cart)
{
SGGeodesy::SGCartToGeoc(cart, *this);
}
inline
SGGeoc::SGGeoc(const SGGeod& geod)
{
SGVec3<double> cart;
SGGeodesy::SGGeodToCart(geod, cart);
SGGeodesy::SGCartToGeoc(cart, *this);
}
inline inline
SGGeoc SGGeoc
SGGeoc::fromRadFt(double lon, double lat, double radius) SGGeoc::fromRadFt(double lon, double lat, double radius)
@@ -165,6 +152,26 @@ SGGeoc::fromDegM(double lon, double lat, double radius)
#endif #endif
} }
inline
SGGeoc
SGGeoc::fromCart(const SGVec3<double>& cart)
{
SGGeoc geoc;
SGGeodesy::SGCartToGeoc(cart, geoc);
return geoc;
}
inline
SGGeoc
SGGeoc::fromGeod(const SGGeod& geod)
{
SGVec3<double> cart;
SGGeodesy::SGGeodToCart(geod, cart);
SGGeoc geoc;
SGGeodesy::SGCartToGeoc(cart, geoc);
return geoc;
}
inline inline
double double
SGGeoc::getLongitudeRad(void) const SGGeoc::getLongitudeRad(void) const
+27 -20
View File
@@ -27,12 +27,6 @@ class SGGeod {
public: public:
/// Default constructor, initializes the instance to lat = lon = elev = 0 /// Default constructor, initializes the instance to lat = lon = elev = 0
SGGeod(void); SGGeod(void);
/// Initialize from a cartesian vector assumed to be in meters
/// Note that this conversion is relatively expensive to compute
SGGeod(const SGVec3<double>& cart);
/// Initialize from a geocentric position
/// Note that this conversion is relatively expensive to compute
SGGeod(const SGGeoc& geoc);
/// Factory from angular values in radians and elevation is 0 /// Factory from angular values in radians and elevation is 0
static SGGeod fromRad(double lon, double lat); static SGGeod fromRad(double lon, double lat);
@@ -46,6 +40,13 @@ public:
static SGGeod fromRadM(double lon, double lat, double elevation); static SGGeod fromRadM(double lon, double lat, double elevation);
/// Factory from angular values in degrees and elevation in m /// Factory from angular values in degrees and elevation in m
static SGGeod fromDegM(double lon, double lat, double elevation); static SGGeod fromDegM(double lon, double lat, double elevation);
/// Factory to convert position from a cartesian position assumed to be
/// in wgs84 measured in meters
/// Note that this conversion is relatively expensive to compute
static SGGeod fromCart(const SGVec3<double>& cart);
/// Factory to convert position from a geocentric position
/// Note that this conversion is relatively expensive to compute
static SGGeod fromGeoc(const SGGeoc& geoc);
/// Return the geodetic longitude in radians /// Return the geodetic longitude in radians
double getLongitudeRad(void) const; double getLongitudeRad(void) const;
@@ -107,20 +108,6 @@ SGGeod::SGGeod(double lon, double lat, double elevation) :
{ {
} }
inline
SGGeod::SGGeod(const SGVec3<double>& cart)
{
SGGeodesy::SGCartToGeod(cart, *this);
}
inline
SGGeod::SGGeod(const SGGeoc& geoc)
{
SGVec3<double> cart;
SGGeodesy::SGGeocToCart(geoc, cart);
SGGeodesy::SGCartToGeod(cart, *this);
}
inline inline
SGGeod SGGeod
SGGeod::fromRad(double lon, double lat) SGGeod::fromRad(double lon, double lat)
@@ -191,6 +178,26 @@ SGGeod::fromDegM(double lon, double lat, double elevation)
#endif #endif
} }
inline
SGGeod
SGGeod::fromCart(const SGVec3<double>& cart)
{
SGGeod geod;
SGGeodesy::SGCartToGeod(cart, geod);
return geod;
}
inline
SGGeod
SGGeod::fromGeoc(const SGGeoc& geoc)
{
SGVec3<double> cart;
SGGeodesy::SGGeocToCart(geoc, cart);
SGGeod geod;
SGGeodesy::SGCartToGeod(cart, geod);
return geod;
}
inline inline
double double
SGGeod::getLongitudeRad(void) const SGGeod::getLongitudeRad(void) const
-6
View File
@@ -18,12 +18,6 @@
#ifndef SGGeodesy_H #ifndef SGGeodesy_H
#define SGGeodesy_H #define SGGeodesy_H
class SGGeoc;
class SGGeod;
template<typename T>
class SGVec3;
class SGGeodesy { class SGGeodesy {
public: public:
// Hard numbers from the WGS84 standard. // Hard numbers from the WGS84 standard.
+38
View File
@@ -0,0 +1,38 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGGeometry_HXX
#define SGGeometry_HXX
// Required ...
#include "SGMath.hxx"
// Make sure all is defined
#include "SGGeometryFwd.hxx"
// Geometric primitives we know about
#include "SGBox.hxx"
#include "SGSphere.hxx"
#include "SGRay.hxx"
#include "SGLineSegment.hxx"
#include "SGPlane.hxx"
#include "SGTriangle.hxx"
// Intersection tests
#include "SGIntersect.hxx"
#endif
+51
View File
@@ -0,0 +1,51 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGGeometryFwd_HXX
#define SGGeometryFwd_HXX
template<typename T>
class SGBox;
typedef SGBox<float> SGBoxf;
typedef SGBox<double> SGBoxd;
template<typename T>
class SGSphere;
typedef SGSphere<float> SGSpheref;
typedef SGSphere<double> SGSphered;
template<typename T>
class SGRay;
typedef SGRay<float> SGRayf;
typedef SGRay<double> SGRayd;
template<typename T>
class SGLineSegment;
typedef SGLineSegment<float> SGLineSegmentf;
typedef SGLineSegment<double> SGLineSegmentd;
template<typename T>
class SGPlane;
typedef SGPlane<float> SGPlanef;
typedef SGPlane<double> SGPlaned;
template<typename T>
class SGTriangle;
typedef SGTriangle<float> SGTrianglef;
typedef SGTriangle<double> SGTriangled;
#endif
+442
View File
@@ -0,0 +1,442 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <cstdlib>
#include <iostream>
#include "SGGeometry.hxx"
#include "sg_random.h"
template<typename T>
SGVec3<T> rndVec3(void)
{
return SGVec3<T>(sg_random(), sg_random(), sg_random());
}
template<typename T>
bool
TriangleLineIntersectionTest(void)
{
unsigned nTests = 100000;
unsigned failedCount = 0;
for (unsigned i = 0; i < nTests; ++i) {
SGVec3<T> v0 = rndVec3<T>();
SGVec3<T> v1 = rndVec3<T>();
SGVec3<T> v2 = rndVec3<T>();
SGTriangle<T> tri(v0, v1, v2);
// generate random coeficients
T u = 4*sg_random() - 2;
T v = 4*sg_random() - 2;
T t = 4*sg_random() - 2;
SGVec3<T> isectpt = v0 + u*(v1 - v0) + v*(v2 - v0);
SGLineSegment<T> lineSegment;
SGVec3<T> dir = rndVec3<T>();
SGVec3<T> isectres;
lineSegment.set(isectpt - t*dir, isectpt + (1 - t)*dir);
if (intersects(isectres, tri, lineSegment)) {
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t && t <= 1) {
if (!equivalent(isectres, isectpt)) {
std::cout << "Failed line segment intersection test #" << i
<< ": not equivalent!\nu = "
<< u << ", v = " << v << ", t = " << t
<< "\n" << tri << "\n" << lineSegment << std::endl;
++failedCount;
}
} else {
std::cout << "Failed line segment intersection test #" << i
<< ": false positive!\nu = "
<< u << ", v = " << v << ", t = " << t
<< "\n" << tri << "\n" << lineSegment << std::endl;
++failedCount;
}
} else {
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t && t <= 1) {
std::cout << "Failed line segment intersection test #" << i
<< ": false negative!\nu = "
<< u << ", v = " << v << ", t = " << t
<< "\n" << tri << "\n" << lineSegment << std::endl;
++failedCount;
}
}
SGRay<T> ray;
ray.set(isectpt - t*dir, dir);
if (intersects(isectres, tri, ray)) {
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t) {
if (!equivalent(isectres, isectpt)) {
std::cout << "Failed ray intersection test #" << i
<< ": not equivalent!\nu = "
<< u << ", v = " << v << ", t = " << t
<< "\n" << tri << "\n" << ray << std::endl;
++failedCount;
}
} else {
std::cout << "Failed ray intersection test #" << i
<< ": false positive!\nu = "
<< u << ", v = " << v << ", t = " << t
<< "\n" << tri << "\n" << ray << std::endl;
++failedCount;
}
} else {
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t) {
std::cout << "Failed ray intersection test #" << i
<< ": false negative !\nu = "
<< u << ", v = " << v << ", t = " << t
<< "\n" << tri << "\n" << ray << std::endl;
++failedCount;
}
}
}
if (nTests < 100*failedCount) {
std::cout << "Failed ray intersection tests: " << failedCount
<< " tests out of " << nTests
<< " went wrong. Abort!" << std::endl;
return false;
}
/// Some crude handmade test
SGVec3<T> v0 = SGVec3<T>(0, 0, 0);
SGVec3<T> v1 = SGVec3<T>(1, 0, 0);
SGVec3<T> v2 = SGVec3<T>(0, 1, 0);
SGTriangle<T> tri(v0, v1, v2);
SGRay<T> ray;
ray.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0.1, 0.1, -1));
if (!intersects(tri, ray)) {
std::cout << "Failed test #1!" << std::endl;
return false;
}
ray.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 0, -1));
if (!intersects(tri, ray)) {
std::cout << "Failed test #2!" << std::endl;
return false;
}
SGLineSegment<T> lineSegment;
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0.1, 0.1, -1));
if (!intersects(tri, lineSegment)) {
std::cout << "Failed test #3!" << std::endl;
return false;
}
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 0, -1));
if (!intersects(tri, lineSegment)) {
std::cout << "Failed test #4!" << std::endl;
return false;
}
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 1, -1));
if (!intersects(tri, lineSegment)) {
std::cout << "Failed test #5!" << std::endl;
return false;
}
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 0, -1));
if (!intersects(tri, lineSegment)) {
std::cout << "Failed test #6!" << std::endl;
return false;
}
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 1, -1));
if (!intersects(tri, lineSegment)) {
std::cout << "Failed test #7!" << std::endl;
return false;
}
// is exactly in the plane
// FIXME: cannot detect that yet ??
// lineSegment.set(SGVec3<T>(0, 0, 0), SGVec3<T>(1, 0, 0));
// if (!intersects(tri, lineSegment)) {
// std::cout << "Failed test #8!" << std::endl;
// return false;
// }
// is exactly in the plane
// FIXME: cannot detect that yet ??
// lineSegment.set(SGVec3<T>(-1, 0, 0), SGVec3<T>(1, 0, 0));
// if (!intersects(tri, lineSegment)) {
// std::cout << "Failed test #9!" << std::endl;
// return false;
// }
// is exactly paralell to the plane
// FIXME: cannot detect that yet ??
// lineSegment.set(SGVec3<T>(-1, 1, 0), SGVec3<T>(1, 1, 0));
// if (intersects(tri, lineSegment)) {
// std::cout << "Failed test #10!" << std::endl;
// return false;
// }
// should fail since the line segment poins slightly beyond the triangle
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 1, -0.9));
if (intersects(tri, lineSegment)) {
std::cout << "Failed test #11!" << std::endl;
return false;
}
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, -0.1, -1));
if (intersects(tri, lineSegment)) {
std::cout << "Failed test #12!" << std::endl;
return false;
}
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(-0.1, -0.1, -1));
if (intersects(tri, lineSegment)) {
std::cout << "Failed test #13!" << std::endl;
return false;
}
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(-0.1, 0, -1));
if (intersects(tri, lineSegment)) {
std::cout << "Failed test #14!" << std::endl;
return false;
}
return true;
}
template<typename T>
bool
SphereLineIntersectionTest(void)
{
unsigned nTests = 100000;
unsigned failedCount = 0;
for (unsigned i = 0; i < nTests; ++i) {
SGVec3<T> center = rndVec3<T>();
T radius = 2*sg_random();
SGSphere<T> sphere(center, radius);
SGVec3<T> offset = normalize(rndVec3<T>());
T t = 4*sg_random();
// This one is the point we use to judge if the test should fail or not
SGVec3<T> base = center + t*offset;
SGVec3<T> per = perpendicular(offset);
SGVec3<T> start = base + 4*sg_random()*per;
SGVec3<T> end = base - 4*sg_random()*per;
SGLineSegment<T> lineSegment;
lineSegment.set(start, end);
if (intersects(sphere, lineSegment)) {
if (radius < t) {
std::cout << "Failed sphere line intersection test #" << i
<< ": false positive!\nt = " << t << "\n"
<< sphere << "\n" << lineSegment << std::endl;
++failedCount;
}
} else {
if (t <= radius) {
std::cout << "Failed sphere line intersection test #" << i
<< ": false negative!\nt = " << t << "\n"
<< sphere << "\n" << lineSegment << std::endl;
++failedCount;
}
}
SGRay<T> ray;
ray.set(start, end - start);
if (intersects(sphere, ray)) {
if (radius < t) {
std::cout << "Failed sphere line intersection test #" << i
<< ": false positive!\nt = " << t << "\n"
<< sphere << "\n" << ray << std::endl;
++failedCount;
}
} else {
if (t <= radius) {
std::cout << "Failed sphere line intersection test #" << i
<< ": false negative!\nt = " << t << "\n"
<< sphere << "\n" << ray << std::endl;
++failedCount;
}
}
}
if (nTests < 100*failedCount) {
std::cout << "Failed sphere line intersection tests: " << failedCount
<< " tests out of " << nTests
<< " went wrong. Abort!" << std::endl;
return false;
}
failedCount = 0;
for (unsigned i = 0; i < nTests; ++i) {
SGVec3<T> center = rndVec3<T>();
T radius = 2*sg_random();
SGSphere<T> sphere(center, radius);
SGVec3<T> offset = normalize(rndVec3<T>());
T t = 4*sg_random();
// This one is the point we use to judge if the test should fail or not
SGVec3<T> base = center + t*offset;
SGVec3<T> start = base;
SGVec3<T> end = base + 2*sg_random()*offset;
SGLineSegment<T> lineSegment;
lineSegment.set(start, end);
if (intersects(sphere, lineSegment)) {
if (radius < t) {
std::cout << "Failed sphere line intersection test #" << i
<< ": false positive!\nt = " << t << "\n"
<< sphere << "\n" << lineSegment << std::endl;
++failedCount;
}
} else {
if (t <= radius) {
std::cout << "Failed sphere line intersection test #" << i
<< ": false negative!\nt = " << t << "\n"
<< sphere << "\n" << lineSegment << std::endl;
++failedCount;
}
}
SGRay<T> ray;
ray.set(start, end - start);
if (intersects(sphere, ray)) {
if (radius < t) {
std::cout << "Failed sphere line intersection test #" << i
<< ": false positive!\nt = " << t << "\n"
<< sphere << "\n" << ray << std::endl;
++failedCount;
}
} else {
if (t <= radius) {
std::cout << "Failed sphere line intersection test #" << i
<< ": false negative!\nt = " << t << "\n"
<< sphere << "\n" << ray << std::endl;
++failedCount;
}
}
}
if (nTests < 100*failedCount) {
std::cout << "Failed sphere line intersection tests: " << failedCount
<< " tests out of " << nTests
<< " went wrong. Abort!" << std::endl;
return false;
}
return true;
}
template<typename T>
bool
BoxLineIntersectionTest(void)
{
// ok, bad test case coverage, but better than nothing ...
unsigned nTests = 100000;
unsigned failedCount = 0;
for (unsigned i = 0; i < nTests; ++i) {
SGBox<T> box;
box.expandBy(rndVec3<T>());
box.expandBy(rndVec3<T>());
SGVec3<T> center = box.getCenter();
// This one is the point we use to judge if the test should fail or not
SGVec3<T> base = rndVec3<T>();
SGVec3<T> dir = base - center;
SGLineSegment<T> lineSegment;
lineSegment.set(base, base + dir);
if (intersects(box, lineSegment)) {
if (!intersects(box, base)) {
std::cout << "Failed box line intersection test #" << i
<< ": false positive!\n"
<< box << "\n" << lineSegment << std::endl;
++failedCount;
}
} else {
if (intersects(box, base)) {
std::cout << "Failed box line intersection test #" << i
<< ": false negative!\n"
<< box << "\n" << lineSegment << std::endl;
++failedCount;
}
}
SGRay<T> ray;
ray.set(base, dir);
if (intersects(box, ray)) {
if (!intersects(box, base)) {
std::cout << "Failed box line intersection test #" << i
<< ": false positive!\n"
<< box << "\n" << ray << std::endl;
++failedCount;
}
} else {
if (intersects(box, base)) {
std::cout << "Failed box line intersection test #" << i
<< ": false negative!\n"
<< box << "\n" << ray << std::endl;
++failedCount;
}
}
}
if (nTests < 100*failedCount) {
std::cout << "Failed box line intersection tests: " << failedCount
<< " tests out of " << nTests
<< " went wrong. Abort!" << std::endl;
return false;
}
return true;
}
int
main(void)
{
std::cout << "Testing Geometry intersection routines.\n"
<< "Some of these tests can fail due to roundoff problems...\n"
<< "Dont worry if only a few of them fail..." << std::endl;
if (!TriangleLineIntersectionTest<float>())
return EXIT_FAILURE;
if (!TriangleLineIntersectionTest<double>())
return EXIT_FAILURE;
if (!SphereLineIntersectionTest<float>())
return EXIT_FAILURE;
if (!SphereLineIntersectionTest<double>())
return EXIT_FAILURE;
if (!BoxLineIntersectionTest<float>())
return EXIT_FAILURE;
if (!BoxLineIntersectionTest<double>())
return EXIT_FAILURE;
std::cout << "Successfully passed all tests!" << std::endl;
return EXIT_SUCCESS;
}
+627
View File
@@ -0,0 +1,627 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGIntersect_HXX
#define SGIntersect_HXX
template<typename T>
inline bool
intersects(const SGBox<T>& box, const SGSphere<T>& sphere)
{
if (sphere.empty())
return false;
// Is more or less trivially included in the next tests
// if (box.empty())
// return false;
if (sphere.getCenter().x() < box.getMin().x() - sphere.getRadius())
return false;
if (sphere.getCenter().y() < box.getMin().y() - sphere.getRadius())
return false;
if (sphere.getCenter().z() < box.getMin().z() - sphere.getRadius())
return false;
if (box.getMax().x() + sphere.getRadius() < sphere.getCenter().x())
return false;
if (box.getMax().y() + sphere.getRadius() < sphere.getCenter().y())
return false;
if (box.getMax().z() + sphere.getRadius() < sphere.getCenter().z())
return false;
return true;
}
// make it symmetric
template<typename T>
inline bool
intersects(const SGSphere<T>& sphere, const SGBox<T>& box)
{ return intersects(box, sphere); }
template<typename T>
inline bool
intersects(const SGVec3<T>& v, const SGBox<T>& box)
{
if (v[0] < box.getMin()[0])
return false;
if (box.getMax()[0] < v[0])
return false;
if (v[1] < box.getMin()[1])
return false;
if (box.getMax()[1] < v[1])
return false;
if (v[2] < box.getMin()[2])
return false;
if (box.getMax()[2] < v[2])
return false;
return true;
}
template<typename T>
inline bool
intersects(const SGBox<T>& box, const SGVec3<T>& v)
{ return intersects(v, box); }
template<typename T>
inline bool
intersects(const SGRay<T>& ray, const SGPlane<T>& plane)
{
// We compute the intersection point
// x = origin + \alpha*direction
// from the ray origin and non nomalized direction.
// For 0 <= \alpha the ray intersects the infinite plane.
// The intersection point x can also be written
// x = n*dist + y
// where n is the planes normal, dist is the distance of the plane from
// the origin in normal direction and y is ana aproriate vector
// perpendicular to n.
// Equate the x values and take the scalar product with the plane normal n.
// dot(n, origin) + \alpha*dot(n, direction) = dist
// We can now compute alpha from the above equation.
// \alpha = (dist - dot(n, origin))/dot(n, direction)
// The negative numerator for the \alpha expression
T num = plane.getPositiveDist();
num -= dot(plane.getNormal(), ray.getOrigin());
// If the numerator is zero, we have the rays origin included in the plane
if (fabs(num) <= SGLimits<T>::min())
return true;
// The denominator for the \alpha expression
T den = dot(plane.getNormal(), ray.getDirection());
// If we get here, we already know that the rays origin is not included
// in the plane. Thus if we have a zero denominator we have
// a ray paralell to the plane. That is no intersection.
if (fabs(den) <= SGLimits<T>::min())
return false;
// We would now compute \alpha = num/den and compare with 0 and 1.
// But to avoid that expensive division, check equation multiplied by
// the denominator.
T alphaDen = copysign(1, den)*num;
if (alphaDen < 0)
return false;
return true;
}
// make it symmetric
template<typename T>
inline bool
intersects(const SGPlane<T>& plane, const SGRay<T>& ray)
{ return intersects(ray, plane); }
template<typename T>
inline bool
intersects(SGVec3<T>& dst, const SGRay<T>& ray, const SGPlane<T>& plane)
{
// We compute the intersection point
// x = origin + \alpha*direction
// from the ray origin and non nomalized direction.
// For 0 <= \alpha the ray intersects the infinite plane.
// The intersection point x can also be written
// x = n*dist + y
// where n is the planes normal, dist is the distance of the plane from
// the origin in normal direction and y is ana aproriate vector
// perpendicular to n.
// Equate the x values and take the scalar product with the plane normal n.
// dot(n, origin) + \alpha*dot(n, direction) = dist
// We can now compute alpha from the above equation.
// \alpha = (dist - dot(n, origin))/dot(n, direction)
// The negative numerator for the \alpha expression
T num = plane.getPositiveDist();
num -= dot(plane.getNormal(), ray.getOrigin());
// If the numerator is zero, we have the rays origin included in the plane
if (fabs(num) <= SGLimits<T>::min()) {
dst = ray.getOrigin();
return true;
}
// The denominator for the \alpha expression
T den = dot(plane.getNormal(), ray.getDirection());
// If we get here, we already know that the rays origin is not included
// in the plane. Thus if we have a zero denominator we have
// a ray paralell to the plane. That is no intersection.
if (fabs(den) <= SGLimits<T>::min())
return false;
// We would now compute \alpha = num/den and compare with 0 and 1.
// But to avoid that expensive division, check equation multiplied by
// the denominator.
T alpha = num/den;
if (alpha < 0)
return false;
dst = ray.getOrigin() + alpha*ray.getDirection();
return true;
}
// make it symmetric
template<typename T>
inline bool
intersects(SGVec3<T>& dst, const SGPlane<T>& plane, const SGRay<T>& ray)
{ return intersects(dst, ray, plane); }
template<typename T>
inline bool
intersects(const SGLineSegment<T>& lineSegment, const SGPlane<T>& plane)
{
// We compute the intersection point
// x = origin + \alpha*direction
// from the line segments origin and non nomalized direction.
// For 0 <= \alpha <= 1 the line segment intersects the infinite plane.
// The intersection point x can also be written
// x = n*dist + y
// where n is the planes normal, dist is the distance of the plane from
// the origin in normal direction and y is ana aproriate vector
// perpendicular to n.
// Equate the x values and take the scalar product with the plane normal n.
// dot(n, origin) + \alpha*dot(n, direction) = dist
// We can now compute alpha from the above equation.
// \alpha = (dist - dot(n, origin))/dot(n, direction)
// The negative numerator for the \alpha expression
T num = plane.getPositiveDist();
num -= dot(plane.getNormal(), lineSegment.getOrigin());
// If the numerator is zero, we have the lines origin included in the plane
if (fabs(num) <= SGLimits<T>::min())
return true;
// The denominator for the \alpha expression
T den = dot(plane.getNormal(), lineSegment.getDirection());
// If we get here, we already know that the lines origin is not included
// in the plane. Thus if we have a zero denominator we have
// a line paralell to the plane. That is no intersection.
if (fabs(den) <= SGLimits<T>::min())
return false;
// We would now compute \alpha = num/den and compare with 0 and 1.
// But to avoid that expensive division, compare equations
// multiplied by |den|. Note that copysign is usually a compiler intrinsic
// that expands in assembler code that not even stalls the cpus pipes.
T alphaDen = copysign(1, den)*num;
if (alphaDen < 0)
return false;
if (den < alphaDen)
return false;
return true;
}
// make it symmetric
template<typename T>
inline bool
intersects(const SGPlane<T>& plane, const SGLineSegment<T>& lineSegment)
{ return intersects(lineSegment, plane); }
template<typename T>
inline bool
intersects(SGVec3<T>& dst, const SGLineSegment<T>& lineSegment, const SGPlane<T>& plane)
{
// We compute the intersection point
// x = origin + \alpha*direction
// from the line segments origin and non nomalized direction.
// For 0 <= \alpha <= 1 the line segment intersects the infinite plane.
// The intersection point x can also be written
// x = n*dist + y
// where n is the planes normal, dist is the distance of the plane from
// the origin in normal direction and y is an aproriate vector
// perpendicular to n.
// Equate the x values and take the scalar product with the plane normal n.
// dot(n, origin) + \alpha*dot(n, direction) = dist
// We can now compute alpha from the above equation.
// \alpha = (dist - dot(n, origin))/dot(n, direction)
// The negative numerator for the \alpha expression
T num = plane.getPositiveDist();
num -= dot(plane.getNormal(), lineSegment.getOrigin());
// If the numerator is zero, we have the lines origin included in the plane
if (fabs(num) <= SGLimits<T>::min()) {
dst = lineSegment.getOrigin();
return true;
}
// The denominator for the \alpha expression
T den = dot(plane.getNormal(), lineSegment.getDirection());
// If we get here, we already know that the lines origin is not included
// in the plane. Thus if we have a zero denominator we have
// a line paralell to the plane. That is: no intersection.
if (fabs(den) <= SGLimits<T>::min())
return false;
// We would now compute \alpha = num/den and compare with 0 and 1.
// But to avoid that expensive division, check equation multiplied by
// the denominator. FIXME: shall we do so? or compute like that?
T alpha = num/den;
if (alpha < 0)
return false;
if (1 < alpha)
return false;
dst = lineSegment.getOrigin() + alpha*lineSegment.getDirection();
return true;
}
// make it symmetric
template<typename T>
inline bool
intersects(SGVec3<T>& dst, const SGPlane<T>& plane, const SGLineSegment<T>& lineSegment)
{ return intersects(dst, lineSegment, plane); }
// Distance of a line segment to a point
template<typename T>
inline T
distSqr(const SGLineSegment<T>& lineSeg, const SGVec3<T>& p)
{
SGVec3<T> ps = p - lineSeg.getStart();
T psdotdir = dot(ps, lineSeg.getDirection());
if (psdotdir <= 0)
return dot(ps, ps);
SGVec3<T> pe = p - lineSeg.getEnd();
if (0 <= dot(pe, lineSeg.getDirection()))
return dot(pe, pe);
return dot(ps, ps) - psdotdir*psdotdir/dot(lineSeg.getDirection(), lineSeg.getDirection());
}
// make it symmetric
template<typename T>
inline T
distSqr(const SGVec3<T>& p, const SGLineSegment<T>& lineSeg)
{ return distSqr(lineSeg, p); }
// with sqrt
template<typename T>
inline T
dist(const SGVec3<T>& p, const SGLineSegment<T>& lineSeg)
{ return sqrt(distSqr(lineSeg, p)); }
template<typename T>
inline T
dist(const SGLineSegment<T>& lineSeg, const SGVec3<T>& p)
{ return sqrt(distSqr(lineSeg, p)); }
template<typename T>
inline bool
intersects(const SGRay<T>& ray, const SGSphere<T>& sphere)
{
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering,
// second edition, page 571
SGVec3<T> l = sphere.getCenter() - ray.getOrigin();
T s = dot(l, ray.getDirection());
T l2 = dot(l, l);
T r2 = sphere.getRadius2();
if (s < 0 && l2 > r2)
return false;
T d2 = dot(ray.getDirection(), ray.getDirection());
// The original test would read
// T m2 = l2 - s*s/d2;
// if (m2 > r2)
// return false;
// but to avoid the expensive division, we multiply by d2
T m2 = d2*l2 - s*s;
if (m2 > d2*r2)
return false;
return true;
}
// make it symmetric
template<typename T>
inline bool
intersects(const SGSphere<T>& sphere, const SGRay<T>& ray)
{ return intersects(ray, sphere); }
template<typename T>
inline bool
intersects(const SGLineSegment<T>& lineSegment, const SGSphere<T>& sphere)
{
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering,
// second edition, page 571
SGVec3<T> l = sphere.getCenter() - lineSegment.getStart();
T ld = length(lineSegment.getDirection());
T s = dot(l, lineSegment.getDirection())/ld;
T l2 = dot(l, l);
T r2 = sphere.getRadius2();
if (s < 0 && l2 > r2)
return false;
T m2 = l2 - s*s;
if (m2 > r2)
return false;
T q = sqrt(r2 - m2);
T t = s - q;
if (ld < t)
return false;
return true;
}
// make it symmetric
template<typename T>
inline bool
intersects(const SGSphere<T>& sphere, const SGLineSegment<T>& lineSegment)
{ return intersects(lineSegment, sphere); }
template<typename T>
inline bool
// FIXME do not use that default argument later. Just for development now
intersects(SGVec3<T>& x, const SGTriangle<T>& tri, const SGRay<T>& ray, T eps = 0)
{
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
// Method based on the observation that we are looking for a
// point x that can be expressed in terms of the triangle points
// x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
// with 0 <= u, v and u + v <= 1.
// OTOH it could be expressed in terms of the ray
// x = o + t*d
// Now we can compute u, v and t.
SGVec3<T> p = cross(ray.getDirection(), tri.getEdge(1));
T denom = dot(p, tri.getEdge(0));
T signDenom = copysign(1, denom);
SGVec3<T> s = ray.getOrigin() - tri.getBaseVertex();
SGVec3<T> q = cross(s, tri.getEdge(0));
// Now t would read
// t = 1/denom*dot(q, tri.getEdge(1));
// To avoid an expensive division we multiply by |denom|
T tDenom = signDenom*dot(q, tri.getEdge(1));
if (tDenom < 0)
return false;
// For line segment we would test against
// if (1 < t)
// return false;
// with the original t. The multiplied test would read
// if (absDenom < tDenom)
// return false;
T absDenom = fabs(denom);
T absDenomEps = absDenom*eps;
// T u = 1/denom*dot(p, s);
T u = signDenom*dot(p, s);
if (u < -absDenomEps)
return false;
// T v = 1/denom*dot(q, d);
// if (v < -eps)
// return false;
T v = signDenom*dot(q, ray.getDirection());
if (v < -absDenomEps)
return false;
if (u + v > absDenom + absDenomEps)
return false;
// return if paralell ??? FIXME what if paralell and in plane?
// may be we are ok below than anyway??
if (absDenom <= SGLimits<T>::min())
return false;
x = ray.getOrigin();
// if we have survived here it could only happen with denom == 0
// that the point is already in plane. Then return the origin ...
if (SGLimitsd::min() < absDenom)
x += (tDenom/absDenom)*ray.getDirection();
return true;
}
template<typename T>
inline bool
intersects(const SGTriangle<T>& tri, const SGRay<T>& ray, T eps = 0)
{
// FIXME: for now just wrap the other method. When that has prooven
// well optimized, implement that special case
SGVec3<T> dummy;
return intersects(dummy, tri, ray, eps);
}
template<typename T>
inline bool
// FIXME do not use that default argument later. Just for development now
intersects(SGVec3<T>& x, const SGTriangle<T>& tri, const SGLineSegment<T>& lineSegment, T eps = 0)
{
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
// Method based on the observation that we are looking for a
// point x that can be expressed in terms of the triangle points
// x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
// with 0 <= u, v and u + v <= 1.
// OTOH it could be expressed in terms of the lineSegment
// x = o + t*d
// Now we can compute u, v and t.
SGVec3<T> p = cross(lineSegment.getDirection(), tri.getEdge(1));
T denom = dot(p, tri.getEdge(0));
T signDenom = copysign(1, denom);
SGVec3<T> s = lineSegment.getStart() - tri.getBaseVertex();
SGVec3<T> q = cross(s, tri.getEdge(0));
// Now t would read
// t = 1/denom*dot(q, tri.getEdge(1));
// To avoid an expensive division we multiply by |denom|
T tDenom = signDenom*dot(q, tri.getEdge(1));
if (tDenom < 0)
return false;
// For line segment we would test against
// if (1 < t)
// return false;
// with the original t. The multiplied test reads
T absDenom = fabs(denom);
if (absDenom < tDenom)
return false;
// take the CPU accuracy in account
T absDenomEps = absDenom*eps;
// T u = 1/denom*dot(p, s);
T u = signDenom*dot(p, s);
if (u < -absDenomEps)
return false;
// T v = 1/denom*dot(q, d);
// if (v < -eps)
// return false;
T v = signDenom*dot(q, lineSegment.getDirection());
if (v < -absDenomEps)
return false;
if (u + v > absDenom + absDenomEps)
return false;
// return if paralell ??? FIXME what if paralell and in plane?
// may be we are ok below than anyway??
if (absDenom <= SGLimits<T>::min())
return false;
x = lineSegment.getStart();
// if we have survived here it could only happen with denom == 0
// that the point is already in plane. Then return the origin ...
if (SGLimitsd::min() < absDenom)
x += (tDenom/absDenom)*lineSegment.getDirection();
return true;
}
template<typename T>
inline bool
intersects(const SGTriangle<T>& tri, const SGLineSegment<T>& lineSegment, T eps = 0)
{
// FIXME: for now just wrap the othr method. When that has prooven
// well optimized, implement that special case
SGVec3<T> dummy;
return intersects(dummy, tri, lineSegment, eps);
}
template<typename T>
inline bool
intersects(const SGVec3<T>& v, const SGSphere<T>& sphere)
{
if (sphere.empty())
return false;
return distSqr(v, sphere.getCenter()) <= sphere.getRadius2();
}
template<typename T>
inline bool
intersects(const SGSphere<T>& sphere, const SGVec3<T>& v)
{ return intersects(v, sphere); }
template<typename T>
inline bool
intersects(const SGBox<T>& box, const SGLineSegment<T>& lineSegment)
{
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
SGVec3<T> c = lineSegment.getCenter() - box.getCenter();
SGVec3<T> w = 0.5*lineSegment.getDirection();
SGVec3<T> v(fabs(w.x()), fabs(w.y()), fabs(w.z()));
SGVec3<T> h = 0.5*box.getSize();
if (fabs(c[0]) > v[0] + h[0])
return false;
if (fabs(c[1]) > v[1] + h[1])
return false;
if (fabs(c[2]) > v[2] + h[2])
return false;
if (fabs(c[1]*w[2] - c[2]*w[1]) > h[1]*v[2] + h[2]*v[1])
return false;
if (fabs(c[0]*w[2] - c[2]*w[0]) > h[0]*v[2] + h[2]*v[0])
return false;
if (fabs(c[0]*w[1] - c[1]*w[0]) > h[0]*v[1] + h[1]*v[0])
return false;
return true;
}
template<typename T>
inline bool
intersects(const SGLineSegment<T>& lineSegment, const SGBox<T>& box)
{ return intersects(box, lineSegment); }
template<typename T>
inline bool
intersects(const SGBox<T>& box, const SGRay<T>& ray)
{
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
for (unsigned i = 0; i < 3; ++i) {
T cMin = box.getMin()[i];
T cMax = box.getMax()[i];
T cOrigin = ray.getOrigin()[i];
T cDir = ray.getDirection()[i];
if (fabs(cDir) <= SGLimits<T>::min()) {
if (cOrigin < cMin)
return false;
if (cMax < cOrigin)
return false;
}
T nearr = - SGLimits<T>::max();
T farr = SGLimits<T>::max();
T T1 = (cMin - cOrigin) / cDir;
T T2 = (cMax - cOrigin) / cDir;
if (T1 > T2) std::swap (T1, T2);/* since T1 intersection with near plane */
if (T1 > nearr) nearr = T1; /* want largest Tnear */
if (T2 < farr) farr = T2; /* want smallest Tfarr */
if (nearr > farr) // farr box is missed
return false;
if (farr < 0) // box is behind ray
return false;
}
return true;
}
// make it symmetric
template<typename T>
inline bool
intersects(const SGRay<T>& ray, const SGBox<T>& box)
{ return intersects(box, ray); }
#endif
-3
View File
@@ -26,7 +26,4 @@
template<typename T> template<typename T>
class SGLimits : public std::numeric_limits<T> {}; class SGLimits : public std::numeric_limits<T> {};
typedef SGLimits<float> SGLimitsf;
typedef SGLimits<double> SGLimitsd;
#endif #endif
+62
View File
@@ -0,0 +1,62 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGLineSegment_H
#define SGLineSegment_H
template<typename T>
class SGLineSegment {
public:
SGLineSegment()
{ }
SGLineSegment(const SGVec3<T>& start, const SGVec3<T>& end) :
_start(start),
_direction(end - start)
{ }
void set(const SGVec3<T>& start, const SGVec3<T>& end)
{ _start = start; _direction = end - start; }
const SGVec3<T>& getStart() const
{ return _start; }
SGVec3<T> getEnd() const
{ return _start + _direction; }
const SGVec3<T>& getDirection() const
{ return _direction; }
SGVec3<T> getNormalizedDirection() const
{ return normalize(getDirection()); }
SGVec3<T> getCenter() const
{ return _start + T(0.5)*_direction; }
private:
SGVec3<T> _start;
SGVec3<T> _direction;
};
/// Output to an ostream
template<typename char_type, typename traits_type, typename T>
inline
std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s,
const SGLineSegment<T>& lineSegment)
{
return s << "line segment: start = " << lineSegment.getStart()
<< ", end = " << lineSegment.getEnd();
}
#endif
+11 -2
View File
@@ -21,15 +21,24 @@
/// Just include them all /// Just include them all
#include <iosfwd> #include <iosfwd>
// FIXME, make it compile on IRIX
#include <osg/GL>
#undef GLUT_APIENTRY_DEFINED // GL/glut.h undef APIENTRY when this symbol is defined. osg/GL defines it (?).
// This probably would work if we didn't use plib/pu.h that include GL/glut.h
// on its side.
#include "SGMathFwd.hxx"
#include "SGCMath.hxx"
#include "SGLimits.hxx" #include "SGLimits.hxx"
#include "SGMisc.hxx" #include "SGMisc.hxx"
#include "SGGeodesy.hxx" #include "SGGeodesy.hxx"
#include "SGVec2.hxx"
#include "SGVec3.hxx" #include "SGVec3.hxx"
#include "SGVec4.hxx" #include "SGVec4.hxx"
#include "SGQuat.hxx"
#include "SGMatrix.hxx"
#include "SGGeoc.hxx" #include "SGGeoc.hxx"
#include "SGGeod.hxx" #include "SGGeod.hxx"
#include "SGQuat.hxx"
#include "SGMatrix.hxx"
#endif #endif
+56
View File
@@ -0,0 +1,56 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGMathFwd_H
#define SGMathFwd_H
// All forward declarations in case they only need to be declared
class SGGeoc;
class SGGeod;
template<typename T>
class SGLimits;
template<typename T>
class SGMatrix;
template<typename T>
class SGMisc;
template<typename T>
class SGQuat;
template<typename T>
class SGVec2;
template<typename T>
class SGVec3;
template<typename T>
class SGVec4;
typedef SGLimits<float> SGLimitsf;
typedef SGLimits<double> SGLimitsd;
typedef SGMatrix<float> SGMatrixf;
typedef SGMatrix<double> SGMatrixd;
typedef SGMisc<float> SGMiscf;
typedef SGMisc<double> SGMiscd;
typedef SGQuat<float> SGQuatf;
typedef SGQuat<double> SGQuatd;
typedef SGVec2<float> SGVec2f;
typedef SGVec2<double> SGVec2d;
typedef SGVec3<float> SGVec3f;
typedef SGVec3<double> SGVec3d;
typedef SGVec4<float> SGVec4f;
typedef SGVec4<double> SGVec4d;
#endif
+15 -9
View File
@@ -174,7 +174,9 @@ MatrixTest(void)
// Create some test matrix // Create some test matrix
SGVec3<T> v0(2, 7, 17); SGVec3<T> v0(2, 7, 17);
SGQuat<T> q0 = SGQuat<T>::fromAngleAxis(SGMisc<T>::pi(), normalize(v0)); SGQuat<T> q0 = SGQuat<T>::fromAngleAxis(SGMisc<T>::pi(), normalize(v0));
SGMatrix<T> m0(q0, v0); SGMatrix<T> m0;
m0.postMultTranslate(v0);
m0.postMultRotate(q0);
// Check the tqo forms of the inverse for that kind of special matrix // Check the tqo forms of the inverse for that kind of special matrix
SGMatrix<T> m1, m2; SGMatrix<T> m1, m2;
@@ -213,16 +215,16 @@ GeodesyTest(void)
geod0 = SGGeod::fromDegM(30, 20, 17); geod0 = SGGeod::fromDegM(30, 20, 17);
// Test the conversion routines to cartesian coordinates // Test the conversion routines to cartesian coordinates
cart0 = geod0; cart0 = SGVec3<double>::fromGeod(geod0);
geod1 = cart0; geod1 = SGGeod::fromCart(cart0);
if (epsDeg < fabs(geod0.getLongitudeDeg() - geod1.getLongitudeDeg()) || if (epsDeg < fabs(geod0.getLongitudeDeg() - geod1.getLongitudeDeg()) ||
epsDeg < fabs(geod0.getLatitudeDeg() - geod1.getLatitudeDeg()) || epsDeg < fabs(geod0.getLatitudeDeg() - geod1.getLatitudeDeg()) ||
epsM < fabs(geod0.getElevationM() - geod1.getElevationM())) epsM < fabs(geod0.getElevationM() - geod1.getElevationM()))
return false; return false;
// Test the conversion routines to radial coordinates // Test the conversion routines to radial coordinates
geoc0 = cart0; geoc0 = SGGeoc::fromCart(cart0);
cart1 = geoc0; cart1 = SGVec3<double>::fromGeoc(geoc0);
if (!equivalent(cart0, cart1)) if (!equivalent(cart0, cart1))
return false; return false;
@@ -236,7 +238,9 @@ sgInterfaceTest(void)
SGVec3f v3f = SGVec3f::e2(); SGVec3f v3f = SGVec3f::e2();
SGVec4f v4f = SGVec4f::e2(); SGVec4f v4f = SGVec4f::e2();
SGQuatf qf = SGQuatf::fromEulerRad(1.2, 1.3, -0.4); SGQuatf qf = SGQuatf::fromEulerRad(1.2, 1.3, -0.4);
SGMatrixf mf(qf, v3f); SGMatrixf mf;
mf.postMultTranslate(v3f);
mf.postMultRotate(qf);
// Copy to and from plibs types check if result is equal, // Copy to and from plibs types check if result is equal,
// test for exact equality // test for exact equality
@@ -283,7 +287,9 @@ sgdInterfaceTest(void)
SGVec3d v3d = SGVec3d::e2(); SGVec3d v3d = SGVec3d::e2();
SGVec4d v4d = SGVec4d::e2(); SGVec4d v4d = SGVec4d::e2();
SGQuatd qd = SGQuatd::fromEulerRad(1.2, 1.3, -0.4); SGQuatd qd = SGQuatd::fromEulerRad(1.2, 1.3, -0.4);
SGMatrixd md(qd, v3d); SGMatrixd md;
md.postMultTranslate(v3d);
md.postMultRotate(qd);
// Copy to and from plibs types check if result is equal, // Copy to and from plibs types check if result is equal,
// test for exact equality // test for exact equality
@@ -346,8 +352,8 @@ main(void)
return EXIT_FAILURE; return EXIT_FAILURE;
// Check geodetic/geocentric/cartesian conversions // Check geodetic/geocentric/cartesian conversions
// if (!GeodesyTest()) if (!GeodesyTest())
// return EXIT_FAILURE; return EXIT_FAILURE;
// Check interaction with sg*/sgd* // Check interaction with sg*/sgd*
if (!sgInterfaceTest()) if (!sgInterfaceTest())
+54 -40
View File
@@ -22,9 +22,6 @@
template<typename T> template<typename T>
struct TransNegRef; struct TransNegRef;
template<typename T>
class SGMatrix;
/// 3D Matrix Class /// 3D Matrix Class
template<typename T> template<typename T>
class SGMatrix { class SGMatrix {
@@ -66,14 +63,13 @@ public:
} }
/// Constructor, build up a SGMatrix from a translation /// Constructor, build up a SGMatrix from a translation
SGMatrix(const SGVec3<T>& trans) template<typename S>
SGMatrix(const SGVec3<S>& trans)
{ set(trans); } { set(trans); }
/// Constructor, build up a SGMatrix from a rotation and a translation /// Constructor, build up a SGMatrix from a rotation and a translation
SGMatrix(const SGQuat<T>& quat, const SGVec3<T>& trans) template<typename S>
{ set(quat, trans); } SGMatrix(const SGQuat<S>& quat)
/// Constructor, build up a SGMatrix from a rotation and a translation
SGMatrix(const SGQuat<T>& quat)
{ set(quat); } { set(quat); }
/// Copy constructor for a transposed negated matrix /// Copy constructor for a transposed negated matrix
@@ -81,39 +77,22 @@ public:
{ set(tm); } { set(tm); }
/// Set from a tranlation /// Set from a tranlation
void set(const SGVec3<T>& trans) template<typename S>
void set(const SGVec3<S>& trans)
{ {
_data.flat[0] = 1; _data.flat[4] = 0; _data.flat[0] = 1; _data.flat[4] = 0;
_data.flat[8] = 0; _data.flat[12] = -trans(0); _data.flat[8] = 0; _data.flat[12] = T(trans(0));
_data.flat[1] = 0; _data.flat[5] = 1; _data.flat[1] = 0; _data.flat[5] = 1;
_data.flat[9] = 0; _data.flat[13] = -trans(1); _data.flat[9] = 0; _data.flat[13] = T(trans(1));
_data.flat[2] = 0; _data.flat[6] = 0; _data.flat[2] = 0; _data.flat[6] = 0;
_data.flat[10] = 1; _data.flat[14] = -trans(2); _data.flat[10] = 1; _data.flat[14] = T(trans(2));
_data.flat[3] = 0; _data.flat[7] = 0; _data.flat[3] = 0; _data.flat[7] = 0;
_data.flat[11] = 0; _data.flat[15] = 1; _data.flat[11] = 0; _data.flat[15] = 1;
} }
/// Set from a scale/rotation and tranlation /// Set from a scale/rotation and tranlation
void set(const SGQuat<T>& quat, const SGVec3<T>& trans) template<typename S>
{ void set(const SGQuat<S>& quat)
T w = quat.w(); T x = quat.x(); T y = quat.y(); T z = quat.z();
T xx = x*x; T yy = y*y; T zz = z*z;
T wx = w*x; T wy = w*y; T wz = w*z;
T xy = x*y; T xz = x*z; T yz = y*z;
_data.flat[0] = 1-2*(yy+zz); _data.flat[1] = 2*(xy-wz);
_data.flat[2] = 2*(xz+wy); _data.flat[3] = 0;
_data.flat[4] = 2*(xy+wz); _data.flat[5] = 1-2*(xx+zz);
_data.flat[6] = 2*(yz-wx); _data.flat[7] = 0;
_data.flat[8] = 2*(xz-wy); _data.flat[9] = 2*(yz+wx);
_data.flat[10] = 1-2*(xx+yy); _data.flat[11] = 0;
// Well, this one is ugly here, as that xform method on the current
// object needs the above data to be already set ...
SGVec3<T> t = xformVec(trans);
_data.flat[12] = -t(0); _data.flat[13] = -t(1);
_data.flat[14] = -t(2); _data.flat[15] = 1;
}
/// Set from a scale/rotation and tranlation
void set(const SGQuat<T>& quat)
{ {
T w = quat.w(); T x = quat.x(); T y = quat.y(); T z = quat.z(); T w = quat.w(); T x = quat.x(); T y = quat.y(); T z = quat.z();
T xx = x*x; T yy = y*y; T zz = z*z; T xx = x*x; T yy = y*y; T zz = z*z;
@@ -202,6 +181,45 @@ public:
/// Inplace matrix multiplication, post multiply /// Inplace matrix multiplication, post multiply
SGMatrix& operator*=(const SGMatrix<T>& m2); SGMatrix& operator*=(const SGMatrix<T>& m2);
template<typename S>
SGMatrix& preMultTranslate(const SGVec3<S>& t)
{
for (unsigned i = 0; i < SGMatrix<T>::nCols-1; ++i)
(*this)(i,3) += T(t(i));
return *this;
}
template<typename S>
SGMatrix& postMultTranslate(const SGVec3<S>& t)
{
SGVec4<T> col3((*this)(0,3), (*this)(1,3), (*this)(2,3), (*this)(3,3));
for (unsigned i = 0; i < SGMatrix<T>::nCols-1; ++i) {
SGVec4<T> tmp((*this)(0,3), (*this)(1,3), (*this)(2,3), (*this)(3,3));
col3 += T(t(i))*tmp;
}
(*this)(0,3) = col3(0); (*this)(1,3) = col3(1);
(*this)(2,3) = col3(2); (*this)(3,3) = col3(3);
return *this;
}
SGMatrix& preMultRotate(const SGQuat<T>& r)
{
for (unsigned i = 0; i < SGMatrix<T>::nCols; ++i) {
SGVec3<T> col((*this)(0,i), (*this)(1,i), (*this)(2,i));
col = r.transform(col);
(*this)(0,i) = col(0); (*this)(1,i) = col(1); (*this)(2,i) = col(2);
}
return *this;
}
SGMatrix& postMultRotate(const SGQuat<T>& r)
{
for (unsigned i = 0; i < SGMatrix<T>::nCols; ++i) {
SGVec3<T> col((*this)(i,0), (*this)(i,1), (*this)(i,2));
col = r.backTransform(col);
(*this)(i,0) = col(0); (*this)(i,1) = col(1); (*this)(i,2) = col(2);
}
return *this;
}
SGVec3<T> xformPt(const SGVec3<T>& pt) const SGVec3<T> xformPt(const SGVec3<T>& pt) const
{ {
SGVec3<T> tpt; SGVec3<T> tpt;
@@ -571,18 +589,14 @@ operator<<(std::basic_ostream<char_type, traits_type>& s, const SGMatrix<T>& m)
return s; return s;
} }
/// Two classes doing actually the same on different types
typedef SGMatrix<float> SGMatrixf;
typedef SGMatrix<double> SGMatrixd;
inline inline
SGMatrixf SGMatrixf
toMatrixf(const SGMatrixd& m) toMatrixf(const SGMatrixd& m)
{ {
return SGMatrixf((float)m(0,0), (float)m(0,1), (float)m(0,2), (float)m(0,3), return SGMatrixf((float)m(0,0), (float)m(0,1), (float)m(0,2), (float)m(0,3),
(float)m(1,0), (float)m(1,1), (float)m(1,2), (float)m(1,3), (float)m(1,0), (float)m(1,1), (float)m(1,2), (float)m(1,3),
(float)m(3,0), (float)m(2,1), (float)m(2,2), (float)m(2,3), (float)m(2,0), (float)m(2,1), (float)m(2,2), (float)m(2,3),
(float)m(4,0), (float)m(4,1), (float)m(4,2), (float)m(4,3)); (float)m(3,0), (float)m(3,1), (float)m(3,2), (float)m(3,3));
} }
inline inline
@@ -591,8 +605,8 @@ toMatrixd(const SGMatrixf& m)
{ {
return SGMatrixd(m(0,0), m(0,1), m(0,2), m(0,3), return SGMatrixd(m(0,0), m(0,1), m(0,2), m(0,3),
m(1,0), m(1,1), m(1,2), m(1,3), m(1,0), m(1,1), m(1,2), m(1,3),
m(3,0), m(2,1), m(2,2), m(2,3), m(2,0), m(2,1), m(2,2), m(2,3),
m(4,0), m(4,1), m(4,2), m(4,3)); m(3,0), m(3,1), m(3,2), m(3,3));
} }
#endif #endif
+38 -5
View File
@@ -18,12 +18,12 @@
#ifndef SGMisc_H #ifndef SGMisc_H
#define SGMisc_H #define SGMisc_H
#include <cmath>
template<typename T> template<typename T>
class SGMisc { class SGMisc {
public: public:
static T pi() { return T(3.1415926535897932384626433832795029L); } static T pi() { return T(3.1415926535897932384626433832795029L); }
static T twopi() { return 2*T(3.1415926535897932384626433832795029L); }
static T min(const T& a, const T& b) static T min(const T& a, const T& b)
{ return a < b ? a : b; } { return a < b ? a : b; }
static T min(const T& a, const T& b, const T& c) static T min(const T& a, const T& b, const T& c)
@@ -36,6 +36,11 @@ public:
{ return max(max(a, b), c); } { return max(max(a, b), c); }
static T max(const T& a, const T& b, const T& c, const T& d) static T max(const T& a, const T& b, const T& c, const T& d)
{ return max(max(max(a, b), c), d); } { return max(max(max(a, b), c), d); }
// clip the value of a to be in the range between and including _min and _max
static T clip(const T& a, const T& _min, const T& _max)
{ return max(_min, min(_max, a)); }
static int sign(const T& a) static int sign(const T& a)
{ {
if (a < -SGLimits<T>::min()) if (a < -SGLimits<T>::min())
@@ -51,6 +56,37 @@ public:
static T deg2rad(const T& val) static T deg2rad(const T& val)
{ return val*pi()/180; } { return val*pi()/180; }
// normalize the value to be in a range between [min, max[
static T
normalizePeriodic(const T& min, const T& max, const T& value)
{
T range = max - min;
if (range < SGLimits<T>::min())
return min;
T normalized = value - range*floor((value - min)/range);
// two security checks that can only happen due to roundoff
if (value <= min)
return min;
if (max <= normalized)
return min;
return normalized;
}
// normalize the angle to be in a range between [-pi, pi[
static T
normalizeAngle(const T& angle)
{ return normalizePeriodic(-pi(), pi(), angle); }
// normalize the angle to be in a range between [0, 2pi[
static T
normalizeAngle2(const T& angle)
{ return normalizePeriodic(0, twopi(), angle); }
static T round(const T& v)
{ return floor(v + T(0.5)); }
static int roundToInt(const T& v)
{ return int(round(v)); }
#ifndef NDEBUG #ifndef NDEBUG
/// Returns true if v is a NaN value /// Returns true if v is a NaN value
/// Use with care: allways code that you do not need to use that! /// Use with care: allways code that you do not need to use that!
@@ -71,7 +107,4 @@ public:
#endif #endif
}; };
typedef SGMisc<float> SGMiscf;
typedef SGMisc<double> SGMiscd;
#endif #endif
+59
View File
@@ -0,0 +1,59 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGPlane_H
#define SGPlane_H
template<typename T>
class SGPlane {
public:
SGPlane()
{ }
SGPlane(const SGVec3<T>& normal, T dist) :
_normal(normal), _dist(dist)
{ }
SGPlane(const SGVec3<T> vertices[3]) :
_normal(normalize(cross(vertices[1] - vertices[0],
vertices[2] - vertices[0]))),
_dist(-dot(_normal, vertices[0]))
{ }
void setNormal(const SGVec3<T>& normal)
{ _normal = normal; }
const SGVec3<T>& getNormal() const
{ return _normal; }
void setDist(const T& dist)
{ _dist = dist; }
const T& getDist() const
{ return _dist; }
/// That is the distance where we measure positive in direction of the normal
T getPositiveDist() const
{ return -_dist; }
/// That is the distance where we measure positive in the oposite direction
/// of the normal.
const T& getNegativeDist() const
{ return _dist; }
private:
// That ordering is important because of one constructor
SGVec3<T> _normal;
T _dist;
};
#endif
+286 -62
View File
@@ -18,9 +18,50 @@
#ifndef SGQuat_H #ifndef SGQuat_H
#define SGQuat_H #define SGQuat_H
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#include <osg/Quat>
template<typename T>
struct SGQuatStorage {
/// Readonly raw storage interface
const T (&data(void) const)[4]
{ return _data; }
/// Readonly raw storage interface
T (&data(void))[4]
{ return _data; }
void osg() const
{ }
private:
T _data[4];
};
template<>
struct SGQuatStorage<double> : public osg::Quat {
/// Access raw data by index, the index is unchecked
const double (&data(void) const)[4]
{ return osg::Quat::_v; }
/// Access raw data by index, the index is unchecked
double (&data(void))[4]
{ return osg::Quat::_v; }
const osg::Quat& osg() const
{ return *this; }
osg::Quat& osg()
{ return *this; }
};
/// 3D Vector Class /// 3D Vector Class
template<typename T> template<typename T>
class SGQuat { class SGQuat : protected SGQuatStorage<T> {
public: public:
typedef T value_type; typedef T value_type;
@@ -33,7 +74,7 @@ public:
/// uninitialized values in the debug build very fast ... /// uninitialized values in the debug build very fast ...
#ifndef NDEBUG #ifndef NDEBUG
for (unsigned i = 0; i < 4; ++i) for (unsigned i = 0; i < 4; ++i)
_data[i] = SGLimits<T>::quiet_NaN(); data()[i] = SGLimits<T>::quiet_NaN();
#endif #endif
} }
/// Constructor. Initialize by the given values /// Constructor. Initialize by the given values
@@ -42,11 +83,13 @@ public:
/// Constructor. Initialize by the content of a plain array, /// Constructor. Initialize by the content of a plain array,
/// make sure it has at least 4 elements /// make sure it has at least 4 elements
explicit SGQuat(const T* d) explicit SGQuat(const T* d)
{ _data[0] = d[0]; _data[1] = d[1]; _data[2] = d[2]; _data[3] = d[3]; } { data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
explicit SGQuat(const osg::Quat& d)
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
/// Return a unit quaternion /// Return a unit quaternion
static SGQuat unit(void) static SGQuat unit(void)
{ return fromRealImag(1, SGVec3<T>(0)); } { return fromRealImag(1, SGVec3<T>(0, 0, 0)); }
/// Return a quaternion from euler angles /// Return a quaternion from euler angles
static SGQuat fromEulerRad(T z, T y, T x) static SGQuat fromEulerRad(T z, T y, T x)
@@ -87,13 +130,17 @@ public:
static SGQuat fromHeadAttBankDeg(T h, T a, T b) static SGQuat fromHeadAttBankDeg(T h, T a, T b)
{ return fromEulerDeg(h, a, b); } { return fromEulerDeg(h, a, b); }
/// Return a quaternion rotation the the horizontal local frame from given /// Return a quaternion rotation from the earth centered to the
/// longitude and latitude /// simulation usual horizontal local frame from given
/// longitude and latitude.
/// The horizontal local frame used in simulations is the frame with x-axis
/// pointing north, the y-axis pointing eastwards and the z axis
/// pointing downwards.
static SGQuat fromLonLatRad(T lon, T lat) static SGQuat fromLonLatRad(T lon, T lat)
{ {
SGQuat q; SGQuat q;
T zd2 = T(0.5)*lon; T zd2 = T(0.5)*lon;
T yd2 = T(-0.25)*SGMisc<value_type>::pi() - T(0.5)*lat; T yd2 = T(-0.25)*SGMisc<T>::pi() - T(0.5)*lat;
T Szd2 = sin(zd2); T Szd2 = sin(zd2);
T Syd2 = sin(yd2); T Syd2 = sin(yd2);
T Czd2 = cos(zd2); T Czd2 = cos(zd2);
@@ -104,11 +151,50 @@ public:
q.z() = Szd2*Cyd2; q.z() = Szd2*Cyd2;
return q; return q;
} }
/// Like the above provided for convenience
/// Return a quaternion rotation the the horizontal local frame from given
/// longitude and latitude
static SGQuat fromLonLatDeg(T lon, T lat) static SGQuat fromLonLatDeg(T lon, T lat)
{ return fromLonLatRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); } { return fromLonLatRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
/// Like the above provided for convenience
static SGQuat fromLonLat(const SGGeod& geod)
{ return fromLonLatRad(geod.getLongitudeRad(), geod.getLatitudeRad()); }
/// Return a quaternion rotation from the earth centered to the
/// OpenGL/viewer horizontal local frame from given longitude and latitude.
/// This frame matches the usual OpenGL axis directions. That is the target
/// frame has an x-axis pointing eastwards, y-axis pointing up and y z-axis
/// pointing south.
static SGQuat viewHLRad(T lon, T lat)
{
// That bails down to a 3-2-1 euler sequence lon+pi/2, 0, -lat-pi
// what is here is again the hand optimized version ...
SGQuat q;
T xd2 = -T(0.5)*lat - T(0.5)*SGMisc<T>::pi();
T zd2 = T(0.5)*lon + T(0.25)*SGMisc<T>::pi();
T Szd2 = sin(zd2);
T Sxd2 = sin(xd2);
T Czd2 = cos(zd2);
T Cxd2 = cos(xd2);
q.w() = Cxd2*Czd2;
q.x() = Sxd2*Czd2;
q.y() = Sxd2*Szd2;
q.z() = Cxd2*Szd2;
return q;
}
/// Like the above provided for convenience
static SGQuat viewHLDeg(T lon, T lat)
{ return viewHLRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
/// Like the above provided for convenience
static SGQuat viewHL(const SGGeod& geod)
{ return viewHLRad(geod.getLongitudeRad(), geod.getLatitudeRad()); }
/// Convert a quaternion rotation from the simulation frame
/// to the view (OpenGL) frame. That is it just swaps the axis part of
/// this current quaternion.
/// That proves useful when you want to use the euler 3-2-1 sequence
/// for the usual heading/pitch/roll sequence within the context of
/// OpenGL/viewer frames.
static SGQuat simToView(const SGQuat& q)
{ return SGQuat(q.y(), -q.z(), -q.x(), q.w()); }
/// Create a quaternion from the angle axis representation /// Create a quaternion from the angle axis representation
static SGQuat fromAngleAxis(T angle, const SGVec3<T>& axis) static SGQuat fromAngleAxis(T angle, const SGVec3<T>& axis)
@@ -132,14 +218,100 @@ public:
return fromRealImag(cos(angle2), T(sin(angle2)/nAxis)*axis); return fromRealImag(cos(angle2), T(sin(angle2)/nAxis)*axis);
} }
static SGQuat fromRotateTo(const SGVec3<T>& from, const SGVec3<T>& to)
{
T nfrom = norm(from);
T nto = norm(to);
if (nfrom < SGLimits<T>::min() || nto < SGLimits<T>::min())
return SGQuat::unit();
return SGQuat::fromRotateToNorm((1/nfrom)*from, (1/nto)*to);
}
// FIXME more finegrained error behavour.
static SGQuat fromRotateTo(const SGVec3<T>& v1, unsigned i1,
const SGVec3<T>& v2, unsigned i2)
{
T nrmv1 = norm(v1);
T nrmv2 = norm(v2);
if (nrmv1 < SGLimits<T>::min() || nrmv2 < SGLimits<T>::min())
return SGQuat::unit();
SGVec3<T> nv1 = (1/nrmv1)*v1;
SGVec3<T> nv2 = (1/nrmv2)*v2;
T dv1v2 = dot(nv1, nv2);
if (fabs(fabs(dv1v2)-1) < SGLimits<T>::epsilon())
return SGQuat::unit();
// The target vector for the first rotation
SGVec3<T> nto1 = SGVec3<T>::zeros();
SGVec3<T> nto2 = SGVec3<T>::zeros();
nto1[i1] = 1;
nto2[i2] = 1;
// The first rotation can be done with the usual routine.
SGQuat q = SGQuat::fromRotateToNorm(nv1, nto1);
// The rotation axis for the second rotation is the
// target for the first one, so the rotation axis is nto1
// We need to get the angle.
// Make nv2 exactly orthogonal to nv1.
nv2 = normalize(nv2 - dv1v2*nv1);
SGVec3<T> tnv2 = q.transform(nv2);
T cosang = dot(nto2, tnv2);
T cos05ang = T(0.5+0.5*cosang);
if (cos05ang <= 0)
cosang = T(0);
cos05ang = sqrt(cos05ang);
T sig = dot(nto1, cross(nto2, tnv2));
T sin05ang = T(0.5-0.5*cosang);
if (sin05ang <= 0)
sin05ang = 0;
sin05ang = copysign(sqrt(sin05ang), sig);
q *= SGQuat::fromRealImag(cos05ang, sin05ang*nto1);
return q;
}
// Return a quaternion which rotates the vector given by v
// to the vector -v. Other directions are *not* preserved.
static SGQuat fromChangeSign(const SGVec3<T>& v)
{
// The vector from points to the oposite direction than to.
// Find a vector perpendicular to the vector to.
T absv1 = fabs(v(0));
T absv2 = fabs(v(1));
T absv3 = fabs(v(2));
SGVec3<T> axis;
if (absv2 < absv1 && absv3 < absv1) {
T quot = v(1)/v(0);
axis = (1/sqrt(1+quot*quot))*SGVec3<T>(quot, -1, 0);
} else if (absv1 < absv2 && absv3 < absv2) {
T quot = v(2)/v(1);
axis = (1/sqrt(1+quot*quot))*SGVec3<T>(0, quot, -1);
} else if (absv1 < absv3 && absv2 < absv3) {
T quot = v(0)/v(2);
axis = (1/sqrt(1+quot*quot))*SGVec3<T>(-1, 0, quot);
} else {
// The all zero case.
return SGQuat::unit();
}
return SGQuat::fromRealImag(0, axis);
}
/// Return a quaternion from real and imaginary part /// Return a quaternion from real and imaginary part
static SGQuat fromRealImag(T r, const SGVec3<T>& i) static SGQuat fromRealImag(T r, const SGVec3<T>& i)
{ {
SGQuat q; SGQuat q;
q.w() = r; q.w() = r;
q.x() = i(0); q.x() = i.x();
q.y() = i(1); q.y() = i.y();
q.z() = i(2); q.z() = i.z();
return q; return q;
} }
@@ -150,36 +322,36 @@ public:
/// write the euler angles into the references /// write the euler angles into the references
void getEulerRad(T& zRad, T& yRad, T& xRad) const void getEulerRad(T& zRad, T& yRad, T& xRad) const
{ {
value_type sqrQW = w()*w(); T sqrQW = w()*w();
value_type sqrQX = x()*x(); T sqrQX = x()*x();
value_type sqrQY = y()*y(); T sqrQY = y()*y();
value_type sqrQZ = z()*z(); T sqrQZ = z()*z();
value_type num = 2*(y()*z() + w()*x()); T num = 2*(y()*z() + w()*x());
value_type den = sqrQW - sqrQX - sqrQY + sqrQZ; T den = sqrQW - sqrQX - sqrQY + sqrQZ;
if (fabs(den) < SGLimits<value_type>::min() && if (fabs(den) < SGLimits<T>::min() &&
fabs(num) < SGLimits<value_type>::min()) fabs(num) < SGLimits<T>::min())
xRad = 0; xRad = 0;
else else
xRad = atan2(num, den); xRad = atan2(num, den);
value_type tmp = 2*(x()*z() - w()*y()); T tmp = 2*(x()*z() - w()*y());
if (tmp < -1) if (tmp < -1)
yRad = 0.5*SGMisc<value_type>::pi(); yRad = 0.5*SGMisc<T>::pi();
else if (1 < tmp) else if (1 < tmp)
yRad = -0.5*SGMisc<value_type>::pi(); yRad = -0.5*SGMisc<T>::pi();
else else
yRad = -asin(tmp); yRad = -asin(tmp);
num = 2*(x()*y() + w()*z()); num = 2*(x()*y() + w()*z());
den = sqrQW + sqrQX - sqrQY - sqrQZ; den = sqrQW + sqrQX - sqrQY - sqrQZ;
if (fabs(den) < SGLimits<value_type>::min() && if (fabs(den) < SGLimits<T>::min() &&
fabs(num) < SGLimits<value_type>::min()) fabs(num) < SGLimits<T>::min())
zRad = 0; zRad = 0;
else { else {
value_type psi = atan2(num, den); T psi = atan2(num, den);
if (psi < 0) if (psi < 0)
psi += 2*SGMisc<value_type>::pi(); psi += 2*SGMisc<T>::pi();
zRad = psi; zRad = psi;
} }
} }
@@ -222,67 +394,66 @@ public:
/// Access by index, the index is unchecked /// Access by index, the index is unchecked
const T& operator()(unsigned i) const const T& operator()(unsigned i) const
{ return _data[i]; } { return data()[i]; }
/// Access by index, the index is unchecked /// Access by index, the index is unchecked
T& operator()(unsigned i) T& operator()(unsigned i)
{ return _data[i]; } { return data()[i]; }
/// Access raw data by index, the index is unchecked /// Access raw data by index, the index is unchecked
const T& operator[](unsigned i) const const T& operator[](unsigned i) const
{ return _data[i]; } { return data()[i]; }
/// Access raw data by index, the index is unchecked /// Access raw data by index, the index is unchecked
T& operator[](unsigned i) T& operator[](unsigned i)
{ return _data[i]; } { return data()[i]; }
/// Access the x component /// Access the x component
const T& x(void) const const T& x(void) const
{ return _data[0]; } { return data()[0]; }
/// Access the x component /// Access the x component
T& x(void) T& x(void)
{ return _data[0]; } { return data()[0]; }
/// Access the y component /// Access the y component
const T& y(void) const const T& y(void) const
{ return _data[1]; } { return data()[1]; }
/// Access the y component /// Access the y component
T& y(void) T& y(void)
{ return _data[1]; } { return data()[1]; }
/// Access the z component /// Access the z component
const T& z(void) const const T& z(void) const
{ return _data[2]; } { return data()[2]; }
/// Access the z component /// Access the z component
T& z(void) T& z(void)
{ return _data[2]; } { return data()[2]; }
/// Access the w component /// Access the w component
const T& w(void) const const T& w(void) const
{ return _data[3]; } { return data()[3]; }
/// Access the w component /// Access the w component
T& w(void) T& w(void)
{ return _data[3]; } { return data()[3]; }
/// Get the data pointer, usefull for interfacing with plib's sg*Vec /// Get the data pointer
const T* data(void) const using SGQuatStorage<T>::data;
{ return _data; }
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
T* data(void)
{ return _data; }
/// Readonly interface function to ssg's sgQuat/sgdQuat /// Readonly interface function to ssg's sgQuat/sgdQuat
const T (&sg(void) const)[4] const T (&sg(void) const)[4]
{ return _data; } { return data(); }
/// Interface function to ssg's sgQuat/sgdQuat /// Interface function to ssg's sgQuat/sgdQuat
T (&sg(void))[4] T (&sg(void))[4]
{ return _data; } { return data(); }
/// Interface function to osg's Quat*
using SGQuatStorage<T>::osg;
/// Inplace addition /// Inplace addition
SGQuat& operator+=(const SGQuat& v) SGQuat& operator+=(const SGQuat& v)
{ _data[0]+=v(0);_data[1]+=v(1);_data[2]+=v(2);_data[3]+=v(3);return *this; } { data()[0]+=v(0);data()[1]+=v(1);data()[2]+=v(2);data()[3]+=v(3);return *this; }
/// Inplace subtraction /// Inplace subtraction
SGQuat& operator-=(const SGQuat& v) SGQuat& operator-=(const SGQuat& v)
{ _data[0]-=v(0);_data[1]-=v(1);_data[2]-=v(2);_data[3]-=v(3);return *this; } { data()[0]-=v(0);data()[1]-=v(1);data()[2]-=v(2);data()[3]-=v(3);return *this; }
/// Inplace scalar multiplication /// Inplace scalar multiplication
template<typename S> template<typename S>
SGQuat& operator*=(S s) SGQuat& operator*=(S s)
{ _data[0] *= s; _data[1] *= s; _data[2] *= s; _data[3] *= s; return *this; } { data()[0] *= s; data()[1] *= s; data()[2] *= s; data()[3] *= s; return *this; }
/// Inplace scalar multiplication by 1/s /// Inplace scalar multiplication by 1/s
template<typename S> template<typename S>
SGQuat& operator/=(S s) SGQuat& operator/=(S s)
@@ -294,18 +465,18 @@ public:
/// frame rotated with the quaternion /// frame rotated with the quaternion
SGVec3<T> transform(const SGVec3<T>& v) const SGVec3<T> transform(const SGVec3<T>& v) const
{ {
value_type r = 2/dot(*this, *this); T r = 2/dot(*this, *this);
SGVec3<T> qimag = imag(*this); SGVec3<T> qimag = imag(*this);
value_type qr = real(*this); T qr = real(*this);
return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag - (r*qr)*cross(qimag, v); return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag - (r*qr)*cross(qimag, v);
} }
/// Transform a vector from the coordinate frame rotated with the quaternion /// Transform a vector from the coordinate frame rotated with the quaternion
/// to the current coordinate frame /// to the current coordinate frame
SGVec3<T> backTransform(const SGVec3<T>& v) const SGVec3<T> backTransform(const SGVec3<T>& v) const
{ {
value_type r = 2/dot(*this, *this); T r = 2/dot(*this, *this);
SGVec3<T> qimag = imag(*this); SGVec3<T> qimag = imag(*this);
value_type qr = real(*this); T qr = real(*this);
return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag + (r*qr)*cross(qimag, v); return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag + (r*qr)*cross(qimag, v);
} }
@@ -318,7 +489,7 @@ public:
/// Return the time derivative of the quaternion given the angular velocity /// Return the time derivative of the quaternion given the angular velocity
SGQuat SGQuat
derivative(const SGVec3<T>& angVel) derivative(const SGVec3<T>& angVel) const
{ {
SGQuat deriv; SGQuat deriv;
@@ -331,8 +502,65 @@ public:
} }
private: private:
/// The actual data
T _data[4]; // Private because it assumes normalized inputs.
static SGQuat
fromRotateToSmaller90Deg(T cosang,
const SGVec3<T>& from, const SGVec3<T>& to)
{
// In this function we assume that the angle required to rotate from
// the vector from to the vector to is <= 90 deg.
// That is done so because of possible instabilities when we rotate more
// then 90deg.
// Note that the next comment does actually cover a *more* *general* case
// than we need in this function. That shows that this formula is even
// valid for rotations up to 180deg.
// Because of the signs in the axis, it is sufficient to care for angles
// in the interval [-pi,pi]. That means that 0.5*angle is in the interval
// [-pi/2,pi/2]. But in that range the cosine is allways >= 0.
// So we do not need to care for egative roots in the following equation:
T cos05ang = sqrt(0.5+0.5*cosang);
// Now our assumption of angles <= 90 deg comes in play.
// For that reason, we know that cos05ang is not zero.
// It is even more, we can see from the above formula that
// sqrt(0.5) < cos05ang.
// Compute the rotation axis, that is
// sin(angle)*normalized rotation axis
SGVec3<T> axis = cross(to, from);
// We need sin(0.5*angle)*normalized rotation axis.
// So rescale with sin(0.5*x)/sin(x).
// To do that we use the equation:
// sin(x) = 2*sin(0.5*x)*cos(0.5*x)
return SGQuat::fromRealImag( cos05ang, (1/(2*cos05ang))*axis);
}
// Private because it assumes normalized inputs.
static SGQuat
fromRotateToNorm(const SGVec3<T>& from, const SGVec3<T>& to)
{
// To avoid instabilities with roundoff, we distinguish between rotations
// with more then 90deg and rotations with less than 90deg.
// Compute the cosine of the angle.
T cosang = dot(from, to);
// For the small ones do direct computation
if (T(-0.5) < cosang)
return SGQuat::fromRotateToSmaller90Deg(cosang, from, to);
// For larger rotations. first rotate from to -from.
// Past that we will have a smaller angle again.
SGQuat q1 = SGQuat::fromChangeSign(from);
SGQuat q2 = SGQuat::fromRotateToSmaller90Deg(-cosang, -from, to);
return q1*q2;
}
}; };
/// Unary +, do nothing ... /// Unary +, do nothing ...
@@ -552,10 +780,6 @@ std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGQuat<T>& v) operator<<(std::basic_ostream<char_type, traits_type>& s, const SGQuat<T>& v)
{ return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; } { return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; }
/// Two classes doing actually the same on different types
typedef SGQuat<float> SGQuatf;
typedef SGQuat<double> SGQuatd;
inline inline
SGQuatf SGQuatf
toQuatf(const SGQuatd& v) toQuatf(const SGQuatd& v)
+62
View File
@@ -0,0 +1,62 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGRay_H
#define SGRay_H
template<typename T>
class SGRay {
public:
SGRay()
{ }
SGRay(const SGVec3<T>& origin, const SGVec3<T>& dir) :
_origin(origin), _direction(dir)
{ }
void set(const SGVec3<T>& origin, const SGVec3<T>& dir)
{ _origin = origin; _direction = dir; }
void setOrigin(const SGVec3<T>& origin)
{ _origin = origin; }
const SGVec3<T>& getOrigin() const
{ return _origin; }
void setDirection(const SGVec3<T>& direction)
{ _direction = direction; }
const SGVec3<T>& getDirection() const
{ return _direction; }
SGVec3<T> getNormalizedDirection() const
{ return normalize(getDirection()); }
private:
SGVec3<T> _origin;
SGVec3<T> _direction;
};
/// Output to an ostream
template<typename char_type, typename traits_type, typename T>
inline
std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s,
const SGRay<T>& ray)
{
return s << "ray: origin = " << ray.getOrigin()
<< ", direction = " << ray.getDirection();
}
#endif
+87
View File
@@ -0,0 +1,87 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGSphere_H
#define SGSphere_H
template<typename T>
class SGSphere {
public:
SGSphere() :
_radius(-1)
{ }
SGSphere(const SGVec3<T>& center, const T& radius) :
_center(center),
_radius(radius)
{ }
const SGVec3<T>& getCenter() const
{ return _center; }
void setCenter(const SGVec3<T>& center)
{ _center = center; }
const T& getRadius() const
{ return _radius; }
void setRadius(const T& radius)
{ _radius = radius; }
T getRadius2() const
{ return _radius*_radius; }
const bool empty() const
{ return !valid(); }
bool valid() const
{ return 0 <= _radius; }
void clear()
{ _radius = -1; }
void expandBy(const SGVec3<T>& v)
{
if (empty()) {
_center = v;
_radius = 0;
return;
}
T dist2 = distSqr(_center, v);
if (dist2 <= getRadius2())
return;
T dist = sqrt(dist2);
T newRadius = T(0.5)*(_radius + dist);
_center += ((newRadius - _radius)/dist)*(v - _center);
_radius = newRadius;
}
private:
SGVec3<T> _center;
T _radius;
};
/// Output to an ostream
template<typename char_type, typename traits_type, typename T>
inline
std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s,
const SGSphere<T>& sphere)
{
return s << "center = " << sphere.getCenter()
<< ", radius = " << sphere.getRadius();
}
#endif
+101
View File
@@ -0,0 +1,101 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGTriangle_H
#define SGTrianlge_H
template<typename T>
class SGTriangle {
public:
SGTriangle()
{ }
SGTriangle(const SGVec3<T>& v0, const SGVec3<T>& v1, const SGVec3<T>& v2)
{ set(v0, v1, v2); }
SGTriangle(const SGVec3<T> v[3])
{ set(v); }
void set(const SGVec3<T>& v0, const SGVec3<T>& v1, const SGVec3<T>& v2)
{
_v0 = v0;
_d[0] = v1 - v0;
_d[1] = v2 - v0;
}
void set(const SGVec3<T> v[3])
{
_v0 = v[0];
_d[0] = v[1] - v[0];
_d[1] = v[2] - v[0];
}
SGVec3d getCenter() const
{
SGBoxd box;
box.expandBy(_v0);
box.expandBy(_v0 + _d[0]);
box.expandBy(_v0 + _d[1]);
return box.getCenter();
}
// note that the index is unchecked
SGVec3<T> getVertex(unsigned i) const
{
if (0 < i)
return _v0 + _d[i-1];
return _v0;
}
/// return the normalized surface normal
SGVec3<T> getNormal() const
{ return normalize(cross(_d[0], _d[1])); }
const SGVec3<T>& getBaseVertex() const
{ return _v0; }
void setBaseVertex(const SGVec3<T>& v)
{ _v0 = v; }
const SGVec3<T>& getEdge(unsigned i) const
{ return _d[i]; }
void setEdge(unsigned i, const SGVec3<T>& d)
{ _d[i] = d; }
// flip the positive side
void flip()
{
SGVec3<T> tmp = _d[0];
_d[0] = _d[1];
_d[1] = tmp;
}
private:
/// Store one vertex directly, _d is the offset of the other two
/// vertices wrt the base vertex
/// For fast intersection tests this format prooves usefull. For that same
/// purpose also cache the cross product of the _d[i].
SGVec3<T> _v0;
SGVec3<T> _d[2];
};
/// Output to an ostream
template<typename char_type, typename traits_type, typename T>
inline
std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s,
const SGTriangle<T>& triangle)
{
return s << "triangle: v0 = " << triangle.getVertex(0)
<< ", v1 = " << triangle.getVertex(1)
<< ", v2 = " << triangle.getVertex(2);
}
#endif
+405
View File
@@ -0,0 +1,405 @@
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef SGVec2_H
#define SGVec2_H
#include <osg/Vec2f>
#include <osg/Vec2d>
template<typename T>
struct SGVec2Storage {
/// Readonly raw storage interface
const T (&data(void) const)[2]
{ return _data; }
/// Readonly raw storage interface
T (&data(void))[2]
{ return _data; }
void osg() const
{ }
private:
T _data[2];
};
template<>
struct SGVec2Storage<float> : public osg::Vec2f {
/// Access raw data by index, the index is unchecked
const float (&data(void) const)[2]
{ return osg::Vec2f::_v; }
/// Access raw data by index, the index is unchecked
float (&data(void))[2]
{ return osg::Vec2f::_v; }
const osg::Vec2f& osg() const
{ return *this; }
osg::Vec2f& osg()
{ return *this; }
};
template<>
struct SGVec2Storage<double> : public osg::Vec2d {
/// Access raw data by index, the index is unchecked
const double (&data(void) const)[2]
{ return osg::Vec2d::_v; }
/// Access raw data by index, the index is unchecked
double (&data(void))[2]
{ return osg::Vec2d::_v; }
const osg::Vec2d& osg() const
{ return *this; }
osg::Vec2d& osg()
{ return *this; }
};
/// 2D Vector Class
template<typename T>
class SGVec2 : protected SGVec2Storage<T> {
public:
typedef T value_type;
/// Default constructor. Does not initialize at all.
/// If you need them zero initialized, use SGVec2::zeros()
SGVec2(void)
{
/// Initialize with nans in the debug build, that will guarantee to have
/// a fast uninitialized default constructor in the release but shows up
/// uninitialized values in the debug build very fast ...
#ifndef NDEBUG
for (unsigned i = 0; i < 2; ++i)
data()[i] = SGLimits<T>::quiet_NaN();
#endif
}
/// Constructor. Initialize by the given values
SGVec2(T x, T y)
{ data()[0] = x; data()[1] = y; }
/// Constructor. Initialize by the content of a plain array,
/// make sure it has at least 2 elements
explicit SGVec2(const T* d)
{ data()[0] = d[0]; data()[1] = d[1]; }
explicit SGVec2(const osg::Vec2f& d)
{ data()[0] = d[0]; data()[1] = d[1]; }
explicit SGVec2(const osg::Vec2d& d)
{ data()[0] = d[0]; data()[1] = d[1]; }
/// Access by index, the index is unchecked
const T& operator()(unsigned i) const
{ return data()[i]; }
/// Access by index, the index is unchecked
T& operator()(unsigned i)
{ return data()[i]; }
/// Access raw data by index, the index is unchecked
const T& operator[](unsigned i) const
{ return data()[i]; }
/// Access raw data by index, the index is unchecked
T& operator[](unsigned i)
{ return data()[i]; }
/// Access the x component
const T& x(void) const
{ return data()[0]; }
/// Access the x component
T& x(void)
{ return data()[0]; }
/// Access the y component
const T& y(void) const
{ return data()[1]; }
/// Access the y component
T& y(void)
{ return data()[1]; }
/// Get the data pointer
using SGVec2Storage<T>::data;
/// Readonly interface function to ssg's sgVec2/sgdVec2
const T (&sg(void) const)[2]
{ return data(); }
/// Interface function to ssg's sgVec2/sgdVec2
T (&sg(void))[2]
{ return data(); }
/// Interface function to osg's Vec2*
using SGVec2Storage<T>::osg;
/// Inplace addition
SGVec2& operator+=(const SGVec2& v)
{ data()[0] += v(0); data()[1] += v(1); return *this; }
/// Inplace subtraction
SGVec2& operator-=(const SGVec2& v)
{ data()[0] -= v(0); data()[1] -= v(1); return *this; }
/// Inplace scalar multiplication
template<typename S>
SGVec2& operator*=(S s)
{ data()[0] *= s; data()[1] *= s; return *this; }
/// Inplace scalar multiplication by 1/s
template<typename S>
SGVec2& operator/=(S s)
{ return operator*=(1/T(s)); }
/// Return an all zero vector
static SGVec2 zeros(void)
{ return SGVec2(0, 0); }
/// Return unit vectors
static SGVec2 e1(void)
{ return SGVec2(1, 0); }
static SGVec2 e2(void)
{ return SGVec2(0, 1); }
};
/// Unary +, do nothing ...
template<typename T>
inline
const SGVec2<T>&
operator+(const SGVec2<T>& v)
{ return v; }
/// Unary -, do nearly nothing
template<typename T>
inline
SGVec2<T>
operator-(const SGVec2<T>& v)
{ return SGVec2<T>(-v(0), -v(1)); }
/// Binary +
template<typename T>
inline
SGVec2<T>
operator+(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ return SGVec2<T>(v1(0)+v2(0), v1(1)+v2(1)); }
/// Binary -
template<typename T>
inline
SGVec2<T>
operator-(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ return SGVec2<T>(v1(0)-v2(0), v1(1)-v2(1)); }
/// Scalar multiplication
template<typename S, typename T>
inline
SGVec2<T>
operator*(S s, const SGVec2<T>& v)
{ return SGVec2<T>(s*v(0), s*v(1)); }
/// Scalar multiplication
template<typename S, typename T>
inline
SGVec2<T>
operator*(const SGVec2<T>& v, S s)
{ return SGVec2<T>(s*v(0), s*v(1)); }
/// multiplication as a multiplicator, that is assume that the first vector
/// represents a 2x2 diagonal matrix with the diagonal elements in the vector.
/// Then the result is the product of that matrix times the second vector.
template<typename T>
inline
SGVec2<T>
mult(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ return SGVec2<T>(v1(0)*v2(0), v1(1)*v2(1)); }
/// component wise min
template<typename T>
inline
SGVec2<T>
min(const SGVec2<T>& v1, const SGVec2<T>& v2)
{return SGVec2<T>(SGMisc<T>::min(v1(0), v2(0)), SGMisc<T>::min(v1(1), v2(1)));}
template<typename S, typename T>
inline
SGVec2<T>
min(const SGVec2<T>& v, S s)
{ return SGVec2<T>(SGMisc<T>::min(s, v(0)), SGMisc<T>::min(s, v(1))); }
template<typename S, typename T>
inline
SGVec2<T>
min(S s, const SGVec2<T>& v)
{ return SGVec2<T>(SGMisc<T>::min(s, v(0)), SGMisc<T>::min(s, v(1))); }
/// component wise max
template<typename T>
inline
SGVec2<T>
max(const SGVec2<T>& v1, const SGVec2<T>& v2)
{return SGVec2<T>(SGMisc<T>::max(v1(0), v2(0)), SGMisc<T>::max(v1(1), v2(1)));}
template<typename S, typename T>
inline
SGVec2<T>
max(const SGVec2<T>& v, S s)
{ return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
template<typename S, typename T>
inline
SGVec2<T>
max(S s, const SGVec2<T>& v)
{ return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
/// Scalar dot product
template<typename T>
inline
T
dot(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ return v1(0)*v2(0) + v1(1)*v2(1); }
/// The euclidean norm of the vector, that is what most people call length
template<typename T>
inline
T
norm(const SGVec2<T>& v)
{ return sqrt(dot(v, v)); }
/// The euclidean norm of the vector, that is what most people call length
template<typename T>
inline
T
length(const SGVec2<T>& v)
{ return sqrt(dot(v, v)); }
/// The 1-norm of the vector, this one is the fastest length function we
/// can implement on modern cpu's
template<typename T>
inline
T
norm1(const SGVec2<T>& v)
{ return fabs(v(0)) + fabs(v(1)); }
/// The inf-norm of the vector
template<typename T>
inline
T
normI(const SGVec2<T>& v)
{ return SGMisc<T>::max(fabs(v(0)), fabs(v(1))); }
/// The euclidean norm of the vector, that is what most people call length
template<typename T>
inline
SGVec2<T>
normalize(const SGVec2<T>& v)
{ return (1/norm(v))*v; }
/// Return true if exactly the same
template<typename T>
inline
bool
operator==(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ return v1(0) == v2(0) && v1(1) == v2(1); }
/// Return true if not exactly the same
template<typename T>
inline
bool
operator!=(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ return ! (v1 == v2); }
/// Return true if smaller, good for putting that into a std::map
template<typename T>
inline
bool
operator<(const SGVec2<T>& v1, const SGVec2<T>& v2)
{
if (v1(0) < v2(0)) return true;
else if (v2(0) < v1(0)) return false;
else return (v1(1) < v2(1));
}
template<typename T>
inline
bool
operator<=(const SGVec2<T>& v1, const SGVec2<T>& v2)
{
if (v1(0) < v2(0)) return true;
else if (v2(0) < v1(0)) return false;
else return (v1(1) <= v2(1));
}
template<typename T>
inline
bool
operator>(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ return operator<(v2, v1); }
template<typename T>
inline
bool
operator>=(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ return operator<=(v2, v1); }
/// Return true if equal to the relative tolerance tol
template<typename T>
inline
bool
equivalent(const SGVec2<T>& v1, const SGVec2<T>& v2, T rtol, T atol)
{ return norm1(v1 - v2) < rtol*(norm1(v1) + norm1(v2)) + atol; }
/// Return true if equal to the relative tolerance tol
template<typename T>
inline
bool
equivalent(const SGVec2<T>& v1, const SGVec2<T>& v2, T rtol)
{ return norm1(v1 - v2) < rtol*(norm1(v1) + norm1(v2)); }
/// Return true if about equal to roundoff of the underlying type
template<typename T>
inline
bool
equivalent(const SGVec2<T>& v1, const SGVec2<T>& v2)
{
T tol = 100*SGLimits<T>::epsilon();
return equivalent(v1, v2, tol, tol);
}
/// The euclidean distance of the two vectors
template<typename T>
inline
T
dist(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ return norm(v1 - v2); }
/// The squared euclidean distance of the two vectors
template<typename T>
inline
T
distSqr(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ SGVec2<T> tmp = v1 - v2; return dot(tmp, tmp); }
#ifndef NDEBUG
template<typename T>
inline
bool
isNaN(const SGVec2<T>& v)
{
return SGMisc<T>::isNaN(v(0)) || SGMisc<T>::isNaN(v(1));
}
#endif
/// Output to an ostream
template<typename char_type, typename traits_type, typename T>
inline
std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec2<T>& v)
{ return s << "[ " << v(0) << ", " << v(1) << " ]"; }
inline
SGVec2f
toVec2f(const SGVec2d& v)
{ return SGVec2f((float)v(0), (float)v(1)); }
inline
SGVec2d
toVec2d(const SGVec2f& v)
{ return SGVec2d(v(0), v(1)); }
#endif
+275 -40
View File
@@ -18,9 +18,58 @@
#ifndef SGVec3_H #ifndef SGVec3_H
#define SGVec3_H #define SGVec3_H
#include <osg/Vec3f>
#include <osg/Vec3d>
template<typename T>
struct SGVec3Storage {
/// Readonly raw storage interface
const T (&data(void) const)[3]
{ return _data; }
/// Readonly raw storage interface
T (&data(void))[3]
{ return _data; }
void osg() const
{ }
private:
T _data[3];
};
template<>
struct SGVec3Storage<float> : public osg::Vec3f {
/// Access raw data by index, the index is unchecked
const float (&data(void) const)[3]
{ return osg::Vec3f::_v; }
/// Access raw data by index, the index is unchecked
float (&data(void))[3]
{ return osg::Vec3f::_v; }
const osg::Vec3f& osg() const
{ return *this; }
osg::Vec3f& osg()
{ return *this; }
};
template<>
struct SGVec3Storage<double> : public osg::Vec3d {
/// Access raw data by index, the index is unchecked
const double (&data(void) const)[3]
{ return osg::Vec3d::_v; }
/// Access raw data by index, the index is unchecked
double (&data(void))[3]
{ return osg::Vec3d::_v; }
const osg::Vec3d& osg() const
{ return *this; }
osg::Vec3d& osg()
{ return *this; }
};
/// 3D Vector Class /// 3D Vector Class
template<typename T> template<typename T>
class SGVec3 { class SGVec3 : protected SGVec3Storage<T> {
public: public:
typedef T value_type; typedef T value_type;
@@ -33,82 +82,79 @@ public:
/// uninitialized values in the debug build very fast ... /// uninitialized values in the debug build very fast ...
#ifndef NDEBUG #ifndef NDEBUG
for (unsigned i = 0; i < 3; ++i) for (unsigned i = 0; i < 3; ++i)
_data[i] = SGLimits<T>::quiet_NaN(); data()[i] = SGLimits<T>::quiet_NaN();
#endif #endif
} }
/// Constructor. Initialize by the given values /// Constructor. Initialize by the given values
SGVec3(T x, T y, T z) SGVec3(T x, T y, T z)
{ _data[0] = x; _data[1] = y; _data[2] = z; } { data()[0] = x; data()[1] = y; data()[2] = z; }
/// Constructor. Initialize by the content of a plain array, /// Constructor. Initialize by the content of a plain array,
/// make sure it has at least 3 elements /// make sure it has at least 3 elements
explicit SGVec3(const T* data) explicit SGVec3(const T* d)
{ _data[0] = data[0]; _data[1] = data[1]; _data[2] = data[2]; } { data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
/// Constructor. Initialize by a geodetic coordinate explicit SGVec3(const osg::Vec3f& d)
/// Note that this conversion is relatively expensive to compute { data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
SGVec3(const SGGeod& geod) explicit SGVec3(const osg::Vec3d& d)
{ SGGeodesy::SGGeodToCart(geod, *this); } { data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
/// Constructor. Initialize by a geocentric coordinate explicit SGVec3(const SGVec2<T>& v2, const T& v3 = 0)
/// Note that this conversion is relatively expensive to compute { data()[0] = v2[0]; data()[1] = v2[1]; data()[2] = v3; }
SGVec3(const SGGeoc& geoc)
{ SGGeodesy::SGGeocToCart(geoc, *this); }
/// Access by index, the index is unchecked /// Access by index, the index is unchecked
const T& operator()(unsigned i) const const T& operator()(unsigned i) const
{ return _data[i]; } { return data()[i]; }
/// Access by index, the index is unchecked /// Access by index, the index is unchecked
T& operator()(unsigned i) T& operator()(unsigned i)
{ return _data[i]; } { return data()[i]; }
/// Access raw data by index, the index is unchecked /// Access raw data by index, the index is unchecked
const T& operator[](unsigned i) const const T& operator[](unsigned i) const
{ return _data[i]; } { return data()[i]; }
/// Access raw data by index, the index is unchecked /// Access raw data by index, the index is unchecked
T& operator[](unsigned i) T& operator[](unsigned i)
{ return _data[i]; } { return data()[i]; }
/// Access the x component /// Access the x component
const T& x(void) const const T& x(void) const
{ return _data[0]; } { return data()[0]; }
/// Access the x component /// Access the x component
T& x(void) T& x(void)
{ return _data[0]; } { return data()[0]; }
/// Access the y component /// Access the y component
const T& y(void) const const T& y(void) const
{ return _data[1]; } { return data()[1]; }
/// Access the y component /// Access the y component
T& y(void) T& y(void)
{ return _data[1]; } { return data()[1]; }
/// Access the z component /// Access the z component
const T& z(void) const const T& z(void) const
{ return _data[2]; } { return data()[2]; }
/// Access the z component /// Access the z component
T& z(void) T& z(void)
{ return _data[2]; } { return data()[2]; }
/// Get the data pointer /// Get the data pointer
const T* data(void) const using SGVec3Storage<T>::data;
{ return _data; }
/// Get the data pointer
T* data(void)
{ return _data; }
/// Readonly interface function to ssg's sgVec3/sgdVec3 /// Readonly interface function to ssg's sgVec3/sgdVec3
const T (&sg(void) const)[3] const T (&sg(void) const)[3]
{ return _data; } { return data(); }
/// Interface function to ssg's sgVec3/sgdVec3 /// Interface function to ssg's sgVec3/sgdVec3
T (&sg(void))[3] T (&sg(void))[3]
{ return _data; } { return data(); }
/// Interface function to osg's Vec3*
using SGVec3Storage<T>::osg;
/// Inplace addition /// Inplace addition
SGVec3& operator+=(const SGVec3& v) SGVec3& operator+=(const SGVec3& v)
{ _data[0] += v(0); _data[1] += v(1); _data[2] += v(2); return *this; } { data()[0] += v(0); data()[1] += v(1); data()[2] += v(2); return *this; }
/// Inplace subtraction /// Inplace subtraction
SGVec3& operator-=(const SGVec3& v) SGVec3& operator-=(const SGVec3& v)
{ _data[0] -= v(0); _data[1] -= v(1); _data[2] -= v(2); return *this; } { data()[0] -= v(0); data()[1] -= v(1); data()[2] -= v(2); return *this; }
/// Inplace scalar multiplication /// Inplace scalar multiplication
template<typename S> template<typename S>
SGVec3& operator*=(S s) SGVec3& operator*=(S s)
{ _data[0] *= s; _data[1] *= s; _data[2] *= s; return *this; } { data()[0] *= s; data()[1] *= s; data()[2] *= s; return *this; }
/// Inplace scalar multiplication by 1/s /// Inplace scalar multiplication by 1/s
template<typename S> template<typename S>
SGVec3& operator/=(S s) SGVec3& operator/=(S s)
@@ -125,11 +171,54 @@ public:
static SGVec3 e3(void) static SGVec3 e3(void)
{ return SGVec3(0, 0, 1); } { return SGVec3(0, 0, 1); }
private: /// Constructor. Initialize by a geodetic coordinate
/// The actual data /// Note that this conversion is relatively expensive to compute
T _data[3]; static SGVec3 fromGeod(const SGGeod& geod);
/// Constructor. Initialize by a geocentric coordinate
/// Note that this conversion is relatively expensive to compute
static SGVec3 fromGeoc(const SGGeoc& geoc);
}; };
template<>
inline
SGVec3<double>
SGVec3<double>::fromGeod(const SGGeod& geod)
{
SGVec3<double> cart;
SGGeodesy::SGGeodToCart(geod, cart);
return cart;
}
template<>
inline
SGVec3<float>
SGVec3<float>::fromGeod(const SGGeod& geod)
{
SGVec3<double> cart;
SGGeodesy::SGGeodToCart(geod, cart);
return SGVec3<float>(cart(0), cart(1), cart(2));
}
template<>
inline
SGVec3<double>
SGVec3<double>::fromGeoc(const SGGeoc& geoc)
{
SGVec3<double> cart;
SGGeodesy::SGGeocToCart(geoc, cart);
return cart;
}
template<>
inline
SGVec3<float>
SGVec3<float>::fromGeoc(const SGGeoc& geoc)
{
SGVec3<double> cart;
SGGeodesy::SGGeocToCart(geoc, cart);
return SGVec3<float>(cart(0), cart(1), cart(2));
}
/// Unary +, do nothing ... /// Unary +, do nothing ...
template<typename T> template<typename T>
inline inline
@@ -172,6 +261,73 @@ SGVec3<T>
operator*(const SGVec3<T>& v, S s) operator*(const SGVec3<T>& v, S s)
{ return SGVec3<T>(s*v(0), s*v(1), s*v(2)); } { return SGVec3<T>(s*v(0), s*v(1), s*v(2)); }
/// multiplication as a multiplicator, that is assume that the first vector
/// represents a 3x3 diagonal matrix with the diagonal elements in the vector.
/// Then the result is the product of that matrix times the second vector.
template<typename T>
inline
SGVec3<T>
mult(const SGVec3<T>& v1, const SGVec3<T>& v2)
{ return SGVec3<T>(v1(0)*v2(0), v1(1)*v2(1), v1(2)*v2(2)); }
/// component wise min
template<typename T>
inline
SGVec3<T>
min(const SGVec3<T>& v1, const SGVec3<T>& v2)
{
return SGVec3<T>(SGMisc<T>::min(v1(0), v2(0)),
SGMisc<T>::min(v1(1), v2(1)),
SGMisc<T>::min(v1(2), v2(2)));
}
template<typename S, typename T>
inline
SGVec3<T>
min(const SGVec3<T>& v, S s)
{
return SGVec3<T>(SGMisc<T>::min(s, v(0)),
SGMisc<T>::min(s, v(1)),
SGMisc<T>::min(s, v(2)));
}
template<typename S, typename T>
inline
SGVec3<T>
min(S s, const SGVec3<T>& v)
{
return SGVec3<T>(SGMisc<T>::min(s, v(0)),
SGMisc<T>::min(s, v(1)),
SGMisc<T>::min(s, v(2)));
}
/// component wise max
template<typename T>
inline
SGVec3<T>
max(const SGVec3<T>& v1, const SGVec3<T>& v2)
{
return SGVec3<T>(SGMisc<T>::max(v1(0), v2(0)),
SGMisc<T>::max(v1(1), v2(1)),
SGMisc<T>::max(v1(2), v2(2)));
}
template<typename S, typename T>
inline
SGVec3<T>
max(const SGVec3<T>& v, S s)
{
return SGVec3<T>(SGMisc<T>::max(s, v(0)),
SGMisc<T>::max(s, v(1)),
SGMisc<T>::max(s, v(2)));
}
template<typename S, typename T>
inline
SGVec3<T>
max(S s, const SGVec3<T>& v)
{
return SGVec3<T>(SGMisc<T>::max(s, v(0)),
SGMisc<T>::max(s, v(1)),
SGMisc<T>::max(s, v(2)));
}
/// Scalar dot product /// Scalar dot product
template<typename T> template<typename T>
inline inline
@@ -201,6 +357,13 @@ T
norm1(const SGVec3<T>& v) norm1(const SGVec3<T>& v)
{ return fabs(v(0)) + fabs(v(1)) + fabs(v(2)); } { return fabs(v(0)) + fabs(v(1)) + fabs(v(2)); }
/// The inf-norm of the vector
template<typename T>
inline
T
normI(const SGVec3<T>& v)
{ return SGMisc<T>::max(fabs(v(0)), fabs(v(1)), fabs(v(2))); }
/// Vector cross product /// Vector cross product
template<typename T> template<typename T>
inline inline
@@ -212,6 +375,31 @@ cross(const SGVec3<T>& v1, const SGVec3<T>& v2)
v1(0)*v2(1) - v1(1)*v2(0)); v1(0)*v2(1) - v1(1)*v2(0));
} }
/// return any normalized vector perpendicular to v
template<typename T>
inline
SGVec3<T>
perpendicular(const SGVec3<T>& v)
{
T absv1 = fabs(v(0));
T absv2 = fabs(v(1));
T absv3 = fabs(v(2));
if (absv2 < absv1 && absv3 < absv1) {
T quot = v(1)/v(0);
return (1/sqrt(1+quot*quot))*SGVec3<T>(quot, -1, 0);
} else if (absv3 < absv2) {
T quot = v(2)/v(1);
return (1/sqrt(1+quot*quot))*SGVec3<T>(0, quot, -1);
} else if (SGLimits<T>::min() < absv3) {
T quot = v(0)/v(2);
return (1/sqrt(1+quot*quot))*SGVec3<T>(-1, 0, quot);
} else {
// the all zero case ...
return SGVec3<T>(0, 0, 0);
}
}
/// The euclidean norm of the vector, that is what most people call length /// The euclidean norm of the vector, that is what most people call length
template<typename T> template<typename T>
inline inline
@@ -233,6 +421,43 @@ bool
operator!=(const SGVec3<T>& v1, const SGVec3<T>& v2) operator!=(const SGVec3<T>& v1, const SGVec3<T>& v2)
{ return ! (v1 == v2); } { return ! (v1 == v2); }
/// Return true if smaller, good for putting that into a std::map
template<typename T>
inline
bool
operator<(const SGVec3<T>& v1, const SGVec3<T>& v2)
{
if (v1(0) < v2(0)) return true;
else if (v2(0) < v1(0)) return false;
else if (v1(1) < v2(1)) return true;
else if (v2(1) < v1(1)) return false;
else return (v1(2) < v2(2));
}
template<typename T>
inline
bool
operator<=(const SGVec3<T>& v1, const SGVec3<T>& v2)
{
if (v1(0) < v2(0)) return true;
else if (v2(0) < v1(0)) return false;
else if (v1(1) < v2(1)) return true;
else if (v2(1) < v1(1)) return false;
else return (v1(2) <= v2(2));
}
template<typename T>
inline
bool
operator>(const SGVec3<T>& v1, const SGVec3<T>& v2)
{ return operator<(v2, v1); }
template<typename T>
inline
bool
operator>=(const SGVec3<T>& v1, const SGVec3<T>& v2)
{ return operator<=(v2, v1); }
/// Return true if equal to the relative tolerance tol /// Return true if equal to the relative tolerance tol
template<typename T> template<typename T>
inline inline
@@ -257,6 +482,20 @@ equivalent(const SGVec3<T>& v1, const SGVec3<T>& v2)
return equivalent(v1, v2, tol, tol); return equivalent(v1, v2, tol, tol);
} }
/// The euclidean distance of the two vectors
template<typename T>
inline
T
dist(const SGVec3<T>& v1, const SGVec3<T>& v2)
{ return norm(v1 - v2); }
/// The squared euclidean distance of the two vectors
template<typename T>
inline
T
distSqr(const SGVec3<T>& v1, const SGVec3<T>& v2)
{ SGVec3<T> tmp = v1 - v2; return dot(tmp, tmp); }
#ifndef NDEBUG #ifndef NDEBUG
template<typename T> template<typename T>
inline inline
@@ -275,10 +514,6 @@ std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec3<T>& v) operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec3<T>& v)
{ return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << " ]"; } { return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << " ]"; }
/// Two classes doing actually the same on different types
typedef SGVec3<float> SGVec3f;
typedef SGVec3<double> SGVec3d;
inline inline
SGVec3f SGVec3f
toVec3f(const SGVec3d& v) toVec3f(const SGVec3d& v)
+218 -38
View File
@@ -18,9 +18,58 @@
#ifndef SGVec4_H #ifndef SGVec4_H
#define SGVec4_H #define SGVec4_H
#include <osg/Vec4f>
#include <osg/Vec4d>
template<typename T>
struct SGVec4Storage {
/// Readonly raw storage interface
const T (&data(void) const)[4]
{ return _data; }
/// Readonly raw storage interface
T (&data(void))[4]
{ return _data; }
void osg() const
{ }
private:
T _data[4];
};
template<>
struct SGVec4Storage<float> : public osg::Vec4f {
/// Access raw data by index, the index is unchecked
const float (&data(void) const)[4]
{ return osg::Vec4f::_v; }
/// Access raw data by index, the index is unchecked
float (&data(void))[4]
{ return osg::Vec4f::_v; }
const osg::Vec4f& osg() const
{ return *this; }
osg::Vec4f& osg()
{ return *this; }
};
template<>
struct SGVec4Storage<double> : public osg::Vec4d {
/// Access raw data by index, the index is unchecked
const double (&data(void) const)[4]
{ return osg::Vec4d::_v; }
/// Access raw data by index, the index is unchecked
double (&data(void))[4]
{ return osg::Vec4d::_v; }
const osg::Vec4d& osg() const
{ return *this; }
osg::Vec4d& osg()
{ return *this; }
};
/// 4D Vector Class /// 4D Vector Class
template<typename T> template<typename T>
class SGVec4 { class SGVec4 : protected SGVec4Storage<T> {
public: public:
typedef T value_type; typedef T value_type;
@@ -33,82 +82,86 @@ public:
/// uninitialized values in the debug build very fast ... /// uninitialized values in the debug build very fast ...
#ifndef NDEBUG #ifndef NDEBUG
for (unsigned i = 0; i < 4; ++i) for (unsigned i = 0; i < 4; ++i)
_data[i] = SGLimits<T>::quiet_NaN(); data()[i] = SGLimits<T>::quiet_NaN();
#endif #endif
} }
/// Constructor. Initialize by the given values /// Constructor. Initialize by the given values
SGVec4(T x, T y, T z, T w) SGVec4(T x, T y, T z, T w)
{ _data[0] = x; _data[1] = y; _data[2] = z; _data[3] = w; } { data()[0] = x; data()[1] = y; data()[2] = z; data()[3] = w; }
/// Constructor. Initialize by the content of a plain array, /// Constructor. Initialize by the content of a plain array,
/// make sure it has at least 3 elements /// make sure it has at least 3 elements
explicit SGVec4(const T* d) explicit SGVec4(const T* d)
{ _data[0] = d[0]; _data[1] = d[1]; _data[2] = d[2]; _data[3] = d[3]; } { data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
explicit SGVec4(const osg::Vec4f& d)
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
explicit SGVec4(const osg::Vec4d& d)
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
explicit SGVec4(const SGVec3<T>& v3, const T& v4 = 0)
{ data()[0] = v3[0]; data()[1] = v3[1]; data()[2] = v3[2]; data()[3] = v4; }
/// Access by index, the index is unchecked /// Access by index, the index is unchecked
const T& operator()(unsigned i) const const T& operator()(unsigned i) const
{ return _data[i]; } { return data()[i]; }
/// Access by index, the index is unchecked /// Access by index, the index is unchecked
T& operator()(unsigned i) T& operator()(unsigned i)
{ return _data[i]; } { return data()[i]; }
/// Access raw data by index, the index is unchecked /// Access raw data by index, the index is unchecked
const T& operator[](unsigned i) const const T& operator[](unsigned i) const
{ return _data[i]; } { return data()[i]; }
/// Access raw data by index, the index is unchecked /// Access raw data by index, the index is unchecked
T& operator[](unsigned i) T& operator[](unsigned i)
{ return _data[i]; } { return data()[i]; }
/// Access the x component /// Access the x component
const T& x(void) const const T& x(void) const
{ return _data[0]; } { return data()[0]; }
/// Access the x component /// Access the x component
T& x(void) T& x(void)
{ return _data[0]; } { return data()[0]; }
/// Access the y component /// Access the y component
const T& y(void) const const T& y(void) const
{ return _data[1]; } { return data()[1]; }
/// Access the y component /// Access the y component
T& y(void) T& y(void)
{ return _data[1]; } { return data()[1]; }
/// Access the z component /// Access the z component
const T& z(void) const const T& z(void) const
{ return _data[2]; } { return data()[2]; }
/// Access the z component /// Access the z component
T& z(void) T& z(void)
{ return _data[2]; } { return data()[2]; }
/// Access the x component /// Access the x component
const T& w(void) const const T& w(void) const
{ return _data[3]; } { return data()[3]; }
/// Access the x component /// Access the x component
T& w(void) T& w(void)
{ return _data[3]; } { return data()[3]; }
/// Get the data pointer
using SGVec4Storage<T>::data;
/// Get the data pointer, usefull for interfacing with plib's sg*Vec /// Readonly interface function to ssg's sgVec4/sgdVec4
const T* data(void) const
{ return _data; }
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
T* data(void)
{ return _data; }
/// Readonly interface function to ssg's sgVec3/sgdVec3
const T (&sg(void) const)[4] const T (&sg(void) const)[4]
{ return _data; } { return data(); }
/// Interface function to ssg's sgVec3/sgdVec3 /// Interface function to ssg's sgVec4/sgdVec4
T (&sg(void))[4] T (&sg(void))[4]
{ return _data; } { return data(); }
/// Interface function to osg's Vec4*
using SGVec4Storage<T>::osg;
/// Inplace addition /// Inplace addition
SGVec4& operator+=(const SGVec4& v) SGVec4& operator+=(const SGVec4& v)
{ _data[0]+=v(0);_data[1]+=v(1);_data[2]+=v(2);_data[3]+=v(3);return *this; } { data()[0]+=v(0);data()[1]+=v(1);data()[2]+=v(2);data()[3]+=v(3);return *this; }
/// Inplace subtraction /// Inplace subtraction
SGVec4& operator-=(const SGVec4& v) SGVec4& operator-=(const SGVec4& v)
{ _data[0]-=v(0);_data[1]-=v(1);_data[2]-=v(2);_data[3]-=v(3);return *this; } { data()[0]-=v(0);data()[1]-=v(1);data()[2]-=v(2);data()[3]-=v(3);return *this; }
/// Inplace scalar multiplication /// Inplace scalar multiplication
template<typename S> template<typename S>
SGVec4& operator*=(S s) SGVec4& operator*=(S s)
{ _data[0] *= s; _data[1] *= s; _data[2] *= s; _data[3] *= s; return *this; } { data()[0] *= s; data()[1] *= s; data()[2] *= s; data()[3] *= s; return *this; }
/// Inplace scalar multiplication by 1/s /// Inplace scalar multiplication by 1/s
template<typename S> template<typename S>
SGVec4& operator/=(S s) SGVec4& operator/=(S s)
@@ -126,10 +179,6 @@ public:
{ return SGVec4(0, 0, 1, 0); } { return SGVec4(0, 0, 1, 0); }
static SGVec4 e4(void) static SGVec4 e4(void)
{ return SGVec4(0, 0, 0, 1); } { return SGVec4(0, 0, 0, 1); }
private:
/// The actual data
T _data[4];
}; };
/// Unary +, do nothing ... /// Unary +, do nothing ...
@@ -174,6 +223,79 @@ SGVec4<T>
operator*(const SGVec4<T>& v, S s) operator*(const SGVec4<T>& v, S s)
{ return SGVec4<T>(s*v(0), s*v(1), s*v(2), s*v(3)); } { return SGVec4<T>(s*v(0), s*v(1), s*v(2), s*v(3)); }
/// multiplication as a multiplicator, that is assume that the first vector
/// represents a 4x4 diagonal matrix with the diagonal elements in the vector.
/// Then the result is the product of that matrix times the second vector.
template<typename T>
inline
SGVec4<T>
mult(const SGVec4<T>& v1, const SGVec4<T>& v2)
{ return SGVec4<T>(v1(0)*v2(0), v1(1)*v2(1), v1(2)*v2(2), v1(3)*v2(3)); }
/// component wise min
template<typename T>
inline
SGVec4<T>
min(const SGVec4<T>& v1, const SGVec4<T>& v2)
{
return SGVec4<T>(SGMisc<T>::min(v1(0), v2(0)),
SGMisc<T>::min(v1(1), v2(1)),
SGMisc<T>::min(v1(2), v2(2)),
SGMisc<T>::min(v1(3), v2(3)));
}
template<typename S, typename T>
inline
SGVec4<T>
min(const SGVec4<T>& v, S s)
{
return SGVec4<T>(SGMisc<T>::min(s, v(0)),
SGMisc<T>::min(s, v(1)),
SGMisc<T>::min(s, v(2)),
SGMisc<T>::min(s, v(3)));
}
template<typename S, typename T>
inline
SGVec4<T>
min(S s, const SGVec4<T>& v)
{
return SGVec4<T>(SGMisc<T>::min(s, v(0)),
SGMisc<T>::min(s, v(1)),
SGMisc<T>::min(s, v(2)),
SGMisc<T>::min(s, v(3)));
}
/// component wise max
template<typename T>
inline
SGVec4<T>
max(const SGVec4<T>& v1, const SGVec4<T>& v2)
{
return SGVec4<T>(SGMisc<T>::max(v1(0), v2(0)),
SGMisc<T>::max(v1(1), v2(1)),
SGMisc<T>::max(v1(2), v2(2)),
SGMisc<T>::max(v1(3), v2(3)));
}
template<typename S, typename T>
inline
SGVec4<T>
max(const SGVec4<T>& v, S s)
{
return SGVec4<T>(SGMisc<T>::max(s, v(0)),
SGMisc<T>::max(s, v(1)),
SGMisc<T>::max(s, v(2)),
SGMisc<T>::max(s, v(3)));
}
template<typename S, typename T>
inline
SGVec4<T>
max(S s, const SGVec4<T>& v)
{
return SGVec4<T>(SGMisc<T>::max(s, v(0)),
SGMisc<T>::max(s, v(1)),
SGMisc<T>::max(s, v(2)),
SGMisc<T>::max(s, v(3)));
}
/// Scalar dot product /// Scalar dot product
template<typename T> template<typename T>
inline inline
@@ -203,6 +325,13 @@ T
norm1(const SGVec4<T>& v) norm1(const SGVec4<T>& v)
{ return fabs(v(0)) + fabs(v(1)) + fabs(v(2)) + fabs(v(3)); } { return fabs(v(0)) + fabs(v(1)) + fabs(v(2)) + fabs(v(3)); }
/// The inf-norm of the vector
template<typename T>
inline
T
normI(const SGVec4<T>& v)
{ return SGMisc<T>::max(fabs(v(0)), fabs(v(1)), fabs(v(2)), fabs(v(2))); }
/// The euclidean norm of the vector, that is what most people call length /// The euclidean norm of the vector, that is what most people call length
template<typename T> template<typename T>
inline inline
@@ -224,6 +353,47 @@ bool
operator!=(const SGVec4<T>& v1, const SGVec4<T>& v2) operator!=(const SGVec4<T>& v1, const SGVec4<T>& v2)
{ return ! (v1 == v2); } { return ! (v1 == v2); }
/// Return true if smaller, good for putting that into a std::map
template<typename T>
inline
bool
operator<(const SGVec4<T>& v1, const SGVec4<T>& v2)
{
if (v1(0) < v2(0)) return true;
else if (v2(0) < v1(0)) return false;
else if (v1(1) < v2(1)) return true;
else if (v2(1) < v1(1)) return false;
else if (v1(2) < v2(2)) return true;
else if (v2(2) < v1(2)) return false;
else return (v1(3) < v2(3));
}
template<typename T>
inline
bool
operator<=(const SGVec4<T>& v1, const SGVec4<T>& v2)
{
if (v1(0) < v2(0)) return true;
else if (v2(0) < v1(0)) return false;
else if (v1(1) < v2(1)) return true;
else if (v2(1) < v1(1)) return false;
else if (v1(2) < v2(2)) return true;
else if (v2(2) < v1(2)) return false;
else return (v1(3) <= v2(3));
}
template<typename T>
inline
bool
operator>(const SGVec4<T>& v1, const SGVec4<T>& v2)
{ return operator<(v2, v1); }
template<typename T>
inline
bool
operator>=(const SGVec4<T>& v1, const SGVec4<T>& v2)
{ return operator<=(v2, v1); }
/// Return true if equal to the relative tolerance tol /// Return true if equal to the relative tolerance tol
template<typename T> template<typename T>
inline inline
@@ -248,6 +418,20 @@ equivalent(const SGVec4<T>& v1, const SGVec4<T>& v2)
return equivalent(v1, v2, tol, tol); return equivalent(v1, v2, tol, tol);
} }
/// The euclidean distance of the two vectors
template<typename T>
inline
T
dist(const SGVec4<T>& v1, const SGVec4<T>& v2)
{ return norm(v1 - v2); }
/// The squared euclidean distance of the two vectors
template<typename T>
inline
T
distSqr(const SGVec4<T>& v1, const SGVec4<T>& v2)
{ SGVec4<T> tmp = v1 - v2; return dot(tmp, tmp); }
#ifndef NDEBUG #ifndef NDEBUG
template<typename T> template<typename T>
inline inline
@@ -266,10 +450,6 @@ std::basic_ostream<char_type, traits_type>&
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec4<T>& v) operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec4<T>& v)
{ return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; } { return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; }
/// Two classes doing actually the same on different types
typedef SGVec4<float> SGVec4f;
typedef SGVec4<double> SGVec4d;
inline inline
SGVec4f SGVec4f
toVec4f(const SGVec4d& v) toVec4f(const SGVec4d& v)
-291
View File
@@ -1,291 +0,0 @@
/*
* \file fastmath.cxx
* fast mathematics routines.
*
* Refferences:
*
* A Fast, Compact Approximation of the Exponential Function
* Nicol N. Schraudolph
* 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
*/
/*
* $Id$
*/
#include <simgear/constants.h>
#include "fastmath.hxx"
/**
* This function is on avarage 9 times faster than the system exp() function
* and has an error of about 1.5%
*/
static union {
double d;
struct {
#if BYTE_ORDER == BIG_ENDIAN
int i, j;
#else
int j, i;
#endif
} n;
} _eco;
double fast_exp(double val) {
const double a = 1048576/M_LN2;
const double b_c = 1072632447; /* 1072693248 - 60801 */
_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?
* Float Shift Left and Float Shift Right. Do what you want with this.
*/
void fast_BSL(float &x, register unsigned long shiftAmount) {
*(unsigned long*)&x+=shiftAmount<<23;
}
void fast_BSR(float &x, register unsigned long shiftAmount) {
*(unsigned long*)&x-=shiftAmount<<23;
}
/*
* 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;
}
-116
View File
@@ -1,116 +0,0 @@
/*
* \file fastmath.hxx
* fast mathematics routines.
*
* References:
*
* A Fast, Compact Approximation of the Exponential Function
* Nicol N. Schraudolph
* IDSIA, Lugano, Switzerland
* http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf
*
* Fast log() Function, by Laurent de Soras:
* http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-Fastlogfunction&forum=totd&id=-1
*
*/
/*
* $Id$
*/
#ifndef _SG_FMATH_HXX
#define _SG_FMATH_HXX 1
#ifndef __cplusplus
# error This library requires C++
#endif
#include <math.h>
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)
{
union {
float f;
int i;
} v;
v.f = val;
const int log_2 = ((v.i >> 23) & 255) - 128;
v.i &= ~(255 << 23);
v.i += 127 << 23;
v.f = ((-1.0f/3) * v.f + 2) * v.f - 2.0f/3; // (1)
return (v.f + log_2);
}
/**
* This function is about 3 times faster than the system log() function
* and has an error of about 0.01%
*/
inline float fast_log (const float &val)
{
return (fast_log2 (val) * 0.69314718f);
}
inline float fast_log10 (const float &val)
{
return (fast_log2(val) / 3.321928095f);
}
/**
* 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
+43 -47
View File
@@ -25,12 +25,11 @@
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <stdlib.h> // for exit()
#include STL_STRING #include STL_STRING
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx> #include <simgear/misc/sgstream.hxx>
#include <simgear/props/props.hxx>
#include "interpolater.hxx" #include "interpolater.hxx"
@@ -38,22 +37,29 @@ SG_USING_STD(string);
// Constructor -- starts with an empty table. // Constructor -- starts with an empty table.
SGInterpTable::SGInterpTable() SGInterpTable::SGInterpTable()
: size(0)
{ {
} }
SGInterpTable::SGInterpTable(const SGPropertyNode* interpolation)
{
if (!interpolation)
return;
std::vector<SGPropertyNode_ptr> entries = interpolation->getChildren("entry");
for (unsigned i = 0; i < entries.size(); ++i)
addEntry(entries[i]->getDoubleValue("ind", 0.0),
entries[i]->getDoubleValue("dep", 0.0));
}
// Constructor -- loads the interpolation table from the specified // Constructor -- loads the interpolation table from the specified
// file // file
SGInterpTable::SGInterpTable( const string& file ) SGInterpTable::SGInterpTable( const string& file )
: size(0)
{ {
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file ); SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
sg_gzifstream in( file ); sg_gzifstream in( file );
if ( !in.is_open() ) { if ( !in.is_open() ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file ); SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
exit(-1); return;
} }
in >> skipcomment; in >> skipcomment;
@@ -61,8 +67,7 @@ SGInterpTable::SGInterpTable( const string& file )
double ind, dep; double ind, dep;
in >> ind >> dep; in >> ind >> dep;
in >> skipws; in >> skipws;
table.push_back(Entry(ind, dep)); _table[ind] = dep;
size++;
} }
} }
@@ -70,51 +75,42 @@ SGInterpTable::SGInterpTable( const string& file )
// Add an entry to the table. // Add an entry to the table.
void SGInterpTable::addEntry (double ind, double dep) void SGInterpTable::addEntry (double ind, double dep)
{ {
table.push_back(Entry(ind,dep)); _table[ind] = dep;
size++;
} }
// Given an x value, linearly interpolate the y value from the table // Given an x value, linearly interpolate the y value from the table
double SGInterpTable::interpolate(double x) const double SGInterpTable::interpolate(double x) const
{ {
int i; // Empty table??
double y; if (_table.empty())
return 0;
if (size == 0.0) {
return 0.0; // Find the table bounds for the requested input.
} Table::const_iterator upBoundIt = _table.upper_bound(x);
// points to a value outside the map. That is we are out of range.
i = 0; // use the last entry
if (upBoundIt == _table.end())
while ( (i < size) && (x > table[i].ind) ) { return _table.rbegin()->second;
// cout << " i = " << i << " table[i].ind = " << table[i].ind << endl;
// cout << " size = " << size << endl; // points to the first key must be lower
i++; // use the first entry
} if (upBoundIt == _table.begin())
return upBoundIt->second;
// printf ("i = %d ", i);
// we know that we do not stand at the beginning, so it is safe to do so
if ( i <= 0 ) { Table::const_iterator loBoundIt = upBoundIt;
SG_LOG( SG_MATH, SG_DEBUG, --loBoundIt;
"interpolate(): lookup error, x to small = " << x );
return table[0].dep; // Just do linear interpolation.
} double loBound = loBoundIt->first;
double upBound = upBoundIt->first;
// cout << " table[size-1].ind = " << table[size-1].ind << endl; double loVal = loBoundIt->second;
if ( i >= size ) { double upVal = upBoundIt->second;
SG_LOG( SG_MATH, SG_DEBUG,
"interpolate(): lookup error, x to big = " << x ); // division by zero should not happen since the std::map
return table[size-1].dep; // has sorted out duplicate entries before. Also since we have a
} // map, we know that we get different first values for different iterators
return loVal + (upVal - loVal)*(x - loBound)/(upBound - loBound);
// y = y1 + (y0 - y1)(x - x1) / (x0 - x1)
y = table[i].dep +
( (table[i-1].dep - table[i].dep) *
(x - table[i].ind) ) /
(table[i-1].ind - table[i].ind);
return(y);
} }
+16 -17
View File
@@ -35,12 +35,14 @@
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <vector> #include "simgear/structure/SGReferenced.hxx"
SG_USING_STD(vector);
#include <map>
#include STL_STRING #include STL_STRING
SG_USING_STD(string); SG_USING_STD(string);
class SGPropertyNode;
/** /**
* A class that provids a simple linear 2d interpolation lookup table. * A class that provids a simple linear 2d interpolation lookup table.
@@ -48,21 +50,7 @@ SG_USING_STD(string);
* independant variable must be strictly ascending. The dependent * independant variable must be strictly ascending. The dependent
* variable can be anything. * variable can be anything.
*/ */
class SGInterpTable { class SGInterpTable : public SGReferenced {
struct Entry
{
Entry ()
: ind(0.0L), dep(0.0L) {}
Entry (double independent, double dependent)
: ind(independent), dep(dependent) {}
double ind;
double dep;
};
int size;
vector<Entry> table;
public: public:
/** /**
@@ -70,6 +58,13 @@ public:
*/ */
SGInterpTable(); SGInterpTable();
/**
* Constructor. Loads the interpolation table from an interpolation
* property node.
* @param interpolation property node having entry children
*/
SGInterpTable(const SGPropertyNode* interpolation);
/** /**
* Constructor. Loads the interpolation table from the specified file. * Constructor. Loads the interpolation table from the specified file.
* @param file name of interpolation file * @param file name of interpolation file
@@ -95,6 +90,10 @@ public:
/** Destructor */ /** Destructor */
~SGInterpTable(); ~SGInterpTable();
private:
typedef std::map<double, double> Table;
Table _table;
}; };
-110
View File
@@ -1,110 +0,0 @@
/*
WARNING - Do not remove this header.
This code is a templated version of the 'magic-software' spherical
interpolation code by Dave Eberly. The original (un-hacked) code can be
obtained from here: http://www.magic-software.com/gr_appr.htm
This code is derived from linintp2.h/cpp and sphrintp.h/cpp.
Dave Eberly says that the conditions for use are:
* You may distribute the original source code to others at no charge.
* You may modify the original source code and distribute it to others at
no charge. The modified code must be documented to indicate that it is
not part of the original package.
* You may use this code for non-commercial purposes. You may also
incorporate this code into commercial packages. However, you may not
sell any of your source code which contains my original and/or modified
source code. In such a case, you need to factor out my code and freely
distribute it.
* The original code comes with absolutely no warranty and no guarantee is
made that the code is bug-free.
This does not seem incompatible with GPL - so this modified version
is hereby placed under GPL along with the rest of FlightGear.
Christian Mayer
*/
#ifndef LININTP2_H
#define LININTP2_H
template<class T>
class mgcLinInterp2D
{
public:
mgcLinInterp2D (int _numPoints, double* x, double* y, T* _f);
~mgcLinInterp2D ();
double XMin () { return xmin; }
double XMax () { return xmax; }
double XRange () { return xmax-xmin; }
double YMin () { return ymin; }
double YMax () { return ymax; }
double YRange () { return ymax-ymin; }
int PointCount () { return numPoints; }
void GetPoint (int i, double& x, double& y);
int EdgeCount () { return numEdges; }
void GetEdge (int i, double& x0, double& y0, double& x1, double& y1);
int TriangleCount () { return numTriangles; }
void GetTriangle (int i, double& x0, double& y0, double& x1, double& y1,
double& x2, double& y2);
int Evaluate (double x, double y, T& F);
private:
typedef struct
{
double x, y;
}
Vertex;
typedef struct
{
int vertex[3]; // listed in counterclockwise order
int adj[3];
// adj[0] points to triangle sharing edge (vertex[0],vertex[1])
// adj[1] points to triangle sharing edge (vertex[1],vertex[2])
// adj[2] points to triangle sharing edge (vertex[2],vertex[0])
}
Triangle;
typedef struct
{
int vertex[2];
int triangle[2];
int index[2];
}
Edge;
int numPoints;
double** point;
double** tmppoint;
T* f;
double xmin, xmax, ymin, ymax;
int numEdges;
Edge* edge;
int numTriangles;
Triangle* triangle;
int Delaunay2D ();
void ComputeBarycenter (Vertex& v0, Vertex& v1, Vertex& v2, Vertex& ver,
double c[3]);
int InTriangle (Vertex& v0, Vertex& v1, Vertex& v2, Vertex& test);
};
#include "linintp2.inl"
#endif
-540
View File
@@ -1,540 +0,0 @@
/*
WARNING - Do not remove this header.
This code is a templated version of the 'magic-software' spherical
interpolation code by Dave Eberly. The original (un-hacked) code can be
obtained from here: http://www.magic-software.com/gr_appr.htm
This code is derived from linintp2.h/cpp and sphrintp.h/cpp.
Dave Eberly says that the conditions for use are:
* You may distribute the original source code to others at no charge.
* You may modify the original source code and distribute it to others at
no charge. The modified code must be documented to indicate that it is
not part of the original package.
* You may use this code for non-commercial purposes. You may also
incorporate this code into commercial packages. However, you may not
sell any of your source code which contains my original and/or modified
source code. In such a case, you need to factor out my code and freely
distribute it.
* The original code comes with absolutely no warranty and no guarantee is
made that the code is bug-free.
This does not seem incompatible with GPL - so this modified version
is hereby placed under GPL along with the rest of FlightGear.
Christian Mayer
*/
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include "linintp2.h"
//---------------------------------------------------------------------------
template<class T>
mgcLinInterp2D<T>::mgcLinInterp2D (int _numPoints, double* x, double* y,
T* _f)
{
if ( (numPoints = _numPoints) < 3 )
{
point = 0;
edge = 0;
triangle = 0;
numTriangles = 0;
return;
}
// cout << "[ 20%] allocating memory \r";
point = new double*[numPoints];
tmppoint = new double*[numPoints+3];
f = new T[numPoints];
int i;
for (i = 0; i < numPoints; i++)
point[i] = new double[2];
for (i = 0; i < numPoints+3; i++)
tmppoint[i] = new double[2];
for (i = 0; i < numPoints; i++)
{
point[i][0] = tmppoint[i][0] = x[i];
point[i][1] = tmppoint[i][1] = y[i];
f[i] = _f[i];
}
// cout << "[ 30%] creating delaunay diagram \r";
Delaunay2D();
}
//---------------------------------------------------------------------------
template<class T>
mgcLinInterp2D<T>::~mgcLinInterp2D ()
{
if ( numPoints < 3 )
return;
int i;
if ( point )
{
for (i = 0; i < numPoints; i++)
delete[] point[i];
delete[] point;
}
if ( tmppoint )
{
for (i = 0; i < numPoints+3; i++)
delete[] tmppoint[i];
delete[] tmppoint;
}
delete[] f;
delete[] edge;
delete[] triangle;
}
//---------------------------------------------------------------------------
template<class T>
void mgcLinInterp2D<T>::ComputeBarycenter (Vertex& v0, Vertex& v1, Vertex& v2,
Vertex& ver, double c[3])
{
double A0 = v0.x-v2.x, B0 = v0.y-v2.y;
double A1 = v1.x-v2.x, B1 = v1.y-v2.y;
double A2 = ver.x-v2.x, B2 = ver.y-v2.y;
double m00 = A0*A0+B0*B0, m01 = A0*A1+B0*B1, m11 = A1*A1+B1*B1;
double r0 = A2*A0+B2*B0, r1 = A2*A1+B2*B1;
double det = m00*m11-m01*m01;
c[0] = (m11*r0-m01*r1)/det;
c[1] = (m00*r1-m01*r0)/det;
c[2] = 1-c[0]-c[1];
}
//---------------------------------------------------------------------------
template<class T>
int mgcLinInterp2D<T>::InTriangle (Vertex& v0, Vertex& v1, Vertex& v2,
Vertex& test)
{
const double eps = 1e-08;
double tx, ty, nx, ny;
// test against normal to first edge
tx = test.x - v0.x;
ty = test.y - v0.y;
nx = v0.y - v1.y;
ny = v1.x - v0.x;
if ( tx*nx + ty*ny < -eps )
return 0;
// test against normal to second edge
tx = test.x - v1.x;
ty = test.y - v1.y;
nx = v1.y - v2.y;
ny = v2.x - v1.x;
if ( tx*nx + ty*ny < -eps )
return 0;
// test against normal to third edge
tx = test.x - v2.x;
ty = test.y - v2.y;
nx = v2.y - v0.y;
ny = v0.x - v2.x;
if ( tx*nx + ty*ny < -eps )
return 0;
return 1;
}
//---------------------------------------------------------------------------
template<class T>
int mgcLinInterp2D<T>::Evaluate (double x, double y, T& F)
{
Vertex ver = { x, y };
// determine which triangle contains the target point
int i;
Vertex v0, v1, v2;
for (i = 0; i < numTriangles; i++)
{
Triangle& t = triangle[i];
v0.x = point[t.vertex[0]][0];
v0.y = point[t.vertex[0]][1];
v1.x = point[t.vertex[1]][0];
v1.y = point[t.vertex[1]][1];
v2.x = point[t.vertex[2]][0];
v2.y = point[t.vertex[2]][1];
if ( InTriangle(v0,v1,v2,ver) )
break;
}
if ( i == numTriangles ) // point is outside interpolation region
{
return 0;
}
Triangle& t = triangle[i]; // (x,y) is in this triangle
// compute barycentric coordinates with respect to subtriangle
double bary[3];
ComputeBarycenter(v0,v1,v2,ver,bary);
// compute barycentric combination of function values at vertices
F = bary[0]*f[t.vertex[0]]+bary[1]*f[t.vertex[1]]+bary[2]*f[t.vertex[2]];
return 1;
}
//---------------------------------------------------------------------------
template<class T>
int mgcLinInterp2D<T>::Delaunay2D ()
{
int result;
const double EPSILON = 1e-12;
const int TSIZE = 75;
const double RANGE = 10.0;
xmin = tmppoint[0][0];
xmax = xmin;
ymin = tmppoint[0][1];
ymax = ymin;
int i;
for (i = 0; i < numPoints; i++)
{
double value = tmppoint[i][0];
if ( xmax < value )
xmax = value;
if ( xmin > value )
xmin = value;
value = tmppoint[i][1];
if ( ymax < value )
ymax = value;
if ( ymin > value )
ymin = value;
}
double xrange = xmax-xmin, yrange = ymax-ymin;
double maxrange = xrange;
if ( maxrange < yrange )
maxrange = yrange;
// need to scale the data later to do a correct triangle count
double maxrange2 = maxrange*maxrange;
// tweak the points by very small random numbers
double bgs = EPSILON*maxrange;
srand(367);
for (i = 0; i < numPoints; i++)
{
tmppoint[i][0] += bgs*(0.5 - rand()/double(RAND_MAX));
tmppoint[i][1] += bgs*(0.5 - rand()/double(RAND_MAX));
}
double wrk[2][3] =
{
{ 5*RANGE, -RANGE, -RANGE },
{ -RANGE, 5*RANGE, -RANGE }
};
for (i = 0; i < 3; i++)
{
tmppoint[numPoints+i][0] = xmin+xrange*wrk[0][i];
tmppoint[numPoints+i][1] = ymin+yrange*wrk[1][i];
}
int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i11;
int nts, ii[3];
double xx;
int tsz = 2*TSIZE;
int** tmp = new int*[tsz+1];
tmp[0] = new int[2*(tsz+1)];
for (i0 = 1; i0 < tsz+1; i0++)
tmp[i0] = tmp[0] + 2*i0;
i1 = 2*(numPoints + 2);
int* id = new int[i1];
for (i0 = 0; i0 < i1; i0++)
id[i0] = i0;
int** a3s = new int*[i1];
a3s[0] = new int[3*i1];
for (i0 = 1; i0 < i1; i0++)
a3s[i0] = a3s[0] + 3*i0;
a3s[0][0] = numPoints;
a3s[0][1] = numPoints+1;
a3s[0][2] = numPoints+2;
double** ccr = new double*[i1]; // circumscribed centers and radii
ccr[0] = new double[3*i1];
for (i0 = 1; i0 < i1; i0++)
ccr[i0] = ccr[0] + 3*i0;
ccr[0][0] = 0.0;
ccr[0][1] = 0.0;
ccr[0][2] = FLT_MAX;
nts = 1; // number of triangles
i4 = 1;
// cout << "[ 40%] create triangulation \r";
// compute triangulation
for (i0 = 0; i0 < numPoints; i0++)
{
i1 = i7 = -1;
i9 = 0;
for (i11 = 0; i11 < nts; i11++)
{
i1++;
while ( a3s[i1][0] < 0 )
i1++;
xx = ccr[i1][2];
for (i2 = 0; i2 < 2; i2++)
{
double z = tmppoint[i0][i2]-ccr[i1][i2];
xx -= z*z;
if ( xx < 0 )
goto Corner3;
}
i9--;
i4--;
id[i4] = i1;
for (i2 = 0; i2 < 3; i2++)
{
ii[0] = 0;
if (ii[0] == i2)
ii[0]++;
for (i3 = 1; i3 < 2; i3++)
{
ii[i3] = ii[i3-1] + 1;
if (ii[i3] == i2)
ii[i3]++;
}
if ( i7 > 1 )
{
i8 = i7;
for (i3 = 0; i3 <= i8; i3++)
{
for (i5 = 0; i5 < 2; i5++)
if ( a3s[i1][ii[i5]] != tmp[i3][i5] )
goto Corner1;
for (i6 = 0; i6 < 2; i6++)
tmp[i3][i6] = tmp[i8][i6];
i7--;
goto Corner2;
Corner1:;
}
}
if ( ++i7 > tsz )
{
// temporary storage exceeded, increase TSIZE
result = 0;
goto ExitDelaunay;
}
for (i3 = 0; i3 < 2; i3++)
tmp[i7][i3] = a3s[i1][ii[i3]];
Corner2:;
}
a3s[i1][0] = -1;
Corner3:;
}
for (i1 = 0; i1 <= i7; i1++)
{
for (i2 = 0; i2 < 2; i2++)
for (wrk[i2][2] = 0, i3 = 0; i3 < 2; i3++)
{
wrk[i2][i3] = tmppoint[tmp[i1][i2]][i3]-tmppoint[i0][i3];
wrk[i2][2] +=
0.5*wrk[i2][i3]*(tmppoint[tmp[i1][i2]][i3]+
tmppoint[i0][i3]);
}
xx = wrk[0][0]*wrk[1][1]-wrk[1][0]*wrk[0][1];
ccr[id[i4]][0] = (wrk[0][2]*wrk[1][1]-wrk[1][2]*wrk[0][1])/xx;
ccr[id[i4]][1] = (wrk[0][0]*wrk[1][2]-wrk[1][0]*wrk[0][2])/xx;
for (ccr[id[i4]][2] = 0, i2 = 0; i2 < 2; i2++)
{
double z = tmppoint[i0][i2]-ccr[id[i4]][i2];
ccr[id[i4]][2] += z*z;
a3s[id[i4]][i2] = tmp[i1][i2];
}
a3s[id[i4]][2] = i0;
i4++;
i9++;
}
nts += i9;
}
// count the number of triangles
// cout << "[ 50%] count the number of triangles \r";
numTriangles = 0;
i0 = -1;
for (i11 = 0; i11 < nts; i11++)
{
i0++;
while ( a3s[i0][0] < 0 )
i0++;
if ( a3s[i0][0] < numPoints )
{
for (i1 = 0; i1 < 2; i1++)
for (i2 = 0; i2 < 2; i2++)
wrk[i1][i2] =
tmppoint[a3s[i0][i1]][i2]-tmppoint[a3s[i0][2]][i2];
if ( fabs(wrk[0][0]*wrk[1][1]-wrk[0][1]*wrk[1][0]) > EPSILON*maxrange2 )
numTriangles++;
}
}
// create the triangles
// cout << "[ 60%] create the triangles \r";
triangle = new Triangle[numTriangles];
numTriangles = 0;
i0 = -1;
for (i11 = 0; i11 < nts; i11++)
{
i0++;
while ( a3s[i0][0] < 0 )
i0++;
if ( a3s[i0][0] < numPoints )
{
for (i1 = 0; i1 < 2; i1++)
for (i2 = 0; i2 < 2; i2++)
wrk[i1][i2] =
tmppoint[a3s[i0][i1]][i2]-tmppoint[a3s[i0][2]][i2];
xx = wrk[0][0]*wrk[1][1]-wrk[0][1]*wrk[1][0];
if ( fabs(xx) > EPSILON*maxrange2 )
{
int delta = xx < 0 ? 1 : 0;
Triangle& tri = triangle[numTriangles];
tri.vertex[0] = a3s[i0][0];
tri.vertex[1] = a3s[i0][1+delta];
tri.vertex[2] = a3s[i0][2-delta];
tri.adj[0] = -1;
tri.adj[1] = -1;
tri.adj[2] = -1;
numTriangles++;
}
}
}
// build edge table
// cout << "[ 70%] build the edge table \r";
numEdges = 0;
edge = new Edge[3*numTriangles];
int j, j0, j1;
for (i = 0; i < numTriangles; i++)
{
// if ( (i%500) == 0)
// cout << "[ 7" << 10*i/numTriangles << "%] build the edge table \r";
Triangle& t = triangle[i];
for (j0 = 0, j1 = 1; j0 < 3; j0++, j1 = (j1+1)%3)
{
for (j = 0; j < numEdges; j++)
{
Edge& e = edge[j];
if ( (t.vertex[j0] == e.vertex[0]
&& t.vertex[j1] == e.vertex[1])
|| (t.vertex[j0] == e.vertex[1]
&& t.vertex[j1] == e.vertex[0]) )
break;
}
if ( j == numEdges ) // add edge to table
{
edge[j].vertex[0] = t.vertex[j0];
edge[j].vertex[1] = t.vertex[j1];
edge[j].triangle[0] = i;
edge[j].index[0] = j0;
edge[j].triangle[1] = -1;
numEdges++;
}
else // edge already exists, add triangle to table
{
edge[j].triangle[1] = i;
edge[j].index[1] = j0;
}
}
}
// establish links between adjacent triangles
// cout << "[ 80%] establishing links between adjacent triangles \r";
for (i = 0; i < numEdges; i++)
{
if ( edge[i].triangle[1] != -1 )
{
j0 = edge[i].triangle[0];
j1 = edge[i].triangle[1];
triangle[j0].adj[edge[i].index[0]] = j1;
triangle[j1].adj[edge[i].index[1]] = j0;
}
}
result = 1;
ExitDelaunay:;
delete[] tmp[0];
delete[] tmp;
delete[] id;
delete[] a3s[0];
delete[] a3s;
delete[] ccr[0];
delete[] ccr;
// cout << "[ 90%] finsishes delauney triangulation \r";
return result;
}
//---------------------------------------------------------------------------
template<class T>
void mgcLinInterp2D<T>::GetPoint (int i, double& x, double& y)
{
// assumes i is valid [can use PointCount() before passing i]
x = point[i][0];
y = point[i][1];
}
//---------------------------------------------------------------------------
template<class T>
void mgcLinInterp2D<T>::GetEdge (int i, double& x0, double& y0, double& x1,
double& y1)
{
// assumes i is valid [can use EdgeCount() before passing i]
int v0 = edge[i].vertex[0], v1 = edge[i].vertex[1];
x0 = point[v0][0];
y0 = point[v0][1];
x1 = point[v1][0];
y1 = point[v1][1];
}
//---------------------------------------------------------------------------
template<class T>
void mgcLinInterp2D<T>::GetTriangle (int i, double& x0, double& y0, double& x1,
double& y1, double& x2, double& y2)
{
// assumes i is valid [can use TriangleCount() before passing i]
int v0 = triangle[i].vertex[0];
int v1 = triangle[i].vertex[1];
int v2 = triangle[i].vertex[2];
x0 = point[v0][0];
y0 = point[v0][1];
x1 = point[v1][0];
y1 = point[v1][1];
x2 = point[v2][0];
y2 = point[v2][1];
}
//---------------------------------------------------------------------------
+39
View File
@@ -97,6 +97,8 @@ public:
static Point3D fromSGGeod(const SGGeod& geod); static Point3D fromSGGeod(const SGGeod& geod);
static Point3D fromSGGeoc(const SGGeoc& geoc); static Point3D fromSGGeoc(const SGGeoc& geoc);
static Point3D fromSGVec3(const SGVec3<double>& cart); static Point3D fromSGVec3(const SGVec3<double>& cart);
static Point3D fromSGVec3(const SGVec3<float>& cart);
static Point3D fromSGVec2(const SGVec2<double>& cart);
// Assignment operators // Assignment operators
@@ -132,6 +134,10 @@ public:
SGGeod toSGGeod(void) const; SGGeod toSGGeod(void) const;
SGGeoc toSGGeoc(void) const; SGGeoc toSGGeoc(void) const;
SGVec3d toSGVec3d(void) const;
SGVec3f toSGVec3f(void) const;
SGVec2f toSGVec2f(void) const;
// friends // friends
friend Point3D operator - (const Point3D& p); // -p1 friend Point3D operator - (const Point3D& p); // -p1
friend bool operator == (const Point3D& a, const Point3D& b); // p1 == p2? friend bool operator == (const Point3D& a, const Point3D& b); // p1 == p2?
@@ -239,6 +245,24 @@ inline Point3D Point3D::fromSGVec3(const SGVec3<double>& cart)
return pt; return pt;
} }
inline Point3D Point3D::fromSGVec3(const SGVec3<float>& cart)
{
Point3D pt;
pt.setx(cart.x());
pt.sety(cart.y());
pt.setz(cart.z());
return pt;
}
inline Point3D Point3D::fromSGVec2(const SGVec2<double>& cart)
{
Point3D pt;
pt.setx(cart.x());
pt.sety(cart.y());
pt.setz(0);
return pt;
}
// ASSIGNMENT OPERATORS // ASSIGNMENT OPERATORS
inline Point3D& Point3D::operator = (const Point3D& p) inline Point3D& Point3D::operator = (const Point3D& p)
@@ -341,6 +365,21 @@ inline SGGeoc Point3D::toSGGeoc(void) const
return geoc; return geoc;
} }
inline SGVec3d Point3D::toSGVec3d(void) const
{
return SGVec3d(x(), y(), z());
}
inline SGVec3f Point3D::toSGVec3f(void) const
{
return SGVec3f(x(), y(), z());
}
inline SGVec2f Point3D::toSGVec2f(void) const
{
return SGVec2f(x(), y());
}
// FRIENDS // FRIENDS
inline Point3D operator - (const Point3D& a) inline Point3D operator - (const Point3D& a)
+9 -11
View File
@@ -73,10 +73,9 @@ static inline double M0( double e2 ) {
} }
// given, alt, lat1, lon1, az1 and distance (s), calculate lat2, lon2 // given, lat1, lon1, az1 and distance (s), calculate lat2, lon2
// and az2. Lat, lon, and azimuth are in degrees. distance in meters // and az2. Lat, lon, and azimuth are in degrees. distance in meters
int geo_direct_wgs_84 ( double alt, double lat1, int geo_direct_wgs_84 ( double lat1, double lon1, double az1,
double lon1, double az1,
double s, double *lat2, double *lon2, double s, double *lat2, double *lon2,
double *az2 ) double *az2 )
{ {
@@ -160,16 +159,15 @@ int geo_direct_wgs_84 ( double alt, double lat1,
double dM = a*M0(e2) - s; double dM = a*M0(e2) - s;
double paz = ( phi1 < 0.0 ? 180.0 : 0.0 ); double paz = ( phi1 < 0.0 ? 180.0 : 0.0 );
double zero = 0.0f; double zero = 0.0f;
return geo_direct_wgs_84( alt, zero, lon1, paz, dM, lat2, lon2, az2 ); return geo_direct_wgs_84( zero, lon1, paz, dM, lat2, lon2, az2 );
} }
} }
// given alt, lat1, lon1, lat2, lon2, calculate starting and ending // given lat1, lon1, lat2, lon2, calculate starting and ending
// az1, az2 and distance (s). Lat, lon, and azimuth are in degrees. // az1, az2 and distance (s). Lat, lon, and azimuth are in degrees.
// distance in meters // distance in meters
int geo_inverse_wgs_84( double alt, double lat1, int geo_inverse_wgs_84( double lat1, double lon1, double lat2,
double lon1, double lat2,
double lon2, double *az1, double *az2, double lon2, double *az1, double *az2,
double *s ) double *s )
{ {
@@ -192,14 +190,14 @@ int geo_inverse_wgs_84( double alt, double lat1,
return 0; return 0;
} else if( fabs(cosphi1) < testv ) { } else if( fabs(cosphi1) < testv ) {
// initial point is polar // initial point is polar
int k = geo_inverse_wgs_84( alt, lat2,lon2,lat1,lon1, az1,az2,s ); int k = geo_inverse_wgs_84( lat2,lon2,lat1,lon1, az1,az2,s );
k = k; // avoid compiler error since return result is unused k = k; // avoid compiler error since return result is unused
b = *az1; *az1 = *az2; *az2 = b; b = *az1; *az1 = *az2; *az2 = b;
return 0; return 0;
} else if( fabs(cosphi2) < testv ) { } else if( fabs(cosphi2) < testv ) {
// terminal point is polar // terminal point is polar
double _lon1 = lon1 + 180.0f; double _lon1 = lon1 + 180.0f;
int k = geo_inverse_wgs_84( alt, lat1, lon1, lat1, _lon1, int k = geo_inverse_wgs_84( lat1, lon1, lat1, _lon1,
az1, az2, s ); az1, az2, s );
k = k; // avoid compiler error since return result is unused k = k; // avoid compiler error since return result is unused
*s /= 2.0; *s /= 2.0;
@@ -211,8 +209,8 @@ int geo_inverse_wgs_84( double alt, double lat1,
{ {
// Geodesic passes through the pole (antipodal) // Geodesic passes through the pole (antipodal)
double s1,s2; double s1,s2;
geo_inverse_wgs_84( alt, lat1,lon1, lat1,lon2, az1,az2, &s1 ); geo_inverse_wgs_84( lat1,lon1, lat1,lon2, az1,az2, &s1 );
geo_inverse_wgs_84( alt, lat2,lon2, lat1,lon2, az1,az2, &s2 ); geo_inverse_wgs_84( lat2,lon2, lat1,lon2, az1,az2, &s2 );
*az2 = *az1; *az2 = *az1;
*s = s1 + s2; *s = s1 + s2;
return 0; return 0;
+54 -20
View File
@@ -4,18 +4,6 @@
#include <simgear/math/point3d.hxx> #include <simgear/math/point3d.hxx>
#include "SGMath.hxx" #include "SGMath.hxx"
// Returns the insersection of the line joining the center of the
// earth and the specified cylindrical point with the surface of the
// WGS84 ellipsoid. Works by finding a normalization constant (in
// squashed space) that places the squashed point on the surface of
// the sphere.
inline double seaLevelRadius(double r, double z)
{
double sr = r * SGGeodesy::SQUASH;
double zz = z*z;
return SGGeodesy::POLRAD*sqrt((r*r + zz)/(sr*sr + zz));
}
/** /**
* Convert from geocentric coordinates to geodetic coordinates * Convert from geocentric coordinates to geodetic coordinates
* @param lat_geoc (in) Geocentric latitude, radians, + = North * @param lat_geoc (in) Geocentric latitude, radians, + = North
@@ -56,11 +44,12 @@ inline void sgGeodToGeoc(double lat_geod, double alt,
double *sl_radius, double *lat_geoc) double *sl_radius, double *lat_geoc)
{ {
SGVec3<double> cart; SGVec3<double> cart;
SGGeodesy::SGGeodToCart(SGGeod::fromRadM(0, lat_geod, alt), cart); SGGeod geod = SGGeod::fromRadM(0, lat_geod, alt);
SGGeodesy::SGGeodToCart(geod, cart);
SGGeoc geoc; SGGeoc geoc;
SGGeodesy::SGCartToGeoc(cart, geoc); SGGeodesy::SGCartToGeoc(cart, geoc);
*lat_geoc = geoc.getLatitudeRad(); *lat_geoc = geoc.getLatitudeRad();
*sl_radius = seaLevelRadius(cart(0), cart(2)); *sl_radius = SGGeodesy::SGGeodToSeaLevelRadius(geod);
} }
@@ -130,7 +119,7 @@ inline Point3D sgGeodToCart(const Point3D& geod)
/** /**
* Given a starting position and an offset radial and distance, * Given a starting position and an offset radial and distance,
* calculate an ending positon on a wgs84 ellipsoid. * calculate an ending positon on a wgs84 ellipsoid.
* @param alt (in) meters * @param alt (in) meters (unused)
* @param lat1 (in) degrees * @param lat1 (in) degrees
* @param lon1 (in) degrees * @param lon1 (in) degrees
* @param az1 (in) degrees * @param az1 (in) degrees
@@ -139,16 +128,39 @@ inline Point3D sgGeodToCart(const Point3D& geod)
* @param lon2 (out) degrees * @param lon2 (out) degrees
* @param az2 (out) return course in degrees * @param az2 (out) return course in degrees
*/ */
int geo_direct_wgs_84 ( double alt, double lat1, int geo_direct_wgs_84 ( double lat1, double lon1, double az1,
double lon1, double az1,
double s, double *lat2, double *lon2, double s, double *lat2, double *lon2,
double *az2 ); double *az2 );
inline int geo_direct_wgs_84 ( double alt, double lat1,
double lon1, double az1,
double s, double *lat2, double *lon2,
double *az2 )
{ return geo_direct_wgs_84(lat1, lon1, az1, s, lat2, lon2, az2); }
/**
* Given a starting position and an offset radial and distance,
* calculate an ending positon on a wgs84 ellipsoid.
* @param p1 (in) geodetic position
* @param az1 (in) degrees
* @param s (in) distance in meters
* @param p2 (out) geodetic position
* @param az2 (out) return course in degrees
*/
inline int geo_direct_wgs_84(const SGGeod& p1, double az1,
double s, SGGeod& p2, double *az2 )
{
double lat2, lon2;
int ret = geo_direct_wgs_84(p1.getLatitudeDeg(), p1.getLongitudeDeg(),
az1, s, &lat2, &lon2, az2);
p2.setLatitudeDeg(lat2);
p2.setLongitudeDeg(lon2);
return ret;
}
/** /**
* Given an altitude and two sets of (lat, lon) calculate great circle * Given an altitude and two sets of (lat, lon) calculate great circle
* distance between them as well as the starting and ending azimuths. * distance between them as well as the starting and ending azimuths.
* @param alt (in) meters * @param alt (in) meters (unused)
* @param lat1 (in) degrees * @param lat1 (in) degrees
* @param lon1 (in) degrees * @param lon1 (in) degrees
* @param lat2 (in) degrees * @param lat2 (in) degrees
@@ -157,9 +169,31 @@ int geo_direct_wgs_84 ( double alt, double lat1,
* @param az2 (out) end heading degrees * @param az2 (out) end heading degrees
* @param s (out) distance meters * @param s (out) distance meters
*/ */
int geo_inverse_wgs_84( double alt, double lat1, int geo_inverse_wgs_84( double lat1, double lon1, double lat2,
double lon1, double lat2,
double lon2, double *az1, double *az2, double lon2, double *az1, double *az2,
double *s ); double *s );
inline int geo_inverse_wgs_84( double alt, double lat1,
double lon1, double lat2,
double lon2, double *az1, double *az2,
double *s )
{ return geo_inverse_wgs_84(lat1, lon1, lat2, lon2, az1, az2, s); }
/**
* Given an altitude and two sets of (lat, lon) calculate great circle
* distance between them as well as the starting and ending azimuths.
* @param p1 (in) first position
* @param p2 (in) fsecond position
* @param az1 (out) start heading degrees
* @param az2 (out) end heading degrees
* @param s (out) distance meters
*/
inline int geo_inverse_wgs_84(const SGGeod& p1, const SGGeod& p2,
double *az1, double *az2, double *s )
{
return geo_inverse_wgs_84(p1.getLatitudeDeg(), p1.getLongitudeDeg(),
p2.getLatitudeDeg(), p2.getLongitudeDeg(),
az1, az2, s);
}
#endif // _SG_GEODESY_HXX #endif // _SG_GEODESY_HXX
-78
View File
@@ -1,78 +0,0 @@
/*
WARNING - Do not remove this header.
This code is a templated version of the 'magic-software' spherical
interpolation code by Dave Eberly. The original (un-hacked) code can be
obtained from here: http://www.magic-software.com/gr_appr.htm
This code is derived from linintp2.h/cpp and sphrintp.h/cpp.
Dave Eberly says that the conditions for use are:
* You may distribute the original source code to others at no charge.
* You may modify the original source code and distribute it to others at
no charge. The modified code must be documented to indicate that it is
not part of the original package.
* You may use this code for non-commercial purposes. You may also
incorporate this code into commercial packages. However, you may not
sell any of your source code which contains my original and/or modified
source code. In such a case, you need to factor out my code and freely
distribute it.
* The original code comes with absolutely no warranty and no guarantee is
made that the code is bug-free.
This does not seem incompatible with GPL - so this modified version
is hereby placed under GPL along with the rest of FlightGear.
Christian Mayer
*/
#ifndef SPHRINTP_H
#define SPHRINTP_H
#include "linintp2.h"
#include <plib/sg.h>
template<class T>
class SphereInterpolate
{
public:
SphereInterpolate (int n, const double* x, const double* y,
const double* z, const T* f);
SphereInterpolate (int n, const sgVec2* p, const T* f);
~SphereInterpolate ();
void GetSphericalCoords (const double x, const double y, const double z,
double& thetaAngle, double& phiAngle) const;
int Evaluate (const double x, const double y, const double z, T& f) const;
int Evaluate (const double thetaAngle, const double phiAngle, T& f) const;
T Evaluate(const sgVec2& p) const
{
T retval;
Evaluate(p[1], p[0], retval);
return retval;
}
T Evaluate(const sgVec3& p) const
{
T retval;
Evaluate(p[1], p[0], retval);
return retval;
}
protected:
int numPoints;
double* theta;
double* phi;
T* func;
mgcLinInterp2D<T>* pInterp;
};
#include "sphrintp.inl"
#endif
-172
View File
@@ -1,172 +0,0 @@
/*
WARNING - Do not remove this header.
This code is a templated version of the 'magic-software' spherical
interpolation code by Dave Eberly. The original (un-hacked) code can be
obtained from here: http://www.magic-software.com/gr_appr.htm
This code is derived from linintp2.h/cpp and sphrintp.h/cpp.
Dave Eberly says that the conditions for use are:
* You may distribute the original source code to others at no charge.
* You may modify the original source code and distribute it to others at
no charge. The modified code must be documented to indicate that it is
not part of the original package.
* You may use this code for non-commercial purposes. You may also
incorporate this code into commercial packages. However, you may not
sell any of your source code which contains my original and/or modified
source code. In such a case, you need to factor out my code and freely
distribute it.
* The original code comes with absolutely no warranty and no guarantee is
made that the code is bug-free.
This does not seem incompatible with GPL - so this modified version
is hereby placed under GPL along with the rest of FlightGear.
Christian Mayer
*/
#include <math.h>
#include "sphrintp.h"
static const double PI = 4.0*atan(1.0);
static const double TWOPI = 2.0*PI;
//---------------------------------------------------------------------------
template<class T>
SphereInterpolate<T>::SphereInterpolate (int n, const double* x,
const double* y, const double* z,
const T* f)
{
// Assumes (x[i],y[i],z[i]) is unit length for all 0 <= i < n.
// For complete spherical coverage, include the two antipodal points
// (0,0,1,f(0,0,1)) and (0,0,-1,f(0,0,-1)) in the data set.
// cout << "Initialising spherical interpolator.\n";
// cout << "[ 0%] Allocating memory \r";
theta = new double[3*n];
phi = new double[3*n];
func = new T[3*n];
// convert data to spherical coordinates
int i;
T empty;
for (i = 0; i < n; i++)
{
GetSphericalCoords(x[i],y[i],z[i],theta[i],phi[i]);
func[i] = f[i];
}
// use periodicity to get wrap-around in the Delaunay triangulation
// cout << "[ 10%] copying vertices for wrap-around\r";
int j, k;
for (i = 0, j = n, k = 2*n; i < n; i++, j++, k++)
{
theta[j] = theta[i]+TWOPI;
theta[k] = theta[i]-TWOPI;
phi[j] = phi[i];
phi[k] = phi[i];
func[j] = func[i];
func[k] = func[i];
}
pInterp = new mgcLinInterp2D<T>(3*n,theta,phi,func);
// cout << "[100%] Finished initialising spherical interpolator. \n";
}
template<class T>
SphereInterpolate<T>::SphereInterpolate (int n, const sgVec2* p, const T* f)
{
// Assumes (x[i],y[i],z[i]) is unit length for all 0 <= i < n.
// For complete spherical coverage, include the two antipodal points
// (0,0,1,f(0,0,1)) and (0,0,-1,f(0,0,-1)) in the data set.
// cout << "Initialising spherical interpolator.\n";
// cout << "[ 0%] Allocating memory \r";
theta = new double[3*n];
phi = new double[3*n];
func = new T[3*n];
// convert data to spherical coordinates
// cout << "[ 10%] copying vertices for wrap-around \r";
int i, j, k;
for (i = 0, j = n, k = 2*n; i < n; i++, j++, k++)
{
phi[i] = p[i][0];
theta[i] = p[i][1];
func[i] = f[i];
// use periodicity to get wrap-around in the Delaunay triangulation
phi[j] = phi[i];
phi[k] = phi[i];
theta[j] = theta[i]+TWOPI;
theta[k] = theta[i]-TWOPI;
func[j] = func[i];
func[k] = func[i];
}
pInterp = new mgcLinInterp2D<T>(3*n,theta,phi,func);
// cout << "[100%] Finished initialising spherical interpolator. \n";
}
//---------------------------------------------------------------------------
template<class T>
SphereInterpolate<T>::~SphereInterpolate ()
{
delete pInterp;
delete[] theta;
delete[] phi;
delete[] func;
}
//---------------------------------------------------------------------------
template<class T>
void SphereInterpolate<T>::GetSphericalCoords (const double x, const double y, const double z,
double& thetaAngle,
double& phiAngle) const
{
// Assumes (x,y,z) is unit length. Returns -PI <= thetaAngle <= PI
// and 0 <= phiAngle <= PI.
if ( z < 1.0f )
{
if ( z > -1.0f )
{
thetaAngle = atan2(y,x);
phiAngle = acos(z);
}
else
{
thetaAngle = -PI;
phiAngle = PI;
}
}
else
{
thetaAngle = -PI;
phiAngle = 0.0f;
}
}
//---------------------------------------------------------------------------
template<class T>
int SphereInterpolate<T>::Evaluate (const double x, const double y, const double z, T& f) const
{
// assumes (x,y,z) is unit length
double thetaAngle, phiAngle;
GetSphericalCoords(x,y,z,thetaAngle,phiAngle);
return pInterp->Evaluate(thetaAngle,phiAngle,f);
}
//---------------------------------------------------------------------------
template<class T>
int SphereInterpolate<T>::Evaluate (const double thetaAngle, const double phiAngle, T& f) const
{
return pInterp->Evaluate(thetaAngle,phiAngle,f);
}
//---------------------------------------------------------------------------
+2
View File
@@ -195,6 +195,8 @@ bool SGPath::exists() const {
void SGPath::create_dir( mode_t mode ) { void SGPath::create_dir( mode_t mode ) {
string_list dirlist = sgPathSplit(dir()); string_list dirlist = sgPathSplit(dir());
if ( dirlist.empty() )
return;
string path = dirlist[0]; string path = dirlist[0];
string_list path_elements = sgPathBranchSplit(path); string_list path_elements = sgPathBranchSplit(path);
bool absolute = !path.empty() && path[0] == sgDirPathSep; bool absolute = !path.empty() && path[0] == sgDirPathSep;
+6 -20
View File
@@ -2,26 +2,12 @@ includedir = @includedir@/nasal
lib_LIBRARIES = libsgnasal.a lib_LIBRARIES = libsgnasal.a
include_HEADERS = nasal.h include_HEADERS = nasal.h naref.h
libsgnasal_a_SOURCES = \ libsgnasal_a_SOURCES = bitslib.c code.c code.h codegen.c data.h gc.c \
code.c code.h \ hash.c iolib.c iolib.h lex.c lib.c mathlib.c \
codegen.c \ misc.c naref.h nasal.h parse.c parse.h string.c \
data.h \ thread-posix.c thread-win32.c threadlib.c \
gc.c \ utf8lib.c vector.c
hash.c \
lex.c \
lib.c \
mathlib.c \
iolib.c \
iolib.h \
bitslib.c \
misc.c \
nasal.h \
parse.c parse.h \
string.c \
vector.c \
thread-posix.c \
thread-win32.c
INCLUDES = -I$(top_srcdir) INCLUDES = -I$(top_srcdir)
+10 -17
View File
@@ -5,10 +5,10 @@
// bits (i.e. an unsigned int). Using a 64 bit integer would stretch // bits (i.e. an unsigned int). Using a 64 bit integer would stretch
// that beyond what is representable in the double result, but // that beyond what is representable in the double result, but
// requires portability work. // requires portability work.
#define MSK(n) (1 << (7 - ((n) & 7)))
#define BIT(s,l,n) s[l-1-((n)>>3)] & (1<<((n)&7)) #define BIT(s,l,n) s[(n)>>3] & MSK(n)
#define CLRB(s,l,n) s[l-1-((n)>>3)] &= ~(1<<((n)&7)) #define CLRB(s,l,n) s[(n)>>3] &= ~MSK(n)
#define SETB(s,l,n) s[l-1-((n)>>3)] |= 1<<((n)&7) #define SETB(s,l,n) s[(n)>>3] |= MSK(n)
static unsigned int fld(naContext c, unsigned char* s, static unsigned int fld(naContext c, unsigned char* s,
int slen, int bit, int flen) int slen, int bit, int flen)
@@ -32,7 +32,7 @@ static void setfld(naContext c, unsigned char* s, int slen,
static naRef dofld(naContext c, int argc, naRef* args, int sign) static naRef dofld(naContext c, int argc, naRef* args, int sign)
{ {
struct naStr* s = argc > 0 ? args[0].ref.ptr.str : 0; struct naStr* s = argc > 0 ? PTR(args[0]).str : 0;
int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1; int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1; int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
unsigned int f; unsigned int f;
@@ -56,7 +56,7 @@ static naRef f_fld(naContext c, naRef me, int argc, naRef* args)
static naRef f_setfld(naContext c, naRef me, int argc, naRef* args) static naRef f_setfld(naContext c, naRef me, int argc, naRef* args)
{ {
struct naStr* s = argc > 0 ? args[0].ref.ptr.str : 0; struct naStr* s = argc > 0 ? PTR(args[0]).str : 0;
int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1; int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1; int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
naRef val = argc > 3 ? naNumValue(args[3]) : naNil(); naRef val = argc > 3 ? naNumValue(args[3]) : naNil();
@@ -73,22 +73,15 @@ static naRef f_buf(naContext c, naRef me, int argc, naRef* args)
return naStr_buf(naNewString(c), (int)len.num); return naStr_buf(naNewString(c), (int)len.num);
} }
static struct func { char* name; naCFunction func; } funcs[] = { static naCFuncItem funcs[] = {
{ "sfld", f_sfld }, { "sfld", f_sfld },
{ "fld", f_fld }, { "fld", f_fld },
{ "setfld", f_setfld }, { "setfld", f_setfld },
{ "buf", f_buf }, { "buf", f_buf },
{ 0 }
}; };
naRef naBitsLib(naContext c) naRef naInit_bits(naContext c)
{ {
naRef namespace = naNewHash(c); return naGenLib(c, funcs);
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));
naHash_set(namespace, name, naNewFunc(c, code));
}
return namespace;
} }
+251 -160
View File
@@ -1,11 +1,14 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "nasal.h" #include "nasal.h"
#include "code.h" #include "code.h"
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Debugging stuff. //////////////////////////////////////////////////// // Debugging stuff. ////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
//#define DEBUG_NASAL //#define INTERPRETER_DUMP
#if !defined(DEBUG_NASAL) #if !defined(INTERPRETER_DUMP)
# define DBG(expr) /* noop */ # define DBG(expr) /* noop */
#else #else
# define DBG(expr) expr # define DBG(expr) expr
@@ -17,21 +20,44 @@ void printOpDEBUG(int ip, int op);
void printStackDEBUG(struct Context* ctx); void printStackDEBUG(struct Context* ctx);
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
#define vsnprintf _vsnprintf
#endif
struct Globals* globals = 0; struct Globals* globals = 0;
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code); static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code);
#define ERR(c, msg) naRuntimeError((c),(msg)) #define ERR(c, msg) naRuntimeError((c),(msg))
void naRuntimeError(struct Context* c, char* msg) void naRuntimeError(struct Context* c, const char* fmt, ...)
{ {
c->error = msg; va_list ap;
va_start(ap, fmt);
vsnprintf(c->error, sizeof(c->error), fmt, ap);
va_end(ap);
longjmp(c->jumpHandle, 1); longjmp(c->jumpHandle, 1);
} }
void naRethrowError(naContext subc)
{
strncpy(subc->callParent->error, subc->error, sizeof(subc->error));
subc->callParent->dieArg = subc->dieArg;
longjmp(subc->callParent->jumpHandle, 1);
}
#define END_PTR ((void*)1)
#define IS_END(r) (IS_REF((r)) && PTR((r)).obj == END_PTR)
static naRef endToken()
{
naRef r;
SETPTR(r, END_PTR);
return r;
}
static int boolify(struct Context* ctx, naRef r) static int boolify(struct Context* ctx, naRef r)
{ {
if(IS_NUM(r)) return r.num != 0; if(IS_NUM(r)) return r.num != 0;
if(IS_NIL(r)) return 0; if(IS_NIL(r) || IS_END(r)) return 0;
if(IS_STR(r)) { if(IS_STR(r)) {
double d; double d;
if(naStr_len(r) == 0) return 0; if(naStr_len(r) == 0) return 0;
@@ -65,7 +91,9 @@ static int checkVec(struct Context* ctx, naRef vec, naRef idx)
{ {
int i = (int)numify(ctx, idx); int i = (int)numify(ctx, idx);
if(i < 0) i += naVec_size(vec); if(i < 0) i += naVec_size(vec);
if(i < 0 || i >= naVec_size(vec)) ERR(ctx, "vector index out of bounds"); if(i < 0 || i >= naVec_size(vec))
naRuntimeError(ctx, "vector index %d out of bounds (size: %d)",
i, naVec_size(vec));
return i; return i;
} }
@@ -73,7 +101,9 @@ static int checkStr(struct Context* ctx, naRef str, naRef idx)
{ {
int i = (int)numify(ctx, idx); int i = (int)numify(ctx, idx);
if(i < 0) i += naStr_len(str); if(i < 0) i += naStr_len(str);
if(i < 0 || i >= naStr_len(str)) ERR(ctx, "string index out of bounds"); if(i < 0 || i >= naStr_len(str))
naRuntimeError(ctx, "string index %d out of bounds (size: %d)",
i, naStr_len(str));
return i; return i;
} }
@@ -82,8 +112,7 @@ static naRef containerGet(struct Context* ctx, naRef box, naRef key)
naRef result = naNil(); naRef result = naNil();
if(!IS_SCALAR(key)) ERR(ctx, "container index not scalar"); if(!IS_SCALAR(key)) ERR(ctx, "container index not scalar");
if(IS_HASH(box)) { if(IS_HASH(box)) {
if(!naHash_get(box, key, &result)) naHash_get(box, key, &result);
ERR(ctx, "undefined value in container");
} else if(IS_VEC(box)) { } else if(IS_VEC(box)) {
result = naVec_get(box, checkVec(ctx, box, key)); result = naVec_get(box, checkVec(ctx, box, key));
} else if(IS_STR(box)) { } else if(IS_STR(box)) {
@@ -100,7 +129,7 @@ static void containerSet(struct Context* ctx, naRef box, naRef key, naRef val)
else if(IS_HASH(box)) naHash_set(box, key, val); else if(IS_HASH(box)) naHash_set(box, key, val);
else if(IS_VEC(box)) naVec_set(box, checkVec(ctx, box, key), val); else if(IS_VEC(box)) naVec_set(box, checkVec(ctx, box, key), val);
else if(IS_STR(box)) { else if(IS_STR(box)) {
if(box.ref.ptr.str->hashcode) if(PTR(box).str->hashcode)
ERR(ctx, "cannot change immutable string"); ERR(ctx, "cannot change immutable string");
naStr_data(box)[checkStr(ctx, box, key)] = (char)numify(ctx, val); naStr_data(box)[checkStr(ctx, box, key)] = (char)numify(ctx, val);
} else ERR(ctx, "insert into non-container"); } else ERR(ctx, "insert into non-container");
@@ -128,7 +157,8 @@ static void initContext(struct Context* c)
c->callParent = 0; c->callParent = 0;
c->callChild = 0; c->callChild = 0;
c->dieArg = naNil(); c->dieArg = naNil();
c->error = 0; c->error[0] = 0;
c->userData = 0;
} }
static void initGlobals() static void initGlobals()
@@ -191,47 +221,46 @@ struct Context* naNewContext()
return c; return c;
} }
struct Context* naSubContext(struct Context* super)
{
struct Context* ctx = naNewContext();
if(super->callChild) naFreeContext(super->callChild);
ctx->callParent = super;
super->callChild = ctx;
return ctx;
}
void naFreeContext(struct Context* c) void naFreeContext(struct Context* c)
{ {
c->ntemps = 0; c->ntemps = 0;
if(c->callChild) naFreeContext(c->callChild);
if(c->callParent) c->callParent->callChild = 0;
LOCK(); LOCK();
c->nextFree = globals->freeContexts; c->nextFree = globals->freeContexts;
globals->freeContexts = c; globals->freeContexts = c;
UNLOCK(); UNLOCK();
} }
#if 0 // Note that opTop is incremented separately, to avoid situations
/* // where the "r" expression also references opTop. The SGI compiler
* This is the original code which might not work properly on all // is known to have issues with such code.
* platforms since it allows one to work on the same variable in one #define PUSH(r) do { \
* statement without the prior knowledge how this will behave.
*
* e.g. ctx->opStack[ctx->opTop++] = ctx->opStack[ctx->opTop-1];
* ^^^^^ ^^^^^
*/
# define PUSH(r) do { \
if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow"); \ if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow"); \
ctx->opStack[ctx->opTop++] = r; \ ctx->opStack[ctx->opTop] = r; \
ctx->opTop++; \
} while(0) } while(0)
#else
# define PUSH(r) _PUSH((ctx), (r))
void _PUSH(struct Context* ctx, naRef r) {
if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow");
ctx->opStack[ctx->opTop++] = r;
}
#endif
static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs) static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
{ {
int i; int i;
struct naCode* c = f->func.ref.ptr.func->code.ref.ptr.code; struct naCode* c = PTR(PTR(f->func).func->code).code;
// Set the argument symbols, and put any remaining args in a vector // Set the argument symbols, and put any remaining args in a vector
if(nargs < c->nArgs) ERR(ctx, "not enough arguments to function call"); if(nargs < c->nArgs)
naRuntimeError(ctx, "too few function args (have %d need %d)",
nargs, c->nArgs);
for(i=0; i<c->nArgs; i++) for(i=0; i<c->nArgs; i++)
naHash_newsym(f->locals.ref.ptr.hash, naHash_newsym(PTR(f->locals).hash,
&c->constants[c->argSyms[i]], &args[i]); &c->constants[c->argSyms[i]], &args[i]);
args += c->nArgs; args += c->nArgs;
nargs -= c->nArgs; nargs -= c->nArgs;
@@ -239,7 +268,7 @@ static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
naRef val = nargs > 0 ? args[i] : c->constants[c->optArgVals[i]]; naRef val = nargs > 0 ? args[i] : c->constants[c->optArgVals[i]];
if(IS_CODE(val)) if(IS_CODE(val))
val = bindFunction(ctx, &ctx->fStack[ctx->fTop-2], val); val = bindFunction(ctx, &ctx->fStack[ctx->fTop-2], val);
naHash_newsym(f->locals.ref.ptr.hash, &c->constants[c->optArgSyms[i]], naHash_newsym(PTR(f->locals).hash, &c->constants[c->optArgSyms[i]],
&val); &val);
} }
args += c->nOptArgs; args += c->nOptArgs;
@@ -247,12 +276,12 @@ static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
naRef argsv = naNewVector(ctx); naRef argsv = naNewVector(ctx);
naVec_setsize(argsv, nargs > 0 ? nargs : 0); naVec_setsize(argsv, nargs > 0 ? nargs : 0);
for(i=0; i<nargs; i++) for(i=0; i<nargs; i++)
argsv.ref.ptr.vec->rec->array[i] = *args++; PTR(argsv).vec->rec->array[i] = *args++;
naHash_newsym(f->locals.ref.ptr.hash, &c->restArgSym, &argsv); naHash_newsym(PTR(f->locals).hash, &c->restArgSym, &argsv);
} }
} }
struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail) static struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall)
{ {
naRef *frame; naRef *frame;
struct Frame* f; struct Frame* f;
@@ -263,20 +292,20 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
if(!IS_FUNC(frame[0])) if(!IS_FUNC(frame[0]))
ERR(ctx, "function/method call invoked on uncallable object"); ERR(ctx, "function/method call invoked on uncallable object");
// Just do native calls right here, and don't touch the stack ctx->opFrame = ctx->opTop - (nargs + 1 + mcall);
// frames; return the current one (unless it's a tail call!).
if(frame[0].ref.ptr.func->code.ref.ptr.obj->type == T_CCODE) { // Just do native calls right here
if(PTR(PTR(frame[0]).func->code).obj->type == T_CCODE) {
naRef obj = mcall ? frame[-1] : naNil(); naRef obj = mcall ? frame[-1] : naNil();
naCFunction fp = frame[0].ref.ptr.func->code.ref.ptr.ccode->fptr; naCFunction fp = PTR(PTR(frame[0]).func->code).ccode->fptr;
naRef result = (*fp)(ctx, obj, nargs, frame + 1); naRef result = (*fp)(ctx, obj, nargs, frame + 1);
ctx->opTop -= nargs + 1 + mcall; ctx->opTop = ctx->opFrame;
PUSH(result); PUSH(result);
return &(ctx->fStack[ctx->fTop-1]); return &(ctx->fStack[ctx->fTop-1]);
} }
if(tail) ctx->fTop--; if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
else if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
// Note: assign nil first, otherwise the naNew() can cause a GC, // Note: assign nil first, otherwise the naNew() can cause a GC,
// which will now (after fTop++) see the *old* reference as a // which will now (after fTop++) see the *old* reference as a
// markable value! // markable value!
@@ -285,7 +314,7 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
f->locals = naNewHash(ctx); f->locals = naNewHash(ctx);
f->func = frame[0]; f->func = frame[0];
f->ip = 0; f->ip = 0;
f->bp = ctx->opTop - (nargs + 1 + mcall); f->bp = ctx->opFrame;
if(mcall) if(mcall)
naHash_set(f->locals, globals->meRef, frame[-1]); naHash_set(f->locals, globals->meRef, frame[-1]);
@@ -297,29 +326,35 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
return f; return f;
} }
static naRef evalAndOr(struct Context* ctx, int op, naRef ra, naRef rb)
{
int a = boolify(ctx, ra);
int b = boolify(ctx, rb);
int result;
if(op == OP_AND) result = a && b ? 1 : 0;
else result = a || b ? 1 : 0;
return naNum(result);
}
static naRef evalEquality(int op, naRef ra, naRef rb) static naRef evalEquality(int op, naRef ra, naRef rb)
{ {
int result = naEqual(ra, rb); int result = naEqual(ra, rb);
return naNum((op==OP_EQ) ? result : !result); return naNum((op==OP_EQ) ? result : !result);
} }
static naRef evalCat(naContext ctx, naRef l, naRef r)
{
if(IS_VEC(l) && IS_VEC(r)) {
int i, ls = naVec_size(l), rs = naVec_size(r);
naRef v = naNewVector(ctx);
naVec_setsize(v, ls + rs);
for(i=0; i<ls; i+=1) naVec_set(v, i, naVec_get(l, i));
for(i=0; i<rs; i+=1) naVec_set(v, i+ls, naVec_get(r, i));
return v;
} else {
naRef a = stringify(ctx, l);
naRef b = stringify(ctx, r);
return naStr_concat(naNewString(ctx), a, b);
}
}
// When a code object comes out of the constant pool and shows up on // When a code object comes out of the constant pool and shows up on
// the stack, it needs to be bound with the lexical context. // the stack, it needs to be bound with the lexical context.
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code) static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code)
{ {
naRef result = naNewFunc(ctx, code); naRef result = naNewFunc(ctx, code);
result.ref.ptr.func->namespace = f->locals; PTR(result).func->namespace = f->locals;
result.ref.ptr.func->next = f->func; PTR(result).func->next = f->func;
return result; return result;
} }
@@ -327,7 +362,7 @@ static int getClosure(struct naFunc* c, naRef sym, naRef* result)
{ {
while(c) { while(c) {
if(naHash_get(c->namespace, sym, result)) return 1; if(naHash_get(c->namespace, sym, result)) return 1;
c = c->next.ref.ptr.func; c = PTR(c->next).func;
} }
return 0; return 0;
} }
@@ -336,8 +371,8 @@ static naRef getLocal2(struct Context* ctx, struct Frame* f, naRef sym)
{ {
naRef result; naRef result;
if(!naHash_get(f->locals, sym, &result)) if(!naHash_get(f->locals, sym, &result))
if(!getClosure(f->func.ref.ptr.func, sym, &result)) if(!getClosure(PTR(f->func).func, sym, &result))
ERR(ctx, "undefined symbol"); naRuntimeError(ctx, "undefined symbol: %s", naStr_data(sym));
return result; return result;
} }
@@ -345,14 +380,14 @@ static void getLocal(struct Context* ctx, struct Frame* f,
naRef* sym, naRef* out) naRef* sym, naRef* out)
{ {
struct naFunc* func; struct naFunc* func;
struct naStr* str = sym->ref.ptr.str; struct naStr* str = PTR(*sym).str;
if(naHash_sym(f->locals.ref.ptr.hash, str, out)) if(naHash_sym(PTR(f->locals).hash, str, out))
return; return;
func = f->func.ref.ptr.func; func = PTR(f->func).func;
while(func && func->namespace.ref.ptr.hash) { while(func && PTR(func->namespace).hash) {
if(naHash_sym(func->namespace.ref.ptr.hash, str, out)) if(naHash_sym(PTR(func->namespace).hash, str, out))
return; return;
func = func->next.ref.ptr.func; func = PTR(func->next).func;
} }
// Now do it again using the more general naHash_get(). This will // Now do it again using the more general naHash_get(). This will
// only be necessary if something has created the value in the // only be necessary if something has created the value in the
@@ -363,7 +398,7 @@ static void getLocal(struct Context* ctx, struct Frame* f,
static int setClosure(naRef func, naRef sym, naRef val) static int setClosure(naRef func, naRef sym, naRef val)
{ {
struct naFunc* c = func.ref.ptr.func; struct naFunc* c = PTR(func).func;
if(c == 0) { return 0; } if(c == 0) { return 0; }
else if(naHash_tryset(c->namespace, sym, val)) { return 1; } else if(naHash_tryset(c->namespace, sym, val)) { return 1; }
else { return setClosure(c->next, sym, val); } else { return setClosure(c->next, sym, val); }
@@ -379,39 +414,52 @@ static naRef setSymbol(struct Frame* f, naRef sym, naRef val)
return val; return val;
} }
// Recursively descend into the parents lists // Funky API: returns null to indicate no member, an empty string to
static int getMember(struct Context* ctx, naRef obj, naRef fld, // indicate success, or a non-empty error message. Works this way so
naRef* result, int count) // we can generate smart error messages without throwing them with a
// longjmp -- this gets called under naMember_get() from C code.
static const char* getMember_r(naRef obj, naRef field, naRef* out, int count)
{ {
int i;
naRef p; naRef p;
if(--count < 0) ERR(ctx, "too many parents"); struct VecRec* pv;
if(!IS_HASH(obj)) ERR(ctx, "non-objects have no members"); if(--count < 0) return "too many parents";
if(naHash_get(obj, fld, result)) { if(!IS_HASH(obj)) return 0;
return 1; if(naHash_get(obj, field, out)) return "";
} else if(naHash_get(obj, globals->parentsRef, &p)) { if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
if(IS_VEC(p)) { if(!IS_VEC(p)) return "object \"parents\" field not vector";
int i; pv = PTR(p).vec->rec;
struct VecRec* v = p.ref.ptr.vec->rec; for(i=0; i<pv->size; i++) {
for(i=0; i<v->size; i++) const char* err = getMember_r(pv->array[i], field, out, count);
if(getMember(ctx, v->array[i], fld, result, count)) if(err) return err; /* either an error or success */
return 1;
} else
ERR(ctx, "parents field not vector");
} }
return 0; return 0;
} }
static void getMember(struct Context* ctx, naRef obj, naRef fld,
naRef* result, int count)
{
const char* err = getMember_r(obj, fld, result, count);
if(!err) naRuntimeError(ctx, "No such member: %s", naStr_data(fld));
if(err[0]) naRuntimeError(ctx, err);
}
int naMember_get(naRef obj, naRef field, naRef* out)
{
const char* err = getMember_r(obj, field, out, 64);
return err && !err[0];
}
// OP_EACH works like a vector get, except that it leaves the vector // OP_EACH works like a vector get, except that it leaves the vector
// and index on the stack, increments the index after use, and pops // and index on the stack, increments the index after use, and
// the arguments and pushes a nil if the index is beyond the end. // pushes a nil if the index is beyond the end.
static void evalEach(struct Context* ctx, int useIndex) static void evalEach(struct Context* ctx, int useIndex)
{ {
int idx = (int)(ctx->opStack[ctx->opTop-1].num); int idx = (int)(ctx->opStack[ctx->opTop-1].num);
naRef vec = ctx->opStack[ctx->opTop-2]; naRef vec = ctx->opStack[ctx->opTop-2];
if(!IS_VEC(vec)) naRuntimeError(ctx, "foreach enumeration of non-vector"); if(!IS_VEC(vec)) ERR(ctx, "foreach enumeration of non-vector");
if(!vec.ref.ptr.vec->rec || idx >= vec.ref.ptr.vec->rec->size) { if(!PTR(vec).vec->rec || idx >= PTR(vec).vec->rec->size) {
ctx->opTop -= 2; // pop two values PUSH(endToken());
PUSH(naNil());
return; return;
} }
ctx->opStack[ctx->opTop-1].num = idx+1; // modify in place ctx->opStack[ctx->opTop-1].num = idx+1; // modify in place
@@ -423,13 +471,16 @@ static void evalEach(struct Context* ctx, int useIndex)
#define POP() ctx->opStack[--ctx->opTop] #define POP() ctx->opStack[--ctx->opTop]
#define STK(n) (ctx->opStack[ctx->opTop-(n)]) #define STK(n) (ctx->opStack[ctx->opTop-(n)])
#define FIXFRAME() f = &(ctx->fStack[ctx->fTop-1]); \ #define FIXFRAME() f = &(ctx->fStack[ctx->fTop-1]); \
cd = f->func.ref.ptr.func->code.ref.ptr.code; cd = PTR(PTR(f->func).func->code).code;
static naRef run(struct Context* ctx) static naRef run(struct Context* ctx)
{ {
struct Frame* f; struct Frame* f;
struct naCode* cd; struct naCode* cd;
int op, arg; int op, arg;
naRef a, b, c; naRef a, b;
ctx->dieArg = naNil();
ctx->error[0] = 0;
FIXFRAME(); FIXFRAME();
@@ -455,8 +506,7 @@ static naRef run(struct Context* ctx)
#define BINOP(expr) do { \ #define BINOP(expr) do { \
double l = IS_NUM(STK(2)) ? STK(2).num : numify(ctx, STK(2)); \ double l = IS_NUM(STK(2)) ? STK(2).num : numify(ctx, STK(2)); \
double r = IS_NUM(STK(1)) ? STK(1).num : numify(ctx, STK(1)); \ double r = IS_NUM(STK(1)) ? STK(1).num : numify(ctx, STK(1)); \
STK(2).ref.reftag = ~NASAL_REFTAG; \ SETNUM(STK(2), expr); \
STK(2).num = expr; \
ctx->opTop--; } while(0) ctx->opTop--; } while(0)
case OP_PLUS: BINOP(l + r); break; case OP_PLUS: BINOP(l + r); break;
@@ -467,24 +517,15 @@ static naRef run(struct Context* ctx)
case OP_LTE: BINOP(l <= r ? 1 : 0); break; case OP_LTE: BINOP(l <= r ? 1 : 0); break;
case OP_GT: BINOP(l > r ? 1 : 0); break; case OP_GT: BINOP(l > r ? 1 : 0); break;
case OP_GTE: BINOP(l >= r ? 1 : 0); break; case OP_GTE: BINOP(l >= r ? 1 : 0); break;
#undef BINOP #undef BINOP
case OP_EQ: case OP_NEQ: case OP_EQ: case OP_NEQ:
STK(2) = evalEquality(op, STK(2), STK(1)); STK(2) = evalEquality(op, STK(2), STK(1));
ctx->opTop--; ctx->opTop--;
break; break;
case OP_AND: case OP_OR:
STK(2) = evalAndOr(ctx, op, STK(2), STK(1));
ctx->opTop--;
break;
case OP_CAT: case OP_CAT:
// stringify can call the GC, so don't take stuff of the stack! STK(2) = evalCat(ctx, STK(2), STK(1));
a = stringify(ctx, ctx->opStack[ctx->opTop-1]); ctx->opTop -= 1;
b = stringify(ctx, ctx->opStack[ctx->opTop-2]);
c = naStr_concat(naNewString(ctx), b, a);
ctx->opTop -= 2;
PUSH(c);
break; break;
case OP_NEG: case OP_NEG:
STK(1) = naNum(-numify(ctx, STK(1))); STK(1) = naNum(-numify(ctx, STK(1)));
@@ -506,6 +547,9 @@ static naRef run(struct Context* ctx)
case OP_PUSHNIL: case OP_PUSHNIL:
PUSH(naNil()); PUSH(naNil());
break; break;
case OP_PUSHEND:
PUSH(endToken());
break;
case OP_NEWVEC: case OP_NEWVEC:
PUSH(naNewVector(ctx)); PUSH(naNewVector(ctx));
break; break;
@@ -535,8 +579,7 @@ static naRef run(struct Context* ctx)
ctx->opTop--; ctx->opTop--;
break; break;
case OP_MEMBER: case OP_MEMBER:
if(!getMember(ctx, STK(1), CONSTARG(), &STK(1), 64)) getMember(ctx, STK(1), CONSTARG(), &STK(1), 64);
ERR(ctx, "no such member");
break; break;
case OP_SETMEMBER: case OP_SETMEMBER:
if(!IS_HASH(STK(3))) ERR(ctx, "non-objects have no members"); if(!IS_HASH(STK(3))) ERR(ctx, "non-objects have no members");
@@ -563,15 +606,29 @@ static naRef run(struct Context* ctx)
f->ip = cd->byteCode[f->ip]; f->ip = cd->byteCode[f->ip];
DBG(printf(" [Jump to: %d]\n", f->ip);) DBG(printf(" [Jump to: %d]\n", f->ip);)
break; break;
case OP_JIFNIL: case OP_JIFEND:
arg = ARG(); arg = ARG();
if(IS_NIL(STK(1))) { if(IS_END(STK(1))) {
ctx->opTop--; // Pops **ONLY** if it's nil! ctx->opTop--; // Pops **ONLY** if it's nil!
f->ip = arg; f->ip = arg;
DBG(printf(" [Jump to: %d]\n", f->ip);) DBG(printf(" [Jump to: %d]\n", f->ip);)
} }
break; break;
case OP_JIFTRUE:
arg = ARG();
if(boolify(ctx, STK(1))) {
f->ip = arg;
DBG(printf(" [Jump to: %d]\n", f->ip);)
}
break;
case OP_JIFNOT: case OP_JIFNOT:
arg = ARG();
if(!boolify(ctx, STK(1))) {
f->ip = arg;
DBG(printf(" [Jump to: %d]\n", f->ip);)
}
break;
case OP_JIFNOTPOP:
arg = ARG(); arg = ARG();
if(!boolify(ctx, POP())) { if(!boolify(ctx, POP())) {
f->ip = arg; f->ip = arg;
@@ -579,23 +636,17 @@ static naRef run(struct Context* ctx)
} }
break; break;
case OP_FCALL: case OP_FCALL:
f = setupFuncall(ctx, ARG(), 0, 0); f = setupFuncall(ctx, ARG(), 0);
cd = f->func.ref.ptr.func->code.ref.ptr.code; cd = PTR(PTR(f->func).func->code).code;
break;
case OP_FTAIL:
f = setupFuncall(ctx, ARG(), 0, 1);
cd = f->func.ref.ptr.func->code.ref.ptr.code;
break; break;
case OP_MCALL: case OP_MCALL:
f = setupFuncall(ctx, ARG(), 1, 0); f = setupFuncall(ctx, ARG(), 1);
cd = f->func.ref.ptr.func->code.ref.ptr.code; cd = PTR(PTR(f->func).func->code).code;
break;
case OP_MTAIL:
f = setupFuncall(ctx, ARG(), 1, 1);
cd = f->func.ref.ptr.func->code.ref.ptr.code;
break; break;
case OP_RETURN: case OP_RETURN:
a = STK(1); a = STK(1);
ctx->dieArg = naNil();
if(ctx->callChild) naFreeContext(ctx->callChild);
if(--ctx->fTop <= 0) return a; if(--ctx->fTop <= 0) return a;
ctx->opTop = f->bp + 1; // restore the correct opstack frame! ctx->opTop = f->bp + 1; // restore the correct opstack frame!
STK(1) = a; STK(1) = a;
@@ -609,13 +660,16 @@ static naRef run(struct Context* ctx)
break; break;
case OP_MARK: // save stack state (e.g. "setjmp") case OP_MARK: // save stack state (e.g. "setjmp")
if(ctx->markTop >= MAX_MARK_DEPTH) if(ctx->markTop >= MAX_MARK_DEPTH)
naRuntimeError(ctx, "mark stack overflow"); ERR(ctx, "mark stack overflow");
ctx->markStack[ctx->markTop++] = ctx->opTop; ctx->markStack[ctx->markTop++] = ctx->opTop;
break; break;
case OP_UNMARK: // pop stack state set by mark case OP_UNMARK: // pop stack state set by mark
ctx->markTop--; ctx->markTop--;
break; break;
case OP_BREAK: // restore stack state (FOLLOW WITH JMP!) case OP_BREAK: // restore stack state (FOLLOW WITH JMP!)
ctx->opTop = ctx->markStack[ctx->markTop-1];
break;
case OP_BREAK2: // same, but also pop the mark stack
ctx->opTop = ctx->markStack[--ctx->markTop]; ctx->opTop = ctx->markStack[--ctx->markTop];
break; break;
default: default:
@@ -636,48 +690,55 @@ void naSave(struct Context* ctx, naRef obj)
naVec_append(globals->save, obj); naVec_append(globals->save, obj);
} }
// FIXME: handle ctx->callParent
int naStackDepth(struct Context* ctx) int naStackDepth(struct Context* ctx)
{ {
return ctx->fTop; return ctx ? ctx->fTop + naStackDepth(ctx->callChild): 0;
}
static int findFrame(naContext ctx, naContext* out, int fn)
{
int sd = naStackDepth(ctx->callChild);
if(fn < sd) return findFrame(ctx->callChild, out, fn);
*out = ctx;
return ctx->fTop - 1 - (fn - sd);
} }
// FIXME: handle ctx->callParent
int naGetLine(struct Context* ctx, int frame) int naGetLine(struct Context* ctx, int frame)
{ {
struct Frame* f = &ctx->fStack[ctx->fTop-1-frame]; struct Frame* f;
naRef func = f->func; frame = findFrame(ctx, &ctx, frame);
int ip = f->ip; f = &ctx->fStack[frame];
if(IS_FUNC(func) && IS_CODE(func.ref.ptr.func->code)) { if(IS_FUNC(f->func) && IS_CODE(PTR(f->func).func->code)) {
struct naCode* c = func.ref.ptr.func->code.ref.ptr.code; struct naCode* c = PTR(PTR(f->func).func->code).code;
unsigned short* p = c->lineIps + c->nLines - 2; unsigned short* p = c->lineIps + c->nLines - 2;
while(p >= c->lineIps && p[0] > ip) while(p >= c->lineIps && p[0] > f->ip)
p -= 2; p -= 2;
return p[1]; return p[1];
} }
return -1; return -1;
} }
// FIXME: handle ctx->callParent
naRef naGetSourceFile(struct Context* ctx, int frame) naRef naGetSourceFile(struct Context* ctx, int frame)
{ {
naRef f = ctx->fStack[ctx->fTop-1-frame].func; naRef f;
f = f.ref.ptr.func->code; frame = findFrame(ctx, &ctx, frame);
return f.ref.ptr.code->srcFile; f = ctx->fStack[frame].func;
f = PTR(f).func->code;
return PTR(f).code->srcFile;
} }
char* naGetError(struct Context* ctx) char* naGetError(struct Context* ctx)
{ {
if(IS_STR(ctx->dieArg)) if(IS_STR(ctx->dieArg))
return (char*)ctx->dieArg.ref.ptr.str->data; return (char*)PTR(ctx->dieArg).str->data;
return ctx->error; return ctx->error[0] ? ctx->error : 0;
} }
naRef naBindFunction(naContext ctx, naRef code, naRef closure) naRef naBindFunction(naContext ctx, naRef code, naRef closure)
{ {
naRef func = naNewFunc(ctx, code); naRef func = naNewFunc(ctx, code);
func.ref.ptr.func->namespace = closure; PTR(func).func->namespace = closure;
func.ref.ptr.func->next = naNil(); PTR(func).func->next = naNil();
return func; return func;
} }
@@ -685,8 +746,8 @@ naRef naBindToContext(naContext ctx, naRef code)
{ {
naRef func = naNewFunc(ctx, code); naRef func = naNewFunc(ctx, code);
struct Frame* f = &ctx->fStack[ctx->fTop-1]; struct Frame* f = &ctx->fStack[ctx->fTop-1];
func.ref.ptr.func->namespace = f->locals; PTR(func).func->namespace = f->locals;
func.ref.ptr.func->next = f->func; PTR(func).func->next = f->func;
return func; return func;
} }
@@ -695,7 +756,7 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
{ {
int i; int i;
naRef result; naRef result;
if(!ctx->callParent) naModLock(ctx); if(!ctx->callParent) naModLock();
// We might have to allocate objects, which can call the GC. But // We might have to allocate objects, which can call the GC. But
// the call isn't on the Nasal stack yet, so the GC won't find our // the call isn't on the Nasal stack yet, so the GC won't find our
@@ -706,22 +767,28 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
naTempSave(ctx, obj); naTempSave(ctx, obj);
naTempSave(ctx, locals); naTempSave(ctx, locals);
if(IS_CCODE(func.ref.ptr.func->code)) { // naRuntimeError() calls end up here:
naCFunction fp = func.ref.ptr.func->code.ref.ptr.ccode->fptr; if(setjmp(ctx->jumpHandle)) {
result = (*fp)(ctx, obj, argc, args);
if(!ctx->callParent) naModUnlock(ctx); if(!ctx->callParent) naModUnlock(ctx);
return naNil();
}
if(IS_CCODE(PTR(func).func->code)) {
naCFunction fp = PTR(PTR(func).func->code).ccode->fptr;
result = (*fp)(ctx, obj, argc, args);
if(!ctx->callParent) naModUnlock();
return result; return result;
} }
if(IS_NIL(locals)) if(IS_NIL(locals))
locals = naNewHash(ctx); locals = naNewHash(ctx);
if(!IS_FUNC(func)) if(!IS_FUNC(func)) {
func = naNewFunc(ctx, func); // bind bare code objects func = naNewFunc(ctx, func);
PTR(func).func->namespace = locals;
}
if(!IS_NIL(obj)) if(!IS_NIL(obj))
naHash_set(locals, globals->meRef, obj); naHash_set(locals, globals->meRef, obj);
ctx->dieArg = naNil();
ctx->opTop = ctx->markTop = 0; ctx->opTop = ctx->markTop = 0;
ctx->fTop = 1; ctx->fTop = 1;
ctx->fStack[0].func = func; ctx->fStack[0].func = func;
@@ -729,18 +796,42 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
ctx->fStack[0].ip = 0; ctx->fStack[0].ip = 0;
ctx->fStack[0].bp = ctx->opTop; ctx->fStack[0].bp = ctx->opTop;
setupArgs(ctx, ctx->fStack, args, argc); if(args) setupArgs(ctx, ctx->fStack, args, argc);
// Return early if an error occurred. It will be visible to the
// caller via naGetError().
ctx->error = 0;
if(setjmp(ctx->jumpHandle)) {
if(!ctx->callParent) naModUnlock(ctx);
return naNil();
}
result = run(ctx); result = run(ctx);
if(!ctx->callParent) naModUnlock(ctx); if(!ctx->callParent) naModUnlock(ctx);
return result; return result;
} }
naRef naContinue(naContext ctx)
{
naRef result;
if(!ctx->callParent) naModLock();
ctx->dieArg = naNil();
ctx->error[0] = 0;
if(setjmp(ctx->jumpHandle)) {
if(!ctx->callParent) naModUnlock(ctx);
else naRethrowError(ctx);
return naNil();
}
// Wipe off the old function arguments, and push the expected
// result (either the result of our subcontext, or a synthesized
// nil if the thrown error was from an extension function or
// in-script die() call) before re-running the code from the
// instruction following the error.
ctx->opTop = ctx->opFrame;
PUSH(ctx->callChild ? naContinue(ctx->callChild) : naNil());
// Getting here means the child completed successfully. But
// because its original C stack was longjmp'd out of existence,
// there is no one left to free the context, so we have to do it.
// This is fragile, but unfortunately required.
if(ctx->callChild) naFreeContext(ctx->callChild);
result = run(ctx);
if(!ctx->callParent) naModUnlock();
return result;
}
+19 -10
View File
@@ -10,19 +10,23 @@
#define MAX_MARK_DEPTH 128 #define MAX_MARK_DEPTH 128
// Number of objects (per pool per thread) asked for using naGC_get(). // Number of objects (per pool per thread) asked for using naGC_get().
// Testing with fib.nas shows that this gives the best performance, // The idea is that contexts can "cache" allocations to prevent thread
// without too much per-thread overhead. // contention on the global pools. But in practice this interacts
#define OBJ_CACHE_SZ 128 // very badly with small subcontext calls, which grab huge numbers of
// cached objects and don't use them, causing far more collections
// than necessary. Just leave it at 1 pending a rework of the
// collector synchronization.
#define OBJ_CACHE_SZ 1
enum { enum {
OP_AND, OP_OR, OP_NOT, OP_MUL, OP_PLUS, OP_MINUS, OP_DIV, OP_NEG, 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_CAT, OP_LT, OP_LTE, OP_GT, OP_GTE, OP_EQ, OP_NEQ, OP_EACH,
OP_JMP, OP_JMPLOOP, OP_JIFNOT, OP_JIFNIL, OP_FCALL, OP_MCALL, OP_RETURN, OP_JMP, OP_JMPLOOP, OP_JIFNOTPOP, OP_JIFEND, OP_FCALL, OP_MCALL,
OP_PUSHCONST, OP_PUSHONE, OP_PUSHZERO, OP_PUSHNIL, OP_POP, 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_DUP, OP_XCHG, OP_INSERT, OP_EXTRACT, OP_MEMBER, OP_SETMEMBER,
OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND, OP_NEWHASH, OP_HAPPEND, OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND, OP_NEWHASH, OP_HAPPEND,
OP_MARK, OP_UNMARK, OP_BREAK, OP_FTAIL, OP_MTAIL, OP_SETSYM, OP_DUP2, OP_MARK, OP_UNMARK, OP_BREAK, OP_SETSYM, OP_DUP2, OP_INDEX, OP_BREAK2,
OP_INDEX OP_PUSHEND, OP_JIFTRUE, OP_JIFNOT
}; };
struct Frame { struct Frame {
@@ -69,6 +73,7 @@ struct Context {
struct Frame fStack[MAX_RECURSION]; struct Frame fStack[MAX_RECURSION];
int fTop; int fTop;
naRef opStack[MAX_STACK_DEPTH]; naRef opStack[MAX_STACK_DEPTH];
int opFrame; // like Frame::bp, but for C functions
int opTop; int opTop;
int markStack[MAX_MARK_DEPTH]; int markStack[MAX_MARK_DEPTH];
int markTop; int markTop;
@@ -86,7 +91,7 @@ struct Context {
// Error handling // Error handling
jmp_buf jumpHandle; jmp_buf jumpHandle;
char* error; char error[128];
naRef dieArg; naRef dieArg;
// Sub-call lists // Sub-call lists
@@ -96,6 +101,8 @@ struct Context {
// Linked list pointers in globals // Linked list pointers in globals
struct Context* nextFree; struct Context* nextFree;
struct Context* nextAll; struct Context* nextAll;
void* userData;
}; };
#define globals nasal_globals #define globals nasal_globals
@@ -103,11 +110,13 @@ extern struct Globals* globals;
// Threading low-level functions // Threading low-level functions
void* naNewLock(); void* naNewLock();
void naFreeLock(void* lock);
void naLock(void* lock); void naLock(void* lock);
void naUnlock(void* lock); void naUnlock(void* lock);
void* naNewSem(); void* naNewSem();
void naFreeSem(void* sem);
void naSemDown(void* sem); void naSemDown(void* sem);
void naSemUpAll(void* sem, int count); void naSemUp(void* sem, int count);
void naCheckBottleneck(); void naCheckBottleneck();
+29 -56
View File
@@ -91,41 +91,6 @@ static int findConstantIndex(struct Parser* p, struct Token* t)
return internConstant(p, c); 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) static int genScalarConstant(struct Parser* p, struct Token* t)
{ {
// These opcodes are for special-case use in other constructs, but // These opcodes are for special-case use in other constructs, but
@@ -145,7 +110,7 @@ static int genScalarConstant(struct Parser* p, struct Token* t)
static int genLValue(struct Parser* p, struct Token* t, int* cidx) static int genLValue(struct Parser* p, struct Token* t, int* cidx)
{ {
if(t->type == TOK_LPAR) { if(t->type == TOK_LPAR && t->rule != PREC_SUFFIX) {
return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1" return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1"
} else if(t->type == TOK_SYMBOL) { } else if(t->type == TOK_SYMBOL) {
*cidx = genScalarConstant(p, t); *cidx = genScalarConstant(p, t);
@@ -187,6 +152,15 @@ static void genEqOp(int op, struct Parser* p, struct Token* t)
static int defArg(struct Parser* p, struct Token* t) static int defArg(struct Parser* p, struct Token* t)
{ {
if(t->type == TOK_LPAR) return defArg(p, RIGHT(t)); if(t->type == TOK_LPAR) return defArg(p, RIGHT(t));
if(t->type == TOK_MINUS && RIGHT(t) &&
RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
{
/* default arguments are constants, but "-1" parses as two
* tokens, so we have to subset the expression generator for that
* case */
RIGHT(t)->num *= -1;
return defArg(p, RIGHT(t));
}
return findConstantIndex(p, t); return findConstantIndex(p, t);
} }
@@ -293,8 +267,6 @@ static void genFuncall(struct Parser* p, struct Token* t)
genExpr(p, LEFT(t)); genExpr(p, LEFT(t));
} }
if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0); if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
if(tailContext(t))
op = op == OP_FCALL ? OP_FTAIL : OP_MTAIL;
emitImmediate(p, op, nargs); emitImmediate(p, op, nargs);
} }
@@ -334,15 +306,12 @@ static void fixJumpTarget(struct Parser* p, int spot)
static void genShortCircuit(struct Parser* p, struct Token* t) static void genShortCircuit(struct Parser* p, struct Token* t)
{ {
int jumpNext, jumpEnd, isAnd = (t->type == TOK_AND); int end;
genExpr(p, LEFT(t)); genExpr(p, LEFT(t));
if(isAnd) emit(p, OP_NOT); end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
jumpNext = emitJump(p, OP_JIFNOT); emit(p, OP_POP);
emit(p, isAnd ? OP_PUSHNIL : OP_PUSHONE);
jumpEnd = emitJump(p, OP_JMP);
fixJumpTarget(p, jumpNext);
genExpr(p, RIGHT(t)); genExpr(p, RIGHT(t));
fixJumpTarget(p, jumpEnd); fixJumpTarget(p, end);
} }
@@ -350,7 +319,7 @@ static void genIf(struct Parser* p, struct Token* tif, struct Token* telse)
{ {
int jumpNext, jumpEnd; int jumpNext, jumpEnd;
genExpr(p, tif->children); // the test genExpr(p, tif->children); // the test
jumpNext = emitJump(p, OP_JIFNOT); jumpNext = emitJump(p, OP_JIFNOTPOP);
genExprList(p, tif->children->next->children); // the body genExprList(p, tif->children->next->children); // the body
jumpEnd = emitJump(p, OP_JMP); jumpEnd = emitJump(p, OP_JMP);
fixJumpTarget(p, jumpNext); fixJumpTarget(p, jumpNext);
@@ -374,7 +343,7 @@ static void genQuestion(struct Parser* p, struct Token* t)
if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON) if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
naParseError(p, "invalid ?: expression", t->line); naParseError(p, "invalid ?: expression", t->line);
genExpr(p, LEFT(t)); // the test genExpr(p, LEFT(t)); // the test
jumpNext = emitJump(p, OP_JIFNOT); jumpNext = emitJump(p, OP_JIFNOTPOP);
genExpr(p, LEFT(RIGHT(t))); // the "if true" expr genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
jumpEnd = emitJump(p, OP_JMP); jumpEnd = emitJump(p, OP_JMP);
fixJumpTarget(p, jumpNext); fixJumpTarget(p, jumpNext);
@@ -420,7 +389,7 @@ static void genForWhile(struct Parser* p, struct Token* init,
pushLoop(p, label); pushLoop(p, label);
loopTop = p->cg->codesz; loopTop = p->cg->codesz;
genExpr(p, test); genExpr(p, test);
jumpEnd = emitJump(p, OP_JIFNOT); jumpEnd = emitJump(p, OP_JIFNOTPOP);
genLoop(p, body, update, label, loopTop, jumpEnd); genLoop(p, body, update, label, loopTop, jumpEnd);
} }
@@ -480,17 +449,19 @@ static void genForEach(struct Parser* p, struct Token* t)
vec = RIGHT(h); vec = RIGHT(h);
body = RIGHT(t)->children; body = RIGHT(t)->children;
pushLoop(p, label);
genExpr(p, vec); genExpr(p, vec);
emit(p, OP_PUSHZERO); emit(p, OP_PUSHZERO);
pushLoop(p, label);
loopTop = p->cg->codesz; loopTop = p->cg->codesz;
emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX); emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
jumpEnd = emitJump(p, OP_JIFNIL); jumpEnd = emitJump(p, OP_JIFEND);
assignOp = genLValue(p, elem, &dummy); assignOp = genLValue(p, elem, &dummy);
emit(p, OP_XCHG); emit(p, OP_XCHG);
emit(p, assignOp); emit(p, assignOp);
emit(p, OP_POP); emit(p, OP_POP);
genLoop(p, body, 0, label, loopTop, jumpEnd); genLoop(p, body, 0, label, loopTop, jumpEnd);
emit(p, OP_POP); // Pull off the vector and index
emit(p, OP_POP);
} }
static int tokMatch(struct Token* a, struct Token* b) static int tokMatch(struct Token* a, struct Token* b)
@@ -518,9 +489,9 @@ static void genBreakContinue(struct Parser* p, struct Token* t)
bp = p->cg->loops[p->cg->loopTop - levels].breakIP; bp = p->cg->loops[p->cg->loopTop - levels].breakIP;
cp = p->cg->loops[p->cg->loopTop - levels].contIP; cp = p->cg->loops[p->cg->loopTop - levels].contIP;
for(i=0; i<levels; i++) for(i=0; i<levels; i++)
emit(p, OP_BREAK); emit(p, (i<levels-1) ? OP_BREAK2 : OP_BREAK);
if(t->type == TOK_BREAK) if(t->type == TOK_BREAK)
emit(p, OP_PUSHNIL); // breakIP is always a JIFNOT/JIFNIL! emit(p, OP_PUSHEND); // breakIP is always a JIFNOTPOP/JIFEND!
emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp); emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
} }
@@ -542,6 +513,8 @@ static void newLineEntry(struct Parser* p, int line)
static void genExpr(struct Parser* p, struct Token* t) static void genExpr(struct Parser* p, struct Token* t)
{ {
int i, dummy; int i, dummy;
if(!t) naParseError(p, "parse error", -1); // throw line -1...
p->errLine = t->line; // ...to use this one instead
if(t->line != p->cg->lastLine) if(t->line != p->cg->lastLine)
newLineEntry(p, t->line); newLineEntry(p, t->line);
p->cg->lastLine = t->line; p->cg->lastLine = t->line;
@@ -611,7 +584,7 @@ static void genExpr(struct Parser* p, struct Token* t)
case TOK_MINUS: case TOK_MINUS:
if(BINARY(t)) { if(BINARY(t)) {
genBinOp(OP_MINUS, p, t); // binary subtraction genBinOp(OP_MINUS, p, t); // binary subtraction
} else if(RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) { } else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
RIGHT(t)->num *= -1; // Pre-negate constants RIGHT(t)->num *= -1; // Pre-negate constants
genScalarConstant(p, RIGHT(t)); genScalarConstant(p, RIGHT(t));
} else { } else {
@@ -625,7 +598,7 @@ static void genExpr(struct Parser* p, struct Token* t)
break; break;
case TOK_DOT: case TOK_DOT:
genExpr(p, LEFT(t)); genExpr(p, LEFT(t));
if(RIGHT(t)->type != TOK_SYMBOL) if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
naParseError(p, "object field not symbol", RIGHT(t)->line); naParseError(p, "object field not symbol", RIGHT(t)->line);
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t))); emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
break; break;
@@ -656,7 +629,7 @@ static void genExpr(struct Parser* p, struct Token* t)
static void genExprList(struct Parser* p, struct Token* t) static void genExprList(struct Parser* p, struct Token* t)
{ {
if(t->type == TOK_SEMI) { if(t && t->type == TOK_SEMI) {
genExpr(p, LEFT(t)); genExpr(p, LEFT(t));
if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) { if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
emit(p, OP_POP); emit(p, OP_POP);
@@ -690,7 +663,7 @@ naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
// Now make a code object // Now make a code object
codeObj = naNewCode(p->context); codeObj = naNewCode(p->context);
code = codeObj.ref.ptr.code; code = PTR(codeObj).code;
// Parse the argument list, if any // Parse the argument list, if any
code->restArgSym = globals->argRef; code->restArgSym = globals->argRef;
+72 -16
View File
@@ -3,30 +3,86 @@
#include "nasal.h" #include "nasal.h"
#if defined(NASAL_NAN64)
// On 64 bit systems, Nasal non-numeric references are stored with a
// bitmask that sets the top 16 bits. As a double, this is a
// signalling NaN that cannot itself be produced by normal numerics
// code. The pointer value can be reconstructed if (and only if) we
// are guaranteed that all memory that can be pointed to by a naRef
// (i.e. all memory returned by naAlloc) lives in the bottom 48 bits
// of memory. Linux on x86_64, Win64, Solaris and Irix all have such
// policies with address spaces:
//
// http://msdn.microsoft.com/library/en-us/win64/win64/virtual_address_space.asp
// http://docs.sun.com/app/docs/doc/816-5138/6mba6ua5p?a=view
// http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi/
// ... 0650/bks/SGI_Developer/books/T_IRIX_Prog/sgi_html/ch01.html
//
// In the above, MS guarantees 44 bits of process address space, SGI
// 40, and Sun 43 (Solaris *does* place the stack in the "negative"
// address space at 0xffff..., but we don't care as naRefs will never
// point there). Linux doesn't document this rigorously, but testing
// shows that it allows 47 bits of address space (and current x86_64
// implementations are limited to 48 bits of virtual space anyway). So
// we choose 48 as the conservative compromise.
#define REFMAGIC ((1UL<<48) - 1)
#define _ULP(r) ((unsigned long long)((r).ptr))
#define REFPTR(r) (_ULP(r) & REFMAGIC)
#define IS_REF(r) ((_ULP(r) & ~REFMAGIC) == ~REFMAGIC)
// Portability note: this cast from a pointer type to naPtr (a union)
// is not defined in ISO C, it's a GCC extention that doesn't work on
// (at least) either the SUNWspro or MSVC compilers. Unfortunately,
// fixing this would require abandoning the naPtr union for a set of
// PTR_<type>() macros, which is a ton of work and a lot of extra
// code. And as all enabled 64 bit platforms are gcc anyway, and the
// 32 bit fallback code works in any case, this is acceptable for now.
#define PTR(r) ((naPtr)((struct naObj*)(_ULP(r) & REFMAGIC)))
#define SETPTR(r, p) ((r).ptr = (void*)((unsigned long long)p | ~REFMAGIC))
#define SETNUM(r, n) ((r).num = n)
#else
// On 32 bit systems where the pointer is half the width of the
// double, we store a special magic number in the structure to make
// the double a NaN. This must appear in the top bits of the double,
// which is why the structure layout is endianness-dependent.
#define NASAL_REFTAG 0x7ff56789 // == 2,146,789,257 decimal
#define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG)
#define PTR(r) ((r).ref.ptr)
#define SETPTR(r, p) ((r).ref.ptr.obj = (void*)p, (r).ref.reftag = NASAL_REFTAG)
#define SETNUM(r, n) ((r).ref.reftag = ~NASAL_REFTAG, (r).num = n)
#endif /* platform stuff */
enum { T_STR, T_VEC, T_HASH, T_CODE, 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! NUM_NASAL_TYPES }; // V. important that this come last!
#define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG) #define IS_NUM(r) (!IS_REF(r))
#define IS_NUM(r) ((r).ref.reftag != NASAL_REFTAG) #define IS_OBJ(r) (IS_REF(r) && PTR(r).obj != 0)
#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0) #define IS_NIL(r) (IS_REF(r) && PTR(r).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_STR(r) (IS_OBJ(r) && PTR(r).obj->type == T_STR)
#define IS_NIL(r) (IS_REF((r)) && (r).ref.ptr.obj == 0) #define IS_VEC(r) (IS_OBJ(r) && PTR(r).obj->type == T_VEC)
#define IS_STR(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_STR) #define IS_HASH(r) (IS_OBJ(r) && PTR(r).obj->type == T_HASH)
#define IS_VEC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_VEC) #define IS_CODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CODE)
#define IS_HASH(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_HASH) #define IS_FUNC(r) (IS_OBJ(r) && PTR(r).obj->type == T_FUNC)
#define IS_CODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CODE) #define IS_CCODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CCODE)
#define IS_FUNC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_FUNC) #define IS_GHOST(r) (IS_OBJ(r) && PTR(r).obj->type == T_GHOST)
#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_CONTAINER(r) (IS_VEC(r)||IS_HASH(r))
#define IS_SCALAR(r) (IS_NUM((r)) || IS_STR((r))) #define IS_SCALAR(r) (IS_NUM(r) || IS_STR(r))
#define IDENTICAL(a, b) (IS_REF(a) && IS_REF(b) \ #define IDENTICAL(a, b) (IS_REF(a) && IS_REF(b) \
&& a.ref.ptr.obj == b.ref.ptr.obj) && PTR(a).obj == PTR(b).obj)
#define MUTABLE(r) (IS_STR(r) && (r).ref.ptr.str->hashcode == 0) #define MUTABLE(r) (IS_STR(r) && PTR(r).str->hashcode == 0)
// This is a macro instead of a separate struct to allow compilers to // 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 // avoid padding. GCC on x86, at least, will always pad the size of
// an embedded struct up to 32 bits. Doing it this way allows the // an embedded struct up to 32 bits. Doing it this way allows the
// implementing objects to pack in 16 bits worth of data "for free". // implementing objects to pack in 16 bits worth of data "for free".
#define GC_HEADER \ #define GC_HEADER \
+27 -37
View File
@@ -2,7 +2,7 @@
#include "data.h" #include "data.h"
#include "code.h" #include "code.h"
#define MIN_BLOCK_SIZE 256 #define MIN_BLOCK_SIZE 32
static void reap(struct naPool* p); static void reap(struct naPool* p);
static void mark(naRef r); static void mark(naRef r);
@@ -27,7 +27,7 @@ static void marktemps(struct Context* c)
int i; int i;
naRef r = naNil(); naRef r = naNil();
for(i=0; i<c->ntemps; i++) { for(i=0; i<c->ntemps; i++) {
r.ref.ptr.obj = c->temps[i]; SETPTR(r, c->temps[i]);
mark(r); mark(r);
} }
} }
@@ -108,7 +108,7 @@ static void bottleneck()
if(g->waitCount >= g->nThreads - 1) { if(g->waitCount >= g->nThreads - 1) {
freeDead(); freeDead();
if(g->needGC) garbageCollect(); if(g->needGC) garbageCollect();
if(g->waitCount) naSemUpAll(g->sem, g->waitCount); if(g->waitCount) naSemUp(g->sem, g->waitCount);
g->bottleneck = 0; g->bottleneck = 0;
} }
} }
@@ -130,34 +130,21 @@ static void naCode_gcclean(struct naCode* o)
static void naGhost_gcclean(struct naGhost* g) static void naGhost_gcclean(struct naGhost* g)
{ {
if(g->ptr) g->gtype->destroy(g->ptr); if(g->ptr && g->gtype->destroy) g->gtype->destroy(g->ptr);
g->ptr = 0; g->ptr = 0;
} }
static void freeelem(struct naPool* p, struct naObj* o) static void freeelem(struct naPool* p, struct naObj* o)
{ {
// Free any intrinsic (i.e. non-garbage collected) storage the // Clean up any intrinsic storage the object might have...
// object might have
switch(p->type) { switch(p->type) {
case T_STR: case T_STR: naStr_gcclean ((struct naStr*) o); break;
naStr_gcclean((struct naStr*)o); case T_VEC: naVec_gcclean ((struct naVec*) o); break;
break; case T_HASH: naHash_gcclean ((struct naHash*) o); break;
case T_VEC: case T_CODE: naCode_gcclean ((struct naCode*) o); break;
naVec_gcclean((struct naVec*)o); case T_GHOST: naGhost_gcclean((struct naGhost*)o); break;
break;
case T_HASH:
naHash_gcclean((struct naHash*)o);
break;
case T_CODE:
naCode_gcclean((struct naCode*)o);
break;
case T_GHOST:
naGhost_gcclean((struct naGhost*)o);
break;
} }
p->free[p->nfree++] = o; // ...and add it to the free list
// And add it to the free list
p->free[p->nfree++] = o;
} }
static void newBlock(struct naPool* p, int need) static void newBlock(struct naPool* p, int need)
@@ -227,7 +214,7 @@ struct naObj** naGC_get(struct naPool* p, int n, int* nout)
static void markvec(naRef r) static void markvec(naRef r)
{ {
int i; int i;
struct VecRec* vr = r.ref.ptr.vec->rec; struct VecRec* vr = PTR(r).vec->rec;
if(!vr) return; if(!vr) return;
for(i=0; i<vr->size; i++) for(i=0; i<vr->size; i++)
mark(vr->array[i]); mark(vr->array[i]);
@@ -236,7 +223,7 @@ static void markvec(naRef r)
static void markhash(naRef r) static void markhash(naRef r)
{ {
int i; int i;
struct HashRec* hr = r.ref.ptr.hash->rec; struct HashRec* hr = PTR(r).hash->rec;
if(!hr) return; if(!hr) return;
for(i=0; i < (1<<hr->lgalloced); i++) { for(i=0; i < (1<<hr->lgalloced); i++) {
struct HashNode* hn = hr->table[i]; struct HashNode* hn = hr->table[i];
@@ -257,22 +244,22 @@ static void mark(naRef r)
if(IS_NUM(r) || IS_NIL(r)) if(IS_NUM(r) || IS_NIL(r))
return; return;
if(r.ref.ptr.obj->mark == 1) if(PTR(r).obj->mark == 1)
return; return;
r.ref.ptr.obj->mark = 1; PTR(r).obj->mark = 1;
switch(r.ref.ptr.obj->type) { switch(PTR(r).obj->type) {
case T_VEC: markvec(r); break; case T_VEC: markvec(r); break;
case T_HASH: markhash(r); break; case T_HASH: markhash(r); break;
case T_CODE: case T_CODE:
mark(r.ref.ptr.code->srcFile); mark(PTR(r).code->srcFile);
for(i=0; i<r.ref.ptr.code->nConstants; i++) for(i=0; i<PTR(r).code->nConstants; i++)
mark(r.ref.ptr.code->constants[i]); mark(PTR(r).code->constants[i]);
break; break;
case T_FUNC: case T_FUNC:
mark(r.ref.ptr.func->code); mark(PTR(r).func->code);
mark(r.ref.ptr.func->namespace); mark(PTR(r).func->namespace);
mark(r.ref.ptr.func->next); mark(PTR(r).func->next);
break; break;
} }
} }
@@ -283,7 +270,6 @@ static void reap(struct naPool* p)
{ {
struct Block* b; struct Block* b;
int elem, freesz, total = poolsize(p); int elem, freesz, total = poolsize(p);
p->nfree = 0;
freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total; freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total;
freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ); freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ);
if(p->freesz < freesz) { if(p->freesz < freesz) {
@@ -292,6 +278,9 @@ static void reap(struct naPool* p)
p->free = p->free0 = naAlloc(sizeof(void*) * p->freesz); p->free = p->free0 = naAlloc(sizeof(void*) * p->freesz);
} }
p->nfree = 0;
p->free = p->free0;
for(b = p->blocks; b; b = b->next) for(b = p->blocks; b; b = b->next)
for(elem=0; elem < b->size; elem++) { for(elem=0; elem < b->size; elem++) {
struct naObj* o = (struct naObj*)(b->block + elem * p->elemsz); struct naObj* o = (struct naObj*)(b->block + elem * p->elemsz);
@@ -300,6 +289,8 @@ static void reap(struct naPool* p)
o->mark = 0; o->mark = 0;
} }
p->freetop = p->nfree;
// allocs of this type until the next collection // allocs of this type until the next collection
globals->allocCount += total/2; globals->allocCount += total/2;
@@ -312,7 +303,6 @@ static void reap(struct naPool* p)
if(need > 0) if(need > 0)
newBlock(p, need); newBlock(p, need);
} }
p->freetop = p->nfree;
} }
// Does the swap, returning the old value // Does the swap, returning the old value
+35 -30
View File
@@ -3,9 +3,7 @@
#define MIN_HASH_SIZE 4 #define MIN_HASH_SIZE 4
#define EQUAL(a, b) (((a).ref.reftag == (b).ref.reftag \ #define EQUAL(a, b) (IDENTICAL(a, b) || naEqual(a, b))
&& (a).ref.ptr.obj == (b).ref.ptr.obj) \
|| naEqual(a, b))
#define HASH_MAGIC 2654435769u #define HASH_MAGIC 2654435769u
@@ -28,15 +26,15 @@ static unsigned int hashcode(naRef r)
// 2*sizeof(int). // 2*sizeof(int).
unsigned int* p = (unsigned int*)&(r.num); unsigned int* p = (unsigned int*)&(r.num);
return p[0] ^ p[1]; return p[0] ^ p[1];
} else if(r.ref.ptr.str->hashcode) { } else if(PTR(r).str->hashcode) {
return r.ref.ptr.str->hashcode; return PTR(r).str->hashcode;
} else { } else {
// This is Daniel Bernstein's djb2 hash function that I found // This is Daniel Bernstein's djb2 hash function that I found
// on the web somewhere. It appears to work pretty well. // on the web somewhere. It appears to work pretty well.
unsigned int i, hash = 5831; unsigned int i, hash = 5831;
for(i=0; i<r.ref.ptr.str->len; i++) for(i=0; i<PTR(r).str->len; i++)
hash = (hash * 33) ^ r.ref.ptr.str->data[i]; hash = (hash * 33) ^ PTR(r).str->data[i];
r.ref.ptr.str->hashcode = hash; PTR(r).str->hashcode = hash;
return hash; return hash;
} }
} }
@@ -49,7 +47,7 @@ static unsigned int hashcolumn(struct HashRec* h, naRef key)
return (HASH_MAGIC * hashcode(key)) >> (32 - h->lgalloced); return (HASH_MAGIC * hashcode(key)) >> (32 - h->lgalloced);
} }
static struct HashRec* hashrealloc(struct naHash* hash) static struct HashRec* resize(struct naHash* hash)
{ {
struct HashRec *h, *h0 = hash->rec; struct HashRec *h, *h0 = hash->rec;
int lga, cols, need = h0 ? h0->size - h0->dels : MIN_HASH_SIZE; int lga, cols, need = h0 ? h0->size - h0->dels : MIN_HASH_SIZE;
@@ -90,7 +88,7 @@ int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
int col = (HASH_MAGIC * sym->hashcode) >> (32 - h->lgalloced); int col = (HASH_MAGIC * sym->hashcode) >> (32 - h->lgalloced);
struct HashNode* hn = h->table[col]; struct HashNode* hn = h->table[col];
while(hn) { while(hn) {
if(hn->key.ref.ptr.str == sym) { if(PTR(hn->key).str == sym) {
*out = hn->val; *out = hn->val;
return 1; return 1;
} }
@@ -103,25 +101,32 @@ int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
static struct HashNode* find(struct naHash* hash, naRef key) static struct HashNode* find(struct naHash* hash, naRef key)
{ {
struct HashRec* h = hash->rec; struct HashRec* h = hash->rec;
if(h) { struct HashNode* hn;
struct HashNode* hn = h->table[hashcolumn(h, key)]; if(!h) return 0;
while(hn) { for(hn = h->table[hashcolumn(h, key)]; hn; hn = hn->next)
if(EQUAL(key, hn->key)) if(EQUAL(key, hn->key))
return hn; return hn;
hn = hn->next;
}
}
return 0; return 0;
} }
// Make a temporary string on the stack // Make a temporary string on the stack
static void tmpStr(naRef* out, struct naStr* str, char* key) static void tmpStr(naRef* out, struct naStr* str, const char* key)
{ {
str->len = 0; str->len = 0;
str->type = T_STR;
str->data = (unsigned char*)key; str->data = (unsigned char*)key;
str->hashcode = 0;
while(key[str->len]) str->len++; while(key[str->len]) str->len++;
*out = naNil(); *out = naNil();
out->ref.ptr.str = str; SETPTR(*out, str);
}
int naMember_cget(naRef obj, const char* field, naRef* out)
{
naRef key;
struct naStr str;
tmpStr(&key, &str, field);
return naMember_get(obj, key, out);
} }
naRef naHash_cget(naRef hash, char* key) naRef naHash_cget(naRef hash, char* key)
@@ -145,7 +150,7 @@ void naHash_cset(naRef hash, char* key, naRef val)
int naHash_get(naRef hash, naRef key, naRef* out) int naHash_get(naRef hash, naRef key, naRef* out)
{ {
if(IS_HASH(hash)) { if(IS_HASH(hash)) {
struct HashNode* n = find(hash.ref.ptr.hash, key); struct HashNode* n = find(PTR(hash).hash, key);
if(n) { *out = n->val; return 1; } if(n) { *out = n->val; return 1; }
} }
return 0; return 0;
@@ -155,7 +160,7 @@ int naHash_get(naRef hash, naRef key, naRef* out)
int naHash_tryset(naRef hash, naRef key, naRef val) int naHash_tryset(naRef hash, naRef key, naRef val)
{ {
if(IS_HASH(hash)) { if(IS_HASH(hash)) {
struct HashNode* n = find(hash.ref.ptr.hash, key); struct HashNode* n = find(PTR(hash).hash, key);
if(n) n->val = val; if(n) n->val = val;
return n != 0; return n != 0;
} }
@@ -171,8 +176,8 @@ void naHash_newsym(struct naHash* hash, naRef* sym, naRef* val)
int col; int col;
struct HashRec* h = hash->rec; struct HashRec* h = hash->rec;
while(!h || h->size >= 1<<h->lgalloced) while(!h || h->size >= 1<<h->lgalloced)
h = hashrealloc(hash); h = resize(hash);
col = (HASH_MAGIC * sym->ref.ptr.str->hashcode) >> (32 - h->lgalloced); col = (HASH_MAGIC * PTR(*sym).str->hashcode) >> (32 - h->lgalloced);
INSERT(h, *sym, *val, col); INSERT(h, *sym, *val, col);
} }
@@ -195,10 +200,10 @@ void naHash_set(naRef hash, naRef key, naRef val)
struct HashRec* h; struct HashRec* h;
struct HashNode* n; struct HashNode* n;
if(!IS_HASH(hash)) return; if(!IS_HASH(hash)) return;
if((n = find(hash.ref.ptr.hash, key))) { n->val = val; return; } if((n = find(PTR(hash).hash, key))) { n->val = val; return; }
h = hash.ref.ptr.hash->rec; h = PTR(hash).hash->rec;
while(!h || h->size >= 1<<h->lgalloced) while(!h || h->size >= 1<<h->lgalloced)
h = hashrealloc(hash.ref.ptr.hash); h = resize(PTR(hash).hash);
col = hashcolumn(h, key); col = hashcolumn(h, key);
INSERT(h, key, val, hashcolumn(h, key)); INSERT(h, key, val, hashcolumn(h, key));
chkcycle(h->table[col], h->size - h->dels); chkcycle(h->table[col], h->size - h->dels);
@@ -206,7 +211,7 @@ void naHash_set(naRef hash, naRef key, naRef val)
void naHash_delete(naRef hash, naRef key) void naHash_delete(naRef hash, naRef key)
{ {
struct HashRec* h = hash.ref.ptr.hash->rec; struct HashRec* h = PTR(hash).hash->rec;
int col; int col;
struct HashNode *last=0, *hn; struct HashNode *last=0, *hn;
if(!IS_HASH(hash) || !h) return; if(!IS_HASH(hash) || !h) return;
@@ -227,7 +232,7 @@ void naHash_delete(naRef hash, naRef key)
void naHash_keys(naRef dst, naRef hash) void naHash_keys(naRef dst, naRef hash)
{ {
int i; int i;
struct HashRec* h = hash.ref.ptr.hash->rec; struct HashRec* h = PTR(hash).hash->rec;
if(!IS_HASH(hash) || !h) return; if(!IS_HASH(hash) || !h) return;
for(i=0; i<(1<<h->lgalloced); i++) { for(i=0; i<(1<<h->lgalloced); i++) {
struct HashNode* hn = h->table[i]; struct HashNode* hn = h->table[i];
@@ -240,7 +245,7 @@ void naHash_keys(naRef dst, naRef hash)
int naHash_size(naRef hash) int naHash_size(naRef hash)
{ {
struct HashRec* h = hash.ref.ptr.hash->rec; struct HashRec* h = PTR(hash).hash->rec;
if(!IS_HASH(hash) || !h) return 0; if(!IS_HASH(hash) || !h) return 0;
return h->size - h->dels; return h->size - h->dels;
} }
+22 -29
View File
@@ -11,7 +11,7 @@ naGhostType naIOGhostType = { ghostDestroy };
static struct naIOGhost* ioghost(naRef r) static struct naIOGhost* ioghost(naRef r)
{ {
if(naGhost_type(r) == &naIOGhostType) if(naGhost_type(r) == &naIOGhostType && IOGHOST(r)->handle)
return naGhost_ptr(r); return naGhost_ptr(r);
return 0; return 0;
} }
@@ -32,9 +32,9 @@ static naRef f_read(naContext c, naRef me, int argc, naRef* args)
naRef len = argc > 2 ? naNumValue(args[2]) : naNil(); naRef len = argc > 2 ? naNumValue(args[2]) : naNil();
if(!g || !MUTABLE(str) || !IS_NUM(len)) if(!g || !MUTABLE(str) || !IS_NUM(len))
naRuntimeError(c, "bad argument to read()"); naRuntimeError(c, "bad argument to read()");
if(str.ref.ptr.str->len < (int)len.num) if(PTR(str).str->len < (int)len.num)
naRuntimeError(c, "string not big enough for read"); naRuntimeError(c, "string not big enough for read");
return naNum(g->type->read(c, g->handle, (char*)str.ref.ptr.str->data, return naNum(g->type->read(c, g->handle, (char*)PTR(str).str->data,
(int)len.num)); (int)len.num));
} }
@@ -44,8 +44,8 @@ static naRef f_write(naContext c, naRef me, int argc, naRef* args)
naRef str = argc > 1 ? args[1] : naNil(); naRef str = argc > 1 ? args[1] : naNil();
if(!g || !IS_STR(str)) if(!g || !IS_STR(str))
naRuntimeError(c, "bad argument to write()"); naRuntimeError(c, "bad argument to write()");
return naNum(g->type->write(c, g->handle, (char*)str.ref.ptr.str->data, return naNum(g->type->write(c, g->handle, (char*)PTR(str).str->data,
str.ref.ptr.str->len)); PTR(str).str->len));
} }
static naRef f_seek(naContext c, naRef me, int argc, naRef* args) static naRef f_seek(naContext c, naRef me, int argc, naRef* args)
@@ -113,7 +113,8 @@ static int iotell(naContext c, void* f)
static void iodestroy(void* f) static void iodestroy(void* f)
{ {
ioclose(0, f); if(f != stdin && f != stdout && f != stderr)
ioclose(0, f);
} }
struct naIOType naStdIOType = { ioclose, ioread, iowrite, ioseek, struct naIOType naStdIOType = { ioclose, ioread, iowrite, ioseek,
@@ -133,8 +134,8 @@ static naRef f_open(naContext c, naRef me, int argc, naRef* args)
naRef file = argc > 0 ? naStringValue(c, args[0]) : naNil(); naRef file = argc > 0 ? naStringValue(c, args[0]) : naNil();
naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil(); naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
if(!IS_STR(file)) naRuntimeError(c, "bad argument to open()"); if(!IS_STR(file)) naRuntimeError(c, "bad argument to open()");
f = fopen((char*)file.ref.ptr.str->data, f = fopen((char*)PTR(file).str->data,
IS_STR(mode) ? (const char*)mode.ref.ptr.str->data : "r"); IS_STR(mode) ? (const char*)PTR(mode).str->data : "rb");
if(!f) naRuntimeError(c, strerror(errno)); if(!f) naRuntimeError(c, strerror(errno));
return naIOGhost(c, f); return naIOGhost(c, f);
} }
@@ -169,7 +170,8 @@ static naRef f_readln(naContext ctx, naRef me, int argc, naRef* args)
if(c == '\r') { if(c == '\r') {
char c2 = getcguard(ctx, g->handle, buf); char c2 = getcguard(ctx, g->handle, buf);
if(c2 != EOF && c2 != '\n') if(c2 != EOF && c2 != '\n')
ungetc(c2, g->handle); if(EOF == ungetc(c2, g->handle))
break;
break; break;
} }
buf[i++] = c; buf[i++] = c;
@@ -186,7 +188,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
struct stat s; struct stat s;
naRef result, path = argc > 0 ? naStringValue(ctx, args[0]) : naNil(); naRef result, path = argc > 0 ? naStringValue(ctx, args[0]) : naNil();
if(!IS_STR(path)) naRuntimeError(ctx, "bad argument to stat()"); if(!IS_STR(path)) naRuntimeError(ctx, "bad argument to stat()");
if(stat((char*)path.ref.ptr.str->data, &s) < 0) { if(stat((char*)PTR(path).str->data, &s) < 0) {
if(errno == ENOENT) return naNil(); if(errno == ENOENT) return naNil();
naRuntimeError(ctx, strerror(errno)); naRuntimeError(ctx, strerror(errno));
} }
@@ -199,7 +201,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
return result; return result;
} }
static struct func { char* name; naCFunction func; } funcs[] = { static naCFuncItem funcs[] = {
{ "close", f_close }, { "close", f_close },
{ "read", f_read }, { "read", f_read },
{ "write", f_write }, { "write", f_write },
@@ -208,26 +210,17 @@ static struct func { char* name; naCFunction func; } funcs[] = {
{ "open", f_open }, { "open", f_open },
{ "readln", f_readln }, { "readln", f_readln },
{ "stat", f_stat }, { "stat", f_stat },
{ 0 }
}; };
static void setsym(naContext c, naRef hash, char* sym, naRef val) naRef naInit_io(naContext c)
{ {
naRef name = naStr_fromdata(naNewString(c), sym, strlen(sym)); naRef ns = naGenLib(c, funcs);
naHash_set(hash, naInternSymbol(name), val); naAddSym(c, ns, "SEEK_SET", naNum(SEEK_SET));
} naAddSym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
naAddSym(c, ns, "SEEK_END", naNum(SEEK_END));
naRef naIOLib(naContext c) naAddSym(c, ns, "stdin", naIOGhost(c, stdin));
{ naAddSym(c, ns, "stdout", naIOGhost(c, stdout));
naRef ns = naNewHash(c); naAddSym(c, ns, "stderr", naIOGhost(c, stderr));
int i, n = sizeof(funcs)/sizeof(struct func);
for(i=0; i<n; i++)
setsym(c, ns, funcs[i].name,
naNewFunc(c, naNewCCode(c, funcs[i].func)));
setsym(c, ns, "SEEK_SET", naNum(SEEK_SET));
setsym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
setsym(c, ns, "SEEK_END", naNum(SEEK_END));
setsym(c, ns, "stdin", naIOGhost(c, stdin));
setsym(c, ns, "stdout", naIOGhost(c, stdout));
setsym(c, ns, "stderr", naIOGhost(c, stderr));
return ns; return ns;
} }
+29 -11
View File
@@ -109,7 +109,20 @@ static int lineEnd(struct Parser* p, int line)
static void newToken(struct Parser* p, int pos, int type, static void newToken(struct Parser* p, int pos, int type,
char* str, int slen, double num) char* str, int slen, double num)
{ {
struct Token* tok; struct Token *tok, *last = p->tree.lastChild;
/* Adjacent string literals get concatenated */
if(type == TOK_LITERAL && str) {
if(last && last->type == TOK_LITERAL) {
int i, len1 = last->strlen;
char* str2 = naParseAlloc(p, len1 + slen);
for(i=0; i<len1; i++) str2[i] = last->str[i];
for(i=0; i<slen; i++) str2[i+len1] = str[i];
last->str = str2;
last->strlen += slen;
return;
}
}
tok = naParseAlloc(p, sizeof(struct Token)); tok = naParseAlloc(p, sizeof(struct Token));
tok->type = type; tok->type = type;
@@ -119,17 +132,18 @@ static void newToken(struct Parser* p, int pos, int type,
tok->num = num; tok->num = num;
tok->parent = &p->tree; tok->parent = &p->tree;
tok->next = 0; tok->next = 0;
tok->prev = p->tree.lastChild; tok->prev = last;
tok->children = 0; tok->children = 0;
tok->lastChild = 0; tok->lastChild = 0;
// Context sensitivity hack: a "-" following a binary operator of // Context sensitivity hack: a "-" following a binary operator of
// higher precedence (MUL and DIV, basically) must be a unary // equal or higher precedence must be a unary negation. Needed to
// negation. Needed to get precedence right in the parser for // get precedence right in the parser for expressiong like "a * -2"
// expressiong like "a * -2" if(type == TOK_MINUS && tok->prev) {
if(type == TOK_MINUS && tok->prev) int pt = tok->prev->type;
if(tok->prev->type == TOK_MUL || tok->prev->type == TOK_DIV) if(pt==TOK_PLUS||pt==TOK_MINUS||pt==TOK_CAT||pt==TOK_MUL||pt==TOK_DIV)
tok->type = type = TOK_NEG; tok->type = type = TOK_NEG;
}
if(!p->tree.children) p->tree.children = tok; if(!p->tree.children) p->tree.children = tok;
if(p->tree.lastChild) p->tree.lastChild->next = tok; if(p->tree.lastChild) p->tree.lastChild->next = tok;
@@ -179,6 +193,7 @@ static void dqEscape(char* buf, int len, int index, struct Parser* p,
case 'n': *cOut = '\n'; break; case 'n': *cOut = '\n'; break;
case 't': *cOut = '\t'; break; case 't': *cOut = '\t'; break;
case '\\': *cOut = '\\'; break; case '\\': *cOut = '\\'; break;
case '`': *cOut = '`'; break;
case 'x': case 'x':
if(len < 4) error(p, "unterminated string", index); if(len < 4) error(p, "unterminated string", index);
*cOut = (char)((hexc(buf[2], p, index)<<4) | hexc(buf[3], p, index)); *cOut = (char)((hexc(buf[2], p, index)<<4) | hexc(buf[3], p, index));
@@ -191,11 +206,12 @@ 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) static void charLiteral(struct Parser* p, int index, char* s, int len)
{ {
if(len != 1) error(p, "character constant not single character", index); int n, c;
newToken(p, index, TOK_LITERAL, 0, 0, *s); c = naLexUtf8C(s, len, &n);
if(c < 0 || n != len) error(p, "invalid utf8 character constant", index);
newToken(p, index, TOK_LITERAL, 0, 0, c);
} }
// Read in a string literal // Read in a string literal
@@ -317,6 +333,7 @@ static int tryLexemes(struct Parser* p, int index, int* lexemeOut)
return best; return best;
} }
#define ISNUM(c) ((c) >= '0' && (c) <= '9')
void naLex(struct Parser* p) void naLex(struct Parser* p)
{ {
int i = 0; int i = 0;
@@ -338,7 +355,8 @@ void naLex(struct Parser* p)
i = lexStringLiteral(p, i, c); i = lexStringLiteral(p, i, c);
break; break;
default: default:
if(c >= '0' && c <= '9') i = lexNumLiteral(p, i); if(ISNUM(c) || (c == '.' && (i+1)<p->len && ISNUM(p->buf[i+1])))
i = lexNumLiteral(p, i);
else handled = 0; else handled = 0;
} }
+232 -145
View File
@@ -5,6 +5,7 @@
#include <string.h> #include <string.h>
#ifdef _MSC_VER // sigh... #ifdef _MSC_VER // sigh...
#define snprintf _snprintf
#define vsnprintf _vsnprintf #define vsnprintf _vsnprintf
#endif #endif
@@ -14,9 +15,14 @@
#define NEWSTR(c, s, l) naStr_fromdata(naNewString(c), s, l) #define NEWSTR(c, s, l) naStr_fromdata(naNewString(c), s, l)
#define NEWCSTR(c, s) NEWSTR(c, s, strlen(s)) #define NEWCSTR(c, s) NEWSTR(c, s, strlen(s))
static naRef size(naContext c, naRef me, int argc, naRef* args) // Generic argument error, assumes that the symbol "c" is a naContext,
// and that the __FUNCTION__ string is of the form "f_NASALSYMBOL".
#define ARGERR() \
naRuntimeError(c, "bad/missing argument to %s()", (__FUNCTION__ + 2))
static naRef f_size(naContext c, naRef me, int argc, naRef* args)
{ {
if(argc == 0) return naNil(); if(argc == 0) ARGERR();
if(naIsString(args[0])) return naNum(naStr_len(args[0])); if(naIsString(args[0])) return naNum(naStr_len(args[0]));
if(naIsVector(args[0])) return naNum(naVec_size(args[0])); if(naIsVector(args[0])) return naNum(naVec_size(args[0]));
if(naIsHash(args[0])) return naNum(naHash_size(args[0])); if(naIsHash(args[0])) return naNum(naHash_size(args[0]));
@@ -24,41 +30,37 @@ static naRef size(naContext c, naRef me, int argc, naRef* args)
return naNil(); return naNil();
} }
static naRef keys(naContext c, naRef me, int argc, naRef* args) static naRef f_keys(naContext c, naRef me, int argc, naRef* args)
{ {
naRef v, h = args[0]; naRef v, h = argc > 0 ? args[0] : naNil();
if(!naIsHash(h)) return naNil(); if(!naIsHash(h)) ARGERR();
v = naNewVector(c); v = naNewVector(c);
naHash_keys(v, h); naHash_keys(v, h);
return v; return v;
} }
static naRef append(naContext c, naRef me, int argc, naRef* args) static naRef f_append(naContext c, naRef me, int argc, naRef* args)
{ {
int i; int i;
if(argc < 2) return naNil(); if(argc < 2 || !naIsVector(args[0])) ARGERR();
if(!naIsVector(args[0])) return naNil();
for(i=1; i<argc; i++) naVec_append(args[0], args[i]); for(i=1; i<argc; i++) naVec_append(args[0], args[i]);
return args[0]; return args[0];
} }
static naRef pop(naContext c, naRef me, int argc, naRef* args) static naRef f_pop(naContext c, naRef me, int argc, naRef* args)
{ {
if(argc < 1 || !naIsVector(args[0])) return naNil(); if(argc < 1 || !naIsVector(args[0])) ARGERR();
return naVec_removelast(args[0]); return naVec_removelast(args[0]);
} }
static naRef setsize(naContext c, naRef me, int argc, naRef* args) static naRef f_setsize(naContext c, naRef me, int argc, naRef* args)
{ {
int sz; if(argc < 2 || !naIsVector(args[0])) ARGERR();
if(argc < 2) return naNil(); naVec_setsize(args[0], (int)naNumValue(args[1]).num);
sz = (int)naNumValue(args[1]).num;
if(!naIsVector(args[0])) return naNil();
naVec_setsize(args[0], sz);
return args[0]; return args[0];
} }
static naRef subvec(naContext c, naRef me, int argc, naRef* args) static naRef f_subvec(naContext c, naRef me, int argc, naRef* args)
{ {
int i; int i;
naRef nlen, result, v = args[0]; naRef nlen, result, v = args[0];
@@ -67,8 +69,8 @@ static naRef subvec(naContext c, naRef me, int argc, naRef* args)
nlen = argc > 2 ? naNumValue(args[2]) : naNil(); nlen = argc > 2 ? naNumValue(args[2]) : naNil();
if(!naIsNil(nlen)) if(!naIsNil(nlen))
len = (int)nlen.num; len = (int)nlen.num;
if(!naIsVector(v) || start < 0 || start >= naVec_size(v) || len < 0) if(!naIsVector(v) || start < 0 || start > naVec_size(v) || len < 0)
return naNil(); ARGERR();
if(naIsNil(nlen) || len > naVec_size(v) - start) if(naIsNil(nlen) || len > naVec_size(v) - start)
len = naVec_size(v) - start; len = naVec_size(v) - start;
result = naNewVector(c); result = naNewVector(c);
@@ -78,13 +80,14 @@ static naRef subvec(naContext c, naRef me, int argc, naRef* args)
return result; return result;
} }
static naRef delete(naContext c, naRef me, int argc, naRef* args) static naRef f_delete(naContext c, naRef me, int argc, naRef* args)
{ {
if(argc > 1 && naIsHash(args[0])) naHash_delete(args[0], args[1]); if(argc < 2 || !naIsHash(args[0])) ARGERR();
return naNil(); naHash_delete(args[0], args[1]);
return args[0];
} }
static naRef intf(naContext c, naRef me, int argc, naRef* args) static naRef f_int(naContext c, naRef me, int argc, naRef* args)
{ {
if(argc > 0) { if(argc > 0) {
naRef n = naNumValue(args[0]); naRef n = naNumValue(args[0]);
@@ -92,15 +95,16 @@ static naRef intf(naContext c, naRef me, int argc, naRef* args)
if(n.num < 0) n.num = -floor(-n.num); if(n.num < 0) n.num = -floor(-n.num);
else n.num = floor(n.num); else n.num = floor(n.num);
return n; return n;
} else return naNil(); } else ARGERR();
return naNil();
} }
static naRef num(naContext c, naRef me, int argc, naRef* args) static naRef f_num(naContext c, naRef me, int argc, naRef* args)
{ {
return argc > 0 ? naNumValue(args[0]) : naNil(); return argc > 0 ? naNumValue(args[0]) : naNil();
} }
static naRef streq(naContext c, naRef me, int argc, naRef* args) static naRef f_streq(naContext c, naRef me, int argc, naRef* args)
{ {
return argc > 1 ? naNum(naStrEqual(args[0], args[1])) : naNil(); return argc > 1 ? naNum(naStrEqual(args[0], args[1])) : naNil();
} }
@@ -110,7 +114,7 @@ static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
char *a, *b; char *a, *b;
int i, alen, blen; int i, alen, blen;
if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1])) if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1]))
naRuntimeError(c, "bad argument to cmp"); ARGERR();
a = naStr_data(args[0]); a = naStr_data(args[0]);
alen = naStr_len(args[0]); alen = naStr_len(args[0]);
b = naStr_data(args[1]); b = naStr_data(args[1]);
@@ -122,45 +126,45 @@ static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
return naNum(alen == blen ? 0 : (alen < blen ? -1 : 1)); return naNum(alen == blen ? 0 : (alen < blen ? -1 : 1));
} }
static naRef substr(naContext c, naRef me, int argc, naRef* args) static naRef f_substr(naContext c, naRef me, int argc, naRef* args)
{ {
naRef src = argc > 1 ? args[0] : naNil(); int start, len, srclen;
naRef startR = argc > 1 ? naNumValue(args[1]) : naNil(); naRef src = argc > 0 ? args[0] : naNil();
naRef lenR = argc > 2 ? naNumValue(args[2]) : naNil(); naRef startr = argc > 1 ? naNumValue(args[1]) : naNil();
int start, len; naRef lenr = argc > 2 ? naNumValue(args[2]) : naNil();
if(!naIsString(src)) return naNil(); if(!naIsString(src)) ARGERR();
if(naIsNil(startR)) return naNil(); if(naIsNil(startr) || !naIsNum(startr)) ARGERR();
start = (int)startR.num; if(!naIsNil(lenr) && !naIsNum(lenr)) ARGERR();
if(naIsNil(lenR)) { srclen = naStr_len(src);
len = naStr_len(src) - start; start = (int)startr.num;
if(len < 0) return naNil(); len = naIsNum(lenr) ? (int)lenr.num : (srclen - start);
} else { if(start < 0) start += srclen;
lenR = naNumValue(lenR); if(start < 0) start = len = 0;
if(naIsNil(lenR)) return naNil(); if(start >= srclen) start = len = 0;
len = (int)lenR.num; if(len < 0) len = 0;
} if(len > srclen - start) len = srclen - start;
return naStr_substr(naNewString(c), src, start, len); return naStr_substr(naNewString(c), src, start, len);
} }
static naRef f_chr(naContext c, naRef me, int argc, naRef* args) static naRef f_chr(naContext c, naRef me, int argc, naRef* args)
{ {
char chr[1]; char chr[1];
naRef cr = argc ? naNumValue(args[0]) : naNil(); naRef cr = argc > 0 ? naNumValue(args[0]) : naNil();
if(IS_NIL(cr)) naRuntimeError(c, "chr argument not string"); if(IS_NIL(cr)) ARGERR();
chr[0] = (char)cr.num; chr[0] = (char)cr.num;
return NEWSTR(c, chr, 1); return NEWSTR(c, chr, 1);
} }
static naRef contains(naContext c, naRef me, int argc, naRef* args) static naRef f_contains(naContext c, naRef me, int argc, naRef* args)
{ {
naRef hash = argc > 0 ? args[0] : naNil(); naRef hash = argc > 0 ? args[0] : naNil();
naRef key = argc > 1 ? args[1] : naNil(); naRef key = argc > 1 ? args[1] : naNil();
if(naIsNil(hash) || naIsNil(key)) return naNil(); if(naIsNil(hash) || naIsNil(key)) ARGERR();
if(!naIsHash(hash)) return naNil(); if(!naIsHash(hash)) return naNil();
return naHash_get(hash, key, &key) ? naNum(1) : naNum(0); return naHash_get(hash, key, &key) ? naNum(1) : naNum(0);
} }
static naRef typeOf(naContext c, naRef me, int argc, naRef* args) static naRef f_typeof(naContext c, naRef me, int argc, naRef* args)
{ {
naRef r = argc > 0 ? args[0] : naNil(); naRef r = argc > 0 ? args[0] : naNil();
char* t = "unknown"; char* t = "unknown";
@@ -171,8 +175,20 @@ static naRef typeOf(naContext c, naRef me, int argc, naRef* args)
else if(naIsHash(r)) t = "hash"; else if(naIsHash(r)) t = "hash";
else if(naIsFunc(r)) t = "func"; else if(naIsFunc(r)) t = "func";
else if(naIsGhost(r)) t = "ghost"; else if(naIsGhost(r)) t = "ghost";
r = NEWCSTR(c, t); return NEWCSTR(c, t);
return r; }
static naRef f_ghosttype(naContext c, naRef me, int argc, naRef* args)
{
naRef g = argc > 0 ? args[0] : naNil();
if(!naIsGhost(g)) return naNil();
if(naGhost_type(g)->name) {
return NEWCSTR(c, (char*)naGhost_type(g)->name);
} else {
char buf[32];
sprintf(buf, "%p", naGhost_type(g));
return NEWCSTR(c, buf);
}
} }
static naRef f_compile(naContext c, naRef me, int argc, naRef* args) static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
@@ -180,14 +196,24 @@ static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
int errLine; int errLine;
naRef script, code, fname; naRef script, code, fname;
script = argc > 0 ? args[0] : naNil(); script = argc > 0 ? args[0] : naNil();
if(!naIsString(script)) return naNil(); fname = argc > 1 ? args[1] : NEWCSTR(c, "<compile>");
fname = NEWCSTR(c, "<compile>"); if(!naIsString(script) || !naIsString(fname)) return naNil();
code = naParseCode(c, fname, 1, code = naParseCode(c, fname, 1,
naStr_data(script), naStr_len(script), &errLine); naStr_data(script), naStr_len(script), &errLine);
if(!naIsCode(code)) return naNil(); // FIXME: export error to caller... if(naIsNil(code)) {
char buf[256];
snprintf(buf, sizeof(buf), "Parse error: %s at line %d",
naGetError(c), errLine);
c->dieArg = NEWCSTR(c, buf);
naRuntimeError(c, "__die__");
}
return naBindToContext(c, code); return naBindToContext(c, code);
} }
// FIXME: need a place to save the current IP when we get an error so
// that it can be reset if we get a die()/naRethrowError() situation
// later. Right now, the IP on the stack trace is the line of the
// die() call, when it should be this one...
static naRef f_call(naContext c, naRef me, int argc, naRef* args) static naRef f_call(naContext c, naRef me, int argc, naRef* args)
{ {
naContext subc; naContext subc;
@@ -199,33 +225,49 @@ static naRef f_call(naContext c, naRef me, int argc, naRef* args)
if(!IS_HASH(callme)) callme = naNil(); if(!IS_HASH(callme)) callme = naNil();
if(!IS_HASH(callns)) callns = naNil(); if(!IS_HASH(callns)) callns = naNil();
if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs))) if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
naRuntimeError(c, "bad argument to call()"); ARGERR();
subc = naNewContext();
subc->callParent = c; subc = naSubContext(c);
c->callChild = subc; vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec;
vr = IS_NIL(callargs) ? 0 : callargs.ref.ptr.vec->rec;
result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0, result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
callme, callns); callme, callns);
c->callChild = 0; if(!naGetError(subc)) {
if(argc > 2 && IS_VEC(args[argc-1])) { naFreeContext(subc);
if(!IS_NIL(subc->dieArg)) naVec_append(args[argc-1], subc->dieArg); return result;
else if(naGetError(subc))
naVec_append(args[argc-1], NEWCSTR(subc, naGetError(subc)));
} }
naFreeContext(subc);
return result; // Error handling. Note that we don't free the subcontext after an
// error, in case the user re-throws the same error or calls
// naContinue()
if(argc <= 2 || !IS_VEC(args[argc-1])) {
naRethrowError(subc);
} else {
int i, sd;
naRef errv = args[argc-1];
if(!IS_NIL(subc->dieArg)) naVec_append(errv, subc->dieArg);
else naVec_append(errv, NEWCSTR(subc, naGetError(subc)));
sd = naStackDepth(subc);
for(i=0; i<sd; i++) {
naVec_append(errv, naGetSourceFile(subc, i));
naVec_append(errv, naNum(naGetLine(subc, i)));
}
}
return naNil();
} }
static naRef f_die(naContext c, naRef me, int argc, naRef* args) static naRef f_die(naContext c, naRef me, int argc, naRef* args)
{ {
c->dieArg = argc > 0 ? args[0] : naNil(); naRef darg = argc > 0 ? args[0] : naNil();
if(!naIsNil(darg) && c->callChild && IDENTICAL(c->callChild->dieArg, darg))
naRethrowError(c->callChild);
c->dieArg = darg;
naRuntimeError(c, "__die__"); naRuntimeError(c, "__die__");
return naNil(); // never executes return naNil(); // never executes
} }
// Wrapper around vsnprintf, iteratively increasing the buffer size // Wrapper around vsnprintf, iteratively increasing the buffer size
// until it fits. Returned buffer should be freed by the caller. // until it fits. Returned buffer should be freed by the caller.
char* dosprintf(char* f, ...) static char* dosprintf(char* f, ...)
{ {
char* buf; char* buf;
va_list va; va_list va;
@@ -251,7 +293,7 @@ char* dosprintf(char* f, ...)
// all of ANSI C's syntax except for the "length modifier" feature. // all of ANSI C's syntax except for the "length modifier" feature.
// Note: this does not validate the format character returned in // Note: this does not validate the format character returned in
// "type". That is the caller's job. // "type". That is the caller's job.
static char* nextFormat(naContext ctx, char* f, char** out, int* len, char* type) static char* nextFormat(naContext c, char* f, char** out, int* len, char* type)
{ {
// Skip to the start of the format string // Skip to the start of the format string
while(*f && *f != '%') f++; while(*f && *f != '%') f++;
@@ -266,44 +308,44 @@ static char* nextFormat(naContext ctx, char* f, char** out, int* len, char* type
for(p1 = *out + 1; p1 < f; p1++) for(p1 = *out + 1; p1 < f; p1++)
for(p2 = p1+1; p2 < f; p2++) for(p2 = p1+1; p2 < f; p2++)
if(*p1 == *p2) if(*p1 == *p2)
naRuntimeError(ctx, "duplicate flag in format string"); } naRuntimeError(c, "duplicate flag in format string"); }
while(*f && *f >= '0' && *f <= '9') f++; while(*f && *f >= '0' && *f <= '9') f++;
if(*f && *f == '.') f++; if(*f && *f == '.') f++;
while(*f && *f >= '0' && *f <= '9') f++; while(*f && *f >= '0' && *f <= '9') f++;
if(!*f) naRuntimeError(ctx, "invalid format string"); if(!*f) naRuntimeError(c, "invalid format string");
*type = *f++; *type = *f++;
*len = f - *out; *len = f - *out;
return f; return f;
} }
#define ERR(m) naRuntimeError(ctx, m) #define ERR(m) naRuntimeError(c, m)
#define APPEND(r) result = naStr_concat(naNewString(ctx), result, r) #define APPEND(r) result = naStr_concat(naNewString(c), result, r)
static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args) static naRef f_sprintf(naContext c, naRef me, int argc, naRef* args)
{ {
char t, nultmp, *fstr, *next, *fout=0, *s; char t, nultmp, *fstr, *next, *fout=0, *s;
int flen, argn=1; int flen, argn=1;
naRef format, arg, result = naNewString(ctx); naRef format, arg, result = naNewString(c);
if(argc < 1) ERR("not enough arguments to sprintf"); if(argc < 1) ERR("not enough arguments to sprintf()");
format = naStringValue(ctx, argc > 0 ? args[0] : naNil()); format = naStringValue(c, argc > 0 ? args[0] : naNil());
if(naIsNil(format)) ERR("bad format string in sprintf"); if(naIsNil(format)) ERR("bad format string in sprintf()");
s = naStr_data(format); s = naStr_data(format);
while((next = nextFormat(ctx, s, &fstr, &flen, &t))) { while((next = nextFormat(c, s, &fstr, &flen, &t))) {
APPEND(NEWSTR(ctx, s, fstr-s)); // stuff before the format string APPEND(NEWSTR(c, s, fstr-s)); // stuff before the format string
if(flen == 2 && fstr[1] == '%') { if(flen == 2 && fstr[1] == '%') {
APPEND(NEWSTR(ctx, "%", 1)); APPEND(NEWSTR(c, "%", 1));
s = next; s = next;
continue; continue;
} }
if(argn >= argc) ERR("not enough arguments to sprintf"); if(argn >= argc) ERR("not enough arguments to sprintf()");
arg = args[argn++]; arg = args[argn++];
nultmp = fstr[flen]; // sneaky nul termination... nultmp = fstr[flen]; // sneaky nul termination...
fstr[flen] = 0; fstr[flen] = 0;
if(t == 's') { if(t == 's') {
arg = naStringValue(ctx, arg); arg = naStringValue(c, arg);
if(naIsNil(arg)) fout = dosprintf(fstr, "nil"); if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
else fout = dosprintf(fstr, naStr_data(arg)); else fout = dosprintf(fstr, naStr_data(arg));
} else { } else {
@@ -320,44 +362,42 @@ static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
ERR("invalid sprintf format type"); ERR("invalid sprintf format type");
} }
fstr[flen] = nultmp; fstr[flen] = nultmp;
APPEND(NEWSTR(ctx, fout, strlen(fout))); APPEND(NEWSTR(c, fout, strlen(fout)));
naFree(fout); naFree(fout);
s = next; s = next;
} }
APPEND(NEWSTR(ctx, s, strlen(s))); APPEND(NEWSTR(c, s, strlen(s)));
return result; return result;
} }
// FIXME: handle ctx->callParent frames too! // FIXME: needs to honor subcontext list
static naRef f_caller(naContext ctx, naRef me, int argc, naRef* args) static naRef f_caller(naContext c, naRef me, int argc, naRef* args)
{ {
int fidx; int fidx;
struct Frame* frame; struct Frame* frame;
naRef result, fr = argc ? naNumValue(args[0]) : naNum(1); naRef result, fr = argc ? naNumValue(args[0]) : naNum(1);
if(IS_NIL(fr)) naRuntimeError(ctx, "non numeric argument to caller()"); if(IS_NIL(fr)) ARGERR();
fidx = (int)fr.num; fidx = (int)fr.num;
if(fidx > ctx->fTop - 1) return naNil(); if(fidx > c->fTop - 1) return naNil();
frame = &ctx->fStack[ctx->fTop - 1 - fidx]; frame = &c->fStack[c->fTop - 1 - fidx];
result = naNewVector(ctx); result = naNewVector(c);
naVec_append(result, frame->locals); naVec_append(result, frame->locals);
naVec_append(result, frame->func); naVec_append(result, frame->func);
naVec_append(result, frame->func.ref.ptr.func->code.ref.ptr.code->srcFile); naVec_append(result, PTR(PTR(frame->func).func->code).code->srcFile);
naVec_append(result, naNum(naGetLine(ctx, fidx))); naVec_append(result, naNum(naGetLine(c, fidx)));
return result; return result;
} }
static naRef f_closure(naContext ctx, naRef me, int argc, naRef* args) static naRef f_closure(naContext c, naRef me, int argc, naRef* args)
{ {
int i; int i;
naRef func, idx;
struct naFunc* f; struct naFunc* f;
func = argc > 0 ? args[0] : naNil(); naRef func = argc > 0 ? args[0] : naNil();
idx = argc > 1 ? naNumValue(args[1]) : naNil(); naRef idx = argc > 1 ? naNumValue(args[1]) : naNum(0);
if(!IS_FUNC(func) || IS_NIL(idx)) if(!IS_FUNC(func) || IS_NIL(idx)) ARGERR();
naRuntimeError(ctx, "bad arguments to closure()");
i = (int)idx.num; i = (int)idx.num;
f = func.ref.ptr.func; f = PTR(func).func;
while(i > 0 && f) { i--; f = f->next.ref.ptr.func; } while(i > 0 && f) { i--; f = PTR(f->next).func; }
if(!f) return naNil(); if(!f) return naNil();
return f->namespace; return f->namespace;
} }
@@ -377,40 +417,38 @@ static int find(unsigned char* a, int al, unsigned char* s, int sl, int start)
return -1; return -1;
} }
static naRef f_find(naContext ctx, naRef me, int argc, naRef* args) static naRef f_find(naContext c, naRef me, int argc, naRef* args)
{ {
int start = 0; int start = 0;
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
naRuntimeError(ctx, "bad/missing argument to find");
if(argc > 2) start = (int)(naNumValue(args[2]).num); if(argc > 2) start = (int)(naNumValue(args[2]).num);
return naNum(find(args[0].ref.ptr.str->data, args[0].ref.ptr.str->len, return naNum(find(PTR(args[0]).str->data, PTR(args[0]).str->len,
args[1].ref.ptr.str->data, args[1].ref.ptr.str->len, PTR(args[1]).str->data, PTR(args[1]).str->len,
start)); start));
} }
static naRef f_split(naContext ctx, naRef me, int argc, naRef* args) static naRef f_split(naContext c, naRef me, int argc, naRef* args)
{ {
int sl, dl, i; int sl, dl, i;
char *s, *d, *s0; char *s, *d, *s0;
naRef result; naRef result;
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
naRuntimeError(ctx, "bad/missing argument to split");
d = naStr_data(args[0]); dl = naStr_len(args[0]); d = naStr_data(args[0]); dl = naStr_len(args[0]);
s = naStr_data(args[1]); sl = naStr_len(args[1]); s = naStr_data(args[1]); sl = naStr_len(args[1]);
result = naNewVector(ctx); result = naNewVector(c);
if(dl == 0) { // special case zero-length delimiter if(dl == 0) { // special case zero-length delimiter
for(i=0; i<sl; i++) naVec_append(result, NEWSTR(ctx, s+i, 1)); for(i=0; i<sl; i++) naVec_append(result, NEWSTR(c, s+i, 1));
return result; return result;
} }
s0 = s; s0 = s;
for(i=0; i <= sl-dl; i++) { for(i=0; i <= sl-dl; i++) {
if(match((unsigned char*)(s+i), (unsigned char*)d, dl)) { if(match((unsigned char*)(s+i), (unsigned char*)d, dl)) {
naVec_append(result, NEWSTR(ctx, s0, s+i-s0)); naVec_append(result, NEWSTR(c, s0, s+i-s0));
s0 = s + i + dl; s0 = s + i + dl;
i += dl - 1; i += dl - 1;
} }
} }
if(s0 - s <= sl) naVec_append(result, NEWSTR(ctx, s0, s+sl-s0)); if(s0 - s <= sl) naVec_append(result, NEWSTR(c, s0, s+sl-s0));
return result; return result;
} }
@@ -418,12 +456,12 @@ static naRef f_split(naContext ctx, naRef me, int argc, naRef* args)
// function, which is usually not threadsafe and often of limited // function, which is usually not threadsafe and often of limited
// precision. The 5x loop guarantees that we get a full double worth // precision. The 5x loop guarantees that we get a full double worth
// of precision even for 15 bit (Win32...) rand() implementations. // of precision even for 15 bit (Win32...) rand() implementations.
static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args) static naRef f_rand(naContext c, naRef me, int argc, naRef* args)
{ {
int i; int i;
double r = 0; double r = 0;
if(argc) { if(argc) {
if(!IS_NUM(args[0])) naRuntimeError(ctx, "rand() seed not number"); if(!IS_NUM(args[0])) naRuntimeError(c, "rand() seed not number");
srand((unsigned int)args[0].num); srand((unsigned int)args[0].num);
return naNil(); return naNil();
} }
@@ -431,36 +469,91 @@ static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args)
return naNum(r); return naNum(r);
} }
static naRef f_bind(naContext ctx, naRef me, int argc, naRef* args) static naRef f_bind(naContext c, naRef me, int argc, naRef* args)
{ {
naRef func = argc > 0 ? args[0] : naNil(); naRef func = argc > 0 ? args[0] : naNil();
naRef hash = argc > 1 ? args[1] : naNewHash(ctx); naRef hash = argc > 1 ? args[1] : naNewHash(c);
naRef next = argc > 2 ? args[2] : naNil(); naRef next = argc > 2 ? args[2] : naNil();
if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash)) if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash))
naRuntimeError(ctx, "bad argument to bind"); ARGERR();
func = naNewFunc(ctx, func.ref.ptr.func->code); func = naNewFunc(c, PTR(func).func->code);
func.ref.ptr.func->namespace = hash; PTR(func).func->namespace = hash;
func.ref.ptr.func->next = next; PTR(func).func->next = next;
return func; return func;
} }
struct func { char* name; naCFunction func; }; /* We use the "SortRec" gadget for two reasons: first, because ANSI
static struct func funcs[] = { * qsort() doesn't give us a mechanism for passing a "context" pointer
{ "size", size }, * to the comparison routine we have to store one in every sorted
{ "keys", keys }, * record. Second, using an index into the original vector here
{ "append", append }, * allows us to make the sort stable in the event of a zero returned
{ "pop", pop }, * from the Nasal comparison function. */
{ "setsize", setsize }, struct SortData { naContext ctx, subc; struct SortRec* recs;
{ "subvec", subvec }, naRef* elems; int n; naRef fn; };
{ "delete", delete }, struct SortRec { struct SortData* sd; int i; };
{ "int", intf },
{ "num", num }, static int sortcmp(struct SortRec* a, struct SortRec* b)
{ "streq", streq }, {
struct SortData* sd = a->sd;
naRef args[2], d;
args[0] = sd->elems[a->i];
args[1] = sd->elems[b->i];
d = naCall(sd->subc, sd->fn, 2, args, naNil(), naNil());
if(naGetError(sd->subc)) {
naFree(sd->recs);
naRethrowError(sd->subc);
} else if(!naIsNum(d = naNumValue(d))) {
naFree(sd->recs);
naRuntimeError(sd->ctx, "sort() comparison returned non-number");
}
return (d.num > 0) ? 1 : ((d.num < 0) ? -1 : (a->i - b->i));
}
static naRef f_sort(naContext c, naRef me, int argc, naRef* args)
{
int i;
struct SortData sd;
naRef out;
if(argc != 2 || !naIsVector(args[0]) || !naIsFunc(args[1]))
naRuntimeError(c, "bad/missing argument to sort()");
sd.subc = naSubContext(c);
if(!PTR(args[0]).vec->rec) return naNewVector(c);
sd.elems = PTR(args[0]).vec->rec->array;
sd.n = PTR(args[0]).vec->rec->size;
sd.fn = args[1];
sd.recs = naAlloc(sizeof(struct SortRec) * sd.n);
for(i=0; i<sd.n; i++) {
sd.recs[i].sd = &sd;
sd.recs[i].i = i;
}
qsort(sd.recs, sd.n, sizeof(sd.recs[0]),
(int(*)(const void*,const void*))sortcmp);
out = naNewVector(c);
naVec_setsize(out, sd.n);
for(i=0; i<sd.n; i++)
PTR(out).vec->rec->array[i] = sd.elems[sd.recs[i].i];
naFree(sd.recs);
naFreeContext(sd.subc);
return out;
}
static naCFuncItem funcs[] = {
{ "size", f_size },
{ "keys", f_keys },
{ "append", f_append },
{ "pop", f_pop },
{ "setsize", f_setsize },
{ "subvec", f_subvec },
{ "delete", f_delete },
{ "int", f_int },
{ "num", f_num },
{ "streq", f_streq },
{ "cmp", f_cmp }, { "cmp", f_cmp },
{ "substr", substr }, { "substr", f_substr },
{ "chr", f_chr }, { "chr", f_chr },
{ "contains", contains }, { "contains", f_contains },
{ "typeof", typeOf }, { "typeof", f_typeof },
{ "ghosttype", f_ghosttype },
{ "compile", f_compile }, { "compile", f_compile },
{ "call", f_call }, { "call", f_call },
{ "die", f_die }, { "die", f_die },
@@ -471,17 +564,11 @@ static struct func funcs[] = {
{ "split", f_split }, { "split", f_split },
{ "rand", f_rand }, { "rand", f_rand },
{ "bind", f_bind }, { "bind", f_bind },
{ "sort", f_sort },
{ 0 }
}; };
naRef naStdLib(naContext c) naRef naInit_std(naContext c)
{ {
naRef namespace = naNewHash(c); return naGenLib(c, funcs);
int i, n = sizeof(funcs)/sizeof(struct func);
for(i=0; i<n; i++) {
naRef code = naNewCCode(c, funcs[i].func);
naRef name = NEWSTR(c, funcs[i].name, strlen(funcs[i].name));
name = naInternSymbol(name);
naHash_set(namespace, name, naNewFunc(c, code));
}
return namespace;
} }
+30 -28
View File
@@ -1,16 +1,32 @@
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include "nasal.h" #include "nasal.h"
// Toss a runtime error for any NaN or Inf values produced. Note that
// this assumes an IEEE 754 format.
#define VALIDATE(r) (valid(r.num) ? (r) : die(c, __FUNCTION__+2))
static int valid(double d)
{
union { double d; unsigned long long ull; } u;
u.d = d;
return ((u.ull >> 52) & 0x7ff) != 0x7ff;
}
static naRef die(naContext c, const char* fn)
{
naRuntimeError(c, "floating point error in math.%s()", fn);
return naNil();
}
static naRef f_sin(naContext c, naRef me, int argc, naRef* args) static naRef f_sin(naContext c, naRef me, int argc, naRef* args)
{ {
naRef a = naNumValue(argc > 0 ? args[0] : naNil()); naRef a = naNumValue(argc > 0 ? args[0] : naNil());
if(naIsNil(a)) if(naIsNil(a))
naRuntimeError(c, "non numeric argument to sin()"); naRuntimeError(c, "non numeric argument to sin()");
a.num = sin(a.num); a.num = sin(a.num);
return a; return VALIDATE(a);
} }
static naRef f_cos(naContext c, naRef me, int argc, naRef* args) static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
@@ -19,7 +35,7 @@ static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
if(naIsNil(a)) if(naIsNil(a))
naRuntimeError(c, "non numeric argument to cos()"); naRuntimeError(c, "non numeric argument to cos()");
a.num = cos(a.num); a.num = cos(a.num);
return a; return VALIDATE(a);
} }
static naRef f_exp(naContext c, naRef me, int argc, naRef* args) static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
@@ -28,7 +44,7 @@ static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
if(naIsNil(a)) if(naIsNil(a))
naRuntimeError(c, "non numeric argument to exp()"); naRuntimeError(c, "non numeric argument to exp()");
a.num = exp(a.num); a.num = exp(a.num);
return a; return VALIDATE(a);
} }
static naRef f_ln(naContext c, naRef me, int argc, naRef* args) static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
@@ -37,7 +53,7 @@ static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
if(naIsNil(a)) if(naIsNil(a))
naRuntimeError(c, "non numeric argument to ln()"); naRuntimeError(c, "non numeric argument to ln()");
a.num = log(a.num); a.num = log(a.num);
return a; return VALIDATE(a);
} }
static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args) static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
@@ -46,7 +62,7 @@ static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
if(naIsNil(a)) if(naIsNil(a))
naRuntimeError(c, "non numeric argument to sqrt()"); naRuntimeError(c, "non numeric argument to sqrt()");
a.num = sqrt(a.num); a.num = sqrt(a.num);
return a; return VALIDATE(a);
} }
static naRef f_atan2(naContext c, naRef me, int argc, naRef* args) static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
@@ -56,37 +72,23 @@ static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
if(naIsNil(a) || naIsNil(b)) if(naIsNil(a) || naIsNil(b))
naRuntimeError(c, "non numeric argument to atan2()"); naRuntimeError(c, "non numeric argument to atan2()");
a.num = atan2(a.num, b.num); a.num = atan2(a.num, b.num);
return a; return VALIDATE(a);
} }
static struct func { char* name; naCFunction func; } funcs[] = { static naCFuncItem funcs[] = {
{ "sin", f_sin }, { "sin", f_sin },
{ "cos", f_cos }, { "cos", f_cos },
{ "exp", f_exp }, { "exp", f_exp },
{ "ln", f_ln }, { "ln", f_ln },
{ "sqrt", f_sqrt }, { "sqrt", f_sqrt },
{ "atan2", f_atan2 }, { "atan2", f_atan2 },
{ 0 }
}; };
naRef naMathLib(naContext c) naRef naInit_math(naContext c)
{ {
naRef name, namespace = naNewHash(c); naRef ns = naGenLib(c, funcs);
int i, n = sizeof(funcs)/sizeof(struct func); naAddSym(c, ns, "pi", naNum(3.14159265358979323846));
for(i=0; i<n; i++) { naAddSym(c, ns, "e", naNum(2.7182818284590452354));
naRef code = naNewCCode(c, funcs[i].func); return ns;
naRef name = naStr_fromdata(naNewString(c),
funcs[i].name, strlen(funcs[i].name));
naHash_set(namespace, name, naNewFunc(c, code));
}
// 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(3.14159265358979323846));
name = naStr_fromdata(naNewString(c), "e", 1);
name = naInternSymbol(name);
naHash_set(namespace, name, naNum(2.7182818284590452354));
return namespace;
} }
+43 -25
View File
@@ -23,14 +23,13 @@ void naTempSave(naContext c, naRef r)
naFree(c->temps); naFree(c->temps);
c->temps = newtemps; c->temps = newtemps;
} }
c->temps[c->ntemps++] = r.ref.ptr.obj; c->temps[c->ntemps++] = PTR(r).obj;
} }
naRef naObj(int type, struct naObj* o) naRef naObj(int type, struct naObj* o)
{ {
naRef r; naRef r;
r.ref.reftag = NASAL_REFTAG; SETPTR(r, o);
r.ref.ptr.obj = o;
o->type = type; o->type = type;
return r; return r;
} }
@@ -78,23 +77,23 @@ naRef naNew(struct Context* c, int type)
naRef naNewString(struct Context* c) naRef naNewString(struct Context* c)
{ {
naRef s = naNew(c, T_STR); naRef s = naNew(c, T_STR);
s.ref.ptr.str->len = 0; PTR(s).str->len = 0;
s.ref.ptr.str->data = 0; PTR(s).str->data = 0;
s.ref.ptr.str->hashcode = 0; PTR(s).str->hashcode = 0;
return s; return s;
} }
naRef naNewVector(struct Context* c) naRef naNewVector(struct Context* c)
{ {
naRef r = naNew(c, T_VEC); naRef r = naNew(c, T_VEC);
r.ref.ptr.vec->rec = 0; PTR(r).vec->rec = 0;
return r; return r;
} }
naRef naNewHash(struct Context* c) naRef naNewHash(struct Context* c)
{ {
naRef r = naNew(c, T_HASH); naRef r = naNew(c, T_HASH);
r.ref.ptr.hash->rec = 0; PTR(r).hash->rec = 0;
return r; return r;
} }
@@ -106,59 +105,57 @@ naRef naNewCode(struct Context* c)
naRef naNewCCode(struct Context* c, naCFunction fptr) naRef naNewCCode(struct Context* c, naCFunction fptr)
{ {
naRef r = naNew(c, T_CCODE); naRef r = naNew(c, T_CCODE);
r.ref.ptr.ccode->fptr = fptr; PTR(r).ccode->fptr = fptr;
return r; return r;
} }
naRef naNewFunc(struct Context* c, naRef code) naRef naNewFunc(struct Context* c, naRef code)
{ {
naRef func = naNew(c, T_FUNC); naRef func = naNew(c, T_FUNC);
func.ref.ptr.func->code = code; PTR(func).func->code = code;
func.ref.ptr.func->namespace = naNil(); PTR(func).func->namespace = naNil();
func.ref.ptr.func->next = naNil(); PTR(func).func->next = naNil();
return func; return func;
} }
naRef naNewGhost(naContext c, naGhostType* type, void* ptr) naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
{ {
naRef ghost = naNew(c, T_GHOST); naRef ghost = naNew(c, T_GHOST);
ghost.ref.ptr.ghost->gtype = type; PTR(ghost).ghost->gtype = type;
ghost.ref.ptr.ghost->ptr = ptr; PTR(ghost).ghost->ptr = ptr;
return ghost; return ghost;
} }
naGhostType* naGhost_type(naRef ghost) naGhostType* naGhost_type(naRef ghost)
{ {
if(!IS_GHOST(ghost)) return 0; if(!IS_GHOST(ghost)) return 0;
return ghost.ref.ptr.ghost->gtype; return PTR(ghost).ghost->gtype;
} }
void* naGhost_ptr(naRef ghost) void* naGhost_ptr(naRef ghost)
{ {
if(!IS_GHOST(ghost)) return 0; if(!IS_GHOST(ghost)) return 0;
return ghost.ref.ptr.ghost->ptr; return PTR(ghost).ghost->ptr;
} }
naRef naNil() naRef naNil()
{ {
naRef r; naRef r;
r.ref.reftag = NASAL_REFTAG; SETPTR(r, 0);
r.ref.ptr.obj = 0;
return r; return r;
} }
naRef naNum(double num) naRef naNum(double num)
{ {
naRef r; naRef r;
r.ref.reftag = ~NASAL_REFTAG; SETNUM(r, num);
r.num = num;
return r; return r;
} }
int naEqual(naRef a, naRef b) int naEqual(naRef a, naRef b)
{ {
double na=0, nb=0; double na=0, nb=0;
if(IS_REF(a) && IS_REF(b) && a.ref.ptr.obj == b.ref.ptr.obj) if(IS_REF(a) && IS_REF(b) && PTR(a).obj == PTR(b).obj)
return 1; // Object identity (and nil == nil) return 1; // Object identity (and nil == nil)
if(IS_NIL(a) || IS_NIL(b)) if(IS_NIL(a) || IS_NIL(b))
return 0; return 0;
@@ -182,10 +179,10 @@ int naStrEqual(naRef a, naRef b)
int i; int i;
if(!(IS_STR(a) && IS_STR(b))) if(!(IS_STR(a) && IS_STR(b)))
return 0; return 0;
if(a.ref.ptr.str->len != b.ref.ptr.str->len) if(PTR(a).str->len != PTR(b).str->len)
return 0; return 0;
for(i=0; i<a.ref.ptr.str->len; i++) for(i=0; i<PTR(a).str->len; i++)
if(a.ref.ptr.str->data[i] != b.ref.ptr.str->data[i]) if(PTR(a).str->data[i] != PTR(b).str->data[i])
return 0; return 0;
return 1; return 1;
} }
@@ -214,3 +211,24 @@ int naIsFunc(naRef r) { return IS_FUNC(r); }
int naIsCode(naRef r) { return IS_CODE(r); } int naIsCode(naRef r) { return IS_CODE(r); }
int naIsCCode(naRef r) { return IS_CCODE(r); } int naIsCCode(naRef r) { return IS_CCODE(r); }
int naIsGhost(naRef r) { return IS_GHOST(r); } int naIsGhost(naRef r) { return IS_GHOST(r); }
void naSetUserData(naContext c, void* p) { c->userData = p; }
void* naGetUserData(naContext c)
{
if(c->userData) return c->userData;
return c->callParent ? naGetUserData(c->callParent) : 0;
}
void naAddSym(naContext c, naRef ns, char *sym, naRef val)
{
naRef name = naStr_fromdata(naNewString(c), sym, strlen(sym));
naHash_set(ns, naInternSymbol(name), val);
}
naRef naGenLib(naContext c, naCFuncItem *fns)
{
naRef ns = naNewHash(c);
for(/**/; fns->name; fns++)
naAddSym(c, ns, fns->name, naNewFunc(c, naNewCCode(c, fns->func)));
return ns;
}
+59
View File
@@ -0,0 +1,59 @@
#ifndef _NAREF_H
#define _NAREF_H
/* Rather than play elaborate and complicated games with
* platform-dependent endianness headers, just detect the platforms we
* support. This list is simpler and smaller, yet still quite
* complete. */
#if (defined(__x86_64) && defined(__linux__)) || defined(__sparcv9)
/* Win64 and Irix should work with this too, but have not been
* tested */
# define NASAL_NAN64
#elif defined(_M_IX86) || defined(i386) || defined(__x86_64) || \
defined(__ia64__) || defined(_M_IA64) || defined(__ARMEL__)
# define NASAL_LE
#elif defined(__sparc) || defined(__ppc__) ||defined(__PPC) || \
defined(__mips) || defined(__ARMEB__)
# define NASAL_BE
#else
# error Unrecognized CPU architecture
#endif
typedef union {
struct naObj* obj;
struct naStr* str;
struct naVec* vec;
struct naHash* hash;
struct naCode* code;
struct naFunc* func;
struct naCCode* ccode;
struct naGhost* ghost;
} naPtr;
#if defined(NASAL_NAN64)
/* On suppoted 64 bit platforms (those where all memory returned from
* naAlloc() is guaranteed to lie between 0 and 2^48-1) we union the
* double with the pointer, and use fancy tricks (see data.h) to make
* sure all pointers are stored as NaNs. */
typedef union { double num; void* ptr; } naRef;
#elif defined(NASAL_LE) || defined(NASAL_BE)
/* 32 bit layouts (and 64 bit platforms where we haven't tested the
trick above) need endianness-dependent ordering to make sure that
the reftag lies in the top bits of the double */
#ifdef NASAL_LE
typedef struct { naPtr ptr; int reftag; } naRefPart;
#else /* NASAL_BE */
typedef struct { int reftag; naPtr ptr; } naRefPart;
#endif
typedef union {
double num;
naRefPart ref;
} naRef;
#endif
#endif // _NAREF_H
+111 -109
View File
@@ -4,73 +4,17 @@
extern "C" { extern "C" {
#endif #endif
#ifndef BYTE_ORDER #include "naref.h"
# if (BSD >= 199103) #if __GNUC__ > 2
# include <machine/endian.h> /* This marks the function as having no side effects and depending on
# elif defined(__CYGWIN__) || defined(__MINGW32__) * nothing but its arguments, which allows the optimizer to avoid
# include <sys/param.h> * duplicate calls to naNil(). */
# elif defined(linux) #define GCC_PURE __attribute__((__pure__))
# include <endian.h> #else
# else #define GCC_PURE
# ifndef LITTLE_ENDIAN
# define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
# endif
# ifndef BIG_ENDIAN
# define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */
# endif
# if defined(ultrix) || defined(__alpha__) || defined(__alpha) || \
defined(__i386__) || defined(__i486__) || defined(_X86_) || \
defined(sun386)
# define BYTE_ORDER LITTLE_ENDIAN
# else
# define BYTE_ORDER BIG_ENDIAN
# endif
# endif /* BSD */
#endif /* BYTE_ORDER */
#if BYTE_ORDER == BIG_ENDIAN
# include <limits.h>
# if (LONG_MAX == 2147483647)
# define NASAL_BIG_ENDIAN_32_BIT 1
# endif
#endif #endif
// This is a nasal "reference". They are always copied by value, and
// contain either a pointer to a garbage-collectable nasal object
// (string, vector, hash) or a floating point number. Keeping the
// number here is an optimization to prevent the generation of
// zillions of tiny "number" object that have to be collected. Note
// sneaky hack: on little endian systems, placing reftag after ptr and
// putting 1's in the top 13 (except the sign bit) bits makes the
// double value a NaN, and thus unmistakable (no actual number can
// appear as a reference, and vice versa). Swap the structure order
// on 32 bit big-endian systems. On 64 bit sytems of either
// endianness, reftag and the double won't be coincident anyway.
#define NASAL_REFTAG 0x7ff56789 // == 2,146,789,257 decimal
typedef union {
double num;
struct {
#ifdef NASAL_BIG_ENDIAN_32_BIT
int reftag; // Big-endian systems need this here!
#endif
union {
struct naObj* obj;
struct naStr* str;
struct naVec* vec;
struct naHash* hash;
struct naCode* code;
struct naFunc* func;
struct naCCode* ccode;
struct naGhost* ghost;
} ptr;
#ifndef NASAL_BIG_ENDIAN_32_BIT
int reftag; // Little-endian and 64 bit systems need this here!
#endif
} ref;
} naRef;
typedef struct Context* naContext; typedef struct Context* naContext;
// The function signature for an extension function: // The function signature for an extension function:
@@ -80,7 +24,21 @@ typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args);
naContext naNewContext(); naContext naNewContext();
void naFreeContext(naContext c); void naFreeContext(naContext c);
// Save this object in the context, preventing it (and objects // Use this when making a call to a new context "underneath" a
// preexisting context on the same stack. It allows stack walking to
// see through the boundary, and eliminates the need to release the
// mod lock (i.e. must be called with the mod lock held!)
naContext naSubContext(naContext super);
// The naContext supports a user data pointer that can be used to
// store data specific to an naCall invocation without exposing it to
// Nasal as a ghost. FIXME: this API is semi-dangerous, there is no
// provision for sharing it, nor for validating the source or type of
// the pointer returned.
void naSetUserData(naContext c, void* p);
void* naGetUserData(naContext c) GCC_PURE;
// "Save" this object in the context, preventing it (and objects
// referenced by it) from being garbage collected. // referenced by it) from being garbage collected.
void naSave(naContext ctx, naRef obj); void naSave(naContext ctx, naRef obj);
@@ -89,68 +47,98 @@ void naSave(naContext ctx, naRef obj);
// temporaries to protect them before passing back into a naCall. // temporaries to protect them before passing back into a naCall.
void naTempSave(naContext c, naRef r); void naTempSave(naContext c, naRef r);
// Parse a buffer in memory into a code object. // Parse a buffer in memory into a code object. The srcFile parameter
// is a Nasal string representing the "file" from which the code is
// read. The "first line" is typically 1, but is settable for
// situations where the Nasal code is embedded in another context with
// its own numbering convetions. If an error occurs, returns nil and
// sets the errLine pointer to point to the line at fault. The string
// representation of the error can be retrieved with naGetError() on
// the context.
naRef naParseCode(naContext c, naRef srcFile, int firstLine, naRef naParseCode(naContext c, naRef srcFile, int firstLine,
char* buf, int len, int* errLine); char* buf, int len, int* errLine);
// Binds a bare code object (as returned from naParseCode) with a // Binds a bare code object (as returned from naParseCode) with a
// closure object (a hash) to act as the outer scope / namespace. // closure object (a hash) to act as the outer scope / namespace.
// FIXME: this API is weak. It should expose the recursive nature of
// closures, and allow for extracting the closure and namespace
// information from function objects.
naRef naBindFunction(naContext ctx, naRef code, naRef closure); naRef naBindFunction(naContext ctx, naRef code, naRef closure);
// Similar, but it binds to the current context's closure (i.e. the // Similar, but it binds to the current context's closure (i.e. the
// namespace at the top of the current call stack). // namespace at the top of the current call stack).
naRef naBindToContext(naContext ctx, naRef code); naRef naBindToContext(naContext ctx, naRef code);
// Call a code or function object with the specifed arguments "on" the // Call a code or function object with the specified arguments "on"
// specified object and using the specified hash for the local // the specified object and using the specified hash for the local
// variables. Any of args, obj or locals may be nil. // variables. Passing a null args array skips the parameter variables
naRef naCall(naContext ctx, naRef func, int argc, naRef* args, naRef obj, naRef locals); // (e.g. "arg") assignments; to get a zero-length arg instead, pass in
// argc==0 and a non-null args vector. The obj or locals parameters
// may be nil. Will attempt to acquire the mod lock, so call
// naModUnlock() first if the lock is already held.
naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
naRef obj, naRef locals);
// As naCall(), but continues execution at the operation after a
// previous die() call or runtime error. Useful to do "yield"
// semantics, leaving the context in a condition where it can be
// restarted from C code. Cannot be used currently to restart a
// failed operation. Will attempt to acquire the mod lock, so call
// naModUnlock() first if the lock is already held.
naRef naContinue(naContext ctx);
// Throw an error from the current call stack. This function makes a // 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 // longjmp call to a handler in naCall() and DOES NOT RETURN. It is
// intended for use in library code that cannot otherwise report an // intended for use in library code that cannot otherwise report an
// error via the return value, and MUST be used carefully. If in // error via the return value, and MUST be used carefully. If in
// doubt, return naNil() as your error condition. // doubt, return naNil() as your error condition. Works like
void naRuntimeError(naContext ctx, char* msg); // printf().
void naRuntimeError(naContext c, const char* fmt, ...);
// Call a method on an object (NOTE: func is a function binding, *not* // "Re-throws" a runtime error caught from the subcontext. Acts as a
// a code object as returned from naParseCode). // naRuntimeError() called on the parent context. Does not return.
naRef naMethod(naContext ctx, naRef func, naRef object); void naRethrowError(naContext subc);
// Retrieve the specified member from the object, respecting the
// "parents" array as for "object.field". Returns zero for missing
// fields.
int naMember_get(naRef obj, naRef field, naRef* out);
int naMember_cget(naRef obj, const char* field, naRef* out);
// Returns a hash containing functions from the Nasal standard library // Returns a hash containing functions from the Nasal standard library
// Useful for passing as a namespace to an initial function call // Useful for passing as a namespace to an initial function call
naRef naStdLib(naContext c); naRef naInit_std(naContext c);
// Ditto, for other core libraries // Ditto, for other core libraries
naRef naMathLib(naContext c); naRef naInit_math(naContext c);
naRef naBitsLib(naContext c); naRef naInit_bits(naContext c);
naRef naIOLib(naContext c); naRef naInit_io(naContext c);
naRef naRegexLib(naContext c); naRef naInit_regex(naContext c);
naRef naUnixLib(naContext c); naRef naInit_unix(naContext c);
naRef naInit_thread(naContext c);
naRef naInit_utf8(naContext c);
naRef naInit_sqlite(naContext c);
naRef naInit_readline(naContext c);
naRef naInit_gtk(naContext ctx);
naRef naInit_cairo(naContext ctx);
// Current line number & error message // Context stack inspection, frame zero is the "top"
int naStackDepth(naContext ctx); int naStackDepth(naContext ctx);
int naGetLine(naContext ctx, int frame); int naGetLine(naContext ctx, int frame);
naRef naGetSourceFile(naContext ctx, int frame); naRef naGetSourceFile(naContext ctx, int frame);
char* naGetError(naContext ctx); char* naGetError(naContext ctx);
// Type predicates // Type predicates
int naIsNil(naRef r); int naIsNil(naRef r) GCC_PURE;
int naIsNum(naRef r); int naIsNum(naRef r) GCC_PURE;
int naIsString(naRef r); int naIsString(naRef r) GCC_PURE;
int naIsScalar(naRef r); int naIsScalar(naRef r) GCC_PURE;
int naIsVector(naRef r); int naIsVector(naRef r) GCC_PURE;
int naIsHash(naRef r); int naIsHash(naRef r) GCC_PURE;
int naIsCode(naRef r); int naIsCode(naRef r) GCC_PURE;
int naIsFunc(naRef r); int naIsFunc(naRef r) GCC_PURE;
int naIsCCode(naRef r); int naIsCCode(naRef r) GCC_PURE;
// Allocators/generators: // Allocators/generators:
naRef naNil(); naRef naNil() GCC_PURE;
naRef naNum(double num); naRef naNum(double num) GCC_PURE;
naRef naNewString(naContext c); naRef naNewString(naContext c);
naRef naNewVector(naContext c); naRef naNewVector(naContext c);
naRef naNewHash(naContext c); naRef naNewHash(naContext c);
@@ -158,10 +146,10 @@ naRef naNewFunc(naContext c, naRef code);
naRef naNewCCode(naContext c, naCFunction fptr); naRef naNewCCode(naContext c, naCFunction fptr);
// Some useful conversion/comparison routines // Some useful conversion/comparison routines
int naEqual(naRef a, naRef b); int naEqual(naRef a, naRef b) GCC_PURE;
int naStrEqual(naRef a, naRef b); int naStrEqual(naRef a, naRef b) GCC_PURE;
int naTrue(naRef b); int naTrue(naRef b) GCC_PURE;
naRef naNumValue(naRef n); naRef naNumValue(naRef n) GCC_PURE;
naRef naStringValue(naContext c, naRef n); naRef naStringValue(naContext c, naRef n);
// String utilities: // String utilities:
@@ -192,6 +180,7 @@ void naHash_keys(naRef dst, naRef hash);
// Ghost utilities: // Ghost utilities:
typedef struct naGhostType { typedef struct naGhostType {
void (*destroy)(void* ghost); void (*destroy)(void* ghost);
const char* name;
} naGhostType; } naGhostType;
naRef naNewGhost(naContext c, naGhostType* t, void* ghost); naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
naGhostType* naGhost_type(naRef ghost); naGhostType* naGhost_type(naRef ghost);
@@ -200,18 +189,31 @@ int naIsGhost(naRef r);
// Acquires a "modification lock" on a context, allowing the C code to // 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 // modify Nasal data without fear that such data may be "lost" by the
// garbage collector (the C stack is not examined in GC!). This // garbage collector (nasal data the C stack is not examined in GC!).
// disallows garbage collection until the current thread can be // This disallows garbage collection until the current thread can be
// blocked. The lock should be acquired whenever modifications to // blocked. The lock should be acquired whenever nasal objects are
// Nasal objects are made. It need not be acquired when only read // being modified. It need not be acquired when only read access is
// access is needed. It MUST NOT be acquired by naCFunction's, as // needed, PRESUMING that the Nasal data being read is findable by the
// those are called with the lock already held; acquiring two locks // collector (via naSave, for example) and that another Nasal thread
// for the same thread will cause a deadlock when the GC is invoked. // cannot or will not delete the reference to the data. It MUST NOT
// It should be UNLOCKED by naCFunction's when they are about to do // be acquired by naCFunction's, as those are called with the lock
// any long term non-nasal processing and/or blocking I/O. // 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. Note that naModLock() may need to
// block to allow garbage collection to occur, and that garbage
// collection by other threads may be blocked until naModUnlock() is
// called. It must also be UNLOCKED by threads that hold a lock
// already before making a naCall() or naContinue() call -- these
// functions will attempt to acquire the lock again.
void naModLock(); void naModLock();
void naModUnlock(); void naModUnlock();
// Library utilities. Generate namespaces and add symbols.
typedef struct { char* name; naCFunction func; } naCFuncItem;
naRef naGenLib(naContext c, naCFuncItem *funcs);
void naAddSym(naContext c, naRef ns, char *sym, naRef val);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
+82 -8
View File
@@ -1,11 +1,10 @@
#include <setjmp.h> #include <setjmp.h>
#include <string.h>
#include "parse.h" #include "parse.h"
// Static precedence table, from low (loose binding, do first) to high // Static precedence table, from low (loose binding, do first) to high
// (tight binding, do last). // (tight binding, do last).
enum { PREC_BINARY, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
#define MAX_PREC_TOKS 6 #define MAX_PREC_TOKS 6
struct precedence { struct precedence {
int toks[MAX_PREC_TOKS]; int toks[MAX_PREC_TOKS];
@@ -32,8 +31,10 @@ struct precedence {
void naParseError(struct Parser* p, char* msg, int line) void naParseError(struct Parser* p, char* msg, int line)
{ {
// Some errors (e.g. code generation of a null pointer) lack a
// line number, so we throw -1 and set the line earlier.
if(line > 0) p->errLine = line;
p->err = msg; p->err = msg;
p->errLine = line;
longjmp(p->jumpHandle, 1); longjmp(p->jumpHandle, 1);
} }
@@ -205,11 +206,83 @@ static struct Token* emptyToken(struct Parser* p)
return t; return t;
} }
// Synthesize a curly brace token to wrap token t foward to the end of
// "statement". FIXME: unify this with the addNewChild(), which does
// very similar stuff.
static void embrace(struct Parser* p, struct Token* t)
{
struct Token *b, *end = t;
if(!t) return;
while(end->next) {
if(end->next->type == TOK_SEMI) {
// Slurp up the semi, iff it is followed by an else/elsif,
// otherwise leave it in place.
if(end->next->next) {
if(end->next->next->type == TOK_ELSE) end = end->next;
if(end->next->next->type == TOK_ELSIF) end = end->next;
}
break;
}
if(end->next->type == TOK_COMMA) break;
if(end->next->type == TOK_ELSE) break;
if(end->next->type == TOK_ELSIF) break;
end = end->next;
}
b = emptyToken(p);
b->type = TOK_LCURL;
b->line = t->line;
b->parent = t->parent;
b->prev = t->prev;
b->next = end->next;
b->children = t;
b->lastChild = end;
if(t->prev) t->prev->next = b;
else b->parent->children = b;
if(end->next) end->next->prev = b;
else b->parent->lastChild = b;
t->prev = 0;
end->next = 0;
for(; t; t = t->next)
t->parent = b;
}
#define NEXT(t) (t ? t->next : 0)
#define TYPE(t) (t ? t->type : -1)
static void fixBracelessBlocks(struct Parser* p, struct Token* t)
{
// Find the end, and march *backward*
while(t && t->next) t = t->next;
for(/**/; t; t=t->prev) {
switch(t->type) {
case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
case TOK_IF: case TOK_ELSIF:
if(TYPE(NEXT(t)) == TOK_LPAR && TYPE(NEXT(NEXT(t))) != TOK_LCURL)
embrace(p, t->next->next);
break;
case TOK_ELSE:
if(TYPE(NEXT(t)) != TOK_LCURL)
embrace(p, t->next);
break;
case TOK_FUNC:
if(TYPE(NEXT(t)) == TOK_LPAR) {
if(TYPE(NEXT(NEXT(t))) != TOK_LCURL)
embrace(p, NEXT(NEXT(t)));
} else if(TYPE(NEXT(t)) != TOK_LCURL)
embrace(p, t->next);
break;
default:
break;
}
}
}
// Fixes up parenting for obvious parsing situations, like code blocks // Fixes up parenting for obvious parsing situations, like code blocks
// being the child of a func keyword, etc... // being the child of a func keyword, etc...
static void fixBlockStructure(struct Parser* p, struct Token* start) static void fixBlockStructure(struct Parser* p, struct Token* start)
{ {
struct Token *t, *c; struct Token *t, *c;
fixBracelessBlocks(p, start);
t = start; t = start;
while(t) { while(t) {
switch(t->type) { switch(t->type) {
@@ -287,8 +360,8 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
addSemi = 1; addSemi = 1;
break; break;
} }
if(t->next && t->next->type == TOK_SEMI) if(!t->next || t->next->type == TOK_SEMI || t->next->type == TOK_COMMA)
addSemi = 0; // don't bother if it's already there! addSemi = 0; // don't bother, no need
if(addSemi) { if(addSemi) {
struct Token* semi = emptyToken(p); struct Token* semi = emptyToken(p);
semi->type = TOK_SEMI; semi->type = TOK_SEMI;
@@ -297,6 +370,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
semi->prev = t; semi->prev = t;
semi->parent = t->parent; semi->parent = t->parent;
if(semi->next) semi->next->prev = semi; if(semi->next) semi->next->prev = semi;
else semi->parent->lastChild = semi;
t->next = semi; t->next = semi;
t = semi; // don't bother checking the new one t = semi; // don't bother checking the new one
} }
@@ -455,6 +529,8 @@ static struct Token* parsePrecedence(struct Parser* p,
if(!top) if(!top)
return parsePrecedence(p, start, end, level+1); return parsePrecedence(p, start, end, level+1);
top->rule = rule;
if(left) { if(left) {
left->next = right; left->next = right;
left->prev = 0; left->prev = 0;
@@ -508,7 +584,7 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
// Catch parser errors here. // Catch parser errors here.
*errLine = 0; *errLine = 0;
if(setjmp(p.jumpHandle)) { if(setjmp(p.jumpHandle)) {
c->error = p.err; strncpy(c->error, p.err, sizeof(c->error));
*errLine = p.errLine; *errLine = p.errLine;
return naNil(); return naNil();
} }
@@ -540,5 +616,3 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
return codeObj; return codeObj;
} }
+5
View File
@@ -19,11 +19,15 @@ enum {
TOK_FORINDEX TOK_FORINDEX
}; };
// Precedence rules
enum { PREC_BINARY=1, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
struct Token { struct Token {
int type; int type;
int line; int line;
char* str; char* str;
int strlen; int strlen;
int rule;
double num; double num;
struct Token* parent; struct Token* parent;
struct Token* next; struct Token* next;
@@ -94,6 +98,7 @@ void naParseInit(struct Parser* p);
void* naParseAlloc(struct Parser* p, int bytes); void* naParseAlloc(struct Parser* p, int bytes);
void naParseDestroy(struct Parser* p); void naParseDestroy(struct Parser* p);
void naLex(struct Parser* p); void naLex(struct Parser* p);
int naLexUtf8C(char* s, int len, int* used); /* in utf8lib.c */
naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist); naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist);
void naParse(struct Parser* p); void naParse(struct Parser* p);
+16 -16
View File
@@ -14,13 +14,13 @@ static int fromnum(double val, unsigned char* s);
int naStr_len(naRef s) int naStr_len(naRef s)
{ {
if(!IS_STR(s)) return 0; if(!IS_STR(s)) return 0;
return s.ref.ptr.str->len; return PTR(s).str->len;
} }
char* naStr_data(naRef s) char* naStr_data(naRef s)
{ {
if(!IS_STR(s)) return 0; if(!IS_STR(s)) return 0;
return (char*)s.ref.ptr.str->data; return (char*)PTR(s).str->data;
} }
static void setlen(struct naStr* s, int sz) static void setlen(struct naStr* s, int sz)
@@ -33,24 +33,24 @@ static void setlen(struct naStr* s, int sz)
naRef naStr_buf(naRef dst, int len) naRef naStr_buf(naRef dst, int len)
{ {
setlen(dst.ref.ptr.str, len); setlen(PTR(dst).str, len);
naBZero(dst.ref.ptr.str->data, len); naBZero(PTR(dst).str->data, len);
return dst; return dst;
} }
naRef naStr_fromdata(naRef dst, char* data, int len) naRef naStr_fromdata(naRef dst, char* data, int len)
{ {
if(!IS_STR(dst)) return naNil(); if(!IS_STR(dst)) return naNil();
setlen(dst.ref.ptr.str, len); setlen(PTR(dst).str, len);
memcpy(dst.ref.ptr.str->data, data, len); memcpy(PTR(dst).str->data, data, len);
return dst; return dst;
} }
naRef naStr_concat(naRef dest, naRef s1, naRef s2) naRef naStr_concat(naRef dest, naRef s1, naRef s2)
{ {
struct naStr* dst = dest.ref.ptr.str; struct naStr* dst = PTR(dest).str;
struct naStr* a = s1.ref.ptr.str; struct naStr* a = PTR(s1).str;
struct naStr* b = s2.ref.ptr.str; struct naStr* b = PTR(s2).str;
if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil(); if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
setlen(dst, a->len + b->len); setlen(dst, a->len + b->len);
memcpy(dst->data, a->data, a->len); memcpy(dst->data, a->data, a->len);
@@ -60,8 +60,8 @@ naRef naStr_concat(naRef dest, naRef s1, naRef s2)
naRef naStr_substr(naRef dest, naRef str, int start, int len) naRef naStr_substr(naRef dest, naRef str, int start, int len)
{ {
struct naStr* dst = dest.ref.ptr.str; struct naStr* dst = PTR(dest).str;
struct naStr* s = str.ref.ptr.str; struct naStr* s = PTR(str).str;
if(!(IS_STR(dest)&&IS_STR(str))) return naNil(); if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
if(start + len > s->len) { dst->len = 0; dst->data = 0; return naNil(); } if(start + len > s->len) { dst->len = 0; dst->data = 0; return naNil(); }
setlen(dst, len); setlen(dst, len);
@@ -71,8 +71,8 @@ naRef naStr_substr(naRef dest, naRef str, int start, int len)
int naStr_equal(naRef s1, naRef s2) int naStr_equal(naRef s1, naRef s2)
{ {
struct naStr* a = s1.ref.ptr.str; struct naStr* a = PTR(s1).str;
struct naStr* b = s2.ref.ptr.str; struct naStr* b = PTR(s2).str;
if(a->data == b->data) return 1; if(a->data == b->data) return 1;
if(a->len != b->len) return 0; if(a->len != b->len) return 0;
if(memcmp(a->data, b->data, a->len) == 0) return 1; if(memcmp(a->data, b->data, a->len) == 0) return 1;
@@ -81,7 +81,7 @@ int naStr_equal(naRef s1, naRef s2)
naRef naStr_fromnum(naRef dest, double num) naRef naStr_fromnum(naRef dest, double num)
{ {
struct naStr* dst = dest.ref.ptr.str; struct naStr* dst = PTR(dest).str;
unsigned char buf[DIGITS+8]; unsigned char buf[DIGITS+8];
setlen(dst, fromnum(num, buf)); setlen(dst, fromnum(num, buf));
memcpy(dst->data, buf, dst->len); memcpy(dst->data, buf, dst->len);
@@ -95,13 +95,13 @@ int naStr_parsenum(char* str, int len, double* result)
int naStr_tonum(naRef str, double* out) int naStr_tonum(naRef str, double* out)
{ {
return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, out); return tonum(PTR(str).str->data, PTR(str).str->len, out);
} }
int naStr_numeric(naRef str) int naStr_numeric(naRef str)
{ {
double dummy; double dummy;
return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, &dummy); return tonum(PTR(str).str->data, PTR(str).str->len, &dummy);
} }
void naStr_gcclean(struct naStr* str) void naStr_gcclean(struct naStr* str)
+16 -2
View File
@@ -10,6 +10,12 @@ void* naNewLock()
return lock; return lock;
} }
void naFreeLock(void* lock)
{
pthread_mutex_destroy(lock);
naFree(lock);
}
void naLock(void* lock) void naLock(void* lock)
{ {
pthread_mutex_lock((pthread_mutex_t*)lock); pthread_mutex_lock((pthread_mutex_t*)lock);
@@ -35,6 +41,14 @@ void* naNewSem()
return sem; return sem;
} }
void naFreeSem(void* p)
{
struct naSem* sem = p;
pthread_mutex_destroy(&sem->lock);
pthread_cond_destroy(&sem->cvar);
naFree(sem);
}
void naSemDown(void* sh) void naSemDown(void* sh)
{ {
struct naSem* sem = (struct naSem*)sh; struct naSem* sem = (struct naSem*)sh;
@@ -45,11 +59,11 @@ void naSemDown(void* sh)
pthread_mutex_unlock(&sem->lock); pthread_mutex_unlock(&sem->lock);
} }
void naSemUpAll(void* sh, int count) void naSemUp(void* sh, int count)
{ {
struct naSem* sem = (struct naSem*)sh; struct naSem* sem = (struct naSem*)sh;
pthread_mutex_lock(&sem->lock); pthread_mutex_lock(&sem->lock);
sem->count = count; sem->count += count;
pthread_cond_broadcast(&sem->cvar); pthread_cond_broadcast(&sem->cvar);
pthread_mutex_unlock(&sem->lock); pthread_mutex_unlock(&sem->lock);
} }
+3 -1
View File
@@ -13,9 +13,11 @@ void* naNewLock()
void naLock(void* lock) { EnterCriticalSection((LPCRITICAL_SECTION)lock); } void naLock(void* lock) { EnterCriticalSection((LPCRITICAL_SECTION)lock); }
void naUnlock(void* lock) { LeaveCriticalSection((LPCRITICAL_SECTION)lock); } void naUnlock(void* lock) { LeaveCriticalSection((LPCRITICAL_SECTION)lock); }
void naFreeLock(void* lock) { free(lock); }
void* naNewSem() { return CreateSemaphore(0, 0, MAX_SEM_COUNT, 0); } void* naNewSem() { return CreateSemaphore(0, 0, MAX_SEM_COUNT, 0); }
void naSemDown(void* sem) { WaitForSingleObject((HANDLE)sem, INFINITE); } void naSemDown(void* sem) { WaitForSingleObject((HANDLE)sem, INFINITE); }
void naSemUpAll(void* sem, int count) { ReleaseSemaphore(sem, count, 0); } void naSemUp(void* sem, int count) { ReleaseSemaphore(sem, count, 0); }
void naFreeSem(void* sem) { ReleaseSemaphore(sem, 1, 0); }
#endif #endif
+103
View File
@@ -0,0 +1,103 @@
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include "data.h"
#include "code.h"
static void lockDestroy(void* lock) { naFreeLock(lock); }
static naGhostType LockType = { lockDestroy };
static void semDestroy(void* sem) { naFreeSem(sem); }
static naGhostType SemType = { semDestroy };
typedef struct {
naContext ctx;
naRef func;
} ThreadData;
#ifdef _WIN32
static DWORD WINAPI threadtop(LPVOID param)
#else
static void* threadtop(void* param)
#endif
{
ThreadData* td = param;
naCall(td->ctx, td->func, 0, 0, naNil(), naNil());
naFreeContext(td->ctx);
naFree(td);
return 0;
}
static naRef f_newthread(naContext c, naRef me, int argc, naRef* args)
{
ThreadData *td;
if(argc < 1 || !naIsFunc(args[0]))
naRuntimeError(c, "bad/missing argument to newthread");
td = naAlloc(sizeof(*td));
td->ctx = naNewContext();
td->func = args[0];
naTempSave(td->ctx, td->func);
#ifdef _WIN32
CreateThread(0, 0, threadtop, td, 0, 0);
#else
{ pthread_t t; pthread_create(&t, 0, threadtop, td); }
#endif
return naNil();
}
static naRef f_newlock(naContext c, naRef me, int argc, naRef* args)
{
return naNewGhost(c, &LockType, naNewLock());
}
static naRef f_lock(naContext c, naRef me, int argc, naRef* args)
{
if(argc > 0 && naGhost_type(args[0]) == &LockType)
naLock(naGhost_ptr(args[0]));
return naNil();
}
static naRef f_unlock(naContext c, naRef me, int argc, naRef* args)
{
if(argc > 0 && naGhost_type(args[0]) == &LockType)
naUnlock(naGhost_ptr(args[0]));
return naNil();
}
static naRef f_newsem(naContext c, naRef me, int argc, naRef* args)
{
return naNewGhost(c, &SemType, naNewSem());
}
static naRef f_semdown(naContext c, naRef me, int argc, naRef* args)
{
if(argc > 0 && naGhost_type(args[0]) == &SemType)
naSemDown(naGhost_ptr(args[0]));
return naNil();
}
static naRef f_semup(naContext c, naRef me, int argc, naRef* args)
{
if(argc > 0 && naGhost_type(args[0]) == &SemType)
naSemUp(naGhost_ptr(args[0]), 1);
return naNil();
}
static naCFuncItem funcs[] = {
{ "newthread", f_newthread },
{ "newlock", f_newlock },
{ "lock", f_lock },
{ "unlock", f_unlock },
{ "newsem", f_newsem },
{ "semdown", f_semdown },
{ "semup", f_semup },
{ 0 }
};
naRef naInit_thread(naContext c)
{
return naGenLib(c, funcs);
}
+161
View File
@@ -0,0 +1,161 @@
#include <string.h>
#include "nasal.h"
#include "parse.h"
// bytes required to store a given character
static int cbytes(unsigned int c)
{
static const int NB[] = { 0x7f, 0x07ff, 0xffff, 0x001fffff, 0x03ffffff };
int i;
for(i=0; i<(sizeof(NB)/sizeof(NB[0])) && c>NB[i]; i++) {}
return i+1;
}
// Returns a byte with the N high order bits set
#define TOPBITS(n) ((unsigned char)(((signed char)0x80)>>((n)-1)))
// write a utf8 character, return bytes written or zero on error
static int writec(unsigned int c, unsigned char* s, int len)
{
int i, n = cbytes(c);
if(len < n) return 0;
for(i=n-1; i>0; i--) {
s[i] = 0x80 | (c & 0x3f);
c >>= 6;
}
s[0] = (n > 1 ? TOPBITS(n) : 0) | c;
return n;
}
// read a utf8 character, or -1 on error.
static int readc(unsigned char* s, int len, int* used)
{
int n, i, c;
if(len > 0 && s[0] < 0x80) { *used = 1; return s[0]; }
for(n=2; n<7; n++)
if((s[0] & TOPBITS(n+1)) == TOPBITS(n))
break;
if(len < n || n > 6) return -1;
c = s[0] & (~TOPBITS(n+1));
for(i=1; i<n; i++) {
if((s[i] >> 6) != 2) return -1;
c = (c << 6) | (s[i] & 0x3f);
}
if(n != cbytes(c)) return -1;
*used = n;
return c;
}
/* Public symbol used by the parser */
int naLexUtf8C(char* s, int len, int* used)
{ return readc((void*)s, len, used); }
static unsigned char* nthchar(unsigned char* s, int n, int* len)
{
int i, bytes;
for(i=0; *len && i<n; i++) {
if(readc(s, *len, &bytes) < 0) return 0;
s += bytes; *len -= bytes;
}
return s;
}
static naRef f_chstr(naContext ctx, naRef me, int argc, naRef* args)
{
int n;
naRef ch;
unsigned char buf[6];
if(argc < 1 || naIsNil(ch=naNumValue(args[0])))
naRuntimeError(ctx, "bad/missing argument to utf8.chstr");
n = writec((int)ch.num, buf, sizeof(buf));
return naStr_fromdata(naNewString(ctx), (void*)buf, n);
}
static naRef f_size(naContext c, naRef me, int argc, naRef* args)
{
unsigned char* s;
int sz=0, n, len;
if(argc < 1 || !naIsString(args[0]))
naRuntimeError(c, "bad/missing argument to utf8.strc");
s = (void*)naStr_data(args[0]);
len = naStr_len(args[0]);
while(len > 0) {
if(readc(s, len, &n) < 0)
naRuntimeError(c, "utf8 encoding error in utf8.size");
sz++; len -= n; s += n;
}
return naNum(sz);
}
static naRef f_strc(naContext ctx, naRef me, int argc, naRef* args)
{
naRef idx;
unsigned char* s;
int len, c=0, bytes;
if(argc < 2 || !naIsString(args[0]) || naIsNil(idx=naNumValue(args[1])))
naRuntimeError(ctx, "bad/missing argument to utf8.strc");
len = naStr_len(args[0]);
s = nthchar((void*)naStr_data(args[0]), (int)idx.num, &len);
if(!s || (c = readc(s, len, &bytes)) < 0)
naRuntimeError(ctx, "utf8 encoding error in utf8.strc");
return naNum(c);
}
static naRef f_substr(naContext c, naRef me, int argc, naRef* args)
{
naRef start, end;
int len;
unsigned char *s, *s2;
end = argc > 2 ? naNumValue(args[2]) : naNil();
if((argc < 2 || !naIsString(args[0]) || naIsNil(start=naNumValue(args[1])))
|| (argc > 2 && naIsNil(end)))
naRuntimeError(c, "bad/missing argument to utf8.substr");
len = naStr_len(args[0]);
if(!(s = nthchar((void*)naStr_data(args[0]), (int)start.num, &len)))
naRuntimeError(c, "start index overrun in utf8.substr");
if(!naIsNil(end)) {
if(!(s2 = nthchar(s, (int)end.num, &len)))
naRuntimeError(c, "end index overrun in utf8.substr");
len = (int)(s2-s);
}
return naStr_fromdata(naNewString(c), (void*)s, len);
}
static naRef f_validate(naContext c, naRef me, int argc, naRef* args)
{
naRef result, unkc=naNil();
int len, len2, lenout=0, n;
unsigned char *s, *s2, *buf;
if(argc < 1 || !naIsString(args[0]) ||
(argc > 1 && naIsNil(unkc=naNumValue(args[1]))))
naRuntimeError(c, "bad/missing argument to utf8.strc");
if(naIsNil(unkc)) unkc = naNum('?');
len = naStr_len(args[0]);
s = (void*)naStr_data(args[0]);
len2 = 6*len; // max for ridiculous unkc values
s2 = buf = naAlloc(len2);
while(len > 0) {
int c = readc(s, len, &n);
if(c < 0) { c = (int)unkc.num; n = 1; }
s += n; len -= n;
n = writec(c, s2, len2);
s2 += n; len2 -= n; lenout += n;
}
result = naStr_fromdata(naNewString(c), (char*)buf, lenout);
naFree(buf);
return result;
}
static naCFuncItem funcs[] = {
{ "chstr", f_chstr },
{ "strc", f_strc },
{ "substr", f_substr },
{ "size", f_size },
{ "validate", f_validate },
{ 0 }
};
naRef naInit_utf8(naContext c)
{
return naGenLib(c, funcs);
}
+11 -12
View File
@@ -13,7 +13,7 @@ static struct VecRec* newvecrec(struct VecRec* old)
return vr; return vr;
} }
static void vecrealloc(struct naVec* v) static void resize(struct naVec* v)
{ {
struct VecRec* vr = newvecrec(v->rec); struct VecRec* vr = newvecrec(v->rec);
naGC_swapfree((void**)&(v->rec), vr); naGC_swapfree((void**)&(v->rec), vr);
@@ -28,7 +28,7 @@ void naVec_gcclean(struct naVec* v)
naRef naVec_get(naRef v, int i) naRef naVec_get(naRef v, int i)
{ {
if(IS_VEC(v)) { if(IS_VEC(v)) {
struct VecRec* r = v.ref.ptr.vec->rec; struct VecRec* r = PTR(v).vec->rec;
if(r) { if(r) {
if(i < 0) i += r->size; if(i < 0) i += r->size;
if(i >= 0 && i < r->size) return r->array[i]; if(i >= 0 && i < r->size) return r->array[i];
@@ -40,7 +40,7 @@ naRef naVec_get(naRef v, int i)
void naVec_set(naRef vec, int i, naRef o) void naVec_set(naRef vec, int i, naRef o)
{ {
if(IS_VEC(vec)) { if(IS_VEC(vec)) {
struct VecRec* r = vec.ref.ptr.vec->rec; struct VecRec* r = PTR(vec).vec->rec;
if(r && i >= r->size) return; if(r && i >= r->size) return;
r->array[i] = o; r->array[i] = o;
} }
@@ -49,7 +49,7 @@ void naVec_set(naRef vec, int i, naRef o)
int naVec_size(naRef v) int naVec_size(naRef v)
{ {
if(IS_VEC(v)) { if(IS_VEC(v)) {
struct VecRec* r = v.ref.ptr.vec->rec; struct VecRec* r = PTR(v).vec->rec;
return r ? r->size : 0; return r ? r->size : 0;
} }
return 0; return 0;
@@ -58,10 +58,10 @@ int naVec_size(naRef v)
int naVec_append(naRef vec, naRef o) int naVec_append(naRef vec, naRef o)
{ {
if(IS_VEC(vec)) { if(IS_VEC(vec)) {
struct VecRec* r = vec.ref.ptr.vec->rec; struct VecRec* r = PTR(vec).vec->rec;
while(!r || r->size >= r->alloced) { while(!r || r->size >= r->alloced) {
vecrealloc(vec.ref.ptr.vec); resize(PTR(vec).vec);
r = vec.ref.ptr.vec->rec; r = PTR(vec).vec->rec;
} }
r->array[r->size] = o; r->array[r->size] = o;
return r->size++; return r->size++;
@@ -72,26 +72,25 @@ int naVec_append(naRef vec, naRef o)
void naVec_setsize(naRef vec, int sz) void naVec_setsize(naRef vec, int sz)
{ {
int i; int i;
struct VecRec* v = vec.ref.ptr.vec->rec; struct VecRec* v = PTR(vec).vec->rec;
struct VecRec* nv = naAlloc(sizeof(struct VecRec) + sizeof(naRef) * sz); struct VecRec* nv = naAlloc(sizeof(struct VecRec) + sizeof(naRef) * sz);
nv->size = sz; nv->size = sz;
nv->alloced = sz; nv->alloced = sz;
for(i=0; i<sz; i++) for(i=0; i<sz; i++)
nv->array[i] = (v && i < v->size) ? v->array[i] : naNil(); nv->array[i] = (v && i < v->size) ? v->array[i] : naNil();
naFree(v); naGC_swapfree((void**)&(PTR(vec).vec->rec), nv);
vec.ref.ptr.vec->rec = nv;
} }
naRef naVec_removelast(naRef vec) naRef naVec_removelast(naRef vec)
{ {
naRef o; naRef o;
if(IS_VEC(vec)) { if(IS_VEC(vec)) {
struct VecRec* v = vec.ref.ptr.vec->rec; struct VecRec* v = PTR(vec).vec->rec;
if(!v || v->size == 0) return naNil(); if(!v || v->size == 0) return naNil();
o = v->array[v->size - 1]; o = v->array[v->size - 1];
v->size--; v->size--;
if(v->size < (v->alloced >> 1)) if(v->size < (v->alloced >> 1))
vecrealloc(vec.ref.ptr.vec); resize(PTR(vec).vec);
return o; return o;
} }
return naNil(); return naNil();
-7
View File
@@ -65,7 +65,6 @@ SGNotCondition::SGNotCondition (SGCondition * condition)
SGNotCondition::~SGNotCondition () SGNotCondition::~SGNotCondition ()
{ {
delete _condition;
} }
bool bool
@@ -86,8 +85,6 @@ SGAndCondition::SGAndCondition ()
SGAndCondition::~SGAndCondition () SGAndCondition::~SGAndCondition ()
{ {
for (unsigned int i = 0; i < _conditions.size(); i++)
delete _conditions[i];
} }
bool bool
@@ -119,8 +116,6 @@ SGOrCondition::SGOrCondition ()
SGOrCondition::~SGOrCondition () SGOrCondition::~SGOrCondition ()
{ {
for (unsigned int i = 0; i < _conditions.size(); i++)
delete _conditions[i];
} }
bool bool
@@ -398,13 +393,11 @@ SGConditional::SGConditional ()
SGConditional::~SGConditional () SGConditional::~SGConditional ()
{ {
delete _condition;
} }
void void
SGConditional::setCondition (SGCondition * condition) SGConditional::setCondition (SGCondition * condition)
{ {
delete _condition;
_condition = condition; _condition = condition;
} }
+7 -7
View File
@@ -13,6 +13,7 @@
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx> #include <simgear/props/props_io.hxx>
#include <simgear/structure/SGReferenced.hxx>
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@@ -28,7 +29,7 @@
* *
* This class should migrate to somewhere more general. * This class should migrate to somewhere more general.
*/ */
class SGCondition class SGCondition : public SGReferenced
{ {
public: public:
SGCondition (); SGCondition ();
@@ -63,12 +64,11 @@ private:
class SGNotCondition : public SGCondition class SGNotCondition : public SGCondition
{ {
public: public:
// transfer pointer ownership
SGNotCondition (SGCondition * condition); SGNotCondition (SGCondition * condition);
virtual ~SGNotCondition (); virtual ~SGNotCondition ();
virtual bool test () const; virtual bool test () const;
private: private:
SGCondition * _condition; SGSharedPtr<SGCondition> _condition;
}; };
@@ -87,7 +87,7 @@ public:
// transfer pointer ownership // transfer pointer ownership
virtual void addCondition (SGCondition * condition); virtual void addCondition (SGCondition * condition);
private: private:
vector<SGCondition *> _conditions; std::vector<SGSharedPtr<SGCondition> > _conditions;
}; };
@@ -106,7 +106,7 @@ public:
// transfer pointer ownership // transfer pointer ownership
virtual void addCondition (SGCondition * condition); virtual void addCondition (SGCondition * condition);
private: private:
vector<SGCondition *> _conditions; std::vector<SGSharedPtr<SGCondition> > _conditions;
}; };
@@ -146,7 +146,7 @@ private:
* invoke the test() method whenever it needs to decide whether to * invoke the test() method whenever it needs to decide whether to
* active itself, draw itself, and so on. * active itself, draw itself, and so on.
*/ */
class SGConditional class SGConditional : public SGReferenced
{ {
public: public:
SGConditional (); SGConditional ();
@@ -156,7 +156,7 @@ public:
virtual const SGCondition * getCondition () const { return _condition; } virtual const SGCondition * getCondition () const { return _condition; }
virtual bool test () const; virtual bool test () const;
private: private:
SGCondition * _condition; SGSharedPtr<SGCondition> _condition;
}; };
+84 -36
View File
@@ -595,11 +595,11 @@ void
SGPropertyNode::trace_write () const SGPropertyNode::trace_write () const
{ {
#if PROPS_STANDALONE #if PROPS_STANDALONE
cerr << "TRACE: Write node " << getPath () << ", value\"" cerr << "TRACE: Write node " << getPath () << ", value \""
<< make_string() << '"' << endl; << make_string() << '"' << endl;
#else #else
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath() SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
<< ", value\"" << make_string() << '"'); << ", value \"" << make_string() << '"');
#endif #endif
} }
@@ -613,7 +613,7 @@ SGPropertyNode::trace_read () const
cerr << "TRACE: Write node " << getPath () << ", value \"" cerr << "TRACE: Write node " << getPath () << ", value \""
<< make_string() << '"' << endl; << make_string() << '"' << endl;
#else #else
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath() SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
<< ", value \"" << make_string() << '"'); << ", value \"" << make_string() << '"');
#endif #endif
} }
@@ -756,7 +756,13 @@ SGPropertyNode::~SGPropertyNode ()
_removedChildren[i]->_parent = 0; _removedChildren[i]->_parent = 0;
delete _path_cache; delete _path_cache;
clearValue(); clearValue();
delete _listeners;
if (_listeners) {
vector<SGPropertyChangeListener*>::iterator it;
for (it = _listeners->begin(); it != _listeners->end(); ++it)
(*it)->unregister_property(this);
delete _listeners;
}
} }
@@ -904,6 +910,22 @@ SGPropertyNode::getChildren (const char * name) const
} }
/**
* Remove this node and all children from nodes that link to them
* in their path cache.
*/
void
SGPropertyNode::remove_from_path_caches ()
{
for (unsigned int i = 0; i < _children.size(); ++i)
_children[i]->remove_from_path_caches();
for (unsigned int i = 0; i < _linkedNodes.size(); i++)
_linkedNodes[i]->erase(this);
_linkedNodes.clear();
}
/** /**
* Remove child by position. * Remove child by position.
*/ */
@@ -921,8 +943,8 @@ SGPropertyNode::removeChild (int pos, bool keep)
if (keep) { if (keep) {
_removedChildren.push_back(node); _removedChildren.push_back(node);
} }
if (_path_cache)
_path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account! node->remove_from_path_caches();
node->setAttribute(REMOVED, true); node->setAttribute(REMOVED, true);
node->clearValue(); node->clearValue();
fireChildRemoved(node); fireChildRemoved(node);
@@ -933,7 +955,7 @@ SGPropertyNode::removeChild (int pos, bool keep)
/** /**
* Remove a child node * Remove a child node
*/ */
SGPropertyNode_ptr SGPropertyNode_ptr
SGPropertyNode::removeChild (const char * name, int index, bool keep) SGPropertyNode::removeChild (const char * name, int index, bool keep)
{ {
SGPropertyNode_ptr ret; SGPropertyNode_ptr ret;
@@ -961,6 +983,24 @@ SGPropertyNode::removeChildren (const char * name, bool keep)
} }
/**
* Remove a linked node.
*/
bool
SGPropertyNode::remove_linked_node (hash_table * node)
{
for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
if (_linkedNodes[i] == node) {
vector<hash_table *>::iterator it = _linkedNodes.begin();
it += i;
_linkedNodes.erase(it);
return true;
}
}
return false;
}
const char * const char *
SGPropertyNode::getDisplayName (bool simplify) const SGPropertyNode::getDisplayName (bool simplify) const
{ {
@@ -2187,23 +2227,31 @@ SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
} }
} }
void bool
SGPropertyNode::hash_table::bucket::erase (const char * key) SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
{ {
int i; for (int i = 0; i < _length; i++) {
for (i = 0; i < _length; i++) { if (_entries[i]->get_value() == node) {
if (!strcmp(_entries[i]->get_key(), key)) delete _entries[i];
break; for (++i; i < _length; i++) {
} _entries[i-1] = _entries[i];
}
if (i < _length) { _length--;
for (++i; i < _length; i++) { return true;
_entries[i-1] = _entries[i];
} }
_length--;
} }
return false;
} }
void
SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
{
for (int i = 0; i < _length; i++) {
SGPropertyNode * node = _entries[i]->get_value();
if (node)
node->remove_linked_node(owner);
}
}
SGPropertyNode::hash_table::hash_table () SGPropertyNode::hash_table::hash_table ()
: _data_length(0), : _data_length(0),
@@ -2213,8 +2261,12 @@ SGPropertyNode::hash_table::hash_table ()
SGPropertyNode::hash_table::~hash_table () SGPropertyNode::hash_table::~hash_table ()
{ {
for (unsigned int i = 0; i < _data_length; i++) for (unsigned int i = 0; i < _data_length; i++) {
delete _data[i]; if (_data[i]) {
_data[i]->clear(this);
delete _data[i];
}
}
delete [] _data; delete [] _data;
} }
@@ -2248,17 +2300,17 @@ SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
} }
entry * e = _data[index]->get_entry(key, true); entry * e = _data[index]->get_entry(key, true);
e->set_value(value); e->set_value(value);
value->add_linked_node(this);
} }
void bool
SGPropertyNode::hash_table::erase (const char * key) SGPropertyNode::hash_table::erase (SGPropertyNode * node)
{ {
if (_data_length == 0) for (unsigned int i = 0; i < _data_length; i++)
return; if (_data[i] && _data[i]->erase(node))
unsigned int index = hashcode(key) % _data_length; return true;
if (_data[index] == 0)
return; return false;
_data[index]->erase(key);
} }
unsigned int unsigned int
@@ -2280,12 +2332,8 @@ SGPropertyNode::hash_table::hashcode (const char * key)
SGPropertyChangeListener::~SGPropertyChangeListener () SGPropertyChangeListener::~SGPropertyChangeListener ()
{ {
// This will come back and remove for (int i = _properties.size() - 1; i >= 0; i--)
// the current item each time. Is _properties[i]->removeChangeListener(this);
// that OK?
vector<SGPropertyNode *>::iterator it;
for (it = _properties.begin(); it != _properties.end(); it++)
(*it)->removeChangeListener(this);
} }
void void
+25 -4
View File
@@ -1110,6 +1110,12 @@ public:
void removeChangeListener (SGPropertyChangeListener * listener); void removeChangeListener (SGPropertyChangeListener * listener);
/**
* Get the number of listeners.
*/
int nListeners () const { return _listeners ? _listeners->size() : 0; }
/** /**
* Fire a value change event to all listeners. * Fire a value change event to all listeners.
*/ */
@@ -1183,6 +1189,12 @@ private:
void trace_write () const; void trace_write () const;
/**
* Remove this node from all nodes that link to it in their path cache.
*/
void remove_from_path_caches();
class hash_table; class hash_table;
int _index; int _index;
@@ -1193,6 +1205,7 @@ private:
SGPropertyNode * _parent; SGPropertyNode * _parent;
vector<SGPropertyNode_ptr> _children; vector<SGPropertyNode_ptr> _children;
vector<SGPropertyNode_ptr> _removedChildren; vector<SGPropertyNode_ptr> _removedChildren;
vector<hash_table *> _linkedNodes;
mutable string _path; mutable string _path;
mutable string _buffer; mutable string _buffer;
hash_table * _path_cache; hash_table * _path_cache;
@@ -1223,9 +1236,16 @@ private:
vector <SGPropertyChangeListener *> * _listeners; vector <SGPropertyChangeListener *> * _listeners;
/**
* Register/unregister node that links to this node in its path cache.
*/
void add_linked_node (hash_table * node) { _linkedNodes.push_back(node); }
bool remove_linked_node (hash_table * node);
/** /**
* A very simple hash table with no remove functionality. * A very simple hash table.
*/ */
class hash_table { class hash_table {
public: public:
@@ -1243,7 +1263,7 @@ private:
void set_value (SGPropertyNode * value); void set_value (SGPropertyNode * value);
private: private:
string _key; string _key;
SGSharedPtr<SGPropertyNode> _value; SGSharedPtr<SGPropertyNode> _value;
}; };
@@ -1255,7 +1275,8 @@ private:
bucket (); bucket ();
~bucket (); ~bucket ();
entry * get_entry (const char * key, bool create = false); entry * get_entry (const char * key, bool create = false);
void erase(const char * key); bool erase (SGPropertyNode * node);
void clear (hash_table * owner);
private: private:
int _length; int _length;
entry ** _entries; entry ** _entries;
@@ -1267,7 +1288,7 @@ private:
~hash_table (); ~hash_table ();
SGPropertyNode * get (const char * key); SGPropertyNode * get (const char * key);
void put (const char * key, SGPropertyNode * value); void put (const char * key, SGPropertyNode * value);
void erase(const char * key); bool erase (SGPropertyNode * node);
private: private:
unsigned int hashcode (const char * key); unsigned int hashcode (const char * key);
+24 -4
View File
@@ -229,6 +229,21 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
} catch (sg_io_exception &e) { } catch (sg_io_exception &e) {
setException(e); setException(e);
} }
const char *omit = atts.getValue("omit-node");
if (omit && !strcmp(omit, "y")) {
int nChildren = node->nChildren();
for (int i = 0; i < nChildren; i++) {
SGPropertyNode *src = node->getChild(i);
const char *name = src->getName();
int index = st.counters[name];
st.counters[name]++;
SGPropertyNode *dst = st.node->getChild(name, index, true);
copyProperties(src, dst);
}
st.node->removeChild(node->getName(), node->getIndex(), false);
node = st.node;
}
} }
const char *type = atts.getValue("type"); const char *type = atts.getValue("type");
@@ -432,11 +447,11 @@ doIndent (ostream &output, int indent)
static void static void
writeAtts (ostream &output, const SGPropertyNode * node) writeAtts (ostream &output, const SGPropertyNode * node, bool forceindex)
{ {
int index = node->getIndex(); int index = node->getIndex();
if (index != 0) if (index != 0 || forceindex)
output << " n=\"" << index << '"'; output << " n=\"" << index << '"';
#if 0 #if 0
@@ -484,13 +499,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
const string name = node->getName(); const string name = node->getName();
int nChildren = node->nChildren(); int nChildren = node->nChildren();
bool node_has_value = false;
// If there is a literal value, // If there is a literal value,
// write it first. // write it first.
if (node->hasValue() && (write_all || node->getAttribute(archive_flag))) { if (node->hasValue() && (write_all || node->getAttribute(archive_flag))) {
doIndent(output, indent); doIndent(output, indent);
output << '<' << name; output << '<' << name;
writeAtts(output, node); writeAtts(output, node, nChildren != 0);
if (node->isAlias() && node->getAliasTarget() != 0) { if (node->isAlias() && node->getAliasTarget() != 0) {
output << " alias=\"" << node->getAliasTarget()->getPath() output << " alias=\"" << node->getAliasTarget()->getPath()
<< "\"/>" << endl; << "\"/>" << endl;
@@ -501,13 +517,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
writeData(output, node->getStringValue()); writeData(output, node->getStringValue());
output << "</" << name << '>' << endl; output << "</" << name << '>' << endl;
} }
node_has_value = true;
} }
// If there are children, write them next. // If there are children, write them next.
if (nChildren > 0) { if (nChildren > 0) {
doIndent(output, indent); doIndent(output, indent);
output << '<' << name; output << '<' << name;
writeAtts(output, node); writeAtts(output, node, node_has_value);
output << '>' << endl; output << '>' << endl;
for (int i = 0; i < nChildren; i++) for (int i = 0; i < nChildren; i++)
writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP, archive_flag); writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP, archive_flag);
@@ -540,6 +557,9 @@ void
writeProperties (const string &file, const SGPropertyNode * start_node, writeProperties (const string &file, const SGPropertyNode * start_node,
bool write_all, SGPropertyNode::Attribute archive_flag) bool write_all, SGPropertyNode::Attribute archive_flag)
{ {
SGPath path(file.c_str());
path.create_dir(0777);
ofstream output(file.c_str()); ofstream output(file.c_str());
if (output.good()) { if (output.good()) {
writeProperties(output, start_node, write_all, archive_flag); writeProperties(output, start_node, write_all, archive_flag);
+3
View File
@@ -19,6 +19,9 @@ waytest_LDADD = \
$(top_builddir)/simgear/math/libsgmath.a \ $(top_builddir)/simgear/math/libsgmath.a \
$(top_builddir)/simgear/debug/libsgdebug.a \ $(top_builddir)/simgear/debug/libsgdebug.a \
$(top_builddir)/simgear/misc/libsgmisc.a \ $(top_builddir)/simgear/misc/libsgmisc.a \
$(top_builddir)/simgear/props/libsgprops.a \
$(top_builddir)/simgear/structure/libsgstructure.a \
$(top_builddir)/simgear/xml/libsgxml.a \
$(base_LIBS) \ $(base_LIBS) \
-lz -lz
+48 -1
View File
@@ -49,7 +49,7 @@ double SGRoute::distance_off_route( double x, double y ) const {
int n1 = current_wp; int n1 = current_wp;
sgdVec3 p, p0, p1, d; sgdVec3 p, p0, p1, d;
sgdSetVec3( p, x, y, 0.0 ); sgdSetVec3( p, x, y, 0.0 );
sgdSetVec3( p0, sgdSetVec3( p0,
route[n0].get_target_lon(), route[n0].get_target_lat(), route[n0].get_target_lon(), route[n0].get_target_lat(),
0.0 ); 0.0 );
sgdSetVec3( p1, sgdSetVec3( p1,
@@ -68,3 +68,50 @@ double SGRoute::distance_off_route( double x, double y ) const {
return 0; return 0;
} }
} }
/** Update the length of the leg ending at waypoint index */
void SGRoute::update_distance(int index)
{
SGWayPoint& curr = route[ index ];
double course, dist;
if ( index == 0 ) {
dist = 0;
} else {
const SGWayPoint& prev = route[ index - 1 ];
curr.CourseAndDistance( prev, &course, &dist );
}
curr.set_distance( dist );
}
/**
* Add waypoint (default), or insert waypoint at position n.
* @param wp a waypoint
*/
void SGRoute::add_waypoint( const SGWayPoint &wp, int n ) {
int size = route.size();
if ( n < 0 || n >= size ) {
n = size;
route.push_back( wp );
} else {
route.insert( route.begin() + n, 1, wp );
// update distance of next leg if not at end of route
update_distance( n + 1 );
}
update_distance( n );
}
/** Delete waypoint with index n (last one if n < 0) */
void SGRoute::delete_waypoint( int n ) {
int size = route.size();
if ( size == 0 )
return;
if ( n < 0 || n >= size )
n = size - 1;
route.erase( route.begin() + n );
// update distance of next leg if not at end of route
if ( n < size - 1 )
update_distance( n );
}
+8 -18
View File
@@ -55,6 +55,8 @@ private:
route_list route; route_list route;
int current_wp; int current_wp;
void update_distance(int index);
public: public:
/** Constructor */ /** Constructor */
@@ -70,21 +72,10 @@ public:
} }
/** /**
* Add a waypoint. * Add waypoint (default), or insert waypoint at position n.
* @param wp a waypoint * @param wp a waypoint
*/ */
inline void add_waypoint( const SGWayPoint &wp ) { void add_waypoint( const SGWayPoint &wp, int n = -1 );
route.push_back( wp );
int size = route.size();
if ( size > 1 ) {
SGWayPoint next_to_last = route[ size - 2 ];
double tmpd, tmpc;
wp.CourseAndDistance( next_to_last, &tmpc, &tmpd );
route[size - 1].set_distance( tmpd );
}
}
/** /**
* Get the number of waypoints (i.e. route length ) * Get the number of waypoints (i.e. route length )
* @return route length * @return route length
@@ -146,11 +137,10 @@ public:
} }
/** Delete the front waypoint */ /** Delete the front waypoint */
inline void delete_first() { inline void delete_first() { delete_waypoint(0); }
if ( route.size() ) {
route.erase( route.begin() ); /** Delete waypoint waypoint with index n (last one if n < 0) */
} void delete_waypoint( int n = 0 );
}
/** /**
* Calculate perpendicular distance from the current route segment * Calculate perpendicular distance from the current route segment
+23 -3
View File
@@ -8,8 +8,20 @@
SG_USING_STD(cout); SG_USING_STD(cout);
SG_USING_STD(endl); SG_USING_STD(endl);
int main() { void dump_route(const SGRoute& route, const char* message)
{
cout << "Route dump: " << message << endl;
for (int i = 0; i < route.size(); i++) {
const SGWayPoint wp = route.get_waypoint(i);
cout << "\t#" << i << " " << wp.get_id() << " (" << wp.get_target_lat()
<< ", " << wp.get_target_lon() << ") @" << wp.get_target_alt()
<< " dist: " << wp.get_distance() << endl;
}
}
int main()
{
SGRoute route; SGRoute route;
route.add_waypoint( SGWayPoint(0, 0, 0, SGWayPoint::CARTESIAN, "Start") ); route.add_waypoint( SGWayPoint(0, 0, 0, SGWayPoint::CARTESIAN, "Start") );
@@ -17,7 +29,8 @@ int main() {
route.add_waypoint( SGWayPoint(2, 0, 0, SGWayPoint::CARTESIAN, "2") ); route.add_waypoint( SGWayPoint(2, 0, 0, SGWayPoint::CARTESIAN, "2") );
route.add_waypoint( SGWayPoint(2, 2, 0, SGWayPoint::CARTESIAN, "3") ); route.add_waypoint( SGWayPoint(2, 2, 0, SGWayPoint::CARTESIAN, "3") );
route.add_waypoint( SGWayPoint(4, 2, 0, SGWayPoint::CARTESIAN, "4") ); route.add_waypoint( SGWayPoint(4, 2, 0, SGWayPoint::CARTESIAN, "4") );
dump_route(route, "Init");
route.set_current( 1 ); route.set_current( 1 );
cout << "( 0.5, 0 ) = " << route.distance_off_route( 0.5, 0 ) << endl; cout << "( 0.5, 0 ) = " << route.distance_off_route( 0.5, 0 ) << endl;
@@ -29,5 +42,12 @@ int main() {
cout << "( 2, 4 ) = " << route.distance_off_route( 2, 4 ) << endl; cout << "( 2, 4 ) = " << route.distance_off_route( 2, 4 ) << endl;
cout << "( 2.5, 4 ) = " << route.distance_off_route( 2.5, 4 ) << endl; cout << "( 2.5, 4 ) = " << route.distance_off_route( 2.5, 4 ) << endl;
SGWayPoint wp2 = route.get_waypoint(2);
route.delete_waypoint(2);
dump_route(route, "removed WP2");
route.add_waypoint(wp2, 3);
dump_route(route, "added back WP2 after WP3");
return 0; return 0;
} }
+1 -1
View File
@@ -1,6 +1,6 @@
includedir = @includedir@/scene includedir = @includedir@/scene
SUBDIRS = material model sky tgdb SUBDIRS = material model sky tgdb util
# lib_LIBRARIES = libsgscene.a # lib_LIBRARIES = libsgscene.a
+134 -41
View File
@@ -37,12 +37,23 @@ SG_USING_STD(map);
# include <math.h> # include <math.h>
#endif #endif
#include <osg/CullFace>
#include <osg/Material>
#include <osg/ShadeModel>
#include <osg/TexEnv>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sgstream.hxx> #include <simgear/misc/sgstream.hxx>
#include <simgear/scene/model/model.hxx>
#include "mat.hxx" #include "mat.hxx"
static map<string, osg::ref_ptr<osg::Texture2D> > _tex_cache;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Constructors and destructor. // Constructors and destructor.
@@ -53,7 +64,7 @@ SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props, cons
{ {
init(); init();
read_properties( fg_root, props, season ); read_properties( fg_root, props, season );
build_ssg_state( false ); build_state( false );
} }
SGMaterial::SGMaterial( const string &texpath ) SGMaterial::SGMaterial( const string &texpath )
@@ -63,13 +74,13 @@ SGMaterial::SGMaterial( const string &texpath )
_internal_state st( NULL, texpath, false ); _internal_state st( NULL, texpath, false );
_status.push_back( st ); _status.push_back( st );
build_ssg_state( true ); build_state( true );
} }
SGMaterial::SGMaterial( ssgSimpleState *s ) SGMaterial::SGMaterial( osg::StateSet *s )
{ {
init(); init();
set_ssg_state( s ); set_state( s );
} }
SGMaterial::~SGMaterial (void) SGMaterial::~SGMaterial (void)
@@ -120,6 +131,7 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
string tname = "unknown.rgb"; string tname = "unknown.rgb";
SGPath tpath( fg_root ); SGPath tpath( fg_root );
tpath.append("Textures"); tpath.append("Textures");
tpath.append("Terrain");
tpath.append(tname); tpath.append(tname);
_internal_state st( NULL, tpath.str(), true ); _internal_state st( NULL, tpath.str(), true );
_status.push_back( st ); _status.push_back( st );
@@ -132,6 +144,13 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
mipmap = props->getBoolValue("mipmap", true); mipmap = props->getBoolValue("mipmap", true);
light_coverage = props->getDoubleValue("light-coverage", 0.0); light_coverage = props->getDoubleValue("light-coverage", 0.0);
// surface values for use with ground reactions
solid = props->getBoolValue("solid", true);
friction_factor = props->getDoubleValue("friction-factor", 1.0);
rolling_friction = props->getDoubleValue("rolling-friction", 0.02);
bumpiness = props->getDoubleValue("bumpiness", 0.0);
load_resistance = props->getDoubleValue("load-resistance", 1e30);
// Taken from default values as used in ac3d // Taken from default values as used in ac3d
ambient[0] = props->getDoubleValue("ambient/r", 0.2); ambient[0] = props->getDoubleValue("ambient/r", 0.2);
ambient[1] = props->getDoubleValue("ambient/g", 0.2); ambient[1] = props->getDoubleValue("ambient/g", 0.2);
@@ -159,6 +178,14 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
((SGPropertyNode *)props)->getChildren("object-group"); ((SGPropertyNode *)props)->getChildren("object-group");
for (unsigned int i = 0; i < object_group_nodes.size(); i++) for (unsigned int i = 0; i < object_group_nodes.size(); i++)
object_groups.push_back(new SGMatModelGroup(object_group_nodes[i])); object_groups.push_back(new SGMatModelGroup(object_group_nodes[i]));
// read glyph table for taxi-/runway-signs
vector<SGPropertyNode_ptr> glyph_nodes = props->getChildren("glyph");
for (unsigned int i = 0; i < glyph_nodes.size(); i++) {
const char *name = glyph_nodes[i]->getStringValue("name");
if (name)
glyphs[name] = new SGMaterialGlyph(glyph_nodes[i]);
}
} }
@@ -176,8 +203,16 @@ SGMaterial::init ()
ysize = 0; ysize = 0;
wrapu = true; wrapu = true;
wrapv = true; wrapv = true;
mipmap = true; mipmap = true;
light_coverage = 0.0; light_coverage = 0.0;
solid = true;
friction_factor = 1;
rolling_friction = 0.02;
bumpiness = 0;
load_resistance = 1e30;
shininess = 1.0; shininess = 1.0;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
ambient[i] = (i < 3) ? 0.2 : 1.0; ambient[i] = (i < 3) ? 0.2 : 1.0;
@@ -198,16 +233,15 @@ SGMaterial::load_texture ( int n )
if ( !_status[i].texture_loaded ) { if ( !_status[i].texture_loaded ) {
SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture " SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture "
<< _status[i].texture_path ); << _status[i].texture_path );
_status[i].state->setTexture( assignTexture(_status[i].state.get(), _status[i].texture_path,
(char *)_status[i].texture_path.c_str(), wrapu, wrapv, mipmap);
wrapu, wrapv, mipmap );
_status[i].texture_loaded = true; _status[i].texture_loaded = true;
} }
} }
return true; return true;
} }
ssgSimpleState * osg::StateSet *
SGMaterial::get_state (int n) const SGMaterial::get_state (int n) const
{ {
if (_status.size() == 0) { if (_status.size() == 0) {
@@ -215,65 +249,124 @@ SGMaterial::get_state (int n) const
return NULL; return NULL;
} }
ssgSimpleState *st = (n >= 0) ? _status[n].state osg::StateSet *st = (n >= 0) ? _status[n].state.get()
: _status[_current_ptr].state; : _status[_current_ptr].state.get();
((SGMaterial *)this)->_current_ptr += 1; _current_ptr += 1;
if (_current_ptr >= _status.size()) if (_current_ptr >= _status.size())
((SGMaterial *)this)->_current_ptr = 0; _current_ptr = 0;
return st; return st;
} }
void void
SGMaterial::build_ssg_state( bool defer_tex_load ) SGMaterial::build_state( bool defer_tex_load )
{ {
GLenum shade_model = GL_SMOOTH;
for (unsigned int i = 0; i < _status.size(); i++) for (unsigned int i = 0; i < _status.size(); i++)
{ {
ssgSimpleState *state = new ssgSimpleState(); osg::StateSet *stateSet = new osg::StateSet;
stateSet->setUserData(new SGMaterialUserData(this));
// Set up the textured state // Set up the textured state
state->setShadeModel( shade_model ); osg::ShadeModel* shadeModel = new osg::ShadeModel;
state->enable( GL_LIGHTING ); shadeModel->setMode(osg::ShadeModel::SMOOTH);
state->enable ( GL_CULL_FACE ) ; stateSet->setAttribute(shadeModel);
state->enable( GL_TEXTURE_2D );
state->disable( GL_BLEND ); osg::CullFace* cullFace = new osg::CullFace;
state->disable( GL_ALPHA_TEST ); cullFace->setMode(osg::CullFace::BACK);
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
stateSet->setAttribute(cullFace);
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
if ( !defer_tex_load ) { if ( !defer_tex_load ) {
SG_LOG(SG_INPUT, SG_INFO, " " << _status[i].texture_path ); SG_LOG(SG_INPUT, SG_INFO, " " << _status[i].texture_path );
state->setTexture( (char *)_status[i].texture_path.c_str(), assignTexture( stateSet, _status[i].texture_path, wrapu, wrapv);
wrapu, wrapv );
_status[i].texture_loaded = true; _status[i].texture_loaded = true;
} else { } else {
_status[i].texture_loaded = false; _status[i].texture_loaded = false;
} }
state->enable( GL_COLOR_MATERIAL ); osg::Material* material = new osg::Material;
state->setMaterial ( GL_AMBIENT, material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
ambient[0], ambient[1], material->setAmbient(osg::Material::FRONT_AND_BACK, ambient.osg());
ambient[2], ambient[3] ) ; material->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse.osg());
state->setMaterial ( GL_DIFFUSE, material->setSpecular(osg::Material::FRONT_AND_BACK, specular.osg());
diffuse[0], diffuse[1], material->setEmission(osg::Material::FRONT_AND_BACK, emission.osg());
diffuse[2], diffuse[3] ) ; material->setShininess(osg::Material::FRONT_AND_BACK, shininess );
state->setMaterial ( GL_SPECULAR, stateSet->setAttribute(material);
specular[0], specular[1],
specular[2], specular[3] ) ;
state->setMaterial ( GL_EMISSION,
emission[0], emission[1],
emission[2], emission[3] ) ;
state->setShininess ( shininess );
_status[i].state = state; if (ambient[3] < 1 || diffuse[3] < 1 ||
specular[3] < 1 || emission[3] < 1) {
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
} else {
stateSet->setRenderingHint(osg::StateSet::OPAQUE_BIN);
stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
}
_status[i].state = stateSet;
} }
} }
void SGMaterial::set_ssg_state( ssgSimpleState *s ) void SGMaterial::set_state( osg::StateSet *s )
{ {
_status.push_back( _internal_state( s, "", true ) ); _status.push_back( _internal_state( s, "", true ) );
} }
// end of mat.cxx void SGMaterial::assignTexture( osg::StateSet *state, const std::string &fname,
int _wrapu, int _wrapv, int _mipmap )
{
map<string, osg::ref_ptr<osg::Texture2D> >::iterator _tex_cache_iter;
_tex_cache_iter = _tex_cache.find(fname);
if (_tex_cache_iter == _tex_cache.end())
{
osg::Texture2D* texture = SGLoadTexture2D(fname, _wrapu, _wrapv,
mipmap ? -1 : 0);
texture->setMaxAnisotropy( SGGetTextureFilter());
state->setTextureAttributeAndModes(0, texture);
_tex_cache[fname] = texture;
}
else
{
state->setTextureAttributeAndModes(0, _tex_cache_iter->second.get());
// cout << "Cache hit: " << fname << endl;
}
osg::TexEnv* texEnv = new osg::TexEnv;
texEnv->setMode(osg::TexEnv::MODULATE);
state->setTextureAttributeAndModes(0, texEnv);
}
SGMaterialGlyph* SGMaterial::get_glyph (const string& name) const
{
map<string, SGSharedPtr<SGMaterialGlyph> >::const_iterator it;
it = glyphs.find(name);
if (it == glyphs.end())
return 0;
return it->second;
}
////////////////////////////////////////////////////////////////////////
// SGMaterialGlyph.
////////////////////////////////////////////////////////////////////////
SGMaterialGlyph::SGMaterialGlyph(SGPropertyNode *p) :
_left(p->getDoubleValue("left", 0.0)),
_right(p->getDoubleValue("right", 1.0))
{
}
void
SGSetTextureFilter( int max) {
SGSceneFeatures::instance()->setTextureFilter( max);
}
int
SGGetTextureFilter() {
return SGSceneFeatures::instance()->getTextureFilter();
}
+134 -24
View File
@@ -34,20 +34,26 @@
#include STL_STRING // Standard C++ string library #include STL_STRING // Standard C++ string library
#include <vector> #include <vector>
#include <map>
#include <plib/sg.h> #include <simgear/math/SGMath.hxx>
#include <plib/ssg.h>
#include <osg/ref_ptr>
#include <osg/StateSet>
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
#include <simgear/structure/ssgSharedPtr.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/scene/util/SGSceneFeatures.hxx>
#include "matmodel.hxx" #include "matmodel.hxx"
SG_USING_STD(string); SG_USING_STD(string);
SG_USING_STD(vector); SG_USING_STD(vector);
SG_USING_STD(map);
class SGMaterialGlyph;
/** /**
* A material in the scene graph. * A material in the scene graph.
* *
@@ -86,20 +92,20 @@ public:
/** /**
* Construct a material around an existing SSG state. * Construct a material around an existing state.
* *
* This constructor allows the application to create a custom, * This constructor allows the application to create a custom,
* low-level state for the scene graph and wrap a material around * low-level state for the scene graph and wrap a material around
* it. Note: the pointer ownership is transferred to the material. * it. Note: the pointer ownership is transferred to the material.
* *
* @param s The SSG state for this material. * @param s The state for this material.
*/ */
SGMaterial( ssgSimpleState *s ); SGMaterial( osg::StateSet *s );
/** /**
* Destructor. * Destructor.
*/ */
virtual ~SGMaterial( void ); ~SGMaterial( void );
@@ -113,31 +119,30 @@ public:
* @return true if the texture loaded, false if it was loaded * @return true if the texture loaded, false if it was loaded
* already. * already.
*/ */
virtual bool load_texture (int n = -1); bool load_texture (int n = -1);
/** /**
* Get the textured state. * Get the textured state.
*/ */
virtual ssgSimpleState *get_state (int n = -1) const; osg::StateSet *get_state (int n = -1) const;
/** /**
* Get the number of textures assigned to this material. * Get the number of textures assigned to this material.
*/ */
virtual inline int get_num() const { return _status.size(); } inline int get_num() const { return _status.size(); }
/** /**
* Get the xsize of the texture, in meters. * Get the xsize of the texture, in meters.
*/ */
virtual inline double get_xsize() const { return xsize; } inline double get_xsize() const { return xsize; }
/** /**
* Get the ysize of the texture, in meters. * Get the ysize of the texture, in meters.
*/ */
virtual inline double get_ysize() const { return ysize; } inline double get_ysize() const { return ysize; }
/** /**
@@ -147,22 +152,75 @@ public:
* *
* @return The area (m^2?) covered by each light. * @return The area (m^2?) covered by each light.
*/ */
virtual inline double get_light_coverage () const { return light_coverage; } inline double get_light_coverage () const { return light_coverage; }
/**
* Return if the surface material is solid, if it is not solid, a fluid
* can be assumed, that is usually water.
*/
bool get_solid () const { return solid; }
/**
* Get the friction factor for that material
*/
double get_friction_factor () const { return friction_factor; }
/**
* Get the rolling friction for that material
*/
double get_rolling_friction () const { return rolling_friction; }
/**
* Get the bumpines for that material
*/
double get_bumpiness () const { return bumpiness; }
/**
* Get the load resistance
*/
double get_load_resistance () const { return load_resistance; }
/**
* Get the list of names for this material
*/
const vector<string>& get_names() const { return _names; }
/**
* add the given name to the list of names this material is known
*/
void add_name(const string& name) { _names.push_back(name); }
/** /**
* Get the number of randomly-placed objects defined for this material. * Get the number of randomly-placed objects defined for this material.
*/ */
virtual int get_object_group_count () const { return object_groups.size(); } int get_object_group_count () const { return object_groups.size(); }
/** /**
* Get a randomly-placed object for this material. * Get a randomly-placed object for this material.
*/ */
virtual SGMatModelGroup * get_object_group (int index) const { SGMatModelGroup * get_object_group (int index) const {
return object_groups[index]; return object_groups[index];
} }
/**
* Return pointer to glyph class, or 0 if it doesn't exist.
*/
SGMaterialGlyph * get_glyph (const string& name) const;
void set_light_color(const SGVec4f& color)
{ emission = color; }
const SGVec4f& get_light_color() const
{ return emission; }
SGVec2f get_tex_coord_scale() const
{
float tex_width = get_xsize();
float tex_height = get_ysize();
return SGVec2f((0 < tex_width) ? 1000.0f/tex_width : 1.0f,
(0 < tex_height) ? 1000.0f/tex_height : 1.0f);
}
protected: protected:
@@ -173,14 +231,14 @@ protected:
/** /**
* Initialization method, invoked by all public constructors. * Initialization method, invoked by all public constructors.
*/ */
virtual void init(); void init();
protected: protected:
struct _internal_state { struct _internal_state {
_internal_state( ssgSimpleState *s, const string &t, bool l ) _internal_state( osg::StateSet *s, const string &t, bool l )
: state(s), texture_path(t), texture_loaded(l) {} : state(s), texture_path(t), texture_loaded(l) {}
ssgSharedPtr<ssgSimpleState> state; osg::ref_ptr<osg::StateSet> state;
string texture_path; string texture_path;
bool texture_loaded; bool texture_loaded;
}; };
@@ -196,7 +254,7 @@ private:
vector<_internal_state> _status; vector<_internal_state> _status;
// Round-robin counter // Round-robin counter
unsigned int _current_ptr; mutable unsigned int _current_ptr;
// texture size // texture size
double xsize, ysize; double xsize, ysize;
@@ -210,12 +268,33 @@ private:
// coverage of night lighting. // coverage of night lighting.
double light_coverage; double light_coverage;
// True if the material is solid, false if it is a fluid
bool solid;
// the friction factor of that surface material
double friction_factor;
// the rolling friction of that surface material
double rolling_friction;
// the bumpiness of that surface material
double bumpiness;
// the load resistance of that surface material
double load_resistance;
// material properties // material properties
sgVec4 ambient, diffuse, specular, emission; SGVec4f ambient, diffuse, specular, emission;
double shininess; double shininess;
// the list of names for this material. May be empty.
vector<string> _names;
vector<SGSharedPtr<SGMatModelGroup> > object_groups; vector<SGSharedPtr<SGMatModelGroup> > object_groups;
// taxiway-/runway-sign texture elements
map<string, SGSharedPtr<SGMaterialGlyph> > glyphs;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Internal constructors and methods. // Internal constructors and methods.
@@ -224,10 +303,41 @@ private:
SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented
void read_properties( const string &fg_root, const SGPropertyNode *props, const char *season ); void read_properties( const string &fg_root, const SGPropertyNode *props, const char *season );
void build_ssg_state( bool defer_tex_load ); void build_state( bool defer_tex_load );
void set_ssg_state( ssgSimpleState *s ); void set_state( osg::StateSet *s );
void assignTexture( osg::StateSet *state, const std::string &fname, int _wrapu = TRUE, int _wrapv = TRUE, int _mipmap = TRUE );
}; };
class SGMaterialGlyph : public SGReferenced {
public:
SGMaterialGlyph(SGPropertyNode *);
inline double get_left() const { return _left; }
inline double get_right() const { return _right; }
inline double get_width() const { return _right - _left; }
protected:
double _left;
double _right;
};
class SGMaterialUserData : public osg::Referenced {
public:
SGMaterialUserData(const SGMaterial* material) :
mMaterial(material)
{}
const SGMaterial* getMaterial() const
{ return mMaterial; }
private:
SGSharedPtr<const SGMaterial> mMaterial;
};
void
SGSetTextureFilter( int max);
int
SGGetTextureFilter();
#endif // _SG_MAT_HXX #endif // _SG_MAT_HXX
+38 -376
View File
@@ -42,10 +42,24 @@
#include <string.h> #include <string.h>
#include STL_STRING #include STL_STRING
#include <osg/AlphaFunc>
#include <osg/BlendFunc>
#include <osg/CullFace>
#include <osg/Material>
#include <osg/Point>
#include <osg/PointSprite>
#include <osg/PolygonMode>
#include <osg/PolygonOffset>
#include <osg/StateSet>
#include <osg/TexEnv>
#include <osg/TexGen>
#include <osg/Texture2D>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sgstream.hxx> #include <simgear/misc/sgstream.hxx>
#include <simgear/props/props_io.hxx> #include <simgear/props/props_io.hxx>
#include <simgear/scene/tgdb/userdata.hxx>
#include "mat.hxx" #include "mat.hxx"
@@ -54,126 +68,10 @@
SG_USING_NAMESPACE(std); SG_USING_NAMESPACE(std);
SG_USING_STD(string); SG_USING_STD(string);
// Constructor // Constructor
SGMaterialLib::SGMaterialLib ( void ) { SGMaterialLib::SGMaterialLib ( void ) {
} }
#if 0 // debugging infrastructure
static int gen_test_light_map() {
static const int env_tex_res = 32;
int half_res = env_tex_res / 2;
unsigned char env_map[env_tex_res][env_tex_res][4];
GLuint tex_name;
for ( int i = 0; i < env_tex_res; ++i ) {
for ( int j = 0; j < env_tex_res; ++j ) {
double x = (i - half_res) / (double)half_res;
double y = (j - half_res) / (double)half_res;
double dist = sqrt(x*x + y*y);
if ( dist > 1.0 ) { dist = 1.0; }
// cout << x << "," << y << " " << (int)(dist * 255) << ","
// << (int)((1.0 - dist) * 255) << endl;
env_map[i][j][0] = (int)(dist * 255);
env_map[i][j][1] = (int)((1.0 - dist) * 255);
env_map[i][j][2] = 0;
env_map[i][j][3] = 255;
}
}
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glGenTextures( 1, &tex_name );
glBindTexture( GL_TEXTURE_2D, tex_name );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
return tex_name;
}
#endif
// generate standard colored directional light environment texture map
static int gen_standard_dir_light_map( int r, int g, int b, int alpha ) {
const int env_tex_res = 32;
int half_res = env_tex_res / 2;
unsigned char env_map[env_tex_res][env_tex_res][4];
GLuint tex_name;
for ( int i = 0; i < env_tex_res; ++i ) {
for ( int j = 0; j < env_tex_res; ++j ) {
double x = (i - half_res) / (double)half_res;
double y = (j - half_res) / (double)half_res;
double dist = sqrt(x*x + y*y);
if ( dist > 1.0 ) { dist = 1.0; }
double bright = cos( dist * SGD_PI_2 );
if ( bright < 0.3 ) { bright = 0.3; }
env_map[i][j][0] = r;
env_map[i][j][1] = g;
env_map[i][j][2] = b;
env_map[i][j][3] = (int)(bright * alpha);
}
}
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glGenTextures( 1, &tex_name );
glBindTexture( GL_TEXTURE_2D, tex_name );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
return tex_name;
}
// generate standard colored directional light environment texture map
static int gen_taxiway_dir_light_map( int r, int g, int b, int alpha ) {
const int env_tex_res = 32;
int half_res = env_tex_res / 2;
unsigned char env_map[env_tex_res][env_tex_res][4];
GLuint tex_name;
for ( int i = 0; i < env_tex_res; ++i ) {
for ( int j = 0; j < env_tex_res; ++j ) {
double x = (i - half_res) / (double)half_res;
double y = (j - half_res) / (double)half_res;
double tmp = sqrt(x*x + y*y);
double dist = tmp * tmp;
if ( dist > 1.0 ) { dist = 1.0; }
double bright = sin( dist * SGD_PI_2 );
if ( bright < 0.2 ) { bright = 0.2; }
env_map[i][j][0] = r;
env_map[i][j][1] = g;
env_map[i][j][2] = b;
env_map[i][j][3] = (int)(bright * alpha);
}
}
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glGenTextures( 1, &tex_name );
glBindTexture( GL_TEXTURE_2D, tex_name );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
return tex_name;
}
// Load a library of material properties // Load a library of material properties
bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) { bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) {
@@ -192,13 +90,14 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char
for (int i = 0; i < nMaterials; i++) { for (int i = 0; i < nMaterials; i++) {
const SGPropertyNode * node = materials.getChild(i); const SGPropertyNode * node = materials.getChild(i);
if (!strcmp(node->getName(), "material")) { if (!strcmp(node->getName(), "material")) {
SGSharedPtr<SGMaterial> m = new SGMaterial( fg_root, node, season ); SGSharedPtr<SGMaterial> m = new SGMaterial(fg_root, node, season);
vector<SGPropertyNode_ptr>names = node->getChildren("name"); vector<SGPropertyNode_ptr>names = node->getChildren("name");
for ( unsigned int j = 0; j < names.size(); j++ ) { for ( unsigned int j = 0; j < names.size(); j++ ) {
string name = names[j]->getStringValue(); string name = names[j]->getStringValue();
// cerr << "Material " << name << endl; // cerr << "Material " << name << endl;
matlib[name] = m; matlib[name] = m;
m->add_name(name);
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material " SG_LOG( SG_TERRAIN, SG_INFO, " Loading material "
<< names[j]->getStringValue() ); << names[j]->getStringValue() );
} }
@@ -208,263 +107,6 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char
} }
} }
// hard coded ground light state
ssgSimpleState *gnd_lights = new ssgSimpleState;
gnd_lights->disable( GL_TEXTURE_2D );
gnd_lights->enable( GL_CULL_FACE );
gnd_lights->enable( GL_COLOR_MATERIAL );
gnd_lights->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
gnd_lights->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
gnd_lights->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
gnd_lights->enable( GL_BLEND );
gnd_lights->disable( GL_ALPHA_TEST );
gnd_lights->disable( GL_LIGHTING );
matlib["GROUND_LIGHTS"] = new SGMaterial( gnd_lights );
GLuint tex_name;
// hard coded runway white light state
tex_name = gen_standard_dir_light_map( 235, 235, 195, 255 );
ssgSimpleState *rwy_white_lights = new ssgSimpleState();
rwy_white_lights->disable( GL_LIGHTING );
rwy_white_lights->enable ( GL_CULL_FACE ) ;
rwy_white_lights->enable( GL_TEXTURE_2D );
rwy_white_lights->enable( GL_BLEND );
rwy_white_lights->enable( GL_ALPHA_TEST );
rwy_white_lights->enable( GL_COLOR_MATERIAL );
rwy_white_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_white_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_white_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_white_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_white_lights->setTexture( tex_name );
matlib["RWY_WHITE_LIGHTS"] = new SGMaterial( rwy_white_lights );
// For backwards compatibility ... remove someday
matlib["RUNWAY_LIGHTS"] = new SGMaterial( rwy_white_lights );
matlib["RWY_LIGHTS"] = new SGMaterial( rwy_white_lights );
// end of backwards compatitibilty
// hard coded runway medium intensity white light state
tex_name = gen_standard_dir_light_map( 235, 235, 195, 205 );
ssgSimpleState *rwy_white_medium_lights = new ssgSimpleState();
rwy_white_medium_lights->disable( GL_LIGHTING );
rwy_white_medium_lights->enable ( GL_CULL_FACE ) ;
rwy_white_medium_lights->enable( GL_TEXTURE_2D );
rwy_white_medium_lights->enable( GL_BLEND );
rwy_white_medium_lights->enable( GL_ALPHA_TEST );
rwy_white_medium_lights->enable( GL_COLOR_MATERIAL );
rwy_white_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_white_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_white_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_white_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_white_medium_lights->setTexture( tex_name );
matlib["RWY_WHITE_MEDIUM_LIGHTS"]
= new SGMaterial( rwy_white_medium_lights );
// hard coded runway low intensity white light state
tex_name = gen_standard_dir_light_map( 235, 235, 195, 155 );
ssgSimpleState *rwy_white_low_lights = new ssgSimpleState();
rwy_white_low_lights->disable( GL_LIGHTING );
rwy_white_low_lights->enable ( GL_CULL_FACE ) ;
rwy_white_low_lights->enable( GL_TEXTURE_2D );
rwy_white_low_lights->enable( GL_BLEND );
rwy_white_low_lights->enable( GL_ALPHA_TEST );
rwy_white_low_lights->enable( GL_COLOR_MATERIAL );
rwy_white_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_white_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_white_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_white_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_white_low_lights->setTexture( tex_name );
matlib["RWY_WHITE_LOW_LIGHTS"]
= new SGMaterial( rwy_white_low_lights );
// hard coded runway yellow light state
tex_name = gen_standard_dir_light_map( 235, 215, 20, 255 );
ssgSimpleState *rwy_yellow_lights = new ssgSimpleState();
rwy_yellow_lights->disable( GL_LIGHTING );
rwy_yellow_lights->enable ( GL_CULL_FACE ) ;
rwy_yellow_lights->enable( GL_TEXTURE_2D );
rwy_yellow_lights->enable( GL_BLEND );
rwy_yellow_lights->enable( GL_ALPHA_TEST );
rwy_yellow_lights->enable( GL_COLOR_MATERIAL );
rwy_yellow_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_yellow_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_yellow_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_yellow_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_yellow_lights->setTexture( tex_name );
matlib["RWY_YELLOW_LIGHTS"] = new SGMaterial( rwy_yellow_lights );
// hard coded runway medium intensity yellow light state
tex_name = gen_standard_dir_light_map( 235, 215, 20, 205 );
ssgSimpleState *rwy_yellow_medium_lights = new ssgSimpleState();
rwy_yellow_medium_lights->disable( GL_LIGHTING );
rwy_yellow_medium_lights->enable ( GL_CULL_FACE ) ;
rwy_yellow_medium_lights->enable( GL_TEXTURE_2D );
rwy_yellow_medium_lights->enable( GL_BLEND );
rwy_yellow_medium_lights->enable( GL_ALPHA_TEST );
rwy_yellow_medium_lights->enable( GL_COLOR_MATERIAL );
rwy_yellow_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_yellow_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_yellow_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_yellow_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_yellow_medium_lights->setTexture( tex_name );
matlib["RWY_YELLOW_MEDIUM_LIGHTS"]
= new SGMaterial( rwy_yellow_medium_lights );
// hard coded runway low intensity yellow light state
tex_name = gen_standard_dir_light_map( 235, 215, 20, 155 );
ssgSimpleState *rwy_yellow_low_lights = new ssgSimpleState();
rwy_yellow_low_lights->disable( GL_LIGHTING );
rwy_yellow_low_lights->enable ( GL_CULL_FACE ) ;
rwy_yellow_low_lights->enable( GL_TEXTURE_2D );
rwy_yellow_low_lights->enable( GL_BLEND );
rwy_yellow_low_lights->enable( GL_ALPHA_TEST );
rwy_yellow_low_lights->enable( GL_COLOR_MATERIAL );
rwy_yellow_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_yellow_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_yellow_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_yellow_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_yellow_low_lights->setTexture( tex_name );
matlib["RWY_YELLOW_LOW_LIGHTS"]
= new SGMaterial( rwy_yellow_low_lights );
// hard coded runway red light state
tex_name = gen_standard_dir_light_map( 235, 90, 90, 255 );
ssgSimpleState *rwy_red_lights = new ssgSimpleState();
rwy_red_lights->disable( GL_LIGHTING );
rwy_red_lights->enable ( GL_CULL_FACE ) ;
rwy_red_lights->enable( GL_TEXTURE_2D );
rwy_red_lights->enable( GL_BLEND );
rwy_red_lights->enable( GL_ALPHA_TEST );
rwy_red_lights->enable( GL_COLOR_MATERIAL );
rwy_red_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_red_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_red_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_red_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_red_lights->setTexture( tex_name );
matlib["RWY_RED_LIGHTS"]
= new SGMaterial( rwy_red_lights );
// hard coded medium intensity runway red light state
tex_name = gen_standard_dir_light_map( 235, 90, 90, 205 );
ssgSimpleState *rwy_red_medium_lights = new ssgSimpleState();
rwy_red_medium_lights->disable( GL_LIGHTING );
rwy_red_medium_lights->enable ( GL_CULL_FACE ) ;
rwy_red_medium_lights->enable( GL_TEXTURE_2D );
rwy_red_medium_lights->enable( GL_BLEND );
rwy_red_medium_lights->enable( GL_ALPHA_TEST );
rwy_red_medium_lights->enable( GL_COLOR_MATERIAL );
rwy_red_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_red_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_red_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_red_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_red_medium_lights->setTexture( tex_name );
matlib["RWY_RED_MEDIUM_LIGHTS"]
= new SGMaterial( rwy_red_medium_lights );
// hard coded low intensity runway red light state
tex_name = gen_standard_dir_light_map( 235, 90, 90, 155 );
ssgSimpleState *rwy_red_low_lights = new ssgSimpleState();
rwy_red_low_lights->disable( GL_LIGHTING );
rwy_red_low_lights->enable ( GL_CULL_FACE ) ;
rwy_red_low_lights->enable( GL_TEXTURE_2D );
rwy_red_low_lights->enable( GL_BLEND );
rwy_red_low_lights->enable( GL_ALPHA_TEST );
rwy_red_low_lights->enable( GL_COLOR_MATERIAL );
rwy_red_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_red_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_red_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_red_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_red_low_lights->setTexture( tex_name );
matlib["RWY_RED_LOW_LIGHTS"]
= new SGMaterial( rwy_red_low_lights );
// hard coded runway green light state
tex_name = gen_standard_dir_light_map( 20, 235, 20, 255 );
ssgSimpleState *rwy_green_lights = new ssgSimpleState();
rwy_green_lights->disable( GL_LIGHTING );
rwy_green_lights->enable ( GL_CULL_FACE ) ;
rwy_green_lights->enable( GL_TEXTURE_2D );
rwy_green_lights->enable( GL_BLEND );
rwy_green_lights->enable( GL_ALPHA_TEST );
rwy_green_lights->enable( GL_COLOR_MATERIAL );
rwy_green_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_green_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_green_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_green_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_green_lights->setTexture( tex_name );
matlib["RWY_GREEN_LIGHTS"]
= new SGMaterial( rwy_green_lights );
// hard coded medium intensity runway green light state
tex_name = gen_standard_dir_light_map( 20, 235, 20, 205 );
ssgSimpleState *rwy_green_medium_lights = new ssgSimpleState();
rwy_green_medium_lights->disable( GL_LIGHTING );
rwy_green_medium_lights->enable ( GL_CULL_FACE ) ;
rwy_green_medium_lights->enable( GL_TEXTURE_2D );
rwy_green_medium_lights->enable( GL_BLEND );
rwy_green_medium_lights->enable( GL_ALPHA_TEST );
rwy_green_medium_lights->enable( GL_COLOR_MATERIAL );
rwy_green_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_green_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_green_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_green_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_green_medium_lights->setTexture( tex_name );
matlib["RWY_GREEN_MEDIUM_LIGHTS"]
= new SGMaterial( rwy_green_medium_lights );
// hard coded low intensity runway green light state
tex_name = gen_standard_dir_light_map( 20, 235, 20, 155 );
ssgSimpleState *rwy_green_low_lights = new ssgSimpleState();
rwy_green_low_lights->disable( GL_LIGHTING );
rwy_green_low_lights->enable ( GL_CULL_FACE ) ;
rwy_green_low_lights->enable( GL_TEXTURE_2D );
rwy_green_low_lights->enable( GL_BLEND );
rwy_green_low_lights->enable( GL_ALPHA_TEST );
rwy_green_low_lights->enable( GL_COLOR_MATERIAL );
rwy_green_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_green_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_green_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_green_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
rwy_green_low_lights->setTexture( tex_name );
matlib["RWY_GREEN_LOW_LIGHTS"]
= new SGMaterial( rwy_green_low_lights );
matlib["RWY_GREEN_TAXIWAY_LIGHTS"]
= new SGMaterial( rwy_green_low_lights );
// hard coded low intensity taxiway blue light state
tex_name = gen_taxiway_dir_light_map( 90, 90, 235, 205 );
ssgSimpleState *taxiway_blue_low_lights = new ssgSimpleState();
taxiway_blue_low_lights->disable( GL_LIGHTING );
taxiway_blue_low_lights->enable ( GL_CULL_FACE ) ;
taxiway_blue_low_lights->enable( GL_TEXTURE_2D );
taxiway_blue_low_lights->enable( GL_BLEND );
taxiway_blue_low_lights->enable( GL_ALPHA_TEST );
taxiway_blue_low_lights->enable( GL_COLOR_MATERIAL );
taxiway_blue_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
taxiway_blue_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
taxiway_blue_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
taxiway_blue_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
taxiway_blue_low_lights->setTexture( tex_name );
matlib["RWY_BLUE_TAXIWAY_LIGHTS"]
= new SGMaterial( taxiway_blue_low_lights );
// hard coded runway vasi light state
tex_name = gen_standard_dir_light_map( 235, 235, 195, 255 );
ssgSimpleState *rwy_vasi_lights = new ssgSimpleState();
rwy_vasi_lights->disable( GL_LIGHTING );
rwy_vasi_lights->enable ( GL_CULL_FACE ) ;
rwy_vasi_lights->enable( GL_TEXTURE_2D );
rwy_vasi_lights->enable( GL_BLEND );
rwy_vasi_lights->enable( GL_ALPHA_TEST );
rwy_vasi_lights->enable( GL_COLOR_MATERIAL );
rwy_vasi_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
rwy_vasi_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
rwy_vasi_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
rwy_vasi_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
// rwy_vasi_lights->setTexture( gen_vasi_light_map_old() );
rwy_vasi_lights->setTexture( tex_name );
matlib["RWY_VASI_LIGHTS"] = new SGMaterial( rwy_vasi_lights );
return true; return true;
} }
@@ -491,18 +133,20 @@ bool SGMaterialLib::add_item ( const string &mat_name, const string &full_path )
<< mat_name << " (" << full_path << ")"); << mat_name << " (" << full_path << ")");
matlib[mat_name] = new SGMaterial( full_path ); matlib[mat_name] = new SGMaterial( full_path );
matlib[mat_name]->add_name(mat_name);
return true; return true;
} }
// Load a library of material properties // Load a library of material properties
bool SGMaterialLib::add_item ( const string &mat_name, ssgSimpleState *state ) bool SGMaterialLib::add_item ( const string &mat_name, osg::StateSet *state )
{ {
matlib[mat_name] = new SGMaterial( state ); matlib[mat_name] = new SGMaterial( state );
matlib[mat_name]->add_name(mat_name);
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material given a premade " SG_LOG( SG_TERRAIN, SG_INFO, " Loading material given a premade "
<< "ssgSimpleState = " << mat_name ); << "osg::StateSet = " << mat_name );
return true; return true;
} }
@@ -538,3 +182,21 @@ void SGMaterialLib::load_next_deferred() {
return; return;
} }
} }
const SGMaterial*
SGMaterialLib::findMaterial(const osg::StateSet* stateSet) const
{
if (!stateSet)
return 0;
const osg::Referenced* base = stateSet->getUserData();
if (!base)
return 0;
const SGMaterialUserData* matUserData
= dynamic_cast<const SGMaterialUserData*>(base);
if (!matUserData)
return 0;
return matUserData->getMaterial();
}

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