1
1

Compare commits

...

260 Commits

Author SHA1 Message Date
Julian Eisel
792f0aaad5 Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/editors/gpencil/gpencil_paint.c
2017-04-18 13:18:49 +02:00
bc6f689448 Moved opening and closing the HMD drivers to the HMD window creation to solve issues with Windows 10 for some devices.
This solves i.e the DK2/CV1 screen being accessible when opening a window for configuration (since the DK2 needs rotation).
2017-04-18 12:50:46 +02:00
6814b392eb Implemented new Vive distortion coefficient values based on approximated lenswrap 2017-04-18 12:09:59 +02:00
Julian Eisel
9e17c831eb Move HMD operators to wm_hmd.c 2017-04-16 00:04:11 +02:00
Julian Eisel
2d9f41b1bd Replace wm_device.c with wm_hmd.c, rename functions appropriately 2017-04-15 23:48:12 +02:00
Julian Eisel
1a0b5c3a99 Merge branch 'master' into HMD_viewport 2017-04-15 23:14:15 +02:00
Julian Eisel
dd2bdd2ca0 Fix closing HMD window not exiting HMD session correctly 2017-04-15 17:30:09 +02:00
Julian Eisel
d4dd0184a8 Fix virtual cursor not being removed correctly when stopping hmd session 2017-04-15 16:26:07 +02:00
Julian Eisel
a61b751972 Avoid view setup function prototypes, move them to top of file 2017-04-13 19:47:42 +02:00
Julian Eisel
01acc0d59f Move drawing matrix setup into own function 2017-04-13 19:26:35 +02:00
Julian Eisel
3113329f79 Fix manipulator interaction not using correct projection matrix
Moved matrix setup for interaction into own util function now. Also did
cleanup in related code.
2017-04-13 01:25:42 +02:00
Julian Eisel
a07ca22a99 Force using HMD parameters instead of camera ones in camera perspective 2017-04-13 00:09:27 +02:00
Julian Eisel
8437c6e28e Fix lens separation applied wrongly onto projection matrix 2017-04-12 23:56:51 +02:00
Julian Eisel
a993466b22 Fix projection matrices not taking focal length of HMD into account 2017-04-12 19:55:42 +02:00
a21130f737 Re calibrated the vertical position for the Vive lens distortion shader 2017-04-12 18:18:14 +02:00
Julian Eisel
0b4e2631d2 Fix crash when closing HMD window during running session 2017-04-12 12:27:36 +02:00
Julian Eisel
623841e7df Fix HMD view drawing black if device is set to 'None' 2017-04-12 01:09:18 +02:00
Julian Eisel
b3cdca4a0a Cleanup: Naming, use util function 2017-04-12 00:04:11 +02:00
Julian Eisel
511347ff30 Remove unnecessary check
Avoids having to pass around window-manager
2017-04-11 23:41:48 +02:00
Julian Eisel
8e4b4881c8 Fix Multi-view drawing interfering with HMD view drawing
Don't do any multi-view drawing in HMD view, it doesn't make any sense.
2017-04-11 23:19:11 +02:00
Julian Eisel
3c51b670c5 Make interactions in HMD view work nicely
This should make any interactions in HMD views work like users would
expect. Talking about things like selecting, using tools, placing 3D
cursor, ...
Same goes for HMD mirror views, their interactions should work fine
now.

I'm not so happy how we pass info about HMD state to
ED_view3d_draw_depth and ED_view3d_draw_depth_gpencil, would like to
figure out a nicer way to do that. Also continuous grab works a bit
glitchy.
2017-04-11 21:25:22 +02:00
Julian Eisel
c87925469b Add WM level utility check for active HMD view 2017-04-11 21:13:20 +02:00
Julian Eisel
2fa9fceba0 Special Blender-managed cursor drawing for HMD view
Since OSes only draw one cursor, we need to draw our own cursor for both
eyes.
Note that the interaction coordinates are still incorrect as they ignore
the split screen. Will fix that separately.
2017-04-11 21:13:20 +02:00
2cd6dfe86e Cleanup: tabs 2017-04-03 22:19:47 +10:00
f38dc5c06b Merge branch 'master' into HMD_viewport 2017-04-03 22:14:12 +10:00
66a20c9ad7 Clear hmd window when no loaded
Without this, the window could be saved in an invalid state.
2017-04-03 03:12:16 +10:00
c68fabee47 Remove ifdef check for file versioning
File patching shouldn't depend on build options
2017-04-03 02:54:59 +10:00
e53d432787 Sync with master and minor formatting 2017-04-03 02:50:56 +10:00
355bbb1d49 use 'use_' as an RNA prefix 2017-04-03 02:24:11 +10:00
1b81d776d7 Correct last commit, also quiet warnings 2017-04-03 02:05:44 +10:00
ea85e2fad3 Use max_ff 2017-04-03 02:03:20 +10:00
52e007dbb2 Fix for building without HMD 2017-04-03 01:43:54 +10:00
9327880109 Merge branch 'master' into HMD_viewport 2017-04-03 01:20:08 +10:00
7e4a96f0ab Fixes for Windows compile, fixes crashes when trying to open locked devices 2017-04-01 12:59:29 +02:00
06e9f3304c Numeral small fixes from upstream 0.3rc 2017-03-31 17:29:17 +02:00
9d1b98d383 Updated Vive lens correction values, is a decent approximation, needs extra sample points when looking down
Fixed lens seperation
2017-03-31 17:29:17 +02:00
Julian Eisel
3d7ca99c89 Disable zooming/pannig of HMD view while in camera perspective
Applying zoom to projection matrix wouldn't be correct, applying it to
the view matrix would work, but not easy to do it nicely. We'd also
still miss vertical/horizontal offset since it's realized using lens
shifting (= modifiying projection matrix), so that had to be applyied
onto view matrix as well.
Decided to just disallow paning and zooming completely for now, I don't
think it would make much sense in camera perspective.
2017-03-26 01:47:21 +01:00
Julian Eisel
66952dabe8 Fix HMD panel not visible after recent changes in master 2017-03-25 23:03:37 +01:00
Julian Eisel
8081480a86 Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/blenloader/intern/writefile.c
	source/blender/windowmanager/intern/wm_window.c
2017-03-25 22:15:29 +01:00
4deff6951d msvc fix in packet.c in PSVR driver 2017-03-24 23:24:30 +01:00
43a1310508 Fixes Oculus CV1 Lens Correction 2017-03-24 05:57:03 +01:00
634067f442 OpenHMD update, disables OVRService upon starting the device, only when run with administrator.
Requires custom build of hidapi for now (github TheOnlyJoey/hidapi)
2017-03-24 02:07:07 +01:00
Julian Eisel
abe2669720 Use projection matrix from OpenHMD even if "Rotation from HMD" is disabled
Was actually applying IPD wrongly, should be correct now.
2017-03-07 17:26:36 +01:00
Julian Eisel
cecbb727ac Merge branch 'master' into HMD_viewport 2017-03-07 12:41:10 +01:00
Julian Eisel
08870e72bc Draw additional viewport info in HMD view again (3D-cursor, mini-axis, etc)
On most (if not all) devices the stuff close to view borders won't be
visible because it's out of the field of view. Ideally we'd calculate their
positions based on the FOV, but that's for later.
2017-03-06 22:34:05 +01:00
Julian Eisel
66026afd69 Correction to previous commit, unset shader after session end
Also two other minor correcions.
2017-03-06 22:28:08 +01:00
Julian Eisel
fc0fb35df5 Don't draw HMD view lens shader if session is not running 2017-03-06 21:15:13 +01:00
Julian Eisel
96ef1beb58 Fixup Python UI definition after lens shader removal 2017-03-06 21:03:58 +01:00
Julian Eisel
af3917049b Refactor split-view drawing to make popups readable 2017-03-06 20:58:43 +01:00
Julian Eisel
982c41b549 Fix fragment shader compile error on Intel GPUs 2017-03-06 20:58:43 +01:00
bed9bf1907 Bunch of small HMD fixes, removed old now unused preferences 2017-03-06 02:18:16 +01:00
Julian Eisel
5605db8611 Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/windowmanager/wm.h
2017-03-06 02:13:55 +01:00
Julian Eisel
7015b229d1 Fixup for python UI definition 2017-03-06 02:13:22 +01:00
a5d19a22b7 Fixes for HMD support windows build (thanks LazyDodo) 2017-03-06 01:34:32 +01:00
1d1ba540bb New OpenHMD 0.3rc version with PSVR, Oculus CV1 and better Vive tracking support.
Also introduces global shader, which will be adjusted based on the variables of the HMD drivers, this will make the manual selection of lens correction shaders obsolete, will be removed in next commit.

The hmd window is currently black before started (due to shader not having the hmd data yet), will be fixed as well.
2017-03-06 01:23:14 +01:00
Julian Eisel
edd74baa15 Merge branch 'master' into HMD_viewport 2017-03-06 00:08:01 +01:00
Julian Eisel
20763919a1 Fix issues changing HMD device 2017-03-05 23:48:43 +01:00
Julian Eisel
d5f0807c63 Fix python UI for building without HMD 2017-03-05 23:39:34 +01:00
Julian Eisel
6907aa26c6 Disable OpenHMD dummy device for release builds
Also fixing warning.
2017-03-05 22:32:46 +01:00
Julian Eisel
4950ce4cd9 Don't allow orthographic view in HMD view
Displaying camera in orthographic mode is still allowed. We don't want
to mess with render data and forcing perspective viewport rendering in
HMD view even if the camera is set to be orthographic might be
confusing.
2017-03-05 21:56:49 +01:00
Julian Eisel
07706a28d0 "Only Render" option for HMD view 2017-03-05 20:36:30 +01:00
Julian Eisel
2f0d8e799a Use view orientation data from current 3D view for creating HMD view 2017-03-05 18:31:17 +01:00
Julian Eisel
b3c156927a Mirror mode support (sync HMD viewpoint with regular 3D view)
Adds option "Mirror HMD View" to the HMD panel in the 3D view.

In this implementation we update/redraw the mirrored 3D views with the
HMD view, which can actually cause some extra slowdown (drawing the
viewport at least once more). We decided that this would be the best
solution for now, as the other option would be opening a separate window
showing the mirrored result, which is a bit too much against the
non-overlapping paradigma IMHO.
We could also draw the HMD view into some buffer and reuse this for
mirrored displays, but that would mess up projection matrices.
In Blender 2.8 we'll probably be able to use multi-threaded drawing
anyway, for which this would be the perfect use case.

3D View regions mirroring the HMD view are locked, for quadview we only
use the non-locked region for mirroring.
2017-03-05 17:19:51 +01:00
284c7f72a1 Fix Vive compile option 2017-03-04 15:56:06 +01:00
Julian Eisel
724a991b7f Fix changing device activates it unintentionally
Activating in this context means that OpenHMD starts polling the device
for rotation values. That can slow down things, so we only do it when
actually starting an HMD session.
2017-02-27 17:19:55 +01:00
Julian Eisel
3a79183097 Don't check if HMD returns valid IPD
OpenHMD always returns a valid value, so this check is just a waste of
resources.
2017-02-27 17:05:11 +01:00
Julian Eisel
f705c53cfa Use solid draw mode by default for HMD view 2017-02-27 16:37:11 +01:00
Julian Eisel
a8a93f000a Fix wrong modelview matrices
Was wrongly applying modelview matrices from HMD onto Blender's.
2017-02-27 16:23:45 +01:00
Julian Eisel
3ef07b29c5 Minor UI message fixes 2017-02-26 22:54:42 +01:00
Julian Eisel
8f55592e77 Use "General" as default lens distortion shader 2017-02-26 17:46:05 +01:00
Julian Eisel
926b9ea918 Fix driver for DeePoon HMD
Patch by @TheOnlyJoey, thx for fixing (and breaking!) this ;)
2017-02-26 17:36:51 +01:00
Julian Eisel
0261a18677 Merge branch 'master' into HMD_viewport 2017-02-26 17:18:25 +01:00
3e486c19ff Merge branch 'HMD_viewport' of git.blender.org:blender into HMD_viewport 2017-02-23 20:06:03 +01:00
22570c0ab4 - Updated OpenHMD with fixes from their master (commit 2379647) 2017-02-23 20:04:56 +01:00
Julian Eisel
3fb0674a1a Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/makesdna/DNA_scene_types.h
2017-02-23 15:38:52 +01:00
ef017ec9d0 Added support for correct Oculus DK1 and DK2 shaders with additional Generic shader (which could/should work for most other HMD's)
Shaders can be changed in options so you can pick a shader that matches your device
2017-02-10 22:11:48 +01:00
3318e7bd13 Fixed small oops with copy paste 2017-02-10 17:28:50 +01:00
0bbbeead7d Fixed HMD branch for current master 2017-02-10 17:20:27 +01:00
68f931fd90 Merge branch 'master' of git.blender.org:blender into HMD_viewport 2017-02-10 16:50:30 +01:00
Dalai Felinto
f81ead6c38 Fix blenderplayer build 2017-01-18 16:34:01 +01:00
Julian Eisel
c8d1319452 Fix wrong logic in HMD device toggling 2016-11-24 19:45:23 +01:00
Julian Eisel
0c86cebeb2 Merge branch 'master' into HMD_viewport 2016-11-24 19:08:40 +01:00
Julian Eisel
129955e34b Give info on why "Use Device IPD" is disabled
Also renamed RNA properties and removed unneeded update function.
2016-11-23 23:11:00 +01:00
Julian Eisel
67847067b9 Couple of fix for case no device is available/active
Fixes:
* HMD device option using invalid value
* HMD view drawing on-screen info and using wrong matrices
* Hardly usable 3D view due to projection and modelview matrix being unit matrices
All issues where only visible when the HMD device option is set to 'None'
2016-11-23 18:08:26 +01:00
Julian Eisel
6a696c5bb4 Fixes for build options 2016-11-23 17:53:57 +01:00
Julian Eisel
1ea4d4362d Merge branch 'master' into HMD_viewport 2016-11-23 11:58:34 +01:00
Julian Eisel
a757065875 Fix KM_CLICK events broken 2016-11-23 02:26:43 +01:00
Julian Eisel
911fd31894 Fix HMD device set to 'none' after loading factory settings
We now use the last input device if available.
2016-11-23 02:09:30 +01:00
Julian Eisel
585c5e72ab Fix no active HMD when opening file that was saved during HMD session 2016-11-23 01:58:31 +01:00
Julian Eisel
d0000ef6fc Several minor corrections 2016-11-23 01:24:50 +01:00
Julian Eisel
91d0198d0e Make "Use Device Rotation" toggle work again
When this is disabled we just manually calculate the camera offsets. Actually I have no idea if math is correct but it doesn't seem totally wrong at least :P Don't have an HMD to test right now.
2016-11-23 00:52:22 +01:00
Julian Eisel
e2dd63eb55 Allow zooming/panning while HMD view is in camera perspective 2016-11-22 17:04:28 +01:00
Julian Eisel
48b38797c6 Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/makesrna/intern/rna_userdef.c
2016-11-20 19:32:02 +01:00
Julian Eisel
e06fa55a48 Add a dropdown to support multiple lens-distortion shaders 2016-11-20 00:11:41 +01:00
Julian Eisel
d9428f7a03 Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/blenloader/intern/versioning_270.c
2016-11-19 21:09:48 +01:00
Julian Eisel
c2b72626bf Replace low-level HMD check with higher level API call 2016-11-19 19:25:13 +01:00
Julian Eisel
8bfc10ce66 Make HMD window a proper 'restricted' window
A restricted window is a new concept that doesn't allow changing the screen of a window in any way. This way we can ensure the HMD window is only used for displaying the 3D View, so users can't accidentally change it without knowing how to get back. This also fixes some issues we had when using temp screens like they're used for UserPrefs.
Fixes:
* Could open toolbar/properties in HMD view
* HMD window used when opening UserPrefs through menu/shortcut
* Could easily change editor to non-3D-View
2016-11-19 13:38:17 +01:00
Julian Eisel
a29c325c83 Move HMD view shading option to window manager level
Was a bit ugly to have this in scene level, window manager isn't perfect either, but prefer it there.
2016-11-18 00:12:57 +01:00
Julian Eisel
509945633b Move HMD panel into 3D View properties
Still not a really perfect place since this is global, but can't think of a better one. More options will be added later on, so worth having an own panel.
2016-11-17 23:06:30 +01:00
Julian Eisel
fdb0d37bdf Remove scene level HMDVIEW_SESSION_RUNNING flag
Also separated HMD view drawing from stereo3d drawing some more.
2016-11-15 23:30:05 +01:00
Julian Eisel
ccf5de8a71 Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/blenloader/intern/versioning_270.c
	source/blender/editors/interface/resources.c
2016-11-15 16:18:56 +01:00
Julian Eisel
9ce9540afd Move HMD options to User Preferences 2016-11-11 17:45:46 +01:00
Julian Eisel
fdd4c5a98d Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/blenloader/intern/versioning_270.c
2016-11-11 16:22:40 +01:00
e2ccfdaa29 Fix bplayer (c) 2016-11-03 20:28:48 +01:00
8e1cf5237f Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/blenloader/intern/versioning_270.c
2016-11-03 20:10:55 +01:00
994795c1ed Add libhidapi to install_deps.sh script.
Note: only tested (both package and source compilation) with Debian
testing distro, others (fedora-like, arch-like) might not be working,
especially the compilation option.
2016-11-03 20:05:18 +01:00
TheOnlyJoey
54ed6f8918 Fixed deepoon variables for vc2013 compile 2016-10-31 14:21:47 +01:00
TheOnlyJoey
ce4f04f268 Fixed cmake option for htc vive in OpenHMD 2016-10-29 16:58:09 +02:00
TheOnlyJoey
e7670e9bb0 - Added initial HTC Vive support, still uses complimentary sensor fusion, could drift a bit 2016-10-29 16:21:56 +02:00
TheOnlyJoey
46bc9bcbba - Updated Oculus CV1 support 2016-10-29 16:01:03 +02:00
TheOnlyJoey
1a0d1064ee Removed cordinate frame from OpenHMD Deepoon driver 2016-10-29 01:19:39 +02:00
Julian Eisel
bebd1fbcd8 Own panel for HMD stuff
No need to enable "Views" option anymore now.
2016-10-28 23:56:22 +02:00
459f922484 Updated OpenHMD to match their latest master (1c984fb)
Adds support for Oculus Rift CV1 and Deepoon E2
2016-10-28 23:41:39 +02:00
Julian Eisel
913903af74 Fix warning with WITH_OPENHMD enabled 2016-10-28 23:23:25 +02:00
Julian Eisel
1a1b51f329 Fall back to return unit matrix 2016-10-28 23:11:20 +02:00
Julian Eisel
b7beb76211 Fix compiling without WITH_INPUT_HMD 2016-10-28 20:52:30 +02:00
Julian Eisel
2d2d44ca71 No need to apply HMD rotation in operator anymore
Now done by requesting modelview/projection matrices from OpenHMD.
2016-10-28 20:35:38 +02:00
Julian Eisel
14b9e0a933 Use projection matrix from HMD, don't add to Blender's 2016-10-28 20:03:34 +02:00
Julian Eisel
6d52d7e32d Merge branch 'master' into HMD_viewport 2016-10-12 20:17:24 +02:00
Julian Eisel
bf426bdf1e Proper default value for custom HMD IPD 2016-10-12 20:08:37 +02:00
Julian Eisel
a1562bbb53 Use modelview matrix from OpenHMD, get custom IPD to work
Also renamed interocular distance to IPD in UI (slightly different things), removed unused matrix getters and made sure enabling/disabling custom IPD behaves nicely. Note that both projection and modelview matrices from OpenHMD get the Blender equivalents applied on top, so they act as relative transformations. Rotating, zooming and panning in HMD view works properly too now.
2016-10-12 19:53:03 +02:00
Julian Eisel
505b1fdcb2 Always use projection matrix from OpenHMD
Was previously only used while in camera view.
Right now, you can't zoom during HMD session, should be fixable though. Custom interocular distance and optional HMD rotation don't work now either, need to check if we want to keep them.
2016-10-12 13:05:41 +02:00
Julian Eisel
b95a7c0af3 Fix disabling lens distortion shader causing OpenGL shader error
Also cleanup.
2016-10-12 01:06:09 +02:00
Julian Eisel
f8cfffec4f Use center as pivot for rotating views, avoid passing around arg 2016-10-11 22:44:14 +02:00
Julian Eisel
17a7c6a140 Fix warning without WITH_INPUT_HMD 2016-10-11 22:21:53 +02:00
Julian Eisel
e4a82a1e39 Make HMD IPD work properly with Multi-view format 2016-10-11 22:18:41 +02:00
Julian Eisel
7a4138a5b9 Toggle into scene camera when opening HMD window 2016-10-11 21:53:06 +02:00
Julian Eisel
99a29209b4 Fix crashes with HMD view in scenes without camera 2016-10-11 18:54:29 +02:00
Julian Eisel
637ca57ce9 Init proper default settings when creating new scene 2016-10-11 18:43:42 +02:00
Julian Eisel
9d9db8f748 Fix checkbox for getting IPD from device always disabled while no HMD session runs 2016-10-11 18:41:26 +02:00
Julian Eisel
ed34f17604 Refactor HMD->Camera relation, avoid low-level call 2016-10-11 18:05:11 +02:00
Julian Eisel
3db824b617 Show info in tooltip on why HMD session can't be started 2016-10-11 15:50:11 +02:00
Julian Eisel
24f4c98cc2 Move interocular distance settings out of camera data
These aren't just for the camera, but for entire HMD session.
2016-10-09 03:08:03 +02:00
Julian Eisel
c1846b18b1 Move HMD view settings into own scene level struct
For some reason I placed this in RenderData earlier.
2016-10-09 02:41:43 +02:00
Julian Eisel
f40b22365d HMD view doesn't require own multiview mode anymore
HMD view buttons and options are always visible in "Views" panel now (Properties Editor -> Render Layers context).
2016-10-09 01:22:25 +02:00
Julian Eisel
ebc32889be Return info in tooltip on why IPD button is disabled 2016-10-08 23:14:49 +02:00
Julian Eisel
ddb2a36a4d Merge branch 'master' into HMD_viewport
Conflicts:
	source/blender/blenloader/intern/versioning_270.c
	source/blender/editors/interface/resources.c
2016-10-08 23:06:51 +02:00
Julian Eisel
17cbaf5d16 Merge branch 'master' into HMD_viewport
Conflicts:
	intern/ghost/intern/GHOST_System.cpp
	intern/ghost/intern/GHOST_System.h
	source/blender/blenkernel/BKE_blender_version.h
	source/blender/blenloader/CMakeLists.txt
	source/blender/blenloader/intern/versioning_270.c
	source/blender/windowmanager/CMakeLists.txt
	source/blender/windowmanager/intern/wm_window.c
	source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
2016-09-08 13:30:20 +02:00
Julian Eisel
2ccdd0be51 Fix non-HMD window not drawing viewport in camera view
Also added WITH_INPUT_HMD checks
2016-08-03 16:48:04 +02:00
Julian Eisel
753dbee557 Merge branch 'HMD_viewport' of git.blender.org:blender into HMD_viewport 2016-08-02 01:23:33 +02:00
Julian Eisel
495e99fbc1 Undo accidental change 2016-08-02 01:19:46 +02:00
Julian Eisel
2924c09298 Viewport HMD integration using OpenHMD
= Viewport HMD integration using OpenHMD =

This adds initial support for controlling the viewport view using a head mounted display (HMD).

To use it, go to the Properties Editor, Render Layers context. Enable Views, select "HMD View". You can then open a new HMD Window from there and start a HMD session.

**TODOs:**
* Move HMD options to a better place, they are not Render Layer related (Maybe properties region?)
* Zoom and pan don't work in HMD window while in camera view
* View streched vertically in HMD window while not in camera view
* TODOs/XXXs marked in code (esp. WM_ calls in BKE_)
* Apply D1350 for better mouse interaction while in HMD view

Reviewers: sergey, dfelinto

Differential Revision: https://developer.blender.org/D2133
2016-08-02 01:10:28 +02:00
Julian Eisel
3d9fca040b Update/correct version patching 2016-08-02 00:42:19 +02:00
Julian Eisel
122e479fe7 Fixes for WITH_OPENHMD and WITH_INPUT_HMD options
And cleanup.
2016-08-02 00:39:07 +02:00
Julian Eisel
d0fce1c992 Cleanup: Undo whitespace changes, comments, etc 2016-08-02 00:28:11 +02:00
Julian Eisel
eb9f4d233c Merge branch 'master' into HMD_viewport 2016-08-01 23:01:40 +02:00
Julian Eisel
e1b662f017 Adjust opening position and size of HMD window 2016-08-01 22:30:53 +02:00
Julian Eisel
a68db93fc2 Fix streched viewport in camera view 2016-08-01 22:06:33 +02:00
Julian Eisel
6e30e9b16d Various cleanup 2016-08-01 21:58:21 +02:00
Julian Eisel
7cf31cb048 Cleanup: Use 4x4 matrices, naming, compiler hints, use API function 2016-08-01 02:49:36 +02:00
Julian Eisel
8f025c41e4 Merge branch 'master' into HMD_viewport
Conflicts:
	intern/ghost/intern/GHOST_System.h
	source/blender/blenkernel/intern/camera.c
	source/blender/blenkernel/intern/screen.c
	source/blender/editors/space_view3d/drawobject.c
	source/blender/editors/space_view3d/space_view3d.c
2016-08-01 02:23:40 +02:00
Julian Eisel
28d4cdaffc Reset writefile.c to earlier state to avoid merge hell
Was caused by whitespace auto-cleaning.
2016-08-01 01:49:38 +02:00
Julian Eisel
d90aec52ff Fix linking with Blenderplayer enabled 2016-08-01 01:11:06 +02:00
3774a424ea Implemented initial support for using HMD projection matrices in blender viewport.
Also did some general cleaning
2016-07-31 21:24:55 +02:00
Julian Eisel
95074bcd12 Always use parallel convergence in HMD mode
Previously it was just using whatever was set in non-HMD mode.
I guess using parallel convergence for usage with HMDs is correct, could be wrong though ;)
2016-06-08 20:07:52 +02:00
Julian Eisel
506dfd65eb Only allow using Device IPD if it's available 2016-06-08 19:44:32 +02:00
Julian Eisel
eebc41ec4f Don't display "Set Stereo 3D" button for HMD mode 2016-06-08 18:49:56 +02:00
185619229c Fixed locks when opening/closing HMD sessions
Spaces to Tabs
2016-06-08 16:57:18 +02:00
b99acd7338 Merge branch 'HMD_viewport' of git.blender.org:blender into HMD_viewport 2016-06-08 14:09:38 +02:00
Julian Eisel
699df00847 Make branch compile with blenderplayer 2016-06-07 20:16:23 +02:00
Julian Eisel
dbd5663c26 Merge branch 'master' into HMD_viewport
Conflicts:
	build_files/cmake/macros.cmake
	intern/ghost/intern/GHOST_SystemX11.cpp
	source/blender/editors/space_view3d/view3d_ops.c
2016-06-07 20:14:35 +02:00
90746deeec Merge branch 'HMD_viewport' of git.blender.org:blender into HMD_viewport 2016-05-21 03:08:27 +02:00
Julian Eisel
c2fe571634 Merge branch 'master' into HMD_viewport 2016-05-20 23:21:07 +02:00
Julian Eisel
bf4fe3c84f Add compiler hints to WM_device API 2016-05-20 23:16:34 +02:00
Julian Eisel
4c4333e06c Add asserts for total device number 2016-05-20 23:13:35 +02:00
Julian Eisel
18f050f951 Fix all HMDs in UserPref device option showing same name 2016-05-20 22:56:17 +02:00
53bf3e1d84 Merge branch 'HMD_viewport' of git.blender.org:blender into HMD_viewport 2016-05-20 17:58:29 +02:00
Julian Eisel
072f453448 Merge branch 'master' into HMD_viewport
Conflicts:
	release/scripts/startup/bl_ui/properties_data_camera.py
	source/blender/blenkernel/BKE_blender.h
	source/blender/blenloader/intern/versioning_270.c
	source/blender/editors/interface/interface_handlers.c
	source/blender/editors/space_view3d/view3d_view.c
	source/blender/makesdna/DNA_camera_types.h
	source/blender/windowmanager/intern/wm_event_system.c
	source/blender/windowmanager/intern/wm_operators.c
2016-05-20 01:17:29 +02:00
Julian Eisel
cc160fb0a2 Fix compilation with OPENHMD_DRIVER_EXTERNAL or OPENHMD_DRIVER_ANDROID 2016-05-20 01:01:51 +02:00
b90f3b1982 Updated OpenHMD to latest git version
Now uses threading for updating the hmd, better polling rates for performance on heavy scenes/low framerates
2016-05-19 00:46:44 +02:00
Julian Eisel
a32710fd90 Merge branch 'master' into HMD_viewport 2016-04-13 19:59:45 +02:00
Julian Eisel
a742abfafb Fix crash when stopping HMD session
OpenHMD context should only be closed when deleting GHOST_OpenHMDManager, forgot to change that in rB0c029b7f86a0.
2016-04-13 19:56:35 +02:00
Julian Eisel
deb3e28954 Don't split view in lens distortion shader
We don't want to do this in lens distortion shader since we can't add the view offset needed for the 3D effect.
2016-04-13 19:41:41 +02:00
Julian Eisel
077e3109c8 Correction to previos commit: Use int for region size 2016-04-13 00:51:32 +02:00
Julian Eisel
4424a8e844 Use non-fixed screen size for lens distortion shader
Was assuming 1920x1080. Also minor cleanup.
2016-04-13 00:45:14 +02:00
Julian Eisel
6485c25c0e Fix compile error with WITH_INPUT_HMD disabled 2016-04-10 21:40:31 +02:00
Julian Eisel
8ec1bb0966 Corrections for WITH_INPUT_HMD 2016-04-10 21:07:12 +02:00
Julian Eisel
1a3c402585 Display HMD vendor name in UserPref HMD device option
And minor cleanup.
2016-04-10 20:47:51 +02:00
Julian Eisel
088e381ae2 Quiet warnings without WITH_OPENHMD 2016-04-10 20:18:55 +02:00
Julian Eisel
21fc36fbc8 Bring back version patch
Without it building with WITH_OPENHMD disabled will activate an invalid UserPref HMD device item.
2016-04-10 20:10:24 +02:00
Julian Eisel
d81b2309bc Automate selecting HMD device
This automates setting of HMD device UserPref option a bit, so that it's ready to go without manual adjustments.
We use the last device plugged in on startup (if one is available). On runtime, plugging in a device makes it active if 'None' was previously selected in the UserPref option.
Saving HMD in UserPrefs should also be supported, but can't test.
Also removes EVT_HMD_DEVICENUM_CHANGE and version patch, they're not needed anymore.
2016-04-10 19:57:45 +02:00
Julian Eisel
16af40cc36 Send an event when a HMD was plugged in/out
It's not used for now, will commit separately.
2016-04-10 19:17:56 +02:00
Julian Eisel
691e8b135c More minor cleanup 2016-04-10 15:50:27 +02:00
Julian Eisel
60645b4030 Minor cleanup 2016-04-10 02:23:10 +02:00
Julian Eisel
30723504be Fix crash opening UserPrefs on some systems. 2016-04-10 02:13:51 +02:00
Julian Eisel
4bb2efcb6e Merge branch 'master' into HMD_viewport 2016-04-10 01:42:21 +02:00
Julian Eisel
0c029b7f86 Cleanup & fixes in GHOST_OpenHMDManager
Fix crash opening UserPrefs->System with HMD session running, fix OpenHMD context being re-created on each redraw of UserPrefs->System, get rid of m_available (can use m_device NULL check instead), other minor cleanup.
2016-04-10 01:40:31 +02:00
b189710cd8 - Fixed getting device information for the user preferences
- Defaulting to device 0 in openhmd which is the last plugged in (will fallback on Dummy Device)
2016-04-06 16:41:24 +02:00
Julian Eisel
88879dfae1 Add assert to ensure HMD view is always fullscreen 2016-03-29 02:19:11 +02:00
Julian Eisel
eec5ac5927 Cleanup: Unused variable/unused value 2016-03-29 01:58:01 +02:00
Julian Eisel
bacadeb8c4 Add build option WITH_INPUT_HMD
If we later want to support other drivers aside from OpenHMD, we only want OpenHMD to work at the low GHOST level. The new option is for the higher, driver independent level.
Since currently only OpenHMD is supported, I added a compile warning for the case HMD input is enabled and OpenHMD is disabled. Also added a compile error for the case OpenHMD is enabled and HMD input is disabled.

This means we now have 3 HMD build options:
* WITH_INPUT_HMD - General HMD support
* WITH_OPENHMD - OpenHMD driver support
* WITH_OPENHMD_DYNLOAD - Dynamic runtime OpenHMD deps loading

Actually, _INPUT_HMD isn't totally correct since it does more than just input, but wanted to stick to naming conventions.
2016-03-29 01:42:40 +02:00
Julian Eisel
85759e74ab Merge branch 'master' into HMD_viewport 2016-03-29 00:00:51 +02:00
Julian Eisel
0b41972dca Fix compiling with WITH_OPENHMD disabled 2016-03-28 23:51:10 +02:00
Julian Eisel
c04031e94f Fix reading HMD window from file causing crash on session start 2016-03-28 23:40:46 +02:00
Julian Eisel
45397af24a Some hacks to disallow toggeling out of fullscreen in an HMD window 2016-03-28 23:02:50 +02:00
Julian Eisel
2f4148d833 Remove unused storage for lens distortion shader
Also removes unneeded button from UI and unneeded RNA defines.
2016-03-28 21:38:04 +02:00
Julian Eisel
c8eb1c93af Fix memory leak in lens distortion shader
Also, the shader itself wasn't drawing previously, which it does now (but still incorrect).
2016-03-28 21:13:45 +02:00
Julian Eisel
8f9b30610b Sync Cycles UI code 2016-03-28 20:55:46 +02:00
Julian Eisel
410b681d1f Option for HMD view lens distortion shader
Enabled by default. Note that shader is currently broken though.
2016-03-28 20:50:56 +02:00
Julian Eisel
b6174113c9 Fix HMD session not ended correctly when closing HMD view during session 2016-03-28 19:09:13 +02:00
Julian Eisel
72e5ee8471 Cleanup: Tweak operator names 2016-03-28 19:06:24 +02:00
Julian Eisel
c5fc10ba3f Add UserPref option to change HMD device
A new file wm_device.c is added with this, think this is good to have.

NOTE: Couldn't really test if changing device actually works as I don't have one. Without a device available everything seems to work though.
2016-03-28 15:15:41 +02:00
Julian Eisel
03e8afdb8d Option to request interocular distance from HMD driver
Adds a new camera option to request the interocular distance (IPD) from the HMD device/driver. It's still an open design question if it's even worth to support a custom distance though.

Also hides convergence options for HMD mode, not sure if those are needed.
2016-03-28 12:43:11 +02:00
Julian Eisel
2d57a89629 Show option for interocular distance for HMD mode
Just as for stereo 3D, available in properties editor, camera context.
2016-03-27 15:00:52 +02:00
Julian Eisel
f83eba6011 Merge branch 'master' into HMD_viewport 2016-03-27 14:09:22 +02:00
Julian Eisel
367b6f1646 Merge branch 'master' into HMD_viewport 2016-03-26 01:16:44 +01:00
c0ddaefb5d HMD: Cleanup of CMake file 2016-03-25 10:42:03 +01:00
58568d1bd3 HMD: Add support of lazil loading udev library
This way we can statically link against hidapi libraries but dont'
require static linking against udev or even having specific ABI
version of this library installed on the client machine.

For now the following libraries will try to be loaded:
  libudev.so, libudev.so.0, libudev.so.1 and libudev.so.2

Not future proof since it might be version 3 of udev releases
eventually, good enough for the beginning. We can simply do a
for-loop to query like 100 of ABIs.

Udev wrangler is a bit different from other wranglers we've got,
it has wrapper functions around dlopen-ed symbols, so you can't
check directly if function was loaded or not, but this is the
only way to make external libraries working fine with wrangler
without need of re-compiling the library.
2016-03-25 10:31:10 +01:00
b811750153 HMD: Quick and dirty way to make sort of portable builds on Linux
It will require having libudev.so.1 which isn't ideal but should work for
most distros for now.

Will be worked around later with udev wrangler.
2016-03-24 20:01:16 +01:00
Julian Eisel
9f145cd1b4 Merge branch 'master' into HMD_viewport 2016-03-22 01:26:07 +01:00
Julian Eisel
0751953efd Option for HMD view shading mode 2016-03-22 01:25:01 +01:00
ad502106e4 - Fixed correct event polling for all operating systems
- Fixed up openhmd cmake for windows builds
2016-03-18 17:18:46 +01:00
Julian Eisel
9e1583a0a9 Fix inner manipulator circle not aligned to viewplane 2016-03-18 03:12:12 +01:00
d8239304de Open/close HMD device based on session status 2016-03-18 03:07:40 +01:00
Julian Eisel
d04b6a7cda Fix anaglyph viewport drawing with HMD view open 2016-03-17 23:13:34 +01:00
Julian Eisel
49d9131ebd Fix stopping session not exiting fullscreen 2016-03-17 22:58:42 +01:00
Julian Eisel
599355304d Fix camera not being reset when stopping session by closing HMD window 2016-03-17 22:53:57 +01:00
Julian Eisel
5a8e1c28c8 Reset camera on HMD session end
Added utility functions for getting/setting rotation from quaterion.
2016-03-17 22:50:00 +01:00
134be85218 Fixed memory addressing, should work on every system now 2016-03-17 22:03:13 +01:00
3609e8868c Added check for nan events from OpenHMD 2016-03-17 21:05:45 +01:00
Julian Eisel
53d36ad280 All camera rotation modes work now 2016-03-17 20:38:05 +01:00
12ee739cbc Fixed warnings for compiling OpenHMD, added static flag for windows compile 2016-03-17 20:06:05 +01:00
Julian Eisel
e56fda407c Fix: Image editor window opened when trying to open UserPref window 2016-03-17 18:48:20 +01:00
Julian Eisel
85cde2a444 Fix start session button not grayed out if HMD window was closed using window handlers 2016-03-17 18:38:28 +01:00
Julian Eisel
9c4e06fcc4 Make HMD session non-modal and move it to WM level 2016-03-17 18:14:56 +01:00
062d66156b Expanded OpenHMDManager with additional features 2016-03-17 18:04:07 +01:00
b7ff6efaf2 Fixed hmd event despatching for all operating systems 2016-03-17 17:24:45 +01:00
Julian Eisel
38c6437df7 Use initial camera rotation as starting rotation for HMD
We have to store the previous orientation quaternion so we can get the delta rotation to apply to the object. For now I added a global variable - ugly but works ;)

Currently, you have to set the camera to use quaternion rotation mode, others aren't really usable yet.
2016-03-17 15:56:44 +01:00
53d1c4ed05 Added compile static to OpenHMD cmake on windows 2016-03-17 15:46:48 +01:00
fcaf81cf2d Moved updating the OpenHMD events in the ghost system to a GHOST_System base class wich get called by the derived for OS independent updating 2016-03-17 15:24:27 +01:00
Julian Eisel
98535f578a Draw second camera with offset (actual 3D effect)
We're simply reusing stereo 3D pipeline here.
2016-03-17 00:17:45 +01:00
Julian Eisel
13d06fa38b Fix viewplane drawn with wrong offset 2016-03-17 00:15:49 +01:00
Julian Eisel
164a1af8cd Use a more common way to open the HMD window 2016-03-16 20:18:57 +01:00
f35c1a339d Added OpenHMD in the build structure, uses WITH_OPENHMD so it can be disabled
Has a requirement on libhidapi, cmake checks for that (should be added to install-deps)
2016-03-16 19:48:05 +01:00
Julian Eisel
a9d0ca72c6 Fix cycles not drawing correct settings for HMD UI 2016-03-16 17:24:32 +01:00
Julian Eisel
b0f91cc221 Merge remote-tracking branch 'github/vr_experiments' into HMD_viewport 2016-03-16 16:52:56 +01:00
Julian Eisel
c3b1c5d026 Merge remote-tracking branch 'github/vr_experiments' into HMD_viewport 2016-03-16 16:09:39 +01:00
Julian Eisel
1863ebcacc Fix outliner not recieving events while HMD session is running 2016-03-11 18:28:08 +01:00
Julian Eisel
5ff399d69a Let button to open HMD window close the win if it's already opened 2016-03-11 18:10:18 +01:00
Julian Eisel
30647c0d5c Custom title for HMD window ("Blender HMD View") 2016-03-11 17:03:45 +01:00
Julian Eisel
5ec1249769 Store HMD Window in Window Manager, avoids lookups and screen flag 2016-03-11 16:25:27 +01:00
Julian Eisel
a3d4644996 UI: Minor adjustments 2016-03-11 14:56:12 +01:00
163e978be1 Fixed lens distortion orientation 2016-03-11 06:24:11 +01:00
Julian Eisel
4f38d44eb2 Fix HMD updating even if HMD session is not running 2016-03-11 04:55:56 +01:00
Julian Eisel
cde072b618 Cleanup: Style, removed debug prints 2016-03-11 04:55:56 +01:00
713829c8e4 Merge branch 'vr_experiments' of https://github.com/julianeisel/blender into vr_experiments 2016-03-11 04:46:52 +01:00
e806f478e5 Finished lens distortion shader, removed some unused variables and cleaned up a bit 2016-03-11 04:45:52 +01:00
Julian Eisel
5b8c1da845 Fix HMD update events missing window 2016-03-11 04:43:33 +01:00
Julian Eisel
b8d2c0da47 Allow cursor to be in any window without stopping HMD update 2016-03-11 04:18:48 +01:00
Julian Eisel
c5a75b8647 Fix modal HMD session handler only called while cursor is in main window 2016-03-11 03:30:19 +01:00
Julian Eisel
409154f1f8 Don't allow to open multiple HMD views
And cleanup.
2016-03-11 03:24:23 +01:00
Julian Eisel
994e0b04d9 Fix missing play button 2016-03-11 03:17:52 +01:00
Julian Eisel
e4bc3bac37 Use modal handler for HMD session
Also some cleanup.
2016-03-11 03:05:14 +01:00
Julian Eisel
fe520b7688 Initial side-by-side HMD view support 2016-03-11 01:32:07 +01:00
d737b41a47 Added lens distortion glsl shader for use with HMD (Head Mounted Display) functionality
NOTE: Still has some debug information and test buttons
2016-03-10 20:02:02 +01:00
Julian Eisel
759be70ab4 Couple of fixes and make stuff working 2016-03-10 07:25:06 +01:00
Julian Eisel
8b701bb913 Hook up HMD with camera 2016-03-10 06:22:54 +01:00
Julian Eisel
764a878938 Get operator to open HMD window to work 2016-03-10 03:58:09 +01:00
Galadus
408cbe918b minor changes
ui patches copied from Severin
2016-03-10 01:38:26 +01:00
Galadus
57424a2401 Added OpenHMD Ghost manager
Added OpenHMD Ghost event
Added OpenHMD windowmanager event type for vr camera transform updates
Began integration if the OpenHMDManager with the ghost system (only updated from the GHOST_SystemX11 for now)
2016-03-09 21:44:53 +01:00
142 changed files with 11238 additions and 521 deletions

View File

@@ -371,6 +371,13 @@ if(WIN32)
option(WITH_INPUT_IME "Enable Input Method Editor (IME) for complex Asian character input" ON)
endif()
option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ${_init_INPUT_NDOF})
# HMD - actually not really input, there's also some other stuff for it
option(WITH_INPUT_HMD "Enable HMD support in Blender (Head Mounted Displays for VR support)" ON)
option(WITH_OPENHMD "Enable OpenHMD driver library" ON)
option(WITH_OPENHMD_DYNLOAD "Dynamically load OpenHMD dependencies at runtime" OFF)
mark_as_advanced(WITH_OPENHMD_DYNLOAD)
option(WITH_RAYOPTIMIZATION "Enable use of SIMD (SSE) optimizations for the raytracer" ON)
if(UNIX AND NOT APPLE)
option(WITH_INSTALL_PORTABLE "Install redistributeable runtime, otherwise install into CMAKE_INSTALL_PREFIX" ON)
@@ -709,6 +716,15 @@ if(WITH_PYTHON_MODULE AND WITH_PYTHON_INSTALL)
message(FATAL_ERROR "WITH_PYTHON_MODULE requires WITH_PYTHON_INSTALL to be OFF")
endif()
if(WITH_INPUT_HMD AND NOT WITH_OPENHMD)
message(WARNING "WITH_INPUT_HMD is enabled, but OpenHMD driver (WITH_OPENHMD) is disabled. "
"Only a limited set of HMD features will be available.")
endif()
if(WITH_OPENHMD AND NOT WITH_INPUT_HMD)
message(FATAL_ERROR "WITH_OPENHMD requires WITH_INPUT_HMD")
endif()
# may as well build python module without a UI
if(WITH_PYTHON_MODULE)

View File

@@ -30,13 +30,13 @@ with-all,with-opencollada,\
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,\
force-all,force-python,force-numpy,force-boost,\
force-ocio,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
force-ffmpeg,force-opencollada,force-alembic,\
force-ffmpeg,force-opencollada,force-alembic,force-hidapi\
build-all,build-python,build-numpy,build-boost,\
build-ocio,build-openexr,build-oiio,build-llvm,build-osl,build-osd,build-openvdb,\
build-ffmpeg,build-opencollada,build-alembic,\
build-ffmpeg,build-opencollada,build-alembic,build-hidapi\
skip-python,skip-numpy,skip-boost,\
skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,skip-openvdb,\
skip-ffmpeg,skip-opencollada,skip-alembic \
skip-ffmpeg,skip-opencollada,skip-alembic,skip-hidapi \
-- "$@" \
)
@@ -182,6 +182,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--build-ffmpeg
Force the build of FFMpeg.
--build-hidapi
Force the build of hidapi.
Note about the --build-foo options:
* They force the script to prefer building dependencies rather than using available packages.
This may make things simpler and allow working around some distribution bugs, but on the other hand it will
@@ -234,6 +237,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--force-ffmpeg
Force the rebuild of FFMpeg.
--force-hidapi
Force the rebuild of hidapi.
Note about the --force-foo options:
* They obviously only have an effect if those libraries are built by this script
(i.e. if there is no available and satisfactory package)!
@@ -277,7 +283,10 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
Unconditionally skip OpenCOLLADA installation/building.
--skip-ffmpeg
Unconditionally skip FFMpeg installation/building.\""
Unconditionally skip FFMpeg installation/building.
--skip-hidapi
Unconditionally skip hidapi installation/building.\""
##### Main Vars #####
@@ -399,6 +408,12 @@ MP3LAME_DEV=""
OPENJPEG_USE=false
OPENJPEG_DEV=""
HIDAPI_VERSION="0.8.0"
HIDAPI_VERSION_MIN="0.8.0"
HIDAPI_FORCE_BUILD=false
HIDAPI_FORCE_REBUILD=false
HIDAPI_SKIP=false
# Whether to use system GLEW or not (OpenSubDiv needs recent glew to work).
NO_SYSTEM_GLEW=false
@@ -597,6 +612,9 @@ while true; do
--build-alembic)
ALEMBIC_FORCE_BUILD=true; shift; continue
;;
--build-hidapi)
HIDAPI_FORCE_BUILD=true; shift; continue
;;
--force-all)
PYTHON_FORCE_REBUILD=true
NUMPY_FORCE_REBUILD=true
@@ -611,6 +629,7 @@ while true; do
OPENCOLLADA_FORCE_REBUILD=true
FFMPEG_FORCE_REBUILD=true
ALEMBIC_FORCE_REBUILD=true
HIDAPI_FORCE_REBUILD=true
shift; continue
;;
--force-python)
@@ -654,6 +673,9 @@ while true; do
--force-alembic)
ALEMBIC_FORCE_REBUILD=true; shift; continue
;;
--force-hidapi)
HIDAPI_FORCE_REBUILD=true; shift; continue
;;
--skip-python)
PYTHON_SKIP=true; shift; continue
;;
@@ -693,6 +715,9 @@ while true; do
--skip-alembic)
ALEMBIC_SKIP=true; shift; continue
;;
--skip-hidapi)
HIDAPI_SKIP=true; shift; continue
;;
--)
# no more arguments to parse
break
@@ -791,6 +816,8 @@ OPENCOLLADA_REPO_BRANCH="master"
FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
HIDAPI_SOURCE=( "https://github.com/signal11/hidapi/archive/hidapi-0.8.0-rc1.tar.gz" )
CXXFLAGS_BACK=$CXXFLAGS
if [ "$USE_CXX11" = true ]; then
WARNING "You are trying to use c++11, this *should* go smoothely with any very recent distribution
@@ -839,7 +866,8 @@ You may also want to build them yourself (optional ones are [between brackets]):
* [OpenSubDiv $OSD_VERSION_MIN] (from $OSD_SOURCE_REPO, branch $OSD_SOURCE_REPO_BRANCH, commit $OSD_SOURCE_REPO_UID).
* [OpenVDB $OPENVDB_VERSION_MIN] (from $OPENVDB_SOURCE), [Blosc $OPENVDB_BLOSC_VERSION] (from $OPENVDB_BLOSC_SOURCE).
* [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).
* [Alembic $ALEMBIC_VERSION] (from $ALEMBIC_SOURCE).\""
* [Alembic $ALEMBIC_VERSION] (from $ALEMBIC_SOURCE).
* [HIDAPI $HIDAPI_VERSION] (from $HIDAPI_SOURCE).\""
if [ "$DO_SHOW_DEPS" = true ]; then
PRINT ""
@@ -2511,6 +2539,75 @@ compile_FFmpeg() {
fi
}
#### Build HIDAPI ####
_init_hidapi() {
_src=$SRC/hidapi-$HIDAPI_VERSION
_inst=$INST/hidapi-$HIDAPI_VERSION
_inst_shortcut=$INST/hidapi
}
clean_hidapi() {
_init_hidapi
_clean
}
compile_hidapi() {
if [ "$NO_BUILD" = true ]; then
WARNING "--no-build enabled, HIDAPI will not be compiled!"
return
fi
# To be changed each time we make edits that would modify the compiled result!
hidapi_magic=1
_init_hidapi
# Clean install if needed!
magic_compile_check hidapi-$HIDAPI_VERSION $hidapi_magic
if [ $? -eq 1 -o "$HIDAPI_FORCE_REBUILD" = true ]; then
clean_hidapi
fi
if [ ! -d $_inst ]; then
INFO "Building hidapi-$HIDAPI_VERSION"
prepare_opt
if [ ! -d $_src -o true ]; then
mkdir -p $SRC
download HIDAPI_SOURCE[@] "$_src.tar.gz"
INFO "Unpacking hidapi-$HIDAPI_VERSION"
tar -C $SRC --transform "s,(/?)hidapi-[^/]*(.*),\1hidapi-$HIDAPI_VERSION\2,x" -xf $_src.tar.gz
fi
cd $_src
./bootstrap
./configure --prefix=$_inst
make -j$THREADS install
make clean
if [ -d $_inst ]; then
_create_inst_shortcut
else
ERROR "hidapi-$HIDAPI_VERSION failed to compile, exiting"
exit 1
fi
magic_compile_set hidapi-$HIDAPI_VERSION $hidapi_magic
cd $CWD
INFO "Done compiling hidapi-$HIDAPI_VERSION!"
else
INFO "Own hidapi-$HIDAPI_VERSION is up to date, nothing to do!"
INFO "If you want to force rebuild of this lib, use the --force-hidapi option."
fi
run_ldconfig "hidapi"
}
#### Install on DEB-like ####
get_package_version_DEB() {
@@ -2982,6 +3079,34 @@ install_DEB() {
compile_FFmpeg
fi
fi
PRINT ""
_do_compile_hidapi=false
if [ "$HIDAPI_SKIP" = true ]; then
WARNING "Skipping hidapi installation, as requested..."
elif [ "$HIDAPI_FORCE_BUILD" = true ]; then
INFO "Forced hidapi building, as requested..."
_do_compile_hidapi=true
else
check_package_DEB libhidapi-dev
if [ $? -eq 0 ]; then
check_package_version_ge_DEB libhidapi-dev $HIDAPI_VERSION_MIN
if [ $? -eq 0 ]; then
install_packages_DEB libhidapi-dev
clean_hidapi
else
_do_compile_hidapi=true
fi
else
_do_compile_hidapi=true
fi
fi
if [ "$_do_compile_hidapi" = true ]; then
install_packages_DEB libudev-dev libusb-1.0-0-dev
compile_hidapi
fi
}
@@ -3523,6 +3648,33 @@ install_RPM() {
compile_FFmpeg
fi
fi
PRINT ""
_do_compile_hidapi=false
if [ "$HIDAPI_SKIP" = true ]; then
WARNING "Skipping hidapi installation, as requested..."
elif [ "$HIDAPI_FORCE_BUILD" = true ]; then
INFO "Forced hidapi building, as requested..."
_do_compile_hidapi=true
else
check_package_RPM hidapi-devel
if [ $? -eq 0 ]; then
check_package_version_ge_RPM hidapi-devel $HIDAPI_VERSION_MIN
if [ $? -eq 0 ]; then
install_packages_RPM hidapi-devel
clean_hidapi
else
_do_compile_hidapi=true
fi
else
_do_compile_hidapi=true
fi
fi
if [ "$_do_compile_hidapi" = true ]; then
install_packages_RPM libusbx-devel # No libudev in fedora?
compile_hidapi
fi
}
@@ -3948,6 +4100,33 @@ install_ARCH() {
compile_FFmpeg
fi
fi
PRINT ""
_do_compile_hidapi=false
if [ "$HIDAPI_SKIP" = true ]; then
WARNING "Skipping hidapi installation, as requested..."
elif [ "$HIDAPI_FORCE_BUILD" = true ]; then
INFO "Forced hidapi building, as requested..."
_do_compile_hidapi=true
else
check_package_ARCH hidapi
if [ $? -eq 0 ]; then
check_package_version_ge_ARCH hidapi $HIDAPI_VERSION_MIN
if [ $? -eq 0 ]; then
install_packages_ARCH hidapi
clean_hidapi
else
_do_compile_hidapi=true
fi
else
_do_compile_hidapi=true
fi
fi
if [ "$_do_compile_hidapi" = true ]; then
install_packages_ARCH libusb # No libudev in arch?
compile_hidapi
fi
}
@@ -4111,6 +4290,16 @@ install_OTHER() {
INFO "Forced FFMpeg building, as requested..."
compile_FFmpeg
fi
PRINT ""
_do_compile_hidapi=false
if [ "$HIDAPI_SKIP" = true ]; then
WARNING "Skipping hidapi installation, as requested..."
elif [ "$HIDAPI_FORCE_BUILD" = true ]; then
INFO "Forced hidapi building, as requested..."
compile_hidapi
fi
}
#### Printing User Info ####
@@ -4192,7 +4381,7 @@ print_info() {
_buildargs="-U *SNDFILE* -U *PYTHON* -U *BOOST* -U *Boost*"
_buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CYCLES*"
_buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG* -U *ALEMBIC*"
_buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG* -U *ALEMBIC* -U *OPENHMD* -U *HIDAPI*"
if [ "$USE_CXX11" = true ]; then
_1="-D WITH_CXX11=ON"
@@ -4334,6 +4523,17 @@ print_info() {
fi
fi
if [ "$HIDAPI_SKIP" = false ]; then
_1="-D WITH_OPENHMD=ON"
PRINT " $_1"
_buildargs="$_buildargs $_1"
if [ -d $INST/hidapi ]; then
_1="-D HIDAPI_ROOT_DIR=$INST/hidapi"
PRINT " $_1"
_buildargs="$_buildargs $_1"
fi
fi
PRINT ""
PRINT "Or even simpler, just run (in your blender-source dir):"
PRINT " make -j$THREADS BUILD_CMAKE_ARGS=\"$_buildargs\""

View File

@@ -144,5 +144,14 @@ set(OPENVDB_LIBRARY
CACHE BOOL "" FORCE
)
# OpenHMD
if(GLIBC EQUAL "2.19")
set(HIDAPI_LIBRARY
/usr/lib${MULTILIB}/libhidapi-hidraw.a
CACHE STRING "" FORCE
)
set(WITH_OPENHMD_DYNLOAD ON CACHE BOOL "" FORCE)
endif()
# Additional linking libraries
set(CMAKE_EXE_LINKER_FLAGS "-lrt -static-libstdc++" CACHE STRING "" FORCE)

View File

@@ -0,0 +1,71 @@
# - Find HIDAPI library from http://www.signal11.us/oss/hidapi/
# Find the native HIDAPI includes and library
# This module defines
# HIDAPI_INCLUDE_DIRS, where to find hidapi.h, Set when
# HIDAPI_INCLUDE_DIR is found.
# HIDAPI_LIBRARIES, libraries to link against to use HIDAPI.
# HIDAPI_ROOT_DIR, The base directory to search for HIDAPI.
# This can also be an environment variable.
# HIDAPI_FOUND, If false, do not try to use HIDAPI.
#
# also defined, but not for general use are
# HIDAPI_LIBRARY, where to find the HIDAPI library.
#=============================================================================
# Copyright 2016 Blender Foundation.
#
# 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.
#=============================================================================
# If HIDAPI_ROOT_DIR was defined in the environment, use it.
IF(NOT HIDAPI_ROOT_DIR AND NOT $ENV{HIDAPI_ROOT_DIR} STREQUAL "")
SET(HIDAPI_ROOT_DIR $ENV{HIDAPI_ROOT_DIR})
ENDIF()
SET(_hidapi_SEARCH_DIRS
${HIDAPI_ROOT_DIR}
/usr/local
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt/lib/hidapi
)
FIND_PATH(HIDAPI_INCLUDE_DIR
NAMES
hidapi.h
HINTS
${_hidapi_SEARCH_DIRS}
PATH_SUFFIXES
include/hidapi
)
FIND_LIBRARY(HIDAPI_LIBRARY
NAMES
hidapi hidapi-libusb
HINTS
${_hidapi_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
# Handle the QUIETLY and REQUIRED arguments and set HIDAPI_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(HIDAPI DEFAULT_MSG
HIDAPI_LIBRARY HIDAPI_INCLUDE_DIR)
IF(HIDAPI_FOUND)
SET(HIDAPI_LIBRARIES ${HIDAPI_LIBRARY})
SET(HIDAPI_INCLUDE_DIRS ${HIDAPI_INCLUDE_DIR})
ENDIF(HIDAPI_FOUND)
MARK_AS_ADVANCED(
HIDAPI_INCLUDE_DIR
HIDAPI_LIBRARY
)

View File

@@ -492,6 +492,10 @@ function(setup_liblinks
endif()
endif()
if(WITH_OPENHMD)
target_link_libraries(${target} ${OPENHMD_LIBRARIES} ${HIDAPI_LIBRARY})
endif()
# We put CLEW and CUEW here because OPENSUBDIV_LIBRARIES dpeends on them..
if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV)
target_link_libraries(${target} "extern_clew")
@@ -501,6 +505,9 @@ function(setup_liblinks
target_link_libraries(${target} ${CUDA_CUDA_LIBRARY})
endif()
endif()
if(WITH_OPENHMD AND WITH_OPENHMD_DYNLOAD)
target_link_libraries(${target} "extern_udew")
endif()
target_link_libraries(
${target}
@@ -707,6 +714,10 @@ function(SETUP_BLENDER_SORTED_LIBS)
list(APPEND BLENDER_SORTED_LIBS bf_quicktime)
endif()
if(WITH_OPENHMD)
list(APPEND BLENDER_SORTED_LIBS extern_openhmd)
endif()
if(WITH_MOD_BOOLEAN)
list(APPEND BLENDER_SORTED_LIBS extern_carve)
endif()

View File

@@ -66,7 +66,7 @@ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
list(APPEND PLATFORM_LINKLIBS
ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32
advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp
advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp setupapi
)
if(WITH_INPUT_IME)

View File

@@ -86,6 +86,10 @@ if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV)
endif()
endif()
if(WITH_OPENHMD AND WITH_OPENHMD_DYNLOAD)
add_subdirectory(udew)
endif()
if(WITH_MOD_BOOLEAN)
add_subdirectory(carve)
endif()
@@ -111,3 +115,7 @@ endif()
if(WITH_SDL AND WITH_SDL_DYNLOAD)
add_subdirectory(sdlew)
endif()
if(WITH_OPENHMD)
add_subdirectory(openhmd)
endif()

111
extern/openhmd/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,111 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
src
include
)
set(INC_SYS
)
set(SRC
src/openhmd.c
src/platform-win32.c
src/drv_dummy/dummy.c
src/omath.c
src/platform-posix.c
src/fusion.c
src/queue.c
src/shaders.c
)
# TODO: Either remove this or move to main CMakeLists.txt
OPTION(OPENHMD_DRIVER_OCULUS_RIFT "Oculus Rift DK1, DK2 and CV1" ON)
OPTION(OPENHMD_DRIVER_DEEPOON "Deepoon E2" ON)
OPTION(OPENHMD_DRIVER_PSVR "Sony PSVR" ON)
OPTION(OPENHMD_DRIVER_HTC_VIVE "HTC Vive" ON)
OPTION(OPENHMD_DRIVER_EXTERNAL "External sensor driver" OFF)
OPTION(OPENHMD_DRIVER_ANDROID "General Android driver" OFF)
if(MSVC)
add_definitions(-DOHMD_STATIC)
endif(MSVC)
if(OPENHMD_DRIVER_OCULUS_RIFT)
list(APPEND SRC
src/drv_oculus_rift/rift.c
src/drv_oculus_rift/packet.c
)
add_definitions(-DDRIVER_OCULUS_RIFT)
find_package(HIDAPI REQUIRED)
list(APPEND INC_SYS ${HIDAPI_INCLUDE_DIRS})
endif()
if(OPENHMD_DRIVER_DEEPOON)
list(APPEND SRC
src/drv_deepoon/deepoon.c
src/drv_deepoon/packet.c
)
add_definitions(-DDRIVER_DEEPOON)
find_package(HIDAPI REQUIRED)
list(APPEND INC_SYS ${HIDAPI_INCLUDE_DIRS})
endif()
if(OPENHMD_DRIVER_PSVR)
list(APPEND SRC
src/drv_psvr/psvr.c
src/drv_psvr/packet.c
)
add_definitions(-DDRIVER_PSVR)
find_package(HIDAPI REQUIRED)
list(APPEND INC_SYS ${HIDAPI_INCLUDE_DIRS})
endif()
if(OPENHMD_DRIVER_HTC_VIVE)
list(APPEND SRC
src/drv_htc_vive/vive.c
src/drv_htc_vive/packet.c
)
add_definitions(-DDRIVER_HTC_VIVE)
find_package(HIDAPI REQUIRED)
list(APPEND INC_SYS ${HIDAPI_INCLUDE_DIRS})
endif()
if(OPENHMD_DRIVER_EXTERNAL)
list(APPEND SRC
src/drv_external/external.c
)
add_definitions(-DDRIVER_EXTERNAL)
endif()
if(OPENHMD_DRIVER_ANDROID)
list(APPEND SRC
src/drv_android/android.c
)
add_definitions(-DDRIVER_ANDROID)
endif()
blender_add_lib(extern_openhmd "${SRC}" "${INC}" "${INC_SYS}")

23
extern/openhmd/LICENSE vendored Normal file
View File

@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
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.

9
extern/openhmd/README.md vendored Normal file
View File

@@ -0,0 +1,9 @@
# OpenHMD
This project aims to provide a Free and Open Source API and drivers for immersive technology, such as head mounted displays with built in head tracking.
# License
OpenHMD is released under the permissive Boost Software License (see LICENSE for more information), to make sure it can be linked and distributed with both free and non-free software. While it doesn't require contribution from the users, it is still very appreciated.
# Implemented and maintained by TheOnlyJoey (Joey Ferwerda), contact info@thorwork.org if anything goes wrong

390
extern/openhmd/include/openhmd.h vendored Normal file
View File

@@ -0,0 +1,390 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/**
* \file openhmd.h
* Main header for OpenHMD public API.
**/
#ifndef OPENHMD_H
#define OPENHMD_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#ifdef DLL_EXPORT
#define OHMD_APIENTRY __cdecl
#define OHMD_APIENTRYDLL __declspec( dllexport )
#else
#ifdef OHMD_STATIC
#define OHMD_APIENTRY __cdecl
#define OHMD_APIENTRYDLL
#else
#define OHMD_APIENTRY __cdecl
#define OHMD_APIENTRYDLL __declspec( dllimport )
#endif
#endif
#else
#define OHMD_APIENTRY
#define OHMD_APIENTRYDLL
#endif
/** Maximum length of a string, including termination, in OpenHMD. */
#define OHMD_STR_SIZE 256
/** Return status codes, used for all functions that can return an error. */
typedef enum {
OHMD_S_OK = 0,
OHMD_S_UNKNOWN_ERROR = -1,
OHMD_S_INVALID_PARAMETER = -2,
OHMD_S_UNSUPPORTED = -3,
OHMD_S_INVALID_OPERATION = -4,
/** OHMD_S_USER_RESERVED and below can be used for user purposes, such as errors within ohmd wrappers, etc. */
OHMD_S_USER_RESERVED = -16384,
} ohmd_status;
/** A collection of string value information types, used for getting information with ohmd_list_gets(). */
typedef enum {
OHMD_VENDOR = 0,
OHMD_PRODUCT = 1,
OHMD_PATH = 2,
} ohmd_string_value;
/** A collection of string descriptions, used for getting strings with ohmd_gets(). */
typedef enum {
OHMD_GLSL_DISTORTION_VERT_SRC = 0,
OHMD_GLSL_DISTORTION_FRAG_SRC = 1,
} ohmd_string_description;
/** A collection of float value information types, used for getting and setting information with
ohmd_device_getf() and ohmd_device_setf(). */
typedef enum {
/** float[4] (get): Absolute rotation of the device, in space, as a quaternion (x, y, z, w). */
OHMD_ROTATION_QUAT = 1,
/** float[16] (get): A "ready to use" OpenGL style 4x4 matrix with a modelview matrix for the
left eye of the HMD. */
OHMD_LEFT_EYE_GL_MODELVIEW_MATRIX = 2,
/** float[16] (get): A "ready to use" OpenGL style 4x4 matrix with a modelview matrix for the
right eye of the HMD. */
OHMD_RIGHT_EYE_GL_MODELVIEW_MATRIX = 3,
/** float[16] (get): A "ready to use" OpenGL style 4x4 matrix with a projection matrix for the
left eye of the HMD. */
OHMD_LEFT_EYE_GL_PROJECTION_MATRIX = 4,
/** float[16] (get): A "ready to use" OpenGL style 4x4 matrix with a projection matrix for the
right eye of the HMD. */
OHMD_RIGHT_EYE_GL_PROJECTION_MATRIX = 5,
/** float[3] (get): A 3-D vector representing the absolute position of the device, in space. */
OHMD_POSITION_VECTOR = 6,
/** float[1] (get): Physical width of the device screen in metres. */
OHMD_SCREEN_HORIZONTAL_SIZE = 7,
/** float[1] (get): Physical height of the device screen in metres. */
OHMD_SCREEN_VERTICAL_SIZE = 8,
/** float[1] (get): Physical separation of the device lenses in metres. */
OHMD_LENS_HORIZONTAL_SEPARATION = 9,
/** float[1] (get): Physical vertical position of the lenses in metres. */
OHMD_LENS_VERTICAL_POSITION = 10,
/** float[1] (get): Physical field of view for the left eye in degrees. */
OHMD_LEFT_EYE_FOV = 11,
/** float[1] (get): Physical display aspect ratio for the left eye screen. */
OHMD_LEFT_EYE_ASPECT_RATIO = 12,
/** float[1] (get): Physical field of view for the left right in degrees. */
OHMD_RIGHT_EYE_FOV = 13,
/** float[1] (get): Physical display aspect ratio for the right eye screen. */
OHMD_RIGHT_EYE_ASPECT_RATIO = 14,
/** float[1] (get, set): Physical interpupillary distance of the user in metres. */
OHMD_EYE_IPD = 15,
/** float[1] (get, set): Z-far value for the projection matrix calculations (i.e. drawing distance). */
OHMD_PROJECTION_ZFAR = 16,
/** float[1] (get, set): Z-near value for the projection matrix calculations (i.e. close clipping distance). */
OHMD_PROJECTION_ZNEAR = 17,
/** float[6] (get): Device specific distortion value. */
OHMD_DISTORTION_K = 18,
/**
* float[10] (set): Perform sensor fusion on values from external sensors.
*
* Values are: dt (time since last update in seconds) X, Y, Z gyro, X, Y, Z accelerometer and X, Y, Z magnetometer.
**/
OHMD_EXTERNAL_SENSOR_FUSION = 19,
/** float[4] (get): Universal shader distortion coefficients (PanoTools model <a,b,c,d>. */
OHMD_UNIVERSAL_DISTORTION_K = 20,
/** float[3] (get): Universal shader aberration coefficients (post warp scaling <r,g,b>. */
OHMD_UNIVERSAL_ABERRATION_K = 21,
} ohmd_float_value;
/** A collection of int value information types used for getting information with ohmd_device_geti(). */
typedef enum {
/** int[1] (get): Physical horizontal resolution of the device screen. */
OHMD_SCREEN_HORIZONTAL_RESOLUTION = 0,
/** int[1] (get): Physical vertical resolution of the device screen. */
OHMD_SCREEN_VERTICAL_RESOLUTION = 1,
/** int[1] (get): Get number of events waiting in digital input event queue. */
OHMD_BUTTON_EVENT_COUNT = 2,
/** int[1] (get): Get if the there was an overflow in the event queue causing events to be dropped. */
OHMD_BUTTON_EVENT_OVERFLOW = 3,
/** int[1] (get): Get the number of physical digital input buttons on the device. */
OHMD_BUTTON_COUNT = 4,
/** int[2] (get): Performs an event pop action. Format: [button_index, button_state], where button_state is either OHMD_BUTTON_DOWN or OHMD_BUTTON_UP */
OHMD_BUTTON_POP_EVENT = 5,
} ohmd_int_value;
/** A collection of data information types used for setting information with ohmd_set_data(). */
typedef enum {
/** void* (set): Set void* data for use in the internal drivers. */
OHMD_DRIVER_DATA = 0,
/**
* ohmd_device_properties* (set):
* Set the device properties based on the ohmd_device_properties struct for use in the internal drivers.
*
* This can be used to fill in information about the device internally, such as Android, or for setting profiles.
**/
OHMD_DRIVER_PROPERTIES = 1,
} ohmd_data_value;
typedef enum {
/** int[1] (set, default: 1): Set this to 0 to prevent OpenHMD from creating background threads to do automatic device ticking.
Call ohmd_update(); must be called frequently, at least 10 times per second, if the background threads are disabled. */
OHMD_IDS_AUTOMATIC_UPDATE = 0,
} ohmd_int_settings;
/** Button states for digital input events. */
typedef enum {
/** Button was pressed. */
OHMD_BUTTON_DOWN = 0,
/** Button was released. */
OHMD_BUTTON_UP = 1
} ohmd_button_state;
/** An opaque pointer to a context structure. */
typedef struct ohmd_context ohmd_context;
/** An opaque pointer to a structure representing a device, such as an HMD. */
typedef struct ohmd_device ohmd_device;
/** An opaque pointer to a structure representing arguments for a device. */
typedef struct ohmd_device_settings ohmd_device_settings;
/**
* Create an OpenHMD context.
*
* @return a pointer to an allocated ohmd_context on success or NULL if it fails.
**/
OHMD_APIENTRYDLL ohmd_context* OHMD_APIENTRY ohmd_ctx_create(void);
/**
* Destroy an OpenHMD context.
*
* ohmd_ctx_destroy de-initializes and de-allocates an OpenHMD context allocated with ohmd_ctx_create.
* All devices associated with the context are automatically closed.
*
* @param ctx The context to destroy.
**/
OHMD_APIENTRYDLL void OHMD_APIENTRY ohmd_ctx_destroy(ohmd_context* ctx);
/**
* Get the last error as a human readable string.
*
* If a function taking a context as an argument (ohmd_context "methods") returns non-successfully,
* a human readable error message describing what went wrong can be retrieved with this function.
*
* @param ctx The context to retrieve the error message from.
* @return a pointer to the error message.
**/
OHMD_APIENTRYDLL const char* OHMD_APIENTRY ohmd_ctx_get_error(ohmd_context* ctx);
/**
* Update a context.
*
* Update the values for the devices handled by a context.
*
* If background threads are disabled, this performs tasks like pumping events from the device. The exact details
* are up to the driver but try to call it quite frequently.
* Once per frame in a "game loop" should be sufficient.
* If OpenHMD is handled in a background thread in your program, calling ohmd_ctx_update and then sleeping for 10-20 ms
* is recommended.
*
* @param ctx The context that needs updating.
**/
OHMD_APIENTRYDLL void OHMD_APIENTRY ohmd_ctx_update(ohmd_context* ctx);
/**
* Probe for devices.
*
* Probes for and enumerates supported devices attached to the system.
*
* @param ctx A context with no currently open devices.
* @return the number of devices found on the system.
**/
OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_ctx_probe(ohmd_context* ctx);
/**
* Get string from openhmd.
*
* Gets a string from OpenHMD. This is where non-device specific strings reside.
* This is where the distortion shader sources can be retrieved.
*
* @param type The name of the string to fetch. One of OHMD_GLSL_DISTORTION_FRAG_SRC, and OHMD_GLSL_DISTORTION_FRAG_SRC.
* @return a string with a human readable device name.
**/
OHMD_APIENTRYDLL const char* OHMD_APIENTRY ohmd_gets(ohmd_string_description type);
/**
* Get device description from enumeration list index.
*
* Gets a human readable device description string from a zero indexed enumeration index
* between 0 and (max - 1), where max is the number ohmd_ctx_probe returned
* (i.e. if ohmd_ctx_probe returns 3, valid indices are 0, 1 and 2).
* The function can return three types of data. The vendor name, the product name and
* a driver specific path where the device is attached.
*
* ohmd_ctx_probe must be called before calling ohmd_list_gets.
*
* @param ctx A (probed) context.
* @param index An index, between 0 and the value returned from ohmd_ctx_probe.
* @param type The type of data to fetch. One of OHMD_VENDOR, OHMD_PRODUCT and OHMD_PATH.
* @return a string with a human readable device name.
**/
OHMD_APIENTRYDLL const char* OHMD_APIENTRY ohmd_list_gets(ohmd_context* ctx, int index, ohmd_string_value type);
/**
* Open a device.
*
* Opens a device from a zero indexed enumeration index between 0 and (max - 1)
* where max is the number ohmd_ctx_probe returned (i.e. if ohmd_ctx_probe returns 3,
* valid indices are 0, 1 and 2).
*
* ohmd_ctx_probe must be called before calling ohmd_list_open_device.
*
* @param ctx A (probed) context.
* @param index An index, between 0 and the value returned from ohmd_ctx_probe.
* @return a pointer to an ohmd_device, which represents a hardware device, such as an HMD.
**/
OHMD_APIENTRYDLL ohmd_device* OHMD_APIENTRY ohmd_list_open_device(ohmd_context* ctx, int index);
/**
* Open a device with additional settings provided.
*
* Opens a device from a zero indexed enumeration index between 0 and (max - 1)
* where max is the number ohmd_ctx_probe returned (i.e. if ohmd_ctx_probe returns 3,
* valid indices are 0, 1 and 2).
*
* ohmd_ctx_probe must be called before calling ohmd_list_open_device.
*
* @param ctx A (probed) context.
* @param index An index, between 0 and the value returned from ohmd_ctx_probe.
* @param settings A pointer to a device settings struct.
* @return a pointer to an ohmd_device, which represents a hardware device, such as an HMD.
**/
OHMD_APIENTRYDLL ohmd_device* OHMD_APIENTRY ohmd_list_open_device_s(ohmd_context* ctx, int index, ohmd_device_settings* settings);
/**
* Specify int settings in a device settings struct.
*
* @param settings The device settings struct to set values to.
* @param key The specefic setting you wish to set.
* @param value A pointer to an int or int array (containing the expected number of elements) with the value(s) you wish to set.
**/
OHMD_APIENTRYDLL ohmd_status OHMD_APIENTRY ohmd_device_settings_seti(ohmd_device_settings* settings, ohmd_int_settings key, const int* val);
/**
* Create a device settings instance.
*
* @param ctx A pointer to a valid ohmd_context.
* @return a pointer to an allocated ohmd_context on success or NULL if it fails.
**/
OHMD_APIENTRYDLL ohmd_device_settings* OHMD_APIENTRY ohmd_device_settings_create(ohmd_context* ctx);
/**
* Destroy a device settings instance.
*
* @param ctx The device settings instance to destroy.
**/
OHMD_APIENTRYDLL void OHMD_APIENTRY ohmd_device_settings_destroy(ohmd_device_settings* settings);
/**
* Close a device.
*
* Closes a device opened by ohmd_list_open_device. Note that ohmd_ctx_destroy automatically closes any open devices
* associated with the context being destroyed.
*
* @param device The open device.
* @return 0 on success, <0 on failure.
**/
OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_close_device(ohmd_device* device);
/**
* Get a floating point value from a device.
*
*
* @param device An open device to retrieve the value from.
* @param type What type of value to retrieve, see ohmd_float_value section for more information.
* @param[out] out A pointer to a float, or float array where the retrieved value should be written.
* @return 0 on success, <0 on failure.
**/
OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_device_getf(ohmd_device* device, ohmd_float_value type, float* out);
/**
* Set a floating point value for a device.
*
* @param device An open device to set the value in.
* @param type What type of value to set, see ohmd_float_value section for more information.
* @param in A pointer to a float, or float array where the new value is stored.
* @return 0 on success, <0 on failure.
**/
OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_device_setf(ohmd_device* device, ohmd_float_value type, const float* in);
/**
* Get an integer value from a device.
*
* @param device An open device to retrieve the value from.
* @param type What type of value to retrieve, ohmd_int_value section for more information.
* @param[out] out A pointer to an integer, or integer array where the retrieved value should be written.
* @return 0 on success, <0 on failure.
**/
OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_device_geti(ohmd_device* device, ohmd_int_value type, int* out);
/**
* Set an integer value for a device.
*
* @param device An open device to set the value in.
* @param type What type of value to set, see ohmd_float_value section for more information.
* @param in A pointer to a int, or int array where the new value is stored.
* @return 0 on success, <0 on failure.
**/
OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_device_seti(ohmd_device* device, ohmd_int_value type, const int* in);
/**
* Set an void* data value for a device.
*
* @param device An open device to set the value in.
* @param type What type of value to set, see ohmd_float_value section for more information.
* @param in A pointer to the void* casted object.
* @return 0 on success, <0 on failure.
**/
OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_device_set_data(ohmd_device* device, ohmd_data_value type, const void* in);
#ifdef __cplusplus
}
#endif
#endif

335
extern/openhmd/src/drv_android/android.c vendored Normal file
View File

@@ -0,0 +1,335 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Copyright (C) 2015 Joey Ferwerda
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Android Driver */
#include "android.h"
#ifdef __ANDROID__
#include <android/sensor.h>
#endif // __ANDROID__
typedef struct {
ohmd_device base;
fusion sensor_fusion;
//Android specific
#ifdef __ANDROID__
android_app* state;
ASensorManager* sensorManager;
const ASensor* accelerometerSensor;
const ASensor* gyroscopeSensor;
ASensorEventQueue* sensorEventQueue;
AAssetManager* assetMgr;
short firstRun;
#endif
} android_priv;
//Forward decelerations
static void set_android_properties(ohmd_device* device, ohmd_device_properties* props);
static void nofusion_init(fusion* me);
static void nofusion_update(fusion* me, float dt, const vec3f* accel);
//Static variable for timeDelta;
static float timestamp;
//Android callback for the sensor event queue
static int android_sensor_callback(int fd, int events, void* data)
{
android_priv* priv = (android_priv*)data;
if (priv->accelerometerSensor != NULL)
{
ASensorEvent event;
vec3f gyro;
vec3f accel;
vec3f mag;
float lastevent_timestamp;
while (ASensorEventQueue_getEvents(priv->sensorEventQueue, &event, 1) > 0)
{
if (event.type == ASENSOR_TYPE_ACCELEROMETER)
{
accel.x = event.acceleration.y;
accel.y = -event.acceleration.x;
accel.z = event.acceleration.z;
}
if (event.type == ASENSOR_TYPE_GYROSCOPE)
{
gyro.x = -event.data[1];
gyro.y = event.data[0];
gyro.z = event.data[2];
}
///TODO: Implement mag when available
mag.x = 0.0f;
mag.y = 0.0f;
mag.z = 0.0f;
lastevent_timestamp = event.timestamp;
}
//apply data to the fusion
float dT = 0.0f;
if (timestamp != 0)
dT= (lastevent_timestamp - timestamp) * (1.0f / 1000000000.0f);
//Check if accelerometer only fallback is required
if (!priv->gyroscopeSensor)
nofusion_update(&priv->sensor_fusion, dT, &accel);
else
ofusion_update(&priv->sensor_fusion, dT, &gyro, &accel, &mag); //default
timestamp = lastevent_timestamp;
}
return 1;
}
static void update_device(ohmd_device* device)
{
android_priv* priv = (android_priv*)device;
if(!priv->state)
return;
//We need this since during init the android_app state is not set yet
if (priv->firstRun == 1)
{
priv->sensorEventQueue = ASensorManager_createEventQueue(priv->sensorManager,
priv->state->looper, LOOPER_ID_USER, android_sensor_callback, (void*)priv);
// Start sensors in case this was not done already.
if (priv->accelerometerSensor != NULL)
{
ASensorEventQueue_enableSensor(priv->sensorEventQueue, priv->accelerometerSensor);
// We'd like to get 60 events per second (in us).
ASensorEventQueue_setEventRate(priv->sensorEventQueue, priv->accelerometerSensor, (1000L/60)*1000);
}
if (priv->gyroscopeSensor != NULL)
{
ASensorEventQueue_enableSensor(priv->sensorEventQueue, priv->gyroscopeSensor);
// We'd like to get 60 events per second (in us).
ASensorEventQueue_setEventRate(priv->sensorEventQueue, priv->gyroscopeSensor, (1000L/60)*1000);
}
priv->firstRun = 0;
}
}
static int getf(ohmd_device* device, ohmd_float_value type, float* out)
{
android_priv* priv = (android_priv*)device;
switch(type){
case OHMD_ROTATION_QUAT: {
*(quatf*)out = priv->sensor_fusion.orient;
break;
}
case OHMD_POSITION_VECTOR:
out[0] = out[1] = out[2] = 0;
break;
case OHMD_DISTORTION_K:
// TODO this should be set to the equivalent of no distortion
memset(out, 0, sizeof(float) * 6);
break;
default:
ohmd_set_error(priv->base.ctx, "invalid type given to getf (%d)", type);
return -1;
break;
}
return 0;
}
static int set_data(ohmd_device* device, ohmd_data_value type, void* in)
{
android_priv* priv = (android_priv*)device;
switch(type){
case OHMD_DRIVER_DATA: {
priv->state = (android_app*)in;
break;
}
case OHMD_DRIVER_PROPERTIES: {
set_android_properties(device, (ohmd_device_properties*)in);
break;
}
default:
ohmd_set_error(priv->base.ctx, "invalid type given to set_data (%i)", type);
return -1;
break;
}
return 0;
}
static void close_device(ohmd_device* device)
{
LOGD("closing Android device");
free(device);
}
static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
{
android_priv* priv = ohmd_alloc(driver->ctx, sizeof(android_priv));
if(!priv)
return NULL;
// Set default device properties
ohmd_set_default_device_properties(&priv->base.properties);
// Set device properties
//TODO: Get information from android about device
//TODO: Use profile string to set default for a particular device (Durovis, VR One etc)
priv->base.properties.hsize = 0.149760f;
priv->base.properties.vsize = 0.093600f;
priv->base.properties.hres = 1280;
priv->base.properties.vres = 800;
priv->base.properties.lens_sep = 0.063500f;
priv->base.properties.lens_vpos = 0.046800f;
priv->base.properties.fov = DEG_TO_RAD(125.5144f);
priv->base.properties.ratio = (1280.0f / 800.0f) / 2.0f;
// calculate projection eye projection matrices from the device properties
ohmd_calc_default_proj_matrices(&priv->base.properties);
// set up device callbacks
priv->base.update = update_device;
priv->base.close = close_device;
priv->base.getf = getf;
priv->base.set_data = set_data;
//init Android sensors
priv->sensorManager = ASensorManager_getInstance();
priv->accelerometerSensor = ASensorManager_getDefaultSensor(priv->sensorManager,
ASENSOR_TYPE_ACCELEROMETER);
priv->gyroscopeSensor = ASensorManager_getDefaultSensor(priv->sensorManager,
ASENSOR_TYPE_GYROSCOPE);
priv->firstRun = 1; //need this since ASensorManager_createEventQueue requires a set android_app*
//Check if accelerometer only fallback is required
if (!priv->gyroscopeSensor)
nofusion_init(&priv->sensor_fusion);
else
ofusion_init(&priv->sensor_fusion); //Default when all sensors are available
return (ohmd_device*)priv;
}
static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
{
ohmd_device_desc* desc = &list->devices[list->num_devices++];
strcpy(desc->driver, "OpenHMD Generic Android Driver");
strcpy(desc->vendor, "OpenHMD");
strcpy(desc->product, "Android Device");
strcpy(desc->path, "(none)");
desc->driver_ptr = driver;
}
static void destroy_driver(ohmd_driver* drv)
{
LOGD("shutting down Android driver");
free(drv);
}
ohmd_driver* ohmd_create_android_drv(ohmd_context* ctx)
{
ohmd_driver* drv = ohmd_alloc(ctx, sizeof(ohmd_driver));
if(!drv)
return NULL;
drv->get_device_list = get_device_list;
drv->open_device = open_device;
drv->destroy = destroy_driver;
drv->ctx = ctx;
return drv;
}
/* Android specific functions */
static void nofusion_update(fusion* me, float dt, const vec3f* accel)
{
//avg raw accel data to smooth jitter, and normalise
ofq_add(&me->accel_fq, accel);
vec3f accel_mean;
ofq_get_mean(&me->accel_fq, &accel_mean);
vec3f acc_n = accel_mean;
ovec3f_normalize_me(&acc_n);
//reference vectors for axis-angle
vec3f xyzv[3] = {
{1,0,0},
{0,1,0},
{0,0,1}
};
quatf roll, pitch;
//pitch is rot around x, based on gravity in z and y axes
oquatf_init_axis(&pitch, xyzv+0, atan2f(-acc_n.z, -acc_n.y));
//roll is rot around z, based on gravity in x and y axes
//note we need to invert the values when the device is upside down (y < 0) for proper results
oquatf_init_axis(&roll, xyzv+2, acc_n.y < 0 ? atan2f(-acc_n.x, -acc_n.y) : atan2f(acc_n.x, acc_n.y));
quatf or = {0,0,0,1};
//order of applying is yaw-pitch-roll
//yaw is not possible using only accel
oquatf_mult_me(&or, &pitch);
oquatf_mult_me(&or, &roll);
me->orient = or;
}
//shorter buffers for frame smoothing
static void nofusion_init(fusion* me)
{
memset(me, 0, sizeof(fusion));
me->orient.w = 1.0f;
ofq_init(&me->mag_fq, 10);
ofq_init(&me->accel_fq, 10);
ofq_init(&me->ang_vel_fq, 10);
me->flags = FF_USE_GRAVITY;
me->grav_gain = 0.05f;
}
static void set_android_properties(ohmd_device* device, ohmd_device_properties* props)
{
android_priv* priv = (android_priv*)device;
priv->base.properties.hsize = props->hsize;
priv->base.properties.vsize = props->vsize;
priv->base.properties.hres = props->hres;
priv->base.properties.vres = props->vres;
priv->base.properties.lens_sep = props->lens_sep;
priv->base.properties.lens_vpos = props->lens_vpos;
priv->base.properties.fov = DEG_TO_RAD(props->fov);
priv->base.properties.ratio = props->ratio;
}
static void set_android_profile(ohmd_driver* driver, android_hmd_profile profile)
{
switch(profile){
case DROID_DUROVIS_OPEN_DIVE: break;
case DROID_DUROVIS_DIVE_5: break;
case DROID_DUROVIS_DIVE_7: break;
case DROID_CARL_ZEISS_VRONE: break;
case DROID_GOOGLE_CARDBOARD: break;
case DROID_NONE:
default: break;
}
}

View File

@@ -0,0 +1,91 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Copyright (C) 2015 Joey Ferwerda
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Android Driver */
#ifndef ANDROID_H
#define ANDROID_H
#include "../openhmdi.h"
typedef enum {
DROID_DUROVIS_OPEN_DIVE = 1,
DROID_DUROVIS_DIVE_5 = 2,
DROID_DUROVIS_DIVE_7 = 3,
DROID_CARL_ZEISS_VRONE = 4,
DROID_GOOGLE_CARDBOARD = 5,
DROID_NONE = 0,
} android_hmd_profile;
//Android copy-paste from android_native_app_glue to be able to cast data to something useful
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <android/configuration.h>
#include <android/looper.h>
#include <android/native_activity.h>
struct android_app;
struct android_poll_source {
int32_t id;
struct android_app* app;
void (*process)(struct android_app* app, struct android_poll_source* source);
};
typedef struct android_app {
void* userData;
void (*onAppCmd)(struct android_app* app, int32_t cmd);
int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
ANativeActivity* activity;
AConfiguration* config;
void* savedState;
size_t savedStateSize;
ALooper* looper;
AInputQueue* inputQueue;
ANativeWindow* window;
ARect contentRect;
int activityState;
int destroyRequested;
pthread_mutex_t mutex;
pthread_cond_t cond;
int msgread;
int msgwrite;
pthread_t thread;
struct android_poll_source cmdPollSource;
struct android_poll_source inputPollSource;
int running;
int stateSaved;
int destroyed;
int redrawNeeded;
AInputQueue* pendingInputQueue;
ANativeWindow* pendingWindow;
ARect pendingContentRect;
} android_app;
enum {
LOOPER_ID_MAIN = 1,
LOOPER_ID_INPUT = 2,
LOOPER_ID_USER = 3
};
#endif // ANDROID_H

332
extern/openhmd/src/drv_deepoon/deepoon.c vendored Normal file
View File

@@ -0,0 +1,332 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Deepoon Driver - HID/USB Driver Implementation */
#include <stdlib.h>
#include <hidapi.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include "deepoon.h"
#define TICK_LEN (1.0f / 1000000.0f) // 1000 Hz ticks
#define KEEP_ALIVE_VALUE (10 * 1000)
#define SETFLAG(_s, _flag, _val) (_s) = ((_s) & ~(_flag)) | ((_val) ? (_flag) : 0)
#define DEEPOON_ID 0x0483
#define DEEPOON_HMD 0x5750
typedef struct {
ohmd_device base;
hid_device* handle;
pkt_sensor_range sensor_range;
pkt_sensor_display_info display_info;
rift_coordinate_frame coordinate_frame, hw_coordinate_frame;
pkt_sensor_config sensor_config;
pkt_tracker_sensor sensor;
double last_keep_alive;
fusion sensor_fusion;
vec3f raw_mag, raw_accel, raw_gyro;
} rift_priv;
static rift_priv* rift_priv_get(ohmd_device* device)
{
return (rift_priv*)device;
}
static int get_feature_report(rift_priv* priv, rift_sensor_feature_cmd cmd, unsigned char* buf)
{
memset(buf, 0, FEATURE_BUFFER_SIZE);
buf[0] = (unsigned char)cmd;
return hid_get_feature_report(priv->handle, buf, FEATURE_BUFFER_SIZE);
}
static int send_feature_report(rift_priv* priv, const unsigned char *data, size_t length)
{
return hid_send_feature_report(priv->handle, data, length);
}
static void set_coordinate_frame(rift_priv* priv, rift_coordinate_frame coordframe)
{
priv->coordinate_frame = coordframe;
// set the RIFT_SCF_SENSOR_COORDINATES in the sensor config to match whether coordframe is hmd or sensor
SETFLAG(priv->sensor_config.flags, RIFT_SCF_SENSOR_COORDINATES, coordframe == RIFT_CF_SENSOR);
// encode send the new config to the Rift
unsigned char buf[FEATURE_BUFFER_SIZE];
int size = dp_encode_sensor_config(buf, &priv->sensor_config);
if(send_feature_report(priv, buf, size) == -1){
ohmd_set_error(priv->base.ctx, "send_feature_report failed in set_coordinate frame");
return;
}
// read the state again, set the hw_coordinate_frame to match what
// the hardware actually is set to just incase it doesn't stick.
size = get_feature_report(priv, RIFT_CMD_SENSOR_CONFIG, buf);
if(size <= 0){
LOGW("could not set coordinate frame");
priv->hw_coordinate_frame = RIFT_CF_HMD;
return;
}
priv->hw_coordinate_frame = (priv->sensor_config.flags & RIFT_SCF_SENSOR_COORDINATES) ? RIFT_CF_SENSOR : RIFT_CF_HMD;
if(priv->hw_coordinate_frame != coordframe) {
LOGW("coordinate frame didn't stick");
}
}
static void handle_tracker_sensor_msg(rift_priv* priv, unsigned char* buffer, int size)
{
uint32_t last_sample_tick = priv->sensor.tick;
if(!dp_decode_tracker_sensor_msg(&priv->sensor, buffer, size)){
LOGE("couldn't decode tracker sensor message");
}
pkt_tracker_sensor* s = &priv->sensor;
dp_dump_packet_tracker_sensor(s);
uint32_t tick_delta = 1000;
if(last_sample_tick > 0) //startup correction
tick_delta = s->tick - last_sample_tick;
float dt = tick_delta * TICK_LEN;
vec3f mag = {{0.0f, 0.0f, 0.0f}};
for(int i = 0; i < 1; i++){ //just use 1 sample since we don't have sample order for this frame
vec3f_from_dp_vec(s->samples[i].accel, &priv->raw_accel);
vec3f_from_dp_vec(s->samples[i].gyro, &priv->raw_gyro);
ofusion_update(&priv->sensor_fusion, dt, &priv->raw_gyro, &priv->raw_accel, &mag);
// reset dt to tick_len for the last samples if there were more than one sample
dt = TICK_LEN;
}
}
static void update_device(ohmd_device* device)
{
rift_priv* priv = rift_priv_get(device);
unsigned char buffer[FEATURE_BUFFER_SIZE];
// Handle keep alive messages
double t = ohmd_get_tick();
if(t - priv->last_keep_alive >= (double)priv->sensor_config.keep_alive_interval / 1000.0 - .2){
// send keep alive message
pkt_keep_alive keep_alive = { 0, priv->sensor_config.keep_alive_interval };
int ka_size = dp_encode_keep_alive(buffer, &keep_alive);
send_feature_report(priv, buffer, ka_size);
// Update the time of the last keep alive we have sent.
priv->last_keep_alive = t;
}
// Read all the messages from the device.
while(true){
int size = hid_read(priv->handle, buffer, FEATURE_BUFFER_SIZE);
if(size < 0){
LOGE("error reading from device");
return;
} else if(size == 0) {
return; // No more messages, return.
}
// currently the only message type the hardware supports (I think)
if(buffer[0] == RIFT_IRQ_SENSORS || buffer[0] == 11){
handle_tracker_sensor_msg(priv, buffer, size);
}else{
LOGE("unknown message type: %u", buffer[0]);
}
}
}
static int getf(ohmd_device* device, ohmd_float_value type, float* out)
{
rift_priv* priv = rift_priv_get(device);
switch(type){
case OHMD_DISTORTION_K: {
for (int i = 0; i < 6; i++) {
out[i] = priv->display_info.distortion_k[i];
}
break;
}
case OHMD_ROTATION_QUAT: {
*(quatf*)out = priv->sensor_fusion.orient;
break;
}
case OHMD_POSITION_VECTOR:
out[0] = out[1] = out[2] = 0;
break;
default:
ohmd_set_error(priv->base.ctx, "invalid type given to getf (%ud)", type);
return -1;
break;
}
return 0;
}
static void close_device(ohmd_device* device)
{
LOGD("closing device");
rift_priv* priv = rift_priv_get(device);
hid_close(priv->handle);
free(priv);
}
static char* _hid_to_unix_path(char* path)
{
char bus [4];
char dev [4];
char *result = malloc( sizeof(char) * ( 20 + 1 ) );
sprintf (bus, "%.*s\n", 4, path);
sprintf (dev, "%.*s\n", 4, path + 5);
sprintf (result, "/dev/bus/usb/%03d/%03d",
(int)strtol(bus, NULL, 16),
(int)strtol(dev, NULL, 16));
return result;
}
static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
{
rift_priv* priv = ohmd_alloc(driver->ctx, sizeof(rift_priv));
if(!priv)
goto cleanup;
priv->base.ctx = driver->ctx;
// Open the HID device
priv->handle = hid_open_path(desc->path);
if(!priv->handle) {
char* path = _hid_to_unix_path(desc->path);
ohmd_set_error(driver->ctx, "Could not open %s. "
"Check your rights.", path);
free(path);
goto cleanup;
}
if(hid_set_nonblocking(priv->handle, 1) == -1){
ohmd_set_error(driver->ctx, "failed to set non-blocking on device");
goto cleanup;
}
unsigned char buf[FEATURE_BUFFER_SIZE];
int size;
// if the sensor has display info data, use HMD coordinate frame
priv->coordinate_frame = priv->display_info.distortion_type != RIFT_DT_NONE ? RIFT_CF_HMD : RIFT_CF_SENSOR;
// enable calibration
SETFLAG(priv->sensor_config.flags, RIFT_SCF_USE_CALIBRATION, 1);
SETFLAG(priv->sensor_config.flags, RIFT_SCF_AUTO_CALIBRATION, 1);
// apply sensor config
set_coordinate_frame(priv, priv->coordinate_frame);
// set keep alive interval to n seconds
pkt_keep_alive keep_alive = { 0, KEEP_ALIVE_VALUE };
size = dp_encode_keep_alive(buf, &keep_alive);
send_feature_report(priv, buf, size);
// Update the time of the last keep alive we have sent.
priv->last_keep_alive = ohmd_get_tick();
// Set default device properties
ohmd_set_default_device_properties(&priv->base.properties);
// Set device properties
//NOTE: These values are estimations, no one has taken one appart to check
priv->base.properties.hsize = 0.1698f;
priv->base.properties.vsize = 0.0936f;
priv->base.properties.hres = 1920;
priv->base.properties.vres = 1080;
priv->base.properties.lens_sep = 0.0849f;
priv->base.properties.lens_vpos = 0.0468f;;
priv->base.properties.fov = DEG_TO_RAD(110.0); // TODO calculate.
priv->base.properties.ratio = ((float)1920 / (float)1080) / 2.0f;
// calculate projection eye projection matrices from the device properties
ohmd_calc_default_proj_matrices(&priv->base.properties);
// set up device callbacks
priv->base.update = update_device;
priv->base.close = close_device;
priv->base.getf = getf;
// initialize sensor fusion
ofusion_init(&priv->sensor_fusion);
return &priv->base;
cleanup:
if(priv)
free(priv);
return NULL;
}
static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
{
struct hid_device_info* devs = hid_enumerate(DEEPOON_ID, DEEPOON_HMD);
struct hid_device_info* cur_dev = devs;
while (cur_dev) {
ohmd_device_desc* desc = &list->devices[list->num_devices++];
strcpy(desc->driver, "Deepoon Driver");
strcpy(desc->vendor, "Deepoon");
strcpy(desc->product, "Deepoon E2");
desc->revision = 0;
strcpy(desc->path, cur_dev->path);
desc->driver_ptr = driver;
cur_dev = cur_dev->next;
}
hid_free_enumeration(devs);
}
static void destroy_driver(ohmd_driver* drv)
{
LOGD("shutting down driver");
hid_exit();
free(drv);
}
ohmd_driver* ohmd_create_deepoon_drv(ohmd_context* ctx)
{
ohmd_driver* drv = ohmd_alloc(ctx, sizeof(ohmd_driver));
if(drv == NULL)
return NULL;
drv->get_device_list = get_device_list;
drv->open_device = open_device;
drv->ctx = ctx;
drv->get_device_list = get_device_list;
drv->open_device = open_device;
drv->destroy = destroy_driver;
return drv;
}

111
extern/openhmd/src/drv_deepoon/deepoon.h vendored Normal file
View File

@@ -0,0 +1,111 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Deepoon Driver Internal Interface */
#ifndef DEEPOON_H
#define DEEPOON_H
#include "../openhmdi.h"
#define FEATURE_BUFFER_SIZE 256
typedef enum {
RIFT_CMD_SENSOR_CONFIG = 2,
RIFT_CMD_RANGE = 4,
RIFT_CMD_KEEP_ALIVE = 8,
RIFT_CMD_DISPLAY_INFO = 9
} rift_sensor_feature_cmd;
typedef enum {
RIFT_CF_SENSOR,
RIFT_CF_HMD
} rift_coordinate_frame;
typedef enum {
RIFT_IRQ_SENSORS = 1
} rift_irq_cmd;
typedef enum {
RIFT_DT_NONE,
RIFT_DT_SCREEN_ONLY,
RIFT_DT_DISTORTION
} rift_distortion_type;
// Sensor config flags
#define RIFT_SCF_RAW_MODE 0x01
#define RIFT_SCF_CALIBRATION_TEST 0x02
#define RIFT_SCF_USE_CALIBRATION 0x04
#define RIFT_SCF_AUTO_CALIBRATION 0x08
#define RIFT_SCF_MOTION_KEEP_ALIVE 0x10
#define RIFT_SCF_COMMAND_KEEP_ALIVE 0x20
#define RIFT_SCF_SENSOR_COORDINATES 0x40
typedef struct {
uint16_t command_id;
uint16_t accel_scale;
uint16_t gyro_scale;
uint16_t mag_scale;
} pkt_sensor_range;
typedef struct {
int32_t accel[3];
int32_t gyro[3];
} pkt_tracker_sample;
typedef struct {
uint8_t report_id;
uint8_t sample_delta;
uint16_t sample_number;
uint32_t tick;
pkt_tracker_sample samples[2];
int16_t mag[3];
} pkt_tracker_sensor;
typedef struct {
uint16_t command_id;
uint8_t flags;
uint16_t packet_interval;
uint16_t keep_alive_interval; // in ms
} pkt_sensor_config;
typedef struct {
uint16_t command_id;
rift_distortion_type distortion_type;
uint8_t distortion_type_opts;
uint16_t h_resolution, v_resolution;
float h_screen_size, v_screen_size;
float v_center;
float lens_separation;
float eye_to_screen_distance[2];
float distortion_k[6];
} pkt_sensor_display_info;
typedef struct {
uint16_t command_id;
uint16_t keep_alive_interval;
} pkt_keep_alive;
bool dp_decode_sensor_range(pkt_sensor_range* range, const unsigned char* buffer, int size);
bool dp_decode_sensor_display_info(pkt_sensor_display_info* info, const unsigned char* buffer, int size);
bool dp_decode_sensor_config(pkt_sensor_config* config, const unsigned char* buffer, int size);
bool dp_decode_tracker_sensor_msg(pkt_tracker_sensor* msg, const unsigned char* buffer, int size);
void vec3f_from_dp_vec(const int32_t* smp, vec3f* out_vec);
int dp_encode_sensor_config(unsigned char* buffer, const pkt_sensor_config* config);
int dp_encode_keep_alive(unsigned char* buffer, const pkt_keep_alive* keep_alive);
void dp_dump_packet_sensor_range(const pkt_sensor_range* range);
void dp_dump_packet_sensor_config(const pkt_sensor_config* config);
void dp_dump_packet_sensor_display_info(const pkt_sensor_display_info* info);
void dp_dump_packet_tracker_sensor(const pkt_tracker_sensor* sensor);
#endif

182
extern/openhmd/src/drv_deepoon/packet.c vendored Normal file
View File

@@ -0,0 +1,182 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Deepoon Driver - Packet Decoding and Utilities */
#include <stdio.h>
#include "deepoon.h"
#define SKIP_CMD (buffer++)
#define READ8 *(buffer++);
#define READ16 *buffer | (*(buffer + 1) << 8); buffer += 2;
#define READ32 *buffer | (*(buffer + 1) << 8) | (*(buffer + 2) << 16) | (*(buffer + 3) << 24); buffer += 4;
#define READFLOAT ((float)(*buffer)); buffer += 4;
#define READFIXED (float)(*buffer | (*(buffer + 1) << 8) | (*(buffer + 2) << 16) | (*(buffer + 3) << 24)) / 1000000.0f; buffer += 4;
#define WRITE8(_val) *(buffer++) = (_val);
#define WRITE16(_val) WRITE8((_val) & 0xff); WRITE8(((_val) >> 8) & 0xff);
#define WRITE32(_val) WRITE16((_val) & 0xffff) *buffer; WRITE16(((_val) >> 16) & 0xffff);
bool dp_decodesensor_range(pkt_sensor_range* range, const unsigned char* buffer, int size)
{
if(!(size == 8 || size == 9)){
LOGE("invalid packet size (expected 8 or 9 but got %d)", size);
return false;
}
SKIP_CMD;
range->command_id = READ16;
range->accel_scale = READ8;
range->gyro_scale = READ16;
range->mag_scale = READ16;
return true;
}
bool dp_decodesensor_display_info(pkt_sensor_display_info* info, const unsigned char* buffer, int size)
{
if(!(size == 56 || size == 57)){
LOGE("invalid packet size (expected 56 or 57 but got %d)", size);
//return false;
}
SKIP_CMD;
info->command_id = READ16;
info->distortion_type = READ8;
info->h_resolution = READ16;
info->v_resolution = READ16;
info->h_screen_size = READFIXED;
info->v_screen_size = READFIXED;
info->v_center = READFIXED;
info->lens_separation = READFIXED;
info->eye_to_screen_distance[0] = READFIXED;
info->eye_to_screen_distance[1] = READFIXED;
info->distortion_type_opts = 0;
for(int i = 0; i < 6; i++){
info->distortion_k[i] = READFLOAT;
}
return true;
}
bool dp_decodesensor_config(pkt_sensor_config* config, const unsigned char* buffer, int size)
{
if(!(size == 7 || size == 8)){
LOGE("invalid packet size (expected 7 or 8 but got %d)", size);
return false;
}
SKIP_CMD;
config->command_id = READ16;
config->flags = READ8;
config->packet_interval = READ8;
config->keep_alive_interval = READ16;
return true;
}
static void dp_decodesample(const unsigned char* buffer, int32_t* smp)
{
/*
* Decode 3 tightly packed 21 bit values from 4 bytes.
* We unpack them in the higher 21 bit values first and then shift
* them down to the lower in order to get the sign bits correct.
*/
int x = (buffer[0] << 24) | (buffer[1] << 16) | ((buffer[2] & 0xF8) << 8);
int y = ((buffer[2] & 0x07) << 29) | (buffer[3] << 21) | (buffer[4] << 13) | ((buffer[5] & 0xC0) << 5);
int z = ((buffer[5] & 0x3F) << 26) | (buffer[6] << 18) | (buffer[7] << 10);
smp[0] = x >> 11;
smp[1] = y >> 11;
smp[2] = z >> 11;
}
bool dp_decode_tracker_sensor_msg(pkt_tracker_sensor* msg, const unsigned char* buffer, int size)
{
if(!(size == 62 || size == 64)){
LOGE("invalid packet size (expected 62 or 64 but got %d)", size);
return false;
}
msg->report_id = READ8;
buffer += 2;
msg->sample_delta = READ8;
msg->sample_number = READ16;
buffer += 2;
msg->tick = READ32;
for(int i = 0; i < 2; i++){
dp_decodesample(buffer, msg->samples[i].accel);
buffer += 8;
dp_decodesample(buffer, msg->samples[i].gyro);
buffer += 8;
}
return true;
}
// TODO do we need to consider HMD vs sensor "centric" values
void vec3f_from_dp_vec(const int32_t* smp, vec3f* out_vec)
{
out_vec->x = (float)smp[0] * 0.0001f;
out_vec->y = ((float)smp[2] * 0.0001f) * -1;
out_vec->z = (float)smp[1] * 0.0001f;
}
int dp_encode_sensor_config(unsigned char* buffer, const pkt_sensor_config* config)
{
WRITE8(RIFT_CMD_SENSOR_CONFIG);
WRITE16(config->command_id);
WRITE8(config->flags);
WRITE8(config->packet_interval);
WRITE16(config->keep_alive_interval);
return 7; // sensor config packet size
}
int dp_encode_keep_alive(unsigned char* buffer, const pkt_keep_alive* keep_alive)
{
WRITE8(RIFT_CMD_KEEP_ALIVE);
WRITE16(keep_alive->command_id);
WRITE16(keep_alive->keep_alive_interval);
return 5; // keep alive packet size
}
void dp_dump_packet_sensor_config(const pkt_sensor_config* config)
{
(void)config;
LOGD("sensor config");
LOGD(" command id: %u", config->command_id);
LOGD(" flags: %02x", config->flags);
LOGD(" raw mode: %d", !!(config->flags & RIFT_SCF_RAW_MODE));
LOGD(" calibration test: %d", !!(config->flags & RIFT_SCF_CALIBRATION_TEST));
LOGD(" use calibration: %d", !!(config->flags & RIFT_SCF_USE_CALIBRATION));
LOGD(" auto calibration: %d", !!(config->flags & RIFT_SCF_AUTO_CALIBRATION));
LOGD(" motion keep alive: %d", !!(config->flags & RIFT_SCF_MOTION_KEEP_ALIVE));
LOGD(" motion command keep alive: %d", !!(config->flags & RIFT_SCF_COMMAND_KEEP_ALIVE));
LOGD(" sensor coordinates: %d", !!(config->flags & RIFT_SCF_SENSOR_COORDINATES));
LOGD(" packet interval: %u", config->packet_interval);
LOGD(" keep alive interval: %u", config->keep_alive_interval);
}
void dp_dump_packet_tracker_sensor(const pkt_tracker_sensor* sensor)
{
(void)sensor;
LOGD("TEST: deepoon sensor data");
LOGD(" report id: %u", sensor->report_id);
LOGD(" sample delta: %u", sensor->sample_delta);
LOGD(" sample number: %d", sensor->sample_number);
LOGD(" tick: %u", sensor->tick);
for(int i = 0; i < 2; i++){
LOGD(" accel: %d %d %d", sensor->samples[i].accel[0], sensor->samples[i].accel[1], sensor->samples[i].accel[2]);
LOGD(" gyro: %d %d %d", sensor->samples[i].gyro[0], sensor->samples[i].gyro[1], sensor->samples[i].gyro[2]);
}
}

118
extern/openhmd/src/drv_dummy/dummy.c vendored Normal file
View File

@@ -0,0 +1,118 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Dummy Driver */
#include <string.h>
#include "../openhmdi.h"
typedef struct {
ohmd_device base;
} dummy_priv;
static void update_device(ohmd_device* device)
{
}
static int getf(ohmd_device* device, ohmd_float_value type, float* out)
{
dummy_priv* priv = (dummy_priv*)device;
switch(type){
case OHMD_ROTATION_QUAT:
out[0] = out[1] = out[2] = 0;
out[3] = 1.0f;
break;
case OHMD_POSITION_VECTOR:
out[0] = out[1] = out[2] = 0;
break;
case OHMD_DISTORTION_K:
// TODO this should be set to the equivalent of no distortion
memset(out, 0, sizeof(float) * 6);
break;
default:
ohmd_set_error(priv->base.ctx, "invalid type given to getf (%ud)", type);
return -1;
break;
}
return 0;
}
static void close_device(ohmd_device* device)
{
LOGD("closing dummy device");
free(device);
}
static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
{
dummy_priv* priv = ohmd_alloc(driver->ctx, sizeof(dummy_priv));
if(!priv)
return NULL;
// Set default device properties
ohmd_set_default_device_properties(&priv->base.properties);
// Set device properties (imitates the rift values)
priv->base.properties.hsize = 0.149760f;
priv->base.properties.vsize = 0.093600f;
priv->base.properties.hres = 1280;
priv->base.properties.vres = 800;
priv->base.properties.lens_sep = 0.063500f;
priv->base.properties.lens_vpos = 0.046800f;
priv->base.properties.fov = DEG_TO_RAD(125.5144f);
priv->base.properties.ratio = (1280.0f / 800.0f) / 2.0f;
priv->base.properties.digital_button_count = 4;
// calculate projection eye projection matrices from the device properties
ohmd_calc_default_proj_matrices(&priv->base.properties);
// set up device callbacks
priv->base.update = update_device;
priv->base.close = close_device;
priv->base.getf = getf;
return (ohmd_device*)priv;
}
static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
{
ohmd_device_desc* desc = &list->devices[list->num_devices++];
strcpy(desc->driver, "OpenHMD Dummy Driver");
strcpy(desc->vendor, "OpenHMD");
strcpy(desc->product, "Dummy Device");
strcpy(desc->path, "(none)");
desc->driver_ptr = driver;
}
static void destroy_driver(ohmd_driver* drv)
{
LOGD("shutting down dummy driver");
free(drv);
}
ohmd_driver* ohmd_create_dummy_drv(ohmd_context* ctx)
{
ohmd_driver* drv = ohmd_alloc(ctx, sizeof(ohmd_driver));
if(!drv)
return NULL;
drv->get_device_list = get_device_list;
drv->open_device = open_device;
drv->get_device_list = get_device_list;
drv->open_device = open_device;
drv->destroy = destroy_driver;
return drv;
}

View File

@@ -0,0 +1,152 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Copyright (C) 2015 Joey Ferwerda
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* External Driver */
#include "../openhmdi.h"
#include "string.h"
typedef struct {
ohmd_device base;
fusion sensor_fusion;
} external_priv;
static void update_device(ohmd_device* device)
{
}
static int getf(ohmd_device* device, ohmd_float_value type, float* out)
{
external_priv* priv = (external_priv*)device;
switch(type){
case OHMD_ROTATION_QUAT: {
*(quatf*)out = priv->sensor_fusion.orient;
break;
}
case OHMD_POSITION_VECTOR:
out[0] = out[1] = out[2] = 0;
break;
default:
ohmd_set_error(priv->base.ctx, "invalid type given to getf (%d)", type);
return -1;
break;
}
return 0;
}
static int setf(ohmd_device* device, ohmd_float_value type, const float* in)
{
external_priv* priv = (external_priv*)device;
switch(type){
case OHMD_EXTERNAL_SENSOR_FUSION: {
ofusion_update(&priv->sensor_fusion, *in, (vec3f*)(in + 1), (vec3f*)(in + 4), (vec3f*)(in + 7));
}
break;
default:
ohmd_set_error(priv->base.ctx, "invalid type given to setf (%d)", type);
return -1;
break;
}
return 0;
}
static void close_device(ohmd_device* device)
{
LOGD("closing external device");
free(device);
}
static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
{
external_priv* priv = ohmd_alloc(driver->ctx, sizeof(external_priv));
if(!priv)
return NULL;
// Set default device properties
ohmd_set_default_device_properties(&priv->base.properties);
// Set device properties
//TODO: Get information from external device using set_external_properties?
//Using 'dummy' settings for now
priv->base.properties.hsize = 0.149760f;
priv->base.properties.vsize = 0.093600f;
priv->base.properties.hres = 1280;
priv->base.properties.vres = 800;
priv->base.properties.lens_sep = 0.063500f;
priv->base.properties.lens_vpos = 0.046800f;
priv->base.properties.fov = DEG_TO_RAD(125.5144f);
priv->base.properties.ratio = (1280.0f / 800.0f) / 2.0f;
// calculate projection eye projection matrices from the device properties
ohmd_calc_default_proj_matrices(&priv->base.properties);
// set up device callbacks
priv->base.update = update_device;
priv->base.close = close_device;
priv->base.getf = getf;
priv->base.setf = setf;
ofusion_init(&priv->sensor_fusion);
return (ohmd_device*)priv;
}
static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
{
ohmd_device_desc* desc = &list->devices[list->num_devices++];
strcpy(desc->driver, "OpenHMD Generic External Driver");
strcpy(desc->vendor, "OpenHMD");
strcpy(desc->product, "External Device");
strcpy(desc->path, "(none)");
desc->driver_ptr = driver;
}
static void destroy_driver(ohmd_driver* drv)
{
LOGD("shutting down external driver");
free(drv);
}
ohmd_driver* ohmd_create_external_drv(ohmd_context* ctx)
{
ohmd_driver* drv = ohmd_alloc(ctx, sizeof(ohmd_driver));
if(!drv)
return NULL;
drv->get_device_list = get_device_list;
drv->open_device = open_device;
drv->destroy = destroy_driver;
drv->ctx = ctx;
return drv;
}
/* external specific functions */
/*static void set_external_properties(ohmd_device* device, ohmd_device_properties* props)
{
external_priv* priv = (external_priv*)device;
priv->base.properties.hsize = props->hsize;
priv->base.properties.vsize = props->vsize;
priv->base.properties.hres = props->hres;
priv->base.properties.vres = props->vres;
priv->base.properties.lens_sep = props->lens_sep;
priv->base.properties.lens_vpos = props->lens_vpos;
priv->base.properties.fov = DEG_TO_RAD(props->fov);
priv->base.properties.ratio = props->ratio;
}*/

View File

@@ -0,0 +1 @@
//Reserved

27
extern/openhmd/src/drv_htc_vive/magic.h vendored Normal file
View File

@@ -0,0 +1,27 @@
static const unsigned char vive_magic_power_on[64] = {
0x04, 0x78, 0x29, 0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
0xa8, 0x0d, 0x76, 0x00, 0x40, 0xfc, 0x01, 0x05, 0xfa, 0xec, 0xd1, 0x6d, 0x00,
0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0d, 0x76, 0x00, 0x68, 0xfc,
0x01, 0x05, 0x2c, 0xb0, 0x2e, 0x65, 0x7a, 0x0d, 0x76, 0x00, 0x68, 0x54, 0x72,
0x00, 0x18, 0x54, 0x72, 0x00, 0x00, 0x6a, 0x72, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char vive_magic_power_off1[64] = {
0x04, 0x78, 0x29, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
0x30, 0x05, 0x77, 0x00, 0x30, 0x05, 0x77, 0x00, 0x6c, 0x4d, 0x37, 0x65, 0x40,
0xf9, 0x33, 0x00, 0x04, 0xf8, 0xa3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x70, 0xb0,
0x72, 0x00, 0xf4, 0xf7, 0xa3, 0x04, 0x7c, 0xf8, 0x33, 0x00, 0x0c, 0xf8, 0xa3,
0x04, 0x0a, 0x6e, 0x29, 0x65, 0x24, 0xf9, 0x33, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char vive_magic_power_off2[64] = {
0x04, 0x78, 0x29, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
0x30, 0x05, 0x77, 0x00, 0xe4, 0xf7, 0x33, 0x00, 0xe4, 0xf7, 0x33, 0x00, 0x60,
0x6e, 0x72, 0x00, 0xb4, 0xf7, 0x33, 0x00, 0x04, 0x00, 0x00, 0x00, 0x70, 0xb0,
0x72, 0x00, 0x90, 0xf7, 0x33, 0x00, 0x7c, 0xf8, 0x33, 0x00, 0xd0, 0xf7, 0x33,
0x00, 0x3c, 0x68, 0x29, 0x65, 0x24, 0xf9, 0x33, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char vive_magic_enable_lighthouse[5] = {
0x04
};

View File

@@ -0,0 +1,63 @@
#include "vive.h"
#include "config.h"
#ifdef _MSC_VER
#define inline __inline
#endif
inline static uint8_t read8(const unsigned char** buffer)
{
uint8_t ret = **buffer;
*buffer += 1;
return ret;
}
inline static int16_t read16(const unsigned char** buffer)
{
int16_t ret = **buffer | (*(*buffer + 1) << 8);
*buffer += 2;
return ret;
}
inline static uint32_t read32(const unsigned char** buffer)
{
uint32_t ret = **buffer | (*(*buffer + 1) << 8) | (*(*buffer + 2) << 16) | (*(*buffer + 3) << 24);
*buffer += 4;
return ret;
}
bool vive_decode_sensor_packet(vive_sensor_packet* pkt, const unsigned char* buffer, int size)
{
if(size != 52){
LOGE("invalid vive sensor packet size (expected 52 but got %d)", size);
return false;
}
pkt->report_id = read8(&buffer);
for(int j = 0; j < 3; j++){
// acceleration
for(int i = 0; i < 3; i++){
pkt->samples[j].acc[i] = read16(&buffer);
}
// rotation
for(int i = 0; i < 3; i++){
pkt->samples[j].rot[i] = read16(&buffer);
}
pkt->samples[j].time_ticks = read32(&buffer);
pkt->samples[j].seq = read8(&buffer);
}
return true;
}
//TODO: Implement config packet decoding.
bool vive_decode_config_packet(vive_config_packet* pkt, const unsigned char* buffer, int size)
{
if(size != 64){
LOGE("invalid vive sensor packet size (expected 64 but got %d)", size);
return false;
}
return false;
}

441
extern/openhmd/src/drv_htc_vive/vive.c vendored Normal file
View File

@@ -0,0 +1,441 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* HTC Vive Driver */
#define FEATURE_BUFFER_SIZE 256
#define HTC_ID 0x0bb4
#define VIVE_HMD 0x2c87
#define VALVE_ID 0x28de
#define VIVE_WATCHMAN_DONGLE 0x2101
#define VIVE_LIGHTHOUSE_FPGA_RX 0x2000
#define VIVE_TIME_DIV 48000000.0f
#include <string.h>
#include <wchar.h>
#include <hidapi.h>
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdbool.h>
#include "vive.h"
typedef struct {
ohmd_device base;
hid_device* hmd_handle;
hid_device* imu_handle;
fusion sensor_fusion;
vec3f raw_accel, raw_gyro;
uint32_t last_ticks;
uint8_t last_seq;
vec3f gyro_error;
filter_queue gyro_q;
} vive_priv;
void vec3f_from_vive_vec_accel(const int16_t* smp, vec3f* out_vec)
{
float gravity = 9.81f;
float scaler = 4.0f * gravity / 32768.0f;
out_vec->x = (float)smp[0] * scaler;
out_vec->y = (float)smp[1] * scaler * -1;
out_vec->z = (float)smp[2] * scaler * -1;
}
void vec3f_from_vive_vec_gyro(const int16_t* smp, vec3f* out_vec)
{
float scaler = 8.7f / 32768.0f;
out_vec->x = (float)smp[0] * scaler;
out_vec->y = (float)smp[1] * scaler * -1;
out_vec->z = (float)smp[2] * scaler * -1;
}
static bool process_error(vive_priv* priv)
{
if(priv->gyro_q.at >= priv->gyro_q.size - 1)
return true;
ofq_add(&priv->gyro_q, &priv->raw_gyro);
if(priv->gyro_q.at >= priv->gyro_q.size - 1){
ofq_get_mean(&priv->gyro_q, &priv->gyro_error);
printf("gyro error: %f, %f, %f\n", priv->gyro_error.x, priv->gyro_error.y, priv->gyro_error.z);
}
return false;
}
vive_sensor_sample* get_next_sample(vive_sensor_packet* pkt, int last_seq)
{
int diff[3];
for(int i = 0; i < 3; i++)
{
diff[i] = (int)pkt->samples[i].seq - last_seq;
if(diff[i] < -128){
diff[i] += 256;
}
}
int closest_diff = INT_MAX;
int closest_idx = -1;
for(int i = 0; i < 3; i++)
{
if(diff[i] < closest_diff && diff[i] > 0 && diff[i] < 128){
closest_diff = diff[i];
closest_idx = i;
}
}
if(closest_idx != -1)
return pkt->samples + closest_idx;
return NULL;
}
static void update_device(ohmd_device* device)
{
vive_priv* priv = (vive_priv*)device;
int size = 0;
unsigned char buffer[FEATURE_BUFFER_SIZE];
while((size = hid_read(priv->imu_handle, buffer, FEATURE_BUFFER_SIZE)) > 0){
if(buffer[0] == VIVE_IRQ_SENSORS){
vive_sensor_packet pkt;
vive_decode_sensor_packet(&pkt, buffer, size);
vive_sensor_sample* smp = NULL;
while((smp = get_next_sample(&pkt, priv->last_seq)) != NULL)
{
if(priv->last_ticks == 0)
priv->last_ticks = smp->time_ticks;
uint32_t t1, t2;
t1 = smp->time_ticks;
t2 = priv->last_ticks;
float dt = (t1 - t2) / VIVE_TIME_DIV;
priv->last_ticks = smp->time_ticks;
vec3f_from_vive_vec_accel(smp->acc, &priv->raw_accel);
vec3f_from_vive_vec_gyro(smp->rot, &priv->raw_gyro);
if(process_error(priv)){
vec3f mag = {{0.0f, 0.0f, 0.0f}};
vec3f gyro;
ovec3f_subtract(&priv->raw_gyro, &priv->gyro_error, &gyro);
ofusion_update(&priv->sensor_fusion, dt, &gyro, &priv->raw_accel, &mag);
}
priv->last_seq = smp->seq;
}
}else{
LOGE("unknown message type: %u", buffer[0]);
}
}
if(size < 0){
LOGE("error reading from device");
}
}
static int getf(ohmd_device* device, ohmd_float_value type, float* out)
{
vive_priv* priv = (vive_priv*)device;
switch(type){
case OHMD_ROTATION_QUAT:
*(quatf*)out = priv->sensor_fusion.orient;
break;
case OHMD_POSITION_VECTOR:
out[0] = out[1] = out[2] = 0;
break;
case OHMD_DISTORTION_K:
// TODO this should be set to the equivalent of no distortion
memset(out, 0, sizeof(float) * 6);
break;
default:
ohmd_set_error(priv->base.ctx, "invalid type given to getf (%ud)", type);
return -1;
break;
}
return 0;
}
static void close_device(ohmd_device* device)
{
int hret = 0;
vive_priv* priv = (vive_priv*)device;
LOGD("closing HTC Vive device");
// turn the display off
hret = hid_send_feature_report(priv->hmd_handle, vive_magic_power_off1, sizeof(vive_magic_power_off1));
//printf("power off magic 1: %d\n", hret);
hret = hid_send_feature_report(priv->hmd_handle, vive_magic_power_off2, sizeof(vive_magic_power_off2));
//printf("power off magic 2: %d\n", hret);
hid_close(priv->hmd_handle);
hid_close(priv->imu_handle);
free(device);
}
#if 0
static void dump_indexed_string(hid_device* device, int index)
{
wchar_t wbuffer[512] = {0};
char buffer[1024] = {0};
int hret = hid_get_indexed_string(device, index, wbuffer, 511);
if(hret == 0){
wcstombs(buffer, wbuffer, sizeof(buffer));
printf("indexed string 0x%02x: '%s'\n", index, buffer);
}
}
#endif
static void dump_info_string(int (*fun)(hid_device*, wchar_t*, size_t), const char* what, hid_device* device)
{
wchar_t wbuffer[512] = {0};
char buffer[1024] = {0};
int hret = fun(device, wbuffer, 511);
if(hret == 0){
wcstombs(buffer, wbuffer, sizeof(buffer));
printf("%s: '%s'\n", what, buffer);
}
}
#if 0
static void dumpbin(const char* label, const unsigned char* data, int length)
{
printf("%s:\n", label);
for(int i = 0; i < length; i++){
printf("%02x ", data[i]);
if((i % 16) == 15)
printf("\n");
}
printf("\n");
}
#endif
static hid_device* open_device_idx(int manufacturer, int product, int iface, int iface_tot, int device_index)
{
struct hid_device_info* devs = hid_enumerate(manufacturer, product);
struct hid_device_info* cur_dev = devs;
int idx = 0;
int iface_cur = 0;
hid_device* ret = NULL;
while (cur_dev) {
printf("%04x:%04x %s\n", manufacturer, product, cur_dev->path);
if(idx == device_index && iface == iface_cur){
ret = hid_open_path(cur_dev->path);
printf("opening\n");
}
cur_dev = cur_dev->next;
iface_cur++;
if(iface_cur >= iface_tot){
idx++;
iface_cur = 0;
}
}
hid_free_enumeration(devs);
return ret;
}
static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
{
vive_priv* priv = ohmd_alloc(driver->ctx, sizeof(vive_priv));
if(!priv)
return NULL;
int hret = 0;
priv->base.ctx = driver->ctx;
int idx = atoi(desc->path);
// Open the HMD device
priv->hmd_handle = open_device_idx(HTC_ID, VIVE_HMD, 0, 1, idx);
if(!priv->hmd_handle)
goto cleanup;
if(hid_set_nonblocking(priv->hmd_handle, 1) == -1){
ohmd_set_error(driver->ctx, "failed to set non-blocking on device");
goto cleanup;
}
// Open the lighthouse device
priv->imu_handle = open_device_idx(VALVE_ID, VIVE_LIGHTHOUSE_FPGA_RX, 0, 2, idx);
if(!priv->imu_handle)
goto cleanup;
if(hid_set_nonblocking(priv->imu_handle, 1) == -1){
ohmd_set_error(driver->ctx, "failed to set non-blocking on device");
goto cleanup;
}
dump_info_string(hid_get_manufacturer_string, "manufacturer", priv->hmd_handle);
dump_info_string(hid_get_product_string , "product", priv->hmd_handle);
dump_info_string(hid_get_serial_number_string, "serial number", priv->hmd_handle);
// turn the display on
hret = hid_send_feature_report(priv->hmd_handle, vive_magic_power_on, sizeof(vive_magic_power_on));
printf("power on magic: %d\n", hret);
// enable lighthouse
//hret = hid_send_feature_report(priv->hmd_handle, vive_magic_enable_lighthouse, sizeof(vive_magic_enable_lighthouse));
//printf("enable lighthouse magic: %d\n", hret);
// Set default device properties
ohmd_set_default_device_properties(&priv->base.properties);
// Set device properties TODO: Get from device
priv->base.properties.hsize = 0.122822f;
priv->base.properties.vsize = 0.068234f;
priv->base.properties.hres = 2160;
priv->base.properties.vres = 1200;
/*
// calculated from here: https://www.gamedev.net/topic/683698-projection-matrix-model-of-the-htc-vive/
priv->base.properties.lens_sep = 0.057863;
priv->base.properties.lens_vpos = 0.033896;
*/
// estimated 'by eye' on jsarret's vive
priv->base.properties.lens_sep = 0.056;
priv->base.properties.lens_vpos = 0.032;
float eye_to_screen_distance = 0.023226876441867737;
//priv->base.properties.fov = DEG_TO_RAD(111.435f); //TODO: Confirm exact mesurements
priv->base.properties.ratio = (2160.0f / 1200.0f) / 2.0f;
/*
ohmd_set_universal_distortion_k(&(priv->base.properties), 0.394119, -0.508383, 0.323322, 0.790942);
*/
ohmd_set_universal_distortion_k(&(priv->base.properties), 1.318397, -1.490242, 0.663824, 0.508021);
ohmd_set_universal_aberration_k(&(priv->base.properties), 1.00010147892f, 1.000f, 1.00019614479f);
// calculate projection eye projection matrices from the device properties
//ohmd_calc_default_proj_matrices(&priv->base.properties);
float l,r,t,b,n,f;
// left eye screen bounds
l = -1.0f * (priv->base.properties.hsize/2 - priv->base.properties.lens_sep/2);
r = priv->base.properties.lens_sep/2;
t = priv->base.properties.vsize - priv->base.properties.lens_vpos;
b = -1.0f * priv->base.properties.lens_vpos;
n = eye_to_screen_distance;
f = n*10e6;
//LOGD("l: %0.3f, r: %0.3f, b: %0.3f, t: %0.3f, n: %0.3f, f: %0.3f", l,r,b,t,n,f);
/* eye separation is handled by IPD in the Modelview matrix */
omat4x4f_init_frustum(&priv->base.properties.proj_left, l, r, b, t, n, f);
//right eye screen bounds
l = -1.0f * priv->base.properties.lens_sep/2;
r = priv->base.properties.hsize/2 - priv->base.properties.lens_sep/2;
n = eye_to_screen_distance;
f = n*10e6;
//LOGD("l: %0.3f, r: %0.3f, b: %0.3f, t: %0.3f, n: %0.3f, f: %0.3f", l,r,b,t,n,f);
/* eye separation is handled by IPD in the Modelview matrix */
omat4x4f_init_frustum(&priv->base.properties.proj_right, l, r, b, t, n, f);
priv->base.properties.fov = 2 * atan2f(
priv->base.properties.hsize/2 - priv->base.properties.lens_sep/2,
eye_to_screen_distance);
// set up device callbacks
priv->base.update = update_device;
priv->base.close = close_device;
priv->base.getf = getf;
ofusion_init(&priv->sensor_fusion);
ofq_init(&priv->gyro_q, 128);
return (ohmd_device*)priv;
cleanup:
if(priv)
free(priv);
return NULL;
}
static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
{
struct hid_device_info* devs = hid_enumerate(HTC_ID, VIVE_HMD);
struct hid_device_info* cur_dev = devs;
int idx = 0;
while (cur_dev) {
ohmd_device_desc* desc = &list->devices[list->num_devices++];
strcpy(desc->driver, "OpenHMD HTC Vive Driver");
strcpy(desc->vendor, "HTC/Valve");
strcpy(desc->product, "HTC Vive");
desc->revision = 0;
snprintf(desc->path, OHMD_STR_SIZE, "%d", idx);
desc->driver_ptr = driver;
cur_dev = cur_dev->next;
idx++;
}
hid_free_enumeration(devs);
}
static void destroy_driver(ohmd_driver* drv)
{
LOGD("shutting down HTC Vive driver");
free(drv);
}
ohmd_driver* ohmd_create_htc_vive_drv(ohmd_context* ctx)
{
ohmd_driver* drv = ohmd_alloc(ctx, sizeof(ohmd_driver));
if(!drv)
return NULL;
drv->get_device_list = get_device_list;
drv->open_device = open_device;
drv->destroy = destroy_driver;
drv->ctx = ctx;
return drv;
}

41
extern/openhmd/src/drv_htc_vive/vive.h vendored Normal file
View File

@@ -0,0 +1,41 @@
#ifndef VIVE_H
#define VIVE_H
#include <stdint.h>
#include <stdbool.h>
#include "../openhmdi.h"
#include "magic.h"
typedef enum
{
VIVE_CONFIG_DATA = 17,
VIVE_IRQ_SENSORS = 32,
} vive_irq_cmd;
typedef struct
{
int16_t acc[3];
int16_t rot[3];
uint32_t time_ticks;
uint8_t seq;
} vive_sensor_sample;
typedef struct
{
uint8_t report_id;
vive_sensor_sample samples[3];
} vive_sensor_packet;
typedef struct
{
uint8_t report_id;
uint16_t length;
unsigned char config_data[99999];
} vive_config_packet;
void vec3f_from_vive_vec(const int16_t* smp, vec3f* out_vec);
bool vive_decode_sensor_packet(vive_sensor_packet* pkt, const unsigned char* buffer, int size);
bool vive_decode_config_packet(vive_config_packet* pkt, const unsigned char* buffer, int size);
#endif

View File

@@ -0,0 +1,275 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Oculus Rift Driver - Packet Decoding and Utilities */
#include <stdio.h>
#include "rift.h"
#define SKIP_CMD (buffer++)
#define READ8 *(buffer++);
#define READ16 *buffer | (*(buffer + 1) << 8); buffer += 2;
#define READ32 *buffer | (*(buffer + 1) << 8) | (*(buffer + 2) << 16) | (*(buffer + 3) << 24); buffer += 4;
#define READFLOAT ((float)(*buffer)); buffer += 4;
#define READFIXED (float)(*buffer | (*(buffer + 1) << 8) | (*(buffer + 2) << 16) | (*(buffer + 3) << 24)) / 1000000.0f; buffer += 4;
#define WRITE8(_val) *(buffer++) = (_val);
#define WRITE16(_val) WRITE8((_val) & 0xff); WRITE8(((_val) >> 8) & 0xff);
#define WRITE32(_val) WRITE16((_val) & 0xffff) *buffer; WRITE16(((_val) >> 16) & 0xffff);
bool decode_sensor_range(pkt_sensor_range* range, const unsigned char* buffer, int size)
{
if(!(size == 8 || size == 9)){
LOGE("invalid packet size (expected 8 or 9 but got %d)", size);
return false;
}
SKIP_CMD;
range->command_id = READ16;
range->accel_scale = READ8;
range->gyro_scale = READ16;
range->mag_scale = READ16;
return true;
}
bool decode_sensor_display_info(pkt_sensor_display_info* info, const unsigned char* buffer, int size)
{
if(!(size == 56 || size == 57)){
LOGE("invalid packet size (expected 56 or 57 but got %d)", size);
return false;
}
SKIP_CMD;
info->command_id = READ16;
info->distortion_type = READ8;
info->h_resolution = READ16;
info->v_resolution = READ16;
info->h_screen_size = READFIXED;
info->v_screen_size = READFIXED;
info->v_center = READFIXED;
info->lens_separation = READFIXED;
info->eye_to_screen_distance[0] = READFIXED;
info->eye_to_screen_distance[1] = READFIXED;
info->distortion_type_opts = 0;
for(int i = 0; i < 6; i++){
info->distortion_k[i] = READFLOAT;
}
return true;
}
bool decode_sensor_config(pkt_sensor_config* config, const unsigned char* buffer, int size)
{
if(!(size == 7 || size == 8)){
LOGE("invalid packet size (expected 7 or 8 but got %d)", size);
return false;
}
SKIP_CMD;
config->command_id = READ16;
config->flags = READ8;
config->packet_interval = READ8;
config->keep_alive_interval = READ16;
return true;
}
static void decode_sample(const unsigned char* buffer, int32_t* smp)
{
/*
* Decode 3 tightly packed 21 bit values from 4 bytes.
* We unpack them in the higher 21 bit values first and then shift
* them down to the lower in order to get the sign bits correct.
*/
int x = (buffer[0] << 24) | (buffer[1] << 16) | ((buffer[2] & 0xF8) << 8);
int y = ((buffer[2] & 0x07) << 29) | (buffer[3] << 21) | (buffer[4] << 13) | ((buffer[5] & 0xC0) << 5);
int z = ((buffer[5] & 0x3F) << 26) | (buffer[6] << 18) | (buffer[7] << 10);
smp[0] = x >> 11;
smp[1] = y >> 11;
smp[2] = z >> 11;
}
bool decode_tracker_sensor_msg(pkt_tracker_sensor* msg, const unsigned char* buffer, int size)
{
if(!(size == 62 || size == 64)){
LOGE("invalid packet size (expected 62 or 64 but got %d)", size);
return false;
}
SKIP_CMD;
msg->num_samples = READ8;
msg->timestamp = READ16;
msg->timestamp *= 1000; // DK1 timestamps are in milliseconds
msg->last_command_id = READ16;
msg->temperature = READ16;
msg->num_samples = OHMD_MIN(msg->num_samples, 3);
for(int i = 0; i < msg->num_samples; i++){
decode_sample(buffer, msg->samples[i].accel);
buffer += 8;
decode_sample(buffer, msg->samples[i].gyro);
buffer += 8;
}
// Skip empty samples
buffer += (3 - msg->num_samples) * 16;
for(int i = 0; i < 3; i++){
msg->mag[i] = READ16;
}
return true;
}
bool decode_tracker_sensor_msg_dk2(pkt_tracker_sensor* msg, const unsigned char* buffer, int size)
{
if(!(size == 64)){
LOGE("invalid packet size (expected 62 or 64 but got %d)", size);
return false;
}
SKIP_CMD;
msg->last_command_id = READ16;
msg->num_samples = READ8;
/* Next is the number of samples since start, excluding the samples
contained in this packet */
buffer += 2; // unused: nb_samples_since_start
msg->temperature = READ16;
msg->timestamp = READ32;
/* Second sample value is junk (outdated/uninitialized) value if
num_samples < 2. */
msg->num_samples = OHMD_MIN(msg->num_samples, 2);
for(int i = 0; i < msg->num_samples; i++){
decode_sample(buffer, msg->samples[i].accel);
buffer += 8;
decode_sample(buffer, msg->samples[i].gyro);
buffer += 8;
}
// Skip empty samples
buffer += (2 - msg->num_samples) * 16;
for(int i = 0; i < 3; i++){
msg->mag[i] = READ16;
}
// TODO: positional tracking data and frame data
return true;
}
// TODO do we need to consider HMD vs sensor "centric" values
void vec3f_from_rift_vec(const int32_t* smp, vec3f* out_vec)
{
out_vec->x = (float)smp[0] * 0.0001f;
out_vec->y = (float)smp[1] * 0.0001f;
out_vec->z = (float)smp[2] * 0.0001f;
}
int encode_sensor_config(unsigned char* buffer, const pkt_sensor_config* config)
{
WRITE8(RIFT_CMD_SENSOR_CONFIG);
WRITE16(config->command_id);
WRITE8(config->flags);
WRITE8(config->packet_interval);
WRITE16(config->keep_alive_interval);
return 7; // sensor config packet size
}
int encode_keep_alive(unsigned char* buffer, const pkt_keep_alive* keep_alive)
{
WRITE8(RIFT_CMD_KEEP_ALIVE);
WRITE16(keep_alive->command_id);
WRITE16(keep_alive->keep_alive_interval);
return 5; // keep alive packet size
}
int encode_enable_components(unsigned char* buffer, bool display, bool audio)
{
uint8_t flags = 0;
WRITE8(RIFT_CMD_ENABLE_COMPONENTS);
WRITE16(0); // last command ID
if (display)
flags |= 1;
if (audio)
flags |= 2;
// flags |= 4; // I don't know what it is. Wireless?
WRITE8(flags);
return 4;
}
void dump_packet_sensor_range(const pkt_sensor_range* range)
{
(void)range;
LOGD("sensor range\n");
LOGD(" command id: %d", range->command_id);
LOGD(" accel scale: %d", range->accel_scale);
LOGD(" gyro scale: %d", range->gyro_scale);
LOGD(" mag scale: %d", range->mag_scale);
}
void dump_packet_sensor_display_info(const pkt_sensor_display_info* info)
{
(void)info;
LOGD("display info");
LOGD(" command id: %d", info->command_id);
LOGD(" distortion_type: %d", info->distortion_type);
LOGD(" resolution: %d x %d", info->h_resolution, info->v_resolution);
LOGD(" screen size: %f x %f", info->h_screen_size, info->v_screen_size);
LOGD(" vertical center: %f", info->v_center);
LOGD(" lens_separation: %f", info->lens_separation);
LOGD(" eye_to_screen_distance: %f, %f", info->eye_to_screen_distance[0], info->eye_to_screen_distance[1]);
LOGD(" distortion_k: %f, %f, %f, %f, %f, %f",
info->distortion_k[0], info->distortion_k[1], info->distortion_k[2],
info->distortion_k[3], info->distortion_k[4], info->distortion_k[5]);
}
void dump_packet_sensor_config(const pkt_sensor_config* config)
{
(void)config;
LOGD("sensor config");
LOGD(" command id: %u", config->command_id);
LOGD(" flags: %02x", config->flags);
LOGD(" raw mode: %d", !!(config->flags & RIFT_SCF_RAW_MODE));
LOGD(" calibration test: %d", !!(config->flags & RIFT_SCF_CALIBRATION_TEST));
LOGD(" use calibration: %d", !!(config->flags & RIFT_SCF_USE_CALIBRATION));
LOGD(" auto calibration: %d", !!(config->flags & RIFT_SCF_AUTO_CALIBRATION));
LOGD(" motion keep alive: %d", !!(config->flags & RIFT_SCF_MOTION_KEEP_ALIVE));
LOGD(" motion command keep alive: %d", !!(config->flags & RIFT_SCF_COMMAND_KEEP_ALIVE));
LOGD(" sensor coordinates: %d", !!(config->flags & RIFT_SCF_SENSOR_COORDINATES));
LOGD(" packet interval: %u", config->packet_interval);
LOGD(" keep alive interval: %u", config->keep_alive_interval);
}
void dump_packet_tracker_sensor(const pkt_tracker_sensor* sensor)
{
(void)sensor;
LOGD("tracker sensor:");
LOGD(" last command id: %u", sensor->last_command_id);
LOGD(" timestamp: %u", sensor->timestamp);
LOGD(" temperature: %d", sensor->temperature);
LOGD(" num samples: %u", sensor->num_samples);
LOGD(" magnetic field: %i %i %i", sensor->mag[0], sensor->mag[1], sensor->mag[2]);
for(int i = 0; i < sensor->num_samples; i++){
LOGD(" accel: %d %d %d", sensor->samples[i].accel[0], sensor->samples[i].accel[1], sensor->samples[i].accel[2]);
LOGD(" gyro: %d %d %d", sensor->samples[i].gyro[0], sensor->samples[i].gyro[1], sensor->samples[i].gyro[2]);
}
}

View File

@@ -0,0 +1,456 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Oculus Rift Driver - HID/USB Driver Implementation */
#include <stdlib.h>
#include <hidapi.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include "rift.h"
#define TICK_LEN (1.0f / 1000.0f) // 1000 Hz ticks
#define KEEP_ALIVE_VALUE (10 * 1000)
#define SETFLAG(_s, _flag, _val) (_s) = ((_s) & ~(_flag)) | ((_val) ? (_flag) : 0)
typedef struct {
ohmd_device base;
hid_device* handle;
pkt_sensor_range sensor_range;
pkt_sensor_display_info display_info;
rift_coordinate_frame coordinate_frame, hw_coordinate_frame;
pkt_sensor_config sensor_config;
pkt_tracker_sensor sensor;
uint32_t last_imu_timestamp;
double last_keep_alive;
fusion sensor_fusion;
vec3f raw_mag, raw_accel, raw_gyro;
} rift_priv;
typedef enum {
REV_DK1,
REV_DK2,
REV_CV1
} rift_revision;
typedef struct {
const char* name;
int id;
int iface;
rift_revision rev;
} rift_devices;
static rift_priv* rift_priv_get(ohmd_device* device)
{
return (rift_priv*)device;
}
static int get_feature_report(rift_priv* priv, rift_sensor_feature_cmd cmd, unsigned char* buf)
{
memset(buf, 0, FEATURE_BUFFER_SIZE);
buf[0] = (unsigned char)cmd;
return hid_get_feature_report(priv->handle, buf, FEATURE_BUFFER_SIZE);
}
static int send_feature_report(rift_priv* priv, const unsigned char *data, size_t length)
{
return hid_send_feature_report(priv->handle, data, length);
}
static void set_coordinate_frame(rift_priv* priv, rift_coordinate_frame coordframe)
{
priv->coordinate_frame = coordframe;
// set the RIFT_SCF_SENSOR_COORDINATES in the sensor config to match whether coordframe is hmd or sensor
SETFLAG(priv->sensor_config.flags, RIFT_SCF_SENSOR_COORDINATES, coordframe == RIFT_CF_SENSOR);
// encode send the new config to the Rift
unsigned char buf[FEATURE_BUFFER_SIZE];
int size = encode_sensor_config(buf, &priv->sensor_config);
if(send_feature_report(priv, buf, size) == -1){
ohmd_set_error(priv->base.ctx, "send_feature_report failed in set_coordinate frame");
return;
}
// read the state again, set the hw_coordinate_frame to match what
// the hardware actually is set to just incase it doesn't stick.
size = get_feature_report(priv, RIFT_CMD_SENSOR_CONFIG, buf);
if(size <= 0){
LOGW("could not set coordinate frame");
priv->hw_coordinate_frame = RIFT_CF_HMD;
return;
}
decode_sensor_config(&priv->sensor_config, buf, size);
priv->hw_coordinate_frame = (priv->sensor_config.flags & RIFT_SCF_SENSOR_COORDINATES) ? RIFT_CF_SENSOR : RIFT_CF_HMD;
if(priv->hw_coordinate_frame != coordframe) {
LOGW("coordinate frame didn't stick");
}
}
static void handle_tracker_sensor_msg(rift_priv* priv, unsigned char* buffer, int size)
{
if (buffer[0] == RIFT_IRQ_SENSORS
&& !decode_tracker_sensor_msg(&priv->sensor, buffer, size)){
LOGE("couldn't decode tracker sensor message");
}
if (buffer[0] == RIFT_IRQ_SENSORS_DK2
&& !decode_tracker_sensor_msg_dk2(&priv->sensor, buffer, size)){
LOGE("couldn't decode tracker sensor message");
}
pkt_tracker_sensor* s = &priv->sensor;
dump_packet_tracker_sensor(s);
int32_t mag32[] = { s->mag[0], s->mag[1], s->mag[2] };
vec3f_from_rift_vec(mag32, &priv->raw_mag);
// TODO: handle overflows in a nicer way
float dt = TICK_LEN; // TODO: query the Rift for the sample rate
if (s->timestamp > priv->last_imu_timestamp)
{
dt = (s->timestamp - priv->last_imu_timestamp) / 1000000.0f;
dt -= (s->num_samples - 1) * TICK_LEN; // TODO: query the Rift for the sample rate
}
for(int i = 0; i < s->num_samples; i++){
vec3f_from_rift_vec(s->samples[i].accel, &priv->raw_accel);
vec3f_from_rift_vec(s->samples[i].gyro, &priv->raw_gyro);
ofusion_update(&priv->sensor_fusion, dt, &priv->raw_gyro, &priv->raw_accel, &priv->raw_mag);
dt = TICK_LEN; // TODO: query the Rift for the sample rate
}
priv->last_imu_timestamp = s->timestamp;
}
static void update_device(ohmd_device* device)
{
rift_priv* priv = rift_priv_get(device);
unsigned char buffer[FEATURE_BUFFER_SIZE];
// Handle keep alive messages
double t = ohmd_get_tick();
if(t - priv->last_keep_alive >= (double)priv->sensor_config.keep_alive_interval / 1000.0 - .2){
// send keep alive message
pkt_keep_alive keep_alive = { 0, priv->sensor_config.keep_alive_interval };
int ka_size = encode_keep_alive(buffer, &keep_alive);
if (send_feature_report(priv, buffer, ka_size) == -1)
LOGE("error sending keepalive");
// Update the time of the last keep alive we have sent.
priv->last_keep_alive = t;
}
// Read all the messages from the device.
while(true){
int size = hid_read(priv->handle, buffer, FEATURE_BUFFER_SIZE);
if(size < 0){
LOGE("error reading from device");
return;
} else if(size == 0) {
return; // No more messages, return.
}
// currently the only message type the hardware supports (I think)
if(buffer[0] == RIFT_IRQ_SENSORS || buffer[0] == RIFT_IRQ_SENSORS_DK2) {
handle_tracker_sensor_msg(priv, buffer, size);
}else{
LOGE("unknown message type: %u", buffer[0]);
}
}
}
static int getf(ohmd_device* device, ohmd_float_value type, float* out)
{
rift_priv* priv = rift_priv_get(device);
switch(type){
case OHMD_DISTORTION_K: {
for (int i = 0; i < 6; i++) {
out[i] = priv->display_info.distortion_k[i];
}
break;
}
case OHMD_ROTATION_QUAT: {
*(quatf*)out = priv->sensor_fusion.orient;
break;
}
case OHMD_POSITION_VECTOR:
out[0] = out[1] = out[2] = 0;
break;
default:
ohmd_set_error(priv->base.ctx, "invalid type given to getf (%ud)", type);
return -1;
break;
}
return 0;
}
static void close_device(ohmd_device* device)
{
LOGD("closing device");
rift_priv* priv = rift_priv_get(device);
hid_close(priv->handle);
free(priv);
}
#ifndef _MSC_VER
static char* _hid_to_unix_path(char* path)
{
char bus [4];
char dev [4];
char *result = malloc( sizeof(char) * ( 20 + 1 ) );
sprintf (bus, "%.*s\n", 4, path);
sprintf (dev, "%.*s\n", 4, path + 5);
sprintf (result, "/dev/bus/usb/%03d/%03d",
(int)strtol(bus, NULL, 16),
(int)strtol(dev, NULL, 16));
return result;
}
#else
static char* _hid_to_unix_path(char* path)
{
return path;
}
#endif
static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
{
rift_priv* priv = ohmd_alloc(driver->ctx, sizeof(rift_priv));
if(!priv)
goto cleanup;
priv->last_imu_timestamp = -1;
priv->base.ctx = driver->ctx;
ohmd_toggle_ovr_service(0); //disable OVRService if running
// Open the HID device
priv->handle = hid_open_path(desc->path);
if(!priv->handle) {
char* path = _hid_to_unix_path(desc->path);
ohmd_set_error(driver->ctx, "Could not open %s. "
"Check your rights.", path);
#ifndef _MSC_VER
free(path);
#endif
goto cleanup;
}
if(hid_set_nonblocking(priv->handle, 1) == -1){
ohmd_set_error(driver->ctx, "failed to set non-blocking on device");
goto cleanup;
}
unsigned char buf[FEATURE_BUFFER_SIZE];
int size;
// Read and decode the sensor range
size = get_feature_report(priv, RIFT_CMD_RANGE, buf);
decode_sensor_range(&priv->sensor_range, buf, size);
dump_packet_sensor_range(&priv->sensor_range);
// Read and decode display information
size = get_feature_report(priv, RIFT_CMD_DISPLAY_INFO, buf);
decode_sensor_display_info(&priv->display_info, buf, size);
dump_packet_sensor_display_info(&priv->display_info);
// Read and decode the sensor config
size = get_feature_report(priv, RIFT_CMD_SENSOR_CONFIG, buf);
decode_sensor_config(&priv->sensor_config, buf, size);
dump_packet_sensor_config(&priv->sensor_config);
// if the sensor has display info data, use HMD coordinate frame
priv->coordinate_frame = priv->display_info.distortion_type != RIFT_DT_NONE ? RIFT_CF_HMD : RIFT_CF_SENSOR;
// enable calibration
SETFLAG(priv->sensor_config.flags, RIFT_SCF_USE_CALIBRATION, 1);
SETFLAG(priv->sensor_config.flags, RIFT_SCF_AUTO_CALIBRATION, 1);
// apply sensor config
set_coordinate_frame(priv, priv->coordinate_frame);
// Turn the screens on
if (desc->revision == REV_CV1)
{
size = encode_enable_components(buf, true, true);
if (send_feature_report(priv, buf, size) == -1)
LOGE("error turning the screens on");
}
// set keep alive interval to n seconds
pkt_keep_alive keep_alive = { 0, KEEP_ALIVE_VALUE };
size = encode_keep_alive(buf, &keep_alive);
if (send_feature_report(priv, buf, size) == -1)
LOGE("error setting up keepalive");
// Update the time of the last keep alive we have sent.
priv->last_keep_alive = ohmd_get_tick();
// update sensor settings with new keep alive value
// (which will have been ignored in favor of the default 1000 ms one)
size = get_feature_report(priv, RIFT_CMD_SENSOR_CONFIG, buf);
decode_sensor_config(&priv->sensor_config, buf, size);
dump_packet_sensor_config(&priv->sensor_config);
// Set default device properties
ohmd_set_default_device_properties(&priv->base.properties);
// Set device properties
priv->base.properties.hsize = priv->display_info.h_screen_size;
priv->base.properties.vsize = priv->display_info.v_screen_size;
priv->base.properties.hres = priv->display_info.h_resolution;
priv->base.properties.vres = priv->display_info.v_resolution;
priv->base.properties.lens_sep = priv->display_info.lens_separation;
priv->base.properties.lens_vpos = priv->display_info.v_center;
priv->base.properties.ratio = ((float)priv->display_info.h_resolution / (float)priv->display_info.v_resolution) / 2.0f;
//setup generic distortion coeffs, from hand-calibration
switch (desc->revision) {
case REV_DK2:
ohmd_set_universal_distortion_k(&(priv->base.properties), 0.247, -0.145, 0.103, 0.795);
ohmd_set_universal_aberration_k(&(priv->base.properties), 0.985, 1.000, 1.015);
break;
case REV_DK1:
ohmd_set_universal_distortion_k(&(priv->base.properties), 1.003, -1.005, 0.403, 0.599);
ohmd_set_universal_aberration_k(&(priv->base.properties), 0.985, 1.000, 1.015);
break;
case REV_CV1:
ohmd_set_universal_distortion_k(&(priv->base.properties), 0.098, .324, -0.241, 0.819);
ohmd_set_universal_aberration_k(&(priv->base.properties), 0.9952420, 1.0, 1.0008074);
/* CV1 reports IPD, but not lens center, at least not anywhere I could find, so use the manually measured value of 0.054 */
priv->display_info.lens_separation = 0.054;
priv->base.properties.lens_sep = priv->display_info.lens_separation;
default:
break;
}
// calculate projection eye projection matrices from the device properties
//ohmd_calc_default_proj_matrices(&priv->base.properties);
float l,r,t,b,n,f;
// left eye screen bounds
l = -1.0f * (priv->display_info.h_screen_size/2 - priv->display_info.lens_separation/2);
r = priv->display_info.lens_separation/2;
t = priv->display_info.v_screen_size - priv->display_info.v_center;
b = -1.0f * priv->display_info.v_center;
n = priv->display_info.eye_to_screen_distance[0];
f = n*10e6;
//LOGD("l: %0.3f, r: %0.3f, b: %0.3f, t: %0.3f, n: %0.3f, f: %0.3f", l,r,b,t,n,f);
/* eye separation is handled by IPD in the Modelview matrix */
omat4x4f_init_frustum(&priv->base.properties.proj_left, l, r, b, t, n, f);
//right eye screen bounds
l = -1.0f * priv->display_info.lens_separation/2;
r = priv->display_info.h_screen_size/2 - priv->display_info.lens_separation/2;
n = priv->display_info.eye_to_screen_distance[1];
f = n*10e6;
//LOGD("l: %0.3f, r: %0.3f, b: %0.3f, t: %0.3f, n: %0.3f, f: %0.3f", l,r,b,t,n,f);
/* eye separation is handled by IPD in the Modelview matrix */
omat4x4f_init_frustum(&priv->base.properties.proj_right, l, r, b, t, n, f);
priv->base.properties.fov = 2 * atan2f(
priv->display_info.h_screen_size/2 - priv->display_info.lens_separation/2,
priv->display_info.eye_to_screen_distance[0]);
// set up device callbacks
priv->base.update = update_device;
priv->base.close = close_device;
priv->base.getf = getf;
// initialize sensor fusion
ofusion_init(&priv->sensor_fusion);
return &priv->base;
cleanup:
if(priv)
free(priv);
return NULL;
}
#define OCULUS_VR_INC_ID 0x2833
#define RIFT_ID_COUNT 4
static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
{
// enumerate HID devices and add any Rifts found to the device list
rift_devices rd[RIFT_ID_COUNT] = {
{ "Rift (DK1)", 0x0001, -1, REV_DK1 },
{ "Rift (DK2)", 0x0021, -1, REV_DK2 },
{ "Rift (DK2)", 0x2021, -1, REV_DK2 },
{ "Rift (CV1)", 0x0031, 0, REV_CV1 },
};
for(int i = 0; i < RIFT_ID_COUNT; i++){
struct hid_device_info* devs = hid_enumerate(OCULUS_VR_INC_ID, rd[i].id);
struct hid_device_info* cur_dev = devs;
if(devs == NULL)
continue;
while (cur_dev) {
if(rd[i].iface == -1 || cur_dev->interface_number == rd[i].iface){
ohmd_device_desc* desc = &list->devices[list->num_devices++];
strcpy(desc->driver, "OpenHMD Rift Driver");
strcpy(desc->vendor, "Oculus VR, Inc.");
strcpy(desc->product, rd[i].name);
desc->revision = rd[i].rev;
strcpy(desc->path, cur_dev->path);
desc->driver_ptr = driver;
}
cur_dev = cur_dev->next;
}
hid_free_enumeration(devs);
}
}
static void destroy_driver(ohmd_driver* drv)
{
LOGD("shutting down driver");
hid_exit();
free(drv);
ohmd_toggle_ovr_service(1); //re-enable OVRService if previously running
}
ohmd_driver* ohmd_create_oculus_rift_drv(ohmd_context* ctx)
{
ohmd_driver* drv = ohmd_alloc(ctx, sizeof(ohmd_driver));
if(drv == NULL)
return NULL;
drv->get_device_list = get_device_list;
drv->open_device = open_device;
drv->destroy = destroy_driver;
drv->ctx = ctx;
return drv;
}

View File

@@ -0,0 +1,115 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Oculus Rift Driver Internal Interface */
#ifndef RIFT_H
#define RIFT_H
#include "../openhmdi.h"
#define FEATURE_BUFFER_SIZE 256
typedef enum {
RIFT_CMD_SENSOR_CONFIG = 2,
RIFT_CMD_RANGE = 4,
RIFT_CMD_KEEP_ALIVE = 8,
RIFT_CMD_DISPLAY_INFO = 9,
RIFT_CMD_ENABLE_COMPONENTS = 0x1d
} rift_sensor_feature_cmd;
typedef enum {
RIFT_CF_SENSOR,
RIFT_CF_HMD
} rift_coordinate_frame;
typedef enum {
RIFT_IRQ_SENSORS = 1,
RIFT_IRQ_SENSORS_DK2 = 11
} rift_irq_cmd;
typedef enum {
RIFT_DT_NONE,
RIFT_DT_SCREEN_ONLY,
RIFT_DT_DISTORTION
} rift_distortion_type;
// Sensor config flags
#define RIFT_SCF_RAW_MODE 0x01
#define RIFT_SCF_CALIBRATION_TEST 0x02
#define RIFT_SCF_USE_CALIBRATION 0x04
#define RIFT_SCF_AUTO_CALIBRATION 0x08
#define RIFT_SCF_MOTION_KEEP_ALIVE 0x10
#define RIFT_SCF_COMMAND_KEEP_ALIVE 0x20
#define RIFT_SCF_SENSOR_COORDINATES 0x40
typedef struct {
uint16_t command_id;
uint16_t accel_scale;
uint16_t gyro_scale;
uint16_t mag_scale;
} pkt_sensor_range;
typedef struct {
int32_t accel[3];
int32_t gyro[3];
} pkt_tracker_sample;
typedef struct {
uint8_t num_samples;
uint32_t timestamp;
uint16_t last_command_id;
int16_t temperature;
pkt_tracker_sample samples[3];
int16_t mag[3];
} pkt_tracker_sensor;
typedef struct {
uint16_t command_id;
uint8_t flags;
uint16_t packet_interval;
uint16_t keep_alive_interval; // in ms
} pkt_sensor_config;
typedef struct {
uint16_t command_id;
rift_distortion_type distortion_type;
uint8_t distortion_type_opts;
uint16_t h_resolution, v_resolution;
float h_screen_size, v_screen_size;
float v_center;
float lens_separation;
float eye_to_screen_distance[2];
float distortion_k[6];
} pkt_sensor_display_info;
typedef struct {
uint16_t command_id;
uint16_t keep_alive_interval;
} pkt_keep_alive;
bool decode_sensor_range(pkt_sensor_range* range, const unsigned char* buffer, int size);
bool decode_sensor_display_info(pkt_sensor_display_info* info, const unsigned char* buffer, int size);
bool decode_sensor_config(pkt_sensor_config* config, const unsigned char* buffer, int size);
bool decode_tracker_sensor_msg(pkt_tracker_sensor* msg, const unsigned char* buffer, int size);
bool decode_tracker_sensor_msg_dk2(pkt_tracker_sensor* msg, const unsigned char* buffer, int size);
void vec3f_from_rift_vec(const int32_t* smp, vec3f* out_vec);
int encode_sensor_config(unsigned char* buffer, const pkt_sensor_config* config);
int encode_keep_alive(unsigned char* buffer, const pkt_keep_alive* keep_alive);
int encode_enable_components(unsigned char* buffer, bool display, bool audio);
void dump_packet_sensor_range(const pkt_sensor_range* range);
void dump_packet_sensor_config(const pkt_sensor_config* config);
void dump_packet_sensor_display_info(const pkt_sensor_display_info* info);
void dump_packet_tracker_sensor(const pkt_tracker_sensor* sensor);
#endif

53
extern/openhmd/src/drv_psvr/packet.c vendored Normal file
View File

@@ -0,0 +1,53 @@
#include "psvr.h"
#ifdef _MSC_VER
#define inline __inline
#endif
inline static uint8_t read8(const unsigned char** buffer)
{
uint8_t ret = **buffer;
*buffer += 1;
return ret;
}
inline static int16_t read16(const unsigned char** buffer)
{
int16_t ret = **buffer | (*(*buffer + 1) << 8);
*buffer += 2;
return ret;
}
inline static uint32_t read32(const unsigned char** buffer)
{
uint32_t ret = **buffer | (*(*buffer + 1) << 8) | (*(*buffer + 2) << 16) | (*(*buffer + 3) << 24);
*buffer += 4;
return ret;
}
bool psvr_decode_sensor_packet(psvr_sensor_packet* pkt, const unsigned char* buffer, int size)
{
if(size != 64){
LOGE("invalid psvr sensor packet size (expected 64 but got %d)", size);
return false;
}
buffer += 2; //skip 2
pkt->samples[0].volume = read16(&buffer); //volume
buffer += 12; //unknown, skip 12
pkt->samples[0].tick = read32(&buffer); //TICK
// acceleration
for(int i = 0; i < 3; i++){
pkt->samples[0].gyro[i] = read16(&buffer);
}
// rotation
for(int i = 0; i < 3; i++){
pkt->samples[0].accel[i] = read16(&buffer);
}//34
buffer += 23; //probably other sample somewhere
pkt->samples[0].proximity = read8(&buffer); //255 for close
pkt->samples[0].proximity_state = read8(&buffer); // 0 (nothing) to 3 (headset is on)
return true;
}

296
extern/openhmd/src/drv_psvr/psvr.c vendored Normal file
View File

@@ -0,0 +1,296 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Sony PSVR Driver */
#define FEATURE_BUFFER_SIZE 256
#define TICK_LEN (1.0f / 1000000.0f) // 1000 Hz ticks
#define SONY_ID 0x054c
#define PSVR_HMD 0x09af
#include <string.h>
#include <wchar.h>
#include <hidapi.h>
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdbool.h>
#include "psvr.h"
typedef struct {
ohmd_device base;
hid_device* hmd_handle;
hid_device* hmd_control;
fusion sensor_fusion;
vec3f raw_accel, raw_gyro;
uint32_t last_ticks;
uint8_t last_seq;
psvr_sensor_packet sensor;
} psvr_priv;
void vec3f_from_psvr_vec(const int16_t* smp, vec3f* out_vec)
{
out_vec->x = (float)smp[1] * 0.001f;
out_vec->y = (float)smp[0] * 0.001f;
out_vec->z = (float)smp[2] * 0.001f * -1.0f;
}
static void handle_tracker_sensor_msg(psvr_priv* priv, unsigned char* buffer, int size)
{
uint32_t last_sample_tick = priv->sensor.tick;
if(!psvr_decode_sensor_packet(&priv->sensor, buffer, size)){
LOGE("couldn't decode tracker sensor message");
}
psvr_sensor_packet* s = &priv->sensor;
uint32_t tick_delta = 1000;
if(last_sample_tick > 0) //startup correction
tick_delta = s->tick - last_sample_tick;
float dt = tick_delta * TICK_LEN;
vec3f mag = {{0.0f, 0.0f, 0.0f}};
for(int i = 0; i < 1; i++){ //just use 1 sample since we don't have sample order for frame
vec3f_from_psvr_vec(s->samples[i].accel, &priv->raw_accel);
vec3f_from_psvr_vec(s->samples[i].gyro, &priv->raw_gyro);
ofusion_update(&priv->sensor_fusion, dt, &priv->raw_gyro, &priv->raw_accel, &mag);
// reset dt to tick_len for the last samples if there were more than one sample
dt = TICK_LEN;
}
}
static void update_device(ohmd_device* device)
{
psvr_priv* priv = (psvr_priv*)device;
int size = 0;
unsigned char buffer[FEATURE_BUFFER_SIZE];
while(true){
int size = hid_read(priv->hmd_handle, buffer, FEATURE_BUFFER_SIZE);
if(size < 0){
LOGE("error reading from device");
return;
} else if(size == 0) {
return; // No more messages, return.
}
// currently the only message type the hardware supports (I think)
if(buffer[0] == PSVR_IRQ_SENSORS){
handle_tracker_sensor_msg(priv, buffer, size);
}else if (buffer[0] == PSVR_IRQ_VOLUME_PLUS){
//TODO implement
}else if (buffer[0] == PSVR_IRQ_VOLUME_MINUS){
//TODO implement
}else if (buffer[0] == PSVR_IRQ_MIC_MUTE){
//TODO implement
}else{
LOGE("unknown message type: %u", buffer[0]);
}
}
if(size < 0){
LOGE("error reading from device");
}
}
static int getf(ohmd_device* device, ohmd_float_value type, float* out)
{
psvr_priv* priv = (psvr_priv*)device;
switch(type){
case OHMD_ROTATION_QUAT:
*(quatf*)out = priv->sensor_fusion.orient;
break;
case OHMD_POSITION_VECTOR:
out[0] = out[1] = out[2] = 0;
break;
case OHMD_DISTORTION_K:
// TODO this should be set to the equivalent of no distortion
memset(out, 0, sizeof(float) * 6);
break;
default:
ohmd_set_error(priv->base.ctx, "invalid type given to getf (%ud)", type);
return -1;
break;
}
return 0;
}
static void close_device(ohmd_device* device)
{
psvr_priv* priv = (psvr_priv*)device;
LOGD("closing HTC PSVR device");
hid_close(priv->hmd_handle);
hid_close(priv->hmd_control);
free(device);
}
static hid_device* open_device_idx(int manufacturer, int product, int iface, int iface_tot, int device_index)
{
struct hid_device_info* devs = hid_enumerate(manufacturer, product);
struct hid_device_info* cur_dev = devs;
int idx = 0;
int iface_cur = 0;
hid_device* ret = NULL;
while (cur_dev) {
printf("%04x:%04x %s\n", (unsigned int)manufacturer, (unsigned int)product, cur_dev->path);
if(idx == device_index && iface == iface_cur){
ret = hid_open_path(cur_dev->path);
printf("opening\n");
}
cur_dev = cur_dev->next;
iface_cur++;
if(iface_cur >= iface_tot){
idx++;
iface_cur = 0;
}
}
hid_free_enumeration(devs);
return ret;
}
static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
{
psvr_priv* priv = ohmd_alloc(driver->ctx, sizeof(psvr_priv));
if(!priv)
return NULL;
priv->base.ctx = driver->ctx;
int idx = atoi(desc->path);
// Open the HMD device
priv->hmd_handle = open_device_idx(SONY_ID, PSVR_HMD, 0, 0, idx);
if(!priv->hmd_handle)
goto cleanup;
if(hid_set_nonblocking(priv->hmd_handle, 1) == -1){
ohmd_set_error(driver->ctx, "failed to set non-blocking on device");
goto cleanup;
}
// Open the HMD Control device
priv->hmd_control = open_device_idx(SONY_ID, PSVR_HMD, 0, 0, 1);
if(!priv->hmd_control)
goto cleanup;
if(hid_set_nonblocking(priv->hmd_control, 1) == -1){
ohmd_set_error(driver->ctx, "failed to set non-blocking on device");
goto cleanup;
}
// turn the display on
hid_write(priv->hmd_control, psvr_power_on, sizeof(psvr_power_on));
// set VR mode for the hmd
hid_write(priv->hmd_control, psvr_vrmode_on, sizeof(psvr_vrmode_on));
// Set default device properties
ohmd_set_default_device_properties(&priv->base.properties);
// Set device properties TODO: Get from device
priv->base.properties.hsize = 0.126; //from calculated specs
priv->base.properties.vsize = 0.071; //from calculated specs
priv->base.properties.hres = 1920;
priv->base.properties.vres = 1080;
priv->base.properties.lens_sep = 0.063500;
priv->base.properties.lens_vpos = 0.049694;
priv->base.properties.fov = DEG_TO_RAD(103.57f); //TODO: Confirm exact mesurements
priv->base.properties.ratio = (1920.0f / 1080.0f) / 2.0f;
// calculate projection eye projection matrices from the device properties
ohmd_calc_default_proj_matrices(&priv->base.properties);
// set up device callbacks
priv->base.update = update_device;
priv->base.close = close_device;
priv->base.getf = getf;
ofusion_init(&priv->sensor_fusion);
return (ohmd_device*)priv;
cleanup:
if(priv)
free(priv);
return NULL;
}
static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
{
struct hid_device_info* devs = hid_enumerate(SONY_ID, PSVR_HMD);
struct hid_device_info* cur_dev = devs;
int idx = 0;
while (cur_dev) {
ohmd_device_desc* desc = &list->devices[list->num_devices++];
strcpy(desc->driver, "OpenHMD Sony PSVR Driver");
strcpy(desc->vendor, "Sony");
strcpy(desc->product, "PSVR");
desc->revision = 0;
snprintf(desc->path, OHMD_STR_SIZE, "%d", idx);
desc->driver_ptr = driver;
cur_dev = cur_dev->next;
idx++;
}
hid_free_enumeration(devs);
}
static void destroy_driver(ohmd_driver* drv)
{
LOGD("shutting down Sony PSVR driver");
free(drv);
}
ohmd_driver* ohmd_create_psvr_drv(ohmd_context* ctx)
{
ohmd_driver* drv = ohmd_alloc(ctx, sizeof(ohmd_driver));
if(!drv)
return NULL;
drv->get_device_list = get_device_list;
drv->open_device = open_device;
drv->destroy = destroy_driver;
drv->ctx = ctx;
return drv;
}

48
extern/openhmd/src/drv_psvr/psvr.h vendored Normal file
View File

@@ -0,0 +1,48 @@
#ifndef PSVR_H
#define PSVR_H
#include <stdint.h>
#include <stdbool.h>
#include "../openhmdi.h"
typedef enum
{
PSVR_IRQ_SENSORS = 0,
PSVR_IRQ_VOLUME_PLUS = 2,
PSVR_IRQ_VOLUME_MINUS = 4,
PSVR_IRQ_MIC_MUTE = 8
} psvr_irq_cmd;
typedef struct
{
int16_t accel[3];
int16_t gyro[3];
uint32_t tick;
uint8_t seq;
uint8_t volume;
uint8_t proximity;
uint8_t proximity_state;
} psvr_sensor_sample;
typedef struct
{
uint8_t report_id;
uint32_t tick;
psvr_sensor_sample samples[1];
} psvr_sensor_packet;
static const unsigned char psvr_vrmode_on[12] = {
0x11, 0x00, 0xaa, 0x08, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char psvr_power_on[8] = {
0x17, 0x76, 0xaa, 0x04, 0x01, 0x00, 0x00, 0x00
};
void vec3f_from_psvr_vec(const int16_t* smp, vec3f* out_vec);
bool psvr_decode_sensor_packet(psvr_sensor_packet* pkt, const unsigned char* buffer, int size);
#endif

126
extern/openhmd/src/fusion.c vendored Normal file
View File

@@ -0,0 +1,126 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Sensor Fusion Implementation */
#include <string.h>
#include "openhmdi.h"
void ofusion_init(fusion* me)
{
memset(me, 0, sizeof(fusion));
me->orient.w = 1.0f;
ofq_init(&me->mag_fq, 20);
ofq_init(&me->accel_fq, 20);
ofq_init(&me->ang_vel_fq, 20);
me->flags = FF_USE_GRAVITY;
me->grav_gain = 0.05f;
}
void ofusion_update(fusion* me, float dt, const vec3f* ang_vel, const vec3f* accel, const vec3f* mag)
{
me->ang_vel = *ang_vel;
me->accel = *accel;
me->raw_mag = *mag;
me->mag = *mag;
vec3f world_accel;
oquatf_get_rotated(&me->orient, accel, &world_accel);
me->iterations += 1;
me->time += dt;
ofq_add(&me->mag_fq, mag);
ofq_add(&me->accel_fq, &world_accel);
ofq_add(&me->ang_vel_fq, ang_vel);
float ang_vel_length = ovec3f_get_length(ang_vel);
if(ang_vel_length > 0.0001f){
vec3f rot_axis =
{{ ang_vel->x / ang_vel_length, ang_vel->y / ang_vel_length, ang_vel->z / ang_vel_length }};
float rot_angle = ang_vel_length * dt;
quatf delta_orient;
oquatf_init_axis(&delta_orient, &rot_axis, rot_angle);
oquatf_mult_me(&me->orient, &delta_orient);
}
// gravity correction
if(me->flags & FF_USE_GRAVITY){
const float gravity_tolerance = .4f, ang_vel_tolerance = .1f;
const float min_tilt_error = 0.05f, max_tilt_error = 0.01f;
// if the device is within tolerance levels, count this as the device is level and add to the counter
// otherwise reset the counter and start over
me->device_level_count =
fabsf(ovec3f_get_length(accel) - 9.82f) < gravity_tolerance * 2.0f && ang_vel_length < ang_vel_tolerance
? me->device_level_count + 1 : 0;
// device has been level for long enough, grab mean from the accelerometer filter queue (last n values)
// and use for correction
if(me->device_level_count > 50){
me->device_level_count = 0;
vec3f accel_mean;
ofq_get_mean(&me->accel_fq, &accel_mean);
if (ovec3f_get_length(&accel_mean) - 9.82f < gravity_tolerance)
{
// Calculate a cross product between what the device
// thinks is up and what gravity indicates is down.
// The values are optimized of what we would get out
// from the cross product.
vec3f tilt = {{accel_mean.z, 0, -accel_mean.x}};
ovec3f_normalize_me(&tilt);
ovec3f_normalize_me(&accel_mean);
vec3f up = {{0, 1.0f, 0}};
float tilt_angle = ovec3f_get_angle(&up, &accel_mean);
if(tilt_angle > max_tilt_error){
me->grav_error_angle = tilt_angle;
me->grav_error_axis = tilt;
}
}
}
// preform gravity tilt correction
if(me->grav_error_angle > min_tilt_error){
float use_angle;
// if less than 2000 iterations have passed, set the up axis to the correction value outright
if(me->iterations < 2000){
use_angle = -me->grav_error_angle;
me->grav_error_angle = 0;
}
// otherwise try to correct
else {
use_angle = -me->grav_gain * me->grav_error_angle * 0.005f * (5.0f * ang_vel_length + 1.0f);
me->grav_error_angle += use_angle;
}
// perform the correction
quatf corr_quat, old_orient;
oquatf_init_axis(&corr_quat, &me->grav_error_axis, use_angle);
old_orient = me->orient;
oquatf_mult(&corr_quat, &old_orient, &me->orient);
}
}
// mitigate drift due to floating point
// inprecision with quat multiplication.
oquatf_normalize_me(&me->orient);
}

44
extern/openhmd/src/fusion.h vendored Normal file
View File

@@ -0,0 +1,44 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Sensor Fusion */
#ifndef FUSION_H
#define FUSION_H
#include "omath.h"
#define FF_USE_GRAVITY 1
typedef struct {
int state;
quatf orient; // orientation
vec3f accel; // acceleration
vec3f ang_vel; // angular velocity
vec3f mag; // magnetometer
vec3f raw_mag; // raw magnetometer values
int iterations;
float time;
int flags;
// filter queues for magnetometer, accelerometers and angular velocity
filter_queue mag_fq, accel_fq, ang_vel_fq;
// gravity correction
int device_level_count;
float grav_error_angle;
vec3f grav_error_axis;
float grav_gain; // amount of correction
} fusion;
void ofusion_init(fusion* me);
void ofusion_update(fusion* me, float dt, const vec3f* ang_vel, const vec3f* accel, const vec3f* mag_field);
#endif

39
extern/openhmd/src/log.h vendored Normal file
View File

@@ -0,0 +1,39 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Logging and Error Handling */
#ifndef LOG_H
#define LOG_H
void* ohmd_allocfn(ohmd_context* ctx, const char* e_msg, size_t size);
#define ohmd_alloc(_ctx, _size) ohmd_allocfn(_ctx, "could not allocate " #_size " bytes of RAM @ " __FILE__ ":" OHMD_STRINGIFY(__LINE__), _size)
#ifndef LOGLEVEL
#define LOGLEVEL 2
#endif
#define LOG(_level, _levelstr, ...) do{ if(_level >= LOGLEVEL){ printf("[%s] ", (_levelstr)); printf(__VA_ARGS__); puts(""); } } while(0)
#if LOGLEVEL == 0
#define LOGD(...) LOG(0, "DD", __VA_ARGS__)
#else
#define LOGD(...)
#endif
#define LOGV(...) LOG(1, "VV", __VA_ARGS__)
#define LOGI(...) LOG(2, "II", __VA_ARGS__)
#define LOGW(...) LOG(3, "WW", __VA_ARGS__)
#define LOGE(...) LOG(4, "EE", __VA_ARGS__)
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
#define ohmd_set_error(_ctx, ...) { snprintf((_ctx)->error_msg, OHMD_STR_SIZE, __VA_ARGS__); LOGE(__VA_ARGS__); }
#endif

395
extern/openhmd/src/omath.c vendored Normal file
View File

@@ -0,0 +1,395 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Math Code Implementation */
#include <string.h>
#include "openhmdi.h"
// vector
float ovec3f_get_length(const vec3f* me)
{
return sqrtf(POW2(me->x) + POW2(me->y) + POW2(me->z));
}
void ovec3f_normalize_me(vec3f* me)
{
if(me->x == 0 && me->y == 0 && me->z == 0)
return;
float len = ovec3f_get_length(me);
me->x /= len;
me->y /= len;
me->z /= len;
}
void ovec3f_subtract(const vec3f* a, const vec3f* b, vec3f* out)
{
for(int i = 0; i < 3; i++)
out->arr[i] = a->arr[i] - b->arr[i];
}
float ovec3f_get_dot(const vec3f* me, const vec3f* vec)
{
return me->x * vec->x + me->y * vec->y + me->z * vec->z;
}
float ovec3f_get_angle(const vec3f* me, const vec3f* vec)
{
float dot = ovec3f_get_dot(me, vec);
float lengths = ovec3f_get_length(me) * ovec3f_get_length(vec);
if(lengths == 0)
return 0;
return acosf(dot / lengths);
}
// quaternion
void oquatf_init_axis(quatf* me, const vec3f* vec, float angle)
{
vec3f norm = *vec;
ovec3f_normalize_me(&norm);
me->x = norm.x * sinf(angle / 2.0f);
me->y = norm.y * sinf(angle / 2.0f);
me->z = norm.z * sinf(angle / 2.0f);
me->w = cosf(angle / 2.0f);
}
void oquatf_get_rotated(const quatf* me, const vec3f* vec, vec3f* out_vec)
{
quatf q = {{vec->x * me->w + vec->z * me->y - vec->y * me->z,
vec->y * me->w + vec->x * me->z - vec->z * me->x,
vec->z * me->w + vec->y * me->x - vec->x * me->y,
vec->x * me->x + vec->y * me->y + vec->z * me->z}};
out_vec->x = me->w * q.x + me->x * q.w + me->y * q.z - me->z * q.y;
out_vec->y = me->w * q.y + me->y * q.w + me->z * q.x - me->x * q.z;
out_vec->z = me->w * q.z + me->z * q.w + me->x * q.y - me->y * q.x;
}
void oquatf_mult(const quatf* me, const quatf* q, quatf* out_q)
{
out_q->x = me->w * q->x + me->x * q->w + me->y * q->z - me->z * q->y;
out_q->y = me->w * q->y - me->x * q->z + me->y * q->w + me->z * q->x;
out_q->z = me->w * q->z + me->x * q->y - me->y * q->x + me->z * q->w;
out_q->w = me->w * q->w - me->x * q->x - me->y * q->y - me->z * q->z;
}
void oquatf_mult_me(quatf* me, const quatf* q)
{
quatf tmp = *me;
oquatf_mult(&tmp, q, me);
}
void oquatf_normalize_me(quatf* me)
{
float len = oquatf_get_length(me);
me->x /= len;
me->y /= len;
me->z /= len;
me->w /= len;
}
float oquatf_get_length(const quatf* me)
{
return sqrtf(me->x * me->x + me->y * me->y + me->z * me->z + me->w * me->w);
}
float oquatf_get_dot(const quatf* me, const quatf* q)
{
return me->x * q->x + me->y * q->y + me->z * q->z + me->w * q->w;
}
void oquatf_inverse(quatf* me)
{
float dot = oquatf_get_dot(me, me);
// conjugate
for(int i = 0; i < 3; i++)
me->arr[i] = -me->arr[i];
for(int i = 0; i < 4; i++)
me->arr[i] /= dot;
}
void oquatf_diff(const quatf* me, const quatf* q, quatf* out_q)
{
quatf inv = *me;
oquatf_inverse(&inv);
oquatf_mult(&inv, q, out_q);
}
void oquatf_slerp (float fT, const quatf* rkP, const quatf* rkQ, bool shortestPath, quatf* out_q)
{
float fCos = oquatf_get_dot(rkP, rkQ);
quatf rkT;
// Do we need to invert rotation?
if (fCos < 0.0f && shortestPath)
{
fCos = -fCos;
rkT = *rkQ;
oquatf_inverse(&rkT);
}
else
{
rkT = *rkQ;
}
if (fabsf(fCos) < 1 - 0.001f)
{
// Standard case (slerp)
float fSin = sqrtf(1 - (fCos*fCos));
float fAngle = atan2f(fSin, fCos);
float fInvSin = 1.0f / fSin;
float fCoeff0 = sin((1.0f - fT) * fAngle) * fInvSin;
float fCoeff1 = sin(fT * fAngle) * fInvSin;
out_q->x = fCoeff0 * rkP->x + fCoeff1 * rkT.x;
out_q->y = fCoeff0 * rkP->y + fCoeff1 * rkT.y;
out_q->z = fCoeff0 * rkP->z + fCoeff1 * rkT.z;
out_q->w = fCoeff0 * rkP->w + fCoeff1 * rkT.w;
//return fCoeff0 * rkP + fCoeff1 * rkT;
}
else
{
// There are two situations:
// 1. "rkP" and "rkQ" are very close (fCos ~= +1), so we can do a linear
// interpolation safely.
// 2. "rkP" and "rkQ" are almost inverse of each other (fCos ~= -1), there
// are an infinite number of possibilities interpolation. but we haven't
// have method to fix this case, so just use linear interpolation here.
//Quaternion t = (1.0f - fT) * rkP + fT * rkT;
out_q->x = (1.0f - fT) * rkP->x + fT * rkT.x;
out_q->y = (1.0f - fT) * rkP->y + fT * rkT.y;
out_q->z = (1.0f - fT) * rkP->z + fT * rkT.z;
out_q->w = (1.0f - fT) * rkP->w + fT * rkT.w;
oquatf_normalize_me(out_q);
// taking the complement requires renormalisation
//t.normalise();
//return t;
}
}
void oquatf_get_mat4x4(const quatf* me, const vec3f* point, float mat[4][4])
{
mat[0][0] = 1 - 2 * me->y * me->y - 2 * me->z * me->z;
mat[0][1] = 2 * me->x * me->y - 2 * me->w * me->z;
mat[0][2] = 2 * me->x * me->z + 2 * me->w * me->y;
mat[0][3] = point->x;
mat[1][0] = 2 * me->x * me->y + 2 * me->w * me->z;
mat[1][1] = 1 - 2 * me->x * me->x - 2 * me->z * me->z;
mat[1][2] = 2 * me->y * me->z - 2 * me->w * me->x;
mat[1][3] = point->y;
mat[2][0] = 2 * me->x * me->z - 2 * me->w * me->y;
mat[2][1] = 2 * me->y * me->z + 2 * me->w * me->x;
mat[2][2] = 1 - 2 * me->x * me->x - 2 * me->y * me->y;
mat[2][3] = point->z;
mat[3][0] = 0;
mat[3][1] = 0;
mat[3][2] = 0;
mat[3][3] = 1;
}
// matrix
void omat4x4f_init_ident(mat4x4f* me)
{
memset(me, 0, sizeof(*me));
me->m[0][0] = 1.0f;
me->m[1][1] = 1.0f;
me->m[2][2] = 1.0f;
me->m[3][3] = 1.0f;
}
void omat4x4f_init_perspective(mat4x4f* me, float fovy_rad, float aspect, float znear, float zfar)
{
float sine, cotangent, delta, half_fov;
half_fov = fovy_rad / 2.0f;
delta = zfar - znear;
sine = sinf(half_fov);
if ((delta == 0.0f) || (sine == 0.0f) || (aspect == 0.0f)) {
omat4x4f_init_ident(me);
return;
}
cotangent = cosf(half_fov) / sine;
me->m[0][0] = cotangent / aspect;
me->m[0][1] = 0;
me->m[0][2] = 0;
me->m[0][3] = 0;
me->m[1][0] = 0;
me->m[1][1] = cotangent;
me->m[1][2] = 0;
me->m[1][3] = 0;
me->m[2][0] = 0;
me->m[2][1] = 0;
me->m[2][2] = -(zfar + znear) / delta;
me->m[2][3] = -2.0f * znear * zfar / delta;
me->m[3][0] = 0;
me->m[3][1] = 0;
me->m[3][2] = -1.0f;
me->m[3][3] = 0;
}
void omat4x4f_init_frustum(mat4x4f* me, float left, float right, float bottom, float top, float znear, float zfar)
{
omat4x4f_init_ident(me);
float delta_x = right - left;
float delta_y = top - bottom;
float delta_z = zfar - znear;
if ((delta_x == 0.0f) || (delta_y == 0.0f) || (delta_z == 0.0f)) {
/* can't divide by zero, so just give back identity */
return;
}
me->m[0][0] = 2.0f * znear / delta_x;
me->m[0][1] = 0;
me->m[0][2] = (right + left) / delta_x;
me->m[0][3] = 0;
me->m[1][0] = 0;
me->m[1][1] = 2.0f * znear / delta_y;
me->m[1][2] = (top + bottom) / delta_y;
me->m[1][3] = 0;
me->m[2][0] = 0;
me->m[2][1] = 0;
me->m[2][2] = -(zfar + znear) / delta_z;
me->m[2][3] = -2.0f * zfar * znear / delta_z;
me->m[3][0] = 0;
me->m[3][1] = 0;
me->m[3][2] = -1.0f;
me->m[3][3] = 0;
}
void omat4x4f_init_look_at(mat4x4f* me, const quatf* rot, const vec3f* eye)
{
quatf q;
vec3f p;
q.x = -rot->x;
q.y = -rot->y;
q.z = -rot->z;
q.w = rot->w;
p.x = -eye->x;
p.y = -eye->y;
p.z = -eye->z;
me->m[0][0] = 1 - 2 * q.y * q.y - 2 * q.z * q.z;
me->m[0][1] = 2 * q.x * q.y - 2 * q.w * q.z;
me->m[0][2] = 2 * q.x * q.z + 2 * q.w * q.y;
me->m[0][3] = p.x * me->m[0][0] + p.y * me->m[0][1] + p.z * me->m[0][2];
me->m[1][0] = 2 * q.x * q.y + 2 * q.w * q.z;
me->m[1][1] = 1 - 2 * q.x * q.x - 2 * q.z * q.z;
me->m[1][2] = 2 * q.y * q.z - 2 * q.w * q.x;
me->m[1][3] = p.x * me->m[1][0] + p.y * me->m[1][1] + p.z * me->m[1][2];
me->m[2][0] = 2 * q.x * q.z - 2 * q.w * q.y;
me->m[2][1] = 2 * q.y * q.z + 2 * q.w * q.x;
me->m[2][2] = 1 - 2 * q.x * q.x - 2 * q.y * q.y;
me->m[2][3] = p.x * me->m[2][0] + p.y * me->m[2][1] + p.z * me->m[2][2];
me->m[3][0] = 0;
me->m[3][1] = 0;
me->m[3][2] = 0;
me->m[3][3] = 1;
}
void omat4x4f_init_translate(mat4x4f* me, float x, float y, float z)
{
omat4x4f_init_ident(me);
me->m[0][3] = x;
me->m[1][3] = y;
me->m[2][3] = z;
}
void omat4x4f_transpose(const mat4x4f* m, mat4x4f* o)
{
o->m[0][0] = m->m[0][0];
o->m[1][0] = m->m[0][1];
o->m[2][0] = m->m[0][2];
o->m[3][0] = m->m[0][3];
o->m[0][1] = m->m[1][0];
o->m[1][1] = m->m[1][1];
o->m[2][1] = m->m[1][2];
o->m[3][1] = m->m[1][3];
o->m[0][2] = m->m[2][0];
o->m[1][2] = m->m[2][1];
o->m[2][2] = m->m[2][2];
o->m[3][2] = m->m[2][3];
o->m[0][3] = m->m[3][0];
o->m[1][3] = m->m[3][1];
o->m[2][3] = m->m[3][2];
o->m[3][3] = m->m[3][3];
}
void omat4x4f_mult(const mat4x4f* l, const mat4x4f* r, mat4x4f *o)
{
for(int i = 0; i < 4; i++){
float a0 = l->m[i][0], a1 = l->m[i][1], a2 = l->m[i][2], a3 = l->m[i][3];
o->m[i][0] = a0 * r->m[0][0] + a1 * r->m[1][0] + a2 * r->m[2][0] + a3 * r->m[3][0];
o->m[i][1] = a0 * r->m[0][1] + a1 * r->m[1][1] + a2 * r->m[2][1] + a3 * r->m[3][1];
o->m[i][2] = a0 * r->m[0][2] + a1 * r->m[1][2] + a2 * r->m[2][2] + a3 * r->m[3][2];
o->m[i][3] = a0 * r->m[0][3] + a1 * r->m[1][3] + a2 * r->m[2][3] + a3 * r->m[3][3];
}
}
// filter queue
void ofq_init(filter_queue* me, int size)
{
memset(me, 0, sizeof(filter_queue));
me->size = size;
}
void ofq_add(filter_queue* me, const vec3f* vec)
{
me->elems[me->at] = *vec;
me->at = ((me->at + 1) % me->size);
}
void ofq_get_mean(const filter_queue* me, vec3f* vec)
{
vec->x = vec->y = vec->z = 0;
for(int i = 0; i < me->size; i++){
vec->x += me->elems[i].x;
vec->y += me->elems[i].y;
vec->z += me->elems[i].z;
}
vec->x /= (float)me->size;
vec->y /= (float)me->size;
vec->z /= (float)me->size;
}

90
extern/openhmd/src/omath.h vendored Normal file
View File

@@ -0,0 +1,90 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Math */
#ifndef OMATH_H
#define OMATH_H
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define POW2(_x) ((_x) * (_x))
#define RAD_TO_DEG(_r) ((_r) * 360.0f / (2.0f * (float)M_PI))
#define DEG_TO_RAD(_d) ((_d) * (2.0f * (float)M_PI) / 360.0f)
// vector
typedef union {
struct {
float x, y, z;
};
float arr[3];
} vec3f;
void ovec3f_normalize_me(vec3f* me);
float ovec3f_get_length(const vec3f* me);
float ovec3f_get_angle(const vec3f* me, const vec3f* vec);
float ovec3f_get_dot(const vec3f* me, const vec3f* vec);
void ovec3f_subtract(const vec3f* a, const vec3f* b, vec3f* out);
// quaternion
typedef union {
struct {
float x, y, z, w;
};
float arr[4];
} quatf;
void oquatf_init_axis(quatf* me, const vec3f* vec, float angle);
void oquatf_get_rotated(const quatf* me, const vec3f* vec, vec3f* out_vec);
void oquatf_mult_me(quatf* me, const quatf* q);
void oquatf_mult(const quatf* me, const quatf* q, quatf* out_q);
void oquatf_diff(const quatf* me, const quatf* q, quatf* out_q);
void oquatf_normalize_me(quatf* me);
float oquatf_get_length(const quatf* me);
float oquatf_get_dot(const quatf* me, const quatf* q);
void oquatf_inverse(quatf* me);
void oquatf_get_mat4x4(const quatf* me, const vec3f* point, float mat[4][4]);
// matrix
typedef union {
float m[4][4];
float arr[16];
} mat4x4f;
void omat4x4f_init_ident(mat4x4f* me);
void omat4x4f_init_perspective(mat4x4f* me, float fov_rad, float aspect, float znear, float zfar);
void omat4x4f_init_frustum(mat4x4f* me, float left, float right, float bottom, float top, float znear, float zfar);
void omat4x4f_init_look_at(mat4x4f* me, const quatf* ret, const vec3f* eye);
void omat4x4f_init_translate(mat4x4f* me, float x, float y, float z);
void omat4x4f_mult(const mat4x4f* left, const mat4x4f* right, mat4x4f* out_mat);
void omat4x4f_transpose(const mat4x4f* me, mat4x4f* out_mat);
// filter queue
#define FILTER_QUEUE_MAX_SIZE 256
typedef struct {
int at, size;
vec3f elems[FILTER_QUEUE_MAX_SIZE];
} filter_queue;
void ofq_init(filter_queue* me, int size);
void ofq_add(filter_queue* me, const vec3f* vec);
void ofq_get_mean(const filter_queue* me, vec3f* vec);
#endif

572
extern/openhmd/src/openhmd.c vendored Normal file
View File

@@ -0,0 +1,572 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Main Lib Implemenation */
#include "openhmdi.h"
#include "shaders.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define DIGITAL_INPUT_EVENT_QUEUE_SIZE 1024
// Running automatic updates at 1000 Hz
#define AUTOMATIC_UPDATE_SLEEP (1.0 / 1000.0)
ohmd_context* OHMD_APIENTRY ohmd_ctx_create(void)
{
ohmd_context* ctx = calloc(1, sizeof(ohmd_context));
if(!ctx){
LOGE("could not allocate RAM for context");
return NULL;
}
#if DRIVER_OCULUS_RIFT
ctx->drivers[ctx->num_drivers++] = ohmd_create_oculus_rift_drv(ctx);
#endif
#if DRIVER_DEEPOON
ctx->drivers[ctx->num_drivers++] = ohmd_create_deepoon_drv(ctx);
#endif
#if DRIVER_PSVR
ctx->drivers[ctx->num_drivers++] = ohmd_create_psvr_drv(ctx);
#endif
#if DRIVER_HTC_VIVE
ctx->drivers[ctx->num_drivers++] = ohmd_create_htc_vive_drv(ctx);
#endif
#if DRIVER_EXTERNAL
ctx->drivers[ctx->num_drivers++] = ohmd_create_external_drv(ctx);
#endif
#if DRIVER_ANDROID
ctx->drivers[ctx->num_drivers++] = ohmd_create_android_drv(ctx);
#endif
// add dummy driver last to make it the lowest priority
ctx->drivers[ctx->num_drivers++] = ohmd_create_dummy_drv(ctx);
ctx->update_request_quit = false;
return ctx;
}
void OHMD_APIENTRY ohmd_ctx_destroy(ohmd_context* ctx)
{
ctx->update_request_quit = true;
for(int i = 0; i < ctx->num_active_devices; i++){
ctx->active_devices[i]->close(ctx->active_devices[i]);
}
for(int i = 0; i < ctx->num_drivers; i++){
ctx->drivers[i]->destroy(ctx->drivers[i]);
}
if(ctx->update_thread){
ohmd_destroy_thread(ctx->update_thread);
ohmd_destroy_mutex(ctx->update_mutex);
}
free(ctx);
}
void OHMD_APIENTRY ohmd_ctx_update(ohmd_context* ctx)
{
for(int i = 0; i < ctx->num_active_devices; i++){
ohmd_device* dev = ctx->active_devices[i];
if(!dev->settings.automatic_update && dev->update)
dev->update(dev);
ohmd_lock_mutex(ctx->update_mutex);
dev->getf(dev, OHMD_POSITION_VECTOR, (float*)&dev->position);
dev->getf(dev, OHMD_ROTATION_QUAT, (float*)&dev->rotation);
ohmd_unlock_mutex(ctx->update_mutex);
}
}
const char* OHMD_APIENTRY ohmd_ctx_get_error(ohmd_context* ctx)
{
return ctx->error_msg;
}
int OHMD_APIENTRY ohmd_ctx_probe(ohmd_context* ctx)
{
memset(&ctx->list, 0, sizeof(ohmd_device_list));
for(int i = 0; i < ctx->num_drivers; i++){
ctx->drivers[i]->get_device_list(ctx->drivers[i], &ctx->list);
}
return ctx->list.num_devices;
}
const char* OHMD_APIENTRY ohmd_gets(ohmd_string_description type)
{
switch(type){
case OHMD_GLSL_DISTORTION_VERT_SRC:
return distortion_vert;
case OHMD_GLSL_DISTORTION_FRAG_SRC:
return distortion_frag;
default:
return NULL;
}
}
const char* OHMD_APIENTRY ohmd_list_gets(ohmd_context* ctx, int index, ohmd_string_value type)
{
if(index >= ctx->list.num_devices)
return NULL;
switch(type){
case OHMD_VENDOR:
return ctx->list.devices[index].vendor;
case OHMD_PRODUCT:
return ctx->list.devices[index].product;
case OHMD_PATH:
return ctx->list.devices[index].path;
default:
return NULL;
}
}
static unsigned int ohmd_update_thread(void* arg)
{
ohmd_context* ctx = (ohmd_context*)arg;
while(!ctx->update_request_quit)
{
ohmd_lock_mutex(ctx->update_mutex);
for(int i = 0; i < ctx->num_active_devices; i++){
if(ctx->active_devices[i]->settings.automatic_update && ctx->active_devices[i]->update)
ctx->active_devices[i]->update(ctx->active_devices[i]);
}
ohmd_unlock_mutex(ctx->update_mutex);
ohmd_sleep(AUTOMATIC_UPDATE_SLEEP);
}
return 0;
}
static void ohmd_set_up_update_thread(ohmd_context* ctx)
{
if(!ctx->update_thread){
ctx->update_mutex = ohmd_create_mutex(ctx);
ctx->update_thread = ohmd_create_thread(ctx, ohmd_update_thread, ctx);
}
}
ohmd_device* OHMD_APIENTRY ohmd_list_open_device_s(ohmd_context* ctx, int index, ohmd_device_settings* settings)
{
ohmd_lock_mutex(ctx->update_mutex);
if(index >= 0 && index < ctx->list.num_devices){
ohmd_device_desc* desc = &ctx->list.devices[index];
ohmd_driver* driver = (ohmd_driver*)desc->driver_ptr;
ohmd_device* device = driver->open_device(driver, desc);
if (device == NULL)
return NULL;
device->rotation_correction.w = 1;
device->settings = *settings;
device->ctx = ctx;
device->active_device_idx = ctx->num_active_devices;
ctx->active_devices[ctx->num_active_devices++] = device;
if(device->properties.digital_button_count > 0)
device->digital_input_event_queue = ohmdq_create(ctx, sizeof(ohmd_digital_input_event), DIGITAL_INPUT_EVENT_QUEUE_SIZE);
ohmd_unlock_mutex(ctx->update_mutex);
if(device->settings.automatic_update)
ohmd_set_up_update_thread(ctx);
return device;
}
ohmd_unlock_mutex(ctx->update_mutex);
ohmd_set_error(ctx, "no device with index: %d", index);
return NULL;
}
ohmd_device* OHMD_APIENTRY ohmd_list_open_device(ohmd_context* ctx, int index)
{
ohmd_device_settings settings;
settings.automatic_update = true;
return ohmd_list_open_device_s(ctx, index, &settings);
}
int OHMD_APIENTRY ohmd_close_device(ohmd_device* device)
{
ohmd_lock_mutex(device->ctx->update_mutex);
ohmd_context* ctx = device->ctx;
int idx = device->active_device_idx;
ohmdq* dinq = device->digital_input_event_queue;
memmove(ctx->active_devices + idx, ctx->active_devices + idx + 1,
sizeof(ohmd_device*) * (ctx->num_active_devices - idx - 1));
device->close(device);
if(dinq)
ohmdq_destroy(dinq);
ctx->num_active_devices--;
for(int i = idx; i < ctx->num_active_devices; i++)
ctx->active_devices[i]->active_device_idx--;
ohmd_unlock_mutex(ctx->update_mutex);
return OHMD_S_OK;
}
static int ohmd_device_getf_unp(ohmd_device* device, ohmd_float_value type, float* out)
{
switch(type){
case OHMD_LEFT_EYE_GL_MODELVIEW_MATRIX: {
vec3f point = {{0, 0, 0}};
quatf rot = device->rotation;
quatf tmp = device->rotation_correction;
oquatf_mult_me(&tmp, &rot);
rot = tmp;
mat4x4f orient, world_shift, result;
omat4x4f_init_look_at(&orient, &rot, &point);
omat4x4f_init_translate(&world_shift, +(device->properties.ipd / 2.0f), 0, 0);
omat4x4f_mult(&world_shift, &orient, &result);
omat4x4f_transpose(&result, (mat4x4f*)out);
return OHMD_S_OK;
}
case OHMD_RIGHT_EYE_GL_MODELVIEW_MATRIX: {
vec3f point = {{0, 0, 0}};
quatf rot = device->rotation;
oquatf_mult_me(&rot, &device->rotation_correction);
mat4x4f orient, world_shift, result;
omat4x4f_init_look_at(&orient, &rot, &point);
omat4x4f_init_translate(&world_shift, -(device->properties.ipd / 2.0f), 0, 0);
omat4x4f_mult(&world_shift, &orient, &result);
omat4x4f_transpose(&result, (mat4x4f*)out);
return OHMD_S_OK;
}
case OHMD_LEFT_EYE_GL_PROJECTION_MATRIX:
omat4x4f_transpose(&device->properties.proj_left, (mat4x4f*)out);
return OHMD_S_OK;
case OHMD_RIGHT_EYE_GL_PROJECTION_MATRIX:
omat4x4f_transpose(&device->properties.proj_right, (mat4x4f*)out);
return OHMD_S_OK;
case OHMD_SCREEN_HORIZONTAL_SIZE:
*out = device->properties.hsize;
return OHMD_S_OK;
case OHMD_SCREEN_VERTICAL_SIZE:
*out = device->properties.vsize;
return OHMD_S_OK;
case OHMD_LENS_HORIZONTAL_SEPARATION:
*out = device->properties.lens_sep;
return OHMD_S_OK;
case OHMD_LENS_VERTICAL_POSITION:
*out = device->properties.lens_vpos;
return OHMD_S_OK;
case OHMD_RIGHT_EYE_FOV:
case OHMD_LEFT_EYE_FOV:
*out = device->properties.fov;
return OHMD_S_OK;
case OHMD_RIGHT_EYE_ASPECT_RATIO:
case OHMD_LEFT_EYE_ASPECT_RATIO:
*out = device->properties.ratio;
return OHMD_S_OK;
case OHMD_EYE_IPD:
*out = device->properties.ipd;
return OHMD_S_OK;
case OHMD_PROJECTION_ZFAR:
*out = device->properties.zfar;
return OHMD_S_OK;
case OHMD_PROJECTION_ZNEAR:
*out = device->properties.znear;
return OHMD_S_OK;
case OHMD_ROTATION_QUAT:
{
*(quatf*)out = device->rotation;
oquatf_mult_me((quatf*)out, &device->rotation_correction);
quatf tmp = device->rotation_correction;
oquatf_mult_me(&tmp, (quatf*)out);
*(quatf*)out = tmp;
return OHMD_S_OK;
}
case OHMD_POSITION_VECTOR:
{
*(vec3f*)out = device->position;
for(int i = 0; i < 3; i++)
out[i] += device->position_correction.arr[i];
return OHMD_S_OK;
}
case OHMD_UNIVERSAL_DISTORTION_K: {
for (int i = 0; i < 4; i++) {
out[i] = device->properties.universal_distortion_k[i];
}
return OHMD_S_OK;
}
case OHMD_UNIVERSAL_ABERRATION_K: {
for (int i = 0; i < 3; i++) {
out[i] = device->properties.universal_aberration_k[i];
}
return OHMD_S_OK;
}
default:
return device->getf(device, type, out);
}
}
int OHMD_APIENTRY ohmd_device_getf(ohmd_device* device, ohmd_float_value type, float* out)
{
ohmd_lock_mutex(device->ctx->update_mutex);
int ret = ohmd_device_getf_unp(device, type, out);
ohmd_unlock_mutex(device->ctx->update_mutex);
return ret;
}
int ohmd_device_setf_unp(ohmd_device* device, ohmd_float_value type, const float* in)
{
switch(type){
case OHMD_EYE_IPD:
device->properties.ipd = *in;
return OHMD_S_OK;
case OHMD_PROJECTION_ZFAR:
device->properties.zfar = *in;
return OHMD_S_OK;
case OHMD_PROJECTION_ZNEAR:
device->properties.znear = *in;
return OHMD_S_OK;
case OHMD_ROTATION_QUAT:
{
// adjust rotation correction
quatf q;
int ret = device->getf(device, OHMD_ROTATION_QUAT, (float*)&q);
if(ret != 0){
return ret;
}
oquatf_diff(&q, (quatf*)in, &device->rotation_correction);
return OHMD_S_OK;
}
case OHMD_POSITION_VECTOR:
{
// adjust position correction
vec3f v;
int ret = device->getf(device, OHMD_POSITION_VECTOR, (float*)&v);
if(ret != 0){
return ret;
}
for(int i = 0; i < 3; i++)
device->position_correction.arr[i] = in[i] - v.arr[i];
return OHMD_S_OK;
}
case OHMD_EXTERNAL_SENSOR_FUSION:
{
if(device->setf == NULL)
return OHMD_S_UNSUPPORTED;
return device->setf(device, type, in);
}
default:
return OHMD_S_INVALID_PARAMETER;
}
}
int OHMD_APIENTRY ohmd_device_setf(ohmd_device* device, ohmd_float_value type, const float* in)
{
ohmd_lock_mutex(device->ctx->update_mutex);
int ret = ohmd_device_setf_unp(device, type, in);
ohmd_unlock_mutex(device->ctx->update_mutex);
return ret;
}
int OHMD_APIENTRY ohmd_device_geti(ohmd_device* device, ohmd_int_value type, int* out)
{
ohmdq* dinq = device->digital_input_event_queue;
switch(type){
case OHMD_SCREEN_HORIZONTAL_RESOLUTION:
*out = device->properties.hres;
return OHMD_S_OK;
case OHMD_SCREEN_VERTICAL_RESOLUTION:
*out = device->properties.vres;
return OHMD_S_OK;
case OHMD_BUTTON_EVENT_COUNT:
*out = dinq ? (int)ohmdq_get_size(dinq) : 0;
return OHMD_S_OK;
case OHMD_BUTTON_EVENT_OVERFLOW:
*out = dinq ? (ohmdq_get_size(dinq) == ohmdq_get_max(dinq)) : 0;
return OHMD_S_OK;
case OHMD_BUTTON_COUNT:
*out = device->properties.digital_button_count;
return OHMD_S_OK;
case OHMD_BUTTON_POP_EVENT: {
ohmd_digital_input_event event;
if(!ohmdq_pop(dinq, &event)){
return OHMD_S_INVALID_OPERATION;
}
out[0] = event.idx;
out[1] = event.state;
return OHMD_S_OK;
}
default:
return OHMD_S_INVALID_PARAMETER;
}
}
int OHMD_APIENTRY ohmd_device_seti(ohmd_device* device, ohmd_int_value type, const int* in)
{
switch(type){
default:
return OHMD_S_INVALID_PARAMETER;
}
}
int ohmd_device_set_data_unp(ohmd_device* device, ohmd_data_value type, const void* in)
{
switch(type){
case OHMD_DRIVER_DATA:
device->set_data(device, OHMD_DRIVER_DATA, in);
return OHMD_S_OK;
case OHMD_DRIVER_PROPERTIES:
device->set_data(device, OHMD_DRIVER_PROPERTIES, in);
return OHMD_S_OK;
default:
return OHMD_S_INVALID_PARAMETER;
}
}
int OHMD_APIENTRY ohmd_device_set_data(ohmd_device* device, ohmd_data_value type, const void* in)
{
ohmd_lock_mutex(device->ctx->update_mutex);
int ret = ohmd_device_set_data_unp(device, type, in);
ohmd_unlock_mutex(device->ctx->update_mutex);
return ret;
}
ohmd_status OHMD_APIENTRY ohmd_device_settings_seti(ohmd_device_settings* settings, ohmd_int_settings key, const int* val)
{
switch(key){
case OHMD_IDS_AUTOMATIC_UPDATE:
settings->automatic_update = val[0] == 0 ? false : true;
return OHMD_S_OK;
default:
return OHMD_S_INVALID_PARAMETER;
}
}
ohmd_device_settings* OHMD_APIENTRY ohmd_device_settings_create(ohmd_context* ctx)
{
return ohmd_alloc(ctx, sizeof(ohmd_device_settings));
}
void OHMD_APIENTRY ohmd_device_settings_destroy(ohmd_device_settings* settings)
{
free(settings);
}
void* ohmd_allocfn(ohmd_context* ctx, const char* e_msg, size_t size)
{
void* ret = calloc(1, size);
if(!ret)
ohmd_set_error(ctx, "%s", e_msg);
return ret;
}
void ohmd_set_default_device_properties(ohmd_device_properties* props)
{
props->ipd = 0.061f;
props->znear = 0.1f;
props->zfar = 1000.0f;
ohmd_set_universal_distortion_k(props, 0, 0, 0, 1);
ohmd_set_universal_aberration_k(props, 1.0, 1.0, 1.0);
}
void ohmd_calc_default_proj_matrices(ohmd_device_properties* props)
{
mat4x4f proj_base; // base projection matrix
// Calculate where the lens is on each screen,
// and with the given value offset the projection matrix.
float screen_center = props->hsize / 4.0f;
float lens_shift = screen_center - props->lens_sep / 2.0f;
// XXX: on CV1, props->hsize > props->lens_sep / 2.0,
// I am not sure about the implications, but just taking the absolute
// value of the offset seems to work.
float proj_offset = fabs(4.0f * lens_shift / props->hsize);
// Setup the base projection matrix. Each eye mostly have the
// same projection matrix with the exception of the offset.
omat4x4f_init_perspective(&proj_base, props->fov, props->ratio, props->znear, props->zfar);
// Setup the two adjusted projection matricies. Each is setup to deal
// with the fact that the lens is not in the center of the screen.
// These matrices only change of the hardware changes, so static.
mat4x4f translate;
omat4x4f_init_translate(&translate, proj_offset, 0, 0);
omat4x4f_mult(&translate, &proj_base, &props->proj_left);
omat4x4f_init_translate(&translate, -proj_offset, 0, 0);
omat4x4f_mult(&translate, &proj_base, &props->proj_right);
}
void ohmd_set_universal_distortion_k(ohmd_device_properties* props, float a, float b, float c, float d)
{
props->universal_distortion_k[0] = a;
props->universal_distortion_k[1] = b;
props->universal_distortion_k[2] = c;
props->universal_distortion_k[3] = d;
}
void ohmd_set_universal_aberration_k(ohmd_device_properties* props, float r, float g, float b)
{
props->universal_aberration_k[0] = r;
props->universal_aberration_k[1] = g;
props->universal_aberration_k[2] = b;
}

152
extern/openhmd/src/openhmdi.h vendored Normal file
View File

@@ -0,0 +1,152 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Internal interface */
#ifndef OPENHMDI_H
#define OPENHMDI_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "openhmd.h"
#include "omath.h"
#include "platform.h"
#include "queue.h"
#define OHMD_MAX_DEVICES 16
#define OHMD_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define OHMD_MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define OHMD_STRINGIFY(_what) #_what
typedef struct ohmd_driver ohmd_driver;
typedef struct {
char driver[OHMD_STR_SIZE];
char vendor[OHMD_STR_SIZE];
char product[OHMD_STR_SIZE];
char path[OHMD_STR_SIZE];
int revision;
ohmd_driver* driver_ptr;
} ohmd_device_desc;
typedef struct {
int num_devices;
ohmd_device_desc devices[OHMD_MAX_DEVICES];
} ohmd_device_list;
typedef struct {
int idx;
ohmd_button_state state;
} ohmd_digital_input_event;
struct ohmd_driver {
void (*get_device_list)(ohmd_driver* driver, ohmd_device_list* list);
ohmd_device* (*open_device)(ohmd_driver* driver, ohmd_device_desc* desc);
void (*destroy)(ohmd_driver* driver);
ohmd_context* ctx;
};
typedef struct {
int hres;
int vres;
int digital_button_count;
float hsize;
float vsize;
float lens_sep;
float lens_vpos;
float fov;
float ratio;
float ipd;
float zfar;
float znear;
int accel_only; //bool-like for setting acceleration only fallback (android driver)
mat4x4f proj_left; // adjusted projection matrix for left screen
mat4x4f proj_right; // adjusted projection matrix for right screen
float universal_distortion_k[4]; //PanoTools lens distiorion model [a,b,c,d]
float universal_aberration_k[3]; //post-warp per channel scaling [r,g,b]
} ohmd_device_properties;
struct ohmd_device_settings
{
bool automatic_update;
};
struct ohmd_device {
ohmd_device_properties properties;
quatf rotation_correction;
vec3f position_correction;
int (*getf)(ohmd_device* device, ohmd_float_value type, float* out);
int (*setf)(ohmd_device* device, ohmd_float_value type, const float* in);
int (*seti)(ohmd_device* device, ohmd_int_value type, const int* in);
int (*set_data)(ohmd_device* device, ohmd_data_value type, const void* in);
void (*update)(ohmd_device* device);
void (*close)(ohmd_device* device);
ohmd_context* ctx;
ohmd_device_settings settings;
int active_device_idx; // index into ohmd_device->active_devices[]
quatf rotation;
vec3f position;
ohmdq* digital_input_event_queue;
};
struct ohmd_context {
ohmd_driver* drivers[16];
int num_drivers;
ohmd_device_list list;
ohmd_device* active_devices[256];
int num_active_devices;
ohmd_thread* update_thread;
ohmd_mutex* update_mutex;
bool update_request_quit;
char error_msg[OHMD_STR_SIZE];
};
// helper functions
void ohmd_set_default_device_properties(ohmd_device_properties* props);
void ohmd_calc_default_proj_matrices(ohmd_device_properties* props);
void ohmd_set_universal_distortion_k(ohmd_device_properties* props, float a, float b, float c, float d);
void ohmd_set_universal_aberration_k(ohmd_device_properties* props, float r, float g, float b);
// drivers
ohmd_driver* ohmd_create_dummy_drv(ohmd_context* ctx);
ohmd_driver* ohmd_create_oculus_rift_drv(ohmd_context* ctx);
ohmd_driver* ohmd_create_deepoon_drv(ohmd_context* ctx);
ohmd_driver* ohmd_create_psvr_drv(ohmd_context* ctx);
ohmd_driver* ohmd_create_htc_vive_drv(ohmd_context* ctx);
ohmd_driver* ohmd_create_external_drv(ohmd_context* ctx);
ohmd_driver* ohmd_create_android_drv(ohmd_context* ctx);
#include "log.h"
#include "omath.h"
#include "fusion.h"
#endif

132
extern/openhmd/src/platform-posix.c vendored Normal file
View File

@@ -0,0 +1,132 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Platform Specific Functions, Unix/Posix Implementation */
#if defined(__unix__) || defined(__unix) || defined(__APPLE__) || defined(__MACH__)
#ifdef __CYGWIN__
#define CLOCK_MONOTONIC (clockid_t)4
#endif
#define _POSIX_C_SOURCE 199309L
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <pthread.h>
#include "platform.h"
#include "openhmdi.h"
// Use clock_gettime if the system implements posix realtime timers
#ifndef CLOCK_MONOTONIC
double ohmd_get_tick()
{
struct timeval now;
gettimeofday(&now, NULL);
return (double)now.tv_sec * 1.0 + (double)now.tv_usec / 1000000.0;
}
#else
double ohmd_get_tick()
{
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return (double)now.tv_sec * 1.0 + (double)now.tv_nsec / 1000000000.0;
}
#endif
void ohmd_sleep(double seconds)
{
struct timespec sleepfor;
sleepfor.tv_sec = (time_t)seconds;
sleepfor.tv_nsec = (long)((seconds - sleepfor.tv_sec) * 1000000000.0);
nanosleep(&sleepfor, NULL);
}
// threads
struct ohmd_thread
{
pthread_t thread;
unsigned int (*routine)(void* arg);
void* arg;
};
static void* pthread_wrapper(void* arg)
{
ohmd_thread* my_thread = (ohmd_thread*)arg;
my_thread->routine(my_thread->arg);
return NULL;
}
ohmd_thread* ohmd_create_thread(ohmd_context* ctx, unsigned int (*routine)(void* arg), void* arg)
{
ohmd_thread* thread = ohmd_alloc(ctx, sizeof(ohmd_thread));
if(thread == NULL)
return NULL;
thread->arg = arg;
thread->routine = routine;
int ret = pthread_create(&thread->thread, NULL, pthread_wrapper, thread);
if(ret != 0){
free(thread);
thread = NULL;
}
return thread;
}
ohmd_mutex* ohmd_create_mutex(ohmd_context* ctx)
{
pthread_mutex_t* mutex = ohmd_alloc(ctx, sizeof(pthread_mutex_t));
if(mutex == NULL)
return NULL;
int ret = pthread_mutex_init(mutex, NULL);
if(ret != 0){
free(mutex);
mutex = NULL;
}
return (ohmd_mutex*)mutex;
}
void ohmd_destroy_thread(ohmd_thread* thread)
{
pthread_join(thread->thread, NULL);
free(thread);
}
void ohmd_destroy_mutex(ohmd_mutex* mutex)
{
pthread_mutex_destroy((pthread_mutex_t*)mutex);
free(mutex);
}
void ohmd_lock_mutex(ohmd_mutex* mutex)
{
if(mutex)
pthread_mutex_lock((pthread_mutex_t*)mutex);
}
void ohmd_unlock_mutex(ohmd_mutex* mutex)
{
if(mutex)
pthread_mutex_unlock((pthread_mutex_t*)mutex);
}
/// Handling ovr service
void ohmd_toggle_ovr_service(int state) //State is 0 for Disable, 1 for Enable
{
//Empty implementation
}
#endif

144
extern/openhmd/src/platform-win32.c vendored Normal file
View File

@@ -0,0 +1,144 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Platform Specific Functions, Win32 Implementation */
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#include <windows.h>
#include "platform.h"
#include "openhmdi.h"
double ohmd_get_tick()
{
double high, low;
FILETIME filetime;
GetSystemTimeAsFileTime(&filetime);
high = filetime.dwHighDateTime;
low = filetime.dwLowDateTime;
return (high * 4294967296.0 + low) / 10000000;
}
// TODO higher resolution
void ohmd_sleep(double seconds)
{
Sleep((DWORD)(seconds * 1000));
}
// threads
struct ohmd_thread {
HANDLE handle;
void* arg;
unsigned int (*routine)(void* arg);
};
struct ohmd_mutex {
HANDLE handle;
};
DWORD __stdcall ohmd_thread_wrapper(void* t)
{
ohmd_thread* thread = (ohmd_thread*)t;
return thread->routine(thread->arg);
}
ohmd_thread* ohmd_create_thread(ohmd_context* ctx, unsigned int (*routine)(void* arg), void* arg)
{
ohmd_thread* thread = ohmd_alloc(ctx, sizeof(ohmd_thread));
if(!thread)
return NULL;
thread->routine = routine;
thread->arg = arg;
thread->handle = CreateThread(NULL, 0, ohmd_thread_wrapper, thread, 0, NULL);
return thread;
}
void ohmd_destroy_thread(ohmd_thread* thread)
{
ohmd_sleep(3);
WaitForSingleObject(thread->handle, INFINITE);
CloseHandle(thread->handle);
free(thread);
}
ohmd_mutex* ohmd_create_mutex(ohmd_context* ctx)
{
ohmd_mutex* mutex = ohmd_alloc(ctx, sizeof(ohmd_mutex));
if(!mutex)
return NULL;
mutex->handle = CreateMutex(NULL, FALSE, NULL);
return mutex;
}
void ohmd_destroy_mutex(ohmd_mutex* mutex)
{
CloseHandle(mutex->handle);
free(mutex);
}
void ohmd_lock_mutex(ohmd_mutex* mutex)
{
if(mutex)
WaitForSingleObject(mutex->handle, INFINITE);
}
void ohmd_unlock_mutex(ohmd_mutex* mutex)
{
if(mutex)
ReleaseMutex(mutex->handle);
}
/// Handling ovr service
static int _enable_ovr_service = 0;
void ohmd_toggle_ovr_service(int state) //State is 0 for Disable, 1 for Enable
{
SC_HANDLE serviceDbHandle = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
SC_HANDLE serviceHandle = OpenService(serviceDbHandle, "OVRService", SC_MANAGER_ALL_ACCESS);
SERVICE_STATUS_PROCESS status;
DWORD bytesNeeded;
QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO,(LPBYTE) &status,sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded);
if (state == 0 || status.dwCurrentState == SERVICE_RUNNING)
{
// Stop it
BOOL b = ControlService(serviceHandle, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS) &status);
if (b)
{
printf("OVRService stopped\n");
_enable_ovr_service = 1;
}
else
printf("Error: OVRService failed to stop, please try running with Administrator rights\n");
}
else if (state == 1 && _enable_ovr_service)
{
// Start it
BOOL b = StartService(serviceHandle, NULL, NULL);
if (b)
printf("OVRService started\n");
else
printf("Error: OVRService failed to start, please try running with Administrator rights\n");
}
CloseServiceHandle(serviceHandle);
CloseServiceHandle(serviceDbHandle);
}
#endif

32
extern/openhmd/src/platform.h vendored Normal file
View File

@@ -0,0 +1,32 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2013 Fredrik Hultin.
* Copyright (C) 2013 Jakob Bornecrantz.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Internal Interface for Platform Specific Functions */
#ifndef PLATFORM_H
#define PLATFORM_H
#include "openhmd.h"
double ohmd_get_tick();
void ohmd_sleep(double seconds);
void ohmd_toggle_ovr_service(int state);
typedef struct ohmd_thread ohmd_thread;
typedef struct ohmd_mutex ohmd_mutex;
ohmd_mutex* ohmd_create_mutex(ohmd_context* ctx);
void ohmd_destroy_mutex(ohmd_mutex* mutex);
void ohmd_lock_mutex(ohmd_mutex* mutex);
void ohmd_unlock_mutex(ohmd_mutex* mutex);
ohmd_thread* ohmd_create_thread(ohmd_context* ctx, unsigned int (*routine)(void* arg), void* arg);
void ohmd_destroy_thread(ohmd_thread* thread);
#endif

97
extern/openhmd/src/queue.c vendored Normal file
View File

@@ -0,0 +1,97 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2016 Fredrik Hultin.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Naive Thread Safe Circular Queue Implementation */
#include <stdlib.h>
#include <string.h>
#include "queue.h"
#include "openhmdi.h"
struct ohmdq {
unsigned read_pos;
unsigned write_pos;
unsigned size;
unsigned max;
unsigned elem_size;
char* elems;
ohmd_mutex* mutex;
};
ohmdq* ohmdq_create(ohmd_context* ctx, unsigned elem_size, unsigned max)
{
ohmdq* me = ohmd_alloc(ctx, sizeof(ohmdq));
me->elems = ohmd_alloc(ctx, elem_size * max);
me->max = max;
me->elem_size = elem_size;
me->read_pos = 0;
me->write_pos = 0;
me->size = 0;
me->mutex = ohmd_create_mutex(ctx);
return me;
}
bool ohmdq_push(ohmdq* me, const void* elem)
{
bool ret = false;
ohmd_lock_mutex(me->mutex);
if(me->size < me->max){
memcpy(me->elems + me->write_pos, elem, me->elem_size);
me->write_pos = (me->write_pos + me->elem_size) % (me->max * me->elem_size);
me->size++;
ret = true;
}
ohmd_unlock_mutex(me->mutex);
return ret;
}
bool ohmdq_pop(ohmdq* me, void* out_elem)
{
bool ret = false;
ohmd_lock_mutex(me->mutex);
if(me->size > 0){
memcpy(out_elem, me->elems + me->read_pos, me->elem_size);
me->read_pos = (me->read_pos + me->elem_size) % (me->max * me->elem_size);
me->size--;
ret = true;
}
ohmd_unlock_mutex(me->mutex);
return ret;
}
unsigned ohmdq_get_size(ohmdq* me)
{
unsigned ret;
ohmd_lock_mutex(me->mutex);
ret = me->size;
ohmd_unlock_mutex(me->mutex);
return ret;
}
unsigned ohmdq_get_max(ohmdq* me)
{
return me->max;
}
void ohmdq_destroy(ohmdq* me)
{
free(me->elems);
ohmd_destroy_mutex(me->mutex);
free(me);
}

25
extern/openhmd/src/queue.h vendored Normal file
View File

@@ -0,0 +1,25 @@
/*
* OpenHMD - Free and Open Source API and drivers for immersive technology.
* Copyright (C) 2016 Fredrik Hultin.
* Distributed under the Boost 1.0 licence, see LICENSE for full text.
*/
/* Naive Thread Safe Circular Queue */
#ifndef OHMDQUEUE_H
#define OHMDQUEUE_H
#include <stdbool.h>
typedef struct ohmdq ohmdq;
typedef struct ohmd_context ohmd_context;
ohmdq* ohmdq_create(ohmd_context* ctx, unsigned elem_size, unsigned max);
void ohmdq_destroy(ohmdq* me);
bool ohmdq_push(ohmdq* me, const void* elem);
bool ohmdq_pop(ohmdq* me, void* out_elem);
unsigned ohmdq_get_size(ohmdq* me);
unsigned ohmdq_get_max(ohmdq* me);
#endif

55
extern/openhmd/src/shaders.c vendored Normal file
View File

@@ -0,0 +1,55 @@
const char * distortion_vert =
"#version 120\n"
"void main(void)\n"
"{\n"
"gl_TexCoord[0] = gl_MultiTexCoord0;\n"
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n"
"}";
const char * distortion_frag =
"#version 120\n"
"\n"
"//per eye texture to warp for lens distortion\n"
"uniform sampler2D warpTexture;\n"
"\n"
"//Position of lens center in m (usually eye_w/2, eye_h/2)\n"
"uniform vec2 LensCenter;\n"
"//Scale from texture co-ords to m (usually eye_w, eye_h)\n"
"uniform vec2 ViewportScale;\n"
"//Distortion overall scale in m (usually ~eye_w/2)\n"
"uniform float WarpScale;\n"
"//Distoriton coefficients (PanoTools model) [a,b,c,d]\n"
"uniform vec4 HmdWarpParam;\n"
"\n"
"//chromatic distortion post scaling\n"
"uniform vec3 aberr;\n"
"\n"
"void main()\n"
"{\n"
"//output_loc is the fragment location on screen from [0,1]x[0,1]\n"
"vec2 output_loc = vec2(gl_TexCoord[0].s, gl_TexCoord[0].t);\n"
"//Compute fragment location in lens-centered co-ordinates at world scale\n"
"vec2 r = output_loc * ViewportScale - LensCenter;\n"
"//scale for distortion model\n"
"//distortion model has r=1 being the largest circle inscribed (e.g. eye_w/2)\n"
"r /= WarpScale;\n"
"\n"
"//|r|**2\n"
"float r_mag = length(r);\n"
"//offset for which fragment is sourced\n"
"vec2 r_displaced = r * (HmdWarpParam.w + HmdWarpParam.z * r_mag +\n"
"HmdWarpParam.y * r_mag * r_mag +\n"
"HmdWarpParam.x * r_mag * r_mag * r_mag);\n"
"//back to world scale\n"
"r_displaced *= WarpScale;\n"
"//back to viewport co-ord\n"
"vec2 tc_r = (LensCenter + aberr.r * r_displaced) / ViewportScale;\n"
"vec2 tc_g = (LensCenter + aberr.g * r_displaced) / ViewportScale;\n"
"vec2 tc_b = (LensCenter + aberr.b * r_displaced) / ViewportScale;\n"
"\n"
"float red = texture2D(warpTexture, tc_r).r;\n"
"float green = texture2D(warpTexture, tc_g).g;\n"
"float blue = texture2D(warpTexture, tc_b).b;\n"
"//Black edges off the texture\n"
"gl_FragColor = ((tc_g.x < 0.0) || (tc_g.x > 1.0) || (tc_g.y < 0.0) || (tc_g.y > 1.0)) ? vec4(0.0, 0.0, 0.0, 1.0) : vec4(red, green, blue, 1.0);\n"
"}";

6
extern/openhmd/src/shaders.h vendored Normal file
View File

@@ -0,0 +1,6 @@
#ifndef SHADERS_H
#define SHADERS_H
const char * distortion_vert;
const char * distortion_frag;
#endif /* SHADERS_H */

38
extern/udew/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,38 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2016, Blender Foundation
# All rights reserved.
#
# Contributor(s): Sergey Sharybin.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
include
)
set(INC_SYS
)
set(SRC
include/udew.h
src/udew.c
)
blender_add_lib(extern_udew "${SRC}" "${INC}" "${INC_SYS}")

174
extern/udew/LICENSE vendored Normal file
View File

@@ -0,0 +1,174 @@
Modified Apache 2.0 License
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor
and its affiliates, except as required to comply with Section 4(c) of
the License and to reproduce the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

14
extern/udew/README vendored Normal file
View File

@@ -0,0 +1,14 @@
The udev Extension Wrangler Library (UDEW) is a cross-platform open-source
C/C++ extension loading library. UDEW provides efficient run-time mechanisms
for determining which udev functions and extensions extensions are supported
on the target platform.
LICENSE
UDEW library is released under the Apache 2.0 license.
LIMITATIONS
- udev_device_get_parent_with_subsystem_devtype() need to be merged to a single
line in the geader before generating the wrangler with stubs support
- udev_set_log_fn() is not included into the stubs at all.

205
extern/udew/auto/libudev.h vendored Normal file
View File

@@ -0,0 +1,205 @@
/***
This file is part of systemd.
Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef _LIBUDEV_H_
#define _LIBUDEV_H_
#include <stdarg.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* udev - library context
*
* reads the udev config and system environment
* allows custom logging
*/
struct udev;
struct udev *udev_ref(struct udev *udev);
struct udev *udev_unref(struct udev *udev);
struct udev *udev_new(void);
void udev_set_log_fn(struct udev *udev,
void (*log_fn)(struct udev *udev,
int priority, const char *file, int line, const char *fn,
const char *format, va_list args)) __attribute__ ((deprecated));
int udev_get_log_priority(struct udev *udev) __attribute__ ((deprecated));
void udev_set_log_priority(struct udev *udev, int priority) __attribute__ ((deprecated));
void *udev_get_userdata(struct udev *udev);
void udev_set_userdata(struct udev *udev, void *userdata);
/*
* udev_list
*
* access to libudev generated lists
*/
struct udev_list_entry;
struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry);
struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
const char *udev_list_entry_get_name(struct udev_list_entry *list_entry);
const char *udev_list_entry_get_value(struct udev_list_entry *list_entry);
/**
* udev_list_entry_foreach:
* @list_entry: entry to store the current position
* @first_entry: first entry to start with
*
* Helper to iterate over all entries of a list.
*/
#define udev_list_entry_foreach(list_entry, first_entry) \
for (list_entry = first_entry; \
list_entry != NULL; \
list_entry = udev_list_entry_get_next(list_entry))
/*
* udev_device
*
* access to sysfs/kernel devices
*/
struct udev_device;
struct udev_device *udev_device_ref(struct udev_device *udev_device);
struct udev_device *udev_device_unref(struct udev_device *udev_device);
struct udev *udev_device_get_udev(struct udev_device *udev_device);
struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath);
struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id);
struct udev_device *udev_device_new_from_environment(struct udev *udev);
/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */
struct udev_device *udev_device_get_parent(struct udev_device *udev_device);
struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype);
/* retrieve device properties */
const char *udev_device_get_devpath(struct udev_device *udev_device);
const char *udev_device_get_subsystem(struct udev_device *udev_device);
const char *udev_device_get_devtype(struct udev_device *udev_device);
const char *udev_device_get_syspath(struct udev_device *udev_device);
const char *udev_device_get_sysname(struct udev_device *udev_device);
const char *udev_device_get_sysnum(struct udev_device *udev_device);
const char *udev_device_get_devnode(struct udev_device *udev_device);
int udev_device_get_is_initialized(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device);
const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key);
const char *udev_device_get_driver(struct udev_device *udev_device);
dev_t udev_device_get_devnum(struct udev_device *udev_device);
const char *udev_device_get_action(struct udev_device *udev_device);
unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value);
int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
/*
* udev_monitor
*
* access to kernel uevents and udev events
*/
struct udev_monitor;
struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor);
struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
/* kernel and udev generated events over netlink */
struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name);
/* bind socket */
int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor);
/* in-kernel socket filters to select messages that get delivered to a listener */
int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
const char *subsystem, const char *devtype);
int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
/*
* udev_enumerate
*
* search sysfs for specific devices and provide a sorted list
*/
struct udev_enumerate;
struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
struct udev_enumerate *udev_enumerate_new(struct udev *udev);
/* device properties filter */
int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname);
int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag);
int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent);
int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate);
int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
/* run enumeration with active filters */
int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
/* return device list */
struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
/*
* udev_queue
*
* access to the currently running udev events
*/
struct udev_queue;
struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue);
struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
struct udev_queue *udev_queue_new(struct udev *udev);
unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) __attribute__ ((deprecated));
unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) __attribute__ ((deprecated));
int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) __attribute__ ((deprecated));
int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
unsigned long long int start, unsigned long long int end) __attribute__ ((deprecated));
int udev_queue_get_fd(struct udev_queue *udev_queue);
int udev_queue_flush(struct udev_queue *udev_queue);
struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) __attribute__ ((deprecated));
/*
* udev_hwdb
*
* access to the static hardware properties database
*/
struct udev_hwdb;
struct udev_hwdb *udev_hwdb_new(struct udev *udev);
struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb);
struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb);
struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags);
/*
* udev_util
*
* udev specific utilities
*/
int udev_util_encode_string(const char *str, char *str_enc, size_t len);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

245
extern/udew/auto/udew_gen.sh vendored Executable file
View File

@@ -0,0 +1,245 @@
#!/bin/bash
#HEADER="/usr/include/libudev.h"
HEADER="libudev.h"
SCRIPT=`realpath -s $0`
DIR=`dirname $SCRIPT`
DIR=`dirname $DIR`
H="$DIR/include/udew.h"
C=$DIR/src/udew.c
STUBS=true
mkdir -p $DIR/include
mkdir -p $DIR/src
rm -rf $DIR/include/udew.h
rm -rf $DIR/src/udew.c
echo "Generating udew headers..."
append() {
f=`echo "$1" | sed ':a;N;$!ba;s/\n/\\\\n/g'`
line_num=`grep -n '#ifdef __cplusplus' $H | cut -d : -f 1 | tail -n 1`
gawk -i inplace "NR==$line_num {\$0=\"$f\n\n#ifdef __cplusplus\"} 1" $H
}
cat $HEADER \
| sed -r 's/^((const )?[a-z0-9_]+( [a-z0-9_]+)* \*?)([a-z0-9_]+)\(/typedef \1t\4(/i' \
> $H
if $STUBS; then
fp="_";
fi
f=`grep -E 'typedef ((const )?[a-z0-9_]+( [a-z0-9_]+)* \*?)t([a-z0-9_]+)\(' $H \
| sed -r "s/((const )?[a-z0-9_]+( [a-z0-9_]+)* \*?)t([a-z0-9_]+)\(.*/extern t\4 *$fp\4;/i"`
append "$f"
append "enum {\n\
UDEW_SUCCESS = 0,\n\
UDEW_ERROR_OPEN_FAILED = -1,\n\
UDEW_ERROR_ATEXIT_FAILED = -2,\n\
};\n\
\n\
int udewInit(void);"
if $STUBS; then
decl=`cat $HEADER \
| grep -E '^((const )?[a-z0-9_]+( [a-z0-9_]+)* \*?)([a-z0-9_]+)\(.*\);'`
append "$decl"
fi
sed -i 's/_LIBUDEV_H_/__UDEW_H__/g' $H
sed -i 's/ __attribute__ ((deprecated))//g' $H
line_num=`grep -n '\*\*\*/' $H | cut -d : -f 1`
for x in `seq $line_num`; do
sed -i '1d' $H
done
mv $H $H.tmp
cat << EOF > $H
/*
* Copyright 2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
EOF
cat $H.tmp >> $H
rm $H.tmp
echo "Generating udew source..."
cat << EOF > $C
/*
* Copyright 2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
#ifdef _MSC_VER
# define snprintf _snprintf
# define popen _popen
# define pclose _pclose
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "udew.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# define VC_EXTRALEAN
# include <windows.h>
/* Utility macros. */
typedef HMODULE DynamicLibrary;
# define dynamic_library_open(path) LoadLibrary(path)
# define dynamic_library_close(lib) FreeLibrary(lib)
# define dynamic_library_find(lib, symbol) GetProcAddress(lib, symbol)
#else
# include <dlfcn.h>
typedef void* DynamicLibrary;
# define dynamic_library_open(path) dlopen(path, RTLD_NOW)
# define dynamic_library_close(lib) dlclose(lib)
# define dynamic_library_find(lib, symbol) dlsym(lib, symbol)
#endif
#define GLUE(a, b) a ## b
#define UDEV_LIBRARY_FIND_CHECKED(name) \
GLUE(${fp}, name) = (t##name *)dynamic_library_find(lib, #name); \
assert(GLUE(${fp}, name));
#define UDEV_LIBRARY_FIND(name) \
GLUE(${fp}, name) = (t##name *)dynamic_library_find(lib, #name);
static DynamicLibrary lib;
EOF
content=`grep --no-filename -ER "extern t" $DIR/include/udew.h`
echo "$content" | sed -r "s/extern t([a-z0-9_]+).*/t\1 *$fp\1;/gi" >> $C
cat << EOF >> $C
static DynamicLibrary dynamic_library_open_find(const char **paths) {
int i = 0;
while (paths[i] != NULL) {
DynamicLibrary lib = dynamic_library_open(paths[i]);
if (lib != NULL) {
return lib;
}
++i;
}
return NULL;
}
static void udewExit(void) {
if(lib != NULL) {
/* Ignore errors. */
dynamic_library_close(lib);
lib = NULL;
}
}
/* Implementation function. */
int udewInit(void) {
/* Library paths. */
#ifdef _WIN32
/* Expected in c:/windows/system or similar, no path needed. */
const char *paths[] = {"udev.dll", NULL};
#elif defined(__APPLE__)
/* Default installation path. */
const char *paths[] = {"libudev.dylib", NULL};
#else
const char *paths[] = {"libudev.so",
"libudev.so.0",
"libudev.so.1",
"libudev.so.2",
NULL};
#endif
static int initialized = 0;
static int result = 0;
int error;
if (initialized) {
return result;
}
initialized = 1;
error = atexit(udewExit);
if (error) {
result = UDEW_ERROR_ATEXIT_FAILED;
return result;
}
/* Load library. */
lib = dynamic_library_open_find(paths);
if (lib == NULL) {
result = UDEW_ERROR_OPEN_FAILED;
return result;
}
EOF
echo "$content" | sed -r 's/extern t([a-z0-9_]+).*/ UDEV_LIBRARY_FIND(\1);/gi' >> $C
cat << EOF >> $C
result = UDEW_SUCCESS;
return result;
}
EOF
if $STUBS; then
echo "" >> $C
echo "$decl" | while read l; do
h=`echo "$l" | sed -r 's/;//' | sed 's/ __attribute__ ((deprecated))//'`
echo "$h {" >> $C
f=`echo $h | sed -r 's/^((const )?[a-z0-9_]+( [a-z0-9_]+)* \*?)([a-z0-9_]+)\(.*/\4/i'`
args=`echo $h | sed -r 's/^((const )?[a-z0-9_]+( [a-z0-9_]+)* \*?)([a-z0-9_]+)\((.*)\).*?/\5/i'`
args=`echo $args | python -c "import sys; l=sys.stdin.readline(); l=l.strip(); print(', '.join([x.split(' ')[-1].replace('*', '') for x in l.split(',')]))"`
if [ "$args" = "void" ]; then
args=""
fi
echo " return $fp$f($args);" >> $C
echo -e "}\n" >> $C
done
fi

389
extern/udew/include/udew.h vendored Normal file
View File

@@ -0,0 +1,389 @@
/*
* Copyright 2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
#ifndef __UDEW_H__
#define __UDEW_H__
#include <stdarg.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* udev - library context
*
* reads the udev config and system environment
* allows custom logging
*/
struct udev;
typedef struct udev *tudev_ref(struct udev *udev);
typedef struct udev *tudev_unref(struct udev *udev);
typedef struct udev *tudev_new(void);
typedef void tudev_set_log_fn(struct udev *udev,
void (*log_fn)(struct udev *udev,
int priority, const char *file, int line, const char *fn,
const char *format, va_list args));
typedef int tudev_get_log_priority(struct udev *udev);
typedef void tudev_set_log_priority(struct udev *udev, int priority);
typedef void *tudev_get_userdata(struct udev *udev);
typedef void tudev_set_userdata(struct udev *udev, void *userdata);
/*
* udev_list
*
* access to libudev generated lists
*/
struct udev_list_entry;
typedef struct udev_list_entry *tudev_list_entry_get_next(struct udev_list_entry *list_entry);
typedef struct udev_list_entry *tudev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
typedef const char *tudev_list_entry_get_name(struct udev_list_entry *list_entry);
typedef const char *tudev_list_entry_get_value(struct udev_list_entry *list_entry);
/**
* udev_list_entry_foreach:
* @list_entry: entry to store the current position
* @first_entry: first entry to start with
*
* Helper to iterate over all entries of a list.
*/
#define udev_list_entry_foreach(list_entry, first_entry) \
for (list_entry = first_entry; \
list_entry != NULL; \
list_entry = udev_list_entry_get_next(list_entry))
/*
* udev_device
*
* access to sysfs/kernel devices
*/
struct udev_device;
typedef struct udev_device *tudev_device_ref(struct udev_device *udev_device);
typedef struct udev_device *tudev_device_unref(struct udev_device *udev_device);
typedef struct udev *tudev_device_get_udev(struct udev_device *udev_device);
typedef struct udev_device *tudev_device_new_from_syspath(struct udev *udev, const char *syspath);
typedef struct udev_device *tudev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
typedef struct udev_device *tudev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
typedef struct udev_device *tudev_device_new_from_device_id(struct udev *udev, const char *id);
typedef struct udev_device *tudev_device_new_from_environment(struct udev *udev);
/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */
typedef struct udev_device *tudev_device_get_parent(struct udev_device *udev_device);
typedef struct udev_device *tudev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype);
/* retrieve device properties */
typedef const char *tudev_device_get_devpath(struct udev_device *udev_device);
typedef const char *tudev_device_get_subsystem(struct udev_device *udev_device);
typedef const char *tudev_device_get_devtype(struct udev_device *udev_device);
typedef const char *tudev_device_get_syspath(struct udev_device *udev_device);
typedef const char *tudev_device_get_sysname(struct udev_device *udev_device);
typedef const char *tudev_device_get_sysnum(struct udev_device *udev_device);
typedef const char *tudev_device_get_devnode(struct udev_device *udev_device);
typedef int tudev_device_get_is_initialized(struct udev_device *udev_device);
typedef struct udev_list_entry *tudev_device_get_devlinks_list_entry(struct udev_device *udev_device);
typedef struct udev_list_entry *tudev_device_get_properties_list_entry(struct udev_device *udev_device);
typedef struct udev_list_entry *tudev_device_get_tags_list_entry(struct udev_device *udev_device);
typedef struct udev_list_entry *tudev_device_get_sysattr_list_entry(struct udev_device *udev_device);
typedef const char *tudev_device_get_property_value(struct udev_device *udev_device, const char *key);
typedef const char *tudev_device_get_driver(struct udev_device *udev_device);
typedef dev_t tudev_device_get_devnum(struct udev_device *udev_device);
typedef const char *tudev_device_get_action(struct udev_device *udev_device);
typedef unsigned long long int tudev_device_get_seqnum(struct udev_device *udev_device);
typedef unsigned long long int tudev_device_get_usec_since_initialized(struct udev_device *udev_device);
typedef const char *tudev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
typedef int tudev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value);
typedef int tudev_device_has_tag(struct udev_device *udev_device, const char *tag);
/*
* udev_monitor
*
* access to kernel uevents and udev events
*/
struct udev_monitor;
typedef struct udev_monitor *tudev_monitor_ref(struct udev_monitor *udev_monitor);
typedef struct udev_monitor *tudev_monitor_unref(struct udev_monitor *udev_monitor);
typedef struct udev *tudev_monitor_get_udev(struct udev_monitor *udev_monitor);
/* kernel and udev generated events over netlink */
typedef struct udev_monitor *tudev_monitor_new_from_netlink(struct udev *udev, const char *name);
/* bind socket */
typedef int tudev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
typedef int tudev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
typedef int tudev_monitor_get_fd(struct udev_monitor *udev_monitor);
typedef struct udev_device *tudev_monitor_receive_device(struct udev_monitor *udev_monitor);
/* in-kernel socket filters to select messages that get delivered to a listener */
typedef int tudev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
const char *subsystem, const char *devtype);
typedef int tudev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
typedef int tudev_monitor_filter_update(struct udev_monitor *udev_monitor);
typedef int tudev_monitor_filter_remove(struct udev_monitor *udev_monitor);
/*
* udev_enumerate
*
* search sysfs for specific devices and provide a sorted list
*/
struct udev_enumerate;
typedef struct udev_enumerate *tudev_enumerate_ref(struct udev_enumerate *udev_enumerate);
typedef struct udev_enumerate *tudev_enumerate_unref(struct udev_enumerate *udev_enumerate);
typedef struct udev *tudev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
typedef struct udev_enumerate *tudev_enumerate_new(struct udev *udev);
/* device properties filter */
typedef int tudev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
typedef int tudev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
typedef int tudev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
typedef int tudev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
typedef int tudev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
typedef int tudev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname);
typedef int tudev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag);
typedef int tudev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent);
typedef int tudev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate);
typedef int tudev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
/* run enumeration with active filters */
typedef int tudev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
typedef int tudev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
/* return device list */
typedef struct udev_list_entry *tudev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
/*
* udev_queue
*
* access to the currently running udev events
*/
struct udev_queue;
typedef struct udev_queue *tudev_queue_ref(struct udev_queue *udev_queue);
typedef struct udev_queue *tudev_queue_unref(struct udev_queue *udev_queue);
typedef struct udev *tudev_queue_get_udev(struct udev_queue *udev_queue);
typedef struct udev_queue *tudev_queue_new(struct udev *udev);
typedef unsigned long long int tudev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
typedef unsigned long long int tudev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
typedef int tudev_queue_get_udev_is_active(struct udev_queue *udev_queue);
typedef int tudev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
typedef int tudev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
typedef int tudev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
unsigned long long int start, unsigned long long int end);
typedef int tudev_queue_get_fd(struct udev_queue *udev_queue);
typedef int tudev_queue_flush(struct udev_queue *udev_queue);
typedef struct udev_list_entry *tudev_queue_get_queued_list_entry(struct udev_queue *udev_queue);
/*
* udev_hwdb
*
* access to the static hardware properties database
*/
struct udev_hwdb;
typedef struct udev_hwdb *tudev_hwdb_new(struct udev *udev);
typedef struct udev_hwdb *tudev_hwdb_ref(struct udev_hwdb *hwdb);
typedef struct udev_hwdb *tudev_hwdb_unref(struct udev_hwdb *hwdb);
typedef struct udev_list_entry *tudev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags);
/*
* udev_util
*
* udev specific utilities
*/
typedef int tudev_util_encode_string(const char *str, char *str_enc, size_t len);
extern tudev_ref *_udev_ref;
extern tudev_unref *_udev_unref;
extern tudev_new *_udev_new;
extern tudev_set_log_fn *_udev_set_log_fn;
extern tudev_get_log_priority *_udev_get_log_priority;
extern tudev_set_log_priority *_udev_set_log_priority;
extern tudev_get_userdata *_udev_get_userdata;
extern tudev_set_userdata *_udev_set_userdata;
extern tudev_list_entry_get_next *_udev_list_entry_get_next;
extern tudev_list_entry_get_by_name *_udev_list_entry_get_by_name;
extern tudev_list_entry_get_name *_udev_list_entry_get_name;
extern tudev_list_entry_get_value *_udev_list_entry_get_value;
extern tudev_device_ref *_udev_device_ref;
extern tudev_device_unref *_udev_device_unref;
extern tudev_device_get_udev *_udev_device_get_udev;
extern tudev_device_new_from_syspath *_udev_device_new_from_syspath;
extern tudev_device_new_from_devnum *_udev_device_new_from_devnum;
extern tudev_device_new_from_subsystem_sysname *_udev_device_new_from_subsystem_sysname;
extern tudev_device_new_from_device_id *_udev_device_new_from_device_id;
extern tudev_device_new_from_environment *_udev_device_new_from_environment;
extern tudev_device_get_parent *_udev_device_get_parent;
extern tudev_device_get_parent_with_subsystem_devtype *_udev_device_get_parent_with_subsystem_devtype;
extern tudev_device_get_devpath *_udev_device_get_devpath;
extern tudev_device_get_subsystem *_udev_device_get_subsystem;
extern tudev_device_get_devtype *_udev_device_get_devtype;
extern tudev_device_get_syspath *_udev_device_get_syspath;
extern tudev_device_get_sysname *_udev_device_get_sysname;
extern tudev_device_get_sysnum *_udev_device_get_sysnum;
extern tudev_device_get_devnode *_udev_device_get_devnode;
extern tudev_device_get_is_initialized *_udev_device_get_is_initialized;
extern tudev_device_get_devlinks_list_entry *_udev_device_get_devlinks_list_entry;
extern tudev_device_get_properties_list_entry *_udev_device_get_properties_list_entry;
extern tudev_device_get_tags_list_entry *_udev_device_get_tags_list_entry;
extern tudev_device_get_sysattr_list_entry *_udev_device_get_sysattr_list_entry;
extern tudev_device_get_property_value *_udev_device_get_property_value;
extern tudev_device_get_driver *_udev_device_get_driver;
extern tudev_device_get_devnum *_udev_device_get_devnum;
extern tudev_device_get_action *_udev_device_get_action;
extern tudev_device_get_seqnum *_udev_device_get_seqnum;
extern tudev_device_get_usec_since_initialized *_udev_device_get_usec_since_initialized;
extern tudev_device_get_sysattr_value *_udev_device_get_sysattr_value;
extern tudev_device_set_sysattr_value *_udev_device_set_sysattr_value;
extern tudev_device_has_tag *_udev_device_has_tag;
extern tudev_monitor_ref *_udev_monitor_ref;
extern tudev_monitor_unref *_udev_monitor_unref;
extern tudev_monitor_get_udev *_udev_monitor_get_udev;
extern tudev_monitor_new_from_netlink *_udev_monitor_new_from_netlink;
extern tudev_monitor_enable_receiving *_udev_monitor_enable_receiving;
extern tudev_monitor_set_receive_buffer_size *_udev_monitor_set_receive_buffer_size;
extern tudev_monitor_get_fd *_udev_monitor_get_fd;
extern tudev_monitor_receive_device *_udev_monitor_receive_device;
extern tudev_monitor_filter_add_match_subsystem_devtype *_udev_monitor_filter_add_match_subsystem_devtype;
extern tudev_monitor_filter_add_match_tag *_udev_monitor_filter_add_match_tag;
extern tudev_monitor_filter_update *_udev_monitor_filter_update;
extern tudev_monitor_filter_remove *_udev_monitor_filter_remove;
extern tudev_enumerate_ref *_udev_enumerate_ref;
extern tudev_enumerate_unref *_udev_enumerate_unref;
extern tudev_enumerate_get_udev *_udev_enumerate_get_udev;
extern tudev_enumerate_new *_udev_enumerate_new;
extern tudev_enumerate_add_match_subsystem *_udev_enumerate_add_match_subsystem;
extern tudev_enumerate_add_nomatch_subsystem *_udev_enumerate_add_nomatch_subsystem;
extern tudev_enumerate_add_match_sysattr *_udev_enumerate_add_match_sysattr;
extern tudev_enumerate_add_nomatch_sysattr *_udev_enumerate_add_nomatch_sysattr;
extern tudev_enumerate_add_match_property *_udev_enumerate_add_match_property;
extern tudev_enumerate_add_match_sysname *_udev_enumerate_add_match_sysname;
extern tudev_enumerate_add_match_tag *_udev_enumerate_add_match_tag;
extern tudev_enumerate_add_match_parent *_udev_enumerate_add_match_parent;
extern tudev_enumerate_add_match_is_initialized *_udev_enumerate_add_match_is_initialized;
extern tudev_enumerate_add_syspath *_udev_enumerate_add_syspath;
extern tudev_enumerate_scan_devices *_udev_enumerate_scan_devices;
extern tudev_enumerate_scan_subsystems *_udev_enumerate_scan_subsystems;
extern tudev_enumerate_get_list_entry *_udev_enumerate_get_list_entry;
extern tudev_queue_ref *_udev_queue_ref;
extern tudev_queue_unref *_udev_queue_unref;
extern tudev_queue_get_udev *_udev_queue_get_udev;
extern tudev_queue_new *_udev_queue_new;
extern tudev_queue_get_kernel_seqnum *_udev_queue_get_kernel_seqnum;
extern tudev_queue_get_udev_seqnum *_udev_queue_get_udev_seqnum;
extern tudev_queue_get_udev_is_active *_udev_queue_get_udev_is_active;
extern tudev_queue_get_queue_is_empty *_udev_queue_get_queue_is_empty;
extern tudev_queue_get_seqnum_is_finished *_udev_queue_get_seqnum_is_finished;
extern tudev_queue_get_seqnum_sequence_is_finished *_udev_queue_get_seqnum_sequence_is_finished;
extern tudev_queue_get_fd *_udev_queue_get_fd;
extern tudev_queue_flush *_udev_queue_flush;
extern tudev_queue_get_queued_list_entry *_udev_queue_get_queued_list_entry;
extern tudev_hwdb_new *_udev_hwdb_new;
extern tudev_hwdb_ref *_udev_hwdb_ref;
extern tudev_hwdb_unref *_udev_hwdb_unref;
extern tudev_hwdb_get_properties_list_entry *_udev_hwdb_get_properties_list_entry;
extern tudev_util_encode_string *_udev_util_encode_string;
enum {
UDEW_SUCCESS = 0,
UDEW_ERROR_OPEN_FAILED = -1,
UDEW_ERROR_ATEXIT_FAILED = -2,
};
int udewInit(void);
struct udev *udev_ref(struct udev *udev);
struct udev *udev_unref(struct udev *udev);
struct udev *udev_new(void);
int udev_get_log_priority(struct udev *udev);
void udev_set_log_priority(struct udev *udev, int priority);
void *udev_get_userdata(struct udev *udev);
void udev_set_userdata(struct udev *udev, void *userdata);
struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry);
struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
const char *udev_list_entry_get_name(struct udev_list_entry *list_entry);
const char *udev_list_entry_get_value(struct udev_list_entry *list_entry);
struct udev_device *udev_device_ref(struct udev_device *udev_device);
struct udev_device *udev_device_unref(struct udev_device *udev_device);
struct udev *udev_device_get_udev(struct udev_device *udev_device);
struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath);
struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id);
struct udev_device *udev_device_new_from_environment(struct udev *udev);
struct udev_device *udev_device_get_parent(struct udev_device *udev_device);
struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype);
const char *udev_device_get_devpath(struct udev_device *udev_device);
const char *udev_device_get_subsystem(struct udev_device *udev_device);
const char *udev_device_get_devtype(struct udev_device *udev_device);
const char *udev_device_get_syspath(struct udev_device *udev_device);
const char *udev_device_get_sysname(struct udev_device *udev_device);
const char *udev_device_get_sysnum(struct udev_device *udev_device);
const char *udev_device_get_devnode(struct udev_device *udev_device);
int udev_device_get_is_initialized(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device);
const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key);
const char *udev_device_get_driver(struct udev_device *udev_device);
dev_t udev_device_get_devnum(struct udev_device *udev_device);
const char *udev_device_get_action(struct udev_device *udev_device);
unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value);
int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor);
struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name);
int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor);
int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
struct udev_enumerate *udev_enumerate_new(struct udev *udev);
int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname);
int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag);
int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent);
int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate);
int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue);
struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
struct udev_queue *udev_queue_new(struct udev *udev);
unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
int udev_queue_get_fd(struct udev_queue *udev_queue);
int udev_queue_flush(struct udev_queue *udev_queue);
struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue);
struct udev_hwdb *udev_hwdb_new(struct udev *udev);
struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb);
struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb);
struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags);
int udev_util_encode_string(const char *str, char *str_enc, size_t len);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

656
extern/udew/src/udew.c vendored Normal file
View File

@@ -0,0 +1,656 @@
/*
* Copyright 2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
#ifdef _MSC_VER
# define snprintf _snprintf
# define popen _popen
# define pclose _pclose
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "udew.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# define VC_EXTRALEAN
# include <windows.h>
/* Utility macros. */
typedef HMODULE DynamicLibrary;
# define dynamic_library_open(path) LoadLibrary(path)
# define dynamic_library_close(lib) FreeLibrary(lib)
# define dynamic_library_find(lib, symbol) GetProcAddress(lib, symbol)
#else
# include <dlfcn.h>
typedef void* DynamicLibrary;
# define dynamic_library_open(path) dlopen(path, RTLD_NOW)
# define dynamic_library_close(lib) dlclose(lib)
# define dynamic_library_find(lib, symbol) dlsym(lib, symbol)
#endif
#define GLUE(a, b) a ## b
#define UDEV_LIBRARY_FIND_CHECKED(name) GLUE(_, name) = (t##name *)dynamic_library_find(lib, #name); assert(GLUE(_, name));
#define UDEV_LIBRARY_FIND(name) GLUE(_, name) = (t##name *)dynamic_library_find(lib, #name);
static DynamicLibrary lib;
tudev_ref *_udev_ref;
tudev_unref *_udev_unref;
tudev_new *_udev_new;
tudev_set_log_fn *_udev_set_log_fn;
tudev_get_log_priority *_udev_get_log_priority;
tudev_set_log_priority *_udev_set_log_priority;
tudev_get_userdata *_udev_get_userdata;
tudev_set_userdata *_udev_set_userdata;
tudev_list_entry_get_next *_udev_list_entry_get_next;
tudev_list_entry_get_by_name *_udev_list_entry_get_by_name;
tudev_list_entry_get_name *_udev_list_entry_get_name;
tudev_list_entry_get_value *_udev_list_entry_get_value;
tudev_device_ref *_udev_device_ref;
tudev_device_unref *_udev_device_unref;
tudev_device_get_udev *_udev_device_get_udev;
tudev_device_new_from_syspath *_udev_device_new_from_syspath;
tudev_device_new_from_devnum *_udev_device_new_from_devnum;
tudev_device_new_from_subsystem_sysname *_udev_device_new_from_subsystem_sysname;
tudev_device_new_from_device_id *_udev_device_new_from_device_id;
tudev_device_new_from_environment *_udev_device_new_from_environment;
tudev_device_get_parent *_udev_device_get_parent;
tudev_device_get_parent_with_subsystem_devtype *_udev_device_get_parent_with_subsystem_devtype;
tudev_device_get_devpath *_udev_device_get_devpath;
tudev_device_get_subsystem *_udev_device_get_subsystem;
tudev_device_get_devtype *_udev_device_get_devtype;
tudev_device_get_syspath *_udev_device_get_syspath;
tudev_device_get_sysname *_udev_device_get_sysname;
tudev_device_get_sysnum *_udev_device_get_sysnum;
tudev_device_get_devnode *_udev_device_get_devnode;
tudev_device_get_is_initialized *_udev_device_get_is_initialized;
tudev_device_get_devlinks_list_entry *_udev_device_get_devlinks_list_entry;
tudev_device_get_properties_list_entry *_udev_device_get_properties_list_entry;
tudev_device_get_tags_list_entry *_udev_device_get_tags_list_entry;
tudev_device_get_sysattr_list_entry *_udev_device_get_sysattr_list_entry;
tudev_device_get_property_value *_udev_device_get_property_value;
tudev_device_get_driver *_udev_device_get_driver;
tudev_device_get_devnum *_udev_device_get_devnum;
tudev_device_get_action *_udev_device_get_action;
tudev_device_get_seqnum *_udev_device_get_seqnum;
tudev_device_get_usec_since_initialized *_udev_device_get_usec_since_initialized;
tudev_device_get_sysattr_value *_udev_device_get_sysattr_value;
tudev_device_set_sysattr_value *_udev_device_set_sysattr_value;
tudev_device_has_tag *_udev_device_has_tag;
tudev_monitor_ref *_udev_monitor_ref;
tudev_monitor_unref *_udev_monitor_unref;
tudev_monitor_get_udev *_udev_monitor_get_udev;
tudev_monitor_new_from_netlink *_udev_monitor_new_from_netlink;
tudev_monitor_enable_receiving *_udev_monitor_enable_receiving;
tudev_monitor_set_receive_buffer_size *_udev_monitor_set_receive_buffer_size;
tudev_monitor_get_fd *_udev_monitor_get_fd;
tudev_monitor_receive_device *_udev_monitor_receive_device;
tudev_monitor_filter_add_match_subsystem_devtype *_udev_monitor_filter_add_match_subsystem_devtype;
tudev_monitor_filter_add_match_tag *_udev_monitor_filter_add_match_tag;
tudev_monitor_filter_update *_udev_monitor_filter_update;
tudev_monitor_filter_remove *_udev_monitor_filter_remove;
tudev_enumerate_ref *_udev_enumerate_ref;
tudev_enumerate_unref *_udev_enumerate_unref;
tudev_enumerate_get_udev *_udev_enumerate_get_udev;
tudev_enumerate_new *_udev_enumerate_new;
tudev_enumerate_add_match_subsystem *_udev_enumerate_add_match_subsystem;
tudev_enumerate_add_nomatch_subsystem *_udev_enumerate_add_nomatch_subsystem;
tudev_enumerate_add_match_sysattr *_udev_enumerate_add_match_sysattr;
tudev_enumerate_add_nomatch_sysattr *_udev_enumerate_add_nomatch_sysattr;
tudev_enumerate_add_match_property *_udev_enumerate_add_match_property;
tudev_enumerate_add_match_sysname *_udev_enumerate_add_match_sysname;
tudev_enumerate_add_match_tag *_udev_enumerate_add_match_tag;
tudev_enumerate_add_match_parent *_udev_enumerate_add_match_parent;
tudev_enumerate_add_match_is_initialized *_udev_enumerate_add_match_is_initialized;
tudev_enumerate_add_syspath *_udev_enumerate_add_syspath;
tudev_enumerate_scan_devices *_udev_enumerate_scan_devices;
tudev_enumerate_scan_subsystems *_udev_enumerate_scan_subsystems;
tudev_enumerate_get_list_entry *_udev_enumerate_get_list_entry;
tudev_queue_ref *_udev_queue_ref;
tudev_queue_unref *_udev_queue_unref;
tudev_queue_get_udev *_udev_queue_get_udev;
tudev_queue_new *_udev_queue_new;
tudev_queue_get_kernel_seqnum *_udev_queue_get_kernel_seqnum;
tudev_queue_get_udev_seqnum *_udev_queue_get_udev_seqnum;
tudev_queue_get_udev_is_active *_udev_queue_get_udev_is_active;
tudev_queue_get_queue_is_empty *_udev_queue_get_queue_is_empty;
tudev_queue_get_seqnum_is_finished *_udev_queue_get_seqnum_is_finished;
tudev_queue_get_seqnum_sequence_is_finished *_udev_queue_get_seqnum_sequence_is_finished;
tudev_queue_get_fd *_udev_queue_get_fd;
tudev_queue_flush *_udev_queue_flush;
tudev_queue_get_queued_list_entry *_udev_queue_get_queued_list_entry;
tudev_hwdb_new *_udev_hwdb_new;
tudev_hwdb_ref *_udev_hwdb_ref;
tudev_hwdb_unref *_udev_hwdb_unref;
tudev_hwdb_get_properties_list_entry *_udev_hwdb_get_properties_list_entry;
tudev_util_encode_string *_udev_util_encode_string;
static DynamicLibrary dynamic_library_open_find(const char **paths) {
int i = 0;
while (paths[i] != NULL) {
DynamicLibrary lib = dynamic_library_open(paths[i]);
if (lib != NULL) {
return lib;
}
++i;
}
return NULL;
}
static void udewExit(void) {
if(lib != NULL) {
/* Ignore errors. */
dynamic_library_close(lib);
lib = NULL;
}
}
/* Implementation function. */
int udewInit(void) {
/* Library paths. */
#ifdef _WIN32
/* Expected in c:/windows/system or similar, no path needed. */
const char *paths[] = {"udev.dll", NULL};
#elif defined(__APPLE__)
/* Default installation path. */
const char *paths[] = {"libudev.dylib", NULL};
#else
const char *paths[] = {"libudev.so",
"libudev.so.0",
"libudev.so.1",
"libudev.so.2",
NULL};
#endif
static int initialized = 0;
static int result = 0;
int error;
if (initialized) {
return result;
}
initialized = 1;
error = atexit(udewExit);
if (error) {
result = UDEW_ERROR_ATEXIT_FAILED;
return result;
}
/* Load library. */
lib = dynamic_library_open_find(paths);
if (lib == NULL) {
result = UDEW_ERROR_OPEN_FAILED;
return result;
}
UDEV_LIBRARY_FIND(udev_ref);
UDEV_LIBRARY_FIND(udev_unref);
UDEV_LIBRARY_FIND(udev_new);
UDEV_LIBRARY_FIND(udev_set_log_fn);
UDEV_LIBRARY_FIND(udev_get_log_priority);
UDEV_LIBRARY_FIND(udev_set_log_priority);
UDEV_LIBRARY_FIND(udev_get_userdata);
UDEV_LIBRARY_FIND(udev_set_userdata);
UDEV_LIBRARY_FIND(udev_list_entry_get_next);
UDEV_LIBRARY_FIND(udev_list_entry_get_by_name);
UDEV_LIBRARY_FIND(udev_list_entry_get_name);
UDEV_LIBRARY_FIND(udev_list_entry_get_value);
UDEV_LIBRARY_FIND(udev_device_ref);
UDEV_LIBRARY_FIND(udev_device_unref);
UDEV_LIBRARY_FIND(udev_device_get_udev);
UDEV_LIBRARY_FIND(udev_device_new_from_syspath);
UDEV_LIBRARY_FIND(udev_device_new_from_devnum);
UDEV_LIBRARY_FIND(udev_device_new_from_subsystem_sysname);
UDEV_LIBRARY_FIND(udev_device_new_from_device_id);
UDEV_LIBRARY_FIND(udev_device_new_from_environment);
UDEV_LIBRARY_FIND(udev_device_get_parent);
UDEV_LIBRARY_FIND(udev_device_get_parent_with_subsystem_devtype);
UDEV_LIBRARY_FIND(udev_device_get_devpath);
UDEV_LIBRARY_FIND(udev_device_get_subsystem);
UDEV_LIBRARY_FIND(udev_device_get_devtype);
UDEV_LIBRARY_FIND(udev_device_get_syspath);
UDEV_LIBRARY_FIND(udev_device_get_sysname);
UDEV_LIBRARY_FIND(udev_device_get_sysnum);
UDEV_LIBRARY_FIND(udev_device_get_devnode);
UDEV_LIBRARY_FIND(udev_device_get_is_initialized);
UDEV_LIBRARY_FIND(udev_device_get_devlinks_list_entry);
UDEV_LIBRARY_FIND(udev_device_get_properties_list_entry);
UDEV_LIBRARY_FIND(udev_device_get_tags_list_entry);
UDEV_LIBRARY_FIND(udev_device_get_sysattr_list_entry);
UDEV_LIBRARY_FIND(udev_device_get_property_value);
UDEV_LIBRARY_FIND(udev_device_get_driver);
UDEV_LIBRARY_FIND(udev_device_get_devnum);
UDEV_LIBRARY_FIND(udev_device_get_action);
UDEV_LIBRARY_FIND(udev_device_get_seqnum);
UDEV_LIBRARY_FIND(udev_device_get_usec_since_initialized);
UDEV_LIBRARY_FIND(udev_device_get_sysattr_value);
UDEV_LIBRARY_FIND(udev_device_set_sysattr_value);
UDEV_LIBRARY_FIND(udev_device_has_tag);
UDEV_LIBRARY_FIND(udev_monitor_ref);
UDEV_LIBRARY_FIND(udev_monitor_unref);
UDEV_LIBRARY_FIND(udev_monitor_get_udev);
UDEV_LIBRARY_FIND(udev_monitor_new_from_netlink);
UDEV_LIBRARY_FIND(udev_monitor_enable_receiving);
UDEV_LIBRARY_FIND(udev_monitor_set_receive_buffer_size);
UDEV_LIBRARY_FIND(udev_monitor_get_fd);
UDEV_LIBRARY_FIND(udev_monitor_receive_device);
UDEV_LIBRARY_FIND(udev_monitor_filter_add_match_subsystem_devtype);
UDEV_LIBRARY_FIND(udev_monitor_filter_add_match_tag);
UDEV_LIBRARY_FIND(udev_monitor_filter_update);
UDEV_LIBRARY_FIND(udev_monitor_filter_remove);
UDEV_LIBRARY_FIND(udev_enumerate_ref);
UDEV_LIBRARY_FIND(udev_enumerate_unref);
UDEV_LIBRARY_FIND(udev_enumerate_get_udev);
UDEV_LIBRARY_FIND(udev_enumerate_new);
UDEV_LIBRARY_FIND(udev_enumerate_add_match_subsystem);
UDEV_LIBRARY_FIND(udev_enumerate_add_nomatch_subsystem);
UDEV_LIBRARY_FIND(udev_enumerate_add_match_sysattr);
UDEV_LIBRARY_FIND(udev_enumerate_add_nomatch_sysattr);
UDEV_LIBRARY_FIND(udev_enumerate_add_match_property);
UDEV_LIBRARY_FIND(udev_enumerate_add_match_sysname);
UDEV_LIBRARY_FIND(udev_enumerate_add_match_tag);
UDEV_LIBRARY_FIND(udev_enumerate_add_match_parent);
UDEV_LIBRARY_FIND(udev_enumerate_add_match_is_initialized);
UDEV_LIBRARY_FIND(udev_enumerate_add_syspath);
UDEV_LIBRARY_FIND(udev_enumerate_scan_devices);
UDEV_LIBRARY_FIND(udev_enumerate_scan_subsystems);
UDEV_LIBRARY_FIND(udev_enumerate_get_list_entry);
UDEV_LIBRARY_FIND(udev_queue_ref);
UDEV_LIBRARY_FIND(udev_queue_unref);
UDEV_LIBRARY_FIND(udev_queue_get_udev);
UDEV_LIBRARY_FIND(udev_queue_new);
UDEV_LIBRARY_FIND(udev_queue_get_kernel_seqnum);
UDEV_LIBRARY_FIND(udev_queue_get_udev_seqnum);
UDEV_LIBRARY_FIND(udev_queue_get_udev_is_active);
UDEV_LIBRARY_FIND(udev_queue_get_queue_is_empty);
UDEV_LIBRARY_FIND(udev_queue_get_seqnum_is_finished);
UDEV_LIBRARY_FIND(udev_queue_get_seqnum_sequence_is_finished);
UDEV_LIBRARY_FIND(udev_queue_get_fd);
UDEV_LIBRARY_FIND(udev_queue_flush);
UDEV_LIBRARY_FIND(udev_queue_get_queued_list_entry);
UDEV_LIBRARY_FIND(udev_hwdb_new);
UDEV_LIBRARY_FIND(udev_hwdb_ref);
UDEV_LIBRARY_FIND(udev_hwdb_unref);
UDEV_LIBRARY_FIND(udev_hwdb_get_properties_list_entry);
UDEV_LIBRARY_FIND(udev_util_encode_string);
result = UDEW_SUCCESS;
return result;
}
struct udev *udev_ref(struct udev *udev) {
return _udev_ref(udev);
}
struct udev *udev_unref(struct udev *udev) {
return _udev_unref(udev);
}
struct udev *udev_new(void) {
return _udev_new();
}
int udev_get_log_priority(struct udev *udev) {
return _udev_get_log_priority(udev);
}
void udev_set_log_priority(struct udev *udev, int priority) {
return _udev_set_log_priority(udev, priority);
}
void *udev_get_userdata(struct udev *udev) {
return _udev_get_userdata(udev);
}
void udev_set_userdata(struct udev *udev, void *userdata) {
return _udev_set_userdata(udev, userdata);
}
struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) {
return _udev_list_entry_get_next(list_entry);
}
struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) {
return _udev_list_entry_get_by_name(list_entry, name);
}
const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) {
return _udev_list_entry_get_name(list_entry);
}
const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) {
return _udev_list_entry_get_value(list_entry);
}
struct udev_device *udev_device_ref(struct udev_device *udev_device) {
return _udev_device_ref(udev_device);
}
struct udev_device *udev_device_unref(struct udev_device *udev_device) {
return _udev_device_unref(udev_device);
}
struct udev *udev_device_get_udev(struct udev_device *udev_device) {
return _udev_device_get_udev(udev_device);
}
struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) {
return _udev_device_new_from_syspath(udev, syspath);
}
struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) {
return _udev_device_new_from_devnum(udev, type, devnum);
}
struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) {
return _udev_device_new_from_subsystem_sysname(udev, subsystem, sysname);
}
struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) {
return _udev_device_new_from_device_id(udev, id);
}
struct udev_device *udev_device_new_from_environment(struct udev *udev) {
return _udev_device_new_from_environment(udev);
}
struct udev_device *udev_device_get_parent(struct udev_device *udev_device) {
return _udev_device_get_parent(udev_device);
}
struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) {
return _udev_device_get_parent_with_subsystem_devtype(udev_device, subsystem, devtype);
}
const char *udev_device_get_devpath(struct udev_device *udev_device) {
return _udev_device_get_devpath(udev_device);
}
const char *udev_device_get_subsystem(struct udev_device *udev_device) {
return _udev_device_get_subsystem(udev_device);
}
const char *udev_device_get_devtype(struct udev_device *udev_device) {
return _udev_device_get_devtype(udev_device);
}
const char *udev_device_get_syspath(struct udev_device *udev_device) {
return _udev_device_get_syspath(udev_device);
}
const char *udev_device_get_sysname(struct udev_device *udev_device) {
return _udev_device_get_sysname(udev_device);
}
const char *udev_device_get_sysnum(struct udev_device *udev_device) {
return _udev_device_get_sysnum(udev_device);
}
const char *udev_device_get_devnode(struct udev_device *udev_device) {
return _udev_device_get_devnode(udev_device);
}
int udev_device_get_is_initialized(struct udev_device *udev_device) {
return _udev_device_get_is_initialized(udev_device);
}
struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) {
return _udev_device_get_devlinks_list_entry(udev_device);
}
struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) {
return _udev_device_get_properties_list_entry(udev_device);
}
struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) {
return _udev_device_get_tags_list_entry(udev_device);
}
struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) {
return _udev_device_get_sysattr_list_entry(udev_device);
}
const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) {
return _udev_device_get_property_value(udev_device, key);
}
const char *udev_device_get_driver(struct udev_device *udev_device) {
return _udev_device_get_driver(udev_device);
}
dev_t udev_device_get_devnum(struct udev_device *udev_device) {
return _udev_device_get_devnum(udev_device);
}
const char *udev_device_get_action(struct udev_device *udev_device) {
return _udev_device_get_action(udev_device);
}
unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device) {
return _udev_device_get_seqnum(udev_device);
}
unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) {
return _udev_device_get_usec_since_initialized(udev_device);
}
const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) {
return _udev_device_get_sysattr_value(udev_device, sysattr);
}
int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value) {
return _udev_device_set_sysattr_value(udev_device, sysattr, value);
}
int udev_device_has_tag(struct udev_device *udev_device, const char *tag) {
return _udev_device_has_tag(udev_device, tag);
}
struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) {
return _udev_monitor_ref(udev_monitor);
}
struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) {
return _udev_monitor_unref(udev_monitor);
}
struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) {
return _udev_monitor_get_udev(udev_monitor);
}
struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) {
return _udev_monitor_new_from_netlink(udev, name);
}
int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) {
return _udev_monitor_enable_receiving(udev_monitor);
}
int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) {
return _udev_monitor_set_receive_buffer_size(udev_monitor, size);
}
int udev_monitor_get_fd(struct udev_monitor *udev_monitor) {
return _udev_monitor_get_fd(udev_monitor);
}
struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) {
return _udev_monitor_receive_device(udev_monitor);
}
int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) {
return _udev_monitor_filter_add_match_tag(udev_monitor, tag);
}
int udev_monitor_filter_update(struct udev_monitor *udev_monitor) {
return _udev_monitor_filter_update(udev_monitor);
}
int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) {
return _udev_monitor_filter_remove(udev_monitor);
}
struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) {
return _udev_enumerate_ref(udev_enumerate);
}
struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) {
return _udev_enumerate_unref(udev_enumerate);
}
struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
return _udev_enumerate_get_udev(udev_enumerate);
}
struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
return _udev_enumerate_new(udev);
}
int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
return _udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
}
int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
return _udev_enumerate_add_nomatch_subsystem(udev_enumerate, subsystem);
}
int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
return _udev_enumerate_add_match_sysattr(udev_enumerate, sysattr, value);
}
int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
return _udev_enumerate_add_nomatch_sysattr(udev_enumerate, sysattr, value);
}
int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) {
return _udev_enumerate_add_match_property(udev_enumerate, property, value);
}
int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) {
return _udev_enumerate_add_match_sysname(udev_enumerate, sysname);
}
int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) {
return _udev_enumerate_add_match_tag(udev_enumerate, tag);
}
int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) {
return _udev_enumerate_add_match_parent(udev_enumerate, parent);
}
int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) {
return _udev_enumerate_add_match_is_initialized(udev_enumerate);
}
int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) {
return _udev_enumerate_add_syspath(udev_enumerate, syspath);
}
int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) {
return _udev_enumerate_scan_devices(udev_enumerate);
}
int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) {
return _udev_enumerate_scan_subsystems(udev_enumerate);
}
struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
return _udev_enumerate_get_list_entry(udev_enumerate);
}
struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) {
return _udev_queue_ref(udev_queue);
}
struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue) {
return _udev_queue_unref(udev_queue);
}
struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) {
return _udev_queue_get_udev(udev_queue);
}
struct udev_queue *udev_queue_new(struct udev *udev) {
return _udev_queue_new(udev);
}
unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) {
return _udev_queue_get_kernel_seqnum(udev_queue);
}
unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) {
return _udev_queue_get_udev_seqnum(udev_queue);
}
int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) {
return _udev_queue_get_udev_is_active(udev_queue);
}
int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) {
return _udev_queue_get_queue_is_empty(udev_queue);
}
int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) {
return _udev_queue_get_seqnum_is_finished(udev_queue, seqnum);
}
int udev_queue_get_fd(struct udev_queue *udev_queue) {
return _udev_queue_get_fd(udev_queue);
}
int udev_queue_flush(struct udev_queue *udev_queue) {
return _udev_queue_flush(udev_queue);
}
struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) {
return _udev_queue_get_queued_list_entry(udev_queue);
}
struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
return _udev_hwdb_new(udev);
}
struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) {
return _udev_hwdb_ref(hwdb);
}
struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) {
return _udev_hwdb_unref(hwdb);
}
struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags) {
return _udev_hwdb_get_properties_list_entry(hwdb, modalias, flags);
}
int udev_util_encode_string(const char *str, char *str_enc, size_t len) {
return _udev_util_encode_string(str, str_enc, len);
}

View File

@@ -563,7 +563,7 @@ class CyclesRender_PT_views(CyclesButtonsPanel, Panel):
row.label(text="File Suffix:")
row.prop(rv, "file_suffix", text="")
else:
elif rd.views_format == 'MULTIVIEW':
row = layout.row()
row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)
@@ -574,6 +574,23 @@ class CyclesRender_PT_views(CyclesButtonsPanel, Panel):
row = layout.row()
row.label(text="Camera Suffix:")
row.prop(rv, "camera_suffix", text="")
else:
wm = context.window_manager
running = scene.hmd_running
text_win = "Close HMD Window" if wm.has_hmd_window else "Open HMD Window"
text_run = "Stop Session" if running else "Start Session"
icon = 'PAUSE' if running else 'PLAY'
col = layout.column()
row = col.row(align=True)
row.operator("wm.hmd_view_toggle", text=text_win)
row.operator("wm.hmd_session_run", text=text_run, icon=icon)
col.prop(rd, "hmd_camlock")
col.prop(rd, "use_hmd_view_lensdist", text="Lens Distortion")
col.prop(rd, "hmd_view_shade", text="Shading")
class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):

View File

@@ -112,6 +112,39 @@ if(WITH_INPUT_NDOF)
)
endif()
if (WITH_INPUT_HMD)
add_definitions(-DWITH_INPUT_HMD)
endif()
if(WITH_OPENHMD)
add_definitions(-DWITH_OPENHMD)
if(WITH_OPENHMD_DYNLOAD)
add_definitions(-DWITH_OPENHMD_DYNLOAD)
list(APPEND INC
../../extern/udew/include
)
endif()
if(WIN32)
add_definitions(-DOHMD_STATIC)
endif(WIN32)
list(APPEND INC
../../extern/openhmd
)
list(APPEND SRC
intern/GHOST_OpenHMDManager.h
intern/GHOST_OpenHMDManager.cpp
intern/GHOST_EventOpenHMD.h
)
list(APPEND INC_SYS
${OPENHMD_INCLUDE_DIRS}
)
endif()
if(WITH_HEADLESS OR WITH_GHOST_SDL)
if(WITH_HEADLESS)
list(APPEND SRC

View File

@@ -937,6 +937,24 @@ extern void GHOST_BeginIME(GHOST_WindowHandle windowhandle,
*/
extern void GHOST_EndIME(GHOST_WindowHandle windowhandle);
extern int GHOST_HMDgetNumDevices(void);
extern void GHOST_HMDopenDevice(int index);
extern void GHOST_HMDcloseDevice(void);
extern int GHOST_HMDgetOpenDeviceIndex(void);
extern const char *GHOST_HMDgetDeviceName(int index);
extern const char *GHOST_HMDgetVendorName(int index);
extern float GHOST_HMDgetDeviceIPD(void);
extern void GHOST_HMDsetDeviceIPD(float value);
extern float GHOST_HMDgetLensHorizontalSeparation(void);
extern float GHOST_HMDgetProjectionZNear(void);
extern float GHOST_HMDgetProjectionZFar(void);
extern float GHOST_HMDgetScreenHorizontalSize(void);
extern float GHOST_HMDgetLeftEyeFOV(void);
extern float GHOST_HMDgetRightEyeFOV(void);
extern void GHOST_HMDgetLeftModelviewMatrix(float r_mat[4][4]);
extern void GHOST_HMDgetRightModelviewMatrix(float r_mat[4][4]);
extern void* GHOST_HMDgetDistortionParameters(void);
#ifdef __cplusplus
}
#endif

View File

@@ -40,6 +40,7 @@
#include "GHOST_IWindow.h"
class GHOST_IEventConsumer;
class GHOST_OpenHMDManager;
/**
* \page GHOSTPage GHOST
@@ -385,6 +386,11 @@ public:
virtual void setNDOFDeadZone(float deadzone) = 0;
#endif
/**
* \return A pointer to our OpenHMD manager.
*/
virtual GHOST_OpenHMDManager *getOpenHMDManager() const = 0;
/**
* Toggles console
* \param action

View File

@@ -205,6 +205,8 @@ typedef enum {
GHOST_kEventImeComposition,
GHOST_kEventImeCompositionEnd,
GHOST_kEventHMD, // HMD - head mounted device (virtual reality)
GHOST_kNumEventTypes
} GHOST_TEventType;
@@ -522,6 +524,16 @@ typedef struct {
char utf8_buf[6];
} GHOST_TEventKeyData;
typedef enum {
GHOST_kOrientationUpdate,
GHOST_kDeviceNumChanged,
} GHOST_TEventOpenHMDSubTypes;
typedef struct {
GHOST_TEventOpenHMDSubTypes subtype;
float orientation[4]; // Orientation quaternion of the HMD (only for subtype GHOST_kOrientationUpdate)
} GHOST_TEventOpenHMDData;
typedef struct {
/** Number of pixels on a line. */
GHOST_TUns32 xPixels;

View File

@@ -38,6 +38,7 @@
#include "GHOST_ISystem.h"
#include "GHOST_IEvent.h"
#include "GHOST_IEventConsumer.h"
#include "GHOST_OpenHMDManager.h"
#include "intern/GHOST_CallbackEventConsumer.h"
GHOST_SystemHandle GHOST_CreateSystem(void)
@@ -938,3 +939,204 @@ void GHOST_EndIME(GHOST_WindowHandle windowhandle)
}
#endif /* WITH_INPUT_IME */
#ifdef WITH_INPUT_HMD
int GHOST_HMDgetNumDevices()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getNumDevices();
#else
return 0;
#endif
}
void GHOST_HMDopenDevice(int index)
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
ohmd->openDevice(index);
#else
(void)index;
#endif
}
void GHOST_HMDcloseDevice()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
ohmd->closeDevice();
#endif
}
int GHOST_HMDgetOpenDeviceIndex()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getDeviceIndex();
#else
return -1;
#endif
}
const char *GHOST_HMDgetDeviceName(int index)
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getDeviceName(index);
#else
(void)index;
return NULL;
#endif
}
const char *GHOST_HMDgetVendorName(int index)
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getVendorName(index);
#else
(void)index;
return NULL;
#endif
}
float GHOST_HMDgetDeviceIPD()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getEyeIPD();
#else
return -1.0f;
#endif
}
void GHOST_HMDsetDeviceIPD(float value)
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
ohmd->setEyeIPD(value);
#else
(void)value;
#endif
}
float GHOST_HMDgetLensHorizontalSeparation()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getLensHorizontalSeparation();
#else
return -1.0f;
#endif
}
float GHOST_HMDgetProjectionZNear()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getProjectionZNear();
#else
return -1.0f;
#endif
}
float GHOST_HMDgetProjectionZFar()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getProjectionZFar();
#else
return -1.0f;
#endif
}
float GHOST_HMDgetScreenHorizontalSize()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getScreenHorizontalSize();
#else
return -1.0f;
#endif
}
float GHOST_HMDgetLeftEyeFOV()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getLeftEyeFOV();
#else
return -1.0f;
#endif
}
float GHOST_HMDgetRightEyeFOV()
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getRightEyeFOV();
#else
return -1.0f;
#endif
}
#ifndef WITH_OPENHMD
static void ghost_UnitMat(float r_mat[4][4])
{
r_mat[0][0] = r_mat[1][1] = r_mat[2][2] = r_mat[3][3] = 1.0f;
r_mat[0][1] = r_mat[0][2] = r_mat[0][3] = 0.0f;
r_mat[1][0] = r_mat[1][2] = r_mat[1][3] = 0.0f;
r_mat[2][0] = r_mat[2][1] = r_mat[2][3] = 0.0f;
r_mat[3][0] = r_mat[3][1] = r_mat[3][2] = 0.0f;
}
#endif
void GHOST_HMDgetLeftModelviewMatrix(float r_mat[4][4])
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
ohmd->getLeftEyeGLModelviewMatrix(r_mat);
#else
ghost_UnitMat(r_mat);
#endif
}
void GHOST_HMDgetRightModelviewMatrix(float r_mat[4][4])
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
ohmd->getRightEyeGLModelviewMatrix(r_mat);
#else
ghost_UnitMat(r_mat);
#endif
}
void* GHOST_HMDgetDistortionParameters(void)
{
#ifdef WITH_OPENHMD
GHOST_ISystem *system = GHOST_ISystem::getSystem();
GHOST_OpenHMDManager *ohmd = system->getOpenHMDManager();
return ohmd->getDistortionParameters();
#else
#endif
}
#endif /* WITH_INPUT_HMD */

View File

@@ -0,0 +1,20 @@
#ifndef __GHOST_EVENTOPENHMD_H_
#define __GHOST_EVENTOPENHMD_H_
#include "GHOST_Event.h"
class GHOST_EventOpenHMD : public GHOST_Event
{
public:
GHOST_EventOpenHMD(GHOST_TUns64 time, GHOST_TEventOpenHMDSubTypes subtype, GHOST_IWindow *window)
: GHOST_Event(time, GHOST_kEventHMD, window)
{
m_OpenHMDEventData.subtype = subtype;
m_data = &m_OpenHMDEventData;
}
protected:
GHOST_TEventOpenHMDData m_OpenHMDEventData;
};
#endif // __GHOST_EVENTOPENHMD_H_

View File

@@ -0,0 +1,541 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "GHOST_OpenHMDManager.h"
#include "GHOST_EventOpenHMD.h"
#include "GHOST_WindowManager.h"
#include "include/openhmd.h"
#ifdef WITH_OPENHMD_DYNLOAD
# include "udew.h"
#endif
#define CONTEXT_ASSERT GHOST_ASSERT(m_context, "No OpenHMD context found")
GHOST_OpenHMDManager::GHOST_OpenHMDManager(GHOST_System& sys)
: m_system(sys),
m_context(NULL),
m_device(NULL),
m_deviceIndex(-1),
m_projection_params(NULL)
{
// context can be pre-created. the device can be opened later at will
createContext();
}
GHOST_OpenHMDManager::~GHOST_OpenHMDManager()
{
closeDevice();
destroyContext();
}
bool GHOST_OpenHMDManager::processEvents()
{
GHOST_IWindow *window = m_system.getWindowManager()->getActiveWindow();
if (!window)
return false;
GHOST_TUns64 now = m_system.getMilliSeconds();
static int num_devices_prev = 0;
const int num_devices = getNumDevices();
bool anyProcessed = false;
/* DeviceNumChanged event
* Would be nicer if OpenHMD could handle this for us. */
if (num_devices_prev != num_devices) {
GHOST_EventOpenHMD *event = new GHOST_EventOpenHMD(now, GHOST_kDeviceNumChanged, window);
m_system.pushEvent(event);
num_devices_prev = num_devices;
anyProcessed = true;
}
/* OrientationUpdate event
* We might want to add a timeout check here to avoid too many updates. */
if (m_device) {
GHOST_EventOpenHMD *event = new GHOST_EventOpenHMD(now, GHOST_kOrientationUpdate, window);
GHOST_TEventOpenHMDData *data = (GHOST_TEventOpenHMDData*)event->getData();
ohmd_ctx_update(m_context);
if (!getRotationQuat(data->orientation))
return false;
m_system.pushEvent(event);
anyProcessed = true;
}
return anyProcessed;
}
bool GHOST_OpenHMDManager::available() const
{
return (m_device != NULL);
}
bool GHOST_OpenHMDManager::createContext()
{
if (m_context != NULL)
return true;
#ifdef WITH_OPENHMD_DYNLOAD
static bool udew_initialized = false;
static bool udew_success = true;
if (!udew_initialized) {
udew_initialized = true;
int result = udewInit();
if (result != UDEW_SUCCESS) {
udew_success = false;
fprintf(stderr, "Failed to open udev library\n");
}
}
if (!udew_success) {
return false;
}
#endif
return (m_context = ohmd_ctx_create());
}
void GHOST_OpenHMDManager::destroyContext()
{
ohmd_ctx_destroy(m_context);
m_context = NULL;
}
bool GHOST_OpenHMDManager::openDevice(const char *requested_vendor_name, const char *requested_device_name)
{
// Create the context if it hasn't been created yet.
// Do not check for m_available as that indicates both the context and device
// are valid, which isn't the case if the context isn't available.
if (!createContext()) {
return false;
}
bool success = false;
int num_devices = ohmd_ctx_probe(m_context);
for (int i = 0; i < num_devices; ++i) {
const char* device_name = ohmd_list_gets(m_context, i, OHMD_PRODUCT);
const char* vendor_name = ohmd_list_gets(m_context, i, OHMD_VENDOR);
if (strcmp(device_name, requested_device_name) == 0 && strcmp(vendor_name, requested_vendor_name) == 0) {
success = openDevice(i);
break;
}
}
return success;
}
bool GHOST_OpenHMDManager::openDevice(int index)
{
// Create the context if it hasn't been created yet
// Do not check for m_available as that indicates both the context and device
// are valid, which isn't the case if the context isn't available.
if (!createContext()) {
return false;
}
// out of bounds
if (index >= ohmd_ctx_probe(m_context)) {
return false;
}
// Blender only allows one opened device at a time
if (getOpenHMDDevice()) {
closeDevice();
}
// can't fail to open the device
m_deviceIndex = index;
ohmd_device_settings* settings = ohmd_device_settings_create(m_context);
// If OHMD_IDS_AUTOMATIC_UPDATE is set to 0, ohmd_ctx_update() must be called at least 10 times per second.
// It is enabled by default, runs in seperate thread.
// This allows for correct tracking on low framerates, needed for heavy scenes.
int auto_update = 1;
ohmd_device_settings_seti(settings, OHMD_IDS_AUTOMATIC_UPDATE, &auto_update);
m_device = ohmd_list_open_device_s(m_context, index, settings);
ohmd_device_settings_destroy(settings); //cleanup settings
if (!m_device) {
printf("Could not open device, please check your rights\n");
return false;
}
m_projection_params = new OpenHMDDistortionParameters;
// Set the thing for the stuff
ohmd_device_getf(m_device, OHMD_SCREEN_HORIZONTAL_SIZE, &(m_projection_params->viewport_scale[0]));
m_projection_params->viewport_scale[0] /= 2.0f;
ohmd_device_getf(m_device, OHMD_SCREEN_VERTICAL_SIZE, &(m_projection_params->viewport_scale[1]));
//distortion coefficients
ohmd_device_getf(m_device, OHMD_UNIVERSAL_DISTORTION_K, &(m_projection_params->distortion_coeffs[0]));
ohmd_device_getf(m_device, OHMD_UNIVERSAL_ABERRATION_K, &(m_projection_params->aberr_scale[0]));
//calculate lens centers (assuming the eye separation is the distance betweenteh lense centers)
ohmd_device_getf(m_device, OHMD_LENS_HORIZONTAL_SEPARATION, &m_projection_params->sep);
ohmd_device_getf(m_device, OHMD_LENS_VERTICAL_POSITION, &(m_projection_params->left_lens_center[1]));
ohmd_device_getf(m_device, OHMD_LENS_VERTICAL_POSITION, &(m_projection_params->right_lens_center[1]));
return true;
}
void GHOST_OpenHMDManager::closeDevice()
{
if (!m_device) {
return;
}
ohmd_close_device(m_device);
delete m_projection_params;
m_device = NULL;
m_deviceIndex = -1;
}
int GHOST_OpenHMDManager::getNumDevices()
{
CONTEXT_ASSERT;
return ohmd_ctx_probe(m_context);
}
const char *GHOST_OpenHMDManager::getError() const
{
if (!m_device) {
return NULL;
}
return ohmd_ctx_get_error(m_context);
}
const char *GHOST_OpenHMDManager::getDeviceName() const
{
if (!m_device)
return NULL;
ohmd_ctx_probe(m_context);
return ohmd_list_gets(m_context, m_deviceIndex, OHMD_PRODUCT);
}
const char *GHOST_OpenHMDManager::getDeviceName(int index)
{
CONTEXT_ASSERT;
// Probe to fetch the device information from the hardware
ohmd_ctx_probe(m_context);
return ohmd_list_gets(m_context, index, OHMD_PRODUCT);
}
const char *GHOST_OpenHMDManager::getVendorName() const
{
if (!m_device)
return NULL;
ohmd_ctx_probe(m_context);
return ohmd_list_gets(m_context, m_deviceIndex, OHMD_VENDOR);
}
const char *GHOST_OpenHMDManager::getVendorName(int index)
{
CONTEXT_ASSERT;
// Probe to fetch the device information from the hardware
ohmd_ctx_probe(m_context);
return ohmd_list_gets(m_context, index, OHMD_VENDOR);
}
const char *GHOST_OpenHMDManager::getPath() const
{
if (!m_device)
return NULL;
return ohmd_list_gets(m_context, m_deviceIndex, OHMD_PATH);
}
bool GHOST_OpenHMDManager::getRotationQuat(float orientation[4]) const
{
if (!m_device) {
return false;
}
float tmp[4];
if (ohmd_device_getf(m_device, OHMD_ROTATION_QUAT, tmp) < 0)
return false;
// Convert from x, y, z, w space (OpenHMD) to w, x, y, z (Blender)
orientation[0] = tmp[3];
orientation[1] = tmp[0];
orientation[2] = tmp[1];
orientation[3] = tmp[2];
return true;
}
void GHOST_OpenHMDManager::getLeftEyeGLModelviewMatrix(float mat[4][4]) const
{
if (!m_device) {
return;
}
ohmd_device_getf(m_device, OHMD_LEFT_EYE_GL_MODELVIEW_MATRIX, *mat);
}
void GHOST_OpenHMDManager::getRightEyeGLModelviewMatrix(float mat[4][4]) const
{
if (!m_device) {
return;
}
ohmd_device_getf(m_device, OHMD_RIGHT_EYE_GL_MODELVIEW_MATRIX, *mat);
}
void GHOST_OpenHMDManager::getLeftEyeGLProjectionMatrix(float mat[4][4]) const
{
if (!m_device) {
return;
}
ohmd_device_getf(m_device, OHMD_LEFT_EYE_GL_PROJECTION_MATRIX, *mat);
}
void GHOST_OpenHMDManager::getRightEyeGLProjectionMatrix(float mat[4][4]) const
{
if (!m_device) {
return;
}
ohmd_device_getf(m_device, OHMD_RIGHT_EYE_GL_PROJECTION_MATRIX, *mat);
}
void GHOST_OpenHMDManager::getPositionVector(float position[3]) const
{
if (!m_device) {
return;
}
ohmd_device_getf(m_device, OHMD_POSITION_VECTOR, position);
}
float GHOST_OpenHMDManager::getScreenHorizontalSize() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_SCREEN_HORIZONTAL_SIZE, &val);
return val;
}
float GHOST_OpenHMDManager::getScreenVerticalSize() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_SCREEN_VERTICAL_SIZE, &val);
return val;
}
float GHOST_OpenHMDManager::getLensHorizontalSeparation() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_LENS_HORIZONTAL_SEPARATION, &val);
return val;
}
float GHOST_OpenHMDManager::getLensVerticalPosition() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_LENS_VERTICAL_POSITION, &val);
return val;
}
float GHOST_OpenHMDManager::getLeftEyeFOV() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_LEFT_EYE_FOV, &val);
return val;
}
float GHOST_OpenHMDManager::getLeftEyeAspectRatio() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_LEFT_EYE_ASPECT_RATIO, &val);
return val;
}
float GHOST_OpenHMDManager::getRightEyeFOV() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_RIGHT_EYE_FOV, &val);
return val;
}
float GHOST_OpenHMDManager::getRightEyeAspectRatio() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_RIGHT_EYE_ASPECT_RATIO, &val);
return val;
}
/**
* \returns -1 if not found.
*/
float GHOST_OpenHMDManager::getEyeIPD() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_EYE_IPD, &val);
return val;
}
float GHOST_OpenHMDManager::getProjectionZFar() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_PROJECTION_ZFAR, &val);
return val;
}
float GHOST_OpenHMDManager::getProjectionZNear() const
{
if (!m_device) {
return -1;
}
float val = -1;
ohmd_device_getf(m_device, OHMD_PROJECTION_ZNEAR, &val);
return val;
}
void GHOST_OpenHMDManager::getDistortion(float distortion[6]) const
{
if (!m_device) {
return;
}
ohmd_device_getf(m_device, OHMD_DISTORTION_K, distortion);
}
int GHOST_OpenHMDManager::getScreenHorizontalResolution() const
{
if (!m_device) {
return -1;
}
int val = -1;
ohmd_device_geti(m_device, OHMD_SCREEN_HORIZONTAL_RESOLUTION, &val);
return val;
}
int GHOST_OpenHMDManager::getScreenVerticalResolution() const
{
if (!m_device) {
return -1;
}
int val = -1;
ohmd_device_geti(m_device, OHMD_SCREEN_VERTICAL_RESOLUTION, &val);
return val;
}
bool GHOST_OpenHMDManager::setEyeIPD(float val)
{
if (!m_device) {
return false;
}
return ohmd_device_setf(m_device, OHMD_EYE_IPD, &val);
}
bool GHOST_OpenHMDManager::setProjectionZFar(float val)
{
if (!m_device) {
return false;
}
return ohmd_device_setf(m_device, OHMD_PROJECTION_ZFAR, &val);
}
bool GHOST_OpenHMDManager::setProjectionZNear(float val)
{
if (!m_device) {
return false;
}
return ohmd_device_setf(m_device, OHMD_PROJECTION_ZNEAR, &val);
}
ohmd_context *GHOST_OpenHMDManager::getOpenHMDContext()
{
return m_context;
}
ohmd_device *GHOST_OpenHMDManager::getOpenHMDDevice()
{
return m_device;
}
const int GHOST_OpenHMDManager::getDeviceIndex()
{
return m_deviceIndex;
}
void* GHOST_OpenHMDManager::getDistortionParameters()
{
if (!m_device) {
return NULL;
}
return m_projection_params;
}

View File

@@ -0,0 +1,319 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __GHOST_OPENHMDMANAGER_H__
#define __GHOST_OPENHMDMANAGER_H__
#include "GHOST_System.h"
struct ohmd_context;
struct ohmd_device;
struct OpenHMDDistortionParameters {
float viewport_scale[2];
float distortion_coeffs[4];
float aberr_scale[3];
float sep;
float left_lens_center[2];
float right_lens_center[2];
};
class GHOST_OpenHMDManager
{
public:
// TODO maybe cut out dependency on the system? (only used for getMilliSeconds and
// none of the others without platform implementations use it)
GHOST_OpenHMDManager(GHOST_System&);
virtual ~GHOST_OpenHMDManager();
/**
* \return True if there is a device opened and ready for polling, false otherwise.
*/
bool available() const;
/**
* Update the device context and generate an event containing the current orientation of the device.
* \return A boolean indicating success.
*/
bool processEvents();
/**
* Select the device matching the given vendor and device name.
* This device will then be the device for which ghost events will be generated.
* If no device with the correct name and vendor can be found, or an error occurs,
* the current device is preserved.
* \param requested_vendor_name The exact name of the vendor for the requested device
* \param requested_device_name The exact name of the requested device.
* \return A boolean indicating success.
*/
bool openDevice(const char *requested_vendor_name, const char *requested_device_name);
/**
* Select a device by index
* \param index The index of the requested device
* See openDevice(const char*, const char*) for more information.
*/
bool openDevice(int index);
/**
* Close the currently opened device (if available).
* This means no more events will be generated until another device is opened using openDevice.
* Has no effect is available() is false.
*/
void closeDevice();
/**
* \return The number of connected devices.
* -1 is returned if available() is false.
*/
int getNumDevices();
///TODO add a function to retrieve a list of connected devices, or the data of a single device by index.
//the data should contain at least the device name and vendor name.
/**
* \return A c-style string containing the last error as a human-readable message
* NULL is returned if available() is false.
*/
const char *getError() const;
/**
* \return A c-style string with the human-readable name of the current device.
* NULL is returned if available() is false.
*/
const char *getDeviceName() const;
/**
* \return A c-style string with the human-readable name of the device at \a index.
* NULL is returned if available() is false.
*/
const char *getDeviceName(int index);
/**
* \return A c-style string with the human-readable name of the vendor of the the current device.
* NULL is returned if available() is false.
*/
const char *getVendorName() const;
/**
* \return A c-style string with the human-readable name of the vendor at \a index.
* NULL is returned if available() is false.
*/
const char *getVendorName(int index);
/**
* \return A c-style string with the driver-specific path where the current device is attached.
* NULL is returned if available() is false.
*/
const char *getPath() const;
/**
* \param orientation The absolute orientation of the device, as quaternion, in blender format (w,x,y,z)
* Nothing is written if available() is false.
*/
bool getRotationQuat(float orientation[4]) const;
/**
* \param mat A "ready to use" OpenGL style 4x4 matrix with a modelview matrix for the left eye of the HMD.
* Nothing is written if available() is false.
*/
void getLeftEyeGLModelviewMatrix(float mat[4][4]) const;
/**
* \param mat A "ready to use" OpenGL style 4x4 matrix with a modelview matrix for the right eye of the HMD.
* Nothing is written if available() is false.
*/
void getRightEyeGLModelviewMatrix(float mat[4][4]) const;
/**
* \param mat A "ready to use" OpenGL style 4x4 matrix with a projection matrix for the left eye of the HMD.
* Nothing is written if available() is false.
*/
void getLeftEyeGLProjectionMatrix(float mat[4][4]) const;
/**
* \param mat A "ready to use" OpenGL style 4x4 matrix with a projection matrix for the right eye of the HMD.
* Nothing is written if available() is false.
*/
void getRightEyeGLProjectionMatrix(float mat[4][4]) const;
/**
* \param position A 3-D vector representing the absolute position of the device, in space.
* Nothing is written if available() is false.
*/
void getPositionVector(float position[3]) const;
/**
* \return Physical width of the device screen in metres.
* -1 is returned if available() is false.
*/
float getScreenHorizontalSize() const;
/**
* \return Physical height of the device screen in metres.
* -1 is returned if available() is false.
*/
float getScreenVerticalSize() const;
/**
* \return Physical separation of the device lenses in metres.
* -1 is returned if available() is false.
*/
float getLensHorizontalSeparation() const;
/**
* \return Physical vertical position of the lenses in metres.
* -1 is returned if available() is false.
*/
float getLensVerticalPosition() const;
/**
* \return Physical field of view for the left eye in degrees.
* -1 is returned if available() is false.
*/
float getLeftEyeFOV() const;
/**
* \return Physical display aspect ratio for the left eye screen.
* -1 is returned if available() is false.
*/
float getLeftEyeAspectRatio() const;
/**
* \return Physical display aspect ratio for the left eye screen.
* -1 is returned if available() is false.
*/
float getRightEyeFOV() const;
/**
* \return Physical display aspect ratio for the right eye screen.
* -1 is returned if available() is false.
*/
float getRightEyeAspectRatio() const;
/**
* \return Physical interpupillary distance of the user in metres.
* -1 is returned if available() is false.
*/
float getEyeIPD() const;
/**
* \return Z-far value for the projection matrix calculations (i.e. drawing distance).
* -1 is returned if available() is false.
*/
float getProjectionZFar() const;
/**
* \return Z-near value for the projection matrix calculations (i.e. close clipping distance).
* -1 is returned if available() is false.
*/
float getProjectionZNear() const;
/**
* \param distortion Device specific distortion value.
* Nothing is written if available() is false.
*/
void getDistortion(float distortion[6]) const;
/**
* \return Physical horizontal resolution of the device screen.
* -1 is returned if available() is false.
*/
int getScreenHorizontalResolution() const;
/**
* \return Physical vertical resolution of the device screen.
* -1 is returned if available() is false.
*/
int getScreenVerticalResolution() const;
/**
* Sets the physical interpupillary distance of the user in metres.
* This function can only succeed if available() is true.
* \param val The value to be set.
* \return A boolean indicating success.
*/
bool setEyeIPD(float val);
/**
* Sets the Z-far value for the projection matrix calculations (i.e. drawing distance).
* This function can only succeed if available() is true.
* \param val The value to be set.
* \return A boolean indicating success.
*/
bool setProjectionZFar(float val);
/**
* Sets the Z-near value for the projection matrix calculations (i.e. close clipping distance).
* This function can only succeed if available() is true.
* \param val The value to be set.
* \return A boolean indicating success.
*/
bool setProjectionZNear(float val);
/**
* Get the internal OpenHMD context of this manager.
* \return The context
* Context is only valid if available() is true.
*/
struct ohmd_context *getOpenHMDContext();
/**
* Get the internal OpenHMD device for the currently selected device of this manager.
* \return The device
* Device is only valid if available() is true.
*/
ohmd_device *getOpenHMDDevice();
/**
* Get the index of the currently selected device of this manager.
* \return The index.
* Index is only valid if available() is true.
*/
const int getDeviceIndex();
/**
* \return contains all the information for the lens correction shader
*/
void* getDistortionParameters();
protected:
GHOST_System& m_system;
private:
/**
* Create the context if it hasn't been created yet.
* The context lives as long as the #GHOST_OpenHMDManager lives.
* \return True if a context was created or was already available.
*/
bool createContext();
/**
* Destroy and NULL #m_context. Should only be done when deleting #GHOST_OpenHMDManager.
*/
void destroyContext();
ohmd_context *m_context;
ohmd_device *m_device;
int m_deviceIndex;
OpenHMDDistortionParameters *m_projection_params;
};
#endif //__GHOST_OPENHMDMANAGER_H__

View File

@@ -41,6 +41,7 @@
#include "GHOST_TimerTask.h"
#include "GHOST_TimerManager.h"
#include "GHOST_WindowManager.h"
#include "GHOST_OpenHMDManager.h"
#ifdef WITH_INPUT_NDOF
# include "GHOST_NDOFManager.h"
@@ -51,10 +52,11 @@ GHOST_System::GHOST_System()
m_displayManager(NULL),
m_timerManager(NULL),
m_windowManager(NULL),
m_eventManager(NULL)
m_eventManager(NULL),
#ifdef WITH_INPUT_NDOF
, m_ndofManager(0)
m_ndofManager(0),
#endif
m_openHMDManager(NULL)
{
}
@@ -215,6 +217,19 @@ bool GHOST_System::getFullScreen(void)
return fullScreen;
}
bool GHOST_System::processEvents(bool waitForEvent)
{
bool anyProcessed = false;
#ifdef WITH_OPENHMD
if (m_openHMDManager->processEvents()) {
anyProcessed = true;
}
#endif
(void)waitForEvent; // quiet warning!
return anyProcessed;
}
void GHOST_System::dispatchEvents()
{
@@ -306,7 +321,10 @@ GHOST_TSuccess GHOST_System::init()
m_timerManager = new GHOST_TimerManager();
m_windowManager = new GHOST_WindowManager();
m_eventManager = new GHOST_EventManager();
#ifdef WITH_OPENHMD
m_openHMDManager = new GHOST_OpenHMDManager(*this);
#endif
#ifdef GHOST_DEBUG
if (m_eventManager) {
m_eventPrinter = new GHOST_EventPrinter();
@@ -345,6 +363,10 @@ GHOST_TSuccess GHOST_System::exit()
delete m_ndofManager;
m_ndofManager = NULL;
#endif
if (m_openHMDManager) {
delete m_openHMDManager;
m_openHMDManager = NULL;
}
return GHOST_kSuccess;
}

View File

@@ -51,6 +51,7 @@ class GHOST_WindowManager;
#ifdef WITH_INPUT_NDOF
class GHOST_NDOFManager;
#endif
class GHOST_OpenHMDManager;
/**
* Implementation of platform independent functionality of the GHOST_ISystem
@@ -182,12 +183,9 @@ public:
***************************************************************************************/
/**
* Inherited from GHOST_ISystem but left pure virtual
*
* virtual bool processEvents(bool waitForEvent) = 0;
* Implemented for operating system independent event handling
*/
bool processEvents(bool waitForEvent);
/**
* Dispatches all the events on the stack.
@@ -284,6 +282,11 @@ public:
inline GHOST_NDOFManager *getNDOFManager() const;
#endif
/**
* \return A pointer to our OpenHMD manager.
*/
virtual GHOST_OpenHMDManager *getOpenHMDManager() const;
/**
* Returns the state of all modifier keys.
* \param keys The state of all modifier keys (true == pressed).
@@ -358,7 +361,9 @@ protected:
/** The N-degree of freedom device manager */
GHOST_NDOFManager *m_ndofManager;
#endif
GHOST_OpenHMDManager *m_openHMDManager;
/** Prints all the events. */
#ifdef GHOST_DEBUG
GHOST_EventPrinter *m_eventPrinter;
@@ -391,5 +396,10 @@ inline GHOST_NDOFManager *GHOST_System::getNDOFManager() const
}
#endif
inline GHOST_OpenHMDManager *GHOST_System::getOpenHMDManager() const
{
return m_openHMDManager;
}
#endif // __GHOST_SYSTEM_H__

View File

@@ -746,6 +746,11 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
}
[pool drain];
/* Call base class to update os independent events */
if (GHOST_System::processEvents(anyProcessed)) {
anyProcessed = true;
}
} while (event != nil);
#if 0
} while (waitForEvent && !anyProcessed); // Needed only for timer implementation

View File

@@ -596,6 +596,11 @@ GHOST_SystemSDL::processEvents(bool waitForEvent)
if (generateWindowExposeEvents()) {
anyProcessed = true;
}
/* Call base class to update os independent events */
if (GHOST_System::processEvents(anyProcessed)) {
anyProcessed = true;
}
} while (waitForEvent && !anyProcessed);
return anyProcessed;

View File

@@ -337,6 +337,11 @@ bool GHOST_SystemWin32::processEvents(bool waitForEvent)
::DispatchMessageW(&msg);
anyProcessed = true;
}
/* Call base class to update os independent events */
if (GHOST_System::processEvents(anyProcessed)) {
anyProcessed = true;
}
} while (waitForEvent && !anyProcessed);
return anyProcessed;

View File

@@ -631,7 +631,10 @@ processEvents(
anyProcessed = true;
}
#endif
/* Call base class to update os independent events */
if (GHOST_System::processEvents(anyProcessed)) {
anyProcessed = true;
}
} while (waitForEvent && !anyProcessed);
return anyProcessed;

View File

@@ -151,10 +151,11 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
st = context.camera.stereo
cam = context.camera
col = layout.column()
is_spherical_stereo = cam.type != 'ORTHO' and render.use_spherical_stereo
use_spherical_stereo = is_spherical_stereo and st.use_spherical_stereo
col = layout.column()
col.row().prop(st, "convergence_mode", expand=True)
sub = col.column()

View File

@@ -199,22 +199,22 @@ class RENDERLAYER_PT_views(RenderLayerButtonsPanel, Panel):
scene = context.scene
rd = scene.render
rv = rd.views.active
wm = context.window_manager
layout.active = rd.use_multiview
layout.enabled = rd.use_multiview
basic_stereo = rd.views_format == 'STEREO_3D'
row = layout.row()
row.prop(rd, "views_format", expand=True)
if basic_stereo:
if rd.views_format == 'STEREO_3D':
row = layout.row()
row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2)
row = layout.row()
row.label(text="File Suffix:")
row.prop(rv, "file_suffix", text="")
else:
elif rd.views_format == 'MULTIVIEW':
row = layout.row()
row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)

View File

@@ -292,6 +292,7 @@ class INFO_MT_window(Menu):
import sys
layout = self.layout
rd = context.scene.render
layout.operator("wm.window_duplicate")
layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER')
@@ -305,7 +306,7 @@ class INFO_MT_window(Menu):
layout.separator()
layout.operator("wm.console_toggle", icon='CONSOLE')
if context.scene.render.use_multiview:
if rd.use_multiview and rd.views_format in {'STEREO_3D', 'MULTIVIEW'}:
layout.separator()
layout.operator("wm.set_stereo_3d", icon='CAMERA_STEREO')

View File

@@ -502,6 +502,17 @@ class USERPREF_PT_system(Panel):
col.label(text="OpenSubdiv compute:")
col.row().prop(system, "opensubdiv_compute_type", text="")
if bpy.app.build_options.input_hmd:
col.separator()
col.label(text="Head Mounted Displays:")
col.prop(system, "hmd_device", text="Device")
col.prop(system, "use_hmd_device_rotation")
col.prop(system, "use_hmd_device_ipd")
subcol = col.column()
subcol.active = (not system.use_hmd_device_ipd) or (system.hmd_device == 'NONE')
subcol.prop(system, "hmd_custom_ipd")
# 2. Column
column = split.column()
colsplit = column.split(percentage=0.85)

View File

@@ -3407,6 +3407,37 @@ class VIEW3D_PT_view3d_shading(Panel):
subcol.prop(ssao_settings, "samples")
subcol.prop(ssao_settings, "color")
class VIEW3D_PT_view3d_hmd_view(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "HMD View"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return bpy.app.build_options.input_hmd
def draw(self, context):
layout = self.layout
wm = context.window_manager
view = context.space_data
session_running = wm.is_hmd_session_running
text_win = "Close HMD Window" if wm.has_hmd_window else "Open HMD Window"
text_run = "Stop Session" if session_running else "Start Session"
icon_run = 'PAUSE' if session_running else 'PLAY'
row = layout.row(align=True)
row.operator("wm.hmd_view_toggle", text=text_win)
row.operator("wm.hmd_session_run", text=text_run, icon=icon_run)
layout.prop(view, "use_hmd_mirror")
layout.separator()
layout.prop(wm, "hmd_view_shade", text="Shading")
layout.prop(wm, "hmd_view_show_only_render")
class VIEW3D_PT_view3d_motion_tracking(Panel):
bl_space_type = 'VIEW_3D'
@@ -3928,6 +3959,7 @@ classes = (
VIEW3D_PT_view3d_display,
VIEW3D_PT_view3d_stereo,
VIEW3D_PT_view3d_shading,
VIEW3D_PT_view3d_hmd_view,
VIEW3D_PT_view3d_motion_tracking,
VIEW3D_PT_view3d_meshdisplay,
VIEW3D_PT_view3d_meshstatvis,

View File

@@ -140,7 +140,9 @@ void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_set
/* Camera multi-view API */
struct Object *BKE_camera_multiview_render(struct Scene *scene, struct Object *camera, const char *viewname);
void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, float r_viewmat[4][4]);
void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, const float interocular_distance_override, float r_viewmat[4][4]);
void BKE_camera_multiview_proj_matrix(const bool is_left, float r_projmat[4][4]);
void BKE_camera_multiview_model_matrix_ex(struct RenderData *rd, struct Object *camera, const char *viewname, const float interocular_distance_override, float r_modelmat[4][4]);
void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]);
float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname);
void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname);

View File

@@ -117,6 +117,8 @@ void BKE_object_obdata_size_init(struct Object *ob, const float scale);
void BKE_object_scale_to_mat3(struct Object *ob, float mat[3][3]);
void BKE_object_rot_to_mat3(struct Object *ob, float mat[3][3], bool use_drot);
void BKE_object_mat3_to_rot(struct Object *ob, float mat[3][3], bool use_compat);
void BKE_object_rot_to_quat(struct Object *ob, float r_quat[4]);
void BKE_object_quat_to_rot(struct Object *ob, float quat[4]);
void BKE_object_to_mat3(struct Object *ob, float mat[3][3]);
void BKE_object_to_mat4(struct Object *ob, float mat[4][4]);
void BKE_object_apply_mat4(struct Object *ob, float mat[4][4], const bool use_compat, const bool use_parent);

View File

@@ -285,7 +285,7 @@ struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar);
void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar);
void BKE_screen_area_free(struct ScrArea *sa);
struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type);
struct ARegion *BKE_area_find_region_type(const struct ScrArea *sa, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y);
struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);

View File

@@ -378,6 +378,10 @@ if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
if(WITH_INPUT_HMD)
add_definitions(-DWITH_INPUT_HMD)
endif()
if(WITH_CODEC_AVI)
list(APPEND INC
../avi

View File

@@ -676,20 +676,20 @@ static void camera_model_matrix(Object *camera, float r_modelmat[4][4])
copy_m4_m4(r_modelmat, camera->obmat);
}
static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4])
static void camera_stereo3d_model_matrix(
Object *camera, const bool is_left, const float interocular_distance_override,
float r_modelmat[4][4])
{
Camera *data = (Camera *)camera->data;
float interocular_distance, convergence_distance;
short convergence_mode, pivot;
float sizemat[4][4];
float fac = 1.0f;
float fac_signed;
interocular_distance = data->stereo.interocular_distance;
convergence_distance = data->stereo.convergence_distance;
convergence_mode = data->stereo.convergence_mode;
pivot = data->stereo.pivot;
const float interocular_distance = interocular_distance_override == -1.0f ?
data->stereo.interocular_distance : interocular_distance_override;
const short convergence_mode = data->stereo.convergence_mode;
const short pivot = data->stereo.pivot;
if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
@@ -710,6 +710,7 @@ static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, flo
/* rotation */
if (convergence_mode == CAM_S3D_TOE) {
const float convergence_distance = data->stereo.convergence_distance;
float angle;
float angle_sin, angle_cos;
float toeinmat[4][4];
@@ -774,9 +775,13 @@ static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, flo
}
/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4])
void BKE_camera_multiview_view_matrix(
RenderData *rd, Object *camera, const bool is_left, const float interocular_distance_override,
float r_viewmat[4][4])
{
BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
BKE_camera_multiview_model_matrix_ex(
rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME,
interocular_distance_override, r_viewmat);
invert_m4(r_viewmat);
}
@@ -789,7 +794,9 @@ static bool camera_is_left(const char *viewname)
return true;
}
void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4])
void BKE_camera_multiview_model_matrix_ex(
RenderData *rd, Object *camera, const char *viewname, const float interocular_distance_override,
float r_modelmat[4][4])
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
@@ -801,11 +808,16 @@ void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const cha
}
else { /* SCE_VIEWS_SETUP_BASIC */
const bool is_left = camera_is_left(viewname);
camera_stereo3d_model_matrix(camera, is_left, r_modelmat);
camera_stereo3d_model_matrix(camera, is_left, interocular_distance_override, r_modelmat);
}
normalize_m4(r_modelmat);
}
void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4])
{
BKE_camera_multiview_model_matrix_ex(rd, camera, viewname, -1.0f, r_modelmat);
}
bool BKE_camera_multiview_spherical_stereo(RenderData *rd, Object *camera)
{
Camera *cam;

View File

@@ -1547,6 +1547,32 @@ void BKE_object_mat3_to_rot(Object *ob, float mat[3][3], bool use_compat)
}
}
void BKE_object_rot_to_quat(Object *ob, float r_quat[4])
{
if (ob->rotmode == ROT_MODE_QUAT) {
copy_qt_qt(r_quat, ob->quat);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
axis_angle_to_quat(r_quat, ob->rotAxis, ob->rotAngle);
}
else {
eulO_to_quat(r_quat, ob->rot, ob->rotmode);
}
}
void BKE_object_quat_to_rot(Object *ob, float quat[4])
{
if (ob->rotmode == ROT_MODE_QUAT) {
copy_qt_qt(ob->quat, quat);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
quat_to_axis_angle(ob->rotAxis, &ob->rotAngle, quat);
}
else {
quat_to_eulO(ob->rot, ob->rotmode, quat);
}
}
void BKE_object_tfm_protected_backup(const Object *ob,
ObjectTfmProtectedChannels *obtfm)
{

View File

@@ -404,7 +404,7 @@ unsigned int BKE_screen_visible_layers(bScreen *screen, Scene *scene)
/* ***************** Utilities ********************** */
/* Find a region of the specified type from the given area */
ARegion *BKE_area_find_region_type(ScrArea *sa, int type)
ARegion *BKE_area_find_region_type(const ScrArea *sa, int type)
{
if (sa) {
ARegion *ar;
@@ -682,4 +682,10 @@ void BKE_screen_gpu_fx_validate(GPUFXSettings *fx_settings)
GPU_fx_compositor_init_ssao_settings(fx_ssao);
}
if ((fx_settings->lensdist == NULL) &&
(fx_settings->fx_flag & GPU_FX_FLAG_LensDist))
{
fx_settings->lensdist = MEM_callocN(sizeof(GPULensDistSettings), __func__);
}
}

View File

@@ -90,6 +90,10 @@ if(WITH_ALEMBIC)
add_definitions(-DWITH_ALEMBIC)
endif()
if(WITH_INPUT_HMD)
add_definitions(-DWITH_INPUT_HMD)
endif()
blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}")
# needed so writefile.c can use dna_type_offsets.h

View File

@@ -6213,7 +6213,12 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
id_us_ensure_real(&wm->id);
link_list(fd, &wm->windows);
#ifdef WITH_INPUT_HMD
wm->hmd_view.hmd_win = newdataadr(fd, wm->hmd_view.hmd_win);
#else
wm->hmd_view.hmd_win = NULL;
#endif
for (win = wm->windows.first; win; win = win->next) {
win->ghostwin = NULL;
win->eventstate = NULL;
@@ -7176,7 +7181,9 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
v3d->fx_settings.dof = newdataadr(fd, v3d->fx_settings.dof);
if (v3d->fx_settings.ssao)
v3d->fx_settings.ssao = newdataadr(fd, v3d->fx_settings.ssao);
if (v3d->fx_settings.lensdist)
v3d->fx_settings.lensdist = newdataadr(fd, v3d->fx_settings.lensdist);
blo_do_versions_view3d_split_250(v3d, &sl->regionbase);
}
else if (sl->spacetype == SPACE_IPO) {

View File

@@ -1559,6 +1559,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
{
if (!DNA_struct_elem_find(fd->filesdna, "wmWindowManager", "HMDViewInfo", "hmd_view")) {
for (wmWindowManager *wm = main->wm.first; wm; wm = wm->id.next) {
wm->hmd_view.view_shade = OB_SOLID;
}
}
}
/* To be added to next subversion bump! */
{
/* Mask primitive adding code was not initializing correctly id_type of its points' parent. */

View File

@@ -2933,6 +2933,9 @@ static void write_screen(WriteData *wd, bScreen *sc)
if (v3d->fx_settings.dof) {
writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
}
if (v3d->fx_settings.lensdist) {
writestruct(wd, DATA, GPULensDistSettings, 1, v3d->fx_settings.lensdist);
}
}
else if (sl->spacetype == SPACE_IPO) {
SpaceIpo *sipo = (SpaceIpo *)sl;

View File

@@ -1162,12 +1162,15 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) &&
(v3d->drawtype > OB_WIRE))
{
const wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
view3d_get_transformation(cdd->vc.ar, cdd->vc.rv3d, NULL, &cdd->mats);
/* needed or else the draw matrix can be incorrect */
view3d_operator_needs_opengl(C);
ED_view3d_autodist_init(cdd->vc.scene, cdd->vc.ar, cdd->vc.v3d, 0);
ED_view3d_autodist_init(cdd->vc.scene, wm, win, cdd->vc.ar, cdd->vc.v3d, 0);
if (cdd->vc.rv3d->depths) {
cdd->vc.rv3d->depths->damaged = true;

View File

@@ -2010,8 +2010,11 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
/* init autodist for geometry projection */
if (mode == GP_REPROJECT_SURFACE) {
view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar);
ED_view3d_autodist_init(scene, gsc.ar, CTX_wm_view3d(C), 0);
const wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
view3d_region_operator_needs_opengl(win, gsc.ar);
ED_view3d_autodist_init(scene, wm, win, gsc.ar, CTX_wm_view3d(C), 0);
}
// TODO: For deforming geometry workflow, create new frames?

View File

@@ -113,7 +113,8 @@ typedef enum eGPencil_PaintFlags {
*/
typedef struct tGPsdata {
Scene *scene; /* current scene from context */
wmWindowManager *wm; /* window-manager where painting originated */
wmWindow *win; /* window where painting originated */
ScrArea *sa; /* area where painting originated */
ARegion *ar; /* region where painting originated */
@@ -637,7 +638,8 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
View3D *v3d = p->sa->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->ar);
ED_view3d_autodist_init(p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
ED_view3d_autodist_init(p->scene, p->wm, p->win, p->ar, v3d,
(ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
@@ -1239,7 +1241,7 @@ static void gp_stroke_doeraser(tGPsdata *p)
View3D *v3d = p->sa->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->ar);
ED_view3d_autodist_init(p->scene, p->ar, v3d, 0);
ED_view3d_autodist_init(p->scene, p->wm, p->win, p->ar, v3d, 0);
}
}
@@ -1391,8 +1393,9 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
return 0;
}
/* pass on current scene and window */
/* pass on context info */
p->scene = CTX_data_scene(C);
p->wm = CTX_wm_manager(C);
p->win = CTX_wm_window(C);
unit_m4(p->imat);
@@ -1804,7 +1807,8 @@ static void gp_paint_strokeend(tGPsdata *p)
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->ar);
ED_view3d_autodist_init(p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
ED_view3d_autodist_init(p->scene, p->wm, p->win, p->ar, v3d,
(ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* check if doing eraser or not */

View File

@@ -519,6 +519,7 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
/* init region-specific stuff */
if (sa->spacetype == SPACE_VIEW3D) {
const wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = (View3D *)CTX_wm_space_data(C);
@@ -528,7 +529,7 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
view3d_operator_needs_opengl(C);
view3d_region_operator_needs_opengl(win, ar);
ED_view3d_autodist_init(scene, ar, v3d, 0);
ED_view3d_autodist_init(scene, wm, win, ar, v3d, 0);
/* for camera view set the subrect */
if (rv3d->persp == RV3D_CAMOB) {

View File

@@ -118,6 +118,7 @@ void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
bool ED_screen_stereo3d_required(struct bScreen *screen);
bool ED_screen_is_editable(const struct bScreen *screen);
/* anim */
void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute);

View File

@@ -289,12 +289,17 @@ int ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float
unsigned int ED_view3d_backbuf_sample(struct ViewContext *vc, int x, int y);
bool ED_view3d_autodist(
struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
struct Scene *scene,
const struct wmWindowManager *wm, const struct wmWindow *win,
struct ARegion *ar, struct View3D *v3d,
const int mval[2], float mouse_worldloc[3],
const bool alphaoverride, const float fallback_depth_pt[3]);
/* only draw so ED_view3d_autodist_simple can be called many times after */
void ED_view3d_autodist_init(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, int mode);
void ED_view3d_autodist_init(
struct Scene *scene,
const struct wmWindowManager *wm, const struct wmWindow *win,
struct ARegion *ar, struct View3D *v3d, int mode);
bool ED_view3d_autodist_simple(struct ARegion *ar, const int mval[2], float mouse_worldloc[3], int margin, float *force_depth);
bool ED_view3d_autodist_depth(struct ARegion *ar, const int mval[2], int margin, float *depth);
bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], const int mval_end[2], int margin, float *depth);
@@ -371,11 +376,16 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);
void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]);
void ED_view3d_setup_interaction(
const struct wmWindowManager *wm, const struct wmWindow *win,
struct ARegion *region, struct View3D *v3d, struct RegionView3D *rv3d,
struct Scene *scene, const rcti *viewplane_rect);
bool ED_view3d_quat_from_axis_view(const char view, float quat[4]);
char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon);
char ED_view3d_lock_view_from_index(int index);
char ED_view3d_axis_view_opposite(char view);
bool ED_view3d_lock(struct RegionView3D *rv3d);
void ED_view3d_copy_region_view_data(const struct RegionView3D *src, struct RegionView3D *dst);
uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d);
uint64_t ED_view3d_screen_datamask(const struct bScreen *screen);

View File

@@ -79,6 +79,10 @@ if(WIN32)
endif()
endif()
if(WITH_INPUT_HMD)
add_definitions(-DWITH_INPUT_HMD)
endif()
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_interface "${SRC}" "${INC}" "${INC_SYS}")

View File

@@ -915,7 +915,7 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
view3d_operator_needs_opengl(C);
if (ED_view3d_autodist(scene, ar, v3d, mval, co, true, NULL)) {
if (ED_view3d_autodist(scene, CTX_wm_manager(C), win, ar, v3d, mval, co, true, NULL)) {
const float mval_center_fl[2] = {
(float)ar->winx / 2,
(float)ar->winy / 2};

View File

@@ -56,6 +56,8 @@
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "WM_api.h"
#include "interface_intern.h"
/* global for themes */
@@ -2764,7 +2766,17 @@ void init_userdef_do_versions(void)
* (keep this block even if it becomes empty).
*/
{
#ifdef WITH_INPUT_HMD
if (WM_HMD_num_devices_get() > 0) {
U.hmd_settings.device = 0;
}
else
#endif
{
U.hmd_settings.device = -1;
}
U.hmd_settings.flag = (USER_HMD_USE_DEVICE_IPD | USER_HMD_USE_DEVICE_ROT);
U.hmd_settings.custom_ipd = 0.061f;
}
if (U.pixelsize == 0.0f)

View File

@@ -678,7 +678,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
* running notifiers again will overwrite */
oglrender->scene->customdata_mask |= oglrender->scene->customdata_mask_modal;
if (oglrender->v3d->fx_settings.fx_flag & (GPU_FX_FLAG_DOF | GPU_FX_FLAG_SSAO)) {
if (oglrender->v3d->fx_settings.fx_flag & (GPU_FX_FLAG_DOF | GPU_FX_FLAG_SSAO | GPU_FX_FLAG_LensDist)) {
oglrender->fx = GPU_fx_compositor_create();
}
}

View File

@@ -54,9 +54,8 @@
/* returns biggest area that is not uv/image editor. Note that it uses buttons */
/* window as the last possible alternative. */
/* would use BKE_screen_find_big_area(...) but this is too specific */
static ScrArea *biggest_non_image_area(bContext *C)
static ScrArea *biggest_non_image_area(const bScreen *sc)
{
bScreen *sc = CTX_wm_screen(C);
ScrArea *sa, *big = NULL;
int size, maxsize = 0, bwmaxsize = 0;
short foundwin = 0;
@@ -181,7 +180,9 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
if (!sa) {
bScreen *screen = CTX_wm_screen(C);
sa = find_area_showing_r_result(C, scene, &win);
if (sa == NULL)
sa = find_area_image_empty(C);
@@ -189,9 +190,9 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
if (win && win != CTX_wm_window(C))
wm_window_raise(win);
if (sa == NULL) {
if (sa == NULL && ED_screen_is_editable(screen)) {
/* find largest open non-image area */
sa = biggest_non_image_area(C);
sa = biggest_non_image_area(screen);
if (sa) {
ED_area_newspace(C, sa, SPACE_IMAGE, true);
sima = sa->spacedata.first;
@@ -206,7 +207,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
else {
/* use any area of decent size */
sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
sa = BKE_screen_find_big_area(screen, SPACE_TYPE_ANY, 0);
if (sa->spacetype != SPACE_IMAGE) {
// XXX newspace(sa, SPACE_IMAGE);
sima = sa->spacedata.first;
@@ -216,6 +217,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
}
}
else if (!sa) {
/* Could also search in other screens. */
BKE_report(reports, RPT_ERROR, "Can't show render result in current screen.");
return NULL;
}
}
sima = sa->spacedata.first;
@@ -255,7 +261,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
}
/* test if we have a temp screen in front */
if (win->screen->temp) {
if (win->screen->type == SCREEN_TYPE_TEMP) {
wm_window_lower(win);
return OPERATOR_FINISHED;
}
@@ -301,7 +307,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
wmWindow *wincur = CTX_wm_window(C);
/* test if we have currently a temp screen active */
if (wincur->screen->temp) {
if (wincur->screen->type == SCREEN_TYPE_TEMP) {
wm_window_lower(wincur);
}
else {
@@ -311,7 +317,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* is there another window on current scene showing result? */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
bScreen *sc = win->screen;
if ((sc->temp && ((ScrArea *)sc->areabase.first)->spacetype == SPACE_IMAGE) ||
if (((sc->type == SCREEN_TYPE_TEMP) && ((ScrArea *)sc->areabase.first)->spacetype == SPACE_IMAGE) ||
(win == winshow && winshow != wincur))
{
wm_window_raise(win);

View File

@@ -49,6 +49,10 @@ set(SRC
screen_intern.h
)
if(WITH_INPUT_HMD)
add_definitions(-DWITH_INPUT_HMD)
endif()
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()

View File

@@ -473,6 +473,42 @@ void ED_region_set(const bContext *C, ARegion *ar)
ED_region_pixelspace(ar);
}
static void region_draw_view_setup(wmWindow *win, ARegion *ar)
{
#ifdef WITH_INPUT_HMD
if (ar->regiontype == RGN_TYPE_TEMPORARY) {
/* pass */
}
else if (!WM_window_is_running_hmd_view(win)) {
/* pass */
}
else {
ar->winx /= 2;
ar->winrct.xmax -= ar->winx;
wm_subwindow_rect_set(win, ar->swinid, &ar->winrct);
}
#else
UNUSED_VARS(win, ar);
#endif
}
static void region_draw_view_reset(wmWindow *win, ARegion *ar)
{
#ifdef WITH_INPUT_HMD
if (ar->regiontype == RGN_TYPE_TEMPORARY) {
/* pass */
}
else if (!WM_window_is_running_hmd_view(win)) {
/* pass */
}
else {
ar->winrct.xmax += ar->winx;
ar->winx *= 2;
wm_subwindow_rect_set(win, ar->swinid, &ar->winrct);
}
#else
UNUSED_VARS(win, ar);
#endif
}
/* only exported for WM */
void ED_region_do_draw(bContext *C, ARegion *ar)
@@ -486,6 +522,8 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
if (at->do_lock)
return;
region_draw_view_setup(win, ar);
/* if no partial draw rect set, full rect */
if (ar->drawrct.xmin == ar->drawrct.xmax) {
ar->drawrct = ar->winrct;
@@ -545,6 +583,8 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
region_draw_emboss(ar, &ar->winrct);
}
}
region_draw_view_reset(win, ar);
}
/* **********************************
@@ -1529,7 +1569,11 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar)
void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade)
{
ScrArea *sa = CTX_wm_area(C);
if (!ED_screen_is_editable(CTX_wm_screen(C))) {
return;
}
ar->flag ^= RGN_FLAG_HIDDEN;
if (do_fade && ar->overlap) {

View File

@@ -1344,7 +1344,7 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
/* mark it available for use for other windows */
screen->winid = 0;
if (prevwin->screen->temp == 0) {
if (prevwin->screen->type == SCREEN_TYPE_NORMAL) {
/* use previous window if possible */
CTX_wm_window_set(C, prevwin);
}
@@ -1495,7 +1495,8 @@ bool ED_screen_set(bContext *C, bScreen *sc)
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
bScreen *oldscreen = CTX_wm_screen(C);
BLI_assert(ED_screen_is_editable(sc)); /* Caller should check */
/* validate screen, it's called with notifier reference */
if (BLI_findindex(&bmain->screen, sc) == -1) {
return true;
@@ -1623,12 +1624,12 @@ bool ED_screen_delete(bContext *C, bScreen *sc)
* can safely assume ours is not in use anywhere an delete it */
for (newsc = sc->id.prev; newsc; newsc = newsc->id.prev)
if (!ed_screen_used(wm, newsc) && !newsc->temp)
if (!ed_screen_used(wm, newsc) && newsc->type != SCREEN_TYPE_TEMP)
break;
if (!newsc) {
for (newsc = sc->id.next; newsc; newsc = newsc->id.next)
if (!ed_screen_used(wm, newsc) && !newsc->temp)
if (!ed_screen_used(wm, newsc) && newsc->type != SCREEN_TYPE_TEMP)
break;
}
@@ -1943,7 +1944,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
sc = ED_screen_add(win, oldscreen->scene, newname);
sc->state = state;
sc->redraws_flag = oldscreen->redraws_flag;
sc->temp = oldscreen->temp;
sc->type = oldscreen->type;
/* timer */
sc->animtimer = oldscreen->animtimer;
@@ -2256,3 +2257,8 @@ bool ED_screen_stereo3d_required(bScreen *screen)
return false;
}
bool ED_screen_is_editable(const bScreen *screen)
{
return (screen && screen->type != SCREEN_TYPE_RESTRICTED);
}

View File

@@ -2385,7 +2385,7 @@ static bool screen_set_is_ok(bScreen *screen, bScreen *screen_prev)
return ((screen->winid == 0) &&
/* in typical usage these should have a nonzero winid
* (all temp screens should be used, or closed & freed). */
(screen->temp == false) &&
(screen->type == SCREEN_TYPE_NORMAL) &&
(screen->state == SCREENNORMAL) &&
(screen != screen_prev) &&
(screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT)));
@@ -2403,7 +2403,7 @@ static int screen_set_exec(bContext *C, wmOperator *op)
int delta = RNA_int_get(op->ptr, "delta");
/* temp screens are for userpref or render display */
if (screen->temp || (sa && sa->full && sa->full->temp)) {
if (screen->type != SCREEN_TYPE_NORMAL || (sa && sa->full && sa->full->type != SCREEN_TYPE_NORMAL)) {
return OPERATOR_CANCELLED;
}
@@ -2456,6 +2456,10 @@ static void SCREEN_OT_screen_set(wmOperatorType *ot)
/* ************** screen full-area operator ***************************** */
static int screen_maximize_area_poll(bContext *C)
{
return ED_operator_areaactive(C) && ED_screen_is_editable(CTX_wm_screen(C));
}
/* function to be called outside UI context, or for redo */
static int screen_maximize_area_exec(bContext *C, wmOperator *op)
@@ -2499,7 +2503,7 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
ot->idname = "SCREEN_OT_screen_full_area";
ot->exec = screen_maximize_area_exec;
ot->poll = ED_operator_areaactive;
ot->poll = screen_maximize_area_poll;
ot->flag = 0;
prop = RNA_def_boolean(ot->srna, "use_hide_panels", false, "Hide Panels", "Hide all the panels");
@@ -3021,7 +3025,8 @@ static void view3d_localview_update_rv3d(struct RegionView3D *rv3d)
{
if (rv3d->localvd) {
rv3d->localvd->view = rv3d->view;
rv3d->localvd->persp = rv3d->persp;
rv3d->localvd->persp = ((rv3d->viewlock & RV3D_LOCK_PERSP_VIEW) && (rv3d->localvd->persp == RV3D_ORTHO)) ?
RV3D_PERSP : rv3d->persp;
copy_qt_qt(rv3d->localvd->viewquat, rv3d->viewquat);
}
}
@@ -3035,6 +3040,7 @@ static void region_quadview_init_rv3d(ScrArea *sa, ARegion *ar,
ED_view3d_lastview_store(rv3d);
}
BLI_assert((rv3d->viewlock & RV3D_LOCK_PERSP_VIEW) == 0 || view != RV3D_ORTHO);
rv3d->viewlock = viewlock;
rv3d->view = view;
rv3d->persp = persp;
@@ -3081,14 +3087,16 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
}
rv3d->viewlock_quad = RV3D_VIEWLOCK_INIT;
rv3d->viewlock = 0;
/* allow keeping the LOCKED_SHARED flag */
rv3d->viewlock = RV3D_IS_LOCKED_SHARED(rv3d) ? RV3D_LOCKED_SHARED : 0;
rv3d->rflag &= ~RV3D_CLIPPING;
/* accumulate locks, incase they're mixed */
for (ar_iter = sa->regionbase.first; ar_iter; ar_iter = ar_iter->next) {
if (ar_iter->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d_iter = ar_iter->regiondata;
rv3d->viewlock_quad |= rv3d_iter->viewlock;
rv3d->viewlock_quad |= (RV3D_IS_LOCKED_SHARED(rv3d_iter)) ?
(rv3d_iter->viewlock & ~RV3D_LOCKED_SHARED) : rv3d_iter->viewlock;
}
}
}
@@ -3211,9 +3219,10 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot)
/* ************** header operator ***************************** */
static int header_exec(bContext *C, wmOperator *UNUSED(op))
{
const bScreen *screen = CTX_wm_screen(C);
ARegion *ar = screen_find_region_type(C, RGN_TYPE_HEADER);
if (ar == NULL) {
if (ar == NULL || !ED_screen_is_editable(screen)) {
return OPERATOR_CANCELLED;
}

View File

@@ -5024,7 +5024,7 @@ void paint_proj_stroke(
view3d_operator_needs_opengl(C);
if (!ED_view3d_autodist(scene, ar, v3d, mval_i, cursor, false, NULL))
if (!ED_view3d_autodist(scene, CTX_wm_manager(C), CTX_wm_window(C), ar, v3d, mval_i, cursor, false, NULL))
return;
ED_region_tag_redraw(ar);

View File

@@ -82,6 +82,10 @@ endif()
add_definitions(${GL_DEFINITIONS})
if(WITH_INPUT_HMD)
add_definitions(-DWITH_INPUT_HMD)
endif()
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()

View File

@@ -181,7 +181,12 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
if (ar) {
RegionView3D *rv3d;
if ((ar->regiontype == RGN_TYPE_WINDOW) && (rv3d = ar->regiondata) && (rv3d->viewlock & RV3D_LOCKED) == 0) {
if ((ar->regiontype == RGN_TYPE_WINDOW) &&
(rv3d = ar->regiondata) &&
/* the user region may also use LOCKED_SHARED, meaning the LOCKED flag is
* set but only because it's using the region data from another region */
((rv3d->viewlock & RV3D_LOCKED) == 0 || RV3D_IS_LOCKED_SHARED(rv3d)))
{
*r_v3d = v3d;
*r_ar = ar;
return true;
@@ -193,7 +198,9 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
/* find the first unlocked rv3d */
if (ar->regiondata && ar->regiontype == RGN_TYPE_WINDOW) {
rv3d = ar->regiondata;
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
/* the user region may also use LOCKED_SHARED, meaning the LOCKED flag is
* set but only because it's using the region data from another region */
if ((rv3d->viewlock & RV3D_LOCKED) == 0 || RV3D_IS_LOCKED_SHARED(rv3d)) {
ar_unlock = ar;
if (rv3d->persp == RV3D_PERSP || rv3d->persp == RV3D_CAMOB) {
ar_unlock_user = ar;
@@ -432,13 +439,26 @@ static void view3d_free(SpaceLink *sl)
MEM_freeN(vd->fx_settings.ssao);
if (vd->fx_settings.dof)
MEM_freeN(vd->fx_settings.dof);
if (vd->fx_settings.lensdist)
MEM_freeN(vd->fx_settings.lensdist);
}
/* spacetype; init callback */
static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
static void view3d_init(wmWindowManager *wm, ScrArea *sa)
{
#ifdef WITH_INPUT_HMD
View3D *v3d = sa->spacedata.first;
const wmWindow *hmd_win = wm->hmd_view.hmd_win;
const bool is_hmd_view = hmd_win && (hmd_win->screen->areabase.first == sa);
/* Make sure the HMD view is initialized with the shader set in UserPrefs. */
if (is_hmd_view && v3d->fx_settings.lensdist) {
v3d->fx_settings.fx_flag |= GPU_FX_FLAG_LensDist;
}
#else
UNUSED_VARS(wm, sa);
#endif
}
static SpaceLink *view3d_duplicate(SpaceLink *sl)
@@ -477,6 +497,8 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
v3dn->fx_settings.dof = MEM_dupallocN(v3do->fx_settings.dof);
if (v3dn->fx_settings.ssao)
v3dn->fx_settings.ssao = MEM_dupallocN(v3do->fx_settings.ssao);
if (v3dn->fx_settings.lensdist)
v3dn->fx_settings.lensdist = MEM_dupallocN(v3do->fx_settings.lensdist);
return (SpaceLink *)v3dn;
}

View File

@@ -304,7 +304,8 @@ void ED_view3d_cameracontrol_release(
else {
/* Non Camera we need to reset the view back to the original location bacause the user canceled*/
copy_qt_qt(rv3d->viewquat, vctrl->rot_backup);
rv3d->persp = vctrl->persp_backup;
rv3d->persp = ((rv3d->viewlock & RV3D_LOCK_PERSP_VIEW) && vctrl != RV3D_ORTHO) ?
vctrl->persp_backup : RV3D_PERSP;
}
/* always, is set to zero otherwise */
copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);

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