/*
-----------------------------------------------------------------------------
This source file is part of OpenSpace3D
For the latest info, see http://www.openspace3d.com
Copyright (c) 2015 I-maginer
This program 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 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt
-----------------------------------------------------------------------------
*/
/*
Version : 1.0
First version : 01/20/2015
Author : Bourineau Bastien
*/
var iInterpolateSamples = 12;;
var iPosInterpolateSamples = 6;;
struct ObCursor = [
POBC_pos : [I I],
POBC_initPos : [I I],
POBC_lPos : [[I I] r1],
POBC_lifeTime : I,
POBC_tControl : [F F],
POBC_tLastControl : [F F],
POBC_aim : SO3_WIDGET,
POBC_bClick : I
]mkObCursor;;
struct PlugTOBII = [
PTOBII_inst : PInstance,
PTOBII_obj : ObjTobii,
PTOBII_cursor : ObCursor,
PTOBII_bmpAim : AlphaBitmap,
PTOBII_itickLeft : I,
PTOBII_itickRight : I,
PTOBII_bLeftFound : I,
PTOBII_bRightFound : I,
PTOBII_lLeftPos : [[F F F] r1],
PTOBII_lRightPos : [[F F F] r1],
PTOBII_bMouse : I,
PTOBII_bAim : I,
PTOBII_fDeadZone : F,
PTOBII_iSpace : I,
PTOBII_tScaleRatio : [F F F],
PTOBII_objRef : SO3_OBJECT,
PTOBII_bFocus : I
]mkPlugTOBII;;
// smooth positions
fun smoothPos3(lvec)=
let [0.0 0.0 0.0] -> ovec in
let sizelist lvec -> size in
(
while (lvec != nil) do
(
let hd lvec -> vec in
set ovec = addVectorF ovec vec;
set lvec = tl lvec;
);
if (size > 0) then
divideVectorF ovec [(itof size) (itof size) (itof size)]
else
ovec;
);;
fun smoothPos2(lvec)=
let [0 0] -> ovec in
let sizelist lvec -> size in
(
while (lvec != nil) do
(
let hd lvec -> [x y] in
let ovec -> [ox oy] in
set ovec = [(ox + x) (oy + y)];
set lvec = tl lvec;
);
if (size > 0) then
let ovec -> [ox oy] in
[ftoi ((itof ox) /. (itof size)) ftoi ((itof oy) /. (itof size))]
else
ovec;
);;
fun cbTobiiPreRender(inst, sessionstr, etime, obstr)=
let V3DgetSessionView c3dXsession -> viewstr in
let V3DgetDefaultViewport viewstr -> viewportstr in
let obstr.PTOBII_cursor.POBC_tControl -> [nx ny] in
let obstr.PTOBII_cursor.POBC_tLastControl -> [lx ly] in
let smoothPos3 obstr.PTOBII_lLeftPos -> lsmpos in
let smoothPos3 obstr.PTOBII_lRightPos -> rsmpos in
let obstr.PTOBII_iSpace -> mode in
//camera space
let if (mode == 1) then SO3ViewportGetCamera viewportstr.V3D_viewport else
if (mode == 2) then
V3DgetObjectByName c3dXsession "Current camera shell"
else if (mode == 3) then
obstr.PTOBII_objRef else nil -> camera in
let SO3ObjectGetGlobalPosition camera -> cpos in
let SO3ObjectGetGlobalOrientation camera -> cquat in
let SO3MathsQuatGetDirection cquat (multiplyVectorF lsmpos obstr.PTOBII_tScaleRatio /*[0.5 0.05 (-.0.01)]*/) -> lcsmpos in
let addVectorF cpos lcsmpos -> lcsmpos in
let SO3MathsQuatGetDirection cquat (multiplyVectorF rsmpos obstr.PTOBII_tScaleRatio /*[0.5 0.05 (-.0.01)]*/) -> rcsmpos in
let addVectorF cpos rcsmpos -> rcsmpos in
(
if (obstr.PTOBII_lLeftPos == nil) then nil else
let lcsmpos -> [x y z] in
SendPluginEvent obstr.PTOBII_inst "Left eye pos" strcatn (ftoa x)::" "::(ftoa y)::" "::(ftoa z)::nil nil;
if (obstr.PTOBII_lRightPos == nil) then nil else
let rcsmpos -> [x y z] in
SendPluginEvent obstr.PTOBII_inst "Right eye pos" strcatn (ftoa x)::" "::(ftoa y)::" "::(ftoa z)::nil nil;
let if (obstr.PTOBII_lLeftPos == nil) && (obstr.PTOBII_lRightPos == nil) then
[0.0 0.0 0.0]
else if (obstr.PTOBII_lLeftPos == nil) then
rsmpos
else if (obstr.PTOBII_lRightPos == nil) then
lsmpos
else
multiplyVectorF (addVectorF lsmpos rsmpos) [0.5 0.5 0.5]
-> headpos in
let if (obstr.PTOBII_lLeftPos == nil) && (obstr.PTOBII_lRightPos == nil) then
nil
else
multiplyVectorF SO3MathsQuatToEulerPYR (SO3MathsGetRotationToAxis headpos [0.0 0.0 1.0]) [1.0 1.0 0.0]
-> headrot in
let headpos -> [hx hy hz] in
let headrot -> [hrx hry hrz] in
if (headrot == nil) then
SendPluginEvent obstr.PTOBII_inst "Head pos" strcatn (ftoa hx)::" "::(ftoa hy)::" "::(ftoa hz)::nil nil
else
SendPluginEvent obstr.PTOBII_inst "Head pos" strcatn (ftoa hx)::" "::(ftoa hy)::" "::(ftoa hz)::"\n"::(ftoa SO3MathsRadianToDegree hrx)::" "::(ftoa SO3MathsRadianToDegree hry)::" "::(ftoa SO3MathsRadianToDegree hrz)::nil nil;
let smoothPos2 obstr.PTOBII_cursor.POBC_lPos -> [mx my] in
let _ConvertScreenToWindowCoords viewstr.V3D_win mx my -> [mx my] in
let SO3ObjectGetInfoEx viewportstr.V3D_viewport mx my -> [obj mat subid dist face v1 v2 v3 tx1 tx2 tx3 hitpos uv] in
let hitpos -> [pdx pdy pdz] in
if ((obj == nil) || (zeroVectorF hitpos) || (hitpos == nil)) then nil else
(
let lcsmpos -> [lpx lpy lpz] in
let sqrt ((sqr (pdx -. lpx)) +. (sqr (pdy -. lpy)) +. (sqr (pdz -. lpz))) -> ldist in
let normalizeVectorF (subVectorF [pdx pdy pdz] [lpx lpy lpz]) -> dir in
let SO3MathsQuatToEulerDegreePYR (SO3MathsGetRotationTo [0.0 0.0 (-.1.0)] dir) -> [ldx ldy ldz] in
(
SendPluginEvent obstr.PTOBII_inst "Left distance" (ftoa ldist) nil;
SendPluginEvent obstr.PTOBII_inst "Left orientation" strcatn (ftoa ldx)::" "::(ftoa ldy)::" "::(ftoa ldz)::nil nil;
);
let rcsmpos -> [rpx rpy rpz] in
let sqrt (sqr (pdx -. rpx)) +. (sqr (pdy -. rpy)) +. (sqr (pdz -. rpz)) -> rdist in
let normalizeVectorF (subVectorF [pdx pdy pdz] [rpx rpy rpz]) -> dir in
let SO3MathsQuatToEulerDegreePYR (SO3MathsGetRotationTo [0.0 0.0 (-.1.0)] dir) -> [rdx rdy rdz] in
(
SendPluginEvent obstr.PTOBII_inst "Right distance" (ftoa rdist) nil;
SendPluginEvent obstr.PTOBII_inst "Right orientation" strcatn (ftoa rdx)::" "::(ftoa rdy)::" "::(ftoa rdz)::nil nil;
);
SendPluginEvent obstr.PTOBII_inst "Gaze hit pos" strcatn (ftoa pdx)::" "::(ftoa pdy)::" "::(ftoa pdz)::nil nil;
);
if (nx == lx && ny == ly) then nil else
SendPluginEvent obstr.PTOBII_inst "Control" strcatn "_ _ _\n"::(ftoa -.ny)::" "::(ftoa -.nx)::"_"::nil (getPluginInstanceName obstr.PTOBII_inst);
set obstr.PTOBII_cursor.POBC_tLastControl = [nx ny];
);
0;;
fun showAim(obstr, x, y)=
let (V3DgetSessionView c3dXsession) -> viewstr in
let _ConvertScreenToWindowCoords viewstr.V3D_win x y -> [lx ly] in
(
if (obstr.PTOBII_cursor != nil) then nil else
(
let mkObCursor [[lx ly] [lx ly] [x y]::nil _tickcount [0.0 0.0] [0.0 0.0] nil 0] -> curobj in
set obstr.PTOBII_cursor = curobj;
);
if (!obstr.PTOBII_bAim) then nil else
(
if (obstr.PTOBII_cursor.POBC_aim != nil) then nil else
let (V3DgetSessionView c3dXsession) -> viewstr in
let (V3DgetDefaultViewport viewstr) -> viewportstr in
let _GETalphaBitmapSize obstr.PTOBII_bmpAim -> [bw bh] in
(
set obstr.PTOBII_cursor.POBC_aim = SO3BitmapWidgetCreate (V3DgetSession c3dXsession) viewportstr.V3D_viewport (strcatn (getPluginInstanceName obstr.PTOBII_inst)::"_aim"::nil) lx-(bw / 2) ly-(bh / 2) bw bh 100000;
SO3WidgetSetTransparency obstr.PTOBII_cursor.POBC_aim 1;
SO3WidgetSetKeyboardEnable obstr.PTOBII_cursor.POBC_aim 0;
SO3WidgetSetMouseEnable obstr.PTOBII_cursor.POBC_aim 0;
SO3WidgetSetForeground obstr.PTOBII_cursor.POBC_aim 1;
SO3BitmapWidgetBlitAlpha obstr.PTOBII_cursor.POBC_aim obstr.PTOBII_bmpAim;
);
);
);
if (!obstr.PTOBII_bMouse || !obstr.PTOBII_bFocus) then nil else
(
_RMTCTRL_MouseMove x y RMTCTRL_ABSOLUTEMOVE;
);
0;;
fun updateCoords(obstr, x, y)=
let (V3DgetSessionView c3dXsession) -> viewstr in
(
let _ConvertScreenToWindowCoords viewstr.V3D_win x y -> [lnx lny] in
(
if (!obstr.PTOBII_bAim) then nil else
(
let _GETalphaBitmapSize obstr.PTOBII_bmpAim -> [bw bh] in
SO3WidgetSetPosition obstr.PTOBII_cursor.POBC_aim (lnx-(bw / 2)) (lny-(bh / 2));
);
SendPluginEvent obstr.PTOBII_inst "Gaze pos" strcatn (itoa lnx)::" "::(itoa lny)::nil nil;
let viewstr.V3D_iWinW / 2 -> wcenter in
let viewstr.V3D_iWinH / 2 -> hcenter in
let sqrt (sqr itof(lnx - wcenter)) +. (sqr itof(lny - hcenter)) -> dist in
let 1.0 /. (itof hcenter) -> hcoef in
if ((dist *. hcoef) <. obstr.PTOBII_fDeadZone) then
let hcoef *. (1.0 +. obstr.PTOBII_fDeadZone) -> hcoef in
(
set obstr.PTOBII_cursor.POBC_tControl = [0.0 0.0];
)
else
(
let maxf (-.1.0) minf ((itof (lnx - wcenter)) *. hcoef *. 0.5) 1.0 -> vx in
let maxf (-.1.0) minf ((itof (lny - hcenter)) *. hcoef) 1.0 -> vy in
set obstr.PTOBII_cursor.POBC_tControl = [vx vy];
);
);
if (!obstr.PTOBII_bMouse || !obstr.PTOBII_bFocus) then nil else
(
_RMTCTRL_MouseMove x y RMTCTRL_ABSOLUTEMOVE;
);
);
0;;
fun updateAim(obstr, x, y)=
let obstr.PTOBII_cursor.POBC_lPos -> [dx dy] in
(
if ((sizelist obstr.PTOBII_cursor.POBC_lPos) < iInterpolateSamples) then
set obstr.PTOBII_cursor.POBC_lPos = lcat obstr.PTOBII_cursor.POBC_lPos [x y]::nil
else
set obstr.PTOBII_cursor.POBC_lPos = lcat (tl obstr.PTOBII_cursor.POBC_lPos) [x y]::nil;
let smoothPos2 obstr.PTOBII_cursor.POBC_lPos -> [nx ny] in
updateCoords obstr nx ny;
);
0;;
fun hideAim(obstr)=
set obstr.PTOBII_cursor.POBC_tControl = [0.0 0.0];
if (obstr.PTOBII_cursor.POBC_aim == nil) then nil else
(
SO3WidgetDestroy obstr.PTOBII_cursor.POBC_aim;
set obstr.PTOBII_cursor.POBC_aim = nil;
);
0;;
fun cbConnected(tobii, obstr)=
SendPluginEvent obstr.PTOBII_inst "Connected" nil nil;
0;;
fun cbDisconnected(tobii, obstr)=
SendPluginEvent obstr.PTOBII_inst "Disconnected" nil nil;
0;;
fun cbUserFound(tobii, obstr)=
showAim obstr 0 0;
SendPluginEvent obstr.PTOBII_inst "User found" nil nil;
0;;
fun cbUserLost(tobii, obstr)=
hideAim obstr;
SendPluginEvent obstr.PTOBII_inst "User lost" nil nil;
if (obstr.PTOBII_bLeftFound == 0) then nil else
(
SendPluginEvent obstr.PTOBII_inst "Left eye lost" nil nil;
set obstr.PTOBII_bLeftFound = 0;
);
if (obstr.PTOBII_bRightFound == 0) then nil else
(
SendPluginEvent obstr.PTOBII_inst "Right eye lost" nil nil;
set obstr.PTOBII_bRightFound = 0;
);
0;;
fun cbEyepos(tobii, obstr, lf, rf, lp, rp)=
if (!lf && obstr.PTOBII_bLeftFound && (obstr.PTOBII_itickLeft != 0) && ((_tickcount - obstr.PTOBII_itickLeft) > 350)) then
(
SendPluginEvent obstr.PTOBII_inst "Left eye lost" nil nil;
set obstr.PTOBII_bLeftFound = 0;
set obstr.PTOBII_itickLeft = _tickcount;
)
else if (!lf && obstr.PTOBII_bLeftFound && (obstr.PTOBII_itickLeft == 0)) then
(
set obstr.PTOBII_itickLeft = _tickcount;
)
else if (lf && !obstr.PTOBII_bLeftFound) then
(
SendPluginEvent obstr.PTOBII_inst "Left eye found" nil nil;
if ((_tickcount - obstr.PTOBII_itickLeft) > 400) then nil else
(
SendPluginEvent obstr.PTOBII_inst "Left blink" nil nil;
/*if (!obstr.PTOBII_bMouse) then nil else
(
_RMTCTRL_MouseClick 1;
_RMTCTRL_MouseUnClick 1;
);*/
);
set obstr.PTOBII_bLeftFound = 1;
set obstr.PTOBII_itickLeft = 0;
)
else if (lf) then
(
set obstr.PTOBII_itickLeft = 0;
)
else nil;
if (!rf && obstr.PTOBII_bRightFound && (obstr.PTOBII_itickRight != 0) && ((_tickcount - obstr.PTOBII_itickRight) > 350)) then
(
SendPluginEvent obstr.PTOBII_inst "Right eye lost" nil nil;
set obstr.PTOBII_bRightFound = 0;
set obstr.PTOBII_itickRight = _tickcount;
)
else if (!rf && obstr.PTOBII_bRightFound && (obstr.PTOBII_itickRight == 0)) then
(
set obstr.PTOBII_itickRight = _tickcount;
)
else if (rf && !obstr.PTOBII_bRightFound) then
(
SendPluginEvent obstr.PTOBII_inst "Right eye found" nil nil;
if ((_tickcount - obstr.PTOBII_itickRight) > 400) then nil else
(
SendPluginEvent obstr.PTOBII_inst "Right blink" nil nil;
/*if (!obstr.PTOBII_bMouse) then nil else
(
_RMTCTRL_MouseClick 2;
_RMTCTRL_MouseUnClick 2;
);*/
);
set obstr.PTOBII_bRightFound = 1;
set obstr.PTOBII_itickRight = 0;
)
else if (rf) then
(
set obstr.PTOBII_itickRight = 0;
)
else nil;
if (!lf && !rf) then
(
set obstr.PTOBII_lLeftPos = nil;
set obstr.PTOBII_lRightPos = nil;
)
else
(
if (!lf) then nil else
let lp -> [x y z] in
let [(x /. 1000.0) (y /. 1000.0) (z /. 1000.0)] -> [x y z] in
if ((sizelist obstr.PTOBII_lLeftPos) < iPosInterpolateSamples) then
set obstr.PTOBII_lLeftPos = lcat obstr.PTOBII_lLeftPos [x y z]::nil
else
set obstr.PTOBII_lLeftPos = lcat (tl obstr.PTOBII_lLeftPos) [x y z]::nil;
if (!rf) then nil else
let rp -> [x y z] in
let [(x /. 1000.0) (y /. 1000.0) (z /. 1000.0)] -> [x y z] in
if ((sizelist obstr.PTOBII_lRightPos) < iPosInterpolateSamples) then
set obstr.PTOBII_lRightPos = lcat obstr.PTOBII_lRightPos [x y z]::nil
else
set obstr.PTOBII_lRightPos = lcat (tl obstr.PTOBII_lRightPos) [x y z]::nil;
);
0;;
fun cbGazepos(tobii, obstr, pos)=
//let pos -> [x y] in
// updateAim obstr x y;
0;;
fun cbFixationpos(tobii, obstr, state, pos, duration)=
if (state != 1) then nil else
let pos -> [x y] in
updateAim obstr x y;
/*if ((state != 2) || (duration < 500)) then nil else
let pos -> [x y] in
if (x == 0 && y == 0) then nil else
addLogMessage strcatn "\n>>>> fixation pos : "::(itoa x)::" "::(itoa y)::nil;*/
0;;
/*! \brief Callback on instance destruction
*
* Prototype: fun [PInstance SerialIO] I
*
* \param PInstance : destroyed plugIT instance
* \param PlugTOBII : Tuio struct
*
* \return I : 0
**/
fun deleteOb(inst, obstr)=
setPluginInstanceCbScenePreRender2 obstr.PTOBII_inst nil;
_DStobiiDevice obstr.PTOBII_obj;
//remove aim
if (obstr.PTOBII_cursor.POBC_aim == nil) then nil else
(
SO3WidgetDestroy obstr.PTOBII_cursor.POBC_aim;
set obstr.PTOBII_cursor.POBC_aim = nil;
);
set obstr.PTOBII_cursor = nil;
_DSalphaBitmap obstr.PTOBII_bmpAim;
set obstr.PTOBII_bmpAim = nil;
setPluginInstanceCbFocusView inst nil;
setPluginInstanceCbKillFocusView inst nil;
0;;
fun cbShowTarget(inst, from, action, param, rep, obstr)=
if (obstr.PTOBII_bmpAim != nil) then nil else
set obstr.PTOBII_bmpAim = G2DloadAlphaBmp _channel strcatn (getPluginDirectory (getInstancePlugin inst))::"/res/aim.png"::nil;
if (obstr.PTOBII_bAim == 1) then nil else
(
set obstr.PTOBII_bAim = 1;
showAim obstr 0 0;
);
0;;
fun cbHideTarget(inst, from, action, param, rep, obstr)=
if (obstr.PTOBII_bAim == 0) then nil else
(
set obstr.PTOBII_bAim = 0;
if (obstr.PTOBII_cursor.POBC_aim == nil) then nil else
(
SO3WidgetDestroy obstr.PTOBII_cursor.POBC_aim;
set obstr.PTOBII_cursor.POBC_aim = nil;
);
);
0;;
fun cbEnableMouse(inst, from, action, param, rep, obstr)=
set obstr.PTOBII_bMouse = 1;
0;;
fun cbDisableMouse(inst, from, action, param, rep, obstr)=
set obstr.PTOBII_bMouse = 0;
0;;
fun cbFocus(inst, viewstr, obstr)=
set obstr.PTOBII_bFocus = 1;
0;;
fun cbKillFocus(inst, viewstr, obstr)=
set obstr.PTOBII_bFocus = 0;
0;;
/*! \brief Callback on new plugIT instance
*
* Read the parameters from editor values and connect the serial port
*
* Prototype: fun [PInstance] I
*
* \param PInstance : plugIT instance
*
* \return I : 0
**/
fun newOb(inst)=
let atoi (getPluginInstanceParam inst "mouse") -> mouse in
let if mouse == nil then 0 else mouse -> mouse in
let atoi (getPluginInstanceParam inst "aim") -> aim in
let if aim == nil then 1 else aim -> aim in
let atof (getPluginInstanceParam inst "deadzone") -> deadzone in
let if deadzone == nil then 25.0 else deadzone -> deadzone in
let _CRtobiiDevice _channel -> tobiiobj in
let atof (getPluginInstanceParam inst "scaleX") -> ax in
let atof (getPluginInstanceParam inst "scaleY") -> ay in
let atof (getPluginInstanceParam inst "scaleZ") -> az in
let if ax == nil then 1.0 else ax -> ax in
let if ay == nil then 1.0 else ay -> ay in
let if az == nil then 1.0 else az -> az in
let atoi(getPluginInstanceParam inst "space") -> space in
let if space == nil then 1 else space -> space in
let (getPluginInstanceParam inst "objRef") -> objref in
let V3DgetObjectByName c3dXsession objref -> fatherref in
let mkPlugTOBII [inst tobiiobj nil nil 0 0 0 0 nil nil mouse aim (deadzone /. 100.0) space [ax ay az] fatherref 1] -> obstr in
(
if (!obstr.PTOBII_bAim) then nil else
cbShowTarget inst nil nil nil nil obstr;
setPluginInstanceCbScenePreRender2 obstr.PTOBII_inst mkfun4 @cbTobiiPreRender obstr;
PluginRegisterAction inst "Show target" mkfun6 @cbShowTarget obstr;
PluginRegisterAction inst "Hide target" mkfun6 @cbHideTarget obstr;
PluginRegisterAction inst "Enable mouse" mkfun6 @cbEnableMouse obstr;
PluginRegisterAction inst "Disable mouse" mkfun6 @cbDisableMouse obstr;
setPluginInstanceCbFocusView inst mkfun3 @cbFocus obstr;
setPluginInstanceCbKillFocusView inst mkfun3 @cbKillFocus obstr;
_CBTobiiConnected tobiiobj @cbConnected obstr;
_CBTobiiDisconnected tobiiobj @cbDisconnected obstr;
_CBTobiiUserFound tobiiobj @cbUserFound obstr;
_CBTobiiUserLost tobiiobj @cbUserLost obstr;
_CBTobiiEyesPos tobiiobj @cbEyepos obstr;
_CBTobiiGazePos tobiiobj @cbGazepos obstr;
_CBTobiiFixationPos tobiiobj @cbFixationpos obstr;
_ConnectTobiiDevice tobiiobj;
setPluginInstanceCbDel inst mkfun2 @deleteOb obstr;
);
0;;
/*! \brief Global plugIT function to initialize the plugIT callbacks
*
* Prototype: fun [S] I
*
* \param S : plugIT file path
*
* \return I : 0
**/
fun IniPlug(file)=
PlugRegister @newOb nil;
setPluginEditor @dynamicedit;
0;;