Compare commits

...

188 Commits

Author SHA1 Message Date
Automatic Release Builder
e7598df4d3 new version: 2016.2.0 2016-02-17 21:16:33 +01:00
Automatic Release Builder
63e7a1fbb4 new version: 2016.1.1 2016-02-17 21:16:32 +01:00
Torsten Dreyer
951859d8a7 correct user-agent string for terrasync 2016-02-15 16:53:31 +01:00
James Turner
41f40a9a10 Fix misnamed macro.
- should fix TerraSync user-agent.
2016-02-08 09:37:35 +00:00
Rebecca N. Palmer
a6290e367a math: 'void getMaxSubdiv' does not make any sense
Fixes build failure with GCC 6: https://bugs.debian.org/812014
(getMaxSubdiv is currently unused)
2016-02-06 21:16:27 +00:00
James Turner
af0a51930e CMake: don’t export build to build tree
- only export targets to the install tree, since this is
  hopefully compatible with CMake 2.8
2016-02-02 18:33:20 +00:00
James Turner
ccb5d05eb4 Fix headless build for CMake export 2016-01-30 14:29:12 +00:00
James Turner
9d7402242a Work on CMake export of targets. 2016-01-29 23:15:07 +00:00
James Turner
819833a560 VS2013 compile fixes.
- mostly about return type conversions.
2016-01-27 14:02:27 +00:00
Gijs de Rooy
576ff21488 TerraSync log typo 2016-01-20 12:16:14 +01:00
James Turner
b60f8b4989 New log class for terrasync 2016-01-16 15:49:58 -06:00
James Turner
096d625445 Allow use of noreturn attribute with Clang
- other compilers could also be enabled in the future.
2016-01-12 12:48:34 -06:00
James Turner
dad77b3983 Fix a Simgear compile failure. 2016-01-09 09:45:43 -06:00
James Turner
598b64fa95 Linux test_HTTP fixes.
libCurl HTTP unit-test fixes.
2016-01-08 12:17:02 -06:00
James Turner
b5d6aa3fe4 Linux test_HTTP fixes. 2016-01-06 12:57:04 -06:00
James Turner
f32063e6dd Jenkins build fixes. 2016-01-06 00:07:30 -06:00
James Turner
3d9d44cf73 Fix negative loop counts when dt is small. 2016-01-05 23:18:41 -06:00
James Turner
ac84115ac3 Remove obsolete member 2016-01-05 23:17:20 -06:00
James Turner
d58607242e Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next 2016-01-05 20:43:25 -06:00
Torsten Dreyer
7afd2be652 Version 2016.1.0 2016-01-05 20:45:11 +01:00
James Turner
f256d45b65 Quiet a debug message. 2016-01-04 13:36:32 -06:00
James Turner
edf15e9f55 Quite some debug output from the materials caches. 2016-01-03 21:51:58 -06:00
James Turner
2bb24f43fb New accessors for variant support. 2016-01-03 20:57:19 -06:00
James Turner
be0447d4c0 Fixes for stalling scenery downloads.
- handle closed connections equivalent to IDLE, for timeout purposes
- if the server closes the socket in WAITING_FOR_RESPONSE state, fail
  the first sent request when restoring.

Note this does not explain why the server sometimes closes the socket
in this way, but at least it now causes a detectable failure.
2016-01-03 11:58:22 -06:00
James Turner
ef7a0dc5a3 Trying to debug HTTP timeouts 2016-01-01 17:17:55 -06:00
Erik Hofman
5d754c0419 Fix a very rare nan where r_earth/position_radius > 1.0 2015-12-29 15:49:12 +01:00
Erik Hofman
1f23fb89c0 Remove the dependency on boost for STANDALONE mode 2015-12-24 14:18:53 +01:00
Erik Hofman
584ee1364f use the proper namespace 2015-12-23 10:36:03 +01:00
Erik Hofman
1e32c24a17 Fix two comparison between signed and unsigned integer warnings 2015-12-11 11:09:39 +01:00
James Turner
20ea55bdbc Set macos-min-version for C files too
Should fix another 10.7 issues (Nasal code is .c)
2015-12-10 14:53:17 -06:00
James Turner
c62b4467b4 Templated helper to retrieve a subsystem
- example of naming a subsystem
2015-12-10 14:52:04 -06:00
Erik Hofman
31095c39cc Make it possible to tie the absolute position to a property 2015-12-10 11:50:20 +01:00
James Turner
05d9d7cae8 On Mac, force setting macon-min-version
- the CMake option seems to be erratic, it works locally but not
  on the Jenkins machine for inexplicable reasons.
2015-12-08 20:42:43 +00:00
James Turner
78a548b861 Expose catalog name directly. 2015-11-29 12:43:20 +00:00
Torsten Dreyer
6be4ad27ee Add fg_root and cwd to the search path for loaded models
ref: http://sourceforge.net/p/flightgear/mailman/message/34650992/
2015-11-27 11:11:42 +01:00
Torsten Dreyer
589c5ba35a SGMaterialAnimation: Better handling of missing texture
Don't retry loading a missing texture on every frame.
Emit a warning message instead and retry on the next
change of the textures name.
2015-11-27 11:09:16 +01:00
James Turner
81d668784a Fix spelling of Find(CURL) 2015-11-24 00:09:19 +00:00
James Turner
75ad5a7e5c Whitespace fixes. 2015-11-23 17:57:46 +00:00
James Turner
3f20a3d2c6 Fix for catalog adding/removing bugs 2015-11-23 17:57:36 +00:00
James Turner
a57e969639 Optional use libCurl as the HTTP client.
Will permit HTTPS for packages in the future, disabled by default
for the moment.
2015-11-22 23:53:46 +00:00
James Turner
23b8c86e78 More whitespace fixes. 2015-11-22 23:53:46 +00:00
James Turner
5c9ca9cbe2 EOL cleanups. 2015-11-22 22:36:54 +00:00
James Turner
5676f96fbf Require Cmake 2.8.11
- drop OldGNUInstallDirs work-around as a result
2015-11-22 22:34:31 +00:00
Rebecca N. Palmer
4104f7d18f SGPath(): make realpath() suitable for fgValidatePath
Handle non-existent files, drop obsolete workaround
2015-11-21 21:35:15 +00:00
Thomas Geymayer
10e6bbc2c5 SubsystemMgr: prevent double delete and use shared pointers. 2015-11-20 12:34:46 +01:00
Stuart Buchanan
21e6dd34b2 QuadTree fix for large buildings.
QuadTree relies on a bounding box to set up correctly.

ProxyNodes don't have a BB until the model is loaded,
causing the QuadTree to collapse if the DB loader can't
keep up with the STG loader.

Fix this by creating a default BB before the model
is loaded.
2015-11-06 21:38:53 +00:00
Erik Hofman
319922f044 Add the option to set the reference name afterwards (but before calling play() 2015-11-05 15:33:06 +01:00
Torsten Dreyer
ff3efaee93 Fix wrong log-class for debug message 2015-11-02 10:56:17 +01:00
Stuart Buchanan
08fb433923 Use quadtree to improve culling of STG objects 2015-10-29 20:07:12 +00:00
Stuart Buchanan
1a752d28a4 Remove max density 10000m for surface lights. 2015-10-22 20:28:37 +01:00
Thomas Geymayer
00a20409f7 Canvas: use weak pointer to protect parent element access.
Using a weak pointer is the best way to ensure no invalid
pointer is used. This also fixes a possible crash in
simgear::canvas::Element::getParentStyle on destructing
canvas elements.
2015-09-30 11:54:19 +02:00
James Turner
3bfd0c872a Avoid duplicate refresh of Catalogs
- also fix duplicate reporting of successful refresh
2015-09-27 23:14:50 -05:00
James Turner
945cf5d963 Improve package extraction cleanup 2015-09-27 20:39:58 -05:00
James Turner
4e40913aef Package support progress
- check the catalog version explicitly when refreshing
- handle packages with distinct dir name / primary ID correctly
  (requires an updated catalog XML format)
2015-09-27 19:42:08 -05:00
Erik Hofman
3bc53474ed Revert previous change, OpenAL-Soft is not ready yet. 2015-09-22 12:36:40 +02:00
Rebecca N. Palmer
28dff1d5ca Use our stdint.hxx, not C++11 cstdint 2015-09-21 22:09:47 +01:00
James Turner
81bfec336c Fix missing include for uint8_t on Linux 2015-09-21 14:55:52 -05:00
James Turner
60a0c51e2b Package support hacking
- rename failure code to status code, and add more to handle
  cancellation.
- change caching of active Installs from Catalog to Root, to clarify
  ownership
- expose download status on Install
- adjust Delegate signatures to pass more information
2015-09-20 19:34:51 -05:00
James Turner
70c5d60564 Drop explicit SDK setting on Mac 2015-09-20 19:30:04 -05:00
James Turner
1b2247103a Fix error case on HTTPClient 2015-09-20 19:28:23 -05:00
www2
a49c3a49d3 chance the WMM epic form 1 jan 2005 to 1 jan 2015 2015-09-02 10:37:01 +02:00
www2
105438fc58 Add Update the World Magnetic Model to 2015.0 2015-09-02 10:37:01 +02:00
Erik Hofman
2910c6a77b Thorsten Renk:
Add a 4th layer to the sun (next to disc, inner halo and outer halo). While the inner/outer halos change with atmosphere conditions, the new layer is supposed to represent the effect of blinding brilliance - ideally it adds a suitable ray structure to the sun. The effect is most prominent in space (where I'm most keen on seeing it admittedly) because there all atmospheric halo effects are absent and we end with a really unrealistic white disc.

Some screenshots and discussion there

http://forum.flightgear.org/viewtopic.php?f=47&t=27216
2015-08-26 12:16:56 +02:00
Erik Hofman
6dd859c75e It looks like the current version of OpenAL-Soft has better Doppler support 2015-08-26 11:29:43 +02:00
Torsten Dreyer
b7c7f66bf3 Fix #1783: repeated error message on console
This downgrades the "file not found" message to a warning.
2015-08-05 09:26:46 +02:00
Torsten Dreyer
c7a60d4dc4 Bump version to 3.7.0 2015-07-27 21:42:17 +02:00
Torsten Dreyer
a841fcc89e bump version -> 3.6.0 2015-07-14 11:35:35 +02:00
James Turner
b91d1a3f6a Avoid a warning on startup
- duplicate inits are benign, so don’t warn
2015-06-07 17:49:04 +02:00
James Turner
1378511c13 Remove some debug output. 2015-06-07 17:48:33 +02:00
James Turner
9a9cd62957 Set RPATH on Mac 2015-06-07 15:57:01 +02:00
James Turner
a9742fba7c Fix SVN server fallback when query fails 2015-06-07 15:53:44 +02:00
Thomas Geymayer
9ea772f938 canvas::Map: remove rotation matrix on removing HDG node.
Return to previous rotation if autorotation to HDG is
disabled/removed.
2015-06-02 18:24:31 +02:00
Torsten Dreyer
e64902ae8c Amend previous patch also for PropertyObject<string> 2015-05-28 12:03:48 +02:00
Torsten Dreyer
0b1399479a PropertyObject: enable creation of property
add a create-flag to the node() method of a PropertyObject,
defaulting to false to maintain existing behaviour.
This could be used to add a listener to a non-existing property
without having to write a dummy-value beforehand.

Usage:
myPropertyObject->node() returns the corresponding node or NULL if
does not exist or has not been accessed before.
myPropertyObject->node(true) returns the corresponding node, never NULL.
If the property does not exist, it will gets created.
2015-05-27 20:18:22 +02:00
onox
0369d1f506 Fix position calculation of sound samples
Signed-off-by: Erik Hofman <erik@ehofman.com>
2015-05-18 11:46:16 +02:00
James Turner
f19cf6d56a Packages: more unit-test coverage 2015-04-23 22:05:50 +01:00
James Turner
d12d1b2c3a Packages: increased test coverage. 2015-04-22 23:50:08 +01:00
James Turner
b7fbb79565 Package work on version support.
- start adding test coverage for packages
2015-04-22 23:50:08 +01:00
Torsten Dreyer
541239ceac StateMachine: fix transition source location
source should be child of transition
2015-04-21 13:45:16 +02:00
Torsten Dreyer
fd74095939 StateMachine: fix messed up entry/exit/update bindings 2015-04-21 10:02:22 +02:00
Tim Moore
b24d190e55 Merge branch 'moore/osg-current' into next 2015-04-21 00:08:00 +02:00
Tim Moore
8b351520bd Off-by-one error in the OSG_VERSION_LESS_THAN macro
I was confused about when the version number gets bumped in OSG sources...
2015-04-21 00:06:22 +02:00
James Turner
5bbdcfd240 Windows versionhelpers.h support. 2015-04-20 10:58:11 +01:00
Tim Moore
51ff30f386 changes for OSG 3.3.4 and later
The public interfaces to osgText and osg::GLExtensions changed.
2015-04-19 22:45:59 +02:00
James Turner
6683092bb2 Select default TerraSync server automatically. 2015-04-11 23:50:33 +01:00
James Turner
2c6f9de020 Fix a clang warning 2015-04-11 21:58:23 +01:00
James Turner
686f095f1e Explicit Mac SDK for the moment. 2015-04-11 21:58:15 +01:00
James Turner
089fc5ea0a WindowsXP workaround for SHGetKnowwFolder
Fix from xDraconian after a bug report from Aleesandro.
2015-04-09 15:33:56 +01:00
James Turner
72ae14227e Unit Test: Fixed failure of test_HTTP
From Scott (xDraconian)
2015-03-24 11:10:16 -05:00
James Turner
0e9948f9d4 Portability: Implemented Known Folders for Windows
Patch from Scott (xDraconian)
2015-03-24 11:08:36 -05:00
James Turner
0b6738b616 Portability: Fix compile errors on MSVC
From Scott (xDraconian)
2015-03-24 11:05:57 -05:00
James Turner
3c204e84f4 Fix missing include for Cmake 3.2.1 2015-03-17 23:32:57 +00:00
James Turner
7774b76ad2 Only detect threading library where needed
- avoids failure with newest CMake on Mac
2015-03-17 23:28:52 +00:00
James Turner
acd655b37b Make flag Mac-specific. 2015-03-17 23:26:20 +00:00
James Turner
1a09683351 Fix for Cmake 3.2.1 on Mac SDK handling 2015-03-17 22:31:05 +00:00
James Turner
181afb7fd0 Catalogs: version-redirect support. 2015-03-15 21:55:54 +01:00
James Turner
9d1354f6bd More logging for directory deletion failures. 2015-03-15 21:55:54 +01:00
James Turner
596591bb64 Catalog install feedback.
- also support removing (uninstalling) a catalog and
all installs relating to it.
2015-03-15 21:55:54 +01:00
Rebecca N. Palmer
a67a984d29 Make nasal/iolib.h available to flightgear (for io.open) 2015-03-13 18:19:58 +00:00
Rebecca N. Palmer
37a963da92 Move Nasal io.open to flightgear 2015-03-13 18:19:48 +00:00
James Turner
384a700e05 FreeBSD / clang fix from Gerald Laplanche 2015-03-11 09:46:03 +00:00
James Turner
7d2ecef14a Whitespace clean-up 2015-03-11 09:43:40 +00:00
James Turner
bc72c34d0f Terrasync logging tweaks 2015-03-11 09:43:24 +00:00
Thomas Geymayer
ca7acb1f2c canvas::Map: Property to keep children aligned to given hdg.
Setting the 'hdg' property on child elements will rotate
them with respect to the heading set on the map projection.
2015-02-26 22:34:21 +01:00
James Turner
1365a02aea Fix where we set OS-X deployment option. 2015-02-24 12:36:28 +00:00
James Turner
611785c04b Kill off allCatalogs list.
No longer needed, and fixes crash on shutdown.
2015-02-20 11:31:15 +00:00
Stuart Buchanan
e5995208a9 Support for tree shadows from Thorsten RENK. 2015-02-19 21:14:07 +00:00
Stuart Buchanan
6f15bb415f materials.xml defined vegetation Effect. 2015-02-17 21:47:51 +00:00
James Turner
ce7f78e0ca Remove use of ‘register’ keyword in this file.
Clang is now warning about this, and it’s certainly useless.
2015-02-12 16:21:15 +00:00
James Turner
6323477a35 Tweak warning flags, for newer Clang.
No functionality changing, just less spam in the compile logs.
2015-02-12 16:21:15 +00:00
Rebecca N. Palmer
8c38f799ad DrawElementsFacade: use ref_ptr instead of mismatched new/free
Found by AddressSanitizer; not seen to crash, but probably best fixed
2015-02-12 15:48:36 +00:00
James Turner
1bf0b7222d Explicitly force libc++ on clang 2015-02-11 15:46:01 +00:00
Stuart Buchanan
0cc5374fe7 Fix VASI/PAPI so they are generated. 2015-02-10 21:19:51 +00:00
James Turner
b2ac9982d4 Better CMake policy detection
- thanks to Rebecca Palmer for suggesting this!
2015-02-10 17:11:31 +00:00
James Turner
84cbfb2e98 Cmake policies conditional on Cmake version. 2015-02-09 16:42:40 +00:00
James Turner
7479cadbba Switch 10.7 on Mac and revert to using libc++
(Deployment on libstdc++ with the 10.9 SDK is just too painful)
2015-02-09 15:12:21 +00:00
James Turner
f711306085 Force SDK version / C++ library on Mac. 2015-02-08 13:46:09 +00:00
Peter Sadrozinski
148640be34 memory reduced tile loading.
- do not save the TileGeometryBin and matcach in the randomObjectCallback
- recreate matcache, and get TileGeometry from scenegraph
- split obj.cxx into three distinct files - loadBTG, load surface geometry, and load tile details
- includes fix for sceneries that have missing materials
2015-01-19 21:06:27 +01:00
Rebecca N. Palmer
27a91062bd Fix endianness tests, allowing arm64 support
https://buildd.debian.org/status/logs.php?pkg=simgear&ver=3.2.0~git20140719%2B4a9125-1&suite=experimental
https://launchpadlibrarian.net/183053167/buildlog_ubuntu-utopic-arm64.simgear_3.0.0-4_FAILEDTOBUILD.txt.gz
2015-01-18 21:53:22 +00:00
Rebecca N. Palmer
dc1816bb08 Fix UpdateOnceCallback crash (bug 1554/1556/1568) 2015-01-18 21:29:19 +00:00
Torsten Dreyer
e836e85697 Bump version to 3.5.0 2015-01-17 19:33:25 +01:00
FlightGear Flight Simulator
2d00653f6e Bump version number to 3.4.0 2015-01-17 19:26:46 +01:00
Stuart Buchanan
4647ce2da5 Protect against divide-by-zero error.
Patch from Emilian Huminiuc.
2015-01-15 21:47:22 +00:00
Stuart Buchanan
51d43f809e Fix directional lighting 2015-01-05 20:50:34 +00:00
Peter Sadrozinski
370a115ab9 - remove the test of the test.. 2014-12-27 13:19:29 -05:00
Peter Sadrozinski
32b60f9b80 - fix binobj unit test. Simgear now rejects zero area triangles in .btg files, and the unit test could generate them. 2014-12-27 13:08:53 -05:00
Peter Sadrozinski
beeaef3868 - fix for index overrun when building TexturedTriangleArray
- fix for ws2.0 zero area triangles - drop them when loading
2014-12-26 13:07:33 -05:00
James Turner
ddd9691439 Explicitly track not-found responses from SVN.
When SVN reports a path is not found (ocean tile), track
this data explicitly and cache the result. Reduces backend
hits for missing tiles.
2014-12-01 17:49:03 +00:00
Stuart Buchanan
9da0031039 Fix PagedLOD for random objects.
- Only generate the object set and flights from the data once.
- Only expire the PagedLOD node after a suitable period of time.
2014-11-28 21:57:37 +00:00
Thomas Geymayer
9537876bba Nasal: add an naRef to ghosts to allow for proper gc of dependent objects/ghosts.
This allows for binding the lifetime of any nasal object to
the lifetime of a ghost. Otherwise circular references from
objects saved within the ghost would prevent the ghost from
being garbage collected.
2014-11-23 23:45:22 +01:00
Stuart Buchanan
958ae9bdf0 Fix two bugs in random object placement 2014-11-21 22:14:03 +00:00
Torsten Dreyer
023b5a09f7 Make expiry time for paged models settable from props
Our paged models used the default minimumExpiryTime of zero seconds
which caused frequent stutter with AI traffic loaded.
This patch sets the minimumExpiryTime to 180 seconds, more than enough
to hold the models in memory during a full standard rate turn.

The property to set the expiry time is
/sim/rendering/plod-minimum-expiry-time-secs
2014-11-19 17:23:29 +01:00
Clément de l'Hamaide
46fe57fb8d UniformFactory: fix Rembrandt light 2014-11-16 20:22:29 +01:00
Stuart Buchanan
07e09bb88c Support alpha for cloud definitions Thorsten RENK 2014-11-13 20:38:28 +00:00
James Turner
1b7f310ea6 Merge FreeBSD patches.
Taken from:
http://svnweb.freebsd.org/ports/head/devel/simgear/files/
2014-11-11 22:29:24 +00:00
Stuart Buchanan
365ddb84a7 Limit number of random objects per triangle 2014-11-07 22:22:55 +00:00
Stuart Buchanan
5fef44b11c Change parameter name to avoid clash with cull-face 2014-10-27 22:40:27 +00:00
Stuart Buchanan
1480aa9bb8 Pass whether light is directional to shader.
Patch from Thorsten RENK.
2014-10-21 20:27:46 +01:00
Torsten Dreyer
75271c44a8 Precipitation updates from ThorstenR
Since the consensus seems to be that the precipitation clipping issue is with the panel code, attached is  my proposed update for the precipitation system in SG and FG

* without corresponding control structures in FGData it falls back to default, except I have fixed an inconsistency in freezing behavior - previously rain changed suddenly to snow when the temperature dropped below zero, but the reverse transition was dragged out and gave odd visible motion with the wind as snow gradually changed back to rain with the particle speed not well defined. Now both transitions are sudden. And I see no more particles flow against the wind

* with

 <!-- definitions for the detailed precipitation manager -->
 <precipitation-control>
     <rain-droplet-size type="float" userarchive="n">0.015</rain-droplet-size>
     <snow-flake-size type="float" userarchive="n">0.03</snow-flake-size>
     <detailed-precipitation type="bool" userarchive="n">false</detailed-precipitation>
     <illumination type="float" userarchive="n">1.0</illumination>
     <clip-distance type="float" userarchive="n">5.0</clip-distance>
  </precipitation-control>

added to Environment/environment.xml, the new system allows to switch more detailed management on. This provides

* explicit setting of rain droplet size and snow flake size by the weather system

* automatic sqrt(r) scaling of the vertical speed of raindrops

* automatic transition to snow when freezing for small droplets but hail for large droplet sizes (looks like snow, but has different particle dynamics)

* an illumination scaling factor to dim the precipitating based on the light we have in the scene (I still need to devise a property rule to set this automatically)

The clip distance is also exposed now and considered at startup of the system - might be useful for e.g. airships when the gas bag provides rain cover (?)   or to be simply off for open airplanes
2014-10-21 10:46:48 +02:00
Torsten Dreyer
543f1b7902 Set sun color below horizon
Thorsten Renk:
The following patch sets the sun color to alpha=0 when
the sun is below the local horizon, removing the oddity
that the sun is seen 'through' the terrain when the terrain
at large distance is rendered by the skydome.
2014-10-08 12:45:01 +02:00
Stuart Buchanan
93a63a0678 Further work to clean up UniformCache for Effects 2014-09-27 22:05:30 +01:00
Torsten Dreyer
2bf79a2fa1 Merge branch 'UniformFactory' into next
Merging in Stuart's fix for the Effect system
2014-09-27 21:50:44 +02:00
Torsten Dreyer
ab956f15c3 A better fix for crash in the Effect System
Stuart has improved the UniformCache approach, here are his
changes:
- We have a UniformCache so that each unique Uniform is only created once
- As part of the UniformFactory we also have a queue of listeners that are still to be added
- When the main thread sends an Update node visitor across the Effects,
  all queued listeners are de-queued and added.
2014-09-27 21:48:36 +02:00
Thomas Geymayer
deceee8997 Fix compiler warnings. 2014-09-22 18:24:13 +02:00
Thomas Geymayer
b3c7d63809 Let ENABLE_TESTS enable/disable also the new Boost.Tests. 2014-09-22 18:21:52 +02:00
Clément de l'Hamaide
2026c665b2 Improve the <usage> tag feature
Do not load the <model> if <usage> tag is found as child.
Instead the load is triggered later by FlightGear
2014-09-21 22:05:45 +02:00
Thomas Geymayer
36fd005bb9 cppbind: check if ghost is of wrong type.
- Throw an exception if converting an object
   from Nasal fails due to a wrong type (nil
   does not throw).
 - Update cppbind test cases accordingly (and
   refactor another test suite to use Boost.
   Test).
2014-09-15 23:42:12 +02:00
Torsten Dreyer
46bed67cce first stab at UniformFactory 2014-09-05 11:28:58 +02:00
Torsten Dreyer
5b9af0c0aa Revert "Partial fix for crash in SGPropertyNode::fireValueChanged"
This reverts commit f33ad357e9.
2014-09-05 11:28:28 +02:00
Thomas Geymayer
85090180d0 canvas::Text: fix global StateSet and line start cursor pos with empty line. 2014-08-31 19:24:58 +02:00
Torsten Dreyer
f33ad357e9 Partial fix for crash in SGPropertyNode::fireValueChanged
The effect system used Listeners on property nodes to get the values
for shader uniforms. These listeners get deleted by an osg thread
causing access to freed memory when this happens while the main thread
calls fireValueChanged.

This patch changes the update method to polling for scalar properties.
This isn't 100% threadsafe, too. But at least it does not crash anymore.
2014-08-29 15:30:25 +02:00
Clément de l'Hamaide
c30ce67e16 Remove Textures.high logic 2014-08-27 22:08:20 +02:00
Torsten Dreyer
3ca7369fb2 Canvas: add stroke-linejoin handling for path elements 2014-08-26 00:08:35 +02:00
Thomas Geymayer
088ce31f7c canvas::KeyboardEvent: C0/C1 control characters are not printable. 2014-08-25 21:49:44 +02:00
Thomas Geymayer
4f94c22241 Canvas: add method clearFocusElement. 2014-08-25 21:49:21 +02:00
Thomas Geymayer
e1791b3006 canvas::Text: clean up and expose character/cursor positions. 2014-08-23 15:54:07 +02:00
Stuart Buchanan
e608ed5a01 Use surface-lights effect for random tile lights. 2014-08-10 20:20:42 +01:00
Thomas Geymayer
35ebb16215 Canvas: prepare for keypress events. 2014-08-10 19:39:18 +02:00
Thomas Geymayer
68d0891665 Canvas: fix element mouse hit detection with OSG 3.3.2. 2014-08-10 15:37:43 +02:00
Stuart Buchanan
b11ff19a0f Fix VS2010 lack of fminf 2014-08-10 12:54:58 +01:00
Stuart Buchanan
e7e616e07c New materials.xml format 2014-08-09 20:34:08 +01:00
bcoconni
14f2f9e917 Added some OSG headers for the correct evaluation of the OSG_VERSION_LESS_THAN macro. 2014-08-09 19:53:19 +02:00
Thomas Geymayer
791273c61d Update for OpenSceneGraph 3.3.2 API changes. 2014-08-09 18:13:45 +02:00
Thomas Geymayer
519326f751 Add simple keyboard event demo application. 2014-08-08 00:59:06 +02:00
Thomas Geymayer
d1f5d92a7b Move canvas::AlignmentFlag to separate file.
Mapping in a separate file allows easier exposing of
values and string representation to Nasal.
2014-08-03 16:39:26 +02:00
Christian Schmitt
f448898531 Fix lights appearing three times.
The 3 lights showing up are fixed by my patch. It's the old way of
calculating a normal (PLIB-style) that makes them show up.
2014-08-03 13:13:59 +02:00
Thomas Geymayer
d9b66fc0ef canvas::Layout: support for alignment.
Set alignment inside layouts, taking care of where
excess space is distributed.
2014-08-03 12:02:39 +02:00
Thomas Geymayer
3bcd0bafd5 Lots of (mostly) doxygen fixes/cleanup. 2014-08-01 00:13:25 +02:00
Thomas Geymayer
942181c8ae Canvas: Support for preventDefault() on Events. 2014-07-30 17:16:26 +02:00
Thomas Geymayer
7df39b9fc8 Fallback for old Boost (also with UTF8-CPP library). 2014-07-30 12:44:21 +02:00
Thomas Geymayer
f41b18f064 Improve (mostly Canvas event related) documentation. 2014-07-29 23:57:59 +02:00
Thomas Geymayer
c5d649aa0b Canvas: basic Keyboard event support (with input focus). 2014-07-29 22:22:20 +02:00
Thomas Geymayer
64ac22f50c Canvas: warn for missing tff and png plugins. 2014-07-27 12:11:09 +02:00
Thomas Geymayer
719ee36f5c Canvas: backdrop/stroke option for text (based on Gijs patch). 2014-07-27 11:05:49 +02:00
Thomas Geymayer
92851135d4 Doxygen: disable (not working) latex output and update version. 2014-07-22 12:51:01 +02:00
Thomas Geymayer
76fc47b24b canvas::Layout: support for contents margins. 2014-07-22 12:00:24 +02:00
Thomas Geymayer
f25abad9d7 Move overflow protected add helpers to math. 2014-07-22 11:45:28 +02:00
Thomas Geymayer
23413b4781 canvas::Layout: clear parent/canvas after calling onRemove. 2014-07-21 23:56:41 +02:00
Thomas Geymayer
e036dfc5bf Hopefully final fix for old gcc... 2014-07-21 13:26:09 +02:00
Thomas Geymayer
9260bea850 One more fix for old gcc. 2014-07-21 12:22:33 +02:00
Thomas Geymayer
c1f09034e0 Trying to make old gcc on Jenkins happy. 2014-07-21 10:54:31 +02:00
Thomas Geymayer
557e4f75b5 canvas::Layout: support for hiding items. 2014-07-21 00:25:59 +02:00
Thomas Geymayer
e71d6b24d7 cppbind: helper to call Nasal methods on NasalWidget. 2014-07-21 00:22:15 +02:00
Thomas Geymayer
726a4c6d10 canvas::NasalWidget: check for empty setGeometry callback. 2014-07-20 23:31:32 +02:00
Thomas Geymayer
6af8d32078 cppbind: fix Ghost casting/storage in polymorphic class hierarchies. 2014-07-20 23:17:33 +02:00
Thomas Geymayer
f6b16e2ba8 canvas::Element: floating point scissor coordinates.
GL_SCISSOR itself only supports integer coordinates, but
with reference frames different from GLOBAL transforms
influence the position of the clipping frame, possibly
resulting in wrong positions due to too low precision.
2014-07-19 20:52:17 +02:00
Thomas Geymayer
e415b08da4 canvas::BoxLayout: fix parent ref on add/remove. 2014-07-17 15:10:35 +02:00
Torsten Dreyer
1d93e8d61e New Version: 3.3.0 2014-07-17 14:54:35 +02:00
241 changed files with 12844 additions and 4356 deletions

View File

@@ -2,3 +2,4 @@ if (NOT SYSTEM_EXPAT)
add_subdirectory(expat)
endif()
add_subdirectory(utf8)

17
3rdparty/utf8/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,17 @@
include (SimGearComponent)
set(HEADERS
source/utf8.h
)
set(HEADERS_utf8
source/utf8/checked.h
source/utf8/core.h
source/utf8/unchecked.h
)
set(SOURCES
)
simgear_component(utf8 3rdparty/utf8 "${SOURCES}" "${HEADERS}")
simgear_component(utf8-internal 3rdparty/utf8/utf8 "" "${HEADERS_utf8}")

12
3rdparty/utf8/doc/ReleaseNotes vendored Normal file
View File

@@ -0,0 +1,12 @@
utf8 cpp library
Release 2.3.4
A minor bug fix release. Thanks to all who reported bugs.
Note: Version 2.3.3 contained a regression, and therefore was removed.
Changes from version 2.3.2
- Bug fix [39]: checked.h Line 273 and unchecked.h Line 182 have an extra ';'
- Bug fix [36]: replace_invalid() only works with back_inserter
Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes

1789
3rdparty/utf8/doc/utf8cpp.html vendored Normal file

File diff suppressed because it is too large Load Diff

34
3rdparty/utf8/source/utf8.h vendored Normal file
View File

@@ -0,0 +1,34 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "utf8/checked.h"
#include "utf8/unchecked.h"
#endif // header guard

327
3rdparty/utf8/source/utf8/checked.h vendored Normal file
View File

@@ -0,0 +1,327 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
#include <stdexcept>
namespace utf8
{
// Base for the exceptions that may be thrown from the library
class exception : public ::std::exception {
};
// Exceptions that may be thrown from the library functions.
class invalid_code_point : public exception {
uint32_t cp;
public:
invalid_code_point(uint32_t cp) : cp(cp) {}
virtual const char* what() const throw() { return "Invalid code point"; }
uint32_t code_point() const {return cp;}
};
class invalid_utf8 : public exception {
uint8_t u8;
public:
invalid_utf8 (uint8_t u) : u8(u) {}
virtual const char* what() const throw() { return "Invalid UTF-8"; }
uint8_t utf8_octet() const {return u8;}
};
class invalid_utf16 : public exception {
uint16_t u16;
public:
invalid_utf16 (uint16_t u) : u16(u) {}
virtual const char* what() const throw() { return "Invalid UTF-16"; }
uint16_t utf16_word() const {return u16;}
};
class not_enough_room : public exception {
public:
virtual const char* what() const throw() { return "Not enough space"; }
};
/// The library API - functions intended to be called by the users
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (!utf8::internal::is_code_point_valid(cp))
throw invalid_code_point(cp);
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
throw not_enough_room();
case internal::INVALID_LEAD:
out = utf8::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it, octet_iterator end)
{
uint32_t cp = 0;
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
switch (err_code) {
case internal::UTF8_OK :
break;
case internal::NOT_ENOUGH_ROOM :
throw not_enough_room();
case internal::INVALID_LEAD :
case internal::INCOMPLETE_SEQUENCE :
case internal::OVERLONG_SEQUENCE :
throw invalid_utf8(*it);
case internal::INVALID_CODE_POINT :
throw invalid_code_point(cp);
}
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it, octet_iterator end)
{
return utf8::next(it, end);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it, octet_iterator start)
{
// can't do much if it == start
if (it == start)
throw not_enough_room();
octet_iterator end = it;
// Go back until we hit either a lead octet or start
while (utf8::internal::is_trail(*(--it)))
if (it == start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
return utf8::peek_next(it, end);
}
/// Deprecated in versions that include "prior"
template <typename octet_iterator>
uint32_t previous(octet_iterator& it, octet_iterator pass_start)
{
octet_iterator end = it;
while (utf8::internal::is_trail(*(--it)))
if (it == pass_start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
octet_iterator temp = it;
return utf8::next(temp, end);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n, octet_iterator end)
{
for (distance_type i = 0; i < n; ++i)
utf8::next(it, end);
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::next(first, last);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
if (start != end) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
if (utf8::internal::is_trail_surrogate(trail_surrogate))
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
else
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
}
else
throw invalid_utf16(static_cast<uint16_t>(cp));
}
// Lone trail surrogate
else if (utf8::internal::is_trail_surrogate(cp))
throw invalid_utf16(static_cast<uint16_t>(cp));
result = utf8::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start != end) {
uint32_t cp = utf8::next(start, end);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start != end)
(*result++) = utf8::next(start, end);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
octet_iterator it;
octet_iterator range_start;
octet_iterator range_end;
public:
iterator () {}
explicit iterator (const octet_iterator& octet_it,
const octet_iterator& range_start,
const octet_iterator& range_end) :
it(octet_it), range_start(range_start), range_end(range_end)
{
if (it < range_start || it > range_end)
throw std::out_of_range("Invalid utf-8 iterator position");
}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::next(temp, range_end);
}
bool operator == (const iterator& rhs) const
{
if (range_start != rhs.range_start || range_end != rhs.range_end)
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
utf8::next(it, range_end);
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
utf8::next(it, range_end);
return temp;
}
iterator& operator -- ()
{
utf8::prior(it, range_start);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::prior(it, range_start);
return temp;
}
}; // class iterator
} // namespace utf8
#endif //header guard

