/* ----------------------------------------------------------------------------- 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;;