From 9e0f93c796bcc999b9767657b740a01323fc6fd7 Mon Sep 17 00:00:00 2001 From: Marco Hladik Date: Sat, 7 May 2022 17:04:05 -0700 Subject: [PATCH] Initial support for OpenXR. Remember to side-load the openxr plugin and set _pext_vrinputs to 1. --- src/client/cmd.qc | 34 +++++++++ src/client/defs.h | 4 + src/client/entry.qc | 2 +- src/client/view.qc | 30 +++++--- src/shared/client.h | 7 ++ src/shared/client.qc | 8 +- src/shared/defs.h | 1 + src/shared/include.src | 1 + src/shared/player.qc | 16 ++++ src/shared/player_pmove.qc | 12 ++- src/shared/spectator.qc | 1 + src/xr/NSXRInput.h | 59 +++++++++++++++ src/xr/NSXRInput.qc | 149 +++++++++++++++++++++++++++++++++++++ src/xr/NSXRSpace.h | 37 +++++++++ src/xr/NSXRSpace.qc | 73 ++++++++++++++++++ src/xr/defs.h | 19 +++++ src/xr/include.src | 5 ++ src/xr/xr.h | 24 ++++++ src/xr/xr.qc | 116 +++++++++++++++++++++++++++++ 19 files changed, 580 insertions(+), 18 deletions(-) create mode 100644 src/xr/NSXRInput.h create mode 100644 src/xr/NSXRInput.qc create mode 100644 src/xr/NSXRSpace.h create mode 100644 src/xr/NSXRSpace.qc create mode 100644 src/xr/defs.h create mode 100644 src/xr/include.src create mode 100644 src/xr/xr.h create mode 100644 src/xr/xr.qc diff --git a/src/client/cmd.qc b/src/client/cmd.qc index 17a80d4a..47c3ec5c 100644 --- a/src/client/cmd.qc +++ b/src/client/cmd.qc @@ -267,6 +267,30 @@ Cmd_Parse(string sCMD) case "player_geomtest": CMD_player_geomtest(); break; + + /* XR binds, engine binds them currently */ + case "+attack_left": + pSeat->m_bMoveForward = true; + break; + case "-attack_left": + pSeat->m_bMoveForward = false; + break; + case "+menu_left": + break; + case "-menu_left": + break; + case "+attack_right": + pSeat->m_iInputAttack = true; + break; + case "-attack_right": + pSeat->m_iInputAttack = false; + break; + case "+menu_right": + pSeat->m_iInputReload = TRUE; + break; + case "-menu_right": + pSeat->m_iInputReload = FALSE; + break; default: return (0); } @@ -343,4 +367,14 @@ Cmd_Init(void) /* Requested by Slacer */ registercommand("+zoomin"); registercommand("-zoomin"); + + /* XR binds, temporady until the engine standardizes things */ + registercommand("+attack_left"); + registercommand("-attack_left"); + registercommand("+attack_right"); + registercommand("-attack_right"); + registercommand("+menu_left"); + registercommand("-menu_left"); + registercommand("+menu_right"); + registercommand("-menu_right"); } diff --git a/src/client/defs.h b/src/client/defs.h index 4a2b440d..ca046d9e 100644 --- a/src/client/defs.h +++ b/src/client/defs.h @@ -185,6 +185,7 @@ struct string m_strPrintBuffer[5]; int m_iPrintLines; + bool m_iInputAttack; int m_iInputAttack2; int m_iInputReload; int m_iInputUse; @@ -212,4 +213,7 @@ struct /* vehicles */ float m_flVehTransition; vector m_vecVehEntry; + + /* new XR helpers */ + bool m_bMoveForward; } g_seats[4], *pSeat; diff --git a/src/client/entry.qc b/src/client/entry.qc index 1695c420..1848b28b 100644 --- a/src/client/entry.qc +++ b/src/client/entry.qc @@ -272,7 +272,6 @@ CSQC_UpdateView(float w, float h, float focus) View_PreDraw(); #endif - addentities(MASK_ENGINE); /* ideally move this into a base_player method */ @@ -347,6 +346,7 @@ CSQC_UpdateView(float w, float h, float focus) addentities(MASK_GLOWS); setproperty(VF_DRAWWORLD, 1); SkyCamera_Setup(getproperty(VF_ORIGIN)); + XR_UpdateView(self); /* draw the viewmodel in a second pass if desired */ if (autocvar_r_viewmodelpass && pl.health > 0) { diff --git a/src/client/view.qc b/src/client/view.qc index 25c465a2..31f86d75 100644 --- a/src/client/view.qc +++ b/src/client/view.qc @@ -207,12 +207,25 @@ View_DrawViewModel(void) /* now apply the scale hack */ m_eViewModelL.scale = m_eViewModel.scale = autocvar_r_viewmodelscale; - m_eViewModelL.origin = m_eViewModel.origin = pSeat->m_vecPredictedOrigin + pl.view_ofs; + m_eViewModelL.origin = pl.m_xrInputLeft.GetOrigin(); + m_eViewModel.origin = pl.m_xrInputRight.GetOrigin(); - /* we only calculate bob on the right model, to avoid double speed bobbing */ - Viewmodel_CalcBob(); - Viewmodel_ApplyBob(m_eViewModel); - Viewmodel_ApplyBob(m_eViewModelL); + if (XR_Available(pl)) { + m_eViewModel.angles = pl.m_xrInputLeft.GetAngles(); + m_eViewModelL.angles = pl.m_xrInputRight.GetAngles(); + } else { + /* we only calculate bob on the right model, to avoid double speed bobbing */ + Viewmodel_CalcBob(); + Viewmodel_ApplyBob(m_eViewModel); + Viewmodel_ApplyBob(m_eViewModelL); + + /* view roll */ + if (pl.movetype == MOVETYPE_WALK) { + Camera_StrafeRoll(view_angles); + Camera_RunBob(view_angles); + setproperty(VF_ANGLES, view_angles + pl.punchangle); + } + } /* this is currently broken */ #if 0 @@ -260,13 +273,6 @@ View_DrawViewModel(void) addentity(m_eViewModel); addentity(m_eViewModelL); } - - /* view roll */ - if (pl.movetype == MOVETYPE_WALK) { - Camera_StrafeRoll(view_angles); - Camera_RunBob(view_angles); - setproperty(VF_ANGLES, view_angles + pl.punchangle); - } } void diff --git a/src/shared/client.h b/src/shared/client.h index cd6b2cd2..be02e009 100644 --- a/src/shared/client.h +++ b/src/shared/client.h @@ -5,6 +5,11 @@ base_client:NSSurfacePropEntity vector origin_net; vector velocity_net; + NSXRSpace m_xrSpace; + NSXRInput m_xrInputHead; + NSXRInput m_xrInputLeft; + NSXRInput m_xrInputRight; + void(void) base_client; /* final input handling of the client */ @@ -18,6 +23,8 @@ base_client:NSSurfacePropEntity virtual bool(void) IsDead; virtual bool(void) IsPlayer; + virtual void(void) OnRemoveEntity; + #ifdef CLIENT /* gives the chance to override input variables before networking */ virtual void(void) ClientInputFrame; diff --git a/src/shared/client.qc b/src/shared/client.qc index 052a6193..b4b8fadb 100644 --- a/src/shared/client.qc +++ b/src/shared/client.qc @@ -1,3 +1,9 @@ +void +base_client::OnRemoveEntity(void) +{ + XR_Shutdown(this); +} + void base_client::ClientInput(void) { @@ -63,7 +69,7 @@ base_client::predraw(void) void base_client::base_client(void) { - + XR_Init(this); } diff --git a/src/shared/defs.h b/src/shared/defs.h index 6259b273..631b73f4 100644 --- a/src/shared/defs.h +++ b/src/shared/defs.h @@ -41,6 +41,7 @@ #endif #include "../gs-entbase/shared/baseentity.h" +#include "../xr/defs.h" #include "client.h" #include "spectator.h" #include "player.h" diff --git a/src/shared/include.src b/src/shared/include.src index 03b1db36..4f5dd44a 100644 --- a/src/shared/include.src +++ b/src/shared/include.src @@ -9,4 +9,5 @@ player.qc player_pmove.qc propdata.qc surfaceproperties.qc +../xr/include.src #endlist diff --git a/src/shared/player.qc b/src/shared/player.qc index ddd2bad8..177ec292 100644 --- a/src/shared/player.qc +++ b/src/shared/player.qc @@ -102,6 +102,8 @@ base_player::PostFrame(void) void base_player::ClientInput(void) { + XR_InputFrame(this); + if (!Client_InIntermission() && IsFakeSpectator()) { spectator::ClientInput(); SpectatorTrackPlayer(); @@ -135,6 +137,8 @@ base_player::OnRemoveEntity(void) { if (p_model) remove(p_model); + + super::OnRemoveEntity(); } /* @@ -197,6 +201,17 @@ base_player::ClientInputFrame(void) return; } + /* some input overrides for XR */ + if (XR_Available(this)) { + if (pSeat->m_bMoveForward) { + input_movevalues[0] = cvar("cl_forwardspeed"); + } + + if (pSeat->m_iInputAttack) { + input_buttons |= INPUT_BUTTON0; + } + } + /* compat*/ if (input_impulse == 201) { sendevent("Spraylogo", ""); @@ -931,5 +946,6 @@ base_player::InputUse_Up(void) void base_player::base_player(void) { + super::spectator(); vehicle = __NULL__; } diff --git a/src/shared/player_pmove.qc b/src/shared/player_pmove.qc index 7b60016a..47721eca 100644 --- a/src/shared/player_pmove.qc +++ b/src/shared/player_pmove.qc @@ -330,6 +330,10 @@ base_player::Physics_Run(void) input_buttons = saved_input_buttons; Physics_InputPostMove(); + angles[0] = Math_FixDelta(angles[0]); + angles[1] = Math_FixDelta(angles[1]); + angles[2] = Math_FixDelta(angles[2]); + #ifdef SERVER /* Use Flagger */ vector src, dest; @@ -345,9 +349,9 @@ base_player::Physics_Run(void) flags |= FL_ONUSABLE; } } -#endif - angles[0] = Math_FixDelta(angles[0]); - angles[1] = Math_FixDelta(angles[1]); - angles[2] = Math_FixDelta(angles[2]); + + m_xrSpace.SetOrigin(origin + view_ofs); + m_xrSpace.SetAngles(angles); +#endif } diff --git a/src/shared/spectator.qc b/src/shared/spectator.qc index 58cbda9e..0affeb7c 100644 --- a/src/shared/spectator.qc +++ b/src/shared/spectator.qc @@ -450,6 +450,7 @@ spectator::PostFrame(void) void spectator::spectator(void) { + super::base_client(); modelindex = 0; flags = FL_CLIENT; SetSolid(SOLID_NOT); diff --git a/src/xr/NSXRInput.h b/src/xr/NSXRInput.h new file mode 100644 index 00000000..fef35b49 --- /dev/null +++ b/src/xr/NSXRInput.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016-2022 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +typedef enum +{ + XR_INPUT_UNKNOWN, + XR_INPUT_HEAD, + XR_INPUT_LEFT, + XR_INPUT_RIGHT +} xrinput_e; + +#define XR_STATUS_ORG (1u<<0) +#define XR_STATUS_ANG (1u<<1) +#define XR_STATUS_VEL (1u<<2) +#define XR_STATUS_AVEL (1u<<3) + +class +NSXRInput +{ + NSXRSpace m_xrSpace; + vector m_vecOrigin; + vector m_vecAngles; + vector m_vecVelocity; + vector m_vecAVelocity; + unsigned int m_iStatus; + unsigned int m_iWeapon; + + xrinput_e m_inputType; + + void(void) NSXRInput; + virtual void(xrinput_e) SetType; + virtual void(NSXRSpace) SetParentSpace; + + virtual vector(void) GetOrigin; + virtual vector(void) GetAngles; + virtual vector(void) GetVelocity; + virtual vector(void) GetAngularVelocity; + virtual unsigned int(void) GetStatus; + virtual unsigned int(void) GetWeapon; + virtual xrinput_e (void) GetType; + + virtual bool(void) IsAvailable; + virtual void(void) InputFrame; + + virtual void(void) PrintInfo; +}; \ No newline at end of file diff --git a/src/xr/NSXRInput.qc b/src/xr/NSXRInput.qc new file mode 100644 index 00000000..600f4dd3 --- /dev/null +++ b/src/xr/NSXRInput.qc @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016-2022 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +vector +NSXRInput::GetOrigin(void) +{ + if (!m_xrSpace) { + print("WARNING: XR Space not yet present!\n"); + return [0,0,0]; + } + + return m_xrSpace.RoomToWorldOrigin(m_vecOrigin); +} + +vector +NSXRInput::GetAngles(void) +{ + if (!m_xrSpace) { + print("WARNING: XR Space not yet present!\n"); + return [0,0,0]; + } + + return m_xrSpace.RoomToWorldAngles(m_vecAngles); +} + +vector +NSXRInput::GetVelocity(void) +{ + return m_vecVelocity; +} + +vector +NSXRInput::GetAngularVelocity(void) +{ + return m_vecAVelocity; +} + +unsigned int +NSXRInput::GetStatus(void) +{ + return m_iStatus; +} + +unsigned int +NSXRInput::GetWeapon(void) +{ + return m_iWeapon; +} + +xrinput_e +NSXRInput::GetType(void) +{ + return m_inputType; +} + +void +NSXRInput::InputFrame(void) +{ + switch (m_inputType) { + case XR_INPUT_HEAD: + m_vecOrigin = input_head_origin; + m_vecAngles = input_head_angles; + m_vecVelocity = input_head_velocity; + m_vecAVelocity = input_head_avelocity; + m_iStatus = input_head_status; + m_iWeapon = input_head_weapon; + break; + case XR_INPUT_LEFT: + m_vecOrigin = input_left_origin; + m_vecAngles = input_left_angles; + m_vecVelocity = input_left_velocity; + m_vecAVelocity = input_left_avelocity; + m_iStatus = input_left_status; + m_iWeapon = input_left_weapon; + break; + case XR_INPUT_RIGHT: + m_vecOrigin = input_right_origin; + m_vecAngles = input_right_angles; + m_vecVelocity = input_right_velocity; + m_vecAVelocity = input_right_avelocity; + m_iStatus = input_right_status; + m_iWeapon = input_right_weapon; + break; + default: + print(sprintf("NSXRInput: Cannot run InputFrame() on unknown type")); + } + + //PrintInfo(); +} + +bool +NSXRInput::IsAvailable(void) +{ + /* if it's generating new origin/angles, then the device is very clearly available */ + return (m_iStatus & (XR_STATUS_ORG | XR_STATUS_ANG)) ? true : false; +} + +void +NSXRInput::SetType(xrinput_e type) +{ + m_inputType = type; +} + +void +NSXRInput::SetParentSpace(NSXRSpace xrSpace) +{ + m_xrSpace = xrSpace; +} + +void +NSXRInput::PrintInfo(void) +{ + string deviceType; + + switch (m_inputType) { + case XR_INPUT_HEAD: + deviceType = "HEAD"; + break; + case XR_INPUT_LEFT: + deviceType = "LEFT"; + break; + case XR_INPUT_RIGHT: + deviceType = "RIGHT"; + break; + default: + print(sprintf("NSXRInput: Cannot run PrintInfo() on unknown type")); + } + + crossprint(sprintf("%s o: %v a: %v v:%v va:%v s:%i w:%i\n", deviceType, GetOrigin(), GetAngles(), GetVelocity(), GetAngularVelocity(), GetStatus(), GetWeapon())); +} + +void +NSXRInput::NSXRInput(void) +{ + print("registered NSXRInput\n"); +} \ No newline at end of file diff --git a/src/xr/NSXRSpace.h b/src/xr/NSXRSpace.h new file mode 100644 index 00000000..2f177b49 --- /dev/null +++ b/src/xr/NSXRSpace.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016-2022 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* class handling the room to world translations for XR */ +class +NSXRSpace +{ + vector m_vecForward; + vector m_vecRight; + vector m_vecUp; + vector m_vecOrigin; + + void(void) NSXRSpace; + + virtual void(vector) SetOrigin; + virtual void(vector) SetAngles; + + virtual vector(void) GetForward; + virtual vector(void) GetRight; + virtual vector(void) GetUp; + + virtual vector(vector) RoomToWorldOrigin; + virtual vector(vector) RoomToWorldAngles; +}; \ No newline at end of file diff --git a/src/xr/NSXRSpace.qc b/src/xr/NSXRSpace.qc new file mode 100644 index 00000000..e6be9d98 --- /dev/null +++ b/src/xr/NSXRSpace.qc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016-2022 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +vector +NSXRSpace::GetForward(void) +{ + return m_vecForward; +} + +vector +NSXRSpace::GetRight(void) +{ + return m_vecRight; +} + +vector +NSXRSpace::GetUp(void) +{ + return m_vecUp; +} + +vector +NSXRSpace::RoomToWorldOrigin(vector vecRoomOrg) +{ + vector vecOut; + vecOut = m_vecOrigin; + vecOut += (m_vecForward * vecRoomOrg[0]); + vecOut -= (m_vecRight * vecRoomOrg[1]); + vecOut += (m_vecUp * vecRoomOrg[2]); + return vecOut; +} + +vector +NSXRSpace::RoomToWorldAngles(vector vecRoomAng) +{ + makevectors(vecRoomAng); + rotatevectorsbyvectors(m_vecForward, m_vecRight, m_vecUp); + return vectoangles(v_forward, v_up); +} + +void +NSXRSpace::SetOrigin(vector vecOrigin) +{ + m_vecOrigin = vecOrigin; +} + +void +NSXRSpace::SetAngles(vector vecAngles) +{ + makevectors(vecAngles); + m_vecForward = v_forward; + m_vecRight = v_right; + m_vecUp = v_up; +} + +void +NSXRSpace::NSXRSpace(void) +{ + print("allocated NSXRSpace\n"); +} \ No newline at end of file diff --git a/src/xr/defs.h b/src/xr/defs.h new file mode 100644 index 00000000..9b9019ec --- /dev/null +++ b/src/xr/defs.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016-2022 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "NSXRSpace.h" +#include "NSXRInput.h" +#include "xr.h" diff --git a/src/xr/include.src b/src/xr/include.src new file mode 100644 index 00000000..c078ec79 --- /dev/null +++ b/src/xr/include.src @@ -0,0 +1,5 @@ +#includelist +../xr/NSXRSpace.qc +../xr/NSXRInput.qc +../xr/xr.qc +#endlist diff --git a/src/xr/xr.h b/src/xr/xr.h new file mode 100644 index 00000000..0c3e26b6 --- /dev/null +++ b/src/xr/xr.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016-2022 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +void XR_Init(entity); +void XR_Shutdown(entity); +bool XR_Available(entity); +void XR_InputFrame(entity); + +#ifdef CLIENT +void XR_UpdateView(entity); +#endif \ No newline at end of file diff --git a/src/xr/xr.qc b/src/xr/xr.qc new file mode 100644 index 00000000..eaa72846 --- /dev/null +++ b/src/xr/xr.qc @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016-2022 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + The engine provides us with 3 devices right now, each giving us + their position, angle etc. as well as field stating which bits + of information have gotten updated. + + If no updates are happening from the HMD/head, that means we're + most like not in VR, or the player has taken the headset off and + laid it down. + + If we have no updates from the left and right XR devices, we + will use the regular input_angles and view position for weapons. +*/ + +void +XR_Init(entity ePlayer) +{ + base_client pl = (base_client)ePlayer; + + print("--------- Initializing XR ----------\n"); + pl.m_xrSpace = spawn(NSXRSpace); + + /* the only 3 devices that matter right now */ + pl.m_xrInputHead = spawn(NSXRInput); + pl.m_xrInputHead.SetType(XR_INPUT_HEAD); + pl.m_xrInputHead.SetParentSpace(pl.m_xrSpace); + pl.m_xrInputLeft = spawn(NSXRInput); + pl.m_xrInputLeft.SetType(XR_INPUT_LEFT); + pl.m_xrInputLeft.SetParentSpace(pl.m_xrSpace); + pl.m_xrInputRight = spawn(NSXRInput); + pl.m_xrInputRight.SetType(XR_INPUT_RIGHT); + pl.m_xrInputRight.SetParentSpace(pl.m_xrSpace); +} + +void +XR_Shutdown(entity ePlayer) +{ + base_client pl = (base_client)ePlayer; + remove(pl.m_xrInputHead); + remove(pl.m_xrInputLeft); + remove(pl.m_xrInputRight); + +} + +#ifdef CLIENT +void +XR_UpdateView(entity ePlayer) +{ + base_client pl = (base_client)ePlayer; + + /* not yet ready */ + if (!pl.m_xrSpace) + return; + + /* update our space */ + pl.m_xrSpace.SetOrigin(pSeat->m_vecPredictedOrigin + pSeat->m_ePlayer.view_ofs); + pl.m_xrSpace.SetAngles(input_angles); + + /* now we get the HMD's org/ang and send that off to the renderer */ + setviewprop(VF_ANGLES, pl.m_xrInputHead.GetAngles()); + setviewprop(VF_ORIGIN, pl.m_xrInputHead.GetOrigin()); +} +#endif + +void +XR_InputFrame(entity ePlayer) +{ + base_client pl = (base_client)ePlayer; + + /* not yet ready */ + if (!pl.m_xrSpace) + return; + + if (autocvar(debug_fakevr, 0)) { + input_head_status = (XR_STATUS_ORG | XR_STATUS_ANG); + input_left_status = (XR_STATUS_ORG | XR_STATUS_ANG); + input_right_status = (XR_STATUS_ORG | XR_STATUS_ANG); + + input_head_angles = [sin(time), sin(time * 1.25) * 5, sin(time * 1.45)]; + input_left_angles = [cos(time) * 5,cos(time) * 25,sin(time) * 5]; + input_right_angles = [cos(time) * 5,cos(time) * 25,sin(time) * 5]; + + input_head_origin = [sin(time)*5,cos(time)*5,sin(time)*5]; + input_left_origin = input_head_origin + [cos(time*8) * 2,4,sin(time*8) * 2]; + input_right_origin = input_head_origin + [cos(time*8) * 2,-4,sin(time*8) * 2]; + } + + /* update the input internals for keeping track*/ + pl.m_xrInputHead.InputFrame(); + pl.m_xrInputLeft.InputFrame(); + pl.m_xrInputRight.InputFrame(); +} + +bool +XR_Available(entity ePlayer) +{ + base_client pl = (base_client)ePlayer; + + /* we only care about the HMD... otherwise why even bother? */ + return pl.m_xrInputHead.IsAvailable(); +} \ No newline at end of file