329
3rdparty/utf8/source/utf8/core.h vendored Normal file
View File

@@ -0,0 +1,329 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include <iterator>
namespace utf8
{
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
// You may need to change them to match your system.
// These typedefs have the same names as ones from cstdint, or boost/cstdint
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Helper code - not intended to be directly called by the library users. May be changed at any time
namespace internal
{
// Unicode constants
// Leading (high) surrogates: 0xd800 - 0xdbff
// Trailing (low) surrogates: 0xdc00 - 0xdfff
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
// Maximum valid value for a Unicode code point
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
template<typename octet_type>
inline uint8_t mask8(octet_type oc)
{
return static_cast<uint8_t>(0xff & oc);
}
template<typename u16_type>
inline uint16_t mask16(u16_type oc)
{
return static_cast<uint16_t>(0xffff & oc);
}
template<typename octet_type>
inline bool is_trail(octet_type oc)
{
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
}
template <typename u16>
inline bool is_lead_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
}
template <typename u16>
inline bool is_trail_surrogate(u16 cp)
{
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u16>
inline bool is_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u32>
inline bool is_code_point_valid(u32 cp)
{
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
}
template <typename octet_iterator>
inline typename std::iterator_traits<octet_iterator>::difference_type
sequence_length(octet_iterator lead_it)
{
uint8_t lead = utf8::internal::mask8(*lead_it);
if (lead < 0x80)
return 1;
else if ((lead >> 5) == 0x6)
return 2;
else if ((lead >> 4) == 0xe)
return 3;
else if ((lead >> 3) == 0x1e)
return 4;
else
return 0;
}
template <typename octet_difference_type>
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
{
if (cp < 0x80) {
if (length != 1)
return true;
}
else if (cp < 0x800) {
if (length != 2)
return true;
}
else if (cp < 0x10000) {
if (length != 3)
return true;
}
return false;
}
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
/// Helper for get_sequence_x
template <typename octet_iterator>
utf_error increase_safely(octet_iterator& it, octet_iterator end)
{
if (++it == end)
return NOT_ENOUGH_ROOM;
if (!utf8::internal::is_trail(*it))
return INCOMPLETE_SEQUENCE;
return UTF8_OK;
}
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
/// get_sequence_x functions decode utf-8 sequences of the length x
template <typename octet_iterator>
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
template <typename octet_iterator>
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
// Save the original value of it so we can go back in case of failure
// Of course, it does not make much sense with i.e. stream iterators
octet_iterator original_it = it;
uint32_t cp = 0;
// Determine the sequence length based on the lead octet
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
const octet_difference_type length = utf8::internal::sequence_length(it);
// Get trail octets and calculate the code point
utf_error err = UTF8_OK;
switch (length) {
case 0:
return INVALID_LEAD;
case 1:
err = utf8::internal::get_sequence_1(it, end, cp);
break;
case 2:
err = utf8::internal::get_sequence_2(it, end, cp);
break;
case 3:
err = utf8::internal::get_sequence_3(it, end, cp);
break;
case 4:
err = utf8::internal::get_sequence_4(it, end, cp);
break;
}
if (err == UTF8_OK) {
// Decoding succeeded. Now, security checks...
if (utf8::internal::is_code_point_valid(cp)) {
if (!utf8::internal::is_overlong_sequence(cp, length)){
// Passed! Return here.
code_point = cp;
++it;
return UTF8_OK;
}
else
err = OVERLONG_SEQUENCE;
}
else
err = INVALID_CODE_POINT;
}
// Failure branch - restore the original value of the iterator
it = original_it;
return err;
}
template <typename octet_iterator>
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
uint32_t ignored;
return utf8::internal::validate_next(it, end, ignored);
}
} // namespace internal
/// The library API - functions intended to be called by the users
// Byte order mark
const uint8_t bom[] = {0xef, 0xbb, 0xbf};
template <typename octet_iterator>
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
{
octet_iterator result = start;
while (result != end) {
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
if (err_code != internal::UTF8_OK)
return result;
}
return result;
}
template <typename octet_iterator>
inline bool is_valid(octet_iterator start, octet_iterator end)
{
return (utf8::find_invalid(start, end) == end);
}
template <typename octet_iterator>
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
{
return (
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
);
}
//Deprecated in release 2.3
template <typename octet_iterator>
inline bool is_bom (octet_iterator it)
{
return (
(utf8::internal::mask8(*it++)) == bom[0] &&
(utf8::internal::mask8(*it++)) == bom[1] &&
(utf8::internal::mask8(*it)) == bom[2]
);
}
} // namespace utf8
#endif // header guard

228
3rdparty/utf8/source/utf8/unchecked.h vendored Normal file
View File

@@ -0,0 +1,228 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
namespace utf8
{
namespace unchecked
{
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it)
{
uint32_t cp = utf8::internal::mask8(*it);
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
switch (length) {
case 1:
break;
case 2:
it++;
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
break;
case 3:
++it;
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
++it;
cp += (*it) & 0x3f;
break;
case 4:
++it;
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
++it;
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
++it;
cp += (*it) & 0x3f;
break;
}
++it;
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it)
{
return utf8::unchecked::next(it);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it)
{
while (utf8::internal::is_trail(*(--it))) ;
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
// Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
template <typename octet_iterator>
inline uint32_t previous(octet_iterator& it)
{
return utf8::unchecked::prior(it);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n)
{
for (distance_type i = 0; i < n; ++i)
utf8::unchecked::next(it);
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::unchecked::next(first);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
}
result = utf8::unchecked::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start < end) {
uint32_t cp = utf8::unchecked::next(start);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::unchecked::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start < end)
(*result++) = utf8::unchecked::next(start);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
octet_iterator it;
public:
iterator () {}
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
bool operator == (const iterator& rhs) const
{
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
::std::advance(it, utf8::internal::sequence_length(it));
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
::std::advance(it, utf8::internal::sequence_length(it));
return temp;
}
iterator& operator -- ()
{
utf8::unchecked::prior(it);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::unchecked::prior(it);
return temp;
}
}; // class iterator
} // namespace utf8::unchecked
} // namespace utf8
#endif // header guard

View File

