Compare commits

...

166 Commits

Author SHA1 Message Date
mfranz
46a32dd3ee coding style fixes 2007-07-22 13:58:26 +00:00
mfranz
ecb4dc57b4 Maik JUSTUS: workaround for broken Doppler effect in OpenAL
mf: this patch is meant to be removed as soon as OpenAL got fixed. (The
    OpenAL developers acknowleged the bug and announced that it'll get
    fixed.) For removal try
    $ cd simgear/sound
    $ cvs diff -rAFTER_OPENAL_DOPPLER_WORKAROUND -rBEFORE_OPENAL_DOPPLER_WORKAROUND|patch
2007-07-22 13:50:24 +00:00
mfranz
89d426470b Maik JUSTUS: Doppler fixes (add option to turn off Doppler for sounds that
shouldn't be affected -- marker beep, ATIS messages, etc.)

mf: this is the first part of the original patch. It is supposed to contain
    fixes that are not caused by OpenAL bugs, and thus aren't meant to be
    reverted later. The second part will contain a temprary workaround for
    OpenAL bugs. Unfortunately, I had to do the split myself as the contributor
    refused to do it.
2007-07-22 13:33:23 +00:00
mfranz
23c7a1b5b7 - close loophole through which one could sneak in illegal property names
containing slashes, colons and all sorts of evil characters. In Nasal
  this could be done via props.globals.getChild("1!@#$//[]{}", 0, 1).setValue(0);
  The cause is that getChild() hands the given name directly over to an
  alternative SGPropertyNode ("convenience") constructor which sets the
  name without any checks.
- unify exception messages: first character is lower case
2007-07-17 14:52:51 +00:00
frohlich
3b21e9434f Modified Files:
simgear/route/route.hxx: Remove unused include.
2007-07-08 08:43:40 +00:00
frohlich
d4a4428e64 Modified Files:
simgear/route/waypoint.hxx simgear/route/waypoint.cxx: Use const
	refs where possible.
2007-07-08 08:43:15 +00:00
mfranz
2dfc057135 replace exit() by throw sg_exception(). Of course, we have to be aware
that interdependencies between sg libs are generally unwelcome, but
sg_exception is a rather basic part, and it's already used by xml, props,
scene, sound and, of course, structure. Since props and xml are core
libs, we can assume that sg_exceptions are available.  (OK'ed by Curt)
2007-07-02 15:42:19 +00:00
mfranz
a25eebef9b add SG_ORIGIN macro that expands to a string __FILE__":"__LINE__
Note that __LINE__ is a number and can't be directly used in string
context, which makes the macro worthwhile. (IMHO :-)
2007-07-02 12:55:10 +00:00
mfranz
741c4ca15a back out last changes (radar patch) 2007-06-29 22:45:37 +00:00
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:🪣:erase()
- remove bad code from hash_table:🪣: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
208 changed files with 16677 additions and 9613 deletions

View File

@@ -2,10 +2,9 @@ EXTRA_DIST = \
acinclude.m4 \
autogen.sh \
DoxygenMain.cxx \
project/VC8 \
README.MSVC \
README.zlib \
projects \
projects \
SimGear.dsp \
SimGear.dsw

View File

@@ -556,21 +556,6 @@ SOURCE=.\simgear\math\vector.cxx
# End 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
!IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1184,21 +1169,6 @@ SOURCE=.\simgear\scene\model\animation.cxx
# End Source File
# Begin Source File
SOURCE=.\simgear\scene\model\custtrans.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
# PROP Intermediate_Dir "Release\Lib_sgmodel"
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
# PROP Intermediate_Dir "Debug\Lib_sgmodel"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\simgear\scene\model\location.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1244,7 +1214,7 @@ SOURCE=.\simgear\scene\model\modellib.cxx
# End Source File
# Begin Source File
SOURCE=.\simgear\scene\model\personality.cxx
SOURCE=.\simgear\scene\model\persparam.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1289,7 +1259,7 @@ SOURCE=.\simgear\scene\model\placementtrans.cxx
# End Source File
# Begin Source File
SOURCE=.\simgear\scene\model\shadowvolume.cxx
SOURCE=.\simgear\scene\model\shadanim.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1304,7 +1274,7 @@ SOURCE=.\simgear\scene\model\shadowvolume.cxx
# End Source File
# Begin Source File
SOURCE=.\simgear\scene\model\shadanim.cxx
SOURCE=.\simgear\scene\model\SGMaterialAnimation.cxx
!IF "$(CFG)" == "SimGear - Win32 Release"
@@ -1549,6 +1519,40 @@ SOURCE=.\simgear\scene\tgdb\userdata.cxx
!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 Group
# Begin Group "Lib_sgscreen"
@@ -1805,6 +1809,36 @@ SOURCE=.\simgear\structure\subsystem_mgr.cxx
!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 Group
# Begin Group "Lib_sgtiming"

21
Thanks
View File

@@ -47,6 +47,18 @@ Jean-Francois Doue
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>
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
Maik Justus
Fixed an old bug in the SGPropertyNode class.
Richard Kaszeta <bofh@me.umn.edu>
Contributed screen buffer to ppm screen shot routine.
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
Tim Moore
Ported the (chrome) "shader" animation to OSG, and helped with porting
the "material" animation.
Curt Olson http://www.flightgear.org/~curt/
Curt is responsible for overall project and source code management.
He has his hands in many of the areas.

View File

@@ -119,6 +119,14 @@ if test "x$with_plib" != "x" ; then
EXTRA_DIRS="${EXTRA_DIRS} $with_plib"
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
case "${host}" in
*-apple-darwin* | *-*-cygwin* | *-*-mingw32*)
@@ -430,6 +438,7 @@ AC_CONFIG_FILES([ \
simgear/scene/model/Makefile \
simgear/scene/sky/Makefile \
simgear/scene/tgdb/Makefile \
simgear/scene/util/Makefile \
simgear/screen/Makefile \
simgear/serial/Makefile \
simgear/sound/Makefile \

4
projects/VC7.1/.cvsignore Executable file
View File

@@ -0,0 +1,4 @@
Debug
Release
SimGear.ncb
SimGear.suo

21
projects/VC7.1/SimGear.sln Executable file
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
projects/VC7.1/SimGear.vcproj Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -41,11 +41,11 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../devel/include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
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"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
@@ -103,11 +103,11 @@
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../devel/include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
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"
MinimalRebuild="true"
RuntimeLibrary="0"
RuntimeLibrary="2"
FloatingPointModel="2"
UsePrecompiledHeader="0"
WarningLevel="3"
@@ -215,10 +215,6 @@
RelativePath="..\..\simgear\magvar\coremag.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\custtrans.hxx"
>
</File>
<File
RelativePath="..\..\simgear\nasal\data.h"
>
@@ -507,10 +503,26 @@
RelativePath="..\..\simgear\math\sg_types.hxx"
>
</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
RelativePath="..\..\simgear\math\SGGeoc.hxx"
>
@@ -531,6 +543,10 @@
RelativePath="..\..\simgear\math\SGLimits.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGMaterialAnimation.hxx"
>
</File>
<File
RelativePath="..\..\simgear\math\SGMath.hxx"
>
@@ -547,6 +563,18 @@
RelativePath="..\..\simgear\math\SGMisc.hxx"
>
</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
RelativePath="..\..\simgear\math\SGQuat.hxx"
>
@@ -559,18 +587,54 @@
RelativePath="..\..\simgear\structure\SGReferenced.hxx"
>
</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
RelativePath="..\..\simgear\structure\SGSharedPtr.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGStateAttributeVisitor.hxx"
>
</File>
<File
RelativePath="..\..\simgear\misc\sgstream.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.hxx"
>
</File>
<File
RelativePath="..\..\simgear\threads\SGThread.hxx"
>
</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
RelativePath="..\..\simgear\math\SGVec3.hxx"
>
@@ -587,20 +651,6 @@
RelativePath="..\..\simgear\scene\model\shadowvolume.hxx"
>
</File>
<File
RelativePath="..\..\simgear\simgear_config.h"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCustomBuildTool"
Description=""
CommandLine=""
Outputs=""
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\simgear\scene\sky\sky.hxx"
>
@@ -765,6 +815,10 @@
RelativePath="..\..\simgear\scene\sky\bbcache.cxx"
>
</File>
<File
RelativePath="..\..\simgear\nasal\bitslib.c"
>
</File>
<File
RelativePath="..\..\simgear\ephemeris\celestialBody.cxx"
>
@@ -797,10 +851,6 @@
RelativePath="..\..\simgear\magvar\coremag.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\custtrans.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\sky\dome.cxx"
>
@@ -858,11 +908,11 @@
>
</File>
<File
RelativePath="..\..\simgear\ephemeris\jupiter.cxx"
RelativePath="..\..\simgear\nasal\iolib.c"
>
</File>
<File
RelativePath="..\..\simgear\scene\tgdb\leaf.cxx"
RelativePath="..\..\simgear\ephemeris\jupiter.cxx"
>
</File>
<File
@@ -969,10 +1019,6 @@
RelativePath="..\..\simgear\nasal\parse.c"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\personality.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\persparam.cxx"
>
@@ -1061,18 +1107,70 @@
RelativePath="..\..\simgear\timing\sg_time.cxx"
>
</File>
<File
RelativePath="..\..\simgear\structure\SGBinding.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGEnlargeBoundingBox.cxx"
>
</File>
<File
RelativePath="..\..\simgear\math\SGGeodesy.cxx"
>
</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
RelativePath="..\..\simgear\misc\sgstream.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.cxx"
>
</File>
<File
RelativePath="..\..\simgear\threads\SGThread.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGTranslateTransform.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\tgdb\SGVasiDrawable.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\shadanim.cxx"
>
@@ -1081,10 +1179,6 @@
RelativePath="..\..\simgear\screen\shader.cpp"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\shadowvolume.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\sky\sky.cxx"
>
@@ -1141,6 +1235,10 @@
RelativePath="..\..\simgear\nasal\thread-win32.c"
>
</File>
<File
RelativePath="..\..\simgear\nasal\threadlib.c"
>
</File>
<File
RelativePath="..\..\simgear\timing\timestamp.cxx"
>
@@ -1161,6 +1259,10 @@
RelativePath="..\..\simgear\scene\tgdb\userdata.cxx"
>
</File>
<File
RelativePath="..\..\simgear\nasal\utf8lib.c"
>
</File>
<File
RelativePath="..\..\simgear\nasal\vector.c"
>
@@ -1218,6 +1320,28 @@
>
</File>
</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>
<Globals>
</Globals>

View File

@@ -7,7 +7,7 @@ endif
# METAR_DIRS =
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 = \
compiler.h constants.h sg_inlines.h sg_traits.hxx version.h
@@ -34,4 +34,4 @@ SUBDIRS = \
$(SGTHREAD_DIR) \
timing
DIST_SUBDIRS = $(SUBDIRS) compatibility threads
DIST_SUBDIRS = $(SUBDIRS) compatibility

View File

@@ -44,6 +44,9 @@ SGBucket::SGBucket(const double dlon, const double dlat) {
set_bucket(dlon, dlat);
}
SGBucket::SGBucket(const SGGeod& geod) {
set_bucket(geod);
}
// create an impossible bucket if false
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
void SGBucket::set_bucket( double *lonlat ) {
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
string SGBucket::gen_base_path() const {
// long int index;

View File

@@ -31,6 +31,7 @@
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/math/SGMath.hxx>
#ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
@@ -133,6 +134,13 @@ public:
*/
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.
* @param is_good if false, create an invalid bucket. This is
* useful * if you are comparing cur_bucket to last_bucket and
@@ -146,11 +154,6 @@ public:
*/
SGBucket(const long int bindex);
/**
* Default destructor.
*/
~SGBucket();
/**
* Reset a bucket to represent a new lat and lon
* @param dlon longitude specified in degrees
@@ -165,6 +168,13 @@ public:
*/
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.
* 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.
*/
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.
/**

View File

@@ -230,6 +230,7 @@
# define isnan _isnan
# define snprintf _snprintf
# define copysign _copysign
# pragma warning(disable: 4786) // identifier was truncated to '255' characters
# pragma warning(disable: 4244) // conversion from double to float

View File

@@ -322,6 +322,9 @@ sglog()
# define SG_LOG(C,P,M) sglog() << loglevel(C,P) << M << endl
#endif
#define SG_STRINGIFY(x) #x
#define SG_TOSTRING(x) SG_STRINGIFY(x)
#define SG_ORIGIN __FILE__ ":" SG_TOSTRING(__LINE__)
#endif // _LOGSTREAM_H

View File

@@ -747,6 +747,14 @@ bool SGMetar::scanSkyCondition()
int i;
SGMetarCloud cl;
if (!strncmp(m, "//////", 6)) {
m += 6;
if (!scanBoundary(&m))
return false;
_m = m;
return true;
}
if (!strncmp(m, "CLR", i = 3) // clear
|| !strncmp(m, "SKC", i = 3) // sky clear
|| !strncmp(m, "NSC", i = 3) // no significant clouds
@@ -836,7 +844,7 @@ bool SGMetar::scanTemperature()
return false;
if (!scanBoundary(&m)) {
if (!strncmp(m, "XX", 2)) // not spec compliant!
m += 2, sign = 0;
m += 2, sign = 0, dew = temp;
else {
sign = 1;
if (*m == 'M')

View File

@@ -189,6 +189,8 @@ SGEnviro::SGEnviro() :
}
SGEnviro::~SGEnviro(void) {
// OSGFIXME
return;
list_of_lightning::iterator iLightning;
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
delete (*iLightning);
@@ -197,6 +199,8 @@ SGEnviro::~SGEnviro(void) {
}
void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) {
// OSGFIXME
return;
view_in_cloud = false;
// ask the impostor cache to do some cleanup
if(SGNewCloud::cldCache)
@@ -319,6 +323,8 @@ void SGEnviro::set_lightning_enable_state(bool enable) {
}
void SGEnviro::setLight(sgVec4 adj_fog_color) {
// OSGFIXME
return;
sgCopyVec4( fog_color, adj_fog_color );
if( false ) {
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
@@ -397,6 +403,7 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
LWC = 0.29*2.0;
break;
}
// add to the list for the wxRadar instrument
if( LWC > 0.0 )
radarEcho.push_back( SGWxRadarEcho ( heading, alt, radius, dist, LWC, false, cloudId ) );
@@ -440,6 +447,8 @@ list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
// precipitation rendering code
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
// OSGFIXME
return;
sgVec3 light;
sgAddVec3( light, fog_color, min_light );
float da = SG_PI * 2.0f / (float) slices;
@@ -488,6 +497,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) {
// OSGFIXME
return;
#if 0
static int debug_period = 0;
@@ -557,6 +568,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) {
// OSGFIXME
return;
if( precipitation_enable_state && rain_norm > 0.0)
if( precipitation_max_alt >= last_alt )
drawRain(pitch, roll, heading, hspeed, rain_norm);
@@ -579,6 +592,8 @@ SGLightning::~SGLightning() {
// lightning rendering code
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
// OSGFIXME
return;
sgVec3 dir, newdir;
int nseg = 0;
@@ -626,6 +641,8 @@ void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy
}
void SGLightning::lt_build(void) {
// OSGFIXME
return;
Point3D top;
nb_tree = 0;
top[PX] = 0 ;
@@ -651,6 +668,8 @@ void SGLightning::lt_build(void) {
void SGLightning::lt_Render(void) {
// OSGFIXME
return;
float flash = 0.5;
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
flash = sg_random() * 0.75f + 0.25f;
@@ -675,10 +694,12 @@ void SGLightning::lt_Render(void) {
glDisable( GL_FOG );
glPushMatrix();
sgMat4 modelview, tmp;
ssgGetModelviewMatrix( modelview );
// OSGFIXME
// ssgGetModelviewMatrix( modelview );
sgCopyMat4( tmp, sgEnviro.transform );
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 dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
@@ -736,6 +757,8 @@ void SGLightning::lt_Render(void) {
}
void SGEnviro::addLightning(double lon, double lat, double alt) {
// OSGFIXME
return;
if( lightnings.size() > 10)
return;
SGLightning *lt= new SGLightning(lon, lat, alt);
@@ -743,6 +766,8 @@ void SGEnviro::addLightning(double lon, double lat, double alt) {
}
void SGEnviro::drawLightning(void) {
// OSGFIXME
return;
list_of_lightning::iterator iLightning;
// play 'thunder' for lightning
if( snd_active )

View File

@@ -40,7 +40,8 @@ class SGSoundMgr;
*/
class SGWxRadarEcho {
public:
SGWxRadarEcho(float _heading, float _alt, float _radius, float _dist, double _LWC, bool _lightning, int _cloudId) :
SGWxRadarEcho(float _heading, float _alt, float _radius, float _dist,
double _LWC, bool _lightning, int _cloudId ) :
heading( _heading ),
alt ( _alt ),
radius ( _radius ),
@@ -56,7 +57,7 @@ public:
/** reflectivity converted to liquid water content. */
double LWC;
/** if true then this data is for a lightning else it is for water echo. */
bool lightning;
bool lightning;
/** Unique identifier of cloud */
int cloudId;
};

View File

@@ -31,7 +31,7 @@
// Constructor
SGEphemeris::SGEphemeris( const string &path ) {
SGEphemeris::SGEphemeris( const std::string &path ) {
our_sun = new Star;
moon = new MoonPos;
mercury = new Mercury;
@@ -42,9 +42,8 @@ SGEphemeris::SGEphemeris( const string &path ) {
uranus = new Uranus;
neptune = new Neptune;
nplanets = 7;
for ( int i = 0; i < nplanets; ++i ) {
sgdSetVec3( planets[i], 0.0, 0.0, 0.0 );
}
for ( int i = 0; i < nplanets; ++i )
planets[i] = SGVec3d::zeros();
stars = new SGStarData( SGPath(path) );
}

View File

@@ -29,8 +29,7 @@
#ifndef _EPHEMERIS_HXX
#define _EPHEMERIS_HXX
#include <plib/sg.h>
#include <string>
#include <simgear/ephemeris/star.hxx>
#include <simgear/ephemeris/moonpos.hxx>
@@ -43,6 +42,9 @@
#include <simgear/ephemeris/neptune.hxx>
#include <simgear/ephemeris/stardata.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/misc/sg_path.hxx>
/** Ephemeris class
*
@@ -83,7 +85,7 @@ class SGEphemeris {
// planets[i][1] = Declination
// planets[i][2] = Magnitude
int nplanets;
sgdVec3 planets[7];
SGVec3d planets[7];
SGStarData *stars;
@@ -95,7 +97,7 @@ public:
* calling the constructor you need to provide a path pointing to
* your star database file.
* @param path path to your star database */
SGEphemeris( const string &path );
SGEphemeris( const std::string &path );
/** Destructor */
~SGEphemeris( void );
@@ -155,7 +157,7 @@ public:
* the second is the declination, and the third is the magnitude.
* @return planets array
*/
inline sgdVec3 *getPlanets() { return planets; }
inline SGVec3d *getPlanets() { return planets; }
/** @return the numbers of defined stars. */
inline int getNumStars() const { return stars->getNumStars(); }
@@ -167,7 +169,7 @@ public:
* third is the magnitude.
* @returns star array
*/
inline sgdVec3 *getStars() { return stars->getStars(); }
inline SGVec3d *getStars() { return stars->getStars(); }
};

View File

@@ -25,6 +25,7 @@
#endif
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sgstream.hxx>
#include "stardata.hxx"
@@ -34,16 +35,9 @@
#endif
// Constructor
SGStarData::SGStarData() :
nstars(0)
SGStarData::SGStarData( const SGPath& path )
{
}
SGStarData::SGStarData( SGPath path ) :
nstars(0)
{
data_path = SGPath( path );
load();
load(path);
}
@@ -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
// array, problem for some compilers
stars = new sgdVec3[SG_MAX_STARS];
_stars.clear();
// build the full path name to the stars data base file
data_path.append( "stars" );
SG_LOG( SG_ASTRO, SG_INFO, " Loading stars from " << data_path.str() );
// build the full path name to the stars data base file
SGPath tmp = path;
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() ) {
SG_LOG( SG_ASTRO, SG_ALERT, "Cannot open star file: "
<< data_path.str() );
exit(-1);
<< tmp.str() );
return false;
}
double ra, dec, mag;
char c;
string name;
nstars = 0;
// read in each line of the file
while ( ! in.eof() && nstars < SG_MAX_STARS ) {
while ( ! in.eof() ) {
in >> skipcomment;
getline( in, name, ',' );
@@ -116,13 +107,10 @@ bool SGStarData::load() {
in >> mag;
// cout << " star data = " << ra << " " << dec << " " << mag << endl;
sgdSetVec3( stars[nstars], ra, dec, mag );
++nstars;
_stars.push_back(SGVec3d(ra, dec, mag));
}
SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << nstars << " stars" );
SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << _stars.size() << " stars" );
return true;
}

View File

@@ -24,37 +24,28 @@
#ifndef _SG_STARDATA_HXX
#define _SG_STARDATA_HXX
#include <vector>
#include <simgear/math/SGMath.hxx>
#include <plib/sg.h>
#include <simgear/misc/sg_path.hxx>
#define SG_MAX_STARS 850
class SGPath;
class SGStarData {
int nstars;
sgdVec3 *stars;
SGPath data_path;
public:
// Constructor
SGStarData();
SGStarData( SGPath path );
SGStarData( const SGPath& path );
// Destructor
~SGStarData();
// load the stars database
bool load();
bool load( const SGPath& path );
// stars
inline int getNumStars() const { return nstars; }
inline sgdVec3 *getStars() { return stars; }
inline int getNumStars() const { return _stars.size(); }
inline SGVec3d *getStars() { return &(_stars[0]); }
private:
std::vector<SGVec3d> _stars;
};

View File

@@ -37,14 +37,14 @@ int main( int argc, char **argv ) {
obj.get_gbs_radius());
cout << endl;
point_list nodes = obj.get_wgs84_nodes();
std::vector<SGVec3d> nodes = obj.get_wgs84_nodes();
cout << "# vertex list" << endl;
for ( i = 0; i < (int)nodes.size(); ++i ) {
printf("v %.5f %.5f %.5f\n", nodes[i].x(), nodes[i].y(), nodes[i].z() );
}
cout << endl;
point_list normals = obj.get_normals();
std::vector<SGVec3f> normals = obj.get_normals();
cout << "# vertex normal list" << endl;
for ( i = 0; i < (int)normals.size(); ++i ) {
printf("vn %.5f %.5f %.5f\n",
@@ -52,7 +52,7 @@ int main( int argc, char **argv ) {
}
cout << endl;
point_list texcoords = obj.get_texcoords();
std::vector<SGVec2f> texcoords = obj.get_texcoords();
cout << "# texture coordinate list" << endl;
for ( i = 0; i < (int)texcoords.size(); ++i ) {
printf("vt %.5f %.5f\n",

View File

@@ -174,7 +174,7 @@ static void read_object( gzFile fp,
int idx_size;
bool do_vertices, do_normals, do_colors, do_texcoords;
int j, k, idx;
static sgSimpleBuffer buf( 32768 ); // 32 Kb
sgSimpleBuffer buf( 32768 ); // 32 Kb
char material[256];
// default values
@@ -280,13 +280,13 @@ static void read_object( gzFile fp,
// read a binary file and populate the provided structures.
bool SGBinObject::read_bin( const string& file ) {
Point3D p;
SGVec3d p;
int i, j, k;
unsigned int nbytes;
static sgSimpleBuffer buf( 32768 ); // 32 Kb
sgSimpleBuffer buf( 32768 ); // 32 Kb
// zero out structures
gbs_center = Point3D( 0 );
gbs_center = SGVec3d(0, 0, 0);
gbs_radius = 0.0;
wgs84_nodes.clear();
@@ -322,7 +322,7 @@ bool SGBinObject::read_bin( const string& file ) {
string filegz = file + ".gz";
if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) {
SG_LOG( SG_EVENT, SG_ALERT,
"ERROR: opening " << file << " or " << filegz << "for reading!");
"ERROR: opening " << file << " or " << filegz << " for reading!");
return false;
}
@@ -407,7 +407,7 @@ bool SGBinObject::read_bin( const string& file ) {
sgEndianSwap( (uint64_t *)&(dptr[1]) );
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;
ptr += sizeof(double) * 3;
@@ -447,7 +447,7 @@ bool SGBinObject::read_bin( const string& file ) {
sgEndianSwap( (uint32_t *)&(fptr[1]) );
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;
}
}
@@ -481,7 +481,8 @@ bool SGBinObject::read_bin( const string& file ) {
sgEndianSwap( (uint32_t *)&(fptr[2]) );
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;
}
}
@@ -508,14 +509,11 @@ bool SGBinObject::read_bin( const string& file ) {
int count = nbytes / 3;
normals.reserve( count );
for ( k = 0; k < count; ++k ) {
sgdVec3 normal;
sgdSetVec3( normal,
(ptr[0]) / 127.5 - 1.0,
(ptr[1]) / 127.5 - 1.0,
(ptr[2]) / 127.5 - 1.0 );
sgdNormalizeVec3( normal );
SGVec3f normal((ptr[0]) / 127.5 - 1.0,
(ptr[1]) / 127.5 - 1.0,
(ptr[2]) / 127.5 - 1.0);
normals.push_back(Point3D(normal[0], normal[1], normal[2]));
normals.push_back(normalize(normal));
ptr += 3;
}
}
@@ -547,7 +545,7 @@ bool SGBinObject::read_bin( const string& file ) {
sgEndianSwap( (uint32_t *)&(fptr[0]) );
sgEndianSwap( (uint32_t *)&(fptr[1]) );
}
texcoords.push_back( Point3D( fptr[0], fptr[1], 0 ) );
texcoords.push_back( SGVec2f( fptr[0], fptr[1] ) );
fptr += 2;
}
}
@@ -612,10 +610,6 @@ bool SGBinObject::read_bin( const string& file ) {
bool SGBinObject::write_bin( const string& base, const string& name,
const SGBucket& b )
{
Point3D p;
sgVec2 t;
sgVec3 pt;
sgVec4 color;
int i, j;
unsigned char idx_mask;
int idx_size;
@@ -738,9 +732,8 @@ bool SGBinObject::write_bin( const string& base, const string& name,
sgWriteShort( fp, 1 ); // nelements
sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
p = wgs84_nodes[i] - gbs_center;
sgSetVec3( pt, p.x(), p.y(), p.z() );
sgWriteVec3( fp, pt );
SGVec3f p = toVec3f(wgs84_nodes[i] - gbs_center);
sgWriteVec3( fp, p.data() );
}
// dump vertex color list
@@ -749,12 +742,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
sgWriteShort( fp, 1 ); // nelements
sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes
for ( i = 0; i < (int)colors.size(); ++i ) {
p = colors[i];
// 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 );
sgWriteVec4( fp, colors[i].data() );
}
// dump vertex normal list
@@ -764,7 +752,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
sgWriteUInt( fp, normals.size() * 3 ); // nbytes
char normal[3];
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[1] = (unsigned char)((p.y() + 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
sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes
for ( i = 0; i < (int)texcoords.size(); ++i ) {
p = texcoords[i];
sgSetVec2( t, p.x(), p.y() );
sgWriteVec2( fp, t );
sgWriteVec2( fp, texcoords[i].data() );
}
// 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,
const SGBucket& b )
{
Point3D p;
int i, j;
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
fprintf(fp, "# vertex list\n");
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() );
}
@@ -1092,7 +1077,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
fprintf(fp, "# vertex normal list\n");
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, "\n");
@@ -1100,7 +1085,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
// dump texture coordinates
fprintf(fp, "# texture coordinate list\n");
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, "\n");
@@ -1126,13 +1111,13 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
// make a list of points for the group
point_list group_nodes;
group_nodes.clear();
Point3D bs_center;
SGVec3d bs_center;
double bs_radius = 0;
for ( i = start; i < end; ++i ) {
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
group_nodes.push_back( wgs84_nodes[ tris_v[i][j] ] );
bs_center = sgCalcCenter( group_nodes );
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ tris_v[i][j] ]) );
bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
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
point_list group_nodes;
group_nodes.clear();
Point3D bs_center;
SGVec3d bs_center;
double bs_radius = 0;
for ( i = start; i < end; ++i ) {
for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
group_nodes.push_back( wgs84_nodes[ strips_v[i][j] ] );
bs_center = sgCalcCenter( group_nodes );
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ strips_v[i][j] ]) );
bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
bs_radius = sgCalcBoundingRadius( Point3D::fromSGVec3(bs_center), group_nodes );
}
}

View File

@@ -89,13 +89,13 @@ typedef group_list::const_iterator const_group_list_iterator;
class SGBinObject {
unsigned short version;
Point3D gbs_center;
SGVec3d gbs_center;
float gbs_radius;
point_list wgs84_nodes; // vertex list
point_list colors; // color list
point_list normals; // normal list
point_list texcoords; // texture coordinate list
std::vector<SGVec3d> wgs84_nodes; // vertex list
std::vector<SGVec4f> colors; // color list
std::vector<SGVec3f> normals; // normal list
std::vector<SGVec2f> texcoords; // texture coordinate list
group_list pts_v; // points vertex index
group_list pts_n; // points normal index
@@ -125,23 +125,51 @@ public:
inline unsigned short get_version() const { return version; }
inline const Point3D& get_gbs_center() const { return gbs_center; }
inline void set_gbs_center( const Point3D& p ) { gbs_center = p; }
inline Point3D get_gbs_center() const { return Point3D::fromSGVec3(gbs_center); }
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 void set_gbs_radius( float r ) { gbs_radius = r; }
inline const point_list& get_wgs84_nodes() const { return wgs84_nodes; }
inline void set_wgs84_nodes( const point_list& n ) { wgs84_nodes = n; }
inline const std::vector<SGVec3d>& get_wgs84_nodes() const
{ 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 void set_colors( const point_list& c ) { colors = c; }
inline const std::vector<SGVec4f>& get_colors() const { return colors; }
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 void set_normals( const point_list& n ) { normals = n; }
inline const std::vector<SGVec3f>& get_normals() const { return normals; }
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 void set_texcoords( const point_list& t ) { texcoords = t; }
inline const std::vector<SGVec2f>& get_texcoords() const { return texcoords; }
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 void set_pts_v( const group_list& g ) { pts_v = g; }

View File

@@ -1,11 +1,13 @@
includedir = @includedir@/math
check_PROGRAMS = SGMathTest
check_PROGRAMS = SGMathTest SGGeometryTest
TESTS = $(check_PROGRAMS)
SGMathTest_SOURCES = SGMathTest.cxx
SGMathTest_LDADD = libsgmath.a $(base_LIBS)
SGGeometryTest_SOURCES = SGGeometryTest.cxx
SGGeometryTest_LDADD = libsgmath.a $(base_LIBS)
lib_LIBRARIES = libsgmath.a
@@ -19,19 +21,28 @@ include_HEADERS = \
sg_random.h \
sg_types.hxx \
vector.hxx \
SGBox.hxx \
SGCMath.hxx \
SGGeoc.hxx \
SGGeod.hxx \
SGGeodesy.hxx \
SGGeometry.hxx \
SGGeometryFwd.hxx \
SGIntersect.hxx \
SGLimits.hxx \
SGLineSegment.hxx \
SGMatrix.hxx \
SGMath.hxx \
SGMathFwd.hxx \
SGMisc.hxx \
SGPlane.hxx \
SGQuat.hxx \
SGVec4.hxx \
SGVec3.hxx
SGRay.hxx \
SGSphere.hxx \
SGTriangle.hxx \
SGVec2.hxx \
SGVec3.hxx \
SGVec4.hxx
libsgmath_a_SOURCES = \
interpolater.cxx \

107
simgear/math/SGBox.hxx Normal file
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

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

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

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

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

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

View File

@@ -21,6 +21,11 @@
/// Just include them all
#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"
@@ -28,6 +33,7 @@
#include "SGLimits.hxx"
#include "SGMisc.hxx"
#include "SGGeodesy.hxx"
#include "SGVec2.hxx"
#include "SGVec3.hxx"
#include "SGVec4.hxx"
#include "SGGeoc.hxx"

View File

@@ -32,6 +32,8 @@ class SGMisc;
template<typename T>
class SGQuat;
template<typename T>
class SGVec2;
template<typename T>
class SGVec3;
template<typename T>
class SGVec4;
@@ -44,6 +46,8 @@ 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;

View File

@@ -174,7 +174,9 @@ MatrixTest(void)
// Create some test matrix
SGVec3<T> v0(2, 7, 17);
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
SGMatrix<T> m1, m2;
@@ -236,7 +238,9 @@ sgInterfaceTest(void)
SGVec3f v3f = SGVec3f::e2();
SGVec4f v4f = SGVec4f::e2();
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,
// test for exact equality
@@ -283,7 +287,9 @@ sgdInterfaceTest(void)
SGVec3d v3d = SGVec3d::e2();
SGVec4d v4d = SGVec4d::e2();
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,
// test for exact equality

View File

@@ -63,14 +63,13 @@ public:
}
/// Constructor, build up a SGMatrix from a translation
SGMatrix(const SGVec3<T>& trans)
template<typename S>
SGMatrix(const SGVec3<S>& trans)
{ set(trans); }
/// Constructor, build up a SGMatrix from a rotation and a translation
SGMatrix(const SGQuat<T>& quat, const SGVec3<T>& trans)
{ set(quat, trans); }
/// Constructor, build up a SGMatrix from a rotation and a translation
SGMatrix(const SGQuat<T>& quat)
template<typename S>
SGMatrix(const SGQuat<S>& quat)
{ set(quat); }
/// Copy constructor for a transposed negated matrix
@@ -78,39 +77,22 @@ public:
{ set(tm); }
/// 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[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[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[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[11] = 0; _data.flat[15] = 1;
}
/// Set from a scale/rotation and tranlation
void set(const SGQuat<T>& quat, const SGVec3<T>& trans)
{
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)
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;
@@ -199,6 +181,45 @@ public:
/// Inplace matrix multiplication, post multiply
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> tpt;
@@ -574,8 +595,8 @@ toMatrixf(const SGMatrixd& m)
{
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(3,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(2,0), (float)m(2,1), (float)m(2,2), (float)m(2,3),
(float)m(3,0), (float)m(3,1), (float)m(3,2), (float)m(3,3));
}
inline
@@ -584,8 +605,8 @@ toMatrixd(const SGMatrixf& m)
{
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(3,0), m(2,1), m(2,2), m(2,3),
m(4,0), m(4,1), m(4,2), m(4,3));
m(2,0), m(2,1), m(2,2), m(2,3),
m(3,0), m(3,1), m(3,2), m(3,3));
}
#endif

View File

@@ -22,6 +22,8 @@ template<typename T>
class SGMisc {
public:
static T pi() { return T(3.1415926535897932384626433832795029L); }
static T twopi() { return 2*T(3.1415926535897932384626433832795029L); }
static T min(const T& a, const T& b)
{ return a < b ? a : b; }
static T min(const T& a, const T& b, const T& c)
@@ -34,6 +36,11 @@ public:
{ return max(max(a, b), c); }
static T max(const T& a, const T& b, const T& c, const T& 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)
{
if (a < -SGLimits<T>::min())
@@ -49,6 +56,32 @@ public:
static T deg2rad(const T& val)
{ 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)

59
simgear/math/SGPlane.hxx Normal file
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

View File

@@ -26,10 +26,42 @@
#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
template<typename T>
class SGQuat {
class SGQuat : protected SGQuatStorage<T> {
public:
typedef T value_type;
@@ -42,7 +74,7 @@ public:
/// uninitialized values in the debug build very fast ...
#ifndef NDEBUG
for (unsigned i = 0; i < 4; ++i)
_data[i] = SGLimits<T>::quiet_NaN();
data()[i] = SGLimits<T>::quiet_NaN();
#endif
}
/// Constructor. Initialize by the given values
@@ -51,11 +83,13 @@ public:
/// Constructor. Initialize by the content of a plain array,
/// make sure it has at least 4 elements
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
static SGQuat unit(void)
{ return fromRealImag(1, SGVec3<T>(0)); }
{ return fromRealImag(1, SGVec3<T>(0, 0, 0)); }
/// Return a quaternion from euler angles
static SGQuat fromEulerRad(T z, T y, T x)
@@ -96,13 +130,17 @@ public:
static SGQuat fromHeadAttBankDeg(T h, T a, T b)
{ return fromEulerDeg(h, a, b); }
/// Return a quaternion rotation the the horizontal local frame from given
/// longitude and latitude
/// Return a quaternion rotation from the earth centered to the
/// 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)
{
SGQuat q;
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 Syd2 = sin(yd2);
T Czd2 = cos(zd2);
@@ -113,17 +151,51 @@ public:
q.z() = Szd2*Cyd2;
return q;
}
/// Return a quaternion rotation the the horizontal local frame from given
/// longitude and latitude
/// Like the above provided for convenience
static SGQuat fromLonLatDeg(T lon, T lat)
{ return fromLonLatRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
/// Return a quaternion rotation the the horizontal local frame from given
/// longitude and latitude
/// 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
static SGQuat fromAngleAxis(T angle, const SGVec3<T>& axis)
{
@@ -146,14 +218,100 @@ public:
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
static SGQuat fromRealImag(T r, const SGVec3<T>& i)
{
SGQuat q;
q.w() = r;
q.x() = i(0);
q.y() = i(1);
q.z() = i(2);
q.x() = i.x();
q.y() = i.y();
q.z() = i.z();
return q;
}
@@ -164,36 +322,36 @@ public:
/// write the euler angles into the references
void getEulerRad(T& zRad, T& yRad, T& xRad) const
{
value_type sqrQW = w()*w();
value_type sqrQX = x()*x();
value_type sqrQY = y()*y();
value_type sqrQZ = z()*z();
T sqrQW = w()*w();
T sqrQX = x()*x();
T sqrQY = y()*y();
T sqrQZ = z()*z();
value_type num = 2*(y()*z() + w()*x());
value_type den = sqrQW - sqrQX - sqrQY + sqrQZ;
if (fabs(den) < SGLimits<value_type>::min() &&
fabs(num) < SGLimits<value_type>::min())
T num = 2*(y()*z() + w()*x());
T den = sqrQW - sqrQX - sqrQY + sqrQZ;
if (fabs(den) < SGLimits<T>::min() &&
fabs(num) < SGLimits<T>::min())
xRad = 0;
else
xRad = atan2(num, den);
value_type tmp = 2*(x()*z() - w()*y());
T tmp = 2*(x()*z() - w()*y());
if (tmp < -1)
yRad = 0.5*SGMisc<value_type>::pi();
yRad = 0.5*SGMisc<T>::pi();
else if (1 < tmp)
yRad = -0.5*SGMisc<value_type>::pi();
yRad = -0.5*SGMisc<T>::pi();
else
yRad = -asin(tmp);
num = 2*(x()*y() + w()*z());
den = sqrQW + sqrQX - sqrQY - sqrQZ;
if (fabs(den) < SGLimits<value_type>::min() &&
fabs(num) < SGLimits<value_type>::min())
if (fabs(den) < SGLimits<T>::min() &&
fabs(num) < SGLimits<T>::min())
zRad = 0;
else {
value_type psi = atan2(num, den);
T psi = atan2(num, den);
if (psi < 0)
psi += 2*SGMisc<value_type>::pi();
psi += 2*SGMisc<T>::pi();
zRad = psi;
}
}
@@ -236,67 +394,66 @@ public:
/// Access by index, the index is unchecked
const T& operator()(unsigned i) const
{ return _data[i]; }
{ return data()[i]; }
/// Access by index, the index is unchecked
T& operator()(unsigned i)
{ return _data[i]; }
{ return data()[i]; }
/// Access raw data by index, the index is unchecked
const T& operator[](unsigned i) const
{ return _data[i]; }
{ return data()[i]; }
/// Access raw data by index, the index is unchecked
T& operator[](unsigned i)
{ return _data[i]; }
{ return data()[i]; }
/// Access the x component
const T& x(void) const
{ return _data[0]; }
{ return data()[0]; }
/// Access the x component
T& x(void)
{ return _data[0]; }
{ return data()[0]; }
/// Access the y component
const T& y(void) const
{ return _data[1]; }
{ return data()[1]; }
/// Access the y component
T& y(void)
{ return _data[1]; }
{ return data()[1]; }
/// Access the z component
const T& z(void) const
{ return _data[2]; }
{ return data()[2]; }
/// Access the z component
T& z(void)
{ return _data[2]; }
{ return data()[2]; }
/// Access the w component
const T& w(void) const
{ return _data[3]; }
{ return data()[3]; }
/// Access the w component
T& w(void)
{ return _data[3]; }
{ return data()[3]; }
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
const T* data(void) const
{ return _data; }
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
T* data(void)
{ return _data; }
/// Get the data pointer
using SGQuatStorage<T>::data;
/// Readonly interface function to ssg's sgQuat/sgdQuat
const T (&sg(void) const)[4]
{ return _data; }
{ return data(); }
/// Interface function to ssg's sgQuat/sgdQuat
T (&sg(void))[4]
{ return _data; }
{ return data(); }
/// Interface function to osg's Quat*
using SGQuatStorage<T>::osg;
/// Inplace addition
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
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
template<typename 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
template<typename S>
SGQuat& operator/=(S s)
@@ -308,18 +465,18 @@ public:
/// frame rotated with the quaternion
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);
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);
}
/// Transform a vector from the coordinate frame rotated with the quaternion
/// to the current coordinate frame
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);
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);
}
@@ -332,7 +489,7 @@ public:
/// Return the time derivative of the quaternion given the angular velocity
SGQuat
derivative(const SGVec3<T>& angVel)
derivative(const SGVec3<T>& angVel) const
{
SGQuat deriv;
@@ -345,8 +502,65 @@ public:
}
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 ...

62
simgear/math/SGRay.hxx Normal file
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
simgear/math/SGSphere.hxx Normal file
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
simgear/math/SGTriangle.hxx Normal file
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
simgear/math/SGVec2.hxx Normal file
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

View File

@@ -18,9 +18,58 @@
#ifndef 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
template<typename T>
class SGVec3 {
class SGVec3 : protected SGVec3Storage<T> {
public:
typedef T value_type;
@@ -33,74 +82,79 @@ public:
/// uninitialized values in the debug build very fast ...
#ifndef NDEBUG
for (unsigned i = 0; i < 3; ++i)
_data[i] = SGLimits<T>::quiet_NaN();
data()[i] = SGLimits<T>::quiet_NaN();
#endif
}
/// Constructor. Initialize by the given values
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,
/// make sure it has at least 3 elements
explicit SGVec3(const T* data)
{ _data[0] = data[0]; _data[1] = data[1]; _data[2] = data[2]; }
explicit SGVec3(const T* d)
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
explicit SGVec3(const osg::Vec3f& d)
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
explicit SGVec3(const osg::Vec3d& d)
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
explicit SGVec3(const SGVec2<T>& v2, const T& v3 = 0)
{ data()[0] = v2[0]; data()[1] = v2[1]; data()[2] = v3; }
/// Access by index, the index is unchecked
const T& operator()(unsigned i) const
{ return _data[i]; }
{ return data()[i]; }
/// Access by index, the index is unchecked
T& operator()(unsigned i)
{ return _data[i]; }
{ return data()[i]; }
/// Access raw data by index, the index is unchecked
const T& operator[](unsigned i) const
{ return _data[i]; }
{ return data()[i]; }
/// Access raw data by index, the index is unchecked
T& operator[](unsigned i)
{ return _data[i]; }
{ return data()[i]; }
/// Access the x component
const T& x(void) const
{ return _data[0]; }
{ return data()[0]; }
/// Access the x component
T& x(void)
{ return _data[0]; }
{ return data()[0]; }
/// Access the y component
const T& y(void) const
{ return _data[1]; }
{ return data()[1]; }
/// Access the y component
T& y(void)
{ return _data[1]; }
{ return data()[1]; }
/// Access the z component
const T& z(void) const
{ return _data[2]; }
{ return data()[2]; }
/// Access the z component
T& z(void)
{ return _data[2]; }
{ return data()[2]; }
/// Get the data pointer
const T* data(void) const
{ return _data; }
/// Get the data pointer
T* data(void)
{ return _data; }
using SGVec3Storage<T>::data;
/// Readonly interface function to ssg's sgVec3/sgdVec3
const T (&sg(void) const)[3]
{ return _data; }
{ return data(); }
/// Interface function to ssg's sgVec3/sgdVec3
T (&sg(void))[3]
{ return _data; }
{ return data(); }
/// Interface function to osg's Vec3*
using SGVec3Storage<T>::osg;
/// Inplace addition
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
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
template<typename 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
template<typename S>
SGVec3& operator/=(S s)
@@ -123,10 +177,6 @@ public:
/// Constructor. Initialize by a geocentric coordinate
/// Note that this conversion is relatively expensive to compute
static SGVec3 fromGeoc(const SGGeoc& geoc);
private:
/// The actual data
T _data[3];
};
template<>
@@ -211,6 +261,73 @@ SGVec3<T>
operator*(const SGVec3<T>& v, S s)
{ 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
template<typename T>
inline
@@ -240,6 +357,13 @@ T
norm1(const SGVec3<T>& v)
{ 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
template<typename T>
inline
@@ -251,6 +375,31 @@ cross(const SGVec3<T>& v1, const SGVec3<T>& v2)
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
template<typename T>
inline
@@ -272,6 +421,43 @@ bool
operator!=(const SGVec3<T>& v1, const SGVec3<T>& 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
template<typename T>
inline

View File

@@ -18,9 +18,58 @@
#ifndef 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
template<typename T>
class SGVec4 {
class SGVec4 : protected SGVec4Storage<T> {
public:
typedef T value_type;
@@ -33,82 +82,86 @@ public:
/// uninitialized values in the debug build very fast ...
#ifndef NDEBUG
for (unsigned i = 0; i < 4; ++i)
_data[i] = SGLimits<T>::quiet_NaN();
data()[i] = SGLimits<T>::quiet_NaN();
#endif
}
/// Constructor. Initialize by the given values
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,
/// make sure it has at least 3 elements
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
const T& operator()(unsigned i) const
{ return _data[i]; }
{ return data()[i]; }
/// Access by index, the index is unchecked
T& operator()(unsigned i)
{ return _data[i]; }
{ return data()[i]; }
/// Access raw data by index, the index is unchecked
const T& operator[](unsigned i) const
{ return _data[i]; }
{ return data()[i]; }
/// Access raw data by index, the index is unchecked
T& operator[](unsigned i)
{ return _data[i]; }
{ return data()[i]; }
/// Access the x component
const T& x(void) const
{ return _data[0]; }
{ return data()[0]; }
/// Access the x component
T& x(void)
{ return _data[0]; }
{ return data()[0]; }
/// Access the y component
const T& y(void) const
{ return _data[1]; }
{ return data()[1]; }
/// Access the y component
T& y(void)
{ return _data[1]; }
{ return data()[1]; }
/// Access the z component
const T& z(void) const
{ return _data[2]; }
{ return data()[2]; }
/// Access the z component
T& z(void)
{ return _data[2]; }
{ return data()[2]; }
/// Access the x component
const T& w(void) const
{ return _data[3]; }
{ return data()[3]; }
/// Access the x component
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
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
/// Readonly interface function to ssg's sgVec4/sgdVec4
const T (&sg(void) const)[4]
{ return _data; }
/// Interface function to ssg's sgVec3/sgdVec3
{ return data(); }
/// Interface function to ssg's sgVec4/sgdVec4
T (&sg(void))[4]
{ return _data; }
{ return data(); }
/// Interface function to osg's Vec4*
using SGVec4Storage<T>::osg;
/// Inplace addition
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
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
template<typename 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
template<typename S>
SGVec4& operator/=(S s)
@@ -126,10 +179,6 @@ public:
{ return SGVec4(0, 0, 1, 0); }
static SGVec4 e4(void)
{ return SGVec4(0, 0, 0, 1); }
private:
/// The actual data
T _data[4];
};
/// Unary +, do nothing ...
@@ -174,6 +223,79 @@ SGVec4<T>
operator*(const SGVec4<T>& v, S s)
{ 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
template<typename T>
inline
@@ -203,6 +325,13 @@ T
norm1(const SGVec4<T>& v)
{ 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
template<typename T>
inline
@@ -224,6 +353,47 @@ bool
operator!=(const SGVec4<T>& v1, const SGVec4<T>& 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
template<typename T>
inline

View File

@@ -25,12 +25,11 @@
#include <simgear/compiler.h>
#include <stdlib.h> // for exit()
#include STL_STRING
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/props/props.hxx>
#include "interpolater.hxx"
@@ -38,22 +37,29 @@ SG_USING_STD(string);
// Constructor -- starts with an empty table.
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
// file
SGInterpTable::SGInterpTable( const string& file )
: size(0)
{
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
sg_gzifstream in( file );
if ( !in.is_open() ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
exit(-1);
return;
}
in >> skipcomment;
@@ -61,8 +67,7 @@ SGInterpTable::SGInterpTable( const string& file )
double ind, dep;
in >> ind >> dep;
in >> skipws;
table.push_back(Entry(ind, dep));
size++;
_table[ind] = dep;
}
}
@@ -70,51 +75,42 @@ SGInterpTable::SGInterpTable( const string& file )
// Add an entry to the table.
void SGInterpTable::addEntry (double ind, double dep)
{
table.push_back(Entry(ind,dep));
size++;
_table[ind] = dep;
}
// Given an x value, linearly interpolate the y value from the table
double SGInterpTable::interpolate(double x) const
{
int i;
double y;
if (size == 0.0) {
return 0.0;
}
i = 0;
while ( (i < size) && (x > table[i].ind) ) {
// cout << " i = " << i << " table[i].ind = " << table[i].ind << endl;
// cout << " size = " << size << endl;
i++;
}
// printf ("i = %d ", i);
if ( i <= 0 ) {
SG_LOG( SG_MATH, SG_DEBUG,
"interpolate(): lookup error, x to small = " << x );
return table[0].dep;
}
// cout << " table[size-1].ind = " << table[size-1].ind << endl;
if ( i >= size ) {
SG_LOG( SG_MATH, SG_DEBUG,
"interpolate(): lookup error, x to big = " << x );
return table[size-1].dep;
}
// 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);
// Empty table??
if (_table.empty())
return 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.
// use the last entry
if (upBoundIt == _table.end())
return _table.rbegin()->second;
// points to the first key must be lower
// use the first entry
if (upBoundIt == _table.begin())
return upBoundIt->second;
// we know that we do not stand at the beginning, so it is safe to do so
Table::const_iterator loBoundIt = upBoundIt;
--loBoundIt;
// Just do linear interpolation.
double loBound = loBoundIt->first;
double upBound = upBoundIt->first;
double loVal = loBoundIt->second;
double upVal = upBoundIt->second;
// division by zero should not happen since the std::map
// 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);
}

View File

@@ -35,12 +35,14 @@
#include <simgear/compiler.h>
#include <vector>
SG_USING_STD(vector);
#include "simgear/structure/SGReferenced.hxx"
#include <map>
#include STL_STRING
SG_USING_STD(string);
class SGPropertyNode;
/**
* 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
* variable can be anything.
*/
class SGInterpTable {
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;
class SGInterpTable : public SGReferenced {
public:
/**
@@ -70,6 +58,13 @@ public:
*/
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.
* @param file name of interpolation file
@@ -95,6 +90,10 @@ public:
/** Destructor */
~SGInterpTable();
private:
typedef std::map<double, double> Table;
Table _table;
};

View File

@@ -97,6 +97,8 @@ public:
static Point3D fromSGGeod(const SGGeod& geod);
static Point3D fromSGGeoc(const SGGeoc& geoc);
static Point3D fromSGVec3(const SGVec3<double>& cart);
static Point3D fromSGVec3(const SGVec3<float>& cart);
static Point3D fromSGVec2(const SGVec2<double>& cart);
// Assignment operators
@@ -132,6 +134,10 @@ public:
SGGeod toSGGeod(void) const;
SGGeoc toSGGeoc(void) const;
SGVec3d toSGVec3d(void) const;
SGVec3f toSGVec3f(void) const;
SGVec2f toSGVec2f(void) const;
// friends
friend Point3D operator - (const Point3D& p); // -p1
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;
}
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
inline Point3D& Point3D::operator = (const Point3D& p)
@@ -341,6 +365,21 @@ inline SGGeoc Point3D::toSGGeoc(void) const
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
inline Point3D operator - (const Point3D& a)

View File

@@ -195,6 +195,8 @@ bool SGPath::exists() const {
void SGPath::create_dir( mode_t mode ) {
string_list dirlist = sgPathSplit(dir());
if ( dirlist.empty() )
return;
string path = dirlist[0];
string_list path_elements = sgPathBranchSplit(path);
bool absolute = !path.empty() && path[0] == sgDirPathSep;

View File

@@ -2,26 +2,12 @@ includedir = @includedir@/nasal
lib_LIBRARIES = libsgnasal.a
include_HEADERS = nasal.h
include_HEADERS = nasal.h naref.h
libsgnasal_a_SOURCES = \
code.c code.h \
codegen.c \
data.h \
gc.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
libsgnasal_a_SOURCES = bitslib.c code.c code.h codegen.c data.h gc.c \
hash.c iolib.c iolib.h lex.c lib.c mathlib.c \
misc.c naref.h nasal.h parse.c parse.h string.c \
thread-posix.c thread-win32.c threadlib.c \
utf8lib.c vector.c
INCLUDES = -I$(top_srcdir)

View File

@@ -5,10 +5,10 @@
// bits (i.e. an unsigned int). Using a 64 bit integer would stretch
// that beyond what is representable in the double result, but
// requires portability work.
#define BIT(s,l,n) s[l-1-((n)>>3)] & (1<<((n)&7))
#define CLRB(s,l,n) s[l-1-((n)>>3)] &= ~(1<<((n)&7))
#define SETB(s,l,n) s[l-1-((n)>>3)] |= 1<<((n)&7)
#define MSK(n) (1 << (7 - ((n) & 7)))
#define BIT(s,l,n) s[(n)>>3] & MSK(n)
#define CLRB(s,l,n) s[(n)>>3] &= ~MSK(n)
#define SETB(s,l,n) s[(n)>>3] |= MSK(n)
static unsigned int fld(naContext c, unsigned char* s,
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)
{
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 len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
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)
{
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 len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
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);
}
static struct func { char* name; naCFunction func; } funcs[] = {
static naCFuncItem funcs[] = {
{ "sfld", f_sfld },
{ "fld", f_fld },
{ "setfld", f_setfld },
{ "buf", f_buf },
{ 0 }
};
naRef naBitsLib(naContext c)
naRef naInit_bits(naContext c)
{
naRef namespace = naNewHash(c);
int i, n = sizeof(funcs)/sizeof(struct func);
for(i=0; i<n; i++) {
naRef code = naNewCCode(c, funcs[i].func);
naRef name = naStr_fromdata(naNewString(c),
funcs[i].name, strlen(funcs[i].name));
naHash_set(namespace, name, naNewFunc(c, code));
}
return namespace;
return naGenLib(c, funcs);
}

View File

@@ -1,11 +1,14 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "nasal.h"
#include "code.h"
////////////////////////////////////////////////////////////////////////
// Debugging stuff. ////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//#define DEBUG_NASAL
#if !defined(DEBUG_NASAL)
//#define INTERPRETER_DUMP
#if !defined(INTERPRETER_DUMP)
# define DBG(expr) /* noop */
#else
# define DBG(expr) expr
@@ -17,21 +20,44 @@ void printOpDEBUG(int ip, int op);
void printStackDEBUG(struct Context* ctx);
////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
#define vsnprintf _vsnprintf
#endif
struct Globals* globals = 0;
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code);
#define ERR(c, msg) naRuntimeError((c),(msg))
void naRuntimeError(struct Context* c, char* msg)
{
c->error = msg;
void naRuntimeError(struct Context* c, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(c->error, sizeof(c->error), fmt, ap);
va_end(ap);
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)
{
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)) {
double d;
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);
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;
}
@@ -73,7 +101,9 @@ static int checkStr(struct Context* ctx, naRef str, naRef idx)
{
int i = (int)numify(ctx, idx);
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;
}
@@ -82,8 +112,7 @@ static naRef containerGet(struct Context* ctx, naRef box, naRef key)
naRef result = naNil();
if(!IS_SCALAR(key)) ERR(ctx, "container index not scalar");
if(IS_HASH(box)) {
if(!naHash_get(box, key, &result))
ERR(ctx, "undefined value in container");
naHash_get(box, key, &result);
} else if(IS_VEC(box)) {
result = naVec_get(box, checkVec(ctx, box, key));
} 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_VEC(box)) naVec_set(box, checkVec(ctx, box, key), val);
else if(IS_STR(box)) {
if(box.ref.ptr.str->hashcode)
if(PTR(box).str->hashcode)
ERR(ctx, "cannot change immutable string");
naStr_data(box)[checkStr(ctx, box, key)] = (char)numify(ctx, val);
} else ERR(ctx, "insert into non-container");
@@ -128,7 +157,8 @@ static void initContext(struct Context* c)
c->callParent = 0;
c->callChild = 0;
c->dieArg = naNil();
c->error = 0;
c->error[0] = 0;
c->userData = 0;
}
static void initGlobals()
@@ -191,9 +221,20 @@ struct Context* naNewContext()
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)
{
c->ntemps = 0;
if(c->callChild) naFreeContext(c->callChild);
if(c->callParent) c->callParent->callChild = 0;
LOCK();
c->nextFree = globals->freeContexts;
globals->freeContexts = c;
@@ -212,12 +253,14 @@ void naFreeContext(struct Context* c)
static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
{
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
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++)
naHash_newsym(f->locals.ref.ptr.hash,
naHash_newsym(PTR(f->locals).hash,
&c->constants[c->argSyms[i]], &args[i]);
args += c->nArgs;
nargs -= c->nArgs;
@@ -225,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]];
if(IS_CODE(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);
}
args += c->nOptArgs;
@@ -233,12 +276,12 @@ static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
naRef argsv = naNewVector(ctx);
naVec_setsize(argsv, nargs > 0 ? nargs : 0);
for(i=0; i<nargs; i++)
argsv.ref.ptr.vec->rec->array[i] = *args++;
naHash_newsym(f->locals.ref.ptr.hash, &c->restArgSym, &argsv);
PTR(argsv).vec->rec->array[i] = *args++;
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;
struct Frame* f;
@@ -249,20 +292,20 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
if(!IS_FUNC(frame[0]))
ERR(ctx, "function/method call invoked on uncallable object");
// Just do native calls right here, and don't touch the stack
// frames; return the current one (unless it's a tail call!).
if(frame[0].ref.ptr.func->code.ref.ptr.obj->type == T_CCODE) {
ctx->opFrame = ctx->opTop - (nargs + 1 + mcall);
// Just do native calls right here
if(PTR(PTR(frame[0]).func->code).obj->type == T_CCODE) {
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);
ctx->opTop -= nargs + 1 + mcall;
ctx->opTop = ctx->opFrame;
PUSH(result);
return &(ctx->fStack[ctx->fTop-1]);
}
if(tail) ctx->fTop--;
else if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
// Note: assign nil first, otherwise the naNew() can cause a GC,
// which will now (after fTop++) see the *old* reference as a
// markable value!
@@ -271,7 +314,7 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
f->locals = naNewHash(ctx);
f->func = frame[0];
f->ip = 0;
f->bp = ctx->opTop - (nargs + 1 + mcall);
f->bp = ctx->opFrame;
if(mcall)
naHash_set(f->locals, globals->meRef, frame[-1]);
@@ -283,29 +326,35 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
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)
{
int result = naEqual(ra, rb);
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
// the stack, it needs to be bound with the lexical context.
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code)
{
naRef result = naNewFunc(ctx, code);
result.ref.ptr.func->namespace = f->locals;
result.ref.ptr.func->next = f->func;
PTR(result).func->namespace = f->locals;
PTR(result).func->next = f->func;
return result;
}
@@ -313,7 +362,7 @@ static int getClosure(struct naFunc* c, naRef sym, naRef* result)
{
while(c) {
if(naHash_get(c->namespace, sym, result)) return 1;
c = c->next.ref.ptr.func;
c = PTR(c->next).func;
}
return 0;
}
@@ -322,8 +371,8 @@ static naRef getLocal2(struct Context* ctx, struct Frame* f, naRef sym)
{
naRef result;
if(!naHash_get(f->locals, sym, &result))
if(!getClosure(f->func.ref.ptr.func, sym, &result))
ERR(ctx, "undefined symbol");
if(!getClosure(PTR(f->func).func, sym, &result))
naRuntimeError(ctx, "undefined symbol: %s", naStr_data(sym));
return result;
}
@@ -331,14 +380,14 @@ static void getLocal(struct Context* ctx, struct Frame* f,
naRef* sym, naRef* out)
{
struct naFunc* func;
struct naStr* str = sym->ref.ptr.str;
if(naHash_sym(f->locals.ref.ptr.hash, str, out))
struct naStr* str = PTR(*sym).str;
if(naHash_sym(PTR(f->locals).hash, str, out))
return;
func = f->func.ref.ptr.func;
while(func && func->namespace.ref.ptr.hash) {
if(naHash_sym(func->namespace.ref.ptr.hash, str, out))
func = PTR(f->func).func;
while(func && PTR(func->namespace).hash) {
if(naHash_sym(PTR(func->namespace).hash, str, out))
return;
func = func->next.ref.ptr.func;
func = PTR(func->next).func;
}
// Now do it again using the more general naHash_get(). This will
// only be necessary if something has created the value in the
@@ -349,7 +398,7 @@ static void getLocal(struct Context* ctx, struct Frame* f,
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; }
else if(naHash_tryset(c->namespace, sym, val)) { return 1; }
else { return setClosure(c->next, sym, val); }
@@ -365,28 +414,42 @@ static naRef setSymbol(struct Frame* f, naRef sym, naRef val)
return val;
}
// Recursively descend into the parents lists
static int getMember(struct Context* ctx, naRef obj, naRef fld,
naRef* result, int count)
// Funky API: returns null to indicate no member, an empty string to
// indicate success, or a non-empty error message. Works this way so
// 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;
if(--count < 0) ERR(ctx, "too many parents");
if(!IS_HASH(obj)) ERR(ctx, "non-objects have no members");
if(naHash_get(obj, fld, result)) {
return 1;
} else if(naHash_get(obj, globals->parentsRef, &p)) {
if(IS_VEC(p)) {
int i;
struct VecRec* v = p.ref.ptr.vec->rec;
for(i=0; i<v->size; i++)
if(getMember(ctx, v->array[i], fld, result, count))
return 1;
} else
ERR(ctx, "parents field not vector");
struct VecRec* pv;
if(--count < 0) return "too many parents";
if(!IS_HASH(obj)) return 0;
if(naHash_get(obj, field, out)) return "";
if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
if(!IS_VEC(p)) return "object \"parents\" field not vector";
pv = PTR(p).vec->rec;
for(i=0; i<pv->size; i++) {
const char* err = getMember_r(pv->array[i], field, out, count);
if(err) return err; /* either an error or success */
}
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
// and index on the stack, increments the index after use, and
// pushes a nil if the index is beyond the end.
@@ -394,9 +457,9 @@ static void evalEach(struct Context* ctx, int useIndex)
{
int idx = (int)(ctx->opStack[ctx->opTop-1].num);
naRef vec = ctx->opStack[ctx->opTop-2];
if(!IS_VEC(vec)) naRuntimeError(ctx, "foreach enumeration of non-vector");
if(!vec.ref.ptr.vec->rec || idx >= vec.ref.ptr.vec->rec->size) {
PUSH(naNil());
if(!IS_VEC(vec)) ERR(ctx, "foreach enumeration of non-vector");
if(!PTR(vec).vec->rec || idx >= PTR(vec).vec->rec->size) {
PUSH(endToken());
return;
}
ctx->opStack[ctx->opTop-1].num = idx+1; // modify in place
@@ -408,13 +471,16 @@ static void evalEach(struct Context* ctx, int useIndex)
#define POP() ctx->opStack[--ctx->opTop]
#define STK(n) (ctx->opStack[ctx->opTop-(n)])
#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)
{
struct Frame* f;
struct naCode* cd;
int op, arg;
naRef a, b, c;
naRef a, b;
ctx->dieArg = naNil();
ctx->error[0] = 0;
FIXFRAME();
@@ -440,8 +506,7 @@ static naRef run(struct Context* ctx)
#define BINOP(expr) do { \
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)); \
STK(2).ref.reftag = ~NASAL_REFTAG; \
STK(2).num = expr; \
SETNUM(STK(2), expr); \
ctx->opTop--; } while(0)
case OP_PLUS: BINOP(l + r); break;
@@ -452,24 +517,15 @@ static naRef run(struct Context* ctx)
case OP_LTE: BINOP(l <= r ? 1 : 0); break;
case OP_GT: BINOP(l > r ? 1 : 0); break;
case OP_GTE: BINOP(l >= r ? 1 : 0); break;
#undef BINOP
case OP_EQ: case OP_NEQ:
STK(2) = evalEquality(op, STK(2), STK(1));
ctx->opTop--;
break;
case OP_AND: case OP_OR:
STK(2) = evalAndOr(ctx, op, STK(2), STK(1));
ctx->opTop--;
break;
case OP_CAT:
// stringify can call the GC, so don't take stuff of the stack!
a = stringify(ctx, ctx->opStack[ctx->opTop-1]);
b = stringify(ctx, ctx->opStack[ctx->opTop-2]);
c = naStr_concat(naNewString(ctx), b, a);
ctx->opTop -= 2;
PUSH(c);
STK(2) = evalCat(ctx, STK(2), STK(1));
ctx->opTop -= 1;
break;
case OP_NEG:
STK(1) = naNum(-numify(ctx, STK(1)));
@@ -491,6 +547,9 @@ static naRef run(struct Context* ctx)
case OP_PUSHNIL:
PUSH(naNil());
break;
case OP_PUSHEND:
PUSH(endToken());
break;
case OP_NEWVEC:
PUSH(naNewVector(ctx));
break;
@@ -520,8 +579,7 @@ static naRef run(struct Context* ctx)
ctx->opTop--;
break;
case OP_MEMBER:
if(!getMember(ctx, STK(1), CONSTARG(), &STK(1), 64))
ERR(ctx, "no such member");
getMember(ctx, STK(1), CONSTARG(), &STK(1), 64);
break;
case OP_SETMEMBER:
if(!IS_HASH(STK(3))) ERR(ctx, "non-objects have no members");
@@ -548,15 +606,29 @@ static naRef run(struct Context* ctx)
f->ip = cd->byteCode[f->ip];
DBG(printf(" [Jump to: %d]\n", f->ip);)
break;
case OP_JIFNIL:
case OP_JIFEND:
arg = ARG();
if(IS_NIL(STK(1))) {
if(IS_END(STK(1))) {
ctx->opTop--; // Pops **ONLY** if it's nil!
f->ip = arg;
DBG(printf(" [Jump to: %d]\n", f->ip);)
}
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:
arg = ARG();
if(!boolify(ctx, STK(1))) {
f->ip = arg;
DBG(printf(" [Jump to: %d]\n", f->ip);)
}
break;
case OP_JIFNOTPOP:
arg = ARG();
if(!boolify(ctx, POP())) {
f->ip = arg;
@@ -564,23 +636,17 @@ static naRef run(struct Context* ctx)
}
break;
case OP_FCALL:
f = setupFuncall(ctx, ARG(), 0, 0);
cd = f->func.ref.ptr.func->code.ref.ptr.code;
break;
case OP_FTAIL:
f = setupFuncall(ctx, ARG(), 0, 1);
cd = f->func.ref.ptr.func->code.ref.ptr.code;
f = setupFuncall(ctx, ARG(), 0);
cd = PTR(PTR(f->func).func->code).code;
break;
case OP_MCALL:
f = setupFuncall(ctx, ARG(), 1, 0);
cd = f->func.ref.ptr.func->code.ref.ptr.code;
break;
case OP_MTAIL:
f = setupFuncall(ctx, ARG(), 1, 1);
cd = f->func.ref.ptr.func->code.ref.ptr.code;
f = setupFuncall(ctx, ARG(), 1);
cd = PTR(PTR(f->func).func->code).code;
break;
case OP_RETURN:
a = STK(1);
ctx->dieArg = naNil();
if(ctx->callChild) naFreeContext(ctx->callChild);
if(--ctx->fTop <= 0) return a;
ctx->opTop = f->bp + 1; // restore the correct opstack frame!
STK(1) = a;
@@ -594,7 +660,7 @@ static naRef run(struct Context* ctx)
break;
case OP_MARK: // save stack state (e.g. "setjmp")
if(ctx->markTop >= MAX_MARK_DEPTH)
naRuntimeError(ctx, "mark stack overflow");
ERR(ctx, "mark stack overflow");
ctx->markStack[ctx->markTop++] = ctx->opTop;
break;
case OP_UNMARK: // pop stack state set by mark
@@ -624,48 +690,55 @@ void naSave(struct Context* ctx, naRef obj)
naVec_append(globals->save, obj);
}
// FIXME: handle ctx->callParent
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)
{
struct Frame* f = &ctx->fStack[ctx->fTop-1-frame];
naRef func = f->func;
int ip = f->ip;
if(IS_FUNC(func) && IS_CODE(func.ref.ptr.func->code)) {
struct naCode* c = func.ref.ptr.func->code.ref.ptr.code;
struct Frame* f;
frame = findFrame(ctx, &ctx, frame);
f = &ctx->fStack[frame];
if(IS_FUNC(f->func) && IS_CODE(PTR(f->func).func->code)) {
struct naCode* c = PTR(PTR(f->func).func->code).code;
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;
return p[1];
}
return -1;
}
// FIXME: handle ctx->callParent
naRef naGetSourceFile(struct Context* ctx, int frame)
{
naRef f = ctx->fStack[ctx->fTop-1-frame].func;
f = f.ref.ptr.func->code;
return f.ref.ptr.code->srcFile;
naRef f;
frame = findFrame(ctx, &ctx, frame);
f = ctx->fStack[frame].func;
f = PTR(f).func->code;
return PTR(f).code->srcFile;
}
char* naGetError(struct Context* ctx)
{
if(IS_STR(ctx->dieArg))
return (char*)ctx->dieArg.ref.ptr.str->data;
return ctx->error;
return (char*)PTR(ctx->dieArg).str->data;
return ctx->error[0] ? ctx->error : 0;
}
naRef naBindFunction(naContext ctx, naRef code, naRef closure)
{
naRef func = naNewFunc(ctx, code);
func.ref.ptr.func->namespace = closure;
func.ref.ptr.func->next = naNil();
PTR(func).func->namespace = closure;
PTR(func).func->next = naNil();
return func;
}
@@ -673,8 +746,8 @@ naRef naBindToContext(naContext ctx, naRef code)
{
naRef func = naNewFunc(ctx, code);
struct Frame* f = &ctx->fStack[ctx->fTop-1];
func.ref.ptr.func->namespace = f->locals;
func.ref.ptr.func->next = f->func;
PTR(func).func->namespace = f->locals;
PTR(func).func->next = f->func;
return func;
}
@@ -683,7 +756,7 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
{
int i;
naRef result;
if(!ctx->callParent) naModLock(ctx);
if(!ctx->callParent) naModLock();
// 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
@@ -694,22 +767,28 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
naTempSave(ctx, obj);
naTempSave(ctx, locals);
if(IS_CCODE(func.ref.ptr.func->code)) {
naCFunction fp = func.ref.ptr.func->code.ref.ptr.ccode->fptr;
result = (*fp)(ctx, obj, argc, args);
// naRuntimeError() calls end up here:
if(setjmp(ctx->jumpHandle)) {
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;
}
if(IS_NIL(locals))
locals = naNewHash(ctx);
if(!IS_FUNC(func))
func = naNewFunc(ctx, func); // bind bare code objects
if(!IS_FUNC(func)) {
func = naNewFunc(ctx, func);
PTR(func).func->namespace = locals;
}
if(!IS_NIL(obj))
naHash_set(locals, globals->meRef, obj);
ctx->dieArg = naNil();
ctx->opTop = ctx->markTop = 0;
ctx->fTop = 1;
ctx->fStack[0].func = func;
@@ -717,18 +796,42 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
ctx->fStack[0].ip = 0;
ctx->fStack[0].bp = ctx->opTop;
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();
}
if(args) setupArgs(ctx, ctx->fStack, args, argc);
result = run(ctx);
if(!ctx->callParent) naModUnlock(ctx);
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;
}

View File

@@ -10,19 +10,23 @@
#define MAX_MARK_DEPTH 128
// Number of objects (per pool per thread) asked for using naGC_get().
// Testing with fib.nas shows that this gives the best performance,
// without too much per-thread overhead.
#define OBJ_CACHE_SZ 128
// The idea is that contexts can "cache" allocations to prevent thread
// contention on the global pools. But in practice this interacts
// 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 {
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_JMP, OP_JMPLOOP, OP_JIFNOT, OP_JIFNIL, OP_FCALL, OP_MCALL, OP_RETURN,
OP_PUSHCONST, OP_PUSHONE, OP_PUSHZERO, OP_PUSHNIL, OP_POP,
OP_JMP, OP_JMPLOOP, OP_JIFNOTPOP, OP_JIFEND, OP_FCALL, OP_MCALL,
OP_RETURN, OP_PUSHCONST, OP_PUSHONE, OP_PUSHZERO, OP_PUSHNIL, OP_POP,
OP_DUP, OP_XCHG, OP_INSERT, OP_EXTRACT, OP_MEMBER, OP_SETMEMBER,
OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND, OP_NEWHASH, OP_HAPPEND,
OP_MARK, OP_UNMARK, OP_BREAK, OP_FTAIL, OP_MTAIL, OP_SETSYM, OP_DUP2,
OP_INDEX, OP_BREAK2
OP_MARK, OP_UNMARK, OP_BREAK, OP_SETSYM, OP_DUP2, OP_INDEX, OP_BREAK2,
OP_PUSHEND, OP_JIFTRUE, OP_JIFNOT
};
struct Frame {
@@ -69,6 +73,7 @@ struct Context {
struct Frame fStack[MAX_RECURSION];
int fTop;
naRef opStack[MAX_STACK_DEPTH];
int opFrame; // like Frame::bp, but for C functions
int opTop;
int markStack[MAX_MARK_DEPTH];
int markTop;
@@ -86,7 +91,7 @@ struct Context {
// Error handling
jmp_buf jumpHandle;
char* error;
char error[128];
naRef dieArg;
// Sub-call lists
@@ -96,6 +101,8 @@ struct Context {
// Linked list pointers in globals
struct Context* nextFree;
struct Context* nextAll;
void* userData;
};
#define globals nasal_globals
@@ -103,11 +110,13 @@ extern struct Globals* globals;
// Threading low-level functions
void* naNewLock();
void naFreeLock(void* lock);
void naLock(void* lock);
void naUnlock(void* lock);
void* naNewSem();
void naFreeSem(void* sem);
void naSemDown(void* sem);
void naSemUpAll(void* sem, int count);
void naSemUp(void* sem, int count);
void naCheckBottleneck();

View File

@@ -91,41 +91,6 @@ static int findConstantIndex(struct Parser* p, struct Token* t)
return internConstant(p, c);
}
static int lastExprInBlock(struct Token* t)
{
if(!t->parent) return 1;
if(t->parent->type == TOK_TOP || t->parent->type == TOK_LCURL) return 1;
if(t->parent->type == TOK_SEMI)
if(!t->next || t->next->type == TOK_EMPTY)
return 1;
return 0;
}
// Returns true if the node is in "tail context" -- either a child of
// a return, the last child of a func block, or else the
// last child of an if/elsif/if that is itself in tail context.
static int tailContext(struct Token* t)
{
if(t->parent && t->parent->type == TOK_RETURN)
return 1;
else if(!lastExprInBlock(t))
return 0;
// Walk up the tree. It is ok to see semicolons, else's, elsifs
// and curlies. If we reach the top or a func, then we are in
// tail context. If we hit an if, then we are in tail context
// only if the "if" node is.
while((t = t->parent) != 0)
switch(t->type) {
case TOK_SEMI: case TOK_LCURL: break;
case TOK_ELSE: case TOK_ELSIF: break;
case TOK_TOP: case TOK_FUNC: return 1;
case TOK_IF: return tailContext(t);
default: return 0;
}
return 0;
}
static int genScalarConstant(struct Parser* p, struct Token* t)
{
// These opcodes are for special-case use in other constructs, but
@@ -145,7 +110,7 @@ static int genScalarConstant(struct Parser* p, struct Token* t)
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"
} else if(t->type == TOK_SYMBOL) {
*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)
{
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);
}
@@ -293,8 +267,6 @@ static void genFuncall(struct Parser* p, struct Token* t)
genExpr(p, LEFT(t));
}
if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
if(tailContext(t))
op = op == OP_FCALL ? OP_FTAIL : OP_MTAIL;
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)
{
int jumpNext, jumpEnd, isAnd = (t->type == TOK_AND);
int end;
genExpr(p, LEFT(t));
if(isAnd) emit(p, OP_NOT);
jumpNext = emitJump(p, OP_JIFNOT);
emit(p, isAnd ? OP_PUSHNIL : OP_PUSHONE);
jumpEnd = emitJump(p, OP_JMP);
fixJumpTarget(p, jumpNext);
end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
emit(p, OP_POP);
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;
genExpr(p, tif->children); // the test
jumpNext = emitJump(p, OP_JIFNOT);
jumpNext = emitJump(p, OP_JIFNOTPOP);
genExprList(p, tif->children->next->children); // the body
jumpEnd = emitJump(p, OP_JMP);
fixJumpTarget(p, jumpNext);
@@ -374,7 +343,7 @@ static void genQuestion(struct Parser* p, struct Token* t)
if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
naParseError(p, "invalid ?: expression", t->line);
genExpr(p, LEFT(t)); // the test
jumpNext = emitJump(p, OP_JIFNOT);
jumpNext = emitJump(p, OP_JIFNOTPOP);
genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
jumpEnd = emitJump(p, OP_JMP);
fixJumpTarget(p, jumpNext);
@@ -420,7 +389,7 @@ static void genForWhile(struct Parser* p, struct Token* init,
pushLoop(p, label);
loopTop = p->cg->codesz;
genExpr(p, test);
jumpEnd = emitJump(p, OP_JIFNOT);
jumpEnd = emitJump(p, OP_JIFNOTPOP);
genLoop(p, body, update, label, loopTop, jumpEnd);
}
@@ -485,7 +454,7 @@ static void genForEach(struct Parser* p, struct Token* t)
pushLoop(p, label);
loopTop = p->cg->codesz;
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);
emit(p, OP_XCHG);
emit(p, assignOp);
@@ -522,7 +491,7 @@ static void genBreakContinue(struct Parser* p, struct Token* t)
for(i=0; i<levels; i++)
emit(p, (i<levels-1) ? OP_BREAK2 : OP_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);
}
@@ -544,6 +513,8 @@ static void newLineEntry(struct Parser* p, int line)
static void genExpr(struct Parser* p, struct Token* t)
{
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)
newLineEntry(p, t->line);
p->cg->lastLine = t->line;
@@ -613,7 +584,7 @@ static void genExpr(struct Parser* p, struct Token* t)
case TOK_MINUS:
if(BINARY(t)) {
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
genScalarConstant(p, RIGHT(t));
} else {
@@ -627,7 +598,7 @@ static void genExpr(struct Parser* p, struct Token* t)
break;
case TOK_DOT:
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);
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
break;
@@ -658,7 +629,7 @@ static void genExpr(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));
if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
emit(p, OP_POP);
@@ -692,7 +663,7 @@ naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
// Now make a code object
codeObj = naNewCode(p->context);
code = codeObj.ref.ptr.code;
code = PTR(codeObj).code;
// Parse the argument list, if any
code->restArgSym = globals->argRef;

View File

@@ -3,30 +3,86 @@
#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,
NUM_NASAL_TYPES }; // V. important that this come last!
#define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG)
#define IS_NUM(r) ((r).ref.reftag != NASAL_REFTAG)
#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0)
//#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0 && (((r).ref.ptr.obj->type == 123) ? *(int*)0 : 1))
#define IS_NIL(r) (IS_REF((r)) && (r).ref.ptr.obj == 0)
#define IS_STR(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_STR)
#define IS_VEC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_VEC)
#define IS_HASH(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_HASH)
#define IS_CODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CODE)
#define IS_FUNC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_FUNC)
#define IS_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_NUM(r) (!IS_REF(r))
#define IS_OBJ(r) (IS_REF(r) && PTR(r).obj != 0)
#define IS_NIL(r) (IS_REF(r) && PTR(r).obj == 0)
#define IS_STR(r) (IS_OBJ(r) && PTR(r).obj->type == T_STR)
#define IS_VEC(r) (IS_OBJ(r) && PTR(r).obj->type == T_VEC)
#define IS_HASH(r) (IS_OBJ(r) && PTR(r).obj->type == T_HASH)
#define IS_CODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CODE)
#define IS_FUNC(r) (IS_OBJ(r) && PTR(r).obj->type == T_FUNC)
#define IS_CCODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CCODE)
#define IS_GHOST(r) (IS_OBJ(r) && PTR(r).obj->type == T_GHOST)
#define IS_CONTAINER(r) (IS_VEC(r)||IS_HASH(r))
#define IS_SCALAR(r) (IS_NUM((r)) || IS_STR((r)))
#define IS_SCALAR(r) (IS_NUM(r) || IS_STR(r))
#define IDENTICAL(a, b) (IS_REF(a) && IS_REF(b) \
&& a.ref.ptr.obj == b.ref.ptr.obj)
&& 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
// 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
// implementing objects to pack in 16 bits worth of data "for free".
#define GC_HEADER \

View File

@@ -2,7 +2,7 @@
#include "data.h"
#include "code.h"
#define MIN_BLOCK_SIZE 256
#define MIN_BLOCK_SIZE 32
static void reap(struct naPool* p);
static void mark(naRef r);
@@ -27,7 +27,7 @@ static void marktemps(struct Context* c)
int i;
naRef r = naNil();
for(i=0; i<c->ntemps; i++) {
r.ref.ptr.obj = c->temps[i];
SETPTR(r, c->temps[i]);
mark(r);
}
}
@@ -108,7 +108,7 @@ static void bottleneck()
if(g->waitCount >= g->nThreads - 1) {
freeDead();
if(g->needGC) garbageCollect();
if(g->waitCount) naSemUpAll(g->sem, g->waitCount);
if(g->waitCount) naSemUp(g->sem, g->waitCount);
g->bottleneck = 0;
}
}
@@ -130,7 +130,7 @@ static void naCode_gcclean(struct naCode* o)
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;
}
@@ -214,7 +214,7 @@ struct naObj** naGC_get(struct naPool* p, int n, int* nout)
static void markvec(naRef r)
{
int i;
struct VecRec* vr = r.ref.ptr.vec->rec;
struct VecRec* vr = PTR(r).vec->rec;
if(!vr) return;
for(i=0; i<vr->size; i++)
mark(vr->array[i]);
@@ -223,7 +223,7 @@ static void markvec(naRef r)
static void markhash(naRef r)
{
int i;
struct HashRec* hr = r.ref.ptr.hash->rec;
struct HashRec* hr = PTR(r).hash->rec;
if(!hr) return;
for(i=0; i < (1<<hr->lgalloced); i++) {
struct HashNode* hn = hr->table[i];
@@ -244,22 +244,22 @@ static void mark(naRef r)
if(IS_NUM(r) || IS_NIL(r))
return;
if(r.ref.ptr.obj->mark == 1)
if(PTR(r).obj->mark == 1)
return;
r.ref.ptr.obj->mark = 1;
switch(r.ref.ptr.obj->type) {
PTR(r).obj->mark = 1;
switch(PTR(r).obj->type) {
case T_VEC: markvec(r); break;
case T_HASH: markhash(r); break;
case T_CODE:
mark(r.ref.ptr.code->srcFile);
for(i=0; i<r.ref.ptr.code->nConstants; i++)
mark(r.ref.ptr.code->constants[i]);
mark(PTR(r).code->srcFile);
for(i=0; i<PTR(r).code->nConstants; i++)
mark(PTR(r).code->constants[i]);
break;
case T_FUNC:
mark(r.ref.ptr.func->code);
mark(r.ref.ptr.func->namespace);
mark(r.ref.ptr.func->next);
mark(PTR(r).func->code);
mark(PTR(r).func->namespace);
mark(PTR(r).func->next);
break;
}
}
@@ -270,7 +270,6 @@ static void reap(struct naPool* p)
{
struct Block* b;
int elem, freesz, total = poolsize(p);
p->nfree = 0;
freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total;
freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ);
if(p->freesz < freesz) {
@@ -279,6 +278,9 @@ static void reap(struct naPool* p)
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(elem=0; elem < b->size; elem++) {
struct naObj* o = (struct naObj*)(b->block + elem * p->elemsz);
@@ -287,6 +289,8 @@ static void reap(struct naPool* p)
o->mark = 0;
}
p->freetop = p->nfree;
// allocs of this type until the next collection
globals->allocCount += total/2;
@@ -299,7 +303,6 @@ static void reap(struct naPool* p)
if(need > 0)
newBlock(p, need);
}
p->freetop = p->nfree;
}
// Does the swap, returning the old value

View File

@@ -3,9 +3,7 @@
#define MIN_HASH_SIZE 4
#define EQUAL(a, b) (((a).ref.reftag == (b).ref.reftag \
&& (a).ref.ptr.obj == (b).ref.ptr.obj) \
|| naEqual(a, b))
#define EQUAL(a, b) (IDENTICAL(a, b) || naEqual(a, b))
#define HASH_MAGIC 2654435769u
@@ -28,15 +26,15 @@ static unsigned int hashcode(naRef r)
// 2*sizeof(int).
unsigned int* p = (unsigned int*)&(r.num);
return p[0] ^ p[1];
} else if(r.ref.ptr.str->hashcode) {
return r.ref.ptr.str->hashcode;
} else if(PTR(r).str->hashcode) {
return PTR(r).str->hashcode;
} else {
// This is Daniel Bernstein's djb2 hash function that I found
// on the web somewhere. It appears to work pretty well.
unsigned int i, hash = 5831;
for(i=0; i<r.ref.ptr.str->len; i++)
hash = (hash * 33) ^ r.ref.ptr.str->data[i];
r.ref.ptr.str->hashcode = hash;
for(i=0; i<PTR(r).str->len; i++)
hash = (hash * 33) ^ PTR(r).str->data[i];
PTR(r).str->hashcode = hash;
return hash;
}
}
@@ -90,7 +88,7 @@ int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
int col = (HASH_MAGIC * sym->hashcode) >> (32 - h->lgalloced);
struct HashNode* hn = h->table[col];
while(hn) {
if(hn->key.ref.ptr.str == sym) {
if(PTR(hn->key).str == sym) {
*out = hn->val;
return 1;
}
@@ -103,26 +101,32 @@ int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
static struct HashNode* find(struct naHash* hash, naRef key)
{
struct HashRec* h = hash->rec;
if(h) {
struct HashNode* hn = h->table[hashcolumn(h, key)];
while(hn) {
if(EQUAL(key, hn->key))
return hn;
hn = hn->next;
}
}
struct HashNode* hn;
if(!h) return 0;
for(hn = h->table[hashcolumn(h, key)]; hn; hn = hn->next)
if(EQUAL(key, hn->key))
return hn;
return 0;
}
// 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->type = T_STR;
str->data = (unsigned char*)key;
str->hashcode = 0;
while(key[str->len]) str->len++;
*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)
@@ -146,7 +150,7 @@ void naHash_cset(naRef hash, char* key, naRef val)
int naHash_get(naRef hash, naRef key, naRef* out)
{
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; }
}
return 0;
@@ -156,7 +160,7 @@ int naHash_get(naRef hash, naRef key, naRef* out)
int naHash_tryset(naRef hash, naRef key, naRef val)
{
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;
return n != 0;
}
@@ -173,7 +177,7 @@ void naHash_newsym(struct naHash* hash, naRef* sym, naRef* val)
struct HashRec* h = hash->rec;
while(!h || h->size >= 1<<h->lgalloced)
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);
}
@@ -196,10 +200,10 @@ void naHash_set(naRef hash, naRef key, naRef val)
struct HashRec* h;
struct HashNode* n;
if(!IS_HASH(hash)) return;
if((n = find(hash.ref.ptr.hash, key))) { n->val = val; return; }
h = hash.ref.ptr.hash->rec;
if((n = find(PTR(hash).hash, key))) { n->val = val; return; }
h = PTR(hash).hash->rec;
while(!h || h->size >= 1<<h->lgalloced)
h = resize(hash.ref.ptr.hash);
h = resize(PTR(hash).hash);
col = hashcolumn(h, key);
INSERT(h, key, val, hashcolumn(h, key));
chkcycle(h->table[col], h->size - h->dels);
@@ -207,7 +211,7 @@ void naHash_set(naRef hash, naRef key, naRef val)
void naHash_delete(naRef hash, naRef key)
{
struct HashRec* h = hash.ref.ptr.hash->rec;
struct HashRec* h = PTR(hash).hash->rec;
int col;
struct HashNode *last=0, *hn;
if(!IS_HASH(hash) || !h) return;
@@ -228,7 +232,7 @@ void naHash_delete(naRef hash, naRef key)
void naHash_keys(naRef dst, naRef hash)
{
int i;
struct HashRec* h = hash.ref.ptr.hash->rec;
struct HashRec* h = PTR(hash).hash->rec;
if(!IS_HASH(hash) || !h) return;
for(i=0; i<(1<<h->lgalloced); i++) {
struct HashNode* hn = h->table[i];
@@ -241,7 +245,7 @@ void naHash_keys(naRef dst, 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;
return h->size - h->dels;
}

View File

@@ -11,7 +11,7 @@ naGhostType naIOGhostType = { ghostDestroy };
static struct naIOGhost* ioghost(naRef r)
{
if(naGhost_type(r) == &naIOGhostType)
if(naGhost_type(r) == &naIOGhostType && IOGHOST(r)->handle)
return naGhost_ptr(r);
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();
if(!g || !MUTABLE(str) || !IS_NUM(len))
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");
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));
}
@@ -44,8 +44,8 @@ static naRef f_write(naContext c, naRef me, int argc, naRef* args)
naRef str = argc > 1 ? args[1] : naNil();
if(!g || !IS_STR(str))
naRuntimeError(c, "bad argument to write()");
return naNum(g->type->write(c, g->handle, (char*)str.ref.ptr.str->data,
str.ref.ptr.str->len));
return naNum(g->type->write(c, g->handle, (char*)PTR(str).str->data,
PTR(str).str->len));
}
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)
{
ioclose(0, f);
if(f != stdin && f != stdout && f != stderr)
ioclose(0, f);
}
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 mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
if(!IS_STR(file)) naRuntimeError(c, "bad argument to open()");
f = fopen((char*)file.ref.ptr.str->data,
IS_STR(mode) ? (const char*)mode.ref.ptr.str->data : "r");
f = fopen((char*)PTR(file).str->data,
IS_STR(mode) ? (const char*)PTR(mode).str->data : "rb");
if(!f) naRuntimeError(c, strerror(errno));
return naIOGhost(c, f);
}
@@ -169,7 +170,8 @@ static naRef f_readln(naContext ctx, naRef me, int argc, naRef* args)
if(c == '\r') {
char c2 = getcguard(ctx, g->handle, buf);
if(c2 != EOF && c2 != '\n')
ungetc(c2, g->handle);
if(EOF == ungetc(c2, g->handle))
break;
break;
}
buf[i++] = c;
@@ -186,7 +188,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
struct stat s;
naRef result, path = argc > 0 ? naStringValue(ctx, args[0]) : naNil();
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();
naRuntimeError(ctx, strerror(errno));
}
@@ -199,7 +201,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
return result;
}
static struct func { char* name; naCFunction func; } funcs[] = {
static naCFuncItem funcs[] = {
{ "close", f_close },
{ "read", f_read },
{ "write", f_write },
@@ -208,26 +210,17 @@ static struct func { char* name; naCFunction func; } funcs[] = {
{ "open", f_open },
{ "readln", f_readln },
{ "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));
naHash_set(hash, naInternSymbol(name), val);
}
naRef naIOLib(naContext c)
{
naRef ns = naNewHash(c);
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));
naRef ns = naGenLib(c, funcs);
naAddSym(c, ns, "SEEK_SET", naNum(SEEK_SET));
naAddSym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
naAddSym(c, ns, "SEEK_END", naNum(SEEK_END));
naAddSym(c, ns, "stdin", naIOGhost(c, stdin));
naAddSym(c, ns, "stdout", naIOGhost(c, stdout));
naAddSym(c, ns, "stderr", naIOGhost(c, stderr));
return ns;
}

View File

@@ -109,7 +109,20 @@ static int lineEnd(struct Parser* p, int line)
static void newToken(struct Parser* p, int pos, int type,
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->type = type;
@@ -119,17 +132,18 @@ static void newToken(struct Parser* p, int pos, int type,
tok->num = num;
tok->parent = &p->tree;
tok->next = 0;
tok->prev = p->tree.lastChild;
tok->prev = last;
tok->children = 0;
tok->lastChild = 0;
// Context sensitivity hack: a "-" following a binary operator of
// higher precedence (MUL and DIV, basically) must be a unary
// negation. Needed to get precedence right in the parser for
// expressiong like "a * -2"
if(type == TOK_MINUS && tok->prev)
if(tok->prev->type == TOK_MUL || tok->prev->type == TOK_DIV)
// equal or higher precedence must be a unary negation. Needed to
// get precedence right in the parser for expressiong like "a * -2"
if(type == TOK_MINUS && tok->prev) {
int pt = tok->prev->type;
if(pt==TOK_PLUS||pt==TOK_MINUS||pt==TOK_CAT||pt==TOK_MUL||pt==TOK_DIV)
tok->type = type = TOK_NEG;
}
if(!p->tree.children) p->tree.children = 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 't': *cOut = '\t'; break;
case '\\': *cOut = '\\'; break;
case '`': *cOut = '`'; break;
case 'x':
if(len < 4) error(p, "unterminated string", 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)
{
if(len != 1) error(p, "character constant not single character", index);
newToken(p, index, TOK_LITERAL, 0, 0, *s);
int n, c;
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
@@ -317,6 +333,7 @@ static int tryLexemes(struct Parser* p, int index, int* lexemeOut)
return best;
}
#define ISNUM(c) ((c) >= '0' && (c) <= '9')
void naLex(struct Parser* p)
{
int i = 0;
@@ -338,7 +355,8 @@ void naLex(struct Parser* p)
i = lexStringLiteral(p, i, c);
break;
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;
}

View File

@@ -5,6 +5,7 @@
#include <string.h>
#ifdef _MSC_VER // sigh...
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif
@@ -14,9 +15,14 @@
#define NEWSTR(c, s, l) naStr_fromdata(naNewString(c), s, l)
#define NEWCSTR(c, s) NEWSTR(c, s, strlen(s))
static naRef size(naContext c, naRef 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(naIsVector(args[0])) return naNum(naVec_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();
}
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];
if(!naIsHash(h)) return naNil();
naRef v, h = argc > 0 ? args[0] : naNil();
if(!naIsHash(h)) ARGERR();
v = naNewVector(c);
naHash_keys(v, h);
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;
if(argc < 2) return naNil();
if(!naIsVector(args[0])) return naNil();
if(argc < 2 || !naIsVector(args[0])) ARGERR();
for(i=1; i<argc; i++) naVec_append(args[0], args[i]);
return args[0];
}
static naRef pop(naContext c, naRef me, int argc, naRef* args)
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]);
}
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) return naNil();
sz = (int)naNumValue(args[1]).num;
if(!naIsVector(args[0])) return naNil();
naVec_setsize(args[0], sz);
if(argc < 2 || !naIsVector(args[0])) ARGERR();
naVec_setsize(args[0], (int)naNumValue(args[1]).num);
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;
naRef nlen, result, v = args[0];
@@ -68,7 +70,7 @@ static naRef subvec(naContext c, naRef me, int argc, naRef* args)
if(!naIsNil(nlen))
len = (int)nlen.num;
if(!naIsVector(v) || start < 0 || start > naVec_size(v) || len < 0)
return naNil();
ARGERR();
if(naIsNil(nlen) || len > naVec_size(v) - start)
len = naVec_size(v) - start;
result = naNewVector(c);
@@ -78,13 +80,14 @@ static naRef subvec(naContext c, naRef me, int argc, naRef* args)
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]);
return naNil();
if(argc < 2 || !naIsHash(args[0])) ARGERR();
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) {
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);
else n.num = floor(n.num);
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();
}
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();
}
@@ -110,7 +114,7 @@ static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
char *a, *b;
int i, alen, blen;
if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1]))
naRuntimeError(c, "bad argument to cmp");
ARGERR();
a = naStr_data(args[0]);
alen = naStr_len(args[0]);
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));
}
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();
naRef startR = argc > 1 ? naNumValue(args[1]) : naNil();
naRef lenR = argc > 2 ? naNumValue(args[2]) : naNil();
int start, len;
if(!naIsString(src)) return naNil();
if(naIsNil(startR)) return naNil();
start = (int)startR.num;
if(naIsNil(lenR)) {
len = naStr_len(src) - start;
if(len < 0) return naNil();
} else {
lenR = naNumValue(lenR);
if(naIsNil(lenR)) return naNil();
len = (int)lenR.num;
}
int start, len, srclen;
naRef src = argc > 0 ? args[0] : naNil();
naRef startr = argc > 1 ? naNumValue(args[1]) : naNil();
naRef lenr = argc > 2 ? naNumValue(args[2]) : naNil();
if(!naIsString(src)) ARGERR();
if(naIsNil(startr) || !naIsNum(startr)) ARGERR();
if(!naIsNil(lenr) && !naIsNum(lenr)) ARGERR();
srclen = naStr_len(src);
start = (int)startr.num;
len = naIsNum(lenr) ? (int)lenr.num : (srclen - start);
if(start < 0) start += srclen;
if(start < 0) start = len = 0;
if(start >= srclen) start = len = 0;
if(len < 0) len = 0;
if(len > srclen - start) len = srclen - start;
return naStr_substr(naNewString(c), src, start, len);
}
static naRef f_chr(naContext c, naRef me, int argc, naRef* args)
{
char chr[1];
naRef cr = argc ? naNumValue(args[0]) : naNil();
if(IS_NIL(cr)) naRuntimeError(c, "chr argument not string");
naRef cr = argc > 0 ? naNumValue(args[0]) : naNil();
if(IS_NIL(cr)) ARGERR();
chr[0] = (char)cr.num;
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 key = argc > 1 ? args[1] : naNil();
if(naIsNil(hash) || naIsNil(key)) return naNil();
if(naIsNil(hash) || naIsNil(key)) ARGERR();
if(!naIsHash(hash)) return naNil();
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();
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(naIsFunc(r)) t = "func";
else if(naIsGhost(r)) t = "ghost";
r = NEWCSTR(c, t);
return r;
return NEWCSTR(c, t);
}
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)
@@ -184,10 +200,20 @@ static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
if(!naIsString(script) || !naIsString(fname)) return naNil();
code = naParseCode(c, fname, 1,
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);
}
// 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)
{
naContext subc;
@@ -199,41 +225,49 @@ static naRef f_call(naContext c, naRef me, int argc, naRef* args)
if(!IS_HASH(callme)) callme = naNil();
if(!IS_HASH(callns)) callns = naNil();
if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
naRuntimeError(c, "bad argument to call()");
subc = naNewContext();
subc->callParent = c;
c->callChild = subc;
vr = IS_NIL(callargs) ? 0 : callargs.ref.ptr.vec->rec;
ARGERR();
subc = naSubContext(c);
vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec;
result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
callme, callns);
c->callChild = 0;
if(argc > 2 && IS_VEC(args[argc-1])) {
naRef v = args[argc-1];
if(!IS_NIL(subc->dieArg)) naVec_append(v, subc->dieArg);
else if(naGetError(subc))
naVec_append(v, NEWCSTR(subc, naGetError(subc)));
if(naVec_size(v)) {
int i, sd = naStackDepth(subc);
for(i=0; i<sd; i++) {
naVec_append(v, naGetSourceFile(subc, i));
naVec_append(v, naNum(naGetLine(subc, i)));
}
if(!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)));
}
}
naFreeContext(subc);
return result;
return naNil();
}
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__");
return naNil(); // never executes
}
// Wrapper around vsnprintf, iteratively increasing the buffer size
// until it fits. Returned buffer should be freed by the caller.
char* dosprintf(char* f, ...)
static char* dosprintf(char* f, ...)
{
char* buf;
va_list va;
@@ -259,7 +293,7 @@ char* dosprintf(char* f, ...)
// all of ANSI C's syntax except for the "length modifier" feature.
// Note: this does not validate the format character returned in
// "type". That is the caller's job.
static char* nextFormat(naContext ctx, char* f, char** out, int* len, char* type)
static char* nextFormat(naContext c, char* f, char** out, int* len, char* type)
{
// Skip to the start of the format string
while(*f && *f != '%') f++;
@@ -274,44 +308,44 @@ static char* nextFormat(naContext ctx, char* f, char** out, int* len, char* type
for(p1 = *out + 1; p1 < f; p1++)
for(p2 = p1+1; p2 < f; 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++;
if(*f && *f == '.') f++;
while(*f && *f >= '0' && *f <= '9') f++;
if(!*f) naRuntimeError(ctx, "invalid format string");
if(!*f) naRuntimeError(c, "invalid format string");
*type = *f++;
*len = f - *out;
return f;
}
#define ERR(m) naRuntimeError(ctx, m)
#define APPEND(r) result = naStr_concat(naNewString(ctx), result, r)
static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
#define ERR(m) naRuntimeError(c, m)
#define APPEND(r) result = naStr_concat(naNewString(c), result, r)
static naRef f_sprintf(naContext c, naRef me, int argc, naRef* args)
{
char t, nultmp, *fstr, *next, *fout=0, *s;
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");
format = naStringValue(ctx, argc > 0 ? args[0] : naNil());
if(naIsNil(format)) ERR("bad format string in sprintf");
if(argc < 1) ERR("not enough arguments to sprintf()");
format = naStringValue(c, argc > 0 ? args[0] : naNil());
if(naIsNil(format)) ERR("bad format string in sprintf()");
s = naStr_data(format);
while((next = nextFormat(ctx, s, &fstr, &flen, &t))) {
APPEND(NEWSTR(ctx, s, fstr-s)); // stuff before the format string
while((next = nextFormat(c, s, &fstr, &flen, &t))) {
APPEND(NEWSTR(c, s, fstr-s)); // stuff before the format string
if(flen == 2 && fstr[1] == '%') {
APPEND(NEWSTR(ctx, "%", 1));
APPEND(NEWSTR(c, "%", 1));
s = next;
continue;
}
if(argn >= argc) ERR("not enough arguments to sprintf");
if(argn >= argc) ERR("not enough arguments to sprintf()");
arg = args[argn++];
nultmp = fstr[flen]; // sneaky nul termination...
fstr[flen] = 0;
if(t == 's') {
arg = naStringValue(ctx, arg);
arg = naStringValue(c, arg);
if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
else fout = dosprintf(fstr, naStr_data(arg));
} else {
@@ -328,43 +362,42 @@ static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
ERR("invalid sprintf format type");
}
fstr[flen] = nultmp;
APPEND(NEWSTR(ctx, fout, strlen(fout)));
APPEND(NEWSTR(c, fout, strlen(fout)));
naFree(fout);
s = next;
}
APPEND(NEWSTR(ctx, s, strlen(s)));
APPEND(NEWSTR(c, s, strlen(s)));
return result;
}
// FIXME: handle ctx->callParent frames too!
static naRef f_caller(naContext ctx, naRef me, int argc, naRef* args)
// FIXME: needs to honor subcontext list
static naRef f_caller(naContext c, naRef me, int argc, naRef* args)
{
int fidx;
struct Frame* frame;
naRef result, fr = argc ? naNumValue(args[0]) : naNum(1);
if(IS_NIL(fr)) naRuntimeError(ctx, "non numeric argument to caller()");
if(IS_NIL(fr)) ARGERR();
fidx = (int)fr.num;
if(fidx > ctx->fTop - 1) return naNil();
frame = &ctx->fStack[ctx->fTop - 1 - fidx];
result = naNewVector(ctx);
if(fidx > c->fTop - 1) return naNil();
frame = &c->fStack[c->fTop - 1 - fidx];
result = naNewVector(c);
naVec_append(result, frame->locals);
naVec_append(result, frame->func);
naVec_append(result, frame->func.ref.ptr.func->code.ref.ptr.code->srcFile);
naVec_append(result, naNum(naGetLine(ctx, fidx)));
naVec_append(result, PTR(PTR(frame->func).func->code).code->srcFile);
naVec_append(result, naNum(naGetLine(c, fidx)));
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;
struct naFunc* f;
naRef func = argc > 0 ? args[0] : naNil();
naRef idx = argc > 1 ? naNumValue(args[1]) : naNum(0);
if(!IS_FUNC(func) || IS_NIL(idx))
naRuntimeError(ctx, "bad arguments to closure()");
if(!IS_FUNC(func) || IS_NIL(idx)) ARGERR();
i = (int)idx.num;
f = func.ref.ptr.func;
while(i > 0 && f) { i--; f = f->next.ref.ptr.func; }
f = PTR(func).func;
while(i > 0 && f) { i--; f = PTR(f->next).func; }
if(!f) return naNil();
return f->namespace;
}
@@ -384,40 +417,38 @@ static int find(unsigned char* a, int al, unsigned char* s, int sl, int start)
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;
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
naRuntimeError(ctx, "bad/missing argument to find");
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
if(argc > 2) start = (int)(naNumValue(args[2]).num);
return naNum(find(args[0].ref.ptr.str->data, args[0].ref.ptr.str->len,
args[1].ref.ptr.str->data, args[1].ref.ptr.str->len,
return naNum(find(PTR(args[0]).str->data, PTR(args[0]).str->len,
PTR(args[1]).str->data, PTR(args[1]).str->len,
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;
char *s, *d, *s0;
naRef result;
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
naRuntimeError(ctx, "bad/missing argument to split");
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
d = naStr_data(args[0]); dl = naStr_len(args[0]);
s = naStr_data(args[1]); sl = naStr_len(args[1]);
result = naNewVector(ctx);
result = naNewVector(c);
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;
}
s0 = s;
for(i=0; i <= sl-dl; i++) {
if(match((unsigned char*)(s+i), (unsigned char*)d, dl)) {
naVec_append(result, NEWSTR(ctx, s0, s+i-s0));
naVec_append(result, NEWSTR(c, s0, s+i-s0));
s0 = s + i + dl;
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;
}
@@ -425,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
// precision. The 5x loop guarantees that we get a full double worth
// of precision even for 15 bit (Win32...) rand() implementations.
static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args)
static naRef f_rand(naContext c, naRef me, int argc, naRef* args)
{
int i;
double r = 0;
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);
return naNil();
}
@@ -438,36 +469,91 @@ static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args)
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 hash = argc > 1 ? args[1] : naNewHash(ctx);
naRef hash = argc > 1 ? args[1] : naNewHash(c);
naRef next = argc > 2 ? args[2] : naNil();
if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash))
naRuntimeError(ctx, "bad argument to bind");
func = naNewFunc(ctx, func.ref.ptr.func->code);
func.ref.ptr.func->namespace = hash;
func.ref.ptr.func->next = next;
ARGERR();
func = naNewFunc(c, PTR(func).func->code);
PTR(func).func->namespace = hash;
PTR(func).func->next = next;
return func;
}
struct func { char* name; naCFunction func; };
static struct func funcs[] = {
{ "size", size },
{ "keys", keys },
{ "append", append },
{ "pop", pop },
{ "setsize", setsize },
{ "subvec", subvec },
{ "delete", delete },
{ "int", intf },
{ "num", num },
{ "streq", streq },
/* We use the "SortRec" gadget for two reasons: first, because ANSI
* qsort() doesn't give us a mechanism for passing a "context" pointer
* to the comparison routine we have to store one in every sorted
* record. Second, using an index into the original vector here
* allows us to make the sort stable in the event of a zero returned
* from the Nasal comparison function. */
struct SortData { naContext ctx, subc; struct SortRec* recs;
naRef* elems; int n; naRef fn; };
struct SortRec { struct SortData* sd; int i; };
static int sortcmp(struct SortRec* a, struct SortRec* b)
{
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 },
{ "substr", substr },
{ "substr", f_substr },
{ "chr", f_chr },
{ "contains", contains },
{ "typeof", typeOf },
{ "contains", f_contains },
{ "typeof", f_typeof },
{ "ghosttype", f_ghosttype },
{ "compile", f_compile },
{ "call", f_call },
{ "die", f_die },
@@ -478,17 +564,11 @@ static struct func funcs[] = {
{ "split", f_split },
{ "rand", f_rand },
{ "bind", f_bind },
{ "sort", f_sort },
{ 0 }
};
naRef naStdLib(naContext c)
naRef naInit_std(naContext c)
{
naRef namespace = naNewHash(c);
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;
return naGenLib(c, funcs);
}

View File

@@ -1,16 +1,32 @@
#include <math.h>
#include <string.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)
{
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
if(naIsNil(a))
naRuntimeError(c, "non numeric argument to sin()");
a.num = sin(a.num);
return a;
return VALIDATE(a);
}
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))
naRuntimeError(c, "non numeric argument to cos()");
a.num = cos(a.num);
return a;
return VALIDATE(a);
}
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))
naRuntimeError(c, "non numeric argument to exp()");
a.num = exp(a.num);
return a;
return VALIDATE(a);
}
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))
naRuntimeError(c, "non numeric argument to ln()");
a.num = log(a.num);
return a;
return VALIDATE(a);
}
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))
naRuntimeError(c, "non numeric argument to sqrt()");
a.num = sqrt(a.num);
return a;
return VALIDATE(a);
}
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))
naRuntimeError(c, "non numeric argument to atan2()");
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 },
{ "cos", f_cos },
{ "exp", f_exp },
{ "ln", f_ln },
{ "sqrt", f_sqrt },
{ "atan2", f_atan2 },
{ 0 }
};
naRef naMathLib(naContext c)
naRef naInit_math(naContext c)
{
naRef name, namespace = naNewHash(c);
int i, n = sizeof(funcs)/sizeof(struct func);
for(i=0; i<n; i++) {
naRef code = naNewCCode(c, funcs[i].func);
naRef name = naStr_fromdata(naNewString(c),
funcs[i].name, strlen(funcs[i].name));
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;
naRef ns = naGenLib(c, funcs);
naAddSym(c, ns, "pi", naNum(3.14159265358979323846));
naAddSym(c, ns, "e", naNum(2.7182818284590452354));
return ns;
}

View File

@@ -23,14 +23,13 @@ void naTempSave(naContext c, naRef r)
naFree(c->temps);
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 r;
r.ref.reftag = NASAL_REFTAG;
r.ref.ptr.obj = o;
SETPTR(r, o);
o->type = type;
return r;
}
@@ -78,23 +77,23 @@ naRef naNew(struct Context* c, int type)
naRef naNewString(struct Context* c)
{
naRef s = naNew(c, T_STR);
s.ref.ptr.str->len = 0;
s.ref.ptr.str->data = 0;
s.ref.ptr.str->hashcode = 0;
PTR(s).str->len = 0;
PTR(s).str->data = 0;
PTR(s).str->hashcode = 0;
return s;
}
naRef naNewVector(struct Context* c)
{
naRef r = naNew(c, T_VEC);
r.ref.ptr.vec->rec = 0;
PTR(r).vec->rec = 0;
return r;
}
naRef naNewHash(struct Context* c)
{
naRef r = naNew(c, T_HASH);
r.ref.ptr.hash->rec = 0;
PTR(r).hash->rec = 0;
return r;
}
@@ -106,59 +105,57 @@ naRef naNewCode(struct Context* c)
naRef naNewCCode(struct Context* c, naCFunction fptr)
{
naRef r = naNew(c, T_CCODE);
r.ref.ptr.ccode->fptr = fptr;
PTR(r).ccode->fptr = fptr;
return r;
}
naRef naNewFunc(struct Context* c, naRef code)
{
naRef func = naNew(c, T_FUNC);
func.ref.ptr.func->code = code;
func.ref.ptr.func->namespace = naNil();
func.ref.ptr.func->next = naNil();
PTR(func).func->code = code;
PTR(func).func->namespace = naNil();
PTR(func).func->next = naNil();
return func;
}
naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
{
naRef ghost = naNew(c, T_GHOST);
ghost.ref.ptr.ghost->gtype = type;
ghost.ref.ptr.ghost->ptr = ptr;
PTR(ghost).ghost->gtype = type;
PTR(ghost).ghost->ptr = ptr;
return ghost;
}
naGhostType* naGhost_type(naRef ghost)
{
if(!IS_GHOST(ghost)) return 0;
return ghost.ref.ptr.ghost->gtype;
return PTR(ghost).ghost->gtype;
}
void* naGhost_ptr(naRef ghost)
{
if(!IS_GHOST(ghost)) return 0;
return ghost.ref.ptr.ghost->ptr;
return PTR(ghost).ghost->ptr;
}
naRef naNil()
{
naRef r;
r.ref.reftag = NASAL_REFTAG;
r.ref.ptr.obj = 0;
naRef r;
SETPTR(r, 0);
return r;
}
naRef naNum(double num)
{
naRef r;
r.ref.reftag = ~NASAL_REFTAG;
r.num = num;
SETNUM(r, num);
return r;
}
int naEqual(naRef a, naRef b)
{
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)
if(IS_NIL(a) || IS_NIL(b))
return 0;
@@ -182,10 +179,10 @@ int naStrEqual(naRef a, naRef b)
int i;
if(!(IS_STR(a) && IS_STR(b)))
return 0;
if(a.ref.ptr.str->len != b.ref.ptr.str->len)
if(PTR(a).str->len != PTR(b).str->len)
return 0;
for(i=0; i<a.ref.ptr.str->len; i++)
if(a.ref.ptr.str->data[i] != b.ref.ptr.str->data[i])
for(i=0; i<PTR(a).str->len; i++)
if(PTR(a).str->data[i] != PTR(b).str->data[i])
return 0;
return 1;
}
@@ -214,3 +211,24 @@ int naIsFunc(naRef r) { return IS_FUNC(r); }
int naIsCode(naRef r) { return IS_CODE(r); }
int naIsCCode(naRef r) { return IS_CCODE(r); }
int naIsGhost(naRef r) { return IS_GHOST(r); }
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
simgear/nasal/naref.h Normal file
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

View File

@@ -4,73 +4,17 @@
extern "C" {
#endif
#ifndef BYTE_ORDER
#include "naref.h"
# if (BSD >= 199103)
# include <machine/endian.h>
# elif defined(__CYGWIN__) || defined(__MINGW32__)
# include <sys/param.h>
# elif defined(linux)
# include <endian.h>
# else
# 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
#if __GNUC__ > 2
/* This marks the function as having no side effects and depending on
* nothing but its arguments, which allows the optimizer to avoid
* duplicate calls to naNil(). */
#define GCC_PURE __attribute__((__pure__))
#else
#define GCC_PURE
#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;
// The function signature for an extension function:
@@ -80,7 +24,21 @@ typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args);
naContext naNewContext();
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.
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.
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,
char* buf, int len, int* errLine);
// Binds a bare code object (as returned from naParseCode) with a
// 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);
// Similar, but it binds to the current context's closure (i.e. the
// namespace at the top of the current call stack).
naRef naBindToContext(naContext ctx, naRef code);
// Call a code or function object with the specifed arguments "on" the
// specified object and using the specified hash for the local
// variables. Any of args, obj or locals may be nil.
naRef naCall(naContext ctx, naRef func, int argc, naRef* args, naRef obj, naRef locals);
// Call a code or function object with the specified arguments "on"
// the specified object and using the specified hash for the local
// variables. Passing a null args array skips the parameter variables
// (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
// longjmp call to a handler in naCall() and DOES NOT RETURN. It is
// intended for use in library code that cannot otherwise report an
// error via the return value, and MUST be used carefully. If in
// doubt, return naNil() as your error condition.
void naRuntimeError(naContext ctx, char* msg);
// doubt, return naNil() as your error condition. Works like
// printf().
void naRuntimeError(naContext c, const char* fmt, ...);
// Call a method on an object (NOTE: func is a function binding, *not*
// a code object as returned from naParseCode).
naRef naMethod(naContext ctx, naRef func, naRef object);
// "Re-throws" a runtime error caught from the subcontext. Acts as a
// naRuntimeError() called on the parent context. Does not return.
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
// 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
naRef naMathLib(naContext c);
naRef naBitsLib(naContext c);
naRef naIOLib(naContext c);
naRef naRegexLib(naContext c);
naRef naUnixLib(naContext c);
naRef naInit_math(naContext c);
naRef naInit_bits(naContext c);
naRef naInit_io(naContext c);
naRef naInit_regex(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 naGetLine(naContext ctx, int frame);
naRef naGetSourceFile(naContext ctx, int frame);
char* naGetError(naContext ctx);
// Type predicates
int naIsNil(naRef r);
int naIsNum(naRef r);
int naIsString(naRef r);
int naIsScalar(naRef r);
int naIsVector(naRef r);
int naIsHash(naRef r);
int naIsCode(naRef r);
int naIsFunc(naRef r);
int naIsCCode(naRef r);
int naIsNil(naRef r) GCC_PURE;
int naIsNum(naRef r) GCC_PURE;
int naIsString(naRef r) GCC_PURE;
int naIsScalar(naRef r) GCC_PURE;
int naIsVector(naRef r) GCC_PURE;
int naIsHash(naRef r) GCC_PURE;
int naIsCode(naRef r) GCC_PURE;
int naIsFunc(naRef r) GCC_PURE;
int naIsCCode(naRef r) GCC_PURE;
// Allocators/generators:
naRef naNil();
naRef naNum(double num);
naRef naNil() GCC_PURE;
naRef naNum(double num) GCC_PURE;
naRef naNewString(naContext c);
naRef naNewVector(naContext c);
naRef naNewHash(naContext c);
@@ -158,10 +146,10 @@ naRef naNewFunc(naContext c, naRef code);
naRef naNewCCode(naContext c, naCFunction fptr);
// Some useful conversion/comparison routines
int naEqual(naRef a, naRef b);
int naStrEqual(naRef a, naRef b);
int naTrue(naRef b);
naRef naNumValue(naRef n);
int naEqual(naRef a, naRef b) GCC_PURE;
int naStrEqual(naRef a, naRef b) GCC_PURE;
int naTrue(naRef b) GCC_PURE;
naRef naNumValue(naRef n) GCC_PURE;
naRef naStringValue(naContext c, naRef n);
// String utilities:
@@ -192,6 +180,7 @@ void naHash_keys(naRef dst, naRef hash);
// Ghost utilities:
typedef struct naGhostType {
void (*destroy)(void* ghost);
const char* name;
} naGhostType;
naRef naNewGhost(naContext c, naGhostType* t, void* 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
// modify Nasal data without fear that such data may be "lost" by the
// garbage collector (the C stack is not examined in GC!). This
// disallows garbage collection until the current thread can be
// blocked. The lock should be acquired whenever modifications to
// Nasal objects are made. It need not be acquired when only read
// access is needed. It MUST NOT be acquired by naCFunction's, as
// those are called with the lock already held; acquiring two locks
// for the same thread will cause a deadlock when the GC is invoked.
// It should be UNLOCKED by naCFunction's when they are about to do
// any long term non-nasal processing and/or blocking I/O.
// garbage collector (nasal data the C stack is not examined in GC!).
// This disallows garbage collection until the current thread can be
// blocked. The lock should be acquired whenever nasal objects are
// being modified. It need not be acquired when only read access is
// needed, PRESUMING that the Nasal data being read is findable by the
// collector (via naSave, for example) and that another Nasal thread
// cannot or will not delete the reference to the data. It MUST NOT
// be acquired by naCFunction's, as those are called with the lock
// already held; acquiring two locks for the same thread will cause a
// deadlock when the GC is invoked. It should be UNLOCKED by
// naCFunction's when they are about to do any long term non-nasal
// processing and/or blocking I/O. 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 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
} // extern "C"
#endif

View File

@@ -1,11 +1,10 @@
#include <setjmp.h>
#include <string.h>
#include "parse.h"
// Static precedence table, from low (loose binding, do first) to high
// (tight binding, do last).
enum { PREC_BINARY, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
#define MAX_PREC_TOKS 6
struct precedence {
int toks[MAX_PREC_TOKS];
@@ -32,8 +31,10 @@ struct precedence {
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->errLine = line;
longjmp(p->jumpHandle, 1);
}
@@ -205,11 +206,83 @@ static struct Token* emptyToken(struct Parser* p)
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
// being the child of a func keyword, etc...
static void fixBlockStructure(struct Parser* p, struct Token* start)
{
struct Token *t, *c;
fixBracelessBlocks(p, start);
t = start;
while(t) {
switch(t->type) {
@@ -287,8 +360,8 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
addSemi = 1;
break;
}
if(t->next && t->next->type == TOK_SEMI)
addSemi = 0; // don't bother if it's already there!
if(!t->next || t->next->type == TOK_SEMI || t->next->type == TOK_COMMA)
addSemi = 0; // don't bother, no need
if(addSemi) {
struct Token* semi = emptyToken(p);
semi->type = TOK_SEMI;
@@ -297,6 +370,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
semi->prev = t;
semi->parent = t->parent;
if(semi->next) semi->next->prev = semi;
else semi->parent->lastChild = semi;
t->next = semi;
t = semi; // don't bother checking the new one
}
@@ -455,6 +529,8 @@ static struct Token* parsePrecedence(struct Parser* p,
if(!top)
return parsePrecedence(p, start, end, level+1);
top->rule = rule;
if(left) {
left->next = right;
left->prev = 0;
@@ -508,7 +584,7 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
// Catch parser errors here.
*errLine = 0;
if(setjmp(p.jumpHandle)) {
c->error = p.err;
strncpy(c->error, p.err, sizeof(c->error));
*errLine = p.errLine;
return naNil();
}
@@ -540,5 +616,3 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
return codeObj;
}

View File

@@ -19,11 +19,15 @@ enum {
TOK_FORINDEX
};
// Precedence rules
enum { PREC_BINARY=1, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
struct Token {
int type;
int line;
char* str;
int strlen;
int rule;
double num;
struct Token* parent;
struct Token* next;
@@ -94,6 +98,7 @@ void naParseInit(struct Parser* p);
void* naParseAlloc(struct Parser* p, int bytes);
void naParseDestroy(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);
void naParse(struct Parser* p);

View File

@@ -14,13 +14,13 @@ static int fromnum(double val, unsigned char* s);
int naStr_len(naRef s)
{
if(!IS_STR(s)) return 0;
return s.ref.ptr.str->len;
return PTR(s).str->len;
}
char* naStr_data(naRef s)
{
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)
@@ -33,24 +33,24 @@ static void setlen(struct naStr* s, int sz)
naRef naStr_buf(naRef dst, int len)
{
setlen(dst.ref.ptr.str, len);
naBZero(dst.ref.ptr.str->data, len);
setlen(PTR(dst).str, len);
naBZero(PTR(dst).str->data, len);
return dst;
}
naRef naStr_fromdata(naRef dst, char* data, int len)
{
if(!IS_STR(dst)) return naNil();
setlen(dst.ref.ptr.str, len);
memcpy(dst.ref.ptr.str->data, data, len);
setlen(PTR(dst).str, len);
memcpy(PTR(dst).str->data, data, len);
return dst;
}
naRef naStr_concat(naRef dest, naRef s1, naRef s2)
{
struct naStr* dst = dest.ref.ptr.str;
struct naStr* a = s1.ref.ptr.str;
struct naStr* b = s2.ref.ptr.str;
struct naStr* dst = PTR(dest).str;
struct naStr* a = PTR(s1).str;
struct naStr* b = PTR(s2).str;
if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
setlen(dst, a->len + b->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)
{
struct naStr* dst = dest.ref.ptr.str;
struct naStr* s = str.ref.ptr.str;
struct naStr* dst = PTR(dest).str;
struct naStr* s = PTR(str).str;
if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
if(start + len > s->len) { dst->len = 0; dst->data = 0; return naNil(); }
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)
{
struct naStr* a = s1.ref.ptr.str;
struct naStr* b = s2.ref.ptr.str;
struct naStr* a = PTR(s1).str;
struct naStr* b = PTR(s2).str;
if(a->data == b->data) return 1;
if(a->len != b->len) return 0;
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)
{
struct naStr* dst = dest.ref.ptr.str;
struct naStr* dst = PTR(dest).str;
unsigned char buf[DIGITS+8];
setlen(dst, fromnum(num, buf));
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)
{
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)
{
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)

View File

@@ -10,6 +10,12 @@ void* naNewLock()
return lock;
}
void naFreeLock(void* lock)
{
pthread_mutex_destroy(lock);
naFree(lock);
}
void naLock(void* lock)
{
pthread_mutex_lock((pthread_mutex_t*)lock);
@@ -35,6 +41,14 @@ void* naNewSem()
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)
{
struct naSem* sem = (struct naSem*)sh;
@@ -45,11 +59,11 @@ void naSemDown(void* sh)
pthread_mutex_unlock(&sem->lock);
}
void naSemUpAll(void* sh, int count)
void naSemUp(void* sh, int count)
{
struct naSem* sem = (struct naSem*)sh;
pthread_mutex_lock(&sem->lock);
sem->count = count;
sem->count += count;
pthread_cond_broadcast(&sem->cvar);
pthread_mutex_unlock(&sem->lock);
}

View File

@@ -13,9 +13,11 @@ void* naNewLock()
void naLock(void* lock) { EnterCriticalSection((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 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

103
simgear/nasal/threadlib.c Normal file
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
simgear/nasal/utf8lib.c Normal file
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);
}

View File

@@ -28,7 +28,7 @@ void naVec_gcclean(struct naVec* v)
naRef naVec_get(naRef v, int i)
{
if(IS_VEC(v)) {
struct VecRec* r = v.ref.ptr.vec->rec;
struct VecRec* r = PTR(v).vec->rec;
if(r) {
if(i < 0) i += r->size;
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)
{
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;
r->array[i] = o;
}
@@ -49,7 +49,7 @@ void naVec_set(naRef vec, int i, naRef o)
int naVec_size(naRef 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 0;
@@ -58,10 +58,10 @@ int naVec_size(naRef v)
int naVec_append(naRef vec, naRef o)
{
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) {
resize(vec.ref.ptr.vec);
r = vec.ref.ptr.vec->rec;
resize(PTR(vec).vec);
r = PTR(vec).vec->rec;
}
r->array[r->size] = o;
return r->size++;
@@ -72,26 +72,25 @@ int naVec_append(naRef vec, naRef o)
void naVec_setsize(naRef vec, int sz)
{
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);
nv->size = sz;
nv->alloced = sz;
for(i=0; i<sz; i++)
nv->array[i] = (v && i < v->size) ? v->array[i] : naNil();
naFree(v);
vec.ref.ptr.vec->rec = nv;
naGC_swapfree((void**)&(PTR(vec).vec->rec), nv);
}
naRef naVec_removelast(naRef vec)
{
naRef o;
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();
o = v->array[v->size - 1];
v->size--;
if(v->size < (v->alloced >> 1))
resize(vec.ref.ptr.vec);
resize(PTR(vec).vec);
return o;
}
return naNil();

View File

@@ -65,7 +65,6 @@ SGNotCondition::SGNotCondition (SGCondition * condition)
SGNotCondition::~SGNotCondition ()
{
delete _condition;
}
bool
@@ -86,8 +85,6 @@ SGAndCondition::SGAndCondition ()
SGAndCondition::~SGAndCondition ()
{
for (unsigned int i = 0; i < _conditions.size(); i++)
delete _conditions[i];
}
bool
@@ -119,8 +116,6 @@ SGOrCondition::SGOrCondition ()
SGOrCondition::~SGOrCondition ()
{
for (unsigned int i = 0; i < _conditions.size(); i++)
delete _conditions[i];
}
bool
@@ -398,13 +393,11 @@ SGConditional::SGConditional ()
SGConditional::~SGConditional ()
{
delete _condition;
}
void
SGConditional::setCondition (SGCondition * condition)
{
delete _condition;
_condition = condition;
}

View File

@@ -13,6 +13,7 @@
#include <simgear/debug/logstream.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/structure/SGReferenced.hxx>
////////////////////////////////////////////////////////////////////////
@@ -28,7 +29,7 @@
*
* This class should migrate to somewhere more general.
*/
class SGCondition
class SGCondition : public SGReferenced
{
public:
SGCondition ();
@@ -63,12 +64,11 @@ private:
class SGNotCondition : public SGCondition
{
public:
// transfer pointer ownership
SGNotCondition (SGCondition * condition);
virtual ~SGNotCondition ();
virtual bool test () const;
private:
SGCondition * _condition;
SGSharedPtr<SGCondition> _condition;
};
@@ -87,7 +87,7 @@ public:
// transfer pointer ownership
virtual void addCondition (SGCondition * condition);
private:
vector<SGCondition *> _conditions;
std::vector<SGSharedPtr<SGCondition> > _conditions;
};
@@ -106,7 +106,7 @@ public:
// transfer pointer ownership
virtual void addCondition (SGCondition * condition);
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
* active itself, draw itself, and so on.
*/
class SGConditional
class SGConditional : public SGReferenced
{
public:
SGConditional ();
@@ -156,7 +156,7 @@ public:
virtual const SGCondition * getCondition () const { return _condition; }
virtual bool test () const;
private:
SGCondition * _condition;
SGSharedPtr<SGCondition> _condition;
};

View File

@@ -116,7 +116,7 @@ parse_name (const string &path, int &i)
name = ".";
}
if (i < max && path[i] != '/')
throw string("Illegal character after " + name);
throw string("illegal character after " + name);
}
else if (isalpha(path[i]) || path[i] == '_') {
@@ -295,7 +295,7 @@ find_node (SGPropertyNode * current,
else if (components[position].name == "..") {
SGPropertyNode * parent = current->getParent();
if (parent == 0)
throw string("Attempt to move past root with '..'");
throw string("attempt to move past root with '..'");
else
return find_node(parent, components, position + 1, create);
}
@@ -595,11 +595,11 @@ void
SGPropertyNode::trace_write () const
{
#if PROPS_STANDALONE
cerr << "TRACE: Write node " << getPath () << ", value\""
cerr << "TRACE: Write node " << getPath () << ", value \""
<< make_string() << '"' << endl;
#else
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
<< ", value\"" << make_string() << '"');
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
<< ", value \"" << make_string() << '"');
#endif
}
@@ -613,7 +613,7 @@ SGPropertyNode::trace_read () const
cerr << "TRACE: Write node " << getPath () << ", value \""
<< make_string() << '"' << endl;
#else
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
<< ", value \"" << make_string() << '"');
#endif
}
@@ -739,7 +739,11 @@ SGPropertyNode::SGPropertyNode (const char * name,
_attr(READ|WRITE),
_listeners(0)
{
_name = name;
int i = 0;
_name = parse_name(name, i);
if (i != int(strlen(name)) || name[0] == '.')
throw string("plain name expected instead of '") + name + '\'';
_local_val.string_val = 0;
}
@@ -910,6 +914,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.
*/
@@ -927,8 +947,8 @@ SGPropertyNode::removeChild (int pos, bool keep)
if (keep) {
_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->clearValue();
fireChildRemoved(node);
@@ -939,7 +959,7 @@ SGPropertyNode::removeChild (int pos, bool keep)
/**
* Remove a child node
*/
SGPropertyNode_ptr
SGPropertyNode_ptr
SGPropertyNode::removeChild (const char * name, int index, bool keep)
{
SGPropertyNode_ptr ret;
@@ -967,6 +987,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 *
SGPropertyNode::getDisplayName (bool simplify) const
{
@@ -2193,23 +2231,31 @@ SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
}
}
void
SGPropertyNode::hash_table::bucket::erase (const char * key)
bool
SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
{
int i;
for (i = 0; i < _length; i++) {
if (!strcmp(_entries[i]->get_key(), key))
break;
}
if (i < _length) {
for (++i; i < _length; i++) {
_entries[i-1] = _entries[i];
for (int i = 0; i < _length; i++) {
if (_entries[i]->get_value() == node) {
delete _entries[i];
for (++i; i < _length; i++) {
_entries[i-1] = _entries[i];
}
_length--;
return true;
}
_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 ()
: _data_length(0),
@@ -2219,8 +2265,12 @@ SGPropertyNode::hash_table::hash_table ()
SGPropertyNode::hash_table::~hash_table ()
{
for (unsigned int i = 0; i < _data_length; i++)
delete _data[i];
for (unsigned int i = 0; i < _data_length; i++) {
if (_data[i]) {
_data[i]->clear(this);
delete _data[i];
}
}
delete [] _data;
}
@@ -2254,17 +2304,17 @@ SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
}
entry * e = _data[index]->get_entry(key, true);
e->set_value(value);
value->add_linked_node(this);
}
void
SGPropertyNode::hash_table::erase (const char * key)
bool
SGPropertyNode::hash_table::erase (SGPropertyNode * node)
{
if (_data_length == 0)
return;
unsigned int index = hashcode(key) % _data_length;
if (_data[index] == 0)
return;
_data[index]->erase(key);
for (unsigned int i = 0; i < _data_length; i++)
if (_data[i] && _data[i]->erase(node))
return true;
return false;
}
unsigned int

View File

@@ -1110,6 +1110,12 @@ public:
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.
*/
@@ -1183,6 +1189,12 @@ private:
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;
int _index;
@@ -1193,6 +1205,7 @@ private:
SGPropertyNode * _parent;
vector<SGPropertyNode_ptr> _children;
vector<SGPropertyNode_ptr> _removedChildren;
vector<hash_table *> _linkedNodes;
mutable string _path;
mutable string _buffer;
hash_table * _path_cache;
@@ -1223,9 +1236,16 @@ private:
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 {
public:
@@ -1243,7 +1263,7 @@ private:
void set_value (SGPropertyNode * value);
private:
string _key;
SGSharedPtr<SGPropertyNode> _value;
SGSharedPtr<SGPropertyNode> _value;
};
@@ -1255,7 +1275,8 @@ private:
bucket ();
~bucket ();
entry * get_entry (const char * key, bool create = false);
void erase(const char * key);
bool erase (SGPropertyNode * node);
void clear (hash_table * owner);
private:
int _length;
entry ** _entries;
@@ -1267,7 +1288,7 @@ private:
~hash_table ();
SGPropertyNode * get (const char * key);
void put (const char * key, SGPropertyNode * value);
void erase(const char * key);
bool erase (SGPropertyNode * node);
private:
unsigned int hashcode (const char * key);

View File

@@ -229,6 +229,21 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
} catch (sg_io_exception &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");
@@ -432,11 +447,11 @@ doIndent (ostream &output, int indent)
static void
writeAtts (ostream &output, const SGPropertyNode * node)
writeAtts (ostream &output, const SGPropertyNode * node, bool forceindex)
{
int index = node->getIndex();
if (index != 0)
if (index != 0 || forceindex)
output << " n=\"" << index << '"';
#if 0
@@ -484,13 +499,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
const string name = node->getName();
int nChildren = node->nChildren();
bool node_has_value = false;
// If there is a literal value,
// write it first.
if (node->hasValue() && (write_all || node->getAttribute(archive_flag))) {
doIndent(output, indent);
output << '<' << name;
writeAtts(output, node);
writeAtts(output, node, nChildren != 0);
if (node->isAlias() && node->getAliasTarget() != 0) {
output << " alias=\"" << node->getAliasTarget()->getPath()
<< "\"/>" << endl;
@@ -501,13 +517,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
writeData(output, node->getStringValue());
output << "</" << name << '>' << endl;
}
node_has_value = true;
}
// If there are children, write them next.
if (nChildren > 0) {
doIndent(output, indent);
output << '<' << name;
writeAtts(output, node);
writeAtts(output, node, node_has_value);
output << '>' << endl;
for (int i = 0; i < nChildren; i++)
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,
bool write_all, SGPropertyNode::Attribute archive_flag)
{
SGPath path(file.c_str());
path.create_dir(0777);
ofstream output(file.c_str());
if (output.good()) {
writeProperties(output, start_node, write_all, archive_flag);

View File

@@ -19,6 +19,9 @@ waytest_LDADD = \
$(top_builddir)/simgear/math/libsgmath.a \
$(top_builddir)/simgear/debug/libsgdebug.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) \
-lz

View File

@@ -49,7 +49,7 @@ double SGRoute::distance_off_route( double x, double y ) const {
int n1 = current_wp;
sgdVec3 p, p0, p1, d;
sgdSetVec3( p, x, y, 0.0 );
sgdSetVec3( p0,
sgdSetVec3( p0,
route[n0].get_target_lon(), route[n0].get_target_lat(),
0.0 );
sgdSetVec3( p1,
@@ -68,3 +68,50 @@ double SGRoute::distance_off_route( double x, double y ) const {
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 );
}

View File

@@ -32,13 +32,10 @@
# error This library requires C++
#endif
#include <simgear/compiler.h>
#include STL_STRING
#include <vector>
SG_USING_STD(string);
SG_USING_STD(vector);
#include <simgear/route/waypoint.hxx>
@@ -55,6 +52,8 @@ private:
route_list route;
int current_wp;
void update_distance(int index);
public:
/** Constructor */
@@ -73,21 +72,7 @@ public:
* Add waypoint (default), or insert waypoint at position n.
* @param wp a waypoint
*/
void add_waypoint( const SGWayPoint &wp, int n = -1 ) {
if ( n < 0 || n >= (int)route.size() )
route.push_back( wp );
else
route.insert( route.begin() + n, 1, 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 );
}
}
void add_waypoint( const SGWayPoint &wp, int n = -1 );
/**
* Get the number of waypoints (i.e. route length )
* @return route length
@@ -152,14 +137,7 @@ public:
inline void delete_first() { delete_waypoint(0); }
/** Delete waypoint waypoint with index n (last one if n < 0) */
void delete_waypoint( int n = 0 ) {
if ( !route.size() )
return;
if ( n < 0 || n >= (int)route.size() )
n = route.size() - 1;
route.erase( route.begin() + n );
}
void delete_waypoint( int n = 0 );
/**
* Calculate perpendicular distance from the current route segment

View File

@@ -8,8 +8,20 @@
SG_USING_STD(cout);
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;
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, 2, 0, SGWayPoint::CARTESIAN, "3") );
route.add_waypoint( SGWayPoint(4, 2, 0, SGWayPoint::CARTESIAN, "4") );
dump_route(route, "Init");
route.set_current( 1 );
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.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;
}

View File

@@ -32,7 +32,7 @@
// Constructor
SGWayPoint::SGWayPoint( const double lon, const double lat, const double alt,
const modetype m, const string s, const string n ) {
const modetype m, const string& s, const string& n ) {
target_lon = lon;
target_lat = lat;
target_alt = alt;

View File

@@ -91,7 +91,7 @@ public:
*/
SGWayPoint( const double lon = 0.0, const double lat = 0.0,
const double alt = 0.0, const modetype m = WGS84,
const string s = "", const string n = "" );
const string& s = "", const string& n = "" );
/** Destructor */
~SGWayPoint();

View File

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

View File

@@ -37,14 +37,22 @@ SG_USING_STD(map);
# include <math.h>
#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/misc/sg_path.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/scene/model/model.hxx>
#include "mat.hxx"
static map<string, ssgTexture *> _tex_cache;
static map<string, ssgTexture *>::iterator _tex_cache_iter;
static map<string, osg::ref_ptr<osg::Texture2D> > _tex_cache;
////////////////////////////////////////////////////////////////////////
@@ -56,7 +64,7 @@ SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props, cons
{
init();
read_properties( fg_root, props, season );
build_ssg_state( false );
build_state( false );
}
SGMaterial::SGMaterial( const string &texpath )
@@ -66,13 +74,13 @@ SGMaterial::SGMaterial( const string &texpath )
_internal_state st( NULL, texpath, false );
_status.push_back( st );
build_ssg_state( true );
build_state( true );
}
SGMaterial::SGMaterial( ssgSimpleState *s )
SGMaterial::SGMaterial( osg::StateSet *s )
{
init();
set_ssg_state( s );
set_state( s );
}
SGMaterial::~SGMaterial (void)
@@ -141,7 +149,7 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
friction_factor = props->getDoubleValue("friction-factor", 1.0);
rolling_friction = props->getDoubleValue("rolling-friction", 0.02);
bumpiness = props->getDoubleValue("bumpiness", 0.0);
load_resistence = props->getDoubleValue("load-resistence", 1e30);
load_resistance = props->getDoubleValue("load-resistance", 1e30);
// Taken from default values as used in ac3d
ambient[0] = props->getDoubleValue("ambient/r", 0.2);
@@ -203,7 +211,7 @@ SGMaterial::init ()
friction_factor = 1;
rolling_friction = 0.02;
bumpiness = 0;
load_resistence = 1e30;
load_resistance = 1e30;
shininess = 1.0;
for (int i = 0; i < 4; i++) {
@@ -225,15 +233,15 @@ SGMaterial::load_texture ( int n )
if ( !_status[i].texture_loaded ) {
SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture "
<< _status[i].texture_path );
assignTexture(_status[i].state, _status[i].texture_path,
wrapu, wrapv, mipmap );
assignTexture(_status[i].state.get(), _status[i].texture_path,
wrapu, wrapv, mipmap);
_status[i].texture_loaded = true;
}
}
return true;
}
ssgSimpleState *
osg::StateSet *
SGMaterial::get_state (int n) const
{
if (_status.size() == 0) {
@@ -241,80 +249,95 @@ SGMaterial::get_state (int n) const
return NULL;
}
ssgSimpleState *st = (n >= 0) ? _status[n].state
: _status[_current_ptr].state;
((SGMaterial *)this)->_current_ptr += 1;
osg::StateSet *st = (n >= 0) ? _status[n].state.get()
: _status[_current_ptr].state.get();
_current_ptr += 1;
if (_current_ptr >= _status.size())
((SGMaterial *)this)->_current_ptr = 0;
_current_ptr = 0;
return st;
}
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++)
{
ssgSimpleState *state = new ssgSimpleState();
osg::StateSet *stateSet = new osg::StateSet;
stateSet->setUserData(new SGMaterialUserData(this));
// Set up the textured state
state->setShadeModel( shade_model );
state->enable( GL_LIGHTING );
state->enable ( GL_CULL_FACE ) ;
state->enable( GL_TEXTURE_2D );
state->disable( GL_BLEND );
state->disable( GL_ALPHA_TEST );
osg::ShadeModel* shadeModel = new osg::ShadeModel;
shadeModel->setMode(osg::ShadeModel::SMOOTH);
stateSet->setAttribute(shadeModel);
osg::CullFace* cullFace = new osg::CullFace;
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 ) {
SG_LOG(SG_INPUT, SG_INFO, " " << _status[i].texture_path );
assignTexture( state, _status[i].texture_path, wrapu, wrapv );
assignTexture( stateSet, _status[i].texture_path, wrapu, wrapv);
_status[i].texture_loaded = true;
} else {
_status[i].texture_loaded = false;
}
state->enable( GL_COLOR_MATERIAL );
state->setMaterial ( GL_AMBIENT,
ambient[0], ambient[1],
ambient[2], ambient[3] ) ;
state->setMaterial ( GL_DIFFUSE,
diffuse[0], diffuse[1],
diffuse[2], diffuse[3] ) ;
state->setMaterial ( GL_SPECULAR,
specular[0], specular[1],
specular[2], specular[3] ) ;
state->setMaterial ( GL_EMISSION,
emission[0], emission[1],
emission[2], emission[3] ) ;
state->setShininess ( shininess );
osg::Material* material = new osg::Material;
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
material->setAmbient(osg::Material::FRONT_AND_BACK, ambient.osg());
material->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse.osg());
material->setSpecular(osg::Material::FRONT_AND_BACK, specular.osg());
material->setEmission(osg::Material::FRONT_AND_BACK, emission.osg());
material->setShininess(osg::Material::FRONT_AND_BACK, shininess );
stateSet->setAttribute(material);
_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 ) );
}
void SGMaterial::assignTexture( ssgSimpleState *state, string &fname,
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())
{
state->setTexture((char *)fname.c_str(), _wrapu, _wrapv, _mipmap);
_tex_cache[fname] = state->getTexture();
osg::Texture2D* texture = SGLoadTexture2D(fname, _wrapu, _wrapv,
mipmap ? -1 : 0);
texture->setMaxAnisotropy( SGGetTextureFilter());
state->setTextureAttributeAndModes(0, texture);
_tex_cache[fname] = texture;
}
else
{
state->setTexture(_tex_cache_iter->second);
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
@@ -338,5 +361,12 @@ SGMaterialGlyph::SGMaterialGlyph(SGPropertyNode *p) :
{
}
void
SGSetTextureFilter( int max) {
SGSceneFeatures::instance()->setTextureFilter( max);
}
// end of mat.cxx
int
SGGetTextureFilter() {
return SGSceneFeatures::instance()->getTextureFilter();
}

View File

@@ -38,12 +38,12 @@
#include <simgear/math/SGMath.hxx>
#include <plib/sg.h>
#include <plib/ssg.h>
#include <osg/ref_ptr>
#include <osg/StateSet>
#include <simgear/props/props.hxx>
#include <simgear/structure/ssgSharedPtr.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/scene/util/SGSceneFeatures.hxx>
#include "matmodel.hxx"
@@ -54,7 +54,6 @@ SG_USING_STD(map);
class SGMaterialGlyph;
/**
* A material in the scene graph.
*
@@ -93,15 +92,15 @@ 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,
* low-level state for the scene graph and wrap a material around
* 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.
@@ -122,11 +121,10 @@ public:
*/
bool load_texture (int n = -1);
/**
* Get the textured state.
*/
ssgSimpleState *get_state (int n = -1) const;
osg::StateSet *get_state (int n = -1) const;
/**
@@ -178,9 +176,9 @@ public:
double get_bumpiness () const { return bumpiness; }
/**
* Get the load resistence
* Get the load resistance
*/
double get_load_resistence () const { return load_resistence; }
double get_load_resistance () const { return load_resistance; }
/**
* Get the list of names for this material
@@ -209,6 +207,20 @@ public:
*/
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:
@@ -224,9 +236,9 @@ protected:
protected:
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) {}
ssgSharedPtr<ssgSimpleState> state;
osg::ref_ptr<osg::StateSet> state;
string texture_path;
bool texture_loaded;
};
@@ -242,7 +254,7 @@ private:
vector<_internal_state> _status;
// Round-robin counter
unsigned int _current_ptr;
mutable unsigned int _current_ptr;
// texture size
double xsize, ysize;
@@ -268,8 +280,8 @@ private:
// the bumpiness of that surface material
double bumpiness;
// the load resistence of that surface material
double load_resistence;
// the load resistance of that surface material
double load_resistance;
// material properties
SGVec4f ambient, diffuse, specular, emission;
@@ -291,10 +303,10 @@ private:
SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented
void read_properties( const string &fg_root, const SGPropertyNode *props, const char *season );
void build_ssg_state( bool defer_tex_load );
void set_ssg_state( ssgSimpleState *s );
void build_state( bool defer_tex_load );
void set_state( osg::StateSet *s );
void assignTexture( ssgSimpleState *state, string &fname, int _wrapu = TRUE, int _wrapv = TRUE, int _mipmap = TRUE );
void assignTexture( osg::StateSet *state, const std::string &fname, int _wrapu = TRUE, int _wrapv = TRUE, int _mipmap = TRUE );
};
@@ -311,7 +323,7 @@ protected:
double _right;
};
class SGMaterialUserData : public ssgBase {
class SGMaterialUserData : public osg::Referenced {
public:
SGMaterialUserData(const SGMaterial* material) :
mMaterial(material)
@@ -322,4 +334,10 @@ private:
SGSharedPtr<const SGMaterial> mMaterial;
};
void
SGSetTextureFilter( int max);
int
SGGetTextureFilter();
#endif // _SG_MAT_HXX

View File

@@ -33,8 +33,6 @@
# include <windows.h>
#endif
#include <plib/ssg.h>
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/structure/exception.hxx>
@@ -44,6 +42,19 @@
#include <string.h>
#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/misc/sg_path.hxx>
#include <simgear/misc/sgstream.hxx>
@@ -57,166 +68,10 @@
SG_USING_NAMESPACE(std);
SG_USING_STD(string);
// FIXME: should make this configurable
static const bool sprite_lighting = true;
// Constructor
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 a light sprite texture map
static int gen_standard_light_sprite( 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.01 ) { bright = 0.0; }
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_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
bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) {
@@ -231,13 +86,11 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char
throw;
}
SGSharedPtr<SGMaterial> m;
int nMaterials = materials.nChildren();
for (int i = 0; i < nMaterials; i++) {
const SGPropertyNode * node = materials.getChild(i);
if (!strcmp(node->getName(), "material")) {
m = new SGMaterial( fg_root, node, season );
SGSharedPtr<SGMaterial> m = new SGMaterial(fg_root, node, season);
vector<SGPropertyNode_ptr>names = node->getChildren("name");
for ( unsigned int j = 0; j < names.size(); j++ ) {
@@ -254,340 +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 );
m = new SGMaterial( gnd_lights );
m->add_name("GROUND_LIGHTS");
matlib["GROUND_LIGHTS"] = m;
GLuint tex_name;
// hard coded runway white light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 235, 195, 255 );
} else {
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 );
m = new SGMaterial( rwy_white_lights );
m->add_name("RWY_WHITE_LIGHTS");
matlib["RWY_WHITE_LIGHTS"] = m;
// For backwards compatibility ... remove someday
m->add_name("RUNWAY_LIGHTS");
matlib["RUNWAY_LIGHTS"] = m;
m->add_name("RWY_LIGHTS");
matlib["RWY_LIGHTS"] = m;
// end of backwards compatitibilty
// hard coded runway medium intensity white light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 235, 195, 205 );
} else {
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 );
m = new SGMaterial( rwy_white_medium_lights );
m->add_name("RWY_WHITE_MEDIUM_LIGHTS");
matlib["RWY_WHITE_MEDIUM_LIGHTS"] = m;
// hard coded runway low intensity white light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 235, 195, 155 );
} else {
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 );
m = new SGMaterial( rwy_white_low_lights );
m->add_name("RWY_WHITE_LOW_LIGHTS");
matlib["RWY_WHITE_LOW_LIGHTS"] = m;
// hard coded runway yellow light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 215, 20, 255 );
} else {
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 );
m = new SGMaterial( rwy_yellow_lights );
m->add_name("RWY_YELLOW_LIGHTS");
matlib["RWY_YELLOW_LIGHTS"] = m;
// hard coded runway medium intensity yellow light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 215, 20, 205 );
} else {
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 );
m = new SGMaterial( rwy_yellow_medium_lights );
m->add_name("RWY_YELLOW_MEDIUM_LIGHTS");
matlib["RWY_YELLOW_MEDIUM_LIGHTS"] = m;
// hard coded runway low intensity yellow light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 215, 20, 155 );
} else {
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 );
m = new SGMaterial( rwy_yellow_low_lights );
m->add_name("RWY_YELLOW_LOW_LIGHTS");
matlib["RWY_YELLOW_LOW_LIGHTS"] = m;
// hard coded runway red light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 90, 90, 255 );
} else {
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 );
m = new SGMaterial( rwy_red_lights );
m->add_name("RWY_RED_LIGHTS");
matlib["RWY_RED_LIGHTS"] = m;
// hard coded medium intensity runway red light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 90, 90, 205 );
} else {
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 );
m = new SGMaterial( rwy_red_medium_lights );
m->add_name("RWY_RED_MEDIUM_LIGHTS");
matlib["RWY_RED_MEDIUM_LIGHTS"] = m;
// hard coded low intensity runway red light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 90, 90, 155 );
} else {
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 );
m = new SGMaterial( rwy_red_low_lights );
m->add_name("RWY_RED_LOW_LIGHTS");
matlib["RWY_RED_LOW_LIGHTS"] = m;
// hard coded runway green light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 20, 235, 20, 255 );
} else {
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 );
m = new SGMaterial( rwy_green_lights );
m->add_name("RWY_GREEN_LIGHTS");
matlib["RWY_GREEN_LIGHTS"] = m;
// hard coded medium intensity runway green light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 20, 235, 20, 205 );
} else {
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 );
m = new SGMaterial( rwy_green_medium_lights );
m->add_name("RWY_GREEN_MEDIUM_LIGHTS");
matlib["RWY_GREEN_MEDIUM_LIGHTS"] = m;
// hard coded low intensity runway green light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 20, 235, 20, 155 );
} else {
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 );
m = new SGMaterial( rwy_green_low_lights );
m->add_name("RWY_GREEN_LOW_LIGHTS");
matlib["RWY_GREEN_LOW_LIGHTS"] = m;
m->add_name("RWY_GREEN_TAXIWAY_LIGHTS");
matlib["RWY_GREEN_TAXIWAY_LIGHTS"] = m;
// hard coded low intensity taxiway blue light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 90, 90, 235, 205 );
} else {
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 );
m = new SGMaterial( taxiway_blue_low_lights );
m->add_name("RWY_BLUE_TAXIWAY_LIGHTS");
matlib["RWY_BLUE_TAXIWAY_LIGHTS"] = m;
// hard coded runway vasi light state
if ( sprite_lighting ) {
tex_name = gen_standard_light_sprite( 235, 235, 195, 255 );
} else {
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 );
m = new SGMaterial( rwy_vasi_lights );
m->add_name("RWY_VASI_LIGHTS");
matlib["RWY_VASI_LIGHTS"] = m;
return true;
}
@@ -621,13 +140,13 @@ bool SGMaterialLib::add_item ( const string &mat_name, const string &full_path )
// 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]->add_name(mat_name);
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material given a premade "
<< "ssgSimpleState = " << mat_name );
<< "osg::StateSet = " << mat_name );
return true;
}
@@ -664,17 +183,18 @@ void SGMaterialLib::load_next_deferred() {
}
}
// Return the material from that given leaf
const SGMaterial* SGMaterialLib::findMaterial(/*const*/ssgLeaf* leaf) const
const SGMaterial*
SGMaterialLib::findMaterial(const osg::StateSet* stateSet) const
{
if (!leaf)
if (!stateSet)
return 0;
ssgBase* base = leaf->getUserData();
const osg::Referenced* base = stateSet->getUserData();
if (!base)
return 0;
SGMaterialUserData* matUserData = dynamic_cast<SGMaterialUserData*>(base);
const SGMaterialUserData* matUserData
= dynamic_cast<const SGMaterialUserData*>(base);
if (!matUserData)
return 0;

View File

@@ -37,8 +37,8 @@
#include <map> // STL associative "array"
#include <vector> // STL "array"
#include <plib/ssg.h> // plib include
#include <osg/Node>
#include <osg/StateSet>
class SGMaterial;
@@ -47,14 +47,13 @@ SG_USING_STD(map);
SG_USING_STD(vector);
SG_USING_STD(less);
// Material management class
class SGMaterialLib {
private:
// associative array of materials
typedef map < string, SGSharedPtr<SGMaterial>, less<string> > material_map;
typedef map < string, SGSharedPtr<SGMaterial> > material_map;
typedef material_map::iterator material_map_iterator;
typedef material_map::const_iterator const_material_map_iterator;
@@ -71,7 +70,7 @@ public:
// Add the named texture with default properties
bool add_item( const string &tex_path );
bool add_item( const string &mat_name, const string &tex_path );
bool add_item( const string &mat_name, ssgSimpleState *state );
bool add_item( const string &mat_name, osg::StateSet *state );
// find a material record by material name
SGMaterial *find( const string& material );
@@ -87,7 +86,7 @@ public:
material_map_iterator end() { return matlib.end(); }
const_material_map_iterator end() const { return matlib.end(); }
const SGMaterial* findMaterial(/*const*/ssgLeaf* leaf) const;
const SGMaterial* findMaterial(const osg::StateSet* stateSet) const;
// Destructor
~SGMaterialLib ( void );

View File

@@ -30,7 +30,11 @@
#include <map>
SG_USING_STD(map);
#include <simgear/compiler.h>
#include <osg/AlphaFunc>
#include <osg/Group>
#include <osg/LOD>
#include <osg/StateSet>
#include <osg/Transform>
#ifdef SG_MATH_EXCEPTION_CLASH
# include <math.h>
@@ -120,22 +124,6 @@ SGMatModel::get_model_count( SGModelLib *modellib,
return _models.size();
}
static void
setAlphaClampToBranch( ssgBranch *b, float clamp )
{
int nb = b->getNumKids();
for (int i = 0; i<nb; i++) {
ssgEntity *e = b->getKid(i);
if (e->isAKindOf(ssgTypeLeaf())) {
ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
s->enable( GL_ALPHA_TEST );
s->setAlphaClamp( clamp );
} else if (e->isAKindOf(ssgTypeBranch())) {
setAlphaClampToBranch( (ssgBranch*)e, clamp );
}
}
}
inline void
SGMatModel::load_models ( SGModelLib *modellib,
const string &fg_root,
@@ -145,7 +133,7 @@ SGMatModel::load_models ( SGModelLib *modellib,
// Load model only on demand
if (!_models_loaded) {
for (unsigned int i = 0; i < _paths.size(); i++) {
ssgEntity *entity = modellib->load_model( fg_root, _paths[i],
osg::Node *entity = modellib->load_model( fg_root, _paths[i],
prop_root, sim_time_sec,
/*cache_object*/ true );
if (entity != 0) {
@@ -153,23 +141,29 @@ SGMatModel::load_models ( SGModelLib *modellib,
// in the XML wrapper as well (at least,
// the billboarding should be handled
// there).
float ranges[] = {0, _range_m};
ssgRangeSelector * lod = new ssgRangeSelector;
lod->setRanges(ranges, 2);
osg::LOD * lod = new osg::LOD;
lod->setName("Model LOD");
lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
lod->setRange(0, 0, _range_m);
if (_heading_type == HEADING_BILLBOARD) {
// if the model is a billboard, it is likely :
// 1. a branch with only leaves,
// 2. a tree or a non rectangular shape faked by transparency
// We add alpha clamp then
if ( entity->isAKindOf(ssgTypeBranch()) ) {
ssgBranch *b = (ssgBranch *)entity;
setAlphaClampToBranch( b, 0.01f );
}
ssgCutout * cutout = new ssgCutout(false);
cutout->addKid(entity);
lod->addKid(cutout);
osg::StateSet* stateSet = entity->getOrCreateStateSet();
osg::AlphaFunc* alphaFunc =
new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01f);
stateSet->setAttributeAndModes(alphaFunc,
osg::StateAttribute::OVERRIDE);
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
osg::Transform* transform = new osg::Transform;
transform->setName("Model Billboard Transform");
transform->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
transform->addChild(entity);
lod->addChild(transform);
} else {
lod->addKid(entity);
lod->addChild(entity);
}
_models.push_back(lod);
} else {
@@ -180,7 +174,7 @@ SGMatModel::load_models ( SGModelLib *modellib,
_models_loaded = true;
}
ssgEntity *
osg::Node*
SGMatModel::get_model( int index,
SGModelLib *modellib,
const string &fg_root,
@@ -188,10 +182,10 @@ SGMatModel::get_model( int index,
double sim_time_sec )
{
load_models( modellib, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
return _models[index];
return _models[index].get();
}
ssgEntity *
osg::Node*
SGMatModel::get_random_model( SGModelLib *modellib,
const string &fg_root,
SGPropertyNode *prop_root,
@@ -202,7 +196,7 @@ SGMatModel::get_random_model( SGModelLib *modellib,
int index = int(sg_random() * nModels);
if (index >= nModels)
index = 0;
return _models[index];
return _models[index].get();
}
double

View File

@@ -32,12 +32,11 @@
#include STL_STRING // Standard C++ string library
#include <plib/sg.h>
#include <plib/ssg.h>
#include <osg/ref_ptr>
#include <osg/Node>
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/structure/ssgSharedPtr.hxx>
#include <simgear/props/props.hxx>
SG_USING_STD(string);
@@ -86,7 +85,7 @@ public:
* @param index The index of the model.
* @return The model.
*/
ssgEntity *get_model( int index,
osg::Node *get_model( int index,
SGModelLib *modellib,
const string &fg_root,
SGPropertyNode *prop_root,
@@ -98,7 +97,7 @@ public:
*
* @return A randomly select model from the variants.
*/
ssgEntity *get_random_model( SGModelLib *modellib,
osg::Node *get_random_model( SGModelLib *modellib,
const string &fg_root,
SGPropertyNode *prop_root,
double sim_time_sec );
@@ -141,7 +140,7 @@ private:
double sim_time_sec );
vector<string> _paths;
mutable vector<ssgSharedPtr<ssgEntity> > _models;
mutable vector<osg::ref_ptr<osg::Node> > _models;
mutable bool _models_loaded;
double _coverage_m2;
double _range_m;
@@ -198,7 +197,6 @@ private:
double _range_m;
vector<SGSharedPtr<SGMatModel> > _objects;
};

View File

@@ -6,27 +6,31 @@ noinst_HEADERS =
include_HEADERS = \
animation.hxx \
custtrans.hxx \
location.hxx \
model.hxx \
modellib.hxx \
personality.hxx \
persparam.hxx \
placement.hxx \
placementtrans.hxx \
shadowvolume.hxx
SGMaterialAnimation.hxx \
SGOffsetTransform.hxx \
SGRotateTransform.hxx \
SGScaleTransform.hxx \
SGTranslateTransform.hxx
libsgmodel_a_SOURCES = \
animation.cxx \
custtrans.cxx \
location.cxx \
model.cxx \
modellib.cxx \
personality.cxx \
persparam.cxx \
placement.cxx \
placementtrans.cxx \
shadowvolume.cxx \
shadanim.cxx
shadanim.cxx \
SGMaterialAnimation.cxx \
SGOffsetTransform.cxx \
SGRotateTransform.cxx \
SGScaleTransform.cxx \
SGTranslateTransform.cxx
INCLUDES = -I$(top_srcdir)

View File

@@ -0,0 +1,514 @@
// animation.cxx - classes to manage model animation.
// Written by David Megginson, started 2002.
//
// This file is in the Public Domain, and comes with no warranty.
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include "SGMaterialAnimation.hxx"
#include <osg/AlphaFunc>
#include <osg/Array>
#include <osg/Drawable>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/StateSet>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/ReadFile>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/scene/model/model.hxx>
namespace {
/**
* Get a color from properties.
*/
struct ColorSpec {
float red, green, blue;
float factor;
float offset;
SGPropertyNode_ptr red_prop;
SGPropertyNode_ptr green_prop;
SGPropertyNode_ptr blue_prop;
SGPropertyNode_ptr factor_prop;
SGPropertyNode_ptr offset_prop;
SGVec4f v;
ColorSpec(const SGPropertyNode* configNode, SGPropertyNode* modelRoot)
{
red = -1.0;
green = -1.0;
blue = -1.0;
if (!configNode)
return;
red = configNode->getFloatValue("red", -1.0);
green = configNode->getFloatValue("green", -1.0);
blue = configNode->getFloatValue("blue", -1.0);
factor = configNode->getFloatValue("factor", 1.0);
offset = configNode->getFloatValue("offset", 0.0);
if (!modelRoot)
return;
const SGPropertyNode *node;
node = configNode->getChild("red-prop");
if (node)
red_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("green-prop");
if (node)
green_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("blue-prop");
if (node)
blue_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("factor-prop");
if (node)
factor_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("offset-prop");
if (node)
offset_prop = modelRoot->getNode(node->getStringValue(), true);
}
bool dirty() {
return red >= 0 || green >= 0 || blue >= 0;
}
bool live() {
return red_prop || green_prop || blue_prop
|| factor_prop || offset_prop;
}
SGVec4f &rgba() {
if (red_prop)
red = red_prop->getFloatValue();
if (green_prop)
green = green_prop->getFloatValue();
if (blue_prop)
blue = blue_prop->getFloatValue();
if (factor_prop)
factor = factor_prop->getFloatValue();
if (offset_prop)
offset = offset_prop->getFloatValue();
v[0] = SGMiscf::clip(red*factor + offset, 0, 1);
v[1] = SGMiscf::clip(green*factor + offset, 0, 1);
v[2] = SGMiscf::clip(blue*factor + offset, 0, 1);
v[3] = 1;
return v;
}
osg::Vec4& rgbaVec4()
{
return rgba().osg();
}
SGVec4f &initialRgba() {
v[0] = SGMiscf::clip(red*factor + offset, 0, 1);
v[1] = SGMiscf::clip(green*factor + offset, 0, 1);
v[2] = SGMiscf::clip(blue*factor + offset, 0, 1);
v[3] = 1;
return v;
}
};
/**
* Get a property value from a property.
*/
struct PropSpec {
float value;
float factor;
float offset;
float min;
float max;
SGPropertyNode_ptr value_prop;
SGPropertyNode_ptr factor_prop;
SGPropertyNode_ptr offset_prop;
PropSpec(const char* valueName, const char* valuePropName,
const SGPropertyNode* configNode, SGPropertyNode* modelRoot)
{
value = -1;
if (!configNode)
return;
value = configNode->getFloatValue(valueName, -1);
factor = configNode->getFloatValue("factor", 1);
offset = configNode->getFloatValue("offset", 0);
min = configNode->getFloatValue("min", 0);
max = configNode->getFloatValue("max", 1);
if (!modelRoot)
return;
const SGPropertyNode *node;
node = configNode->getChild(valuePropName);
if (node)
value_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("factor-prop");
if (node)
factor_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("offset-prop");
if (node)
offset_prop = modelRoot->getNode(node->getStringValue(), true);
}
bool dirty() { return value >= 0.0; }
bool live() { return value_prop || factor_prop || offset_prop; }
float getValue()
{
if (value_prop)
value = value_prop->getFloatValue();
if (offset_prop)
offset = offset_prop->getFloatValue();
if (factor_prop)
factor = factor_prop->getFloatValue();
return SGMiscf::clip(value*factor + offset, min, max);
}
float getInitialValue()
{
return SGMiscf::clip(value*factor + offset, min, max);
}
};
/**
* The possible color properties supplied by a material animation.
*/
enum SuppliedColor {
DIFFUSE = 1,
AMBIENT = 2,
SPECULAR = 4,
EMISSION = 8,
SHININESS = 16,
TRANSPARENCY = 32
};
const unsigned AMBIENT_DIFFUSE = AMBIENT | DIFFUSE;
const int allMaterialColors = (DIFFUSE | AMBIENT | SPECULAR | EMISSION
| SHININESS);
// Visitor for finding default material colors in the animation node's
// subgraph. This makes some assumptions about the subgraph i.e.,
// there will be one material and one color value found. This is
// probably true for ac3d models and most uses of material animations,
// but will break down if, for example, you animate the transparency
// of a vertex colored model.
class MaterialDefaultsVisitor : public osg::NodeVisitor {
public:
MaterialDefaultsVisitor()
: osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
ambientDiffuse(-1.0f, -1.0f, -1.0f, -1.0f)
{
setVisitorType(osg::NodeVisitor::NODE_VISITOR);
}
virtual void apply(osg::Node& node)
{
maybeGetMaterialValues(node.getStateSet());
traverse(node);
}
virtual void apply(osg::Geode& node)
{
maybeGetMaterialValues(node.getStateSet());
int numDrawables = node.getNumDrawables();
for (int i = 0; i < numDrawables; i++) {
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(node.getDrawable(i));
if (!geom || geom->getColorBinding() != osg::Geometry::BIND_OVERALL)
continue;
maybeGetMaterialValues(geom->getStateSet());
osg::Array* colorArray = geom->getColorArray();
osg::Vec4Array* colorVec4 = dynamic_cast<osg::Vec4Array*>(colorArray);
if (colorVec4) {
ambientDiffuse = (*colorVec4)[0];
break;
}
osg::Vec3Array* colorVec3 = dynamic_cast<osg::Vec3Array*>(colorArray);
if (colorVec3) {
ambientDiffuse = osg::Vec4((*colorVec3)[0], 1.0f);
break;
}
}
}
void maybeGetMaterialValues(osg::StateSet* stateSet)
{
if (!stateSet)
return;
osg::Material* nodeMat
= dynamic_cast<osg::Material*>(stateSet->getAttribute(osg::StateAttribute::MATERIAL));
if (!nodeMat)
return;
material = nodeMat;
}
osg::ref_ptr<osg::Material> material;
osg::Vec4 ambientDiffuse;
};
class UpdateCallback : public osg::NodeCallback {
public:
UpdateCallback(const osgDB::FilePathList& texturePathList,
const SGCondition* condition,
const SGPropertyNode* configNode, SGPropertyNode* modelRoot) :
_condition(condition),
_ambient(configNode->getChild("ambient"), modelRoot),
_diffuse(configNode->getChild("diffuse"), modelRoot),
_specular(configNode->getChild("specular"), modelRoot),
_emission(configNode->getChild("emission"), modelRoot),
_shininess("shininess", "shininess-prop",
configNode->getChild("shininess"), modelRoot),
_transparency("alpha", "alpha-prop",
configNode->getChild("transparency"), modelRoot),
_texturePathList(texturePathList)
{
const SGPropertyNode* node;
node = configNode->getChild("threshold-prop");
if (node)
_thresholdProp = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("texture-prop");
if (node)
_textureProp = modelRoot->getNode(node->getStringValue(), true);
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
osg::StateSet* stateSet = node->getStateSet();
if ((!_condition || _condition->test()) && stateSet) {
if (_textureProp) {
std::string textureName = _textureProp->getStringValue();
if (_textureName != textureName) {
while (stateSet->getTextureAttribute(0,
osg::StateAttribute::TEXTURE)) {
stateSet->removeTextureAttribute(0, osg::StateAttribute::TEXTURE);
}
std::string textureFile;
textureFile = osgDB::findFileInPath(textureName, _texturePathList);
if (!textureFile.empty()) {
osg::Texture2D* texture2D = SGLoadTexture2D(textureFile);
if (texture2D) {
stateSet->setTextureAttribute(0, texture2D,
osg::StateAttribute::OVERRIDE);
stateSet->setTextureMode(0, GL_TEXTURE_2D,
osg::StateAttribute::ON);
_textureName = textureName;
}
}
}
}
if (_thresholdProp) {
osg::StateSet* stateSet = node->getOrCreateStateSet();
osg::StateAttribute* stateAttribute;
stateAttribute = stateSet->getAttribute(osg::StateAttribute::ALPHAFUNC);
osg::AlphaFunc* alphaFunc = dynamic_cast<osg::AlphaFunc*>(stateAttribute);
assert(alphaFunc);
alphaFunc->setReferenceValue(_thresholdProp->getFloatValue());
}
osg::StateAttribute* stateAttribute
= stateSet->getAttribute(osg::StateAttribute::MATERIAL);
osg::Material* material = dynamic_cast<osg::Material*>(stateAttribute);
if (material) {
if (_ambient.live())
material->setAmbient(osg::Material::FRONT_AND_BACK,
_ambient.rgbaVec4());
if (_diffuse.live())
material->setDiffuse(osg::Material::FRONT_AND_BACK,
_diffuse.rgbaVec4());
if (_specular.live())
material->setSpecular(osg::Material::FRONT_AND_BACK,
_specular.rgbaVec4());
if (_emission.live())
material->setEmission(osg::Material::FRONT_AND_BACK,
_emission.rgbaVec4());
if (_shininess.live())
material->setShininess(osg::Material::FRONT_AND_BACK,
_shininess.getValue());
if (_transparency.live()) {
float alpha = _transparency.getValue();
material->setAlpha(osg::Material::FRONT_AND_BACK, alpha);
if (alpha < 1.0f) {
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
} else {
stateSet->setRenderingHint(osg::StateSet::DEFAULT_BIN);
}
}
}
}
traverse(node, nv);
}
private:
SGSharedPtr<const SGCondition> _condition;
SGSharedPtr<const SGPropertyNode> _textureProp;
SGSharedPtr<const SGPropertyNode> _thresholdProp;
std::string _textureName;
ColorSpec _ambient;
ColorSpec _diffuse;
ColorSpec _specular;
ColorSpec _emission;
PropSpec _shininess;
PropSpec _transparency;
osgDB::FilePathList _texturePathList;
};
} // namespace
SGMaterialAnimation::SGMaterialAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot) :
SGAnimation(configNode, modelRoot)
{
if (configNode->hasChild("global"))
SG_LOG(SG_IO, SG_ALERT, "Use of <global> in material animation is "
"no longer supported");
}
osg::Group*
SGMaterialAnimation::createAnimationGroup(osg::Group& parent)
{
osg::Group* group = new osg::Group;
group->setName("material animation group");
SGPropertyNode* inputRoot = getModelRoot();
const SGPropertyNode* node = getConfig()->getChild("property-base");
if (node)
inputRoot = getModelRoot()->getRootNode()->getNode(node->getStringValue(),
true);
osgDB::FilePathList texturePathList = osgDB::getDataFilePathList();
if (getConfig()->hasChild("texture")) {
std::string textureName = getConfig()->getStringValue("texture");
std::string textureFile;
textureFile = osgDB::findFileInPath(textureName, texturePathList);
if (!textureFile.empty()) {
osg::StateSet* stateSet = group->getOrCreateStateSet();
osg::Texture2D* texture2D = SGLoadTexture2D(textureFile);
if (texture2D) {
stateSet->setTextureAttribute(0, texture2D,
osg::StateAttribute::OVERRIDE);
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
if (texture2D->getImage()->isImageTranslucent()) {
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
}
}
}
}
if (getConfig()->hasChild("threshold-prop") ||
getConfig()->hasChild("threshold")) {
osg::StateSet* stateSet = group->getOrCreateStateSet();
osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
alphaFunc->setFunction(osg::AlphaFunc::GREATER);
float threshold = getConfig()->getFloatValue("threshold", 0);
alphaFunc->setReferenceValue(threshold);
stateSet->setAttribute(alphaFunc, osg::StateAttribute::OVERRIDE);
}
unsigned suppliedColors = 0;
if (getConfig()->hasChild("ambient"))
suppliedColors |= AMBIENT;
if (getConfig()->hasChild("diffuse"))
suppliedColors |= DIFFUSE;
if (getConfig()->hasChild("specular"))
suppliedColors |= SPECULAR;
if (getConfig()->hasChild("emission"))
suppliedColors |= EMISSION;
if (getConfig()->hasChild("shininess")
|| getConfig()->hasChild("shininess-prop"))
suppliedColors |= SHININESS;
if (getConfig()->hasChild("transparency"))
suppliedColors |= TRANSPARENCY;
if (suppliedColors != 0) {
osg::StateSet* stateSet = group->getOrCreateStateSet();
osg::Material* mat;
if (defaultMaterial.valid()) {
mat = defaultMaterial.get();
} else {
mat = new osg::Material;
mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
}
mat->setDataVariance(osg::Object::DYNAMIC);
unsigned defaultColorModeMask = 0;
mat->setUpdateCallback(0); // Just to make sure.
switch (mat->getColorMode()) {
case osg::Material::OFF:
defaultColorModeMask = 0;
break;
case osg::Material::AMBIENT:
defaultColorModeMask = AMBIENT;
break;
case osg::Material::DIFFUSE:
defaultColorModeMask = DIFFUSE;
break;
case osg::Material::AMBIENT_AND_DIFFUSE:
defaultColorModeMask = AMBIENT | DIFFUSE;
break;
case osg::Material::SPECULAR:
defaultColorModeMask = SPECULAR;
break;
case osg::Material::EMISSION:
defaultColorModeMask = EMISSION;
break;
}
// Copy the color found by traversing geometry into the material
// in case we need to specify it (e.g., transparency) and it is
// not specified by the animation.
if (defaultAmbientDiffuse.x() >= 0) {
if (defaultColorModeMask & AMBIENT)
mat->setAmbient(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
if (defaultColorModeMask & DIFFUSE)
mat->setDiffuse(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
}
// Compute which colors in the animation override colors set via
// colorMode / glColor, and set the colorMode for the animation's
// material accordingly.
if (suppliedColors & TRANSPARENCY) {
// All colors will be affected by the material. Hope all the
// defaults are fine, if needed.
mat->setColorMode(osg::Material::OFF);
} else if ((suppliedColors & defaultColorModeMask) != 0) {
// First deal with the complicated AMBIENT/DIFFUSE case.
if ((defaultColorModeMask & AMBIENT_DIFFUSE) != 0) {
// glColor can supply colors not specified by the animation.
unsigned matColorModeMask = ((~suppliedColors & defaultColorModeMask)
& AMBIENT_DIFFUSE);
if ((matColorModeMask & DIFFUSE) != 0)
mat->setColorMode(osg::Material::DIFFUSE);
else if ((matColorModeMask & AMBIENT) != 0)
mat->setColorMode(osg::Material::AMBIENT);
else
mat->setColorMode(osg::Material::OFF);
} else {
// The animation overrides the glColor color.
mat->setColorMode(osg::Material::OFF);
}
} else {
// No overlap between the animation and color mode, so leave
// the color mode alone.
}
stateSet->setAttribute(mat,(osg::StateAttribute::ON
| osg::StateAttribute::OVERRIDE));
}
group->setUpdateCallback(new UpdateCallback(texturePathList,
getCondition(),
getConfig(), inputRoot));
parent.addChild(group);
return group;
}
void
SGMaterialAnimation::install(osg::Node& node)
{
SGAnimation::install(node);
MaterialDefaultsVisitor defaultsVisitor;
node.accept(defaultsVisitor);
if (defaultsVisitor.material.valid()) {
defaultMaterial
= static_cast<osg::Material*>(defaultsVisitor.material->clone(osg::CopyOp::SHALLOW_COPY));
}
defaultAmbientDiffuse = defaultsVisitor.ambientDiffuse;
}

View File

@@ -0,0 +1,32 @@
// animation.hxx - classes to manage model animation.
// Written by David Megginson, started 2002.
//
// This file is in the Public Domain, and comes with no warranty.
#ifndef _SG_MATERIALANIMATION_HXX
#define _SG_MATERIALANIMATION_HXX 1
#ifndef __cplusplus
# error This library requires C++
#endif
#include <osg/Material>
#include "animation.hxx"
//////////////////////////////////////////////////////////////////////
// Material animation
//////////////////////////////////////////////////////////////////////
class SGMaterialAnimation : public SGAnimation {
public:
SGMaterialAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
virtual void install(osg::Node& node);
private:
osg::ref_ptr<osg::Material> defaultMaterial;
osg::Vec4 defaultAmbientDiffuse;
};
#endif // _SG_MATERIALANIMATION_HXX

View File

@@ -0,0 +1,68 @@
/* -*-c++-*-
*
* Copyright (C) 2006-2007 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include "SGOffsetTransform.hxx"
SGOffsetTransform::SGOffsetTransform(double scaleFactor) :
_scaleFactor(scaleFactor),
_rScaleFactor(1/scaleFactor)
{
}
bool
SGOffsetTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) {
osg::Vec3 center = nv->getEyePoint();
osg::Matrix transform;
transform(0,0) = _scaleFactor;
transform(1,1) = _scaleFactor;
transform(2,2) = _scaleFactor;
transform(3,0) = center[0]*(1 - _scaleFactor);
transform(3,1) = center[1]*(1 - _scaleFactor);
transform(3,2) = center[2]*(1 - _scaleFactor);
matrix.preMult(transform);
}
return true;
}
bool
SGOffsetTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) {
osg::Vec3 center = nv->getEyePoint();
osg::Matrix transform;
transform(0,0) = _rScaleFactor;
transform(1,1) = _rScaleFactor;
transform(2,2) = _rScaleFactor;
transform(3,0) = center[0]*(1 - _rScaleFactor);
transform(3,1) = center[1]*(1 - _rScaleFactor);
transform(3,2) = center[2]*(1 - _rScaleFactor);
matrix.postMult(transform);
}
return true;
}

View File

@@ -0,0 +1,39 @@
/* -*-c++-*-
*
* Copyright (C) 2006-2007 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifndef SG_OFFSET_TRASNFORM_HXX
#define SG_OFFSET_TRASNFORM_HXX
#include <osg/Transform>
class SGOffsetTransform : public osg::Transform {
public:
SGOffsetTransform(double scaleFactor);
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const;
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const;
private:
double _scaleFactor;
double _rScaleFactor;
};
#endif

View File

@@ -0,0 +1,122 @@
/* -*-c++-*-
*
* Copyright (C) 2006-2007 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include "SGRotateTransform.hxx"
static void
set_rotation (osg::Matrix &matrix, double position_rad,
const SGVec3d &center, const SGVec3d &axis)
{
double temp_angle = -position_rad;
double s = sin(temp_angle);
double c = cos(temp_angle);
double t = 1 - c;
// axis was normalized at load time
// hint to the compiler to put these into FP registers
double x = axis[0];
double y = axis[1];
double z = axis[2];
matrix(0, 0) = t * x * x + c ;
matrix(0, 1) = t * y * x - s * z ;
matrix(0, 2) = t * z * x + s * y ;
matrix(0, 3) = 0;
matrix(1, 0) = t * x * y + s * z ;
matrix(1, 1) = t * y * y + c ;
matrix(1, 2) = t * z * y - s * x ;
matrix(1, 3) = 0;
matrix(2, 0) = t * x * z - s * y ;
matrix(2, 1) = t * y * z + s * x ;
matrix(2, 2) = t * z * z + c ;
matrix(2, 3) = 0;
// hint to the compiler to put these into FP registers
x = center[0];
y = center[1];
z = center[2];
matrix(3, 0) = x - x*matrix(0, 0) - y*matrix(1, 0) - z*matrix(2, 0);
matrix(3, 1) = y - x*matrix(0, 1) - y*matrix(1, 1) - z*matrix(2, 1);
matrix(3, 2) = z - x*matrix(0, 2) - y*matrix(1, 2) - z*matrix(2, 2);
matrix(3, 3) = 1;
}
SGRotateTransform::SGRotateTransform() :
_center(0, 0, 0),
_axis(0, 0, 0),
_angleRad(0)
{
setReferenceFrame(RELATIVE_RF);
}
bool
SGRotateTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const
{
// This is the fast path, optimize a bit
if (_referenceFrame == RELATIVE_RF) {
// FIXME optimize
osg::Matrix tmp;
set_rotation(tmp, _angleRad, _center, _axis);
matrix.preMult(tmp);
} else {
osg::Matrix tmp;
set_rotation(tmp, _angleRad, _center, _axis);
matrix = tmp;
}
return true;
}
bool
SGRotateTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const
{
if (_referenceFrame == RELATIVE_RF) {
// FIXME optimize
osg::Matrix tmp;
set_rotation(tmp, -_angleRad, _center, _axis);
matrix.postMult(tmp);
} else {
// FIXME optimize
osg::Matrix tmp;
set_rotation(tmp, -_angleRad, _center, _axis);
matrix = tmp;
}
return true;
}
osg::BoundingSphere
SGRotateTransform::computeBound() const
{
osg::BoundingSphere bs = osg::Group::computeBound();
osg::BoundingSphere centerbs(_center.osg(), bs.radius());
centerbs.expandBy(bs);
return centerbs;
}

View File

@@ -0,0 +1,69 @@
/* -*-c++-*-
*
* Copyright (C) 2006-2007 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifndef SG_ROTATE_TRANSFORM_HXX
#define SG_ROTATE_TRANSFORM_HXX
#include <osg/Transform>
#include <simgear/math/SGMath.hxx>
class SGRotateTransform : public osg::Transform {
public:
SGRotateTransform();
void setCenter(const SGVec3f& center)
{ setCenter(toVec3d(center)); }
void setCenter(const SGVec3d& center)
{ _center = center; dirtyBound(); }
const SGVec3d& getCenter() const
{ return _center; }
void setAxis(const SGVec3f& axis)
{ setAxis(toVec3d(axis)); }
void setAxis(const SGVec3d& axis)
{ _axis = axis; dirtyBound(); }
const SGVec3d& getAxis() const
{ return _axis; }
void setAngleRad(double angle)
{ _angleRad = angle; }
double getAngleRad() const
{ return _angleRad; }
void setAngleDeg(double angle)
{ _angleRad = SGMiscd::deg2rad(angle); }
double getAngleDeg() const
{ return SGMiscd::rad2deg(_angleRad); }
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const;
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const;
virtual osg::BoundingSphere computeBound() const;
private:
SGVec3d _center;
SGVec3d _axis;
double _angleRad;
};
#endif

View File

@@ -0,0 +1,109 @@
/* -*-c++-*-
*
* Copyright (C) 2006-2007 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
/* -*-c++-*-
*
* Copyright (C) 2006-2007 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include "SGScaleTransform.hxx"
SGScaleTransform::SGScaleTransform() :
_center(0, 0, 0),
_scaleFactor(1, 1, 1),
_boundScale(1)
{
setReferenceFrame(RELATIVE_RF);
}
bool
SGScaleTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const
{
osg::Matrix transform;
transform(0,0) = _scaleFactor[0];
transform(1,1) = _scaleFactor[1];
transform(2,2) = _scaleFactor[2];
transform(3,0) = _center[0]*(1 - _scaleFactor[0]);
transform(3,1) = _center[1]*(1 - _scaleFactor[1]);
transform(3,2) = _center[2]*(1 - _scaleFactor[2]);
if (_referenceFrame == RELATIVE_RF)
matrix.preMult(transform);
else
matrix = transform;
return true;
}
bool
SGScaleTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const
{
if (fabs(_scaleFactor[0]) < SGLimitsd::min())
return false;
if (fabs(_scaleFactor[1]) < SGLimitsd::min())
return false;
if (fabs(_scaleFactor[2]) < SGLimitsd::min())
return false;
SGVec3d rScaleFactor(1/_scaleFactor[0],
1/_scaleFactor[1],
1/_scaleFactor[2]);
osg::Matrix transform;
transform(0,0) = rScaleFactor[0];
transform(1,1) = rScaleFactor[1];
transform(2,2) = rScaleFactor[2];
transform(3,0) = _center[0]*(1 - rScaleFactor[0]);
transform(3,1) = _center[1]*(1 - rScaleFactor[1]);
transform(3,2) = _center[2]*(1 - rScaleFactor[2]);
if (_referenceFrame == RELATIVE_RF)
matrix.postMult(transform);
else
matrix = transform;
return true;
}
osg::BoundingSphere
SGScaleTransform::computeBound() const
{
osg::BoundingSphere bs = osg::Group::computeBound();
_boundScale = normI(_scaleFactor);
bs.radius() *= _boundScale;
return bs;
}

View File

@@ -0,0 +1,73 @@
/* -*-c++-*-
*
* Copyright (C) 2006-2007 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifndef SG_SCALE_TRANSFORM_HXX
#define SG_SCALE_TRANSFORM_HXX
#include <osg/Transform>
#include <simgear/math/SGMath.hxx>
class SGScaleTransform : public osg::Transform {
public:
SGScaleTransform();
void setCenter(const SGVec3f& center)
{ setCenter(toVec3d(center)); }
void setCenter(const SGVec3d& center)
{ _center = center; dirtyBound(); }
const SGVec3d& getCenter() const
{ return _center; }
void setScaleFactor(const SGVec3d& scaleFactor)
{
double boundScale = normI(scaleFactor);
if (_boundScale < boundScale || 5*boundScale < _boundScale) {
_boundScale = boundScale;
dirtyBound();
}
_scaleFactor = scaleFactor;
}
void setScaleFactor(double scaleFactor)
{
double boundScale = fabs(scaleFactor);
if (_boundScale < boundScale || 5*boundScale < _boundScale) {
_boundScale = boundScale;
dirtyBound();
}
_scaleFactor = SGVec3d(scaleFactor, scaleFactor, scaleFactor);
}
const SGVec3d& getScaleFactor() const
{ return _scaleFactor; }
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const;
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const;
virtual osg::BoundingSphere computeBound() const;
private:
SGVec3d _center;
SGVec3d _scaleFactor;
mutable double _boundScale;
};
#endif

View File

@@ -0,0 +1,83 @@
/* -*-c++-*-
*
* Copyright (C) 2006-2007 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include "SGTranslateTransform.hxx"
static inline void
set_translation (osg::Matrix &matrix, double position_m, const SGVec3d &axis)
{
SGVec3d xyz = axis * position_m;
matrix.makeIdentity();
matrix(3, 0) = xyz[0];
matrix(3, 1) = xyz[1];
matrix(3, 2) = xyz[2];
}
SGTranslateTransform::SGTranslateTransform() :
_axis(0, 0, 0),
_value(0)
{
setReferenceFrame(RELATIVE_RF);
}
bool
SGTranslateTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const
{
if (_referenceFrame == RELATIVE_RF) {
osg::Matrix tmp;
set_translation(tmp, _value, _axis);
matrix.preMult(tmp);
} else {
osg::Matrix tmp;
set_translation(tmp, _value, _axis);
matrix = tmp;
}
return true;
}
bool
SGTranslateTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const
{
if (_referenceFrame == RELATIVE_RF) {
osg::Matrix tmp;
set_translation(tmp, -_value, _axis);
matrix.postMult(tmp);
} else {
osg::Matrix tmp;
set_translation(tmp, -_value, _axis);
matrix = tmp;
}
return true;
}
osg::BoundingSphere
SGTranslateTransform::computeBound() const
{
osg::BoundingSphere bs = osg::Group::computeBound();
bs._center += _axis.osg()*_value;
return bs;
}

View File

@@ -0,0 +1,53 @@
/* -*-c++-*-
*
* Copyright (C) 2006-2007 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifndef SG_TRANSLATE_TRANSFORM_HXX
#define SG_TRANSLATE_TRANSFORM_HXX
#include <osg/Transform>
#include <simgear/math/SGMath.hxx>
class SGTranslateTransform : public osg::Transform {
public:
SGTranslateTransform();
void setAxis(const SGVec3d& axis)
{ _axis = axis; dirtyBound(); }
const SGVec3d& getAxis() const
{ return _axis; }
void setValue(double value)
{ _value = value; dirtyBound(); }
double getValue() const
{ return _value; }
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const;
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
osg::NodeVisitor* nv) const;
virtual osg::BoundingSphere computeBound() const;
private:
SGVec3d _axis;
double _value;
};
#endif

File diff suppressed because it is too large Load Diff

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