@@ -1,8 +1,26 @@
cmake_minimum_required (VERSION 2.6.4)
cmake_minimum_required (VERSION 2.8.11)
if(COMMAND cmake_policy)
if(POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
if(POLICY CMP0042)
cmake_policy(SET CMP0042 NEW)
endif()
endif()
include (CheckFunctionExists)
include (CheckIncludeFile)
include (CheckLibraryExists)
include (CheckCXXSourceCompiles)
include (CheckCXXCompilerFlag)
include (GenerateExportHeader)
# using 10.7 because boost requires libc++ and 10.6 doesn't include it
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
# only relevant for building shared libs but let's set it regardless
set(CMAKE_OSX_RPATH 1)
project(SimGear)
@@ -34,7 +52,7 @@ SET(CPACK_INSTALL_CMAKE_PROJECTS ${CMAKE_CURRENT_BINARY_DIR};SimGear;ALL;/)
# split version string into components, note CMAKE_MATCH_0 is the entire regexp match
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CPACK_PACKAGE_VERSION ${SIMGEAR_VERSION} )
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
set(CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
@@ -62,12 +80,7 @@ endif(NOT CMAKE_BUILD_TYPE)
# Determine name of library installation directory, i.e. "lib" vs "lib64", which
# differs between all Debian-based vs all other Linux distros.
# See cmake bug #11964, http://cmake.org/gitweb?p=cmake.git;a=commit;h=126c993d
# GNUInstallDirs requires CMake >= 2.8.5, use own file for older cmake
if(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
include(GNUInstallDirs)
else(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
include(OldGNUInstallDirs)
endif(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
include(GNUInstallDirs)
message(STATUS "Library installation directory: ${CMAKE_INSTALL_LIBDIR}")
#####################################################################################
@@ -104,6 +117,7 @@ option(ENABLE_RTI "Set to ON to build SimGear with RTI support" OFF)
option(ENABLE_TESTS "Set to OFF to disable building SimGear's test applications" ON)
option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support" ON)
option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON)
option(ENABLE_CURL "Set to ON to use libCurl as the HTTP client backend" OFF)
if (MSVC)
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
@@ -161,13 +175,23 @@ endif (MSVC AND MSVC_3RDPARTY_ROOT)
if(APPLE)
find_library(COCOA_LIBRARY Cocoa)
# this should be handled by setting CMAKE_OSX_DEPLOYMENT_TARGET
# but it's not working reliably, so forcing it for now
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.7")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR
${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
find_package(Threads REQUIRED)
endif()
# Somehow this only works if included before searching for Boost...
include(BoostTestTargets)
find_package(Boost REQUIRED)
set (BOOST_CXX_FLAGS "-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION -DBOOST_BIMAP_DISABLE_SERIALIZATION")
set (BOOST_CXX_FLAGS "-DBOOST_BIMAP_DISABLE_SERIALIZATION")
if(SIMGEAR_HEADLESS)
message(STATUS "SimGear mode: HEADLESS")
@@ -175,17 +199,21 @@ if(SIMGEAR_HEADLESS)
else()
message(STATUS "SimGear mode: NORMAL")
find_package(OpenGL REQUIRED)
if (ENABLE_SOUND)
find_package(OpenAL REQUIRED)
message(STATUS "Sound support: ENABLED")
endif(ENABLE_SOUND)
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgUtil)
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil)
endif(SIMGEAR_HEADLESS)
find_package(ZLIB REQUIRED)
find_package(Threads REQUIRED)
if (ENABLE_CURL)
find_package(CURL REQUIRED)
message(STATUS "Curl HTTP client: ENABLED")
endif()
if (SYSTEM_EXPAT)
message(STATUS "Requested to use system Expat library, forcing SIMGEAR_SHARED to true")
@@ -197,8 +225,8 @@ else()
# XML_STATIC is important to avoid sg_expat_external.h
# declaring symbols as declspec(import)
add_definitions(-DHAVE_EXPAT_CONFIG_H -DXML_STATIC)
set(EXPAT_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/3rdparty/expat
set(EXPAT_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/3rdparty/expat
${PROJECT_BINARY_DIR}/3rdparty/expat)
endif(SYSTEM_EXPAT)
@@ -275,13 +303,13 @@ SET(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "add a postfix, usually empty on wi
# isnan might not be real symbol, so can't check using function_exists
check_cxx_source_compiles(
"#include <cmath>
void f() { isnan(0.0);} "
"#include <cmath>
int main() { return isnan(0.0);} "
HAVE_ISNAN)
check_cxx_source_compiles(
"#include <cmath>
void f() { std::isnan(0.0);} "
"#include <cmath>
int main() { return std::isnan(0.0);} "
HAVE_STD_ISNAN)
if(CMAKE_COMPILER_IS_GNUCXX)
@@ -297,8 +325,12 @@ if(CMAKE_COMPILER_IS_GNUCXX)
endif(CMAKE_COMPILER_IS_GNUCXX)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual")
set(WARNING_FLAGS_C "-Wall")
# Boost redeclares class members
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual -Wno-redeclared-class-member")
set(WARNING_FLAGS_C "-Wall")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@@ -320,16 +352,16 @@ if(WIN32)
# foreach(warning 4244 4251 4267 4275 4290 4786 4305 4996)
# SET(WARNING_FLAGS "${WARNING_FLAGS} /wd${warning}")
# endforeach(warning)
set(MSVC_FLAGS "-DWIN32 -DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS /wd4996 /wd4250 -Dstrdup=_strdup")
if (${MSVC_VERSION} GREATER 1599)
set( MSVC_LD_FLAGS "/FORCE:MULTIPLE" )
endif (${MSVC_VERSION} GREATER 1599)
endif(MSVC)
# assumed on Windows
set(HAVE_GETLOCALTIME 1)
set( WINSOCK_LIBRARY "ws2_32.lib" )
set( RT_LIBRARY "winmm" )
endif(WIN32)
@@ -338,16 +370,17 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
# use BEFORE to ensure local directories are used first,
# use BEFORE to ensure local directories are used first,
# ahead of system-installed libs
include_directories(BEFORE ${PROJECT_SOURCE_DIR})
include_directories(BEFORE ${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
${OPENAL_INCLUDE_DIR}
${CURL_INCLUDE_DIRS}
)
add_definitions(-DHAVE_CONFIG_H)
@@ -376,7 +409,8 @@ set(TEST_LIBS_INTERNAL_CORE
${WINSOCK_LIBRARY}
${RT_LIBRARY}
${DL_LIBRARY}
${COCOA_LIBRARY})
${COCOA_LIBRARY}
${CURL_LIBRARIES})
set(TEST_LIBS SimGearCore ${TEST_LIBS_INTERNAL_CORE})
if(NOT SIMGEAR_HEADLESS)
@@ -385,9 +419,45 @@ endif()
install (FILES ${PROJECT_BINARY_DIR}/simgear/simgear_config.h DESTINATION include/simgear/)
include_directories(3rdparty/utf8/source)
add_subdirectory(3rdparty)
add_subdirectory(simgear)
#-----------------------------------------------------------------------------
### Export stuff, see https://cmake.org/cmake/help/v3.2/manual/cmake-packages.7.html#creating-packages
#-----------------------------------------------------------------------------
generate_export_header(SimGearCore)
if(NOT SIMGEAR_HEADLESS)
generate_export_header(SimGearScene)
endif()
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
VERSION ${SIMGEAR_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_file(SimGearConfig.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
@ONLY
)
set(ConfigPackageLocation lib/cmake/SimGear)
install(EXPORT SimGearTargets
DESTINATION ${ConfigPackageLocation}
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
DESTINATION ${ConfigPackageLocation}
COMPONENT Devel
)
#-----------------------------------------------------------------------------
### uninstall target
#-----------------------------------------------------------------------------
@@ -397,5 +467,3 @@ CONFIGURE_FILE(
IMMEDIATE @ONLY)
ADD_CUSTOM_TARGET(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")

View File

@@ -51,15 +51,15 @@ if("${Boost_VERSION}0" LESS "1034000")
"NOTE: boost::test-based targets and tests cannot "
"be added: boost >= 1.34.0 required but not found. "
"(found: '${Boost_VERSION}'; want >=103400) ")
if(BUILD_TESTING)
if(ENABLE_TESTS)
message(FATAL_ERROR
${_shared_msg}
"You may disable BUILD_TESTING to continue without the "
"You may disable ENABLE_TESTS to continue without the "
"tests.")
else()
message(STATUS
${_shared_msg}
"BUILD_TESTING disabled, so continuing anyway.")
"ENABLE_TESTS disabled, so continuing anyway.")
endif()
endif()
@@ -88,7 +88,7 @@ if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
endif()
function(add_boost_test _name)
if(NOT BUILD_TESTING)
if(NOT ENABLE_TESTS)
return()
endif()

View File

@@ -1,182 +0,0 @@
# - Define GNU standard installation directories
# Provides install directory variables as defined for GNU software:
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
# Inclusion of this module defines the following variables:
# CMAKE_INSTALL_<dir> - destination for files of a given type
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
# where <dir> is one of:
# BINDIR - user executables (bin)
# SBINDIR - system admin executables (sbin)
# LIBEXECDIR - program executables (libexec)
# SYSCONFDIR - read-only single-machine data (etc)
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
# LOCALSTATEDIR - modifiable single-machine data (var)
# LIBDIR - object code libraries (lib or lib64)
# INCLUDEDIR - C header files (include)
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
# DATAROOTDIR - read-only architecture-independent data root (share)
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
# INFODIR - info documentation (DATAROOTDIR/info)
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
# MANDIR - man documentation (DATAROOTDIR/man)
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
# install() commands for the corresponding file type. If the includer does
# not define a value the above-shown default will be used and the value will
# appear in the cache for editing by the user.
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
# from the corresponding destination by prepending (if necessary) the value
# of CMAKE_INSTALL_PREFIX.
#=============================================================================
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
# Copyright 2011 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# Installation directories
#
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(_LIBDIR_DEFAULT "lib")
# Override this default 'lib' with 'lib64' iff:
# - we are on Linux system but NOT cross-compiling
# - we are NOT on debian
# - we are on a 64 bits system
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
# Note that the future of multi-arch handling may be even
# more complicated than that: http://wiki.debian.org/Multiarch
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
AND NOT CMAKE_CROSSCOMPILING
AND NOT EXISTS "/etc/debian_version")
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
message(AUTHOR_WARNING
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
"Please enable at least one language before including GNUInstallDirs.")
else()
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(_LIBDIR_DEFAULT "lib64")
endif()
endif()
endif()
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
endif()
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
endif()
#-----------------------------------------------------------------------------
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
# the cache and store the defaults in local variables if the cache values are
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
if(NOT CMAKE_INSTALL_DATADIR)
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
endif()
if(NOT CMAKE_INSTALL_INFODIR)
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
endif()
if(NOT CMAKE_INSTALL_LOCALEDIR)
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
endif()
if(NOT CMAKE_INSTALL_MANDIR)
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
endif()
if(NOT CMAKE_INSTALL_DOCDIR)
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
endif()
#-----------------------------------------------------------------------------
mark_as_advanced(
CMAKE_INSTALL_BINDIR
CMAKE_INSTALL_SBINDIR
CMAKE_INSTALL_LIBEXECDIR
CMAKE_INSTALL_SYSCONFDIR
CMAKE_INSTALL_SHAREDSTATEDIR
CMAKE_INSTALL_LOCALSTATEDIR
CMAKE_INSTALL_LIBDIR
CMAKE_INSTALL_INCLUDEDIR
CMAKE_INSTALL_OLDINCLUDEDIR
CMAKE_INSTALL_DATAROOTDIR
CMAKE_INSTALL_DATADIR
CMAKE_INSTALL_INFODIR
CMAKE_INSTALL_LOCALEDIR
CMAKE_INSTALL_MANDIR
CMAKE_INSTALL_DOCDIR
)
# Result directories
#
foreach(dir
BINDIR
SBINDIR
LIBEXECDIR
SYSCONFDIR
SHAREDSTATEDIR
LOCALSTATEDIR
LIBDIR
INCLUDEDIR
OLDINCLUDEDIR
DATAROOTDIR
DATADIR
INFODIR
LOCALEDIR
MANDIR
DOCDIR
)
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
else()
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
endif()
endforeach()

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = SimGear
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 2.11.0
PROJECT_NUMBER = 3.3.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -744,30 +744,7 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched.
INPUT = DoxygenMain.cxx \
simgear/bucket \
simgear/canvas \
simgear/compiler.h \
simgear/constants.h \
simgear/debug \
simgear/environment \
simgear/ephemeris \
simgear/io \
simgear/magvar \
simgear/math \
simgear/misc \
simgear/nasal \
simgear/props \
simgear/route \
simgear/scene \
simgear/screen \
simgear/serial \
simgear/structure \
simgear/sg_inlines.h \
simgear/sg_traits.hxx \
simgear/sound \
simgear/threads \
simgear/timing \
simgear/xml
simgear
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1568,7 +1545,7 @@ EXTRA_SEARCH_MAPPINGS =
# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = YES
GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@@ -1923,7 +1900,7 @@ ENABLE_PREPROCESSING = YES
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = NO
MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and

16
SimGearConfig.cmake.in Normal file
View File

@@ -0,0 +1,16 @@
include(CMakeFindDependencyMacro)
find_dependency(ZLIB)
find_dependency(Threads)
# OSG
set(SIMGEAR_HEADLESS @SIMGEAR_HEADLESS@)
set(SIMGEAR_SOUND @ENABLE_SOUND@)
# OpenAL isn't a public dependency, so maybe not needed
#if (SIMGEAR_SOUND)
# find_dependency(OpenAL)
#endif()
include("${CMAKE_CURRENT_LIST_DIR}/SimGearTargets.cmake")

View File

@@ -1,7 +1,7 @@
file(WRITE ${PROJECT_BINARY_DIR}/simgear/version.h "#define SIMGEAR_VERSION ${SIMGEAR_VERSION}")
foreach( mylibfolder
foreach( mylibfolder
bucket
bvh
debug
@@ -54,9 +54,11 @@ if(SIMGEAR_SHARED)
set_property(TARGET SimGearCore PROPERTY LINKER_LANGUAGE CXX)
set_property(TARGET SimGearCore PROPERTY VERSION ${SIMGEAR_VERSION})
set_property(TARGET SimGearCore PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
install(TARGETS SimGearCore EXPORT SimGearCoreConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT SimGearCoreConfig DESTINATION share/SimGearCore)
install(TARGETS SimGearCore
EXPORT SimGearTargets
LIBRARY DESTINATION
${CMAKE_INSTALL_LIBDIR})
if(NOT SIMGEAR_HEADLESS)
add_library(SimGearScene SHARED ${sceneSources})
set_property(TARGET SimGearScene PROPERTY LINKER_LANGUAGE CXX)
@@ -64,10 +66,12 @@ if(SIMGEAR_SHARED)
set_property(TARGET SimGearScene PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
# EXPORT SimGearSceneConfig
install(TARGETS SimGearScene LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} )
# install(EXPORT SimGearSceneConfig DESTINATION share/SimGearScene)
install(TARGETS SimGearScene
EXPORT SimGearTargets
LIBRARY
DESTINATION ${CMAKE_INSTALL_LIBDIR} )
endif()
else()
message(STATUS "Library building mode: STATIC LIBRARIES")
@@ -90,8 +94,10 @@ else()
endforeach()
add_library(SimGearCore STATIC ${coreSources} ${localExpatSources})
install(TARGETS SimGearCore ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS SimGearCore
EXPORT SimGearTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
if(NOT SIMGEAR_HEADLESS)
get_property(FG_GROUPS_SCENE_SOURCES_C GLOBAL PROPERTY FG_GROUPS_SCENE_SOURCES_C)
string(REPLACE "@" ";" groups ${FG_GROUPS_SCENE_SOURCES_C} )
@@ -112,7 +118,9 @@ else()
endforeach()
add_library(SimGearScene STATIC ${sceneSources})
install(TARGETS SimGearScene ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS SimGearScene
EXPORT SimGearTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif(NOT SIMGEAR_HEADLESS)
endif(SIMGEAR_SHARED)
@@ -122,7 +130,8 @@ target_link_libraries(SimGearCore
${DL_LIBRARY}
${EXPAT_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${COCOA_LIBRARY})
${COCOA_LIBRARY}
${CURL_LIBRARIES})
if(NOT SIMGEAR_HEADLESS)
target_link_libraries(SimGearScene

View File

@@ -127,21 +127,22 @@ public:
/**
* Construct a bucket given a specific location.
* @param dlon longitude specified in degrees
* @param dlat latitude specified in degrees
*
* @param geod Geodetic location
*/
SGBucket(const SGGeod& geod);
/** Construct a bucket given a unique bucket index number.
*
* @param bindex unique bucket index
*/
SGBucket(const long int bindex);
#ifndef NO_DEPRECATED_API
/**
* Reset a bucket to represent a new lat and lon
* @param dlon longitude specified in degrees
* @param dlat latitude specified in degrees
* Reset a bucket to represent a new location.
*
* @param geod New geodetic location
*/
void set_bucket(const SGGeod& geod);

View File

@@ -43,7 +43,7 @@ public:
void removeChild(BVHNode* child);
unsigned getNumChildren() const
{ return _children.size(); }
{ return static_cast<unsigned>(_children.size()); }
const BVHNode* getChild(unsigned i) const
{ if (_children.size() <= i) return 0; return _children[i]; }
BVHNode* getChild(unsigned i)

View File

@@ -31,13 +31,13 @@ public:
virtual ~BVHStaticData() {}
unsigned addVertex(const SGVec3f& vertex)
{ _vertices.push_back(vertex); return _vertices.size() - 1; }
{ _vertices.push_back(vertex); return static_cast<unsigned>(_vertices.size() - 1); }
const SGVec3f& getVertex(unsigned i) const
{ return _vertices[i]; }
unsigned addMaterial(const BVHMaterial* material)
{ _materials.push_back(material); return _materials.size() - 1; }
{ _materials.push_back(material); return static_cast<unsigned>(_materials.size() - 1); }
const BVHMaterial* getMaterial(unsigned i) const
{ if (_materials.size() <= i) return 0; return _materials[i]; }

View File

@@ -20,6 +20,7 @@
#include "CanvasEventManager.hxx"
#include "CanvasEventVisitor.hxx"
#include "CanvasPlacement.hxx"
#include <simgear/canvas/events/KeyboardEvent.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
#include <simgear/scene/util/parse_color.hxx>
#include <simgear/scene/util/RenderConstants.hxx>
@@ -196,7 +197,25 @@ namespace canvas
{
_layout = layout;
_layout->setCanvas(this);
_status |= LAYOUT_DIRTY;
}
//----------------------------------------------------------------------------
void Canvas::setFocusElement(const ElementPtr& el)
{
if( el && el->getCanvas().lock() != this )
{
SG_LOG(SG_GUI, SG_WARN, "setFocusElement: element not from this canvas");
return;
}
// TODO focus out/in events
_focus_element = el;
}
//----------------------------------------------------------------------------
void Canvas::clearFocusElement()
{
_focus_element.reset();
}
//----------------------------------------------------------------------------
@@ -256,15 +275,7 @@ namespace canvas
}
if( _layout )
{
if( (_status & LAYOUT_DIRTY) )
{
_layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
_status &= ~LAYOUT_DIRTY;
}
else
_layout->update();
}
_layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
if( _visible || _render_always )
{
@@ -410,7 +421,6 @@ namespace canvas
if( _view_width == w )
return;
_view_width = w;
_status |= LAYOUT_DIRTY;
_texture.setViewSize(_view_width, _view_height);
}
@@ -421,7 +431,6 @@ namespace canvas
if( _view_height == h )
return;
_view_height = h;
_status |= LAYOUT_DIRTY;
_texture.setViewSize(_view_width, _view_height);
}
@@ -459,6 +468,18 @@ namespace canvas
return _event_manager->handleEvent(event, visitor.getPropagationPath());
}
//----------------------------------------------------------------------------
bool Canvas::handleKeyboardEvent(const KeyboardEventPtr& event)
{
ElementPtr target = _focus_element.lock();
if( !target )
target = _root_group;
if( !target )
return false;
return target->dispatchEvent(event);
}
//----------------------------------------------------------------------------
bool Canvas::propagateEvent( EventPtr const& event,
EventPropagationPath const& path )

View File

@@ -1,4 +1,5 @@
///@file The canvas for rendering with the 2d API
///@file
/// The canvas for rendering with the 2d API
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
@@ -43,6 +44,9 @@ namespace canvas
class CanvasMgr;
class MouseEvent;
/**
* Canvas to draw onto (to an off-screen render target).
*/
class Canvas:
public PropertyBasedElement,
public nasal::Object
@@ -53,8 +57,7 @@ namespace canvas
{
STATUS_OK,
STATUS_DIRTY = 1,
LAYOUT_DIRTY = STATUS_DIRTY << 1,
MISSING_SIZE_X = LAYOUT_DIRTY << 1,
MISSING_SIZE_X = STATUS_DIRTY << 1,
MISSING_SIZE_Y = MISSING_SIZE_X << 1,
MISSING_SIZE = MISSING_SIZE_X | MISSING_SIZE_Y,
CREATE_FAILED = MISSING_SIZE_Y << 1
@@ -133,6 +136,22 @@ namespace canvas
*/
void setLayout(const LayoutRef& layout);
/**
* Set the focus to the given element.
*
* The focus element will receive all keyboard events propagated to this
* canvas. If there is no valid focus element the root group will receive
* the events instead.
*/
void setFocusElement(const ElementPtr& el);
/**
* Clear the focus element.
*
* @see setFocusElement()
*/
void clearFocusElement();
/**
* Enable rendering for the next frame
*
@@ -160,6 +179,8 @@ namespace canvas
SGRect<int> getViewport() const;
bool handleMouseEvent(const MouseEventPtr& event);
bool handleKeyboardEvent(const KeyboardEventPtr& event);
bool propagateEvent( EventPtr const& event,
EventPropagationPath const& path );
@@ -211,13 +232,15 @@ namespace canvas
GroupPtr _root_group;
LayoutRef _layout;
ElementWeakPtr _focus_element;
CullCallbackPtr _cull_callback;
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
bool _render_always; //!< Used to disable automatic lazy rendering (culling)
std::vector<SGPropertyNode*> _dirty_placements;
std::vector<Placements> _placements;
std::set<CanvasWeakPtr> _parent_canvases, //<! Canvases showing this canvas
_child_canvases; //<! Canvases displayed within
std::set<CanvasWeakPtr> _parent_canvases, //!< Canvases showing this canvas
_child_canvases; //!< Canvases displayed within
// this canvas
typedef std::map<std::string, PlacementFactory> PlacementFactoryMap;

View File

@@ -27,7 +27,8 @@ namespace canvas
Event::Event():
type(UNKNOWN),
time(-1),
propagation_stopped(false)
propagation_stopped(false),
default_prevented(false)
{
}
@@ -80,6 +81,18 @@ namespace canvas
propagation_stopped = true;
}
//----------------------------------------------------------------------------
void Event::preventDefault()
{
default_prevented = true;
}
//----------------------------------------------------------------------------
bool Event::defaultPrevented() const
{
return default_prevented;
}
//----------------------------------------------------------------------------
int Event::getOrRegisterType(const std::string& type_str)
{
@@ -125,7 +138,7 @@ namespace canvas
if( type_map.empty() )
{
# define ENUM_MAPPING(type, str)\
# define ENUM_MAPPING(type, str, class_name)\
type_map.insert(TypeMap::value_type(str, type));
# include "CanvasEventTypes.hxx"
# undef ENUM_MAPPING

View File

@@ -1,4 +1,5 @@
// Canvas Event for event model similar to DOM Level 3 Event Model
/// @file
/// Canvas Event for event model similar to DOM Level 3 Event Model
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
@@ -27,26 +28,36 @@ namespace simgear
namespace canvas
{
/**
* Base class for all Canvas events.
*
* The event system is closely following the specification of the DOM Level 3
* Event Model.
*/
class Event:
public SGReferenced
{
public:
/// Event type identifier
enum Type
{
UNKNOWN,
# define ENUM_MAPPING(name, str) name,
# define ENUM_MAPPING(name, str, class_name)\
name, /*!< class_name (type=str) */
# include "CanvasEventTypes.hxx"
# undef ENUM_MAPPING
CUSTOM_EVENT ///< all user defined event types share the same id. They
/// are just differentiated by using the type string.
CUSTOM_EVENT ///< First event type id available for user defined event
/// type.
/// @see CustomEvent
};
int type;
ElementWeakPtr target,
current_target;
double time;
bool propagation_stopped;
bool propagation_stopped,
default_prevented;
Event();
@@ -72,10 +83,33 @@ namespace canvas
ElementWeakPtr getTarget() const;
ElementWeakPtr getCurrentTarget() const;
/**
* Get time at which the event was generated.
*/
double getTime() const;
/**
* Prevent further propagation of the event during event flow.
*
* @note This does not prevent calling further event handlers registered
* on the current event target.
*/
void stopPropagation();
/**
* Cancel any default action normally taken as result of this event.
*
* @note For event handlers registered on the DesktopGroup (Nasal:
* canvas.getDesktop()) this stops the event from being further
* propagated to the normal FlightGear input event handling code.
*/
void preventDefault();
/**
* Get if preventDefault() has been called.
*/
bool defaultPrevented() const;
static int getOrRegisterType(const std::string& type);
static int strToType(const std::string& type);
static std::string typeToStr(int type);

View File

@@ -20,14 +20,17 @@
# error "Don't include this file directly!"
#endif
ENUM_MAPPING(MOUSE_DOWN, "mousedown")
ENUM_MAPPING(MOUSE_UP, "mouseup")
ENUM_MAPPING(CLICK, "click")
ENUM_MAPPING(DBL_CLICK, "dblclick")
ENUM_MAPPING(DRAG, "drag")
ENUM_MAPPING(WHEEL, "wheel")
ENUM_MAPPING(MOUSE_MOVE, "mousemove")
ENUM_MAPPING(MOUSE_OVER, "mouseover")
ENUM_MAPPING(MOUSE_OUT, "mouseout")
ENUM_MAPPING(MOUSE_ENTER, "mouseenter")
ENUM_MAPPING(MOUSE_LEAVE, "mouseleave")
ENUM_MAPPING(MOUSE_DOWN, "mousedown", MouseEvent)
ENUM_MAPPING(MOUSE_UP, "mouseup", MouseEvent)
ENUM_MAPPING(CLICK, "click", MouseEvent)
ENUM_MAPPING(DBL_CLICK, "dblclick", MouseEvent)
ENUM_MAPPING(DRAG, "drag", MouseEvent)
ENUM_MAPPING(WHEEL, "wheel", MouseEvent)
ENUM_MAPPING(MOUSE_MOVE, "mousemove", MouseEvent)
ENUM_MAPPING(MOUSE_OVER, "mouseover", MouseEvent)
ENUM_MAPPING(MOUSE_OUT, "mouseout", MouseEvent)
ENUM_MAPPING(MOUSE_ENTER, "mouseenter", MouseEvent)
ENUM_MAPPING(MOUSE_LEAVE, "mouseleave", MouseEvent)
ENUM_MAPPING(KEY_DOWN, "keydown", KeyboardEvent)
ENUM_MAPPING(KEY_UP, "keyup", KeyboardEvent)
ENUM_MAPPING(KEY_PRESS, "keypress", KeyboardEvent)

View File

@@ -1,7 +1,8 @@
///@file Placement for putting a canvas texture onto OpenSceneGraph objects.
//
// It also provides a SGPickCallback for passing mouse events to the canvas and
// manages emissive lighting of the placed canvas.
///@file
/// Placement for putting a canvas texture onto OpenSceneGraph objects.
///
/// It also provides a SGPickCallback for passing mouse events to the canvas and
/// manages emissive lighting of the placed canvas.
//
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
//

View File

@@ -172,6 +172,19 @@ namespace canvas
return _capture_events;
}
//----------------------------------------------------------------------------
void Window::setVisible(bool visible)
{
LayoutItem::setVisible(visible);
Element::setVisible(LayoutItem::isVisible());
}
//----------------------------------------------------------------------------
bool Window::isVisible() const
{
return Element::isVisible();
}
//----------------------------------------------------------------------------
void Window::raise()
{
@@ -267,6 +280,9 @@ namespace canvas
->createChild<Image>("content");
_image_content->setSrcCanvas(content);
// Forward keyboard events to content
_image_content->setFocus();
// Draw content on top of decoration
_image_content->set<int>("z-index", 1);
}

View File

@@ -84,6 +84,9 @@ namespace canvas
bool isResizable() const;
bool isCapturingEvents() const;
virtual void setVisible(bool visible);
virtual bool isVisible() const;
/**
* Moves window on top of all other windows with the same z-index.
*

View File

@@ -44,6 +44,7 @@
#include <osg/ShadeModel>
#include <osg/StateSet>
#include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
#include <osg/Version>
#include <osgUtil/RenderBin>
#include <cassert>
@@ -266,7 +267,15 @@ namespace canvas
//----------------------------------------------------------------------------
void ODGauge::reinit()
{
osg::NodeCallback* cull_callback = camera ? camera->getCullCallback() : 0;
osg::NodeCallback* cull_callback =
camera
#if OSG_VERSION_LESS_THAN(3,3,2)
? camera->getCullCallback()
#else
? dynamic_cast<osg::NodeCallback*>(camera->getCullCallback())
#endif
: 0;
clear();
allocRT(cull_callback);
}

View File

@@ -156,7 +156,7 @@ SHfloat getMaxFloat();
/* OpenGL headers */
#if defined(VG_API_LINUX)
#if defined(VG_API_LINUX) || defined(VG_API_FREEBSD)
#include <GL/gl.h>
#include <GL/glx.h>
#elif defined(VG_API_MACOSX)

View File

@@ -53,6 +53,8 @@ namespace canvas
SG_FWD_DECL(Event)
SG_FWD_DECL(CustomEvent)
SG_FWD_DECL(DeviceEvent)
SG_FWD_DECL(KeyboardEvent)
SG_FWD_DECL(MouseEvent)
#undef SG_FWD_DECL

View File

@@ -26,7 +26,8 @@
#include <osg/Drawable>
#include <osg/Geode>
#include <osg/Scissor>
#include <osg/StateAttribute>
#include <osg/Version>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/foreach.hpp>
@@ -46,27 +47,34 @@ namespace canvas
* glScissor with coordinates relative to different reference frames.
*/
class Element::RelativeScissor:
public osg::Scissor
public osg::StateAttribute
{
public:
ReferenceFrame _coord_reference;
osg::observer_ptr<osg::Node> _node;
RelativeScissor(osg::Node* node = NULL):
explicit RelativeScissor(osg::Node* node = NULL):
_coord_reference(GLOBAL),
_node(node)
_node(node),
_x(0),
_y(0),
_width(0),
_height(0)
{
_width = 0;
_height = 0;
}
/** Copy constructor using CopyOp to manage deep vs shallow copy. */
RelativeScissor( const RelativeScissor& vp,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY ):
Scissor(vp, copyop),
StateAttribute(vp, copyop),
_coord_reference(vp._coord_reference),
_node(vp._node)
_node(vp._node),
_x(vp._x),
_y(vp._y),
_width(vp._width),
_height(vp._height)
{}
META_StateAttribute(simgear, RelativeScissor, SCISSOR);
@@ -89,6 +97,24 @@ namespace canvas
return 0; // passed all the above comparison macros, must be equal.
}
virtual bool getModeUsage(StateAttribute::ModeUsage& usage) const
{
usage.usesMode(GL_SCISSOR_TEST);
return true;
}
inline float& x() { return _x; }
inline float x() const { return _x; }
inline float& y() { return _y; }
inline float y() const { return _y; }
inline float& width() { return _width; }
inline float width() const { return _width; }
inline float& height() { return _height; }
inline float height() const { return _height; }
virtual void apply(osg::State& state) const
{
if( _width <= 0 || _height <= 0 )
@@ -163,6 +189,12 @@ namespace canvas
return false;
}
protected:
float _x,
_y,
_width,
_height;
};
//----------------------------------------------------------------------------
@@ -175,19 +207,6 @@ namespace canvas
//----------------------------------------------------------------------------
Element::~Element()
{
if( !_transform.valid() )
return;
for(unsigned int i = 0; i < _transform->getNumChildren(); ++i)
{
OSGUserData* ud =
static_cast<OSGUserData*>(_transform->getChild(i)->getUserData());
if( ud )
// Ensure parent is cleared to prevent accessing released memory if an
// element somehow survives longer than his parent.
ud->element->_parent = 0;
}
}
//----------------------------------------------------------------------------
@@ -214,7 +233,7 @@ namespace canvas
//----------------------------------------------------------------------------
ElementPtr Element::getParent() const
{
return _parent;
return _parent.lock();
}
//----------------------------------------------------------------------------
@@ -272,6 +291,14 @@ namespace canvas
_listener.clear();
}
//----------------------------------------------------------------------------
void Element::setFocus()
{
CanvasPtr canvas = _canvas.lock();
if( canvas )
canvas->setFocusElement(this);
}
//----------------------------------------------------------------------------
bool Element::accept(EventVisitor& visitor)
{
@@ -284,8 +311,9 @@ namespace canvas
//----------------------------------------------------------------------------
bool Element::ascend(EventVisitor& visitor)
{
if( _parent )
return _parent->accept(visitor);
ElementPtr parent = getParent();
if( parent )
return parent->accept(visitor);
return true;
}
@@ -295,6 +323,15 @@ namespace canvas
return true;
}
//----------------------------------------------------------------------------
size_t Element::numEventHandler(int type) const
{
ListenerMap::const_iterator listeners = _listener.find(type);
if( listeners != _listener.end() )
return listeners->second.size();
return 0;
}
//----------------------------------------------------------------------------
bool Element::handleEvent(const EventPtr& event)
{
@@ -325,9 +362,9 @@ namespace canvas
EventPropagationPath path;
path.push_back( EventTarget(this) );
for( Element* parent = _parent;
parent != NULL;
parent = parent->_parent )
for( ElementPtr parent = getParent();
parent.valid();
parent = parent->getParent() )
path.push_front( EventTarget(parent) );
CanvasPtr canvas = _canvas.lock();
@@ -349,7 +386,13 @@ namespace canvas
// Drawables have a bounding box...
if( _drawable )
return _drawable->getBound().contains(osg::Vec3f(local_pos, 0));
return _drawable->
#if OSG_VERSION_LESS_THAN(3,3,2)
getBound()
#else
getBoundingBox()
#endif
.contains(osg::Vec3f(local_pos, 0));
else if( _transform.valid() )
// ... for other elements, i.e. groups only a bounding sphere is available
return _transform->getBound().contains(osg::Vec3f(parent_pos, 0));
@@ -576,10 +619,10 @@ namespace canvas
_scissor = new RelativeScissor(_transform.get());
// <top>, <right>, <bottom>, <left>
_scissor->x() = SGMiscf::roundToInt(values[3]);
_scissor->y() = SGMiscf::roundToInt(values[0]);
_scissor->width() = SGMiscf::roundToInt(width);
_scissor->height() = SGMiscf::roundToInt(height);
_scissor->x() = values[3];
_scissor->y() = values[0];
_scissor->width() = width;
_scissor->height() = height;
SGPropertyNode* clip_frame = _node->getChild("clip-frame", 0);
if( clip_frame )
@@ -601,7 +644,11 @@ namespace canvas
osg::BoundingBox Element::getBoundingBox() const
{
if( _drawable )
#if OSG_VERSION_LESS_THAN(3,3,2)
return _drawable->getBound();
#else
return _drawable->getBoundingBox();
#endif
osg::BoundingBox bb;
@@ -624,7 +671,13 @@ namespace canvas
return osg::BoundingBox();
osg::BoundingBox transformed;
const osg::BoundingBox& bb = _drawable->getBound();
const osg::BoundingBox& bb =
#if OSG_VERSION_LESS_THAN(3,3,2)
_drawable->getBound();
#else
_drawable->getBoundingBox();
#endif
for(int i = 0; i < 4; ++i)
transformed.expandBy( bb.corner(i) * m );
@@ -707,7 +760,7 @@ namespace canvas
Element::Element( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
PropertyBasedElement(node),
_canvas( canvas ),
_parent( parent ),
@@ -806,11 +859,12 @@ namespace canvas
Element::getParentStyle(const SGPropertyNode* child) const
{
// Try to get value from parent...
if( _parent )
ElementPtr parent = getParent();
if( parent )
{
Style::const_iterator style =
_parent->_style.find(child->getNameString());
if( style != _parent->_style.end() )
parent->_style.find(child->getNameString());
if( style != parent->_style.end() )
return style->second;
}

View File

@@ -1,4 +1,5 @@
///@file Interface for 2D Canvas elements
///@file
/// Interface for 2D Canvas elements
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
@@ -42,7 +43,7 @@ namespace canvas
{
/**
* Baseclass for Elements displayed inside a Canvas.
* Base class for Elements displayed inside a Canvas.
*/
class Element:
public PropertyBasedElement
@@ -108,10 +109,16 @@ namespace canvas
bool addEventListener(const std::string& type, const EventListener& cb);
virtual void clearEventListener();
/// Get (keyboard) input focus.
void setFocus();
virtual bool accept(EventVisitor& visitor);
virtual bool ascend(EventVisitor& visitor);
virtual bool traverse(EventVisitor& visitor);
/// Get the number of event handlers for the given type
size_t numEventHandler(int type) const;
virtual bool handleEvent(const EventPtr& event);
bool dispatchEvent(const EventPtr& event);
@@ -128,12 +135,12 @@ namespace canvas
/**
* Set visibility of the element.
*/
void setVisible(bool visible);
virtual void setVisible(bool visible);
/**
* Get whether the element is visible or hidden.
*/
bool isVisible() const;
virtual bool isVisible() const;
osg::MatrixTransform* getMatrixTransform();
osg::MatrixTransform const* getMatrixTransform() const;
@@ -225,8 +232,8 @@ namespace canvas
class RelativeScissor;
CanvasWeakPtr _canvas;
Element *_parent;
CanvasWeakPtr _canvas;
ElementWeakPtr _parent;
mutable uint32_t _attributes_dirty;
@@ -249,7 +256,7 @@ namespace canvas
Element( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent );
ElementWeakPtr parent );
/**
* Returns false on first call and true on any successive call. Use to
@@ -272,9 +279,10 @@ namespace canvas
/**
* Register a function for setting a style specified by the given property
*
* @param name Property name
* @param type Interpolation type
* @param setter Setter function
* @param name Property name
* @param type Interpolation type
* @param setter Setter function
* @param inheritable If this style propagates to child elements
*
* @tparam T1 Type of value used to retrieve value from property
* node
@@ -556,7 +564,7 @@ namespace canvas
/**
* Get stateset of drawable if available or use transform otherwise
*/
osg::StateSet* getOrCreateStateSet();
virtual osg::StateSet* getOrCreateStateSet();
void setupStyle();

View File

@@ -70,7 +70,7 @@ namespace canvas
Group::Group( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Element(canvas, node, parent_style, parent)
{
staticInit();

View File

@@ -45,7 +45,7 @@ namespace canvas
Group( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style = Style(),
Element* parent = 0 );
ElementWeakPtr parent = 0 );
virtual ~Group();
ElementPtr createChild( const std::string& type,

View File

@@ -21,6 +21,7 @@
#include <simgear/canvas/Canvas.hxx>
#include <simgear/canvas/CanvasMgr.hxx>
#include <simgear/canvas/CanvasSystemAdapter.hxx>
#include <simgear/canvas/events/KeyboardEvent.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/parse_color.hxx>
@@ -30,6 +31,7 @@
#include <osg/Geometry>
#include <osg/PrimitiveSet>
#include <osgDB/Registry>
#include <osg/Version>
namespace simgear
{
@@ -100,13 +102,17 @@ namespace canvas
addStyle("preserveAspectRatio", "", &Image::setPreserveAspectRatio);
addStyle("slice", "", &Image::setSlice);
addStyle("slice-width", "", &Image::setSliceWidth);
osgDB::Registry* reg = osgDB::Registry::instance();
if( !reg->getReaderWriterForExtension("png") )
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: Missing 'png' image reader");
}
//----------------------------------------------------------------------------
Image::Image( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Element(canvas, node, parent_style, parent),
_texture(new osg::Texture2D),
_node_src_rect( node->getNode("source", 0, true) ),
@@ -408,7 +414,14 @@ namespace canvas
&& child->getNameString() == "visible"
&& child->getBoolValue() )
{
CullCallback* cb = static_cast<CullCallback*>(_geom->getCullCallback());
CullCallback* cb =
#if OSG_VERSION_LESS_THAN(3,3,2)
static_cast<CullCallback*>
#else
dynamic_cast<CullCallback*>
#endif
( _geom->getCullCallback() );
if( cb )
cb->cullNextFrame();
}
@@ -521,8 +534,7 @@ namespace canvas
if( !src_canvas )
return handled;
MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get());
if( mouse_event )
if( MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get()) )
{
mouse_event.reset( new MouseEvent(*mouse_event) );
@@ -547,6 +559,11 @@ namespace canvas
handled |= src_canvas->handleMouseEvent(mouse_event);
}
else if( KeyboardEventPtr keyboard_event =
dynamic_cast<KeyboardEvent*>(event.get()) )
{
handled |= src_canvas->handleKeyboardEvent(keyboard_event);
}
return handled;
}

View File

@@ -50,7 +50,7 @@ namespace canvas
Image( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style = Style(),
Element* parent = 0 );
ElementWeakPtr parent = 0 );
virtual ~Image();
virtual void update(double dt);

View File

@@ -44,6 +44,7 @@ namespace canvas
//----------------------------------------------------------------------------
const std::string GEO = "-geo";
const std::string HDG = "hdg";
const std::string Map::TYPE_NAME = "map";
//----------------------------------------------------------------------------
@@ -61,7 +62,7 @@ namespace canvas
Map::Map( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Group(canvas, node, parent_style, parent),
// TODO make projection configurable
_projection(new SansonFlamsteedProjection),
@@ -112,87 +113,50 @@ namespace canvas
//----------------------------------------------------------------------------
void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
{
if( !boost::ends_with(child->getNameString(), GEO) )
if( boost::ends_with(child->getNameString(), GEO) )
_geo_nodes[child].reset(new GeoNodePair());
else if( parent != _node && child->getNameString() == HDG )
_hdg_nodes.insert(child);
else
return Element::childAdded(parent, child);
_geo_nodes[child].reset(new GeoNodePair());
}
//----------------------------------------------------------------------------
void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
{
if( !boost::ends_with(child->getNameString(), GEO) )
return Element::childRemoved(parent, child);
// TODO remove from other node
_geo_nodes.erase(child);
}
//----------------------------------------------------------------------------
void Map::valueChanged(SGPropertyNode * child)
{
const std::string& name = child->getNameString();
if( !boost::ends_with(name, GEO) )
return Group::valueChanged(child);
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
if( it_geo_node == _geo_nodes.end() )
LOG_GEO_RET("geo node not found!")
GeoNodePair* geo_node = it_geo_node->second.get();
geo_node->setDirty();
if( geo_node->getStatus() & GeoNodePair::INCOMPLETE )
if( boost::ends_with(child->getNameString(), GEO) )
// TODO remove from other node
_geo_nodes.erase(child);
else if( parent != _node && child->getName() == HDG )
{
// Detect lat, lon tuples...
GeoCoord coord = parseGeoCoord(child->getStringValue());
int index_other = -1;
_hdg_nodes.erase(child);
switch( coord.type )
{
case GeoCoord::LATITUDE:
index_other = child->getIndex() + 1;
geo_node->setNodeLat(child);
break;
case GeoCoord::LONGITUDE:
index_other = child->getIndex() - 1;
geo_node->setNodeLon(child);
break;
default:
LOG_GEO_RET("Invalid geo coord")
}
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
if( !other )
return;
GeoCoord coord_other = parseGeoCoord(other->getStringValue());
if( coord_other.type == GeoCoord::INVALID
|| coord_other.type == coord.type )
return;
GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
if( it_geo_node_other == _geo_nodes.end() )
LOG_GEO_RET("other geo node not found!")
GeoNodePair* geo_node_other = it_geo_node_other->second.get();
// Let use both nodes use the same GeoNodePair instance
if( geo_node_other != geo_node )
it_geo_node_other->second = it_geo_node->second;
if( coord_other.type == GeoCoord::LATITUDE )
geo_node->setNodeLat(other);
else
geo_node->setNodeLon(other);
// Set name for resulting screen coordinate nodes
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
// Remove rotation matrix (tf[0]) and return to element always being
// oriented upwards (or any orientation inside other matrices).
child->getParent()->removeChild("tf", 0);
}
else
return Element::childRemoved(parent, child);
}
//----------------------------------------------------------------------------
void Map::childChanged(SGPropertyNode * child)
void Map::valueChanged(SGPropertyNode* child)
{
if( child->getParent() != _node )
{
const std::string& name = child->getNameString();
if( boost::ends_with(name, GEO) )
return geoNodeChanged(child);
else if( name == HDG )
return hdgNodeChanged(child);
}
return Group::valueChanged(child);
}
//----------------------------------------------------------------------------
void Map::childChanged(SGPropertyNode* child)
{
if( child->getParent() != _node )
return Group::childChanged(child);
@@ -201,8 +165,14 @@ namespace canvas
|| child->getNameString() == "ref-lon" )
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
_node->getDoubleValue("ref-lon") );
else if( child->getNameString() == "hdg" )
else if( child->getNameString() == HDG )
{
_projection->setOrientation(child->getFloatValue());
for( NodeSet::iterator it = _hdg_nodes.begin();
it != _hdg_nodes.end();
++it )
hdgNodeChanged(*it);
}
else if( child->getNameString() == "range" )
_projection->setRange(child->getDoubleValue());
else if( child->getNameString() == "screen-range" )
@@ -213,6 +183,74 @@ namespace canvas
_projection_dirty = true;
}
//----------------------------------------------------------------------------
void Map::geoNodeChanged(SGPropertyNode* child)
{
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
if( it_geo_node == _geo_nodes.end() )
LOG_GEO_RET("GeoNode not found!")
GeoNodePair* geo_node = it_geo_node->second.get();
geo_node->setDirty();
if( !(geo_node->getStatus() & GeoNodePair::INCOMPLETE) )
return;
// Detect lat, lon tuples...
GeoCoord coord = parseGeoCoord(child->getStringValue());
int index_other = -1;
switch( coord.type )
{
case GeoCoord::LATITUDE:
index_other = child->getIndex() + 1;
geo_node->setNodeLat(child);
break;
case GeoCoord::LONGITUDE:
index_other = child->getIndex() - 1;
geo_node->setNodeLon(child);
break;
default:
LOG_GEO_RET("Invalid geo coord")
}
const std::string& name = child->getNameString();
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
if( !other )
return;
GeoCoord coord_other = parseGeoCoord(other->getStringValue());
if( coord_other.type == GeoCoord::INVALID
|| coord_other.type == coord.type )
return;
GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
if( it_geo_node_other == _geo_nodes.end() )
LOG_GEO_RET("other geo node not found!")
GeoNodePair* geo_node_other = it_geo_node_other->second.get();
// Let use both nodes use the same GeoNodePair instance
if( geo_node_other != geo_node )
it_geo_node_other->second = it_geo_node->second;
if( coord_other.type == GeoCoord::LATITUDE )
geo_node->setNodeLat(other);
else
geo_node->setNodeLon(other);
// Set name for resulting screen coordinate nodes
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
}
//----------------------------------------------------------------------------
void Map::hdgNodeChanged(SGPropertyNode* child)
{
child->getParent()->setFloatValue(
"tf[0]/rot",
SGMiscf::deg2rad(child->getFloatValue() - _projection->orientation())
);
}
//----------------------------------------------------------------------------
Map::GeoCoord Map::parseGeoCoord(const std::string& val) const
{

View File

@@ -24,6 +24,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
namespace simgear
{
@@ -41,7 +42,7 @@ namespace canvas
Map( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent = 0 );
ElementWeakPtr parent = 0 );
virtual ~Map();
virtual void update(double dt);
@@ -59,14 +60,18 @@ namespace canvas
typedef boost::unordered_map< SGPropertyNode*,
boost::shared_ptr<GeoNodePair>
> GeoNodes;
typedef boost::unordered_set<SGPropertyNode*> NodeSet;
GeoNodes _geo_nodes;
NodeSet _hdg_nodes;
boost::shared_ptr<HorizontalProjection> _projection;
bool _projection_dirty;
struct GeoCoord
{
GeoCoord():
type(INVALID)
type(INVALID),
value(0)
{}
enum
{
@@ -77,6 +82,9 @@ namespace canvas
double value;
};
void geoNodeChanged(SGPropertyNode * child);
void hdgNodeChanged(SGPropertyNode * child);
GeoCoord parseGeoCoord(const std::string& val) const;
};

View File

@@ -20,6 +20,7 @@
#include <simgear/scene/util/parse_color.hxx>
#include <osg/Drawable>
#include <osg/Version>
#include <vg/openvg.h>
#include <cassert>
@@ -69,7 +70,8 @@ namespace canvas
_mode(0),
_fill_rule(VG_EVEN_ODD),
_stroke_width(1),
_stroke_linecap(VG_CAP_BUTT)
_stroke_linecap(VG_CAP_BUTT),
_stroke_linejoin(VG_JOIN_MITER)
{
setSupportsDisplayList(false);
setDataVariance(Object::DYNAMIC);
@@ -202,6 +204,21 @@ namespace canvas
_stroke_linecap = VG_CAP_BUTT;
}
/**
* Set stroke-linejoin
*
* @see http://www.w3.org/TR/SVG/painting.html#StrokeLinejoinProperty
*/
void setStrokeLinejoin(const std::string& linejoin)
{
if( linejoin == "round" )
_stroke_linejoin = VG_JOIN_ROUND;
else if( linejoin == "bevel" )
_stroke_linejoin = VG_JOIN_BEVEL;
else
_stroke_linejoin = VG_JOIN_MITER;
}
/**
* Draw callback
*/
@@ -251,6 +268,7 @@ namespace canvas
vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width);
vgSeti(VG_STROKE_CAP_STYLE, _stroke_linecap);
vgSeti(VG_STROKE_JOIN_STYLE, _stroke_linejoin);
vgSetfv( VG_STROKE_DASH_PATTERN,
_stroke_dash.size(),
_stroke_dash.empty() ? 0 : &_stroke_dash[0] );
@@ -372,7 +390,13 @@ namespace canvas
/**
* Compute the bounding box
*/
virtual osg::BoundingBox computeBound() const
virtual osg::BoundingBox
#if OSG_VERSION_LESS_THAN(3,3,2)
computeBound()
#else
computeBoundingBox()
#endif
const
{
if( _path == VG_INVALID_HANDLE || (_attributes_dirty & PATH) )
return osg::BoundingBox();
@@ -419,6 +443,7 @@ namespace canvas
VGfloat _stroke_width;
std::vector<VGfloat> _stroke_dash;
VGCapStyle _stroke_linecap;
VGJoinStyle _stroke_linejoin;
osg::Vec3f transformPoint( const osg::Matrix& m,
osg::Vec2f pos ) const
@@ -499,13 +524,14 @@ namespace canvas
addStyle("stroke-width", "numeric", &PathDrawable::setStrokeWidth, path);
addStyle("stroke-dasharray", "", &PathDrawable::setStrokeDashArray, path);
addStyle("stroke-linecap", "", &PathDrawable::setStrokeLinecap, path);
addStyle("stroke-linejoin", "", &PathDrawable::setStrokeLinejoin, path);
}
//----------------------------------------------------------------------------
Path::Path( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Element(canvas, node, parent_style, parent),
_path( new PathDrawable(this) )
{

View File

@@ -36,7 +36,7 @@ namespace canvas
Path( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent = 0 );
ElementWeakPtr parent = 0 );
virtual ~Path();
virtual void update(double dt);

View File

@@ -21,6 +21,7 @@
#include <simgear/canvas/CanvasSystemAdapter.hxx>
#include <simgear/scene/util/parse_color.hxx>
#include <osg/Version>
#include <osgDB/Registry>
#include <osgText/Text>
namespace simgear
@@ -31,27 +32,199 @@ namespace canvas
public osgText::Text
{
public:
TextOSG(canvas::Text* text);
void setFontResolution(int res);
void setCharacterAspect(float aspect);
void setLineHeight(float factor);
void setFill(const std::string& fill);
void setStroke(const std::string& color);
void setBackgroundColor(const std::string& fill);
SGVec2i sizeForWidth(int w) const;
osg::Vec2 handleHit(const osg::Vec2f& pos);
float lineHeight() const;
virtual osg::BoundingBox computeBound() const;
/// Get the number of lines
size_t lineCount() const;
/// Get line @a i
TextLine lineAt(size_t i) const;
/// Get nearest line to given y-coordinate
TextLine nearestLine(float pos_y) const;
SGVec2i sizeForWidth(int w) const;
virtual osg::BoundingBox
#if OSG_VERSION_LESS_THAN(3,3,2)
computeBound()
#else
computeBoundingBox()
#endif
const;
protected:
friend class TextLine;
canvas::Text *_text_element;
virtual void computePositions(unsigned int contextID) const;
};
class TextLine
{
public:
TextLine();
TextLine(size_t line, Text::TextOSG const* text);
/// Number of characters on this line
size_t size() const;
bool empty() const;
osg::Vec2 cursorPos(size_t i) const;
osg::Vec2 nearestCursor(float x) const;
protected:
typedef Text::TextOSG::GlyphQuads GlyphQuads;
Text::TextOSG const *_text;
GlyphQuads const *_quads;
size_t _line,
_begin,
_end;
};
//----------------------------------------------------------------------------
TextLine::TextLine():
_text(NULL),
_quads(NULL),
_line(0),
_begin(-1),
_end(-1)
{
}
//----------------------------------------------------------------------------
TextLine::TextLine(size_t line, Text::TextOSG const* text):
_text(text),
_quads(NULL),
_line(line),
_begin(-1),
_end(-1)
{
if( !text || text->_textureGlyphQuadMap.empty() || !_text->lineCount() )
return;
_quads = &text->_textureGlyphQuadMap.begin()->second;
GlyphQuads::LineNumbers const& line_numbers = _quads->_lineNumbers;
GlyphQuads::LineNumbers::const_iterator begin_it =
std::lower_bound(line_numbers.begin(), line_numbers.end(), _line);
if( begin_it == line_numbers.end() || *begin_it != _line )
// empty line or past last line
return;
_begin = begin_it - line_numbers.begin();
_end = std::upper_bound(begin_it, line_numbers.end(), _line)
- line_numbers.begin();
}
//----------------------------------------------------------------------------
size_t TextLine::size() const
{
return _end - _begin;
}
//----------------------------------------------------------------------------
bool TextLine::empty() const
{
return _end == _begin;
}
//----------------------------------------------------------------------------
osg::Vec2 TextLine::cursorPos(size_t i) const
{
if( !_quads )
return osg::Vec2(0, 0);
if( i > size() )
// Position after last character if out of range (TODO better exception?)
i = size();
osg::Vec2 pos(0, _text->_offset.y() + _line * _text->lineHeight());
if( empty() )
return pos;
#if OSG_VERSION_LESS_THAN(3,3,5)
GlyphQuads::Coords2 const& coords = _quads->_coords;
#else
GlyphQuads::Coords2 refCoords = _quads->_coords;
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
#endif
size_t global_i = _begin + i;
if( global_i == _begin )
// before first character of line
pos.x() = coords[_begin * 4].x();
else if( global_i == _end )
// After Last character of line
pos.x() = coords[(_end - 1) * 4 + 2].x();
else
{
float prev_l = coords[(global_i - 1) * 4].x(),
prev_r = coords[(global_i - 1) * 4 + 2].x(),
cur_l = coords[global_i * 4].x();
if( prev_l == prev_r )
// If previous character width is zero set to begin of next character
// (Happens eg. with spaces)
pos.x() = cur_l;
else
// position at center between characters
pos.x() = 0.5 * (prev_r + cur_l);
}
return pos;
}
//----------------------------------------------------------------------------
osg::Vec2 TextLine::nearestCursor(float x) const
{
if( empty() )
return cursorPos(0);
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
#if OSG_VERSION_LESS_THAN(3,3,5)
GlyphQuads::Coords2 const& coords = _quads->_coords;
#else
GlyphQuads::Coords2 refCoords = _quads->_coords;
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
#endif
float const HIT_FRACTION = 0.6;
float const character_width = _text->getCharacterHeight()
* _text->getCharacterAspectRatio();
size_t i = _begin;
for(; i < _end; ++i)
{
// Get threshold for mouse x position for setting cursor before or after
// current character
float threshold = coords[i * 4].x()
+ HIT_FRACTION * glyphs[i]->getHorizontalAdvance()
* character_width;
if( x <= threshold )
break;
}
return cursorPos(i - _begin);
}
//----------------------------------------------------------------------------
Text::TextOSG::TextOSG(canvas::Text* text):
_text_element(text)
@@ -88,6 +261,19 @@ namespace canvas
setColor( color );
}
//----------------------------------------------------------------------------
void Text::TextOSG::setStroke(const std::string& stroke)
{
osg::Vec4 color;
if( stroke == "none" || !parseColor(stroke, color) )
setBackdropType(NONE);
else
{
setBackdropType(OUTLINE);
setBackdropColor(color);
}
}
//----------------------------------------------------------------------------
void Text::TextOSG::setBackgroundColor(const std::string& fill)
{
@@ -96,6 +282,45 @@ namespace canvas
setBoundingBoxColor( color );
}
//----------------------------------------------------------------------------
float Text::TextOSG::lineHeight() const
{
return (1 + _lineSpacing) * _characterHeight;
}
//----------------------------------------------------------------------------
size_t Text::TextOSG::lineCount() const
{
return _lineCount;
}
//----------------------------------------------------------------------------
TextLine Text::TextOSG::lineAt(size_t i) const
{
return TextLine(i, this);
}
//----------------------------------------------------------------------------
TextLine Text::TextOSG::nearestLine(float pos_y) const
{
osgText::Font const* font = getActiveFont();
if( !font || lineCount() <= 0 )
return TextLine(0, this);
float asc = .9f, desc = -.2f;
font->getVerticalSize(asc, desc);
float first_line_y = _offset.y()
- (1 + _lineSpacing / 2 + desc) * _characterHeight;
size_t line_num = std::min<size_t>(
std::max<size_t>(0, (pos_y - first_line_y) / lineHeight()),
lineCount() - 1
);
return TextLine(line_num, this);
}
//----------------------------------------------------------------------------
// simplified version of osgText::Text::computeGlyphRepresentation() to
// just calculate the size for a given weight. Glpyh calculations/creating
@@ -372,89 +597,20 @@ namespace canvas
}
//----------------------------------------------------------------------------
osg::Vec2 Text::TextOSG::handleHit(const osg::Vec2f& pos)
osg::BoundingBox
#if OSG_VERSION_LESS_THAN(3,3,2)
Text::TextOSG::computeBound()
#else
Text::TextOSG::computeBoundingBox()
#endif
const
{
float line_height = _characterHeight + _lineSpacing;
// TODO check with align other than TOP
float first_line_y = -0.5 * _lineSpacing;//_offset.y() - _characterHeight;
size_t line = std::max<int>(0, (pos.y() - first_line_y) / line_height);
if( _textureGlyphQuadMap.empty() )
return osg::Vec2(-1, -1);
// TODO check when it can be larger
assert( _textureGlyphQuadMap.size() == 1 );
const GlyphQuads& glyphquad = _textureGlyphQuadMap.begin()->second;
const GlyphQuads::Glyphs& glyphs = glyphquad._glyphs;
const GlyphQuads::Coords2& coords = glyphquad._coords;
const GlyphQuads::LineNumbers& line_numbers = glyphquad._lineNumbers;
const float HIT_FRACTION = 0.6;
const float character_width = getCharacterHeight()
* getCharacterAspectRatio();
float y = (line + 0.5) * line_height;
bool line_found = false;
for(size_t i = 0; i < line_numbers.size(); ++i)
{
if( line_numbers[i] != line )
{
if( !line_found )
{
if( line_numbers[i] < line )
// Wait for the correct line...
continue;
// We have already passed the correct line -> It's empty...
return osg::Vec2(0, y);
}
// Next line and not returned -> not before any character
// -> return position after last character of line
return osg::Vec2(coords[(i - 1) * 4 + 2].x(), y);
}
line_found = true;
// Get threshold for mouse x position for setting cursor before or after
// current character
float threshold = coords[i * 4].x()
+ HIT_FRACTION * glyphs[i]->getHorizontalAdvance()
* character_width;
if( pos.x() <= threshold )
{
osg::Vec2 hit(0, y);
if( i == 0 || line_numbers[i - 1] != line )
// first character of line
hit.x() = coords[i * 4].x();
else if( coords[(i - 1) * 4].x() == coords[(i - 1) * 4 + 2].x() )
// If previous character width is zero set to begin of next character
// (Happens eg. with spaces)
hit.x() = coords[i * 4].x();
else
// position at center between characters
hit.x() = 0.5 * (coords[(i - 1) * 4 + 2].x() + coords[i * 4].x());
return hit;
}
}
// Nothing found -> return position after last character
return osg::Vec2
(
coords.back().x(),
(_lineCount - 0.5) * line_height
);
}
//----------------------------------------------------------------------------
osg::BoundingBox Text::TextOSG::computeBound() const
{
osg::BoundingBox bb = osgText::Text::computeBound();
osg::BoundingBox bb =
#if OSG_VERSION_LESS_THAN(3,3,2)
osgText::Text::computeBound();
#else
osgText::Text::computeBoundingBox();
#endif
#if OSG_VERSION_LESS_THAN(3,1,0)
if( bb.valid() )
@@ -480,7 +636,13 @@ namespace canvas
const GlyphQuads& quads = _textureGlyphQuadMap.begin()->second;
const GlyphQuads::Glyphs& glyphs = quads._glyphs;
const GlyphQuads::Coords2& coords = quads._coords;
#if OSG_VERSION_LESS_THAN(3,3,5)
GlyphQuads::Coords2 const& coords = quads._coords;
#else
GlyphQuads::Coords2 refCoords = quads._coords;
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
#endif
const GlyphQuads::LineNumbers& line_numbers = quads._lineNumbers;
float wr = _characterHeight / getCharacterAspectRatio();
@@ -546,6 +708,7 @@ namespace canvas
addStyle("fill", "color", &TextOSG::setFill, text);
addStyle("background", "color", &TextOSG::setBackgroundColor, text);
addStyle("stroke", "color", &TextOSG::setStroke, text);
addStyle("character-size",
"numeric",
static_cast<
@@ -567,13 +730,17 @@ namespace canvas
addStyle("font", "", &Text::setFont);
addStyle("alignment", "", &Text::setAlignment);
addStyle("text", "", &Text::setText, false);
osgDB::Registry* reg = osgDB::Registry::instance();
if( !reg->getReaderWriterForExtension("ttf") )
SG_LOG(SG_GL, SG_ALERT, "canvas::Text: Missing 'ttf' font reader");
}
//----------------------------------------------------------------------------
Text::Text( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Element(canvas, node, parent_style, parent),
_text( new Text::TextOSG(this) )
{
@@ -657,10 +824,39 @@ namespace canvas
return _text->sizeForWidth(INT_MAX).x();
}
//----------------------------------------------------------------------------
size_t Text::lineCount() const
{
return _text->lineCount();
}
//----------------------------------------------------------------------------
size_t Text::lineLength(size_t line) const
{
return _text->lineAt(line).size();
}
//----------------------------------------------------------------------------
osg::Vec2 Text::getNearestCursor(const osg::Vec2& pos) const
{
return _text->handleHit(pos);
return _text->nearestLine(pos.y()).nearestCursor(pos.x());
}
//----------------------------------------------------------------------------
osg::Vec2 Text::getCursorPos(size_t line, size_t character) const
{
return _text->lineAt(line).cursorPos(character);
}
//----------------------------------------------------------------------------
osg::StateSet* Text::getOrCreateStateSet()
{
if( !_transform.valid() )
return 0;
// Only check for StateSet on Transform, as the text stateset is shared
// between all text instances using the same font (texture).
return _transform->getOrCreateStateSet();
}
} // namespace canvas

View File

@@ -29,6 +29,7 @@ namespace simgear
namespace canvas
{
class TextLine;
class Text:
public Element
{
@@ -39,7 +40,7 @@ namespace canvas
Text( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent = 0 );
ElementWeakPtr parent = 0 );
~Text();
void setText(const char* text);
@@ -48,13 +49,24 @@ namespace canvas
int heightForWidth(int w) const;
int maxWidth() const;
/// Number of text lines.
size_t lineCount() const;
/// Number of characters in @a line.
size_t lineLength(size_t line) const;
osg::Vec2 getNearestCursor(const osg::Vec2& pos) const;
osg::Vec2 getCursorPos(size_t line, size_t character) const;
protected:
friend class TextLine;
class TextOSG;
osg::ref_ptr<TextOSG> _text;
virtual osg::StateSet* getOrCreateStateSet();
};
} // namespace canvas

View File

@@ -34,7 +34,10 @@ namespace canvas
public:
struct ScreenPosition
{
ScreenPosition() {}
ScreenPosition():
x(0),
y(0)
{}
ScreenPosition(double x, double y):
x(x),
@@ -67,8 +70,11 @@ namespace canvas
public:
HorizontalProjection():
_cos_rot(1),
_sin_rot(0),
_ref_lat(0),
_ref_lon(0),
_angle(0),
_cos_angle(1),
_sin_angle(0),
_range(5)
{
setScreenRange(200);
@@ -88,9 +94,19 @@ namespace canvas
*/
void setOrientation(float hdg)
{
_angle = hdg;
hdg = SGMiscf::deg2rad(hdg);
_sin_rot = sin(hdg);
_cos_rot = cos(hdg);
_sin_angle = sin(hdg);
_cos_angle = cos(hdg);
}
/**
* Get orientation/heading of the projection (in degree)
*/
float orientation() const
{
return _angle;
}
void setRange(double range)
@@ -114,8 +130,8 @@ namespace canvas
pos.y *= scale;
return ScreenPosition
(
_cos_rot * pos.x - _sin_rot * pos.y,
-_sin_rot * pos.x - _cos_rot * pos.y
_cos_angle * pos.x - _sin_angle * pos.y,
-_sin_angle * pos.x - _cos_angle * pos.y
);
}
@@ -129,10 +145,11 @@ namespace canvas
*/
virtual ScreenPosition project(double lat, double lon) const = 0;
double _ref_lat,
_ref_lon,
_cos_rot,
_sin_rot,
double _ref_lat, ///<! Reference latitude (radian)
_ref_lon, ///<! Reference latitude (radian)
_angle, ///<! Map rotation angle (degree)
_cos_angle,
_sin_angle,
_range;
};

View File

@@ -2,11 +2,15 @@ include (SimGearComponent)
set(HEADERS
CustomEvent.hxx
DeviceEvent.hxx
KeyboardEvent.hxx
MouseEvent.hxx
)
set(SOURCES
CustomEvent.cxx
DeviceEvent.cxx
KeyboardEvent.cxx
MouseEvent.cxx
)
@@ -15,4 +19,10 @@ simgear_scene_component(canvas-events canvas/events "${SOURCES}" "${HEADERS}")
add_boost_test(canvas_event
SOURCES event_test.cpp
LIBRARIES ${TEST_LIBS}
)
add_executable(input_event_demo input_event_demo.cxx)
target_link_libraries(input_event_demo
${TEST_LIBS}
${OPENSCENEGRAPH_LIBRARIES}
)

View File

@@ -1,4 +1,5 @@
///@file Canvas user defined event
///@file
/// Canvas user defined event
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
@@ -27,6 +28,10 @@ namespace simgear
namespace canvas
{
/**
* User defined event (optionally carrying additional context information or
* data).
*/
class CustomEvent:
public Event
{
@@ -36,6 +41,7 @@ namespace canvas
*
* @param type_str Event type name (if name does not exist yet it will
* be registered as new event type)
* @param bubbles If this event should take part in the bubbling phase
* @param data Optional user data stored in event
*/
CustomEvent( std::string const& type_str,
@@ -45,6 +51,7 @@ namespace canvas
/**
*
* @param type_id Event type id
* @param bubbles If this event should take part in the bubbling phase
* @param data Optional user data stored in event
*/
CustomEvent( int type_id,
@@ -61,10 +68,16 @@ namespace canvas
*/
StringMap const& getDetail() const { return detail; }
/**
* Get whether this event supports bubbling.
*
* @see #bubbles
* @see CustomEvent()
*/
virtual bool canBubble() const { return bubbles; }
StringMap detail; //<! user data map
bool bubbles;
StringMap detail; //!< User data map
bool bubbles; //!< Whether the event supports bubbling
};
} // namespace canvas

View File

@@ -0,0 +1,66 @@
// Input device event
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
// 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 Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "DeviceEvent.hxx"
#include <osgGA/GUIEventAdapter>
namespace simgear
{
namespace canvas
{
//----------------------------------------------------------------------------
DeviceEvent::DeviceEvent():
modifiers(0)
{
}
//----------------------------------------------------------------------------
DeviceEvent::DeviceEvent(const osgGA::GUIEventAdapter& ea):
modifiers(ea.getModKeyMask())
{
time = ea.getTime();
}
//----------------------------------------------------------------------------
bool DeviceEvent::ctrlKey() const
{
return (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL) != 0;
}
//----------------------------------------------------------------------------
bool DeviceEvent::shiftKey() const
{
return (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT) != 0;
}
//----------------------------------------------------------------------------
bool DeviceEvent::altKey() const
{
return (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT) != 0;
}
//----------------------------------------------------------------------------
bool DeviceEvent::metaKey() const
{
return (modifiers & osgGA::GUIEventAdapter::MODKEY_META) != 0;
}
} // namespace canvas
} // namespace simgear

View File

@@ -0,0 +1,67 @@
///@file
/// Input device event (keyboard/mouse)
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
// 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 Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef CANVAS_DEVICE_EVENT_HXX_
#define CANVAS_DEVICE_EVENT_HXX_
#include <simgear/canvas/CanvasEvent.hxx>
namespace osgGA { class GUIEventAdapter; }
namespace simgear
{
namespace canvas
{
/**
* Common interface for input device events.
*/
class DeviceEvent:
public Event
{
public:
/// Default initialization (no active keyboard modifier).
DeviceEvent();
/// Initialize from an OpenSceneGraph event.
DeviceEvent(const osgGA::GUIEventAdapter& ea);
/// Get mask of active keyboard modifiers at the time of the event.
int getModifiers() const { return modifiers; }
/// Get if a Ctrl modifier was active.
bool ctrlKey() const;
/// Get if a Shift modifier was active.
bool shiftKey() const;
/// Get if an Alt modifier was active.
bool altKey() const;
/// Get if a Meta modifier was active.
bool metaKey() const;
protected:
int modifiers; //!< Keyboard modifier state
};
} // namespace canvas
} // namespace simgear
#endif /* CANVAS_DEVICE_EVENT_HXX_ */

View File

@@ -0,0 +1,323 @@
// Keyboard event
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
// 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 Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "KeyboardEvent.hxx"
#include "utf8.h"
#include <osgGA/GUIEventAdapter>
#include <boost/version.hpp>
#if BOOST_VERSION >= 104800
# include <boost/container/flat_map.hpp>
# include <boost/container/flat_set.hpp>
#else
# include <map>
# include <set>
#endif
#include <iterator>
namespace simgear
{
namespace canvas
{
typedef osgGA::GUIEventAdapter EA;
// TODO check Win/Mac keycode for altgr/ISO Level3 Shift
const uint32_t KEY_AltGraph = 0xfe03;
//----------------------------------------------------------------------------
KeyboardEvent::KeyboardEvent():
_key(0),
_unmodified_key(0),
_repeat(false),
_location(DOM_KEY_LOCATION_STANDARD)
{
}
//----------------------------------------------------------------------------
KeyboardEvent::KeyboardEvent(const osgGA::GUIEventAdapter& ea):
DeviceEvent(ea),
_key(ea.getKey()),
_unmodified_key(ea.getUnmodifiedKey()),
_repeat(false),
_location(DOM_KEY_LOCATION_STANDARD)
{
if( ea.getEventType() == EA::KEYDOWN )
type = KEY_DOWN;
else if( ea.getEventType() == EA::KEYUP )
type = KEY_UP;
// else
// // TODO what to do with wrong event type?
}
//----------------------------------------------------------------------------
void KeyboardEvent::setKey(uint32_t key)
{
_name.clear();
_key = key;
}
//----------------------------------------------------------------------------
void KeyboardEvent::setUnmodifiedKey(uint32_t key)
{
_name.clear();
_unmodified_key = key;
}
//----------------------------------------------------------------------------
void KeyboardEvent::setRepeat(bool repeat)
{
_repeat = repeat;
}
//----------------------------------------------------------------------------
std::string KeyboardEvent::key() const
{
if( !_name.empty() )
return _name;
// We need to make sure only valid const char* pointers are passed. The best
// way is just to use string constants.
// Use an empty string ("") to just use the value reported by the operating
// system.
typedef std::pair<const char*, uint8_t> InternalKeyInfo;
#if BOOST_VERSION >= 104800
typedef boost::container::flat_map<int, InternalKeyInfo> InternalKeyMap;
typedef boost::container::flat_set<int> KeyList;
#else
# warning "Use Boost >= 1.48 for faster and more memory efficient key lookup"
typedef std::map<int, InternalKeyInfo> InternalKeyMap;
typedef std::set<int> KeyList;
#endif
static InternalKeyMap key_map;
static KeyList num_pad_keys;
if( key_map.empty() )
{
const uint8_t S = DOM_KEY_LOCATION_STANDARD,
L = DOM_KEY_LOCATION_LEFT,
R = DOM_KEY_LOCATION_RIGHT,
N = DOM_KEY_LOCATION_NUMPAD;
key_map[ EA::KEY_BackSpace ] = std::make_pair("Backspace", S);
key_map[ EA::KEY_Tab ] = std::make_pair("Tab", S);
key_map[ EA::KEY_Linefeed ] = std::make_pair("Linefeed", S);
key_map[ EA::KEY_Clear ] = std::make_pair("Clear", S);
key_map[ EA::KEY_Return ] = std::make_pair("Enter", S);
key_map[ EA::KEY_Pause ] = std::make_pair("Pause", S);
key_map[ EA::KEY_Scroll_Lock ] = std::make_pair("ScrollLock", S);
key_map[ EA::KEY_Sys_Req ] = std::make_pair("SystemRequest", S);
key_map[ EA::KEY_Escape ] = std::make_pair("Escape", S);
key_map[ EA::KEY_Delete ] = std::make_pair("Delete", S);
key_map[ EA::KEY_Home ] = std::make_pair("Home", S);
key_map[ EA::KEY_Left ] = std::make_pair("Left", S);
key_map[ EA::KEY_Up ] = std::make_pair("Up", S);
key_map[ EA::KEY_Right ] = std::make_pair("Right", S);
key_map[ EA::KEY_Down ] = std::make_pair("Down", S);
key_map[ EA::KEY_Page_Up ] = std::make_pair("PageUp", S);
key_map[ EA::KEY_Page_Down ] = std::make_pair("PageDown", S);
key_map[ EA::KEY_End ] = std::make_pair("End", S);
key_map[ EA::KEY_Begin ] = std::make_pair("Begin", S);
key_map[ EA::KEY_Select ] = std::make_pair("Select", S);
key_map[ EA::KEY_Print ] = std::make_pair("PrintScreen", S);
key_map[ EA::KEY_Execute ] = std::make_pair("Execute", S);
key_map[ EA::KEY_Insert ] = std::make_pair("Insert", S);
key_map[ EA::KEY_Undo ] = std::make_pair("Undo", S);
key_map[ EA::KEY_Redo ] = std::make_pair("Redo", S);
key_map[ EA::KEY_Menu ] = std::make_pair("ContextMenu", S);
key_map[ EA::KEY_Find ] = std::make_pair("Find", S);
key_map[ EA::KEY_Cancel ] = std::make_pair("Cancel", S);
key_map[ EA::KEY_Help ] = std::make_pair("Help", S);
key_map[ EA::KEY_Break ] = std::make_pair("Break", S);
key_map[ EA::KEY_Mode_switch ] = std::make_pair("ModeChange", S);
key_map[ EA::KEY_Num_Lock ] = std::make_pair("NumLock", S);
key_map[ EA::KEY_KP_Space ] = std::make_pair(" ", N);
key_map[ EA::KEY_KP_Tab ] = std::make_pair("Tab", N);
key_map[ EA::KEY_KP_Enter ] = std::make_pair("Enter", N);
key_map[ EA::KEY_KP_F1 ] = std::make_pair("F1", N);
key_map[ EA::KEY_KP_F2 ] = std::make_pair("F2", N);
key_map[ EA::KEY_KP_F3 ] = std::make_pair("F3", N);
key_map[ EA::KEY_KP_F4 ] = std::make_pair("F4", N);
key_map[ EA::KEY_KP_Home ] = std::make_pair("Home", N);
key_map[ EA::KEY_KP_Left ] = std::make_pair("Left", N);
key_map[ EA::KEY_KP_Up ] = std::make_pair("Up", N);
key_map[ EA::KEY_KP_Right ] = std::make_pair("Right", N);
key_map[ EA::KEY_KP_Down ] = std::make_pair("Down", N);
key_map[ EA::KEY_KP_Page_Up ] = std::make_pair("PageUp", N);
key_map[ EA::KEY_KP_Page_Down ] = std::make_pair("PageDown", N);
key_map[ EA::KEY_KP_End ] = std::make_pair("End", N);
key_map[ EA::KEY_KP_Begin ] = std::make_pair("Begin", N);
key_map[ EA::KEY_KP_Insert ] = std::make_pair("Insert", N);
key_map[ EA::KEY_KP_Delete ] = std::make_pair("Delete", N);
key_map[ EA::KEY_KP_Equal ] = std::make_pair("=", N);
key_map[ EA::KEY_KP_Multiply ] = std::make_pair("*", N);
key_map[ EA::KEY_KP_Add ] = std::make_pair("+", N);
key_map[ EA::KEY_KP_Separator ] = std::make_pair("", N);
key_map[ EA::KEY_KP_Subtract ] = std::make_pair("-", N);
key_map[ EA::KEY_KP_Decimal ] = std::make_pair("", N);
key_map[ EA::KEY_KP_Divide ] = std::make_pair("/", N);
key_map[ EA::KEY_KP_0 ] = std::make_pair("0", N);
key_map[ EA::KEY_KP_1 ] = std::make_pair("1", N);
key_map[ EA::KEY_KP_2 ] = std::make_pair("2", N);
key_map[ EA::KEY_KP_3 ] = std::make_pair("3", N);
key_map[ EA::KEY_KP_4 ] = std::make_pair("4", N);
key_map[ EA::KEY_KP_5 ] = std::make_pair("5", N);
key_map[ EA::KEY_KP_6 ] = std::make_pair("6", N);
key_map[ EA::KEY_KP_7 ] = std::make_pair("7", N);
key_map[ EA::KEY_KP_8 ] = std::make_pair("8", N);
key_map[ EA::KEY_KP_9 ] = std::make_pair("9", N);
key_map[ EA::KEY_F1 ] = std::make_pair("F1", S);
key_map[ EA::KEY_F2 ] = std::make_pair("F2", S);
key_map[ EA::KEY_F3 ] = std::make_pair("F3", S);
key_map[ EA::KEY_F4 ] = std::make_pair("F4", S);
key_map[ EA::KEY_F5 ] = std::make_pair("F5", S);
key_map[ EA::KEY_F6 ] = std::make_pair("F6", S);
key_map[ EA::KEY_F7 ] = std::make_pair("F7", S);
key_map[ EA::KEY_F8 ] = std::make_pair("F8", S);
key_map[ EA::KEY_F9 ] = std::make_pair("F9", S);
key_map[ EA::KEY_F10 ] = std::make_pair("F10", S);
key_map[ EA::KEY_F11 ] = std::make_pair("F11", S);
key_map[ EA::KEY_F12 ] = std::make_pair("F12", S);
key_map[ EA::KEY_F13 ] = std::make_pair("F13", S);
key_map[ EA::KEY_F14 ] = std::make_pair("F14", S);
key_map[ EA::KEY_F15 ] = std::make_pair("F15", S);
key_map[ EA::KEY_F16 ] = std::make_pair("F16", S);
key_map[ EA::KEY_F17 ] = std::make_pair("F17", S);
key_map[ EA::KEY_F18 ] = std::make_pair("F18", S);
key_map[ EA::KEY_F19 ] = std::make_pair("F19", S);
key_map[ EA::KEY_F20 ] = std::make_pair("F20", S);
key_map[ EA::KEY_F21 ] = std::make_pair("F21", S);
key_map[ EA::KEY_F22 ] = std::make_pair("F22", S);
key_map[ EA::KEY_F23 ] = std::make_pair("F23", S);
key_map[ EA::KEY_F24 ] = std::make_pair("F24", S);
key_map[ EA::KEY_F25 ] = std::make_pair("F25", S);
key_map[ EA::KEY_F26 ] = std::make_pair("F26", S);
key_map[ EA::KEY_F27 ] = std::make_pair("F27", S);
key_map[ EA::KEY_F28 ] = std::make_pair("F28", S);
key_map[ EA::KEY_F29 ] = std::make_pair("F29", S);
key_map[ EA::KEY_F30 ] = std::make_pair("F30", S);
key_map[ EA::KEY_F31 ] = std::make_pair("F31", S);
key_map[ EA::KEY_F32 ] = std::make_pair("F32", S);
key_map[ EA::KEY_F33 ] = std::make_pair("F33", S);
key_map[ EA::KEY_F34 ] = std::make_pair("F34", S);
key_map[ EA::KEY_F35 ] = std::make_pair("F35", S);
key_map[ KEY_AltGraph ] = std::make_pair("AltGraph", S);
key_map[ EA::KEY_Shift_L ] = std::make_pair("Shift", L);
key_map[ EA::KEY_Shift_R ] = std::make_pair("Shift", R);
key_map[ EA::KEY_Control_L ] = std::make_pair("Control", L);
key_map[ EA::KEY_Control_R ] = std::make_pair("Control", R);
key_map[ EA::KEY_Caps_Lock ] = std::make_pair("CapsLock", S);
key_map[ EA::KEY_Shift_Lock ] = std::make_pair("ShiftLock", S);
key_map[ EA::KEY_Meta_L ] = std::make_pair("Meta", L);
key_map[ EA::KEY_Meta_R ] = std::make_pair("Meta", R);
key_map[ EA::KEY_Alt_L ] = std::make_pair("Alt", L);
key_map[ EA::KEY_Alt_R ] = std::make_pair("Alt", R);
key_map[ EA::KEY_Super_L ] = std::make_pair("Super", L);
key_map[ EA::KEY_Super_R ] = std::make_pair("Super", R);
key_map[ EA::KEY_Hyper_L ] = std::make_pair("Hyper", L);
key_map[ EA::KEY_Hyper_R ] = std::make_pair("Hyper", R);
num_pad_keys.insert(EA::KEY_KP_Home );
num_pad_keys.insert(EA::KEY_KP_Left );
num_pad_keys.insert(EA::KEY_KP_Up );
num_pad_keys.insert(EA::KEY_KP_Right );
num_pad_keys.insert(EA::KEY_KP_Down );
num_pad_keys.insert(EA::KEY_KP_Page_Up );
num_pad_keys.insert(EA::KEY_KP_Page_Down);
num_pad_keys.insert(EA::KEY_KP_End );
num_pad_keys.insert(EA::KEY_KP_Begin );
num_pad_keys.insert(EA::KEY_KP_Insert );
num_pad_keys.insert(EA::KEY_KP_Delete );
}
_location = DOM_KEY_LOCATION_STANDARD;
InternalKeyMap::const_iterator it = key_map.find(_key);
if( it != key_map.end())
{
_name = it->second.first;
_location = it->second.second;
}
// Empty or no mapping -> convert UTF-32 key value to UTF-8
if( _name.empty() )
{
if( !utf8::internal::is_code_point_valid(_key) )
_name = "Unidentified";
else
utf8::unchecked::append(_key, std::back_inserter(_name));
}
// Keys on the numpad with NumLock enabled are reported just like their
// equivalent keys in the standard key block. Using the unmodified key value
// we can detect such keys and set the location accordingly.
if( num_pad_keys.find(_unmodified_key) != num_pad_keys.end() )
_location = DOM_KEY_LOCATION_NUMPAD;
return _name;
}
//----------------------------------------------------------------------------
KeyboardEvent::DOMKeyLocation KeyboardEvent::location() const
{
key(); // ensure location is up-to-date
return static_cast<DOMKeyLocation>(_location);
}
//----------------------------------------------------------------------------
bool KeyboardEvent::isModifier() const
{
return ( _key >= EA::KEY_Shift_L
&& _key <= EA::KEY_Hyper_R
)
|| _key == KEY_AltGraph;
}
//----------------------------------------------------------------------------
bool KeyboardEvent::isPrint() const
{
const std::string& key_name = key();
if( key_name.empty() )
return false;
std::string::const_iterator it = key_name.begin();
uint32_t cp = utf8::next(it, key_name.end());
// Check if _name contains exactly one (UTF-8 encoded) character.
if( it != key_name.end() )
return false;
// C0 and C1 control characters are not printable.
if( cp <= 0x1f || (0x7f <= cp && cp <= 0x9f) )
return false;
return true;
}
} // namespace canvas
} // namespace simgear

View File

@@ -0,0 +1,81 @@
///@file
/// Keyboard event
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
// 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 Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef CANVAS_KEYBOARD_EVENT_HXX_
#define CANVAS_KEYBOARD_EVENT_HXX_
#include "DeviceEvent.hxx"
namespace simgear
{
namespace canvas
{
/**
* Keyboard (button up/down) event
*/
class KeyboardEvent:
public DeviceEvent
{
public:
enum DOMKeyLocation
{
DOM_KEY_LOCATION_STANDARD = 0,
DOM_KEY_LOCATION_LEFT,
DOM_KEY_LOCATION_RIGHT,
DOM_KEY_LOCATION_NUMPAD
};
KeyboardEvent();
KeyboardEvent(const osgGA::GUIEventAdapter& ea);
void setKey(uint32_t key);
void setUnmodifiedKey(uint32_t key);
void setRepeat(bool repeat);
std::string key() const;
DOMKeyLocation location() const;
bool repeat() const { return _repeat; }
uint32_t charCode() const { return _key; }
uint32_t keyCode() const { return _unmodified_key; }
/// Whether the key which has triggered this event is a modifier
bool isModifier() const;
/// Whether this events represents an input of a printable character
bool isPrint() const;
protected:
uint32_t _key, //!< Key identifier for this event
_unmodified_key; //!< Virtual key identifier without any
// modifiers applied
bool _repeat; //!< If key has been depressed long enough to
// generate key repetition
mutable std::string _name; //!< Printable representation/name
mutable uint8_t _location; //!< Location of the key on the keyboard
};
} // namespace canvas
} // namespace simgear
#endif /* CANVAS_KEYBOARD_EVENT_HXX_ */

View File

@@ -17,6 +17,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "MouseEvent.hxx"
#include <osgGA/GUIEventAdapter>
namespace simgear
{
@@ -27,7 +28,6 @@ namespace canvas
MouseEvent::MouseEvent():
button(0),
buttons(0),
modifiers(0),
click_count(0)
{
@@ -35,13 +35,11 @@ namespace canvas
//----------------------------------------------------------------------------
MouseEvent::MouseEvent(const osgGA::GUIEventAdapter& ea):
DeviceEvent(ea),
button(0),
buttons(ea.getButtonMask()),
modifiers(ea.getModKeyMask()),
click_count(0)
{
time = ea.getTime();
// Convert button mask to index
int button_mask = ea.getButton();
while( (button_mask >>= 1) > 0 )

View File

@@ -1,4 +1,5 @@
///@file Mouse event
///@file
/// Mouse event
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
@@ -19,16 +20,18 @@
#ifndef CANVAS_MOUSE_EVENT_HXX_
#define CANVAS_MOUSE_EVENT_HXX_
#include <simgear/canvas/CanvasEvent.hxx>
#include <osgGA/GUIEventAdapter>
#include "DeviceEvent.hxx"
namespace simgear
{
namespace canvas
{
/**
* Mouse (button/move/wheel) event
*/
class MouseEvent:
public Event
public DeviceEvent
{
public:
MouseEvent();
@@ -55,18 +58,16 @@ namespace canvas
int getButton() const { return button; }
int getButtonMask() const { return buttons; }
int getModifiers() const { return modifiers; }
int getCurrentClickCount() const { return click_count; }
osg::Vec2f screen_pos, //<! Position in screen coordinates
client_pos, //<! Position in window/canvas coordinates
local_pos, //<! Position in local/element coordinates
osg::Vec2f screen_pos, //!< Position in screen coordinates
client_pos, //!< Position in window/canvas coordinates
local_pos, //!< Position in local/element coordinates
delta;
int button, //<! Button for this event
buttons, //<! Current button state
modifiers, //<! Keyboard modifier state
click_count; //<! Current click count
int button, //!< Button for this event
buttons, //!< Current button state
click_count; //!< Current click count
};
} // namespace canvas

View File

@@ -0,0 +1,78 @@
// Keyboard event demo. Press some keys and get some info...
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
// 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 Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "KeyboardEvent.hxx"
#include <osgViewer/Viewer>
#include <iostream>
class DemoEventHandler:
public osgGA::GUIEventHandler
{
public:
bool handle( const osgGA::GUIEventAdapter& ea,
osgGA::GUIActionAdapter&,
osg::Object*,
osg::NodeVisitor* )
{
switch( ea.getEventType() )
{
case osgGA::GUIEventAdapter::PUSH:
case osgGA::GUIEventAdapter::RELEASE:
case osgGA::GUIEventAdapter::DRAG:
case osgGA::GUIEventAdapter::MOVE:
case osgGA::GUIEventAdapter::SCROLL:
return handleMouse(ea);
case osgGA::GUIEventAdapter::KEYDOWN:
case osgGA::GUIEventAdapter::KEYUP:
return handleKeyboard(ea);
default:
return false;
}
}
protected:
bool handleMouse(const osgGA::GUIEventAdapter&)
{
return false;
}
bool handleKeyboard(const osgGA::GUIEventAdapter& ea)
{
simgear::canvas::KeyboardEvent evt(ea);
std::cout << evt.getTypeString() << " '" << evt.key() << "'"
<< ", loc=" << evt.location()
<< ", char=" << evt.charCode()
<< ", key=" << evt.keyCode()
<< (evt.isPrint() ? ", printable" : "")
<< std::endl;
return true;
}
};
int main()
{
osgViewer::Viewer viewer;
osg::ref_ptr<DemoEventHandler> handler( new DemoEventHandler );
viewer.addEventHandler(handler);
viewer.setUpViewInWindow(100, 100, 200, 100, 0);
viewer.setRunMaxFrameRate(5);
return viewer.run();
}

View File

@@ -0,0 +1,43 @@
///@file
/// Enumeration of layout alignment flags.
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
// 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 Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef ALIGN_ENUM_MAPPING
# error "Only include with ALIGN_ENUM_MAPPING defined!"
#endif
ALIGN_ENUM_MAPPING(AlignFill, 0, Use all available space)
ALIGN_ENUM_MAPPING(AlignLeft, 0x01, Align with left edge)
ALIGN_ENUM_MAPPING(AlignRight, 0x02, Align with right edge)
ALIGN_ENUM_MAPPING(AlignHCenter, 0x04, Center horizontally in available space)
ALIGN_ENUM_MAPPING(AlignTop, 0x20, Align with top edge)
ALIGN_ENUM_MAPPING(AlignBottom, 0x40, Align with bottom edge)
ALIGN_ENUM_MAPPING(AlignVCenter, 0x80, Center vertically in available space)
ALIGN_ENUM_MAPPING( AlignCenter,
AlignVCenter | AlignHCenter,
Center both vertically and horizontally )
ALIGN_ENUM_MAPPING( AlignHorizontal_Mask,
AlignLeft | AlignRight | AlignHCenter,
Mask of all horizontal alignment flags )
ALIGN_ENUM_MAPPING( AlignVertical_Mask,
AlignTop | AlignBottom | AlignVCenter,
Mask of all vertical alignment flags )

View File

@@ -46,9 +46,11 @@ namespace canvas
}
//----------------------------------------------------------------------------
void BoxLayout::addItem(const LayoutItemRef& item, int stretch)
void BoxLayout::addItem( const LayoutItemRef& item,
int stretch,
uint8_t alignment )
{
insertItem(-1, item, stretch);
insertItem(-1, item, stretch, alignment);
}
//----------------------------------------------------------------------------
@@ -64,14 +66,24 @@ namespace canvas
}
//----------------------------------------------------------------------------
void BoxLayout::insertItem(int index, const LayoutItemRef& item, int stretch)
void BoxLayout::insertItem( int index,
const LayoutItemRef& item,
int stretch,
uint8_t alignment )
{
ItemData item_data = {0};
item_data.layout_item = item;
item_data.stretch = std::max(0, stretch);
item->setCanvas(_canvas);
item->setParent(this);
if( alignment != AlignFill )
item->setAlignment(alignment);
if( SGWeakReferenced::count(this) )
item->setParent(this);
else
SG_LOG( SG_GUI,
SG_WARN,
"Adding item to expired or non-refcounted layout" );
if( index < 0 )
_layout_items.push_back(item_data);
@@ -122,6 +134,7 @@ namespace canvas
LayoutItems::iterator it = _layout_items.begin() + index;
LayoutItemRef item = it->layout_item;
item->onRemove();
item->setParent(LayoutItemWeakRef());
_layout_items.erase(it);
invalidate();
@@ -137,6 +150,7 @@ namespace canvas
++it )
{
it->layout_item->onRemove();
it->layout_item->setParent(LayoutItemWeakRef());
}
_layout_items.clear();
invalidate();
@@ -223,26 +237,6 @@ namespace canvas
return _layout_data.has_hfw;
}
//----------------------------------------------------------------------------
int BoxLayout::heightForWidth(int w) const
{
if( !hasHeightForWidth() )
return -1;
updateWFHCache(w);
return _hfw_height;
}
//----------------------------------------------------------------------------
int BoxLayout::minimumHeightForWidth(int w) const
{
if( !hasHeightForWidth() )
return -1;
updateWFHCache(w);
return _hfw_min_height;
}
//----------------------------------------------------------------------------
void BoxLayout::setCanvas(const CanvasWeakPtr& canvas)
{
@@ -272,16 +266,23 @@ namespace canvas
for(size_t i = 0; i < _layout_items.size(); ++i)
{
// TODO check visible
ItemData& item_data = _layout_items[i];
LayoutItem const& item = *item_data.layout_item;
item_data.visible = item.isVisible();
if( !item_data.visible )
continue;
item_data.min_size = (item.minimumSize().*_get_layout_coord)();
item_data.max_size = (item.maximumSize().*_get_layout_coord)();
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
item_data.has_hfw = item.hasHeightForWidth();
uint8_t alignment_mask = horiz()
? AlignHorizontal_Mask
: AlignVertical_Mask;
item_data.has_align = (item.alignment() & alignment_mask) != 0;
if( !dynamic_cast<SpacerItem*>(item_data.layout_item.get()) )
{
if( is_first )
@@ -297,9 +298,9 @@ namespace canvas
}
// Add sizes of all children in layout direction
safeAdd(min_size.x(), item_data.min_size);
safeAdd(max_size.x(), item_data.max_size);
safeAdd(size_hint.x(), item_data.size_hint);
SGMisc<int>::addClipOverflowInplace(min_size.x(), item_data.min_size);
SGMisc<int>::addClipOverflowInplace(max_size.x(), item_data.max_size);
SGMisc<int>::addClipOverflowInplace(size_hint.x(), item_data.size_hint);
// Take maximum in fixed (non-layouted) direction
min_size.y() = std::max( min_size.y(),
@@ -312,9 +313,9 @@ namespace canvas
_layout_data.has_hfw = _layout_data.has_hfw || item.hasHeightForWidth();
}
safeAdd(min_size.x(), _layout_data.padding);
safeAdd(max_size.x(), _layout_data.padding);
safeAdd(size_hint.x(), _layout_data.padding);
SGMisc<int>::addClipOverflowInplace(min_size.x(), _layout_data.padding);
SGMisc<int>::addClipOverflowInplace(max_size.x(), _layout_data.padding);
SGMisc<int>::addClipOverflowInplace(size_hint.x(), _layout_data.padding);
_layout_data.min_size = min_size.x();
_layout_data.max_size = max_size.x();
@@ -348,6 +349,9 @@ namespace canvas
for(size_t i = 0; i < _layout_items.size(); ++i)
{
ItemData const& data = _layout_items[i];
if( !data.visible )
continue;
_hfw_height = std::max(_hfw_height, data.hfw(data.size));
_hfw_min_height = std::max(_hfw_min_height, data.mhfw(data.size));
}
@@ -357,6 +361,9 @@ namespace canvas
for(size_t i = 0; i < _layout_items.size(); ++i)
{
ItemData const& data = _layout_items[i];
if( !data.visible )
continue;
_hfw_height += data.hfw(w) + data.padding_orig;
_hfw_min_height += data.mhfw(w) + data.padding_orig;
}
@@ -386,6 +393,27 @@ namespace canvas
return _max_size;
}
//----------------------------------------------------------------------------
int BoxLayout::heightForWidthImpl(int w) const
{
if( !hasHeightForWidth() )
return -1;
updateWFHCache(w);
return _hfw_height;
}
//----------------------------------------------------------------------------
int BoxLayout::minimumHeightForWidthImpl(int w) const
{
if( !hasHeightForWidth() )
return -1;
updateWFHCache(w);
return _hfw_min_height;
}
//----------------------------------------------------------------------------
void BoxLayout::doLayout(const SGRecti& geom)
{
@@ -406,6 +434,9 @@ namespace canvas
for(size_t i = 0; i < _layout_items.size(); ++i)
{
ItemData& data = _layout_items[i];
if( !data.visible )
continue;
if( data.has_hfw )
{
int w = SGMisc<int>::clip( geom.width(),
@@ -434,7 +465,10 @@ namespace canvas
_layout_data.size_hint = size_hint_save;
// and finally set the layouted geometry for each item
int fixed_size = (geom.size().*_get_fixed_coord)();
SGVec2i size( 0,
// Always assign all available space. Alignment handles final
// size.
(geom.size().*_get_fixed_coord)() );
SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
(geom.pos().*_get_fixed_coord)() );
@@ -445,17 +479,11 @@ namespace canvas
for(size_t i = 0; i < _layout_items.size(); ++i)
{
ItemData const& data = _layout_items[i];
if( !data.visible )
continue;
cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
SGVec2i size(
data.size,
std::min( (data.layout_item->maximumSize().*_get_fixed_coord)(),
fixed_size )
);
// Center in fixed direction (TODO allow specifying alignment)
int offset_fixed = (fixed_size - size.y()) / 2;
cur_pos.y() += offset_fixed;
size.x() = data.size;
data.layout_item->setGeometry(SGRecti(
(cur_pos.*_get_layout_coord)(),
@@ -466,10 +494,16 @@ namespace canvas
if( !reverse )
cur_pos.x() += data.size;
cur_pos.y() -= offset_fixed;
}
}
//----------------------------------------------------------------------------
void BoxLayout::visibilityChanged(bool visible)
{
for(size_t i = 0; i < _layout_items.size(); ++i)
callSetVisibleInternal(_layout_items[i].layout_item.get(), visible);
}
//----------------------------------------------------------------------------
HBoxLayout::HBoxLayout():
BoxLayout(LeftToRight)

View File

@@ -1,4 +1,4 @@
// Align items horizontally or vertically in a box
/// @file
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
@@ -26,6 +26,11 @@ namespace simgear
namespace canvas
{
/**
* Align LayoutItems horizontally or vertically in a box.
*
* @see http://qt-project.org/doc/qt-4.8/qboxlayout.html#details
*/
class BoxLayout:
public Layout
{
@@ -44,13 +49,18 @@ namespace canvas
virtual void addItem(const LayoutItemRef& item);
void addItem(const LayoutItemRef& item, int stretch);
void addItem( const LayoutItemRef& item,
int stretch,
uint8_t alignment = 0 );
void addStretch(int stretch = 0);
void addSpacing(int size);
void insertItem(int index, const LayoutItemRef& item, int stretch = 0);
void insertItem( int index,
const LayoutItemRef& item,
int stretch = 0,
uint8_t alignment = 0 );
void insertStretch(int index, int stretch = 0);
@@ -86,8 +96,6 @@ namespace canvas
Direction direction() const;
virtual bool hasHeightForWidth() const;
virtual int heightForWidth(int w) const;
virtual int minimumHeightForWidth(int w) const;
virtual void setCanvas(const CanvasWeakPtr& canvas);
@@ -96,9 +104,9 @@ namespace canvas
protected:
typedef const int& (SGVec2i::*CoordGetter)() const;
CoordGetter _get_layout_coord, //<! getter for coordinate in layout
CoordGetter _get_layout_coord, //!< getter for coordinate in layout
// direction
_get_fixed_coord; //<! getter for coordinate in secondary
_get_fixed_coord; //!< getter for coordinate in secondary
// (fixed) direction
int _padding;
@@ -121,7 +129,12 @@ namespace canvas
virtual SGVec2i minimumSizeImpl() const;
virtual SGVec2i maximumSizeImpl() const;
virtual int heightForWidthImpl(int w) const;
virtual int minimumHeightForWidthImpl(int w) const;
virtual void doLayout(const SGRecti& geom);
virtual void visibilityChanged(bool visible);
};
/**

View File

@@ -1,6 +1,7 @@
include (SimGearComponent)
set(HEADERS
AlignFlag_values.hxx
BoxLayout.hxx
Layout.hxx
LayoutItem.hxx

View File

@@ -24,36 +24,6 @@ namespace simgear
namespace canvas
{
//----------------------------------------------------------------------------
void Layout::update()
{
if( !(_flags & (LAYOUT_DIRTY | SIZE_INFO_DIRTY)) )
return;
doLayout(_geometry);
_flags &= ~LAYOUT_DIRTY;
}
//----------------------------------------------------------------------------
void Layout::invalidate()
{
LayoutItem::invalidate();
_flags |= LAYOUT_DIRTY;
}
//----------------------------------------------------------------------------
void Layout::setGeometry(const SGRecti& geom)
{
if( geom != _geometry )
{
_geometry = geom;
_flags |= LAYOUT_DIRTY;
}
update();
}
//----------------------------------------------------------------------------
void Layout::removeItem(const LayoutItemRef& item)
{
@@ -74,6 +44,19 @@ namespace canvas
takeAt(0);
}
//----------------------------------------------------------------------------
SGRecti Layout::alignmentRect(const SGRecti& geom) const
{
return alignment() == AlignFill
// Without explicit alignment (default == AlignFill) use the whole
// available space and let the layout and its items distribute the
// excess space.
? geom
// Otherwise align according to flags.
: LayoutItem::alignmentRect(geom);
}
//----------------------------------------------------------------------------
void Layout::ItemData::reset()
{
@@ -85,6 +68,8 @@ namespace canvas
padding = 0;
size = 0;
stretch = 0;
visible = false;
has_align = false;
has_hfw = false;
done = false;
}
@@ -108,19 +93,28 @@ namespace canvas
}
//----------------------------------------------------------------------------
void Layout::safeAdd(int& a, int b)
Layout::Layout():
_num_not_done(0),
_sum_stretch(0),
_space_stretch(0),
_space_left(0)
{
if( SGLimits<int>::max() - b < a )
a = SGLimits<int>::max();
else
a += b;
}
//----------------------------------------------------------------------------
void Layout::contentsRectChanged(const SGRecti& rect)
{
doLayout(rect);
_flags &= ~LAYOUT_DIRTY;
}
//----------------------------------------------------------------------------
void Layout::distribute(std::vector<ItemData>& items, const ItemData& space)
{
const int num_children = static_cast<int>(items.size());
_num_not_done = num_children;
_num_not_done = 0;
SG_LOG( SG_GUI,
SG_DEBUG,
@@ -148,6 +142,9 @@ namespace canvas
for(int i = 0; i < num_children; ++i)
{
ItemData& d = items[i];
if( !d.visible )
continue;
d.size = less_then_hint ? d.min_size : d.size_hint;
d.padding = d.padding_orig;
d.done = d.size >= (less_then_hint ? d.size_hint : d.max_size);
@@ -162,10 +159,8 @@ namespace canvas
);
if( d.done )
{
_num_not_done -= 1;
continue;
}
_num_not_done += 1;
if( d.stretch > 0 )
{
@@ -191,6 +186,8 @@ namespace canvas
for(int i = 0; i < num_children; ++i)
{
ItemData& d = items[i];
if( !d.visible )
continue;
SG_LOG(
SG_GUI,
@@ -265,18 +262,59 @@ namespace canvas
else
{
_space_left = space.size - space.max_size;
int num_align = 0;
for(int i = 0; i < num_children; ++i)
{
if( !items[i].visible )
continue;
_num_not_done += 1;
if( items[i].has_align )
num_align += 1;
}
SG_LOG(
SG_GUI,
SG_DEBUG,
"Distributing excess space:"
" not_done=" << _num_not_done
<< ", num_align=" << num_align
<< ", space_left=" << _space_left
);
for(int i = 0; i < num_children; ++i)
{
ItemData& d = items[i];
if( !d.visible )
continue;
d.padding = d.padding_orig;
d.size = d.max_size;
// Add superfluous space as padding
d.padding = d.padding_orig + _space_left
// Padding after last child...
/ (_num_not_done + 1);
int space_add = 0;
_space_left -= d.padding - d.padding_orig;
_num_not_done -= 1;
if( d.has_align )
{
// Equally distribute superfluous space and let each child items
// alignment handle the exact usage.
space_add = _space_left / num_align;
num_align -= 1;
d.size += space_add;
}
else if( num_align <= 0 )
{
// Add superfluous space as padding
space_add = _space_left
// Padding after last child...
/ (_num_not_done + 1);
_num_not_done -= 1;
d.padding += space_add;
}
_space_left -= space_add;
}
}
@@ -284,10 +322,11 @@ namespace canvas
for(int i = 0; i < num_children; ++i)
{
ItemData const& d = items[i];
SG_LOG( SG_GUI,
SG_DEBUG,
i << ") pad=" << d.padding
<< ", size = " << d.size );
if( d.visible )
SG_LOG(SG_GUI, SG_DEBUG, i << ") pad=" << d.padding
<< ", size= " << d.size);
else
SG_LOG(SG_GUI, SG_DEBUG, i << ") [hidden]");
}
}

View File

@@ -1,4 +1,4 @@
// Basic class for canvas layouts
/// @file
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
@@ -27,15 +27,13 @@ namespace simgear
namespace canvas
{
/**
* Base class for all Canvas layouts.
*/
class Layout:
public LayoutItem
{
public:
void update();
virtual void invalidate();
virtual void setGeometry(const SGRecti& geom);
virtual void addItem(const LayoutItemRef& item) = 0;
virtual void setSpacing(int spacing) = 0;
virtual int spacing() const = 0;
@@ -71,11 +69,22 @@ namespace canvas
*/
virtual void clear();
/**
* Get the actual geometry of this layout given the rectangle \a geom
* taking into account the alignment flags and size hints. For layouts,
* if no alignment (different to AlignFill) is set, the whole area is
* used. Excess space is distributed by the layouting algorithm and
* handled by the individual children.
*
* @param geom Area available to this layout.
* @return The resulting geometry for this layout.
*/
virtual SGRecti alignmentRect(const SGRecti& geom) const;
protected:
enum LayoutFlags
{
LAYOUT_DIRTY = LayoutItem::LAST_FLAG << 1,
LAST_FLAG = LAYOUT_DIRTY
LAST_FLAG = LayoutItem::LAST_FLAG
};
struct ItemData
@@ -84,12 +93,14 @@ namespace canvas
int size_hint,
min_size,
max_size,
padding_orig, //<! original padding as specified by the user
padding, //<! padding before element (layouted)
size, //<! layouted size
stretch; //<! stretch factor
bool has_hfw : 1, //<! height for width
done : 1; //<! layouting done
padding_orig, //!< original padding as specified by the user
padding, //!< padding before element (layouted)
size, //!< layouted size
stretch; //!< stretch factor
bool visible : 1,
has_align: 1, //!< Has alignment factor set (!= AlignFill)
has_hfw : 1, //!< height for width
done : 1; //!< layouting done
/** Clear values (reset to default/empty state) */
void reset();
@@ -98,16 +109,15 @@ namespace canvas
int mhfw(int w) const;
};
Layout();
virtual void contentsRectChanged(const SGRecti& rect);
/**
* Override to implement the actual layouting
*/
virtual void doLayout(const SGRecti& geom) = 0;
/**
* Add two integers taking care of overflow (limit to INT_MAX)
*/
static void safeAdd(int& a, int b);
/**
* Distribute the available @a space to all @a items
*/
@@ -115,12 +125,12 @@ namespace canvas
private:
int _num_not_done, //<! number of children not layouted yet
_sum_stretch, //<! sum of stretch factors of all not yet layouted
int _num_not_done, //!< number of children not layouted yet
_sum_stretch, //!< sum of stretch factors of all not yet layouted
// children
_space_stretch,//<! space currently assigned to all not yet layouted
_space_stretch,//!< space currently assigned to all not yet layouted
// stretchable children
_space_left; //<! remaining space not used by any child yet
_space_left; //!< remaining space not used by any child yet
};

View File

@@ -23,12 +23,61 @@ namespace simgear
{
namespace canvas
{
//----------------------------------------------------------------------------
Margins::Margins(int m):
l(m), t(m), r(m), b(m)
{
}
//----------------------------------------------------------------------------
Margins::Margins(int h, int v):
l(h), t(v),
r(h), b(v)
{
}
//----------------------------------------------------------------------------
Margins::Margins(int l, int t, int r, int b):
l(l), t(t), r(r), b(b)
{
}
//----------------------------------------------------------------------------
int Margins::horiz() const
{
return l + r;
}
//----------------------------------------------------------------------------
int Margins::vert() const
{
return t + b;
}
//----------------------------------------------------------------------------
SGVec2i Margins::size() const
{
return SGVec2i(horiz(), vert());
}
//----------------------------------------------------------------------------
bool Margins::isNull() const
{
return l == 0 && t == 0 && r == 0 && b == 0;
}
//----------------------------------------------------------------------------
const SGVec2i LayoutItem::MAX_SIZE( SGLimits<int>::max(),
SGLimits<int>::max() );
//----------------------------------------------------------------------------
LayoutItem::LayoutItem():
_flags(0),
_alignment(AlignFill),
_flags(VISIBLE),
_size_hint(0, 0),
_min_size(0, 0),
_max_size(MAX_SIZE)
@@ -42,6 +91,44 @@ namespace canvas
}
//----------------------------------------------------------------------------
void LayoutItem::setContentsMargins(const Margins& margins)
{
_margins = margins;
}
//----------------------------------------------------------------------------
void LayoutItem::setContentsMargins(int left, int top, int right, int bottom)
{
_margins.l = left;
_margins.t = top;
_margins.r = right;
_margins.b = bottom;
}
//----------------------------------------------------------------------------
void LayoutItem::setContentsMargin(int margin)
{
setContentsMargins(margin, margin, margin, margin);
}
//----------------------------------------------------------------------------
Margins LayoutItem::getContentsMargins() const
{
return _margins;
}
//----------------------------------------------------------------------------
SGRecti LayoutItem::contentsRect() const
{
return SGRecti(
_geometry.x() + _margins.l,
_geometry.y() + _margins.t,
std::max(0, _geometry.width() - _margins.horiz()),
std::max(0, _geometry.height() - _margins.vert())
);
}
//----------------------------------------------------------------------------
SGVec2i LayoutItem::sizeHint() const
{
@@ -51,7 +138,7 @@ namespace canvas
_flags &= ~SIZE_HINT_DIRTY;
}
return _size_hint;
return addClipOverflow(_size_hint, _margins.size());
}
//----------------------------------------------------------------------------
@@ -63,7 +150,7 @@ namespace canvas
_flags &= ~MINIMUM_SIZE_DIRTY;
}
return _min_size;
return addClipOverflow(_min_size, _margins.size());
}
//----------------------------------------------------------------------------
@@ -75,7 +162,7 @@ namespace canvas
_flags &= ~MAXIMUM_SIZE_DIRTY;
}
return _max_size;
return addClipOverflow(_max_size, _margins.size());
}
//----------------------------------------------------------------------------
@@ -87,19 +174,60 @@ namespace canvas
//----------------------------------------------------------------------------
int LayoutItem::heightForWidth(int w) const
{
return -1;
int h = heightForWidthImpl(w - _margins.horiz());
return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
}
//------------------------------------------------------------------------------
int LayoutItem::minimumHeightForWidth(int w) const
{
return heightForWidth(w);
int h = minimumHeightForWidthImpl(w - _margins.horiz());
return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
}
//----------------------------------------------------------------------------
void LayoutItem::setAlignment(uint8_t align)
{
if( align == _alignment )
return;
_alignment = align;
invalidateParent();
}
//----------------------------------------------------------------------------
uint8_t LayoutItem::alignment() const
{
return _alignment;
}
//----------------------------------------------------------------------------
void LayoutItem::setVisible(bool visible)
{
if( visible )
_flags &= ~EXPLICITLY_HIDDEN;
else
_flags |= EXPLICITLY_HIDDEN;
setVisibleInternal(visible);
}
//----------------------------------------------------------------------------
bool LayoutItem::isVisible() const
{
return _flags & VISIBLE;
}
//----------------------------------------------------------------------------
bool LayoutItem::isExplicitlyHidden() const
{
return _flags & EXPLICITLY_HIDDEN;
}
//----------------------------------------------------------------------------
void LayoutItem::invalidate()
{
_flags |= SIZE_INFO_DIRTY;
_flags |= SIZE_INFO_DIRTY | LAYOUT_DIRTY;
invalidateParent();
}
@@ -111,10 +239,24 @@ namespace canvas
parent->invalidate();
}
//----------------------------------------------------------------------------
void LayoutItem::update()
{
if( (_flags & LAYOUT_DIRTY) && isVisible() )
contentsRectChanged( contentsRect() );
}
//----------------------------------------------------------------------------
void LayoutItem::setGeometry(const SGRecti& geom)
{
_geometry = geom;
SGRecti ar = alignmentRect(geom);
if( ar != _geometry )
{
_geometry = ar;
_flags |= LAYOUT_DIRTY;
}
update();
}
//----------------------------------------------------------------------------
@@ -123,6 +265,41 @@ namespace canvas
return _geometry;
}
//----------------------------------------------------------------------------
SGRecti LayoutItem::alignmentRect(const SGRecti& geom) const
{
uint8_t halign = alignment() & AlignHorizontal_Mask,
valign = alignment() & AlignVertical_Mask;
// Size
SGVec2i size = sizeHint();
if( halign == AlignFill )
size.x() = maximumSize().x();
size.x() = std::min(size.x(), geom.width());
if( valign == AlignFill )
size.y() = maximumSize().y();
else if( hasHeightForWidth() )
size.y() = heightForWidth(size.x());
size.y() = std::min(size.y(), geom.height());
// Position
SGVec2i pos = geom.pos();
if( halign & AlignRight )
pos.x() += geom.width() - size.x();
else if( !(halign & AlignLeft) )
pos.x() += (geom.width() - size.x()) / 2;
if( valign & AlignBottom )
pos.y() += geom.height() - size.y();
else if( !(valign & AlignTop) )
pos.y() += (geom.height() - size.y()) / 2;
return SGRecti(pos, pos + size);
}
//----------------------------------------------------------------------------
void LayoutItem::setCanvas(const CanvasWeakPtr& canvas)
{
@@ -140,7 +317,14 @@ namespace canvas
{
_parent = parent;
LayoutItemRef parent_ref = parent.lock();
setCanvas(parent_ref ? parent_ref->_canvas : CanvasWeakPtr());
if( parent_ref )
// Only change the canvas if there is a new parent. If the item is removed
// keep the old canvas, as it may be used for example during the call to
// onRemove.
setCanvas(parent_ref->_canvas);
setVisibleInternal(!parent_ref || parent_ref->isVisible());
}
//----------------------------------------------------------------------------
@@ -167,5 +351,43 @@ namespace canvas
return _max_size;
}
//----------------------------------------------------------------------------
int LayoutItem::heightForWidthImpl(int w) const
{
return -1;
}
//------------------------------------------------------------------------------
int LayoutItem::minimumHeightForWidthImpl(int w) const
{
return heightForWidth(w);
}
//----------------------------------------------------------------------------
void LayoutItem::setVisibleInternal(bool visible)
{
LayoutItemRef parent = getParent();
if( isExplicitlyHidden() || (parent && !parent->isVisible()) )
visible = false;
if( isVisible() == visible )
return;
invalidateParent();
if( visible )
_flags |= VISIBLE;
else
_flags &= ~VISIBLE;
visibilityChanged(visible);
}
//----------------------------------------------------------------------------
void LayoutItem::callSetVisibleInternal(LayoutItem* item, bool visible)
{
item->setVisibleInternal(visible);
}
} // namespace canvas
} // namespace simgear

View File

@@ -1,4 +1,5 @@
///@file Basic element for layouting canvas elements
///@file
/// Basic element for layouting canvas elements.
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
@@ -34,6 +35,65 @@ namespace canvas
typedef SGSharedPtr<LayoutItem> LayoutItemRef;
typedef SGWeakPtr<LayoutItem> LayoutItemWeakRef;
/**
* Holds the four margins for a rectangle.
*/
struct Margins
{
int l, t, r, b;
/**
* Set all margins to the same value @a m.
*/
explicit Margins(int m = 0);
/**
* Set horizontal and vertical margins to the same values @a h and @a v
* respectively.
*
* @param h Horizontal margins
* @param v Vertical margins
*/
Margins(int h, int v);
/**
* Set the margins to the given values.
*/
Margins(int left, int top, int right, int bottom);
/**
* Get the total horizontal margin (sum of left and right margin).
*/
int horiz() const;
/**
* Get the total vertical margin (sum of top and bottom margin).
*/
int vert() const;
/**
* Get total horizontal and vertical margin as vector.
*/
SGVec2i size() const;
/**
* Returns true if all margins are 0.
*/
bool isNull() const;
};
/**
* Flags for LayoutItem alignment inside {@link Layout Layouts}.
*
* @note You can only use one horizontal and one vertical flag at the same.
*/
enum AlignmentFlag
{
#define ALIGN_ENUM_MAPPING(key, val, comment) key = val, /*!< comment */
# include "AlignFlag_values.hxx"
#undef ALIGN_ENUM_MAPPING
};
/**
* Base class for all layouting elements. Specializations either implement a
* layouting algorithm or a widget.
@@ -49,6 +109,49 @@ namespace canvas
LayoutItem();
virtual ~LayoutItem();
/**
* Set the margins to use by the layout system around the item.
*
* The margins define the size of the clear area around an item. It
* increases the size hints and reduces the size of the geometry()
* available to child layouts and widgets.
*
* @see Margins
*/
void setContentsMargins(const Margins& margins);
/**
* Set the individual margins.
*
* @see setContentsMargins(const Margins&)
*/
void setContentsMargins(int left, int top, int right, int bottom);
/**
* Set all margins to the same value.
*
* @see setContentsMargins(const Margins&)
*/
void setContentsMargin(int margin);
/**
* Get the currently used margins.
*
* @see setContentsMargins(const Margins&)
* @see Margins
*/
Margins getContentsMargins() const;
/**
* Get the area available to the contents.
*
* This is equal to the geometry() reduced by the sizes of the margins.
*
* @see setContentsMargins(const Margins&)
* @see geometry()
*/
SGRecti contentsRect() const;
/**
* Get the preferred size of this item.
*/
@@ -64,9 +167,60 @@ namespace canvas
*/
SGVec2i maximumSize() const;
/**
* Returns true if this items preferred and minimum height depend on its
* width.
*
* The default implementation returns false. Reimplement for items
* providing height for width.
*
* @see heightForWidth()
* @see minimumHeightForWidth()
*/
virtual bool hasHeightForWidth() const;
virtual int heightForWidth(int w) const;
virtual int minimumHeightForWidth(int w) const;
/**
* Returns the preferred height for the given width @a w.
*
* Reimplement heightForWidthImpl() for items providing height for width.
*
* @see hasHeightForWidth()
*/
int heightForWidth(int w) const;
/**
* Returns the minimum height for the given width @a w.
*
* Reimplement minimumHeightForWidthImpl() for items providing height for
* width.
*
* @see hasHeightForWidth()
*/
int minimumHeightForWidth(int w) const;
/**
* Set alignment of item within {@link Layout Layouts}.
*
* @param alignment Bitwise combination of vertical and horizontal
* alignment flags.
* @see AlignmentFlag
*/
void setAlignment(uint8_t alignment);
/**
* Get all alignment flags.
*
* @see AlignmentFlag
*/
uint8_t alignment() const;
virtual void setVisible(bool visible);
virtual bool isVisible() const;
bool isExplicitlyHidden() const;
void show() { setVisible(true); }
void hide() { setVisible(false); }
/**
* Mark all cached data as invalid and require it to be recalculated.
@@ -74,10 +228,15 @@ namespace canvas
virtual void invalidate();
/**
* Mark all cached data of parent item as invalid (if it is known)
* Mark all cached data of parent item as invalid (if the parent is set).
*/
void invalidateParent();
/**
* Apply any changes not applied yet.
*/
void update();
/**
* Set position and size of this element. For layouts this triggers a
* recalculation of the layout.
@@ -89,6 +248,20 @@ namespace canvas
*/
virtual SGRecti geometry() const;
/**
* Get the actual geometry of this item given the rectangle \a geom
* taking into account the alignment flags and size hints.
*
* @param geom Area available to this item.
* @return The resulting geometry for this item.
*
* @see setAlignment()
* @see minimumSize()
* @see maximumSize()
* @see sizeHint()
*/
virtual SGRecti alignmentRect(const SGRecti& geom) const;
/**
* Set the canvas this item is attached to.
*/
@@ -124,13 +297,18 @@ namespace canvas
SIZE_INFO_DIRTY = SIZE_HINT_DIRTY
| MINIMUM_SIZE_DIRTY
| MAXIMUM_SIZE_DIRTY,
LAST_FLAG = MAXIMUM_SIZE_DIRTY
EXPLICITLY_HIDDEN = MAXIMUM_SIZE_DIRTY << 1,
VISIBLE = EXPLICITLY_HIDDEN << 1,
LAYOUT_DIRTY = VISIBLE << 1,
LAST_FLAG = LAYOUT_DIRTY
};
CanvasWeakPtr _canvas;
LayoutItemWeakRef _parent;
SGRecti _geometry;
Margins _margins;
uint8_t _alignment;
mutable uint32_t _flags;
mutable SGVec2i _size_hint,
@@ -141,6 +319,50 @@ namespace canvas
virtual SGVec2i minimumSizeImpl() const;
virtual SGVec2i maximumSizeImpl() const;
/**
* Returns the preferred height for the given width @a w.
*
* The default implementation returns -1, indicating that the preferred
* height is independent of the given width.
*
* Reimplement this function for items supporting height for width.
*
* @note Do not take margins into account, as this is already handled
* before calling this function.
*
* @see hasHeightForWidth()
*/
virtual int heightForWidthImpl(int w) const;
/**
* Returns the minimum height for the given width @a w.
*
* The default implementation returns -1, indicating that the minimum
* height is independent of the given width.
*
* Reimplement this function for items supporting height for width.
*
* @note Do not take margins into account, as this is already handled
* before calling this function.
*
* @see hasHeightForWidth()
*/
virtual int minimumHeightForWidthImpl(int w) const;
/**
* @return whether the visibility has changed.
*/
void setVisibleInternal(bool visible);
virtual void contentsRectChanged(const SGRecti& rect) {};
virtual void visibilityChanged(bool visible) {}
/**
* Allow calling the protected setVisibleImpl from derived classes
*/
static void callSetVisibleInternal(LayoutItem* item, bool visible);
};
} // namespace canvas

View File

@@ -19,6 +19,7 @@
#include "NasalWidget.hxx"
#include <simgear/canvas/Canvas.hxx>
#include <simgear/nasal/cppbind/NasalContext.hxx>
#include <simgear/nasal/cppbind/Ghost.hxx>
namespace simgear
@@ -45,53 +46,12 @@ namespace canvas
onRemove();
}
//----------------------------------------------------------------------------
void NasalWidget::invalidate()
{
LayoutItem::invalidate();
_flags |= LAYOUT_DIRTY;
}
//----------------------------------------------------------------------------
void NasalWidget::setGeometry(const SGRect<int>& geom)
{
if( _geometry != geom )
_geometry = geom;
else if( !(_flags & LAYOUT_DIRTY) || !_set_geometry )
return;
naContext c = naNewContext();
try
{
_set_geometry(nasal::to_nasal(c, this), geom);
_flags &= ~LAYOUT_DIRTY;
}
catch( std::exception const& ex )
{
SG_LOG(
SG_GUI,
SG_WARN,
"NasalWidget::setGeometry: callback error: '" << ex.what() << "'"
);
}
naFreeContext(c);
}
//----------------------------------------------------------------------------
void NasalWidget::onRemove()
{
if( !_nasal_impl.valid() )
return;
typedef boost::function<void(nasal::Me)> Deleter;
naContext c = naNewContext();
try
{
Deleter del =
nasal::get_member<Deleter>(c, _nasal_impl.get_naRef(), "onRemove");
if( del )
del(nasal::to_nasal(c, this));
callMethod<void>("onRemove");
}
catch( std::exception const& ex )
{
@@ -101,7 +61,6 @@ namespace canvas
"NasalWidget::onRemove: callback error: '" << ex.what() << "'"
);
}
naFreeContext(c);
}
//----------------------------------------------------------------------------
@@ -192,22 +151,6 @@ namespace canvas
return !_height_for_width.empty() || !_min_height_for_width.empty();
}
//----------------------------------------------------------------------------
int NasalWidget::heightForWidth(int w) const
{
return callHeightForWidthFunc( _height_for_width.empty()
? _min_height_for_width
: _height_for_width, w );
}
//----------------------------------------------------------------------------
int NasalWidget::minimumHeightForWidth(int w) const
{
return callHeightForWidthFunc( _min_height_for_width.empty()
? _height_for_width
: _min_height_for_width, w );
}
//----------------------------------------------------------------------------
static naRef f_makeNasalWidget(const nasal::CallContext& ctx)
{
@@ -291,5 +234,62 @@ namespace canvas
);
}
//----------------------------------------------------------------------------
int NasalWidget::heightForWidthImpl(int w) const
{
return callHeightForWidthFunc( _height_for_width.empty()
? _min_height_for_width
: _height_for_width, w );
}
//----------------------------------------------------------------------------
int NasalWidget::minimumHeightForWidthImpl(int w) const
{
return callHeightForWidthFunc( _min_height_for_width.empty()
? _height_for_width
: _min_height_for_width, w );
}
//----------------------------------------------------------------------------
void NasalWidget::contentsRectChanged(const SGRect<int>& rect)
{
if( !_set_geometry )
return;
try
{
nasal::Context c;
_set_geometry(nasal::to_nasal(c, this), rect);
_flags &= ~LAYOUT_DIRTY;
}
catch( std::exception const& ex )
{
SG_LOG(
SG_GUI,
SG_WARN,
"NasalWidget::setGeometry: callback error: '" << ex.what() << "'"
);
}
}
//----------------------------------------------------------------------------
void NasalWidget::visibilityChanged(bool visible)
{
try
{
callMethod<void>("visibilityChanged", visible);
}
catch( std::exception const& ex )
{
SG_LOG(
SG_GUI,
SG_WARN,
"NasalWidget::visibilityChanged: callback error: '" << ex.what() << "'"
);
}
}
} // namespace canvas
} // namespace simgear

View File

@@ -1,4 +1,5 @@
///@file Glue for GUI widgets implemented in Nasal space
///@file
/// Glue for GUI widgets implemented in Nasal space.
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//
@@ -31,7 +32,7 @@ namespace canvas
{
/**
* Baseclass/ghost to create widgets with Nasal.
* Base class/ghost to implement gui widgets in Nasal space.
*/
class NasalWidget:
public LayoutItem,
@@ -51,8 +52,6 @@ namespace canvas
~NasalWidget();
virtual void invalidate();
virtual void setGeometry(const SGRecti& geom);
virtual void onRemove();
void setSetGeometryFunc(const SetGeometryFunc& func);
@@ -85,8 +84,6 @@ namespace canvas
void setLayoutMaximumSize(const SGVec2i& s);
virtual bool hasHeightForWidth() const;
virtual int heightForWidth(int w) const;
virtual int minimumHeightForWidth(int w) const;
/**
* @param ns Namespace to register the class interface
@@ -118,6 +115,13 @@ namespace canvas
virtual SGVec2i minimumSizeImpl() const;
virtual SGVec2i maximumSizeImpl() const;
virtual int heightForWidthImpl(int w) const;
virtual int minimumHeightForWidthImpl(int w) const;
virtual void contentsRectChanged(const SGRecti& rect);
virtual void visibilityChanged(bool visible);
};
typedef SGSharedPtr<NasalWidget> NasalWidgetRef;

View File

@@ -1,4 +1,4 @@
///@file Element providing blank space in a layout.
///@file
//
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
//

View File

@@ -23,6 +23,8 @@
#include "NasalWidget.hxx"
#include <simgear/debug/logstream.hxx>
#include <simgear/nasal/cppbind/NasalContext.hxx>
#include <cstdlib>
//------------------------------------------------------------------------------
@@ -62,16 +64,17 @@ class TestWidget:
void setMaxSize(const SGVec2i& size) { _max_size = size; }
void setSizeHint(const SGVec2i& size) { _size_hint = size; }
virtual void setGeometry(const SGRecti& geom) { _geom = geom; }
virtual SGRecti geometry() const { return _geom; }
protected:
SGRecti _geom;
virtual SGVec2i sizeHintImpl() const { return _size_hint; }
virtual SGVec2i minimumSizeImpl() const { return _min_size; }
virtual SGVec2i maximumSizeImpl() const { return _max_size; }
virtual void visibilityChanged(bool visible)
{
if( !visible )
_geometry.set(0, 0, 0, 0);
}
};
class TestWidgetHFW:
@@ -91,12 +94,12 @@ class TestWidgetHFW:
return true;
}
virtual int heightForWidth(int w) const
virtual int heightForWidthImpl(int w) const
{
return _size_hint.x() * _size_hint.y() / w;
}
virtual int minimumHeightForWidth(int w) const
virtual int minimumHeightForWidthImpl(int w) const
{
return _min_size.x() * _min_size.y() / w;
}
@@ -107,45 +110,45 @@ typedef SGSharedPtr<TestWidget> TestWidgetRef;
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( horizontal_layout )
{
sc::BoxLayout box_layout(sc::BoxLayout::BottomToTop);
box_layout.setSpacing(5);
sc::BoxLayoutRef box_layout(new sc::BoxLayout(sc::BoxLayout::BottomToTop));
box_layout->setSpacing(5);
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::BottomToTop);
BOOST_CHECK_EQUAL(box_layout.spacing(), 5);
BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::BottomToTop);
BOOST_CHECK_EQUAL(box_layout->spacing(), 5);
box_layout.setDirection(sc::BoxLayout::LeftToRight);
box_layout.setSpacing(9);
box_layout->setDirection(sc::BoxLayout::LeftToRight);
box_layout->setSpacing(9);
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::LeftToRight);
BOOST_CHECK_EQUAL(box_layout.spacing(), 9);
BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::LeftToRight);
BOOST_CHECK_EQUAL(box_layout->spacing(), 9);
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
SGVec2i(16, 16),
SGVec2i(16, 16) ) );
box_layout.addItem(fixed_size_widget);
box_layout->addItem(fixed_size_widget);
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(16, 16));
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(16, 16));
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(16, 16));
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(16, 16));
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(16, 16));
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(16, 16));
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32),
SGVec2i(256, 64) ) );
box_layout.addItem(limited_resize_widget);
box_layout->addItem(limited_resize_widget);
// Combined sizes of both widget plus the padding between them
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(41, 16));
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(57, 32));
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(281, 64));
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(41, 16));
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(57, 32));
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(281, 64));
// Test with different spacing/padding
box_layout.setSpacing(5);
box_layout->setSpacing(5);
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(37, 16));
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(53, 32));
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(277, 64));
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(37, 16));
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(53, 32));
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(277, 64));
box_layout.setGeometry(SGRecti(0, 0, 128, 32));
box_layout->setGeometry(SGRecti(0, 0, 128, 32));
// Fixed size for first widget and remaining space goes to second widget
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
@@ -154,12 +157,12 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
TestWidgetRef stretch_widget( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32),
SGVec2i(128, 32) ) );
box_layout.addItem(stretch_widget, 1);
box_layout.update();
box_layout->addItem(stretch_widget, 1);
box_layout->update();
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(58, 16));
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(90, 32));
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(410, 64));
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(58, 16));
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(90, 32));
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(410, 64));
// Due to the stretch factor only the last widget gets additional space. All
// other widgets get the preferred size.
@@ -169,63 +172,101 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
// Test stretch factor
TestWidgetRef fast_stretch( new TestWidget(*stretch_widget) );
sc::BoxLayout box_layout_stretch(sc::BoxLayout::LeftToRight);
sc::BoxLayoutRef box_layout_stretch(
new sc::BoxLayout(sc::BoxLayout::LeftToRight)
);
box_layout_stretch.addItem(stretch_widget, 1);
box_layout_stretch.addItem(fast_stretch, 2);
box_layout_stretch->addItem(stretch_widget, 1);
box_layout_stretch->addItem(fast_stretch, 2);
box_layout_stretch.setGeometry(SGRecti(0,0,128,32));
box_layout_stretch->setGeometry(SGRecti(0,0,128,32));
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 41, 32));
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(46, 0, 82, 32));
box_layout_stretch.setGeometry(SGRecti(0,0,256,32));
box_layout_stretch->setGeometry(SGRecti(0,0,256,32));
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 123, 32));
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
// Test superflous space to padding
box_layout_stretch.setGeometry(SGRecti(0,0,512,32));
box_layout_stretch->setGeometry(SGRecti(0,0,512,32));
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(83, 0, 128, 32));
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(300, 0, 128, 32));
// Test more space then preferred, but less than maximum
{
sc::HBoxLayout hbox;
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32),
SGVec2i(9999, 32) ) ),
w2( new TestWidget(*w1) );
// ...and now with alignment
//
// All widgets without alignment get their maximum space and the remaining
// space is equally distributed to the remaining items. All items with
// alignment are set to their size hint and positioned according to their
// alignment.
hbox.addItem(w1);
hbox.addItem(w2);
// Left widget: size hint and positioned on the left
// Right widget: maximum size and positioned on the right
stretch_widget->setAlignment(sc::AlignLeft);
box_layout_stretch->update();
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
hbox.setGeometry( SGRecti(0, 0, 256, 32) );
// Left widget: align right
stretch_widget->setAlignment(sc::AlignRight);
box_layout_stretch->update();
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(347, 0, 32, 32));
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
// Left widget: size hint and positioned on the right
// Right widget: size hint and positioned on the left of the right half
fast_stretch->setAlignment(sc::AlignLeft);
box_layout_stretch->update();
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(221, 0, 32, 32));
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 0, 32, 32));
hbox.setStretch(0, 1);
hbox.setStretch(1, 1);
// Also check vertical alignment
stretch_widget->setAlignment(sc::AlignLeft | sc::AlignTop);
fast_stretch->setAlignment(sc::AlignLeft | sc::AlignBottom);
box_layout_stretch->setGeometry(SGRecti(0,0,512,64));
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 32, 32, 32));
}
BOOST_CHECK_EQUAL(hbox.stretch(0), 1);
BOOST_CHECK_EQUAL(hbox.stretch(1), 1);
//------------------------------------------------------------------------------
// Test more space then preferred, but less than maximum
BOOST_AUTO_TEST_CASE( hbox_pref_to_max )
{
sc::BoxLayoutRef hbox(new sc::HBoxLayout());
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32),
SGVec2i(9999, 32) ) ),
w2( new TestWidget(*w1) );
hbox.update();
hbox->addItem(w1);
hbox->addItem(w2);
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
hbox->setGeometry( SGRecti(0, 0, 256, 32) );
BOOST_REQUIRE( hbox.setStretchFactor(w1, 2) );
BOOST_REQUIRE( hbox.setStretchFactor(w2, 3) );
BOOST_CHECK_EQUAL(hbox.stretch(0), 2);
BOOST_CHECK_EQUAL(hbox.stretch(1), 3);
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
hbox.removeItem(w1);
hbox->setStretch(0, 1);
hbox->setStretch(1, 1);
BOOST_CHECK( !hbox.setStretchFactor(w1, 0) );
}
BOOST_CHECK_EQUAL(hbox->stretch(0), 1);
BOOST_CHECK_EQUAL(hbox->stretch(1), 1);
hbox->update();
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
BOOST_REQUIRE( hbox->setStretchFactor(w1, 2) );
BOOST_REQUIRE( hbox->setStretchFactor(w2, 3) );
BOOST_CHECK_EQUAL(hbox->stretch(0), 2);
BOOST_CHECK_EQUAL(hbox->stretch(1), 3);
hbox->removeItem(w1);
BOOST_CHECK( !hbox->setStretchFactor(w1, 0) );
}
//------------------------------------------------------------------------------
@@ -295,35 +336,203 @@ BOOST_AUTO_TEST_CASE( vertical_layout)
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( boxlayout_insert_remove )
{
sc::HBoxLayout hbox;
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
BOOST_CHECK_EQUAL(hbox.count(), 0);
BOOST_CHECK(!hbox.itemAt(0));
BOOST_CHECK(!hbox.takeAt(0));
BOOST_CHECK_EQUAL(hbox->count(), 0);
BOOST_CHECK(!hbox->itemAt(0));
BOOST_CHECK(!hbox->takeAt(0));
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32),
SGVec2i(9999, 32) ) ),
w2( new TestWidget(*w1) );
hbox.addItem(w1);
BOOST_CHECK_EQUAL(hbox.count(), 1);
BOOST_CHECK_EQUAL(hbox.itemAt(0), w1);
hbox->addItem(w1);
BOOST_CHECK_EQUAL(hbox->count(), 1);
BOOST_CHECK_EQUAL(hbox->itemAt(0), w1);
BOOST_CHECK_EQUAL(w1->getParent(), hbox);
hbox.insertItem(0, w2);
BOOST_CHECK_EQUAL(hbox.count(), 2);
BOOST_CHECK_EQUAL(hbox.itemAt(0), w2);
BOOST_CHECK_EQUAL(hbox.itemAt(1), w1);
hbox->insertItem(0, w2);
BOOST_CHECK_EQUAL(hbox->count(), 2);
BOOST_CHECK_EQUAL(hbox->itemAt(0), w2);
BOOST_CHECK_EQUAL(hbox->itemAt(1), w1);
BOOST_CHECK_EQUAL(w2->getParent(), hbox);
hbox.removeItem(w2);
BOOST_CHECK_EQUAL(hbox.count(), 1);
BOOST_CHECK_EQUAL(hbox.itemAt(0), w1);
hbox->removeItem(w2);
BOOST_CHECK_EQUAL(hbox->count(), 1);
BOOST_CHECK_EQUAL(hbox->itemAt(0), w1);
BOOST_CHECK( !w2->getParent() );
hbox.addItem(w2);
BOOST_CHECK_EQUAL(hbox.count(), 2);
hbox->addItem(w2);
BOOST_CHECK_EQUAL(hbox->count(), 2);
BOOST_CHECK_EQUAL(w2->getParent(), hbox);
hbox.clear();
BOOST_CHECK_EQUAL(hbox.count(), 0);
hbox->clear();
BOOST_CHECK_EQUAL(hbox->count(), 0);
BOOST_CHECK( !w1->getParent() );
BOOST_CHECK( !w2->getParent() );
}
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( boxlayout_visibility )
{
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32) ) ),
w2( new TestWidget(*w1) ),
w3( new TestWidget(*w1) );
hbox->addItem(w1);
hbox->addItem(w2);
hbox->addItem(w3);
BOOST_REQUIRE_EQUAL(hbox->sizeHint().x(), 3 * 32 + 2 * hbox->spacing());
hbox->setGeometry(SGRecti(0, 0, 69, 32));
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 20, 32));
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
w2->setVisible(false);
BOOST_REQUIRE(hbox->isVisible());
BOOST_REQUIRE(w1->isVisible());
BOOST_REQUIRE(!w2->isVisible());
BOOST_REQUIRE(w2->isExplicitlyHidden());
BOOST_REQUIRE(w3->isVisible());
BOOST_CHECK_EQUAL(hbox->sizeHint().x(), 2 * 32 + 1 * hbox->spacing());
hbox->update();
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 32, 32));
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 0, 0, 0));
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(37, 0, 32, 32));
hbox->setVisible(false);
BOOST_REQUIRE(!hbox->isVisible());
BOOST_REQUIRE(hbox->isExplicitlyHidden());
BOOST_REQUIRE(!w1->isVisible());
BOOST_REQUIRE(!w1->isExplicitlyHidden());
BOOST_REQUIRE(!w2->isVisible());
BOOST_REQUIRE(w2->isExplicitlyHidden());
BOOST_REQUIRE(!w3->isVisible());
BOOST_REQUIRE(!w3->isExplicitlyHidden());
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 0, 0));
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 0, 0, 0));
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(0, 0, 0, 0));
w2->setVisible(true);
BOOST_REQUIRE(!w2->isVisible());
BOOST_REQUIRE(!w2->isExplicitlyHidden());
hbox->setVisible(true);
BOOST_REQUIRE(hbox->isVisible());
BOOST_REQUIRE(w1->isVisible());
BOOST_REQUIRE(w2->isVisible());
BOOST_REQUIRE(w3->isVisible());
hbox->update();
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 20, 32));
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
}
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( boxlayout_contents_margins )
{
sc::Margins m;
BOOST_REQUIRE(m.isNull());
m = sc::Margins(5);
BOOST_REQUIRE_EQUAL(m.l, 5);
BOOST_REQUIRE_EQUAL(m.t, 5);
BOOST_REQUIRE_EQUAL(m.r, 5);
BOOST_REQUIRE_EQUAL(m.b, 5);
m = sc::Margins(6, 7);
BOOST_REQUIRE_EQUAL(m.l, 6);
BOOST_REQUIRE_EQUAL(m.t, 7);
BOOST_REQUIRE_EQUAL(m.r, 6);
BOOST_REQUIRE_EQUAL(m.b, 7);
BOOST_REQUIRE_EQUAL(m.horiz(), 12);
BOOST_REQUIRE_EQUAL(m.vert(), 14);
BOOST_REQUIRE(!m.isNull());
m = sc::Margins(1, 2, 3, 4);
BOOST_REQUIRE_EQUAL(m.l, 1);
BOOST_REQUIRE_EQUAL(m.t, 2);
BOOST_REQUIRE_EQUAL(m.r, 3);
BOOST_REQUIRE_EQUAL(m.b, 4);
BOOST_REQUIRE_EQUAL(m.horiz(), 4);
BOOST_REQUIRE_EQUAL(m.vert(), 6);
BOOST_REQUIRE_EQUAL(m.size(), SGVec2i(4, 6));
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
hbox->setContentsMargins(5, 10, 15, 20);
BOOST_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(20, 30));
BOOST_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(20, 30));
BOOST_CHECK_EQUAL(hbox->maximumSize(), SGVec2i(20, 30));
hbox->setGeometry(SGRecti(0, 0, 30, 40));
BOOST_CHECK_EQUAL(hbox->geometry(), SGRecti(0, 0, 30, 40));
BOOST_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 10, 10));
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32) ) ),
w2( new TestWidget(*w1) ),
w3( new TestWidget(*w1) );
w1->setContentsMargin(5);
w2->setContentsMargin(6);
w3->setContentsMargin(7);
BOOST_CHECK_EQUAL(w1->minimumSize(), SGVec2i(26, 26));
BOOST_CHECK_EQUAL(w1->sizeHint(), SGVec2i(42, 42));
BOOST_CHECK_EQUAL(w1->maximumSize(), sc::LayoutItem::MAX_SIZE);
BOOST_CHECK_EQUAL(w2->minimumSize(), SGVec2i(28, 28));
BOOST_CHECK_EQUAL(w2->sizeHint(), SGVec2i(44, 44));
BOOST_CHECK_EQUAL(w2->maximumSize(), sc::LayoutItem::MAX_SIZE);
BOOST_CHECK_EQUAL(w3->minimumSize(), SGVec2i(30, 30));
BOOST_CHECK_EQUAL(w3->sizeHint(), SGVec2i(46, 46));
BOOST_CHECK_EQUAL(w3->maximumSize(), sc::LayoutItem::MAX_SIZE);
hbox->addItem(w1);
hbox->addItem(w2);
hbox->addItem(w3);
BOOST_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(114, 60));
BOOST_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(162, 76));
BOOST_CHECK_EQUAL(hbox->maximumSize(), sc::LayoutItem::MAX_SIZE);
hbox->setGeometry(SGRecti(0, 0, hbox->sizeHint().x(), hbox->sizeHint().y()));
BOOST_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 142, 46));
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(5, 10, 42, 46));
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(52, 10, 44, 46));
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(101, 10, 46, 46));
BOOST_CHECK_EQUAL(w1->contentsRect(), SGRecti(10, 15, 32, 36));
BOOST_CHECK_EQUAL(w2->contentsRect(), SGRecti(58, 16, 32, 34));
BOOST_CHECK_EQUAL(w3->contentsRect(), SGRecti(108, 17, 32, 32));
}
//------------------------------------------------------------------------------
@@ -417,13 +626,77 @@ BOOST_AUTO_TEST_CASE( boxlayout_hfw )
BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
}
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( item_alignment_rect )
{
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
SGVec2i(32, 32) ) );
const SGRecti r(10, 10, 64, 64);
// Default: AlignFill -> fill up to maximum size
BOOST_CHECK_EQUAL(w1->alignmentRect(r), r);
// Horizontal
// AlignLeft -> width from size hint, positioned on the left
w1->setAlignment(sc::AlignLeft);
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 32, 64));
// AlignRight -> width from size hint, positioned on the left
w1->setAlignment(sc::AlignRight);
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(42, 10, 32, 64));
// AlignHCenter -> width from size hint, positioned in the center
w1->setAlignment(sc::AlignHCenter);
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 10, 32, 64));
// Vertical
// AlignTop -> height from size hint, positioned on the top
w1->setAlignment(sc::AlignTop);
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 64, 32));
// AlignBottom -> height from size hint, positioned on the bottom
w1->setAlignment(sc::AlignBottom);
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 42, 64, 32));
// AlignVCenter -> height from size hint, positioned in the center
w1->setAlignment(sc::AlignVCenter);
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 26, 64, 32));
// Vertical + Horizontal
w1->setAlignment(sc::AlignCenter);
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 26, 32, 32));
}
//------------------------------------------------------------------------------
// TODO extend to_nasal_helper for automatic argument conversion
static naRef f_Widget_visibilityChanged(nasal::CallContext ctx)
{
sc::NasalWidget* w = ctx.from_nasal<sc::NasalWidget*>(ctx.me);
if( !ctx.requireArg<bool>(0) )
w->setGeometry(SGRecti(0, 0, -1, -1));
return naNil();
}
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( nasal_widget )
{
naContext c = naNewContext();
naRef me = naNewHash(c);
nasal::Context c;
nasal::Hash globals = c.newHash();
sc::NasalWidgetRef w( new sc::NasalWidget(me) );
nasal::Object::setupGhost();
nasal::Ghost<sc::LayoutItemRef>::init("LayoutItem");
sc::NasalWidget::setupGhost(globals);
nasal::Hash me = c.newHash();
me.set("visibilityChanged", &f_Widget_visibilityChanged);
sc::NasalWidgetRef w( new sc::NasalWidget(me.get_naRef()) );
// Default layout sizes (no user set values)
BOOST_CHECK_EQUAL(w->minimumSize(), SGVec2i(16, 16));
@@ -457,5 +730,6 @@ BOOST_AUTO_TEST_CASE( nasal_widget )
BOOST_CHECK_EQUAL(w->sizeHint(), SGVec2i(3, 22));
BOOST_CHECK_EQUAL(w->maximumSize(), SGVec2i(4, 23));
naFreeContext(c);
w->setVisible(false);
BOOST_CHECK_EQUAL(w->geometry(), SGRecti(0, 0, -1, -1));
}

View File

@@ -190,6 +190,12 @@ inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
# define DEPRECATED
#endif
#if defined(__clang__)
# define SG_NO_RETURN [[noreturn]]
#else
# define SG_NO_RETURN
#endif
//
// No user modifiable definitions beyond here.
//

View File

@@ -26,6 +26,8 @@
#include <simgear/sg_inlines.h>
#include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGGuard.hxx>
#include <cstdlib> // for malloc
namespace simgear
{

View File

@@ -32,7 +32,8 @@ typedef enum {
SG_SOUND = 0x00200000,
SG_NAVAID = 0x00400000,
SG_GUI = 0x00800000,
SG_UNDEFD = 0x01000000, // For range checking
SG_TERRASYNC = 0x01000000,
SG_UNDEFD = 0x02000000, // For range checking
SG_ALL = 0xFFFFFFFF
} sgDebugClass;

View File

@@ -71,6 +71,7 @@ const char* debugClassToString(sgDebugClass c)
case SG_SOUND: return "sound";
case SG_NAVAID: return "navaid";
case SG_GUI: return "gui";
case SG_TERRASYNC: return "terrasync";
default: return "unknown";
}
}

View File

@@ -37,7 +37,7 @@
* Build a new OSG object from osgParticle.
*/
SGPrecipitation::SGPrecipitation() :
_freeze(false), _enabled(true), _snow_intensity(0.0), _rain_intensity(0.0), _clip_distance(5.0)
_freeze(false), _enabled(true), _droplet_external(false), _snow_intensity(0.0), _rain_intensity(0.0), _clip_distance(5.0), _rain_droplet_size(0.0), _snow_flake_size(0.0), _illumination(1.0)
{
_precipitationEffect = new osgParticle::PrecipitationEffect;
}
@@ -47,6 +47,11 @@ void SGPrecipitation::setEnabled( bool value )
_enabled = value;
}
void SGPrecipitation::setDropletExternal( bool value )
{
_droplet_external = value;
}
bool SGPrecipitation::getEnabled() const
{
return _enabled;
@@ -66,7 +71,7 @@ osg::Group* SGPrecipitation::build(void)
_precipitationEffect->rain(0);
if (_clip_distance!=0.0)
{
{
osg::ref_ptr<osg::ClipNode> clipNode = new osg::ClipNode;
clipNode->addClipPlane( new osg::ClipPlane( 0 ) );
clipNode->getClipPlane(0)->setClipPlane( 0.0, 0.0, -1.0, -_clip_distance );
@@ -119,17 +124,72 @@ void SGPrecipitation::setRainIntensity(float intensity)
this->_rain_intensity = intensity;
}
/**
* @brief Define the rain droplet size
*
* This function permits you to define and change the rain droplet size
* which is used if external droplet size control is enabled
*/
/**
void SGPrecipitation::setRainDropletSize(float size)
{
_rain_droplet_size = size;
}
/**
* @brief Define the illumination multiplier
*
* This function permits you to define and change the rain droplet size
* which is used if external droplet size control is enabled
*/
void SGPrecipitation::setIllumination(float illumination)
{
_illumination = illumination;
}
/**
* @brief Define the snow flake size
*
* This function permits you to define and change the snow flake size
* which is used if external droplet size control is enabled
*/
void SGPrecipitation::setSnowFlakeSize(float size)
{
_snow_flake_size = size;
}
/**
* @brief Define the rain droplet size
*
* This function permits you to define and change the rain droplet size
* which is used if external droplet size control is enabled
*/
void SGPrecipitation::setClipDistance(float distance)
{
_clip_distance = distance;
}
/**
* @brief Freeze the rain to snow
*
* @param freeze Boolean
*
*
* @param freeze Boolean
*
* This function permits you to turn off the rain to snow.
*/
void SGPrecipitation::setFreezing(bool freeze)
{
if ((this->_freeze)&&(!freeze)) // rain freezes suddenly, so we need to unfreeze
{
this->_rain_intensity = this->_snow_intensity;
this->_snow_intensity = 0.0;
}
this->_freeze = freeze;
}
@@ -137,7 +197,7 @@ void SGPrecipitation::setFreezing(bool freeze)
* @brief Define the wind direction and speed
*
* This function permits you to define and change the wind direction
*
*
* After apply the MatrixTransform to the osg::Precipitation object,
* x points full south... From wind heading and speed, we can calculate
* the wind vector.
@@ -169,34 +229,74 @@ void SGPrecipitation::setWindProperty(double heading, double speed)
bool SGPrecipitation::update(void)
{
if (this->_freeze) {
if (this->_rain_intensity > 0)
this->_snow_intensity = this->_rain_intensity;
if (this->_rain_intensity > 0) {
this->_snow_intensity = this->_rain_intensity;
}
}
if (_enabled && this->_snow_intensity > 0) {
_precipitationEffect->setWind(_wind_vec);
_precipitationEffect->setParticleSpeed( -0.75f - 0.25f*_snow_intensity);
_precipitationEffect->setParticleSize(0.02f + 0.03f*_snow_intensity);
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 7.2f);
if(_droplet_external)
{
if ((_freeze) && (_rain_droplet_size > 0.03)) // this is hail or sleet
{
_precipitationEffect->setParticleSize(_rain_droplet_size*1.5f);
_precipitationEffect->setParticleSpeed( -1.0f - 22.36f*sqrtf(_rain_droplet_size));
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 4.8f);
}
else if (_freeze) // this is snow from frozen small rain droplets
{
_precipitationEffect->setParticleSize(_rain_droplet_size*1.3f);
_precipitationEffect->setParticleSpeed( -0.75f - 0.25f*_snow_intensity);
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 10.0f);
}
else // this was snow in the first place
{
_precipitationEffect->setParticleSize(_snow_flake_size);
_precipitationEffect->setParticleSpeed( -0.75f - 0.25f*_snow_intensity);
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 7.2f);
}
}
else
{
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 7.2f);
_precipitationEffect->setParticleSize(0.02f + 0.03f*_snow_intensity);
_precipitationEffect->setParticleSpeed( -0.75f - 0.25f*_snow_intensity);
}
_precipitationEffect->setCellSize(osg::Vec3(5.0f / (0.25f+_snow_intensity), 5.0f / (0.25f+_snow_intensity), 5.0f));
_precipitationEffect->setNearTransition(25.f);
_precipitationEffect->setFarTransition(100.0f - 60.0f*sqrtf(_snow_intensity));
_precipitationEffect->setParticleColor(osg::Vec4(0.85, 0.85, 0.85, 1.0) - osg::Vec4(0.1, 0.1, 0.1, 1.0) * _snow_intensity);
_precipitationEffect->setParticleColor(osg::Vec4(0.85 * _illumination, 0.85 * _illumination, 0.85 * _illumination, 1.0) - osg::Vec4(0.1, 0.1, 0.1, 1.0) * _snow_intensity);
} else if (_enabled && this->_rain_intensity > 0) {
_precipitationEffect->setWind(_wind_vec);
_precipitationEffect->setParticleSpeed( -2.0f + -5.0f*_rain_intensity);
if(_droplet_external)
{
_precipitationEffect->setParticleSize(_rain_droplet_size);
_precipitationEffect->setParticleSpeed( -1.0f - 22.36f*sqrtf(_rain_droplet_size));
}
else
{
_precipitationEffect->setParticleSize(0.01 + 0.02*_rain_intensity);
_precipitationEffect->setParticleSpeed( -2.0f + -5.0f*_rain_intensity);
}
_precipitationEffect->setParticleSize(0.01 + 0.02*_rain_intensity);
_precipitationEffect->setMaximumParticleDensity(_rain_intensity * 7.5f);
_precipitationEffect->setCellSize(osg::Vec3(5.0f / (0.25f+_rain_intensity), 5.0f / (0.25f+_rain_intensity), 5.0f));
_precipitationEffect->setNearTransition(25.f);
_precipitationEffect->setFarTransition(100.0f - 60.0f*sqrtf(_rain_intensity));
_precipitationEffect->setParticleColor( osg::Vec4(0x7A, 0xCE, 0xFF, 0x80));
_precipitationEffect->setParticleColor( osg::Vec4(0.64 * _illumination, 0.64 * _illumination, 0.64 * _illumination, 0.5));
} else {
_precipitationEffect->snow(0);
_precipitationEffect->rain(0);

View File

@@ -37,10 +37,14 @@ class SGPrecipitation : public osg::Referenced
private:
bool _freeze;
bool _enabled;
bool _droplet_external;
float _snow_intensity;
float _rain_intensity;
float _clip_distance;
float _rain_droplet_size;
float _snow_flake_size;
float _illumination;
osg::Vec3 _wind_vec;
@@ -54,8 +58,13 @@ public:
void setWindProperty(double, double);
void setFreezing(bool);
void setDropletExternal(bool);
void setRainIntensity(float);
void setSnowIntensity(float);
void setRainDropletSize(float);
void setSnowFlakeSize(float);
void setIllumination(float);
void setClipDistance(float);
void setEnabled( bool );
bool getEnabled() const;

View File

@@ -22,7 +22,7 @@
* $Id$
**************************************************************************/
#include <math.h>
#include <cmath>
#include "jupiter.hxx"

View File

@@ -22,7 +22,7 @@
* $Id$
**************************************************************************/
#include <math.h>
#include <cmath>
#include "mars.hxx"

View File

@@ -22,7 +22,7 @@
* $Id$
**************************************************************************/
#include <math.h>
#include <cmath>
#include "mercury.hxx"

View File

@@ -25,7 +25,7 @@
#ifdef __BORLANDC__
# define exception c_exception
#endif
#include <math.h>
#include <cmath>
#include "neptune.hxx"

View File

@@ -22,7 +22,7 @@
* $Id$
**************************************************************************/
#include <math.h>
#include <cmath>
#include "saturn.hxx"

View File

@@ -22,7 +22,7 @@
* $Id$
**************************************************************************/
#include <math.h>
#include <cmath>
#include <simgear/debug/logstream.hxx>

View File

@@ -41,7 +41,7 @@ public:
bool load( const SGPath& path );
// stars
inline int getNumStars() const { return _stars.size(); }
inline int getNumStars() const { return static_cast<int>(_stars.size()); }
inline SGVec3d *getStars() { return &(_stars[0]); }
private:

View File

@@ -22,7 +22,7 @@
* $Id$
**************************************************************************/
#include <math.h>
#include <cmath>
#include "uranus.hxx"

View File

@@ -22,7 +22,7 @@
* $Id$
**************************************************************************/
#include <math.h>
#include <cmath>
#include "venus.hxx"

View File

@@ -18,7 +18,6 @@ set(HEADERS
HTTPFileRequest.hxx
HTTPMemoryRequest.hxx
HTTPRequest.hxx
HTTPContentDecode.hxx
DAVMultiStatus.hxx
SVNRepository.hxx
SVNDirectory.hxx
@@ -41,13 +40,17 @@ set(SOURCES
HTTPFileRequest.cxx
HTTPMemoryRequest.cxx
HTTPRequest.cxx
HTTPContentDecode.cxx
DAVMultiStatus.cxx
SVNRepository.cxx
SVNDirectory.cxx
SVNReportParser.cxx
)
if (NOT ENABLE_CURL)
list(APPEND SOURCES HTTPContentDecode.cxx)
list(APPEND HEADERS HTTPContentDecode.hxx)
endif()
simgear_component(io io "${SOURCES}" "${HEADERS}")
if(ENABLE_TESTS)
@@ -70,8 +73,8 @@ add_executable(decode_binobj decode_binobj.cxx)
target_link_libraries(decode_binobj ${TEST_LIBS})
add_executable(test_binobj test_binobj.cxx)
target_link_libraries(test_binobj ${TEST_LIBS})
target_link_libraries(test_binobj ${TEST_LIBS})
add_test(binobj ${EXECUTABLE_OUTPUT_PATH}/test_binobj)
endif(ENABLE_TESTS)

View File

@@ -193,7 +193,7 @@ public:
{
if (tagStack.empty()) {
if (strcmp(name, DAV_MULTISTATUS_TAG)) {
SG_LOG(SG_IO, SG_WARN, "root element is not " <<
SG_LOG(SG_TERRASYNC, SG_WARN, "root element is not " <<
DAV_MULTISTATUS_TAG << ", got:" << name);
} else {
@@ -202,7 +202,7 @@ public:
// not at the root element
if (tagStack.back() == DAV_MULTISTATUS_TAG) {
if (strcmp(name, DAV_RESPONSE_TAG)) {
SG_LOG(SG_IO, SG_WARN, "multistatus child is not response: saw:"
SG_LOG(SG_TERRASYNC, SG_WARN, "multistatus child is not response: saw:"
<< name);
}
}
@@ -362,7 +362,7 @@ void DAVMultiStatus::parseXML(const char* data, int size)
}
if (!XML_Parse(_d->xmlParser, data, size, false)) {
SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
SG_LOG(SG_TERRASYNC, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
<< " at line:" << XML_GetCurrentLineNumber(_d->xmlParser)
<< " column " << XML_GetCurrentColumnNumber(_d->xmlParser));
@@ -376,7 +376,7 @@ void DAVMultiStatus::finishParse()
{
if (_d->parserInited) {
if (!XML_Parse(_d->xmlParser, NULL, 0, true)) {
SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
SG_LOG(SG_TERRASYNC, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
<< " at line:" << XML_GetCurrentLineNumber(_d->xmlParser)
<< " column " << XML_GetCurrentColumnNumber(_d->xmlParser));
_d->valid = false;

File diff suppressed because it is too large Load Diff

View File

@@ -38,15 +38,15 @@ namespace HTTP
// forward decls
class Connection;
class Client
{
public:
Client();
~Client();
void update(int waitTimeout = 0);
void makeRequest(const Request_ptr& r);
/**
@@ -68,44 +68,51 @@ public:
void setUserAgent(const std::string& ua);
void setProxy(const std::string& proxy, int port, const std::string& auth = "");
/**
* Specify the maximum permitted simultaneous connections
* (default value is 1)
*/
void setMaxConnections(unsigned int maxCons);
const std::string& userAgent() const;
const std::string& proxyHost() const;
const std::string& proxyAuth() const;
/**
* predicate, check if at least one connection is active, with at
* least one request active or queued.
*/
bool hasActiveRequests() const;
/**
* crude tracking of bytes-per-second transferred over the socket.
* suitable for user feedback and rough profiling, nothing more.
*/
unsigned int transferRateBytesPerSec() const;
/**
* total bytes downloaded by this HTTP client, for bandwidth usage
* monitoring
*/
uint64_t totalBytesDownloaded() const;
void debugDumpRequests();
private:
// libCurl callbacks
static size_t requestWriteCallback(char *ptr, size_t size, size_t nmemb, void *userdata);
static size_t requestReadCallback(char *ptr, size_t size, size_t nmemb, void *userdata);
static size_t requestHeaderCallback(char *buffer, size_t size, size_t nitems, void *userdata);
void requestFinished(Connection* con);
void receivedBytes(unsigned int count);
friend class Connection;
friend class Request;
class ClientPrivate;
std::auto_ptr<ClientPrivate> d;
};

View File

@@ -1,4 +1,4 @@
///@file HTTP request writing response to a file.
///@file
//
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
//
@@ -27,6 +27,9 @@ namespace simgear
namespace HTTP
{
/**
* HTTP request writing response to a file.
*/
class FileRequest:
public Request
{

View File

@@ -1,4 +1,4 @@
///@file HTTP request keeping response in memory.
///@file
//
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
//
@@ -27,6 +27,9 @@ namespace simgear
namespace HTTP
{
/**
* HTTP request keeping response in memory.
*/
class MemoryRequest:
public Request
{

View File

@@ -1,3 +1,20 @@
// Copyright (C) 2011 James Turner <zakalawe@mac.com>
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
//
// 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 Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "HTTPRequest.hxx"
#include <simgear/compiler.h>
@@ -116,19 +133,25 @@ void Request::responseStart(const std::string& r)
const int maxSplit = 2; // HTTP/1.1 nnn reason-string
string_list parts = strutils::split(r, NULL, maxSplit);
if (parts.size() != 3) {
throw sg_io_exception("bad HTTP response");
throw sg_io_exception("bad HTTP response:" + r);
}
_responseVersion = decodeHTTPVersion(parts[0]);
_responseStatus = strutils::to_int(parts[1]);
_responseReason = parts[2];
setReadyState(STATUS_RECEIVED);
}
//------------------------------------------------------------------------------
void Request::responseHeader(const std::string& key, const std::string& value)
{
if( key == "connection" )
if( key == "connection" ) {
_willClose = (value.find("close") != std::string::npos);
} else if (key == "content-length") {
int sz = strutils::to_int(value);
setResponseLength(sz);
}
_responseHeaders[key] = value;
}
@@ -190,7 +213,7 @@ std::string Request::scheme() const
if (firstColon > 0) {
return url().substr(0, firstColon);
}
return ""; // couldn't parse scheme
}
@@ -202,20 +225,20 @@ std::string Request::path() const
if (schemeEnd < 0) {
return ""; // couldn't parse scheme
}
int hostEnd = u.find('/', schemeEnd + 3);
if (hostEnd < 0) {
// couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
// fixup to root resource path: '/'
return "/";
// couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
// fixup to root resource path: '/'
return "/";
}
int query = u.find('?', hostEnd + 1);
if (query < 0) {
// all remainder of URL is path
return u.substr(hostEnd);
}
return u.substr(hostEnd, query - hostEnd);
}
@@ -227,7 +250,7 @@ std::string Request::query() const
if (query < 0) {
return ""; //no query string found
}
return u.substr(query); //includes question mark
}
@@ -302,6 +325,7 @@ unsigned int Request::responseLength() const
//------------------------------------------------------------------------------
void Request::setFailure(int code, const std::string& reason)
{
SG_LOG(SG_IO, SG_WARN, "HTTP request: set failure:" << code << " reason " << reason);
_responseStatus = code;
_responseReason = reason;

View File

@@ -1,3 +1,22 @@
///@file
//
// Copyright (C) 2011 James Turner <zakalawe@mac.com>
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
//
// 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 Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef SG_HTTP_REQUEST_HXX
#define SG_HTTP_REQUEST_HXX
@@ -18,6 +37,9 @@ namespace simgear
namespace HTTP
{
/**
* Base class for HTTP request (and answer).
*/
class Request:
public SGReferenced
{
@@ -28,6 +50,7 @@ public:
{
UNSENT = 0,
OPENED,
STATUS_RECEIVED,
HEADERS_RECEIVED,
LOADING,
DONE,
@@ -102,19 +125,19 @@ public:
void setBodyData( const SGPropertyNode* data );
virtual void setUrl(const std::string& url);
virtual std::string method() const
{ return _method; }
virtual std::string url() const
{ return _url; }
virtual std::string scheme() const;
virtual std::string path() const;
virtual std::string host() const;
virtual std::string hostAndPort() const;
virtual unsigned short port() const;
virtual std::string query() const;
StringMap const& responseHeaders() const
{ return _responseHeaders; }
@@ -122,13 +145,13 @@ public:
virtual int responseCode() const
{ return _responseStatus; }
virtual std::string responseReason() const
{ return _responseReason; }
void setResponseLength(unsigned int l);
virtual unsigned int responseLength() const;
/**
* Check if request contains body data.
*/
@@ -143,32 +166,32 @@ public:
* Retrieve the size of the request body.
*/
virtual size_t bodyLength() const;
/**
* Retrieve the body data bytes. Will be passed the maximum body bytes
* to return in the buffer, and must return the actual number
* of bytes written.
* of bytes written.
*/
virtual size_t getBodyData(char* s, size_t offset, size_t max_count) const;
/**
* running total of body bytes received so far. Can be used
* to generate a completion percentage, if the response length is
* known.
* known.
*/
unsigned int responseBytesReceived() const
{ return _receivedBodyBytes; }
enum HTTPVersion {
HTTP_VERSION_UNKNOWN = 0,
HTTP_0_x, // 0.9 or similar
HTTP_1_0,
HTTP_1_1
};
HTTPVersion responseVersion() const
{ return _responseVersion; }
ReadyState readyState() const { return _ready_state; }
/**
@@ -204,7 +227,7 @@ private:
friend class Client;
friend class Connection;
friend class ContentDecoder;
Request(const Request&); // = delete;
Request& operator=(const Request&); // = delete;

View File

@@ -96,14 +96,14 @@ void SVNDirectory::parseCache()
LineState lineState = LINESTATE_HREF;
std::ifstream file(p.c_str());
if (!file.is_open()) {
SG_LOG(SG_IO, SG_WARN, "unable to open cache file for reading:" << p);
SG_LOG(SG_TERRASYNC, SG_WARN, "unable to open cache file for reading:" << p);
return;
}
bool doneSelf = false;
file.getline(href, 1024);
if (strcmp(CACHE_VERSION_4_TOKEN, href)) {
SG_LOG(SG_IO, SG_WARN, "invalid cache file [missing header token]:" << p << " '" << href << "'");
SG_LOG(SG_TERRASYNC, SG_WARN, "invalid cache file [missing header token]:" << p << " '" << href << "'");
return;
}
@@ -183,7 +183,7 @@ void SVNDirectory::writeCache()
void SVNDirectory::setBaseUrl(const string& url)
{
if (_parent) {
SG_LOG(SG_IO, SG_ALERT, "setting base URL on non-root directory " << url);
SG_LOG(SG_TERRASYNC, SG_ALERT, "setting base URL on non-root directory " << url);
return;
}
@@ -239,7 +239,6 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
{
DAVResource* child = dav->childWithName(nm);
if (!child) {
// std::cerr << "ZZZ: deleteChildByName: unknown:" << nm << std::endl;
return;
}
@@ -247,17 +246,24 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
if (child->isCollection()) {
Dir d(path);
d.remove(true);
bool ok = d.remove(true);
if (!ok) {
SG_LOG(SG_TERRASYNC, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove dir:"
<< nm << " at path:\n\t" << path);
}
DirectoryList::iterator it = findChildDir(nm);
if (it != _children.end()) {
SVNDirectory* c = *it;
// std::cout << "YYY: deleting SVNDirectory for:" << nm << std::endl;
delete c;
_children.erase(it);
}
} else {
path.remove();
bool ok = path.remove();
if (!ok) {
SG_LOG(SG_TERRASYNC, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove path:" << nm
<< " at path:\n\t" << path);
}
}
dav->removeChild(child);

View File

@@ -73,7 +73,7 @@ public:
void updateFailed(HTTP::Request* req, SVNRepository::ResultCode err)
{
SG_LOG(SG_IO, SG_WARN, "SVN: failed to update from:" << req->url()
SG_LOG(SG_TERRASYNC, SG_WARN, "SVN: failed to update from:" << req->url()
<< "\n(repository:" << p->baseUrl() << ")");
isUpdating = false;
status = err;
@@ -120,6 +120,7 @@ namespace { // anonmouse
Request(repo->baseUrl, "PROPFIND"),
_repo(repo)
{
assert(repo);
requestHeader("Depth") = "0";
setBodyData( PROPFIND_REQUEST_BODY,
"application/xml; charset=\"utf-8\"" );
@@ -133,11 +134,13 @@ namespace { // anonmouse
} else if (responseCode() == 404) {
_repo->propFindFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND);
} else {
SG_LOG(SG_IO, SG_WARN, "request for:" << url() <<
SG_LOG(SG_TERRASYNC, SG_WARN, "request for:" << url() <<
" return code " << responseCode());
_repo->propFindFailed(this, SVNRepository::SVN_ERROR_SOCKET);
_repo = NULL;
}
Request::responseHeadersComplete();
}
virtual void onDone()
@@ -228,7 +231,7 @@ protected:
_repo->updateFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND);
_failed = true;
} else {
SG_LOG(SG_IO, SG_WARN, "SVN: request for:" << url() <<
SG_LOG(SG_TERRASYNC, SG_WARN, "SVN: request for:" << url() <<
" got HTTP status " << responseCode());
_repo->updateFailed(this, SVNRepository::SVN_ERROR_HTTP);
_failed = true;
@@ -328,7 +331,7 @@ void SVNRepository::update()
}
if (_d->targetRevision == rootDir()->cachedRevision()) {
SG_LOG(SG_IO, SG_DEBUG, baseUrl() << " in sync at version " << _d->targetRevision);
SG_LOG(SG_TERRASYNC, SG_DEBUG, baseUrl() << " in sync at version " << _d->targetRevision);
_d->isUpdating = false;
return;
}
@@ -372,7 +375,7 @@ void SVNRepoPrivate::propFindComplete(HTTP::Request* req, DAVCollection* c)
void SVNRepoPrivate::propFindFailed(HTTP::Request *req, SVNRepository::ResultCode err)
{
if (err != SVNRepository::SVN_ERROR_NOT_FOUND) {
SG_LOG(SG_IO, SG_WARN, "PropFind failed for:" << req->url());
SG_LOG(SG_TERRASYNC, SG_WARN, "PropFind failed for:" << req->url());
}
isUpdating = false;

View File

@@ -274,6 +274,15 @@ static void read_indices(char* buffer,
if (vaMask & SG_VA_FLOAT_3) vas[7].push_back(*src++);
}
} // of elements in the index
// WS2.0 fix : toss zero area triangles
if ( ( count == 3 ) && (indexMask & SG_IDX_VERTICES) ) {
if ( (vertices[0] == vertices[1]) ||
(vertices[1] == vertices[2]) ||
(vertices[2] == vertices[0]) ) {
vertices.clear();
}
}
}
template <class T>
@@ -468,12 +477,15 @@ void SGBinObject::read_object( gzFile fp,
read_indices<uint16_t>(ptr, nbytes, idx_mask, vertex_attrib_mask, vs, ns, cs, tcs, vas );
}
vertices.push_back( vs );
normals.push_back( ns );
colors.push_back( cs );
texCoords.push_back( tcs );
vertexAttribs.push_back( vas );
materials.push_back( material );
// Fix for WS2.0 - ignore zero area triangles
if ( !vs.empty() ) {
vertices.push_back( vs );
normals.push_back( ns );
colors.push_back( cs );
texCoords.push_back( tcs );
vertexAttribs.push_back( vas );
materials.push_back( material );
}
} // of element iteration
}

View File

@@ -44,9 +44,8 @@
#include "sg_file.hxx"
using std::string;
SGFile::SGFile(const string &file, int repeat_)
SGFile::SGFile(const std::string &file, int repeat_)
: file_name(file), fp(-1), eof_flag(true), repeat(repeat_), iteration(0)
{
set_type( sgFileType );

View File

@@ -1,37 +1,31 @@
/** \file sg_file.hxx
* File I/O routines.
*/
///@file
/// File I/O routines.
//
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
// 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 program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// 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
// General Public License for more details.
// 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.
//
// $Id$
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef _SG_FILE_HXX
#define _SG_FILE_HXX
#include <simgear/compiler.h>
#include <string>
#include "iochannel.hxx"
#include <string>
/**
* A file I/O class based on SGIOChannel.
@@ -91,7 +85,4 @@ public:
virtual bool eof() const { return eof_flag; };
};
#endif // _SG_FILE_HXX

View File

@@ -227,6 +227,13 @@ void NetChannel::handleAccept (void) {
void NetChannel::handleError (int error)
{
if (error == EINPROGRESS) {
// this shoudl never happen, because we should use isNonBlocking to check
// such error codes.
SG_LOG(SG_IO, SG_WARN, "Got EINPROGRESS at NetChannel::handleError: suggests broken logic somewhere else");
return; // not an actual error, don't warn
}
// warn about address lookup failures seperately, don't warn again.
// (and we (ab-)use ENOENT to mean 'name not found'.
if (error != ENOENT) {
@@ -251,6 +258,11 @@ NetChannelPoller::removeChannel(NetChannel* channel)
assert(channel->poller == this);
channel->poller = NULL;
// portability: MSVC throws assertion failure when empty
if (channels.empty()) {
return;
}
ChannelList::iterator it = channels.begin();
for (; it != channels.end(); ++it) {
if (*it == channel) {

View File

@@ -27,6 +27,7 @@
#include <cstring>
#include <cstdlib>
#include <algorithm>
namespace simgear {

View File

@@ -32,6 +32,7 @@
#include <cstring>
#include <cstdlib> // for atoi
#include <algorithm>
using std::string;

View File

@@ -3,15 +3,23 @@
#include <iostream>
#include <map>
#include <sstream>
#include <errno.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h>
#include "HTTPClient.hxx"
#include "HTTPRequest.hxx"
#include <simgear/io/sg_netChat.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/timing/timestamp.hxx>
#include <simgear/debug/logstream.hxx>
#if defined(ENABLE_CURL)
#include <curl/multi.h>
#endif
using std::cout;
using std::cerr;
@@ -46,7 +54,7 @@ char body2[body2Size];
cerr << "failed:" << #a << endl; \
exit(1); \
}
class TestRequest : public HTTP::Request
{
public:
@@ -54,41 +62,43 @@ public:
bool failed;
string bodyData;
TestRequest(const std::string& url, const std::string method = "GET") :
TestRequest(const std::string& url, const std::string method = "GET") :
HTTP::Request(url, method),
complete(false)
complete(false),
failed(false)
{
}
std::map<string, string> headers;
protected:
virtual void onDone()
{
complete = true;
}
}
virtual void onFail()
{
failed = true;
}
virtual void gotBodyData(const char* s, int n)
{
//std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
bodyData += string(s, n);
}
virtual void responseHeader(const string& header, const string& value)
{
Request::responseHeader(header, value);
headers[header] = value;
}
};
class TestServerChannel : public NetChat
{
public:
public:
enum State
{
STATE_IDLE = 0,
@@ -96,19 +106,19 @@ public:
STATE_CLOSING,
STATE_REQUEST_BODY
};
TestServerChannel()
{
state = STATE_IDLE;
setTerminator("\r\n");
}
virtual void collectIncomingData(const char* s, int n)
{
buffer += string(s, n);
}
virtual void foundTerminator(void)
{
if (state == STATE_IDLE) {
@@ -118,16 +128,16 @@ public:
cerr << "malformed request:" << buffer << endl;
exit(-1);
}
method = line[0];
path = line[1];
string::size_type queryPos = path.find('?');
if (queryPos != string::npos) {
parseArgs(path.substr(queryPos + 1));
path = path.substr(0, queryPos);
}
httpVersion = line[2];
requestHeaders.clear();
buffer.clear();
@@ -138,10 +148,10 @@ public:
receivedRequestHeaders();
return;
}
string::size_type colonPos = buffer.find(':');
if (colonPos == string::npos) {
cerr << "malformed HTTP response header:" << buffer << endl;
cerr << "test malformed HTTP response header:" << buffer << endl;
buffer.clear();
return;
}
@@ -156,8 +166,8 @@ public:
} else if (state == STATE_CLOSING) {
// ignore!
}
}
}
void parseArgs(const string& argData)
{
string_list argv = strutils::split(argData, "&");
@@ -173,11 +183,10 @@ public:
args[key] = value;
}
}
void receivedRequestHeaders()
{
state = STATE_IDLE;
if (path == "/test1") {
string contentStr(BODY1);
stringstream d;
@@ -205,7 +214,7 @@ public:
} else if (path == "/test_headers") {
COMPARE(requestHeaders["X-Foo"], string("Bar"));
COMPARE(requestHeaders["X-AnotherHeader"], string("A longer value"));
string contentStr(BODY1);
stringstream d;
d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
@@ -235,11 +244,11 @@ public:
if (requestHeaders["Host"] != "www.google.com") {
sendErrorResponse(400, true, "bad destination");
}
if (requestHeaders["Proxy-Authorization"] != string()) {
sendErrorResponse(401, false, "bad auth"); // shouldn't supply auth
sendErrorResponse(401, false, "bad auth, not empty"); // shouldn't supply auth
}
sendBody2();
} else if (path == "http://www.google.com/test3") {
// proxy test
@@ -247,8 +256,28 @@ public:
sendErrorResponse(400, true, "bad destination");
}
if (requestHeaders["Proxy-Authorization"] != "ABCDEF") {
sendErrorResponse(401, false, "bad auth"); // forbidden
string credentials = requestHeaders["Proxy-Authorization"];
if (credentials.substr(0, 5) != "Basic") {
// request basic auth
stringstream d;
d << "HTTP/1.1 " << 407 << " " << reasonForCode(407) << "\r\n";
d << "WWW-Authenticate: Basic real=\"simgear\"\r\n";
d << "\r\n"; // final CRLF to terminate the headers
push(d.str().c_str());
return;
}
std::vector<unsigned char> userAndPass;
strutils::decodeBase64(credentials.substr(6), userAndPass);
std::string decodedUserPass((char*) userAndPass.data(), userAndPass.size());
if (decodedUserPass != "johndoe:swordfish") {
std::map<string, string>::const_iterator it;
for (it = requestHeaders.begin(); it != requestHeaders.end(); ++it) {
cerr << "header:" << it->first << " = " << it->second << endl;
}
sendErrorResponse(401, false, "bad auth, not as set"); // forbidden
}
sendBody2();
@@ -272,6 +301,12 @@ public:
d << contentStr;
push(d.str().c_str());
closeAfterSending();
} else if (path == "/test_abrupt_close") {
// simulate server doing socket close before sending any
// response - this used to cause a TerraSync failure since we
// would get stuck restarting the request
closeAfterSending();
} else if (path == "/test_args") {
if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
sendErrorResponse(400, true, "bad arguments");
@@ -291,43 +326,78 @@ public:
sendErrorResponse(400, true, "bad content type");
return;
}
requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
setByteCount(requestContentLength);
state = STATE_REQUEST_BODY;
} else if ((path == "/test_put") || (path == "/test_create")) {
if (requestHeaders["Content-Type"] != "x-application/foobar") {
cerr << "bad content type: '" << requestHeaders["Content-Type"] << "'" << endl;
sendErrorResponse(400, true, "bad content type");
return;
}
requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
setByteCount(requestContentLength);
state = STATE_REQUEST_BODY;
} else {
sendErrorResponse(404, false, "");
}
}
void closeAfterSending()
{
state = STATE_CLOSING;
closeWhenDone();
}
void receivedBody()
{
state = STATE_IDLE;
if (method == "POST") {
parseArgs(buffer);
}
if (path == "/test_post") {
if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
sendErrorResponse(400, true, "bad arguments");
return;
}
stringstream d;
d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
push(d.str().c_str());
cerr << "sent 204 response ok" << endl;
} else if (path == "/test_put") {
std::cerr << "sending PUT response" << std::endl;
COMPARE(buffer, BODY3);
stringstream d;
d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
push(d.str().c_str());
} else if (path == "/test_create") {
std::cerr << "sending create response" << std::endl;
std::string entityStr = "http://localhost:2000/something.txt";
COMPARE(buffer, BODY3);
stringstream d;
d << "HTTP/1.1 " << 201 << " " << reasonForCode(201) << "\r\n";
d << "Location:" << entityStr << "\r\n";
d << "Content-Length:" << entityStr.size() << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
d << entityStr;
push(d.str().c_str());
} else {
std::cerr << "weird URL " << path << std::endl;
sendErrorResponse(400, true, "bad URL:" + path);
}
buffer.clear();
}
void sendBody2()
{
stringstream d;
@@ -337,32 +407,36 @@ public:
push(d.str().c_str());
bufferSend(body2, body2Size);
}
void sendErrorResponse(int code, bool close, string content)
{
cerr << "sending error " << code << " for " << path << endl;
cerr << "\tcontent:" << content << endl;
stringstream headerData;
headerData << "HTTP/1.1 " << code << " " << reasonForCode(code) << "\r\n";
headerData << "Content-Length:" << content.size() << "\r\n";
headerData << "\r\n"; // final CRLF to terminate the headers
push(headerData.str().c_str());
push(content.c_str());
if (close) {
closeWhenDone();
}
}
string reasonForCode(int code)
string reasonForCode(int code)
{
switch (code) {
case 200: return "OK";
case 201: return "Created";
case 204: return "no content";
case 404: return "not found";
case 407: return "proxy authentication required";
default: return "unknown code";
}
}
State state;
string buffer;
string method;
@@ -376,20 +450,22 @@ public:
class TestServer : public NetChannel
{
simgear::NetChannelPoller _poller;
public:
public:
TestServer()
{
Socket::initSockets();
open();
bind(NULL, 2000); // localhost, any port
listen(5);
_poller.addChannel(this);
}
virtual ~TestServer()
{
{
}
virtual bool writable (void) { return false ; }
virtual void handleAccept (void)
@@ -399,10 +475,10 @@ public:
//cout << "did accept from " << addr.getHost() << ":" << addr.getPort() << endl;
TestServerChannel* chan = new TestServerChannel();
chan->setHandle(handle);
_poller.addChannel(chan);
}
void poll()
{
_poller.poll();
@@ -414,42 +490,43 @@ TestServer testServer;
void waitForComplete(HTTP::Client* cl, TestRequest* tr)
{
SGTimeStamp start(SGTimeStamp::now());
while (start.elapsedMSec() < 1000) {
while (start.elapsedMSec() < 10000) {
cl->update();
testServer.poll();
if (tr->complete) {
return;
}
SGTimeStamp::sleepForMSec(1);
SGTimeStamp::sleepForMSec(15);
}
cerr << "timed out" << endl;
}
void waitForFailed(HTTP::Client* cl, TestRequest* tr)
{
SGTimeStamp start(SGTimeStamp::now());
while (start.elapsedMSec() < 1000) {
while (start.elapsedMSec() < 10000) {
cl->update();
testServer.poll();
if (tr->failed) {
return;
}
SGTimeStamp::sleepForMSec(1);
SGTimeStamp::sleepForMSec(15);
}
cerr << "timed out waiting for failure" << endl;
}
int main(int argc, char* argv[])
{
sglog().setLogLevels( SG_ALL, SG_INFO );
HTTP::Client cl;
// force all requests to use the same connection for this test
cl.setMaxConnections(1);
cl.setMaxConnections(1);
// test URL parsing
TestRequest* tr1 = new TestRequest("http://localhost.woo.zar:2000/test1?foo=bar");
COMPARE(tr1->scheme(), "http");
@@ -457,14 +534,14 @@ int main(int argc, char* argv[])
COMPARE(tr1->host(), "localhost.woo.zar");
COMPARE(tr1->port(), 2000);
COMPARE(tr1->path(), "/test1");
TestRequest* tr2 = new TestRequest("http://192.168.1.1/test1/dir/thing/file.png");
COMPARE(tr2->scheme(), "http");
COMPARE(tr2->hostAndPort(), "192.168.1.1");
COMPARE(tr2->host(), "192.168.1.1");
COMPARE(tr2->port(), 80);
COMPARE(tr2->path(), "/test1/dir/thing/file.png");
// basic get request
{
TestRequest* tr = new TestRequest("http://localhost:2000/test1");
@@ -478,12 +555,12 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
COMPARE(tr->bodyData, string(BODY1));
}
{
TestRequest* tr = new TestRequest("http://localhost:2000/testLorem");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 200);
COMPARE(tr->responseReason(), string("OK"));
@@ -491,7 +568,7 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), strlen(BODY3));
COMPARE(tr->bodyData, string(BODY3));
}
{
TestRequest* tr = new TestRequest("http://localhost:2000/test_args?foo=abc&bar=1234&username=johndoe");
HTTP::Request_ptr own(tr);
@@ -499,9 +576,7 @@ int main(int argc, char* argv[])
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 200);
}
cerr << "done args" << endl;
{
TestRequest* tr = new TestRequest("http://localhost:2000/test_headers");
HTTP::Request_ptr own(tr);
@@ -516,12 +591,12 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
COMPARE(tr->bodyData, string(BODY1));
}
// larger get request
for (unsigned int i=0; i<body2Size; ++i) {
body2[i] = (i << 4) | (i >> 2);
}
{
TestRequest* tr = new TestRequest("http://localhost:2000/test2");
HTTP::Request_ptr own(tr);
@@ -531,8 +606,8 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), body2Size);
COMPARE(tr->bodyData, string(body2, body2Size));
}
cerr << "testing chunked" << endl;
cerr << "testing chunked transfer encoding" << endl;
{
TestRequest* tr = new TestRequest("http://localhost:2000/testchunked");
HTTP::Request_ptr own(tr);
@@ -546,7 +621,7 @@ int main(int argc, char* argv[])
// check trailers made it too
COMPARE(tr->headers["x-foobar"], string("wibble"));
}
// test 404
{
TestRequest* tr = new TestRequest("http://localhost:2000/not-found");
@@ -593,15 +668,40 @@ int main(int argc, char* argv[])
}
cout << "done3" << endl;
// test connectToHost failure
/*
{
TestRequest* tr = new TestRequest("http://not.found/something");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForFailed(tr);
COMPARE(tr->responseCode(), -1);
waitForFailed(&cl, tr);
#if defined(ENABLE_CURL)
const int HOST_NOT_FOUND_CODE = CURLE_COULDNT_RESOLVE_HOST;
#else
const int HOST_NOT_FOUND_CODE = ENOENT;
#endif
COMPARE(tr->responseCode(), HOST_NOT_FOUND_CODE);
}
*/
cout << "testing abrupt close" << endl;
// test server-side abrupt close
{
TestRequest* tr = new TestRequest("http://localhost:2000/test_abrupt_close");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForFailed(&cl, tr);
#if defined(ENABLE_CURL)
const int SERVER_NO_DATA_CODE = CURLE_GOT_NOTHING;
#else
const int SERVER_NO_DATA_CODE = 500;
#endif
COMPARE(tr->responseCode(), SERVER_NO_DATA_CODE);
}
cout << "testing proxy close" << endl;
// test proxy
{
cl.setProxy("localhost", 2000);
@@ -613,9 +713,10 @@ int main(int argc, char* argv[])
COMPARE(tr->responseLength(), body2Size);
COMPARE(tr->bodyData, string(body2, body2Size));
}
#if defined(ENABLE_CURL)
{
cl.setProxy("localhost", 2000, "ABCDEF");
cl.setProxy("localhost", 2000, "johndoe:swordfish");
TestRequest* tr = new TestRequest("http://www.google.com/test3");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
@@ -624,81 +725,105 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), body2Size);
COMPARE(tr->bodyData, string(body2, body2Size));
}
#endif
// pipelining
cout << "testing HTTP 1.1 pipelineing" << endl;
cout << "testing HTTP 1.1 pipelining" << endl;
{
cl.setProxy("", 80);
TestRequest* tr = new TestRequest("http://localhost:2000/test1");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
HTTP::Request_ptr own2(tr2);
cl.makeRequest(tr2);
TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
HTTP::Request_ptr own3(tr3);
cl.makeRequest(tr3);
waitForComplete(&cl, tr3);
VERIFY(tr->complete);
VERIFY(tr2->complete);
COMPARE(tr->bodyData, string(BODY1));
COMPARE(tr2->responseLength(), strlen(BODY3));
COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
COMPARE(tr2->bodyData, string(BODY3));
COMPARE(tr3->bodyData, string(BODY1));
}
// multiple requests with an HTTP 1.0 server
{
cout << "http 1.0 multiple requests" << endl;
cl.setProxy("", 80);
TestRequest* tr = new TestRequest("http://localhost:2000/test_1_0/A");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
TestRequest* tr2 = new TestRequest("http://localhost:2000/test_1_0/B");
HTTP::Request_ptr own2(tr2);
cl.makeRequest(tr2);
TestRequest* tr3 = new TestRequest("http://localhost:2000/test_1_0/C");
HTTP::Request_ptr own3(tr3);
cl.makeRequest(tr3);
waitForComplete(&cl, tr3);
VERIFY(tr->complete);
VERIFY(tr2->complete);
COMPARE(tr->responseLength(), strlen(BODY1));
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
COMPARE(tr->bodyData, string(BODY1));
COMPARE(tr2->responseLength(), strlen(BODY3));
COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
COMPARE(tr2->bodyData, string(BODY3));
COMPARE(tr3->bodyData, string(BODY1));
}
// POST
{
cout << "POST" << endl;
cout << "testing POST" << endl;
TestRequest* tr = new TestRequest("http://localhost:2000/test_post?foo=abc&bar=1234&username=johndoe", "POST");
tr->setBodyData("", "application/x-www-form-urlencoded");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 204);
}
// PUT
{
cout << "testing PUT" << endl;
TestRequest* tr = new TestRequest("http://localhost:2000/test_put", "PUT");
tr->setBodyData(BODY3, "x-application/foobar");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 204);
}
{
cout << "testing PUT create" << endl;
TestRequest* tr = new TestRequest("http://localhost:2000/test_create", "PUT");
tr->setBodyData(BODY3, "x-application/foobar");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 201);
}
// test_zero_length_content
{
cout << "zero-length-content-response" << endl;
@@ -710,8 +835,8 @@ int main(int argc, char* argv[])
COMPARE(tr->bodyData, string());
COMPARE(tr->responseBytesReceived(), 0);
}
cout << "all tests passed ok" << endl;
return EXIT_SUCCESS;
}

View File

@@ -93,13 +93,32 @@ void compareTexCoords(const SGBinObject& rd, const std::vector<SGVec2f>& b)
VERIFY(equivalent(pos, b[i], 0.001f));
}
}
int_list make_tri(int maxIndex)
{
int_list r;
r.push_back(random() % maxIndex);
r.push_back(random() % maxIndex);
r.push_back(random() % maxIndex);
int a, b, c;
bool valid = false;
int retry = 10;
while(!valid && retry--) {
a = (random() % maxIndex);
b = (random() % maxIndex);
c = (random() % maxIndex);
valid = ( (a!=b) && (b!=c) && (c!=a) );
}
if (!valid) {
cerr << "can't generate valid triangle" << endl;
exit(1);
}
r.push_back(a);
r.push_back(b);
r.push_back(c);
return r;
}

View File

@@ -24,7 +24,7 @@
// Put in some bullet-proofing to handle magnetic and geographic poles.
// 3/28/2000 EAW
//
// Updated coefficient arrays to use the current WMM2005 model,
// Updated coefficient arrays to use the current wmm2005 model,
// (valid between 2005.0 and 2010.0)
// Also removed unused variables and corrected earth radii constants
// to the values for WGS84 and WMM2005.
@@ -36,6 +36,20 @@
//
// 25/10/2006 Wim Van Hoydonck -- wim.van.hoydonck@gmail.com
//
//
// Updated coefficient arrays to use the current WMM2015 model,
// (valid between 2015.0 and 2020.0)
// Also removed unused variables and corrected earth radii constants
// to the values for WGS84 and WMM2015.
// Reference:
// A. Chulliat , S. Macmillan, P. Alken, C. Beggan, M.
// Nair, B. Hamilton, A. Woods, V. Ridley,
// S Maus, and A Thomson, December 2014, The
// US/UK World Magnetic Model for 2015-2020,
// NOAA Technical Report WMM2015_Report.pdf
//
// 18/06/2015 Jean-Paul Anceaux -- j.p.r.anceaux@gmail.com
// The routine uses a spherical harmonic expansion of the magnetic
// potential up to twelfth order, together with its time variation, as
@@ -52,7 +66,7 @@
// the magnetic poles (where it is ill-defined) where the error may reach
// 4 degrees or more.
//
// Variation is undefined at both the geographic and
// Variation is undefined at both the geographic and
// magnetic poles, even though the field itself is well-behaved. To
// avoid the routine blowing up, latitude entries corresponding to
// the geographic poles are slightly offset. At the magnetic poles,
@@ -79,7 +93,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cmath>
#include <simgear/constants.h>
#include <simgear/sg_inlines.h>
@@ -90,72 +104,72 @@ static const double a = 6378.137; /* semi-major axis (equatorial radius) o
static const double b = 6356.7523142; /* semi-minor axis referenced to the WGS84 ellipsoid */
static const double r_0 = 6371.2; /* standard Earth magnetic reference radius */
static double gnm_wmm2005[13][13] =
static double gnm_wmm2015[13][13] =
{
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-29556.8, -1671.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-2340.6, 3046.9, 1657.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{1335.4, -2305.1, 1246.7, 674.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{919.8, 798.1, 211.3, -379.4, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-227.4, 354.6, 208.7, -136.5, -168.3, -14.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{73.2, 69.7, 76.7, -151.2, -14.9, 14.6, -86.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{80.1, -74.5, -1.4, 38.5, 12.4, 9.5, 5.7, 1.8, 0.0, 0.0, 0.0, 0.0, 0.0},
{24.9, 7.7, -11.6, -6.9, -18.2, 10.0, 9.2, -11.6, -5.2, 0.0, 0.0, 0.0, 0.0},
{5.6, 9.9, 3.5, -7.0, 5.1, -10.8, -1.3, 8.8, -6.7, -9.1, 0.0, 0.0, 0.0},
{-2.3, -6.3, 1.6, -2.6, 0.0, 3.1, 0.4, 2.1, 3.9, -0.1, -2.3, 0.0, 0.0},
{2.8, -1.6, -1.7, 1.7, -0.1, 0.1, -0.7, 0.7, 1.8, 0.0, 1.1, 4.1, 0.0},
{-2.4, -0.4, 0.2, 0.8, -0.3, 1.1, -0.5, 0.4, -0.3, -0.3, -0.1, -0.3, -0.1},
{-29438.5, -1501.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-2445.3, 3012.5, 1676.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{1351.1, -2352.3, 1225.6, 581.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{907.2, 813.7, 120.3, -335.0, 70.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-232.6, 360.1, 192.4, -141.0, -157.4, 4.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{69.5, 67.4, 72.8, -129.8, -29.0, 13.2, -70.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{81.6, -76.1, -6.8, 51.9, 15.0, 9.3, -2.8, 6.7, 0.0, 0.0, 0.0, 0.0, 0.0},
{24.0, 8.6, -16.9, -3.2, -20.6, 13.3, 11.7, -16.0, -2.0, 0.0, 0.0, 0.0, 0.0},
{5.4, 8.8, 3.1, -3.1, 0.6, -13.3, -0.1, 8.7, -9.1, -10.5, 0.0, 0.0, 0.0},
{-1.9, -6.5, 0.2, 0.6, -0.6, 1.7, -0.7, 2.1, 2.3, -1.8, -3.6, 0.0, 0.0},
{3.1, -1.5, -2.3, 2.1, -0.9, 0.6, -0.7, 0.2, 1.7, -0.2, 0.4, 3.5, 0.0},
{-2.0, -0.3, 0.4, 1.3, -0.9, 0.9, 0.1, 0.5, -0.4, -0.4, 0.2, -0.9, 0.0},
};
static double hnm_wmm2005[13][13]=
static double hnm_wmm2015[13][13]=
{
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 5079.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -2594.7, -516.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -199.9, 269.3, -524.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 281.5, -226.0, 145.8, -304.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 42.4, 179.8, -123.0, -19.5, 103.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.3, 54.7, 63.6, -63.4, -0.1, 50.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -61.5, -22.4, 7.2, 25.4, 11.0, -26.4, -5.1, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 11.2, -21.0, 9.6, -19.8, 16.1, 7.7, -12.9, -0.2, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.1, 12.9, 12.6, -6.7, -8.1, 8.0, 2.9, -7.9, 6.0, 0.0, 0.0, 0.0},
{0.0, 2.4, 0.2, 4.4, 4.8, -6.5, -1.1, -3.4, -0.8, -2.3, -7.9, 0.0, 0.0},
{0.0, 0.3, 1.2, -0.8, -2.5, 0.9, -0.6, -2.7, -0.9, -1.3, -2.0, -1.2, 0.0},
{0.0, -0.4, 0.3, 2.4, -2.6, 0.6, 0.3, 0.0, 0.0, 0.3, -0.9, -0.4, 0.8},
{0.0, 4796.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -2845.6, -642.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -115.3, 245.0, -538.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 283.4, -188.6, 180.9, -329.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 47.4, 196.9, -119.4, 16.1, 100.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.7, 33.2, 58.8, -66.5, 7.3, 62.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -54.1, -19.4, 5.6, 24.4, 3.3, -27.5, -2.3, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 10.2, -18.1, 13.2, -14.6, 16.2, 5.7, -9.1, 2.2, 0.0, 0.0, 0.0, 0.0},
{0.0, -21.6, 10.8, 11.7, -6.8, -6.9, 7.8, 1.0, -3.9, 8.5, 0.0, 0.0, 0.0},
{0.0, 3.3, -0.3, 4.6, 4.4, -7.9, -0.6, -4.1, -2.8, -1.1, -8.7, 0.0, 0.0},
{0.0, -0.1, 2.1, -0.7, -1.1, 0.7, -0.2, -2.1, -1.5, -2.5, -2.0, -2.3, 0.0},
{0.0, -1.0, 0.5, 1.8, -2.2, 0.3, 0.7, -0.1, 0.3, 0.2, -0.9, -0.2, 0.7},
};
static double gtnm_wmm2005[13][13]=
static double gtnm_wmm2015[13][13]=
{
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{8.0, 10.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-15.1, -7.8, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.4, -2.6, -1.2, -6.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-2.5, 2.8, -7.0, 6.2, -3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-2.8, 0.7, -3.2, -1.1, 0.1, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.7, 0.4, -0.3, 2.3, -2.1, -0.6, 1.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.2, -0.1, -0.3, 1.1, 0.6, 0.5, -0.4, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.1, 0.3, -0.4, 0.3, -0.3, 0.2, 0.4, -0.7, 0.4, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{10.7, 17.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-8.6, -3.3, 2.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{3.1, -6.2, -0.4, -10.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.4, 0.8, -9.2, 4.0, -4.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.2, 0.1, -1.4, 0.0, 1.3, 3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.5, -0.2, -0.6, 2.4, -1.1, 0.3, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.2, -0.2, -0.4, 1.3, 0.2, -0.4, -0.9, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.1, -0.5, 0.5, -0.2, 0.4, 0.2, -0.4, 0.3, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.1, -0.1, 0.4, -0.5, -0.2, 0.1, 0.0, -0.2, -0.1, 0.0, 0.0, 0.0},
{0.0, 0.0, -0.1, 0.3, -0.1, -0.1, -0.1, 0.0, -0.2, -0.1, -0.2, 0.0, 0.0},
{0.0, 0.0, -0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.1, -0.1, 0.0},
{0.1, 0.0, 0.0, 0.1, -0.1, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
};
static double htnm_wmm2005[13][13]=
static double htnm_wmm2015[13][13]=
{
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -23.2, -14.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 5.0, -7.0, -0.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 2.2, 1.6, 5.8, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.7, 2.1, 4.8, -1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.6, -1.9, -0.4, -0.5, -0.3, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.6, 0.4, 0.2, 0.3, -0.8, -0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.2, 0.1, 0.3, 0.4, 0.1, -0.2, 0.4, 0.4, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -26.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -27.1, -13.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 8.4, -0.4, 2.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.6, 5.3, 3.0, -5.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.4, 1.6, -1.1, 3.3, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, -2.2, -0.7, 0.1, 1.0, 1.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.7, 0.5, -0.2, -0.1, -0.7, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.3, 0.3, 0.3, 0.6, -0.1, -0.2, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.2, -0.1, -0.2, 0.1, 0.1, 0.0, -0.2, 0.4, 0.3, 0.0, 0.0, 0.0},
{0.0, 0.1, -0.1, 0.0, 0.0, -0.2, 0.1, -0.1, -0.2, 0.1, -0.1, 0.0, 0.0},
{0.0, 0.0, 0.1, 0.0, 0.1, 0.0, 0.0, 0.1, 0.0, -0.1, 0.0, -0.1, 0.0},
{0.0, 0.0, 0.0, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
};
static const int nmax = 12;
@@ -174,7 +188,7 @@ static double roots[13][13][2];
unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd )
{
unsigned long jd;
yy = (yy < 50) ? (2000 + yy) : (1900 + yy);
jd = dd - 32075L + 1461L * (yy + 4800L + (mm - 14) / 12 ) / 4;
jd = jd + 367L * (mm - 2 - (mm - 14) / 12*12) / 12;
@@ -182,7 +196,7 @@ unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd )
/* printf("julian date = %d\n", jd ); */
return jd;
}
}
/*
@@ -195,8 +209,8 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
{
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
int n,m;
/* reference date for current model is 1 januari 2005 */
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
/* reference date for current model is 1 januari 2015 */
long date0_wmm2015 = yymmdd_to_julian_days(15,1,1);
double yearfrac,sr,r,theta,c,s,psi,fn,fn_0,B_r,B_theta,B_phi,X,Y,Z;
double sinpsi, cospsi, inv_s;
@@ -215,7 +229,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
/* theta is geocentric co-latitude */
r = h*h + 2.0*h * sr +
(a*a*a*a - ( a*a*a*a - b*b*b*b ) * sinlat*sinlat ) /
(a*a*a*a - ( a*a*a*a - b*b*b*b ) * sinlat*sinlat ) /
(a*a - (a*a - b*b) * sinlat*sinlat );
r = sqrt(r);
@@ -224,7 +238,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
c = cos(theta);
s = sin(theta);
/* protect against zero divide at geographic poles */
inv_s = 1.0 / (s + (s == 0.)*1.0e-8);
inv_s = 1.0 / (s + (s == 0.)*1.0e-8);
/* zero out arrays */
for ( n = 0; n <= nmax; n++ ) {
@@ -283,12 +297,12 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
/* compute Gauss coefficients gnm and hnm of degree n and order m for the desired time
achieved by adjusting the coefficients at time t0 for linear secular variation */
/* WMM2005 */
yearfrac = (dat - date0_wmm2005) / 365.25;
/* WMM2015 */
yearfrac = (dat - date0_wmm2015) / 365.25;
for ( n = 1; n <= nmax; n++ ) {
for ( m = 0; m <= nmax; m++ ) {
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
}
}
@@ -310,7 +324,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
double c2_n=0;
double c3_n=0;
for ( m = 0; m <= n; m++ ) {
double tmp = (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]);
double tmp = (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]);
c1_n=c1_n + tmp * P[n][m];
c2_n=c2_n + tmp * DP[n][m];
c3_n=c3_n + m * (gnm[n][m] * sm[m] - hnm[n][m] * cm[m]) * P[n][m];
@@ -340,7 +354,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
/* find variation in radians */
/* return zero variation at magnetic pole X=Y=0. */
/* E is positive */
return (X != 0. || Y != 0.) ? atan2(Y, X) : (double) 0.;
return (X != 0. || Y != 0.) ? atan2(Y, X) : (double) 0.;
}
@@ -350,7 +364,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
int n,m;
/* reference dates */
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
long date0_wmm2015 = yymmdd_to_julian_days(5,1,1);
double yearfrac,sr,r,theta,c,s,psi,fn,B_r,B_theta,B_phi,X,Y,Z;
@@ -362,7 +376,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
/* theta is geocentric co-latitude */
r = h * h + 2.0*h * sr +
(pow(a,4.0) - (pow(a,4.0) - pow(b,4.0)) * pow(sin(lat),2.0)) /
(pow(a,4.0) - (pow(a,4.0) - pow(b,4.0)) * pow(sin(lat),2.0)) /
(a * a - (a * a - b * b) * pow(sin(lat),2.0));
r = sqrt(r);
@@ -407,12 +421,12 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
}
/* compute gnm, hnm at dat */
/* WMM2005 */
yearfrac = (dat - date0_wmm2005) / 365.25;
/* WMM2015 */
yearfrac = (dat - date0_wmm2015) / 365.25;
for ( n = 1; n <= nmax; n++ ) {
for ( m = 0; m <= nmax; m++ ) {
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
}
}

View File

@@ -26,7 +26,7 @@
#endif
#include <math.h>
#include <cmath>
#include <simgear/magvar/magvar.hxx>
#include <simgear/math/SGMath.hxx>

View File

@@ -1,8 +1,8 @@
/* 2/14/00 fixed help message- dip angle (down positive), variation (E positive) */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <simgear/constants.h>

View File

@@ -41,6 +41,30 @@ public:
static T clip(const T& a, const T& _min, const T& _max)
{ return max(_min, min(_max, a)); }
/// Add two (integer) values taking care of overflows.
static T addClipOverflow(T a, T b)
{
if( b > 0 )
{
if( SGLimits<T>::max() - b < a )
return SGLimits<T>::max();
}
else
{
if( SGLimits<T>::min() - b > a )
return SGLimits<T>::min();
}
return a + b;
}
/// Add two (integer) values in place, taking care of overflows.
static T& addClipOverflowInplace(T& a, T b)
{
return a = addClipOverflow(a, b);
}
/**
* Seek a variable towards a target value with given rate and timestep
*
@@ -130,7 +154,7 @@ public:
static bool isNaN(const T& v)
{
#ifdef HAVE_ISNAN
return isnan(v);
return (isnan(v) != 0);
#elif defined HAVE_STD_ISNAN
return std::isnan(v);
#else

View File

@@ -196,6 +196,17 @@ SGVec2<T>
max(S s, const SGVec2<T>& v)
{ return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
/// Add two vectors taking care of (integer) overflows. The values are limited
/// to the respective minimum and maximum values.
template<class T>
SGVec2<T> addClipOverflow(SGVec2<T> const& lhs, SGVec2<T> const& rhs)
{
return SGVec2<T>(
SGMisc<T>::addClipOverflow(lhs.x(), rhs.x()),
SGMisc<T>::addClipOverflow(lhs.y(), rhs.y())
);
}
/// Scalar dot product
template<typename T>
inline

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