Use strings for paths;

It's probably slower, but it's way less complicated, so it seems like
a win for now.  Can implement compile-time hashing, tries etc. later
if it's identified as a performance issue for a real person.

Also a bunch of cleanup in openvr.c and oculus.c.
This commit is contained in:
bjorn 2019-04-19 17:33:40 -07:00
parent 45931d005a
commit df5de9a35e
6 changed files with 254 additions and 438 deletions

View File

@ -25,34 +25,6 @@ const char* HeadsetOrigins[] = {
NULL
};
const char* Subpaths[] = {
[P_NONE] = "",
[P_HEAD] = "head",
[P_HAND] = "hand",
[P_EYE] = "eye",
[P_TRACKER] = "tracker",
[P_LEFT] = "left",
[P_RIGHT] = "right",
[P_PROXIMITY] = "proximity",
[P_TRIGGER] = "trigger",
[P_TRACKPAD] = "trackpad",
[P_JOYSTICK] = "joystick",
[P_MENU] = "menu",
[P_GRIP] = "grip",
[P_A] = "a",
[P_B] = "b",
[P_X] = "x",
[P_Y] = "y",
[P_1] = "1",
[P_2] = "2",
[P_3] = "3",
[P_4] = "4",
[P_5] = "5",
[P_6] = "6",
[P_7] = "7",
[P_8] = "8"
};
typedef struct {
lua_State* L;
int ref;
@ -60,42 +32,9 @@ typedef struct {
static HeadsetRenderData headsetRenderData;
Path luax_optpath(lua_State* L, int index, const char* fallback) {
char* str = (char*) luaL_optstring(L, index, fallback);
Path path = { { P_NONE } };
int count = 0;
if (str[0] == '/') {
str++;
}
while (1) {
char* slash = strchr(str, '/');
if (slash) {
*slash = '\0';
}
Subpath subpath = P_NONE;
for (size_t i = 0; i < sizeof(Subpaths) / sizeof(Subpaths[0]); i++) {
if (!strcmp(str, Subpaths[i])) {
subpath = i;
break;
}
}
lovrAssert(subpath != P_NONE, "Unknown path component '%s'", str);
path.p[count++] = subpath;
if (slash) {
*slash = '/';
str = slash + 1;
} else {
break;
}
}
return path;
static const char* luax_optpath(lua_State* L, int index) {
const char* str = luaL_optstring(L, index, "head");
return str[0] == '/' ? ++str : str;
}
static void renderHelper(void* userdata) {
@ -221,7 +160,7 @@ static int l_lovrHeadsetGetBoundsGeometry(lua_State* L) {
}
int l_lovrHeadsetGetPose(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
float x, y, z, angle, ax, ay, az;
FOREACH_TRACKING_DRIVER(driver) {
if (driver->getPose(path, &x, &y, &z, &angle, &ax, &ay, &az)) {
@ -239,7 +178,7 @@ int l_lovrHeadsetGetPose(lua_State* L) {
}
int l_lovrHeadsetGetPosition(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
float x, y, z;
FOREACH_TRACKING_DRIVER(driver) {
if (driver->getPose(path, &x, &y, &z, NULL, NULL, NULL, NULL)) {
@ -253,7 +192,7 @@ int l_lovrHeadsetGetPosition(lua_State* L) {
}
int l_lovrHeadsetGetOrientation(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
float angle, ax, ay, az;
FOREACH_TRACKING_DRIVER(driver) {
if (driver->getPose(path, NULL, NULL, NULL, &angle, &ax, &ay, &az)) {
@ -268,7 +207,7 @@ int l_lovrHeadsetGetOrientation(lua_State* L) {
}
int l_lovrHeadsetGetDirection(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
float angle, ax, ay, az;
FOREACH_TRACKING_DRIVER(driver) {
if (driver->getPose(path, NULL, NULL, NULL, &angle, &ax, &ay, &az)) {
@ -286,7 +225,7 @@ int l_lovrHeadsetGetDirection(lua_State* L) {
}
int l_lovrHeadsetGetVelocity(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
float vx, vy, vz;
FOREACH_TRACKING_DRIVER(driver) {
if (driver->getVelocity(path, &vx, &vy, &vz, NULL, NULL, NULL)) {
@ -300,7 +239,7 @@ int l_lovrHeadsetGetVelocity(lua_State* L) {
}
int l_lovrHeadsetGetAngularVelocity(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
float vax, vay, vaz;
FOREACH_TRACKING_DRIVER(driver) {
if (driver->getVelocity(path, NULL, NULL, NULL, &vax, &vay, &vaz)) {
@ -314,7 +253,7 @@ int l_lovrHeadsetGetAngularVelocity(lua_State* L) {
}
int l_lovrHeadsetIsTracked(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
FOREACH_TRACKING_DRIVER(driver) {
if (driver->getPose(path, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) {
return true;
@ -324,7 +263,7 @@ int l_lovrHeadsetIsTracked(lua_State* L) {
}
int l_lovrHeadsetIsDown(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
bool down;
FOREACH_TRACKING_DRIVER(driver) {
if (driver->isDown(path, &down)) {
@ -336,7 +275,7 @@ int l_lovrHeadsetIsDown(lua_State* L) {
}
int l_lovrHeadsetIsTouched(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
bool touched;
FOREACH_TRACKING_DRIVER(driver) {
if (driver->isDown(path, &touched)) {
@ -348,7 +287,7 @@ int l_lovrHeadsetIsTouched(lua_State* L) {
}
int l_lovrHeadsetGetAxis(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
float x, y, z;
int count;
FOREACH_TRACKING_DRIVER(driver) {
@ -364,7 +303,7 @@ int l_lovrHeadsetGetAxis(lua_State* L) {
}
int l_lovrHeadsetVibrate(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
float strength = luax_optfloat(L, 2, 1.f);
float duration = luax_optfloat(L, 3, .5f);
float frequency = luax_optfloat(L, 4, 0.f);
@ -379,7 +318,7 @@ int l_lovrHeadsetVibrate(lua_State* L) {
}
int l_lovrHeadsetNewModel(lua_State* L) {
Path path = luax_optpath(L, 1, "head");
const char* path = luax_optpath(L, 1);
ModelData* modelData = NULL;
FOREACH_TRACKING_DRIVER(driver) {

View File

@ -74,9 +74,9 @@ static const float* getBoundsGeometry(int* count) {
return NULL;
}
static bool getPose(Path path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
bool head = PATH_EQ(path, P_HEAD);
bool hand = PATH_EQ(path, P_HAND, P_LEFT) || PATH_EQ(path, P_HAND, P_RIGHT);
static bool getPose(const char* path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
bool head = !strcmp(path, "head");
bool hand = !strcmp(path, "hand/left") || !strcmp(path, "hand/right");
if (!head && !hand) {
return false;
@ -97,8 +97,8 @@ static bool getPose(Path path, float* x, float* y, float* z, float* angle, float
return true;
}
static bool getVelocity(Path path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz) {
if (!PATH_EQ(path, P_HEAD)) {
static bool getVelocity(const char* path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz) {
if (strcmp(path, "head")) {
return false;
}
@ -117,8 +117,8 @@ static bool getVelocity(Path path, float* vx, float* vy, float* vz, float* vax,
return true;
}
static bool isDown(Path path, bool* down) {
if (PATH_EQ(path, P_HAND, P_LEFT) || PATH_EQ(path, P_HAND, P_RIGHT)) {
static bool isDown(const char* path, bool* down) {
if (!strcmp(path, "hand/left") || !strcmp(path, "hand/right")) {
*down = lovrPlatformIsMouseDown(MOUSE_RIGHT);
return true;
}
@ -126,19 +126,19 @@ static bool isDown(Path path, bool* down) {
return false;
}
static bool isTouched(Path path, bool* touched) {
static bool isTouched(const char* path, bool* touched) {
return false;
}
static int getAxis(Path path, float* x, float* y, float* z) {
static int getAxis(const char* path, float* x, float* y, float* z) {
return 0;
}
static bool vibrate(Path path, float strength, float duration, float frequency) {
static bool vibrate(const char* path, float strength, float duration, float frequency) {
return false;
}
static ModelData* newModelData(Path path) {
static ModelData* newModelData(const char* path) {
return NULL;
}

View File

@ -21,43 +21,6 @@ typedef enum {
DRIVER_WEBVR
} HeadsetDriver;
typedef enum {
P_NONE,
P_HEAD,
P_HAND,
P_EYE,
P_TRACKER,
P_LEFT,
P_RIGHT,
P_PROXIMITY,
P_TRIGGER,
P_TRACKPAD,
P_JOYSTICK,
P_MENU,
P_GRIP,
P_A,
P_B,
P_X,
P_Y,
P_1,
P_2,
P_3,
P_4,
P_5,
P_6,
P_7,
P_8
} Subpath;
typedef union {
uint8_t p[8];
uint64_t u64;
} Path;
#define MAKE_PATH(...) ((Path) { { __VA_ARGS__ } })
#define PATH_EQ(p, ...) ((p).u64 == MAKE_PATH(__VA_ARGS__).u64)
#define PATH_STARTS_WITH(p, ...) ((MAKE_PATH(__VA_ARGS__).u64 ^ p.u64 & MAKE_PATH(__VA_ARGS__).u64) == 0)
typedef struct HeadsetInterface {
struct HeadsetInterface* next;
HeadsetDriver driverType;
@ -70,13 +33,13 @@ typedef struct HeadsetInterface {
void (*setClipDistance)(float clipNear, float clipFar);
void (*getBoundsDimensions)(float* width, float* depth);
const float* (*getBoundsGeometry)(int* count);
bool (*getPose)(Path path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az);
bool (*getVelocity)(Path path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz);
bool (*isDown)(Path path, bool* down);
bool (*isTouched)(Path path, bool* touched);
int (*getAxis)(Path path, float* x, float* y, float* z);
bool (*vibrate)(Path path, float strength, float duration, float frequency);
struct ModelData* (*newModelData)(Path path);
bool (*getPose)(const char* path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az);
bool (*getVelocity)(const char* path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz);
bool (*isDown)(const char* path, bool* down);
bool (*isTouched)(const char* path, bool* touched);
int (*getAxis)(const char* path, float* x, float* y, float* z);
bool (*vibrate)(const char* path, float strength, float duration, float frequency);
struct ModelData* (*newModelData)(const char* path);
void (*renderTo)(void (*callback)(void*), void* userdata);
struct Texture* (*getMirrorTexture)(void);
void (*update)(float dt);

View File

@ -159,14 +159,16 @@ static const float* getBoundsGeometry(int* count) {
return NULL;
}
static bool getPose(Path path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
static bool getPose(const char* path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
ovrTrackingState *ts = refreshTracking();
ovrPosef* pose;
if (PATH_EQ(path, P_HEAD)) {
if (!strcmp(path, "head")) {
pose = &ts->HeadPose.ThePose;
} else if (PATH_STARTS_WITH(path, P_HAND) && (path.p[1] == P_LEFT || path.p[1] == P_RIGHT)) {
pose = &ts->HandPoses[path.p[1] - P_LEFT].ThePose;
} else if (!strcmp(path, "hand/left")) {
pose = &ts->HandPoses[0].ThePose;
} else if (!strcmp(path, "hand/right")) {
pose = &ts->HandPoses[1].ThePose;
} else {
return false;
}
@ -185,14 +187,16 @@ static bool getPose(Path path, float* x, float* y, float* z, float* angle, float
return true;
}
static bool getVelocity(Path path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz) {
static bool getVelocity(const char* path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz) {
ovrTrackingState *ts = refreshTracking();
ovrPosef* pose;
ovrPoseStatef* pose;
if (PATH_EQ(path, P_HEAD)) {
velocity = &ts->HeadPose;
} else if (PATH_STARTS_WITH(path, P_HAND) && (path.p[1] == P_LEFT || path.p[1] == P_RIGHT)) {
velocity = &ts->HandPoses[path.p[1] - P_LEFT];
if (!strcmp(path, "head")) {
pose = &ts->HeadPose;
} else if (!strcmp(path, "hand/left")) {
pose = &ts->HandPoses[ovrHand_Left];
} else if (!strcmp(path, "hand/right")) {
pose = &ts->HandPoses[ovrHand_Right];
} else {
return false;
}
@ -212,87 +216,86 @@ static bool getVelocity(Path path, float* vx, float* vy, float* vz, float* vax,
return true;
}
static bool isDown(Path path, bool* down) {
if (PATH_EQ(path, P_HEAD, P_PROXIMITY)) {
static bool getHandInfo(const char* path, ovrHandType* hand, uint32_t* mask, const char** next) {
if (!strncmp("hand/left", path, strlen("hand/left"))) {
*hand = ovrHand_Left;
*mask = ovrButton_LMask;
*next = path + strlen("hand/left/");
return true;
} else if (!strncmp("hand/right", path, strlen("hand/right"))) {
*hand = ovrHand_Right;
*mask = ovrButton_RMask;
*next = path + strlen("hand/right/");
return true;
} else {
return false;
}
}
static bool isDown(const char* path, bool* down) {
if (!strcmp(path, "head/proximity")) {
ovrSessionStatus status;
ovr_GetSessionStatus(state.session, &status);
*down = status.HmdMounted;
return true;
}
// Make sure the path starts with /hand/left or /hand/right and only has 3 pieces
if (path.p[0] != P_HAND || (path.p[1] != P_LEFT && path.p[1] != P_RIGHT) || path.p[3] != P_NONE) {
return false;
}
ovrHandType hand;
uint32_t mask;
const char* button;
ovrHandType hand = path.p[1] - P_LEFT;
ovrInputState* is = refreshButtons();
uint32_t mask = is->Buttons & (hand == ovrHand_Left ? ovrButton_LMask : ovrButton_RMask);
switch (path.p[2]) {
case P_A: *down = (mask & ovrButton_A); return true;
case P_B: *down = (mask & ovrButton_B); return true;
case P_X: *down = (mask & ovrButton_X); return true;
case P_Y: *down = (mask & ovrButton_Y); return true;
case P_MENU: *down = (mask & ovrButton_Enter); return true;
case P_TRIGGER: *down = (is->IndexTriggerNoDeadzone[hand] > 0.5f); return true;
case P_JOYSTICK: *down = (mask & (ovrButton_LThumb | ovrButton_RThumb)); return true;
case P_GRIP: *down = (is->HandTrigger[hand] > 0.9f); return true;
if (getHandInfo(path, &hand, &mask, &button)) {
ovrInputState* is = refreshButtons();
if (!strcmp(path, "a")) { return *down = (mask & ovrButton_A), true; }
else if (!strcmp(path, "b")) { return *down = (mask & ovrButton_B), true; }
else if (!strcmp(path, "x")) { return *down = (mask & ovrButton_X), true; }
else if (!strcmp(path, "y")) { return *down = (mask & ovrButton_Y), true; }
else if (!strcmp(path, "menu")) { return *down = (mask & ovrButton_Enter), true; }
else if (!strcmp(path, "trigger")) { return *down = (is->IndexTriggerNoDeadzone[hand] > .5f), true; }
else if (!strcmp(path, "joystick")) { return *down = (mask & (ovrButton_LThumb | ovrButton_RThumb)), true; }
else if (!strcmp(path, "grip")) { return *down = (is->HandTrigger[hand] > .9f), true; }
}
return false;
}
static bool isTouched(Path path, bool* touched) {
static bool isTouched(const char* path, bool* touched) {
ovrHandType hand;
uint32_t mask;
const char* button;
// Make sure the path starts with /hand/left or /hand/right and only has 3 pieces
if (path.p[0] != P_HAND || (path.p[1] != P_LEFT && path.p[1] != P_RIGHT) || path.p[3] != P_NONE) {
return false;
}
ovrHandType hand = path.p[1] - P_LEFT;
ovrInputState* is = refreshButtons();
uint32_t mask = is->Buttons & (hand == ovrHand_Left ? ovrButton_LMask : ovrButton_RMask);
switch (path.p[2]) {
case P_A: *touched = (mask & ovrTouch_A); return true;
case P_B: *touched = (mask & ovrTouch_B); return true;
case P_X: *touched = (mask & ovrTouch_X); return true;
case P_Y: *touched = (mask & ovrTouch_Y); return true;
case P_TRIGGER: *touched = (mask & (ovrTouch_LIndexTrigger | ovrTouch_RIndexTrigger)); return true;
case P_JOYSTICK: *touched = (mask & (ovrTouch_LThumb | ovrTouch_RThumb)); return true;
if (getHandInfo(path, &hand, &mask, &button)) {
if (!strcmp(path, "a")) { return *touched = (mask & ovrTouch_A), true; }
else if (!strcmp(path, "b")) { return *touched = (mask & ovrTouch_B), true; }
else if (!strcmp(path, "x")) { return *touched = (mask & ovrTouch_X), true; }
else if (!strcmp(path, "y")) { return *touched = (mask & ovrTouch_Y), true; }
else if (!strcmp(path, "trigger")) { return *touched = (mask & (ovrTouch_LIndexTrigger | ovrTouch_RIndexTrigger)), true; }
else if (!strcmp(path, "joystick")) { return *touched = (mask & (ovrTouch_LThumb | ovrTouch_RThumb)), true; }
}
return false;
}
static int getAxis(Path path, float* x, float* y, float* z) {
static int getAxis(const char* path, float* x, float* y, float* z) {
ovrHandType hand;
uint32_t mask;
const char* button;
// Make sure the path starts with /hand/left or /hand/right and only has 3 pieces
if (path.p[0] != P_HAND || (path.p[1] != P_LEFT && path.p[1] != P_RIGHT) || path.p[3] != P_NONE) {
return false;
}
ovrInputState *is = refreshButtons();
ovrHandType hand = path.p[1] - P_LEFT;
switch (path.p[2]) {
case P_GRIP: *x = is->HandTriggerNoDeadzone[hand]; return 1;
case P_TRIGGER: *x = is->IndexTriggerNoDeadzone[hand]; return 1;
case P_JOYSTICK:
*x = is->ThumbstickNoDeadzone[hand].x;
*y = is->ThumbstickNoDeadzone[hand].y;
return 2;
if (getHandInfo(path, &hand, &mask, &button)) {
ovrInputState* is = refreshButtons();
if (!strcmp(path, "grip")) { return *x = is->HandTriggerNoDeadzone[hand], 1; }
if (!strcmp(path, "trigger")) { return *x = is->IndexTriggerNoDeadzone[hand], 1; }
if (!strcmp(path, "joystick")) { return *x = is->ThumbstickNoDeadzone[hand].x, *y = is->ThumbstickNoDeadzone[hand].y, 2; }
}
return 0;
}
static bool vibrate(Path path, float strength, float duration, float frequency) {
static bool vibrate(const char* path, float strength, float duration, float frequency) {
return false; // TODO
}
static ModelData* newModelData(Path path) {
static ModelData* newModelData(const char* path) {
return NULL; // TODO
}

View File

@ -74,12 +74,12 @@ static const float* getBoundsGeometry(int* count) {
return NULL;
}
static bool getPose(Path path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
static bool getPose(const char* path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
BridgeLovrPose* pose;
if (PATH_EQ(path, P_HEAD)) {
if (!strcmp(path, "head")) {
pose = &bridgeLovrMobileData.updateData.lastHeadPose;
} else if (PATH_EQ(path, P_HAND)) {
} else if (!strcmp(path, "hand")) {
pose = &bridgeLovrMobileData.updateData.goPose;
} else {
return false;
@ -98,12 +98,12 @@ static bool getPose(Path path, float* x, float* y, float* z, float* angle, float
return true;
}
static bool getVelocity(Path path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz) {
static bool getVelocity(const char* path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz) {
BridgeLovrVel* velocity;
if (PATH_EQ(path, P_HEAD)) {
if (!strcmp(path, "head")) {
velocity = &bridgeLovrMobileData.updateData.lastHeadVelocity;
} else if (PATH_EQ(path, P_HAND)) {
} else if (!strcmp(path, "hand")) {
velocity = &bridgeLovrMobileData.updateData.goVelocity;
} else {
return false;
@ -124,50 +124,46 @@ static bool getVelocity(Path path, float* vx, float* vy, float* vz, float* vax,
return true;
}
static bool buttonCheck(BridgeLovrButton field, Path path, bool* result) {
if (!PATH_EQ(path, P_HAND) || path.p[2] != P_NONE) {
return false; // Path needs to start with /hand and have exactly one more piece
static bool buttonCheck(BridgeLovrButton field, const char* path, bool* result) {
if (!strcmp("hand", path, strlen("hand"))) {
path += strlen("hand/");
if (!strcmp(path, "menu")) { return *result = (field & BRIDGE_LOVR_BUTTON_MENU), true; }
else if (!strcmp(path, "trigger")) { return *result = (field & BRIDGE_LOVR_BUTTON_SHOULDER), true; }
else if (!strcmp(path, "trackpad")) { return *result = (field & BRIDGE_LOVR_BUTTON_TOUCHPAD), true; }
}
switch (path.p[1]) {
case P_MENU: *result = (field & BRIDGE_LOVR_BUTTON_MENU); return true;
case P_TRIGGER: *result = (field & BRIDGE_LOVR_BUTTON_SHOULDER); return true;
case P_TRACKPAD: *result = (field & BRIDGE_LOVR_BUTTON_TOUCHPAD); return true;
default: return false;
}
}
static bool isDown(Path path, bool* down) {
return buttonCheck(bridgeLovrMobileData.updateData.goButtonDown, path, down);
}
static bool isTouched(Path path, bool* touched) {
return buttonCheck(bridgeLovrMobileData.updateData.goButtonTouch, path, touched);
}
static int getAxis(Path path, float* x, float* y, float* z) {
if (!PATH_EQ(path, P_HAND) || path.p[2] != P_NONE) {
return 0; // Path needs to start with /hand and have exactly one more piece
}
switch (path.p[1]) {
case P_TRACKPAD:
*x = (bridgeLovrMobileData.updateData.goTrackpad.x - 160.f) / 160.f;
*y = (bridgeLovrMobileData.updateData.goTrackpad.y - 160.f) / 160.f;
return 2;
case P_TRIGGER:
*x = bridgeLovrMobileData.updateData.goButtonDown ? 1.f : 0.f;
return 1;
default:
return 0;
}
}
static bool vibrate(Path path, float strength, float duration, float frequency) {
return false;
}
static ModelData* newModelData(Path path) {
static bool isDown(const char* path, bool* down) {
return buttonCheck(bridgeLovrMobileData.updateData.goButtonDown, path, down);
}
static bool isTouched(const char* path, bool* touched) {
return buttonCheck(bridgeLovrMobileData.updateData.goButtonTouch, path, touched);
}
static int getAxis(const char* path, float* x, float* y, float* z) {
if (!strcmp("hand", path, strlen("hand"))) {
path += strlen("hand/");
if (!strcmp(path, "trackpad")) {
*x = (bridgeLovrMobileData.updateData.goTrackpad.x - 160.f) / 160.f;
*y = (bridgeLovrMobileData.updateData.goTrackpad.y - 160.f) / 160.f;
return 2;
} else if (!strcmp(path, "trigger")) {
*x = bridgeLovrMobileData.updateData.goButtonDown ? 1.f : 0.f;
return 1;
}
}
return 0;
}
static bool vibrate(const char* path, float strength, float duration, float frequency) {
return false;
}
static ModelData* newModelData(const char* path) {
return NULL;
}

View File

@ -23,8 +23,8 @@ extern void VR_ShutdownInternal();
extern bool VR_IsHmdPresent();
extern intptr_t VR_GetGenericInterface(const char* pchInterfaceVersion, EVRInitError* peError);
extern bool VR_IsRuntimeInstalled();
#define HEADSET_INDEX k_unTrackedDeviceIndex_Hmd
#define INVALID_INDEX k_unTrackedDeviceIndexInvalid
#define HEADSET k_unTrackedDeviceIndex_Hmd
#define INVALID_DEVICE k_unTrackedDeviceIndexInvalid
static struct {
struct VR_IVRSystem_FnTable* system;
@ -43,111 +43,24 @@ static struct {
int msaa;
} state;
static bool getTransform(unsigned int device, mat4 transform) {
TrackedDevicePose_t pose = state.poses[device];
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
return false;
} else {
mat4_fromMat34(transform, pose.mDeviceToAbsoluteTracking.m);
transform[13] += state.offset;
return true;
}
}
static TrackedDeviceIndex_t getDeviceIndexForPath(Path path) {
if (PATH_EQ(path, P_HEAD)) {
return HEADSET_INDEX;
} else if (PATH_EQ(path, P_HAND, P_LEFT)) {
static TrackedDeviceIndex_t pathToDevice(const char* path, const char** next) {
if (!strcmp(path, "head")) {
if (next) *next = path + strlen("head/");
return HEADSET;
} else if (!strcmp(path, "hand/left")) {
if (next) *next = path + strlen("hand/left/");
return state.system->GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole_TrackedControllerRole_LeftHand);
} else if (PATH_EQ(path, P_HAND, P_RIGHT)) {
} else if (!strcmp(path, "hand/right")) {
if (next) *next = path + strlen("hand/right/");
return state.system->GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole_TrackedControllerRole_RightHand);
} else if (path.p[0] == P_TRACKER && path.p[1] >= P_1 && path.p[1] <= P_8 && path.p[2] == P_NONE) {
} else if (!strncmp("tracker/", path, strlen("tracker/"))) {
path += strlen("tracker/");
uint32_t index = (path[0] - '0') - 1;
TrackedDeviceIndex_t indices[8];
uint32_t trackerCount = state.system->GetSortedTrackedDeviceIndicesOfClass(ETrackedDeviceClass_TrackedDeviceClass_GenericTracker, indices, 8, 0);
uint32_t index = path.p[1] - P_1;
return index < trackerCount ? indices[index] : k_unTrackedDeviceIndexInvalid;
return (index >= 0 && index < trackerCount) ? indices[index] : INVALID_DEVICE;
} else {
return k_unTrackedDeviceIndexInvalid;
}
}
static bool getButtonState(Path path, bool touch, bool* value) {
VRControllerState_t input;
if (PATH_EQ(path, P_HEAD, P_PROXIMITY) && !touch) {
if (!state.system->GetControllerState(HEADSET_INDEX, &input, sizeof(input))) {
return false;
}
*value = (input.ulButtonPressed >> EVRButtonId_k_EButton_ProximitySensor) & 1;
return true;
} else if (!PATH_STARTS_WITH(path, P_HAND, P_LEFT) && !PATH_STARTS_WITH(path, P_HAND, P_RIGHT)) {
return false;
}
TrackedDeviceIndex_t deviceIndex = getDeviceIndexForPath(path);
if (deviceIndex == INVALID_INDEX) {
return false;
}
if (!state.system->GetControllerState(deviceIndex, &input, sizeof(input))) {
return false;
}
uint64_t mask = touch ? input.ulButtonTouched : input.ulButtonPressed;
if (state.rift) {
switch (path.p[2]) {
case P_TRIGGER:
*value = (mask >> EVRButtonId_k_EButton_Axis1) & 1;
return true;
case P_GRIP:
*value = (mask >> EVRButtonId_k_EButton_Axis2) & 1;
return true;
case P_TRACKPAD:
*value = (mask >> EVRButtonId_k_EButton_Axis0) & 1;
return true;
case P_A:
*value = path.p[1] == P_RIGHT && (mask >> EVRButtonId_k_EButton_A) & 1;
return true;
case P_B:
*value = path.p[1] == P_RIGHT && (mask >> EVRButtonId_k_EButton_ApplicationMenu) & 1;
return true;
case P_X:
*value = path.p[1] == P_LEFT && (mask >> EVRButtonId_k_EButton_A) & 1;
return true;
case P_Y:
*value = path.p[1] == P_LEFT && (mask >> EVRButtonId_k_EButton_ApplicationMenu) & 1;
return true;
default: return false;
}
} else {
switch (path.p[2]) {
case P_TRIGGER:
*value = (mask >> EVRButtonId_k_EButton_SteamVR_Trigger) & 1;
return true;
case P_TRACKPAD:
*value = (mask >> EVRButtonId_k_EButton_SteamVR_Touchpad) & 1;
return true;
case P_MENU:
*value = (mask >> EVRButtonId_k_EButton_ApplicationMenu) & 1;
return true;
case P_GRIP:
*value = (mask >> EVRButtonId_k_EButton_Grip) & 1;
return true;
default: return false;
}
return INVALID_DEVICE;
}
}
@ -204,7 +117,7 @@ static void destroy(void) {
static bool getName(char* name, size_t length) {
ETrackedPropertyError error;
state.system->GetStringTrackedDeviceProperty(HEADSET_INDEX, ETrackedDeviceProperty_Prop_ManufacturerName_String, name, length, &error);
state.system->GetStringTrackedDeviceProperty(HEADSET, ETrackedDeviceProperty_Prop_ManufacturerName_String, name, length, &error);
return error == ETrackedPropertyError_TrackedProp_Success;
}
@ -252,135 +165,137 @@ static const float* getBoundsGeometry(int* count) {
return NULL;
}
static bool getPose(Path path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
TrackedDeviceIndex_t deviceIndex = getDeviceIndexForPath(path);
float transform[16];
if (deviceIndex != INVALID_INDEX && getTransform(deviceIndex, transform)) {
mat4_getTransform(transform, x, y, z, NULL, NULL, NULL, angle, ax, ay, az);
static bool getTransform(unsigned int device, mat4 transform) {
TrackedDevicePose_t pose = state.poses[device];
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
return false;
} else {
mat4_fromMat34(transform, pose.mDeviceToAbsoluteTracking.m);
transform[13] += state.offset;
return true;
}
}
static bool getPose(const char* path, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
float transform[16];
TrackedDeviceIndex_t device = pathToDevice(path, NULL);
if (device == INVALID_DEVICE && !getTransform(device, transform)) {
return false;
}
mat4_getTransform(transform, x, y, z, NULL, NULL, NULL, angle, ax, ay, az);
return true;
}
static bool getVelocity(const char* path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz) {
TrackedDeviceIndex_t device = pathToDevice(path, NULL);
TrackedDevicePose_t* pose = &state.poses[device];
if (device == INVALID_DEVICE || !pose->bPoseIsValid || !pose->bDeviceIsConnected) {
return false;
}
if (vx) {
*vx = pose->vVelocity.v[0];
*vy = pose->vVelocity.v[1];
*vz = pose->vVelocity.v[2];
}
if (vax) {
*vax = pose->vAngularVelocity.v[0];
*vay = pose->vAngularVelocity.v[1];
*vaz = pose->vAngularVelocity.v[2];
}
return true;
}
static bool getButtonState(const char* path, bool touch, bool* value) {
VRControllerState_t input;
if (!strcmp(path, "head/proximity") && !touch) {
if (!state.system->GetControllerState(HEADSET, &input, sizeof(input))) {
return false;
}
return *value = (input.ulButtonPressed >> EVRButtonId_k_EButton_ProximitySensor) & 1, true;
}
const char* button;
TrackedDeviceIndex_t device = pathToDevice(path, &button);
if (device != INVALID_DEVICE || state.system->GetControllerState(device, &input, sizeof(input))) {
uint64_t mask = touch ? input.ulButtonTouched : input.ulButtonPressed;
if (state.rift) {
if (!strcmp(button, "trigger")) { return *value = (mask >> EVRButtonId_k_EButton_Axis1) & 1, true; }
else if (!strcmp(button, "grip")) { return *value = (mask >> EVRButtonId_k_EButton_Axis2) & 1, true; }
else if (!strcmp(button, "trackpad")) { return *value = (mask >> EVRButtonId_k_EButton_Axis0) & 1, true; }
else if (!strcmp(path, "hand/right/a") || !strcmp(path, "hand/left/x")) { return *value = (mask >> EVRButtonId_k_EButton_A) & 1, true; }
else if (!strcmp(path, "hand/right/b") || !strcmp(path, "hand/left/y")) { return *value = (mask >> EVRButtonId_k_EButton_ApplicationMenu) & 1, true; }
} else {
if (!strcmp(button, "trigger")) { return *value = (mask >> EVRButtonId_k_EButton_SteamVR_Trigger) & 1, true; }
else if (!strcmp(button, "trackpad")) { return *value = (mask >> EVRButtonId_k_EButton_SteamVR_Touchpad) & 1, true; }
else if (!strcmp(button, "menu")) { return *value = (mask >> EVRButtonId_k_EButton_ApplicationMenu) & 1, true; }
else if (!strcmp(button, "grip")) { return *value = (mask >> EVRButtonId_k_EButton_Grip) & 1, true; }
}
}
return false;
}
static bool getVelocity(Path path, float* vx, float* vy, float* vz, float* vax, float* vay, float* vaz) {
TrackedDeviceIndex_t deviceIndex = getDeviceIndexForPath(path);
if (deviceIndex == INVALID_INDEX) {
return false;
}
TrackedDevicePose_t* pose = &state.poses[deviceIndex];
if (!pose->bPoseIsValid || !pose->bDeviceIsConnected) {
return false;
} else {
if (vx) {
*vx = pose->vVelocity.v[0];
*vy = pose->vVelocity.v[1];
*vz = pose->vVelocity.v[2];
}
if (vax) {
*vax = pose->vAngularVelocity.v[0];
*vay = pose->vAngularVelocity.v[1];
*vaz = pose->vAngularVelocity.v[2];
}
return true;
}
}
static bool isDown(Path path, bool* down) {
static bool isDown(const char* path, bool* down) {
return getButtonState(path, false, down);
}
static bool isTouched(Path path, bool* touched) {
static bool isTouched(const char* path, bool* touched) {
return getButtonState(path, true, touched);
}
static int getAxis(Path path, float* x, float* y, float* z) {
if (path.p[3] != P_NONE) {
return 0;
}
TrackedDeviceIndex_t deviceIndex = getDeviceIndexForPath(path);
if (deviceIndex == INVALID_INDEX) {
return 0;
}
static int getAxis(const char* path, float* x, float* y, float* z) {
const char* axis;
TrackedDeviceIndex_t device = pathToDevice(path, &axis);
VRControllerState_t input;
if (!state.system->GetControllerState(deviceIndex, &input, sizeof(input))) {
return 0;
}
if (state.rift) {
switch (path.p[2]) {
case P_TRIGGER:
*x = input.rAxis[1].x;
return 1;
case P_GRIP:
*x = input.rAxis[2].x;
return 1;
case P_TRACKPAD:
*x = input.rAxis[0].x;
*y = input.rAxis[0].y;
return 2;
default: return 0;
}
} else {
switch (path.p[2]) {
case P_TRIGGER:
*x = input.rAxis[1].x;
return 1;
case P_TRACKPAD:
*x = input.rAxis[0].x;
*y = input.rAxis[0].y;
return 2;
default: return 0;
}
if (device != INVALID_DEVICE || state.system->GetControllerState(device, &input, sizeof(input))) {
if (!strcmp(axis, "trigger")) { return *x = input.rAxis[1].x, 1; }
else if (state.rift && !strcmp(axis, "grip")) { return *x = input.rAxis[2].x, 1; }
else if (!strcmp(axis, "trackpad")) { return *x = input.rAxis[0].x, *y = input.rAxis[0].y, 2; }
}
return 0;
}
static bool vibrate(Path path, float strength, float duration, float frequency) {
static bool vibrate(const char* path, float strength, float duration, float frequency) {
if (duration <= 0) return false;
if (!PATH_STARTS_WITH(path, P_HAND)) return false;
TrackedDeviceIndex_t deviceIndex = getDeviceIndexForPath(path);
if (deviceIndex == INVALID_INDEX) return false;
TrackedDeviceIndex_t device = pathToDevice(path, NULL);
if (device == INVALID_DEVICE) return false;
unsigned short uSeconds = (unsigned short) (duration * 1e6f);
state.system->TriggerHapticPulse(deviceIndex, 0, uSeconds);
unsigned short uSeconds = (unsigned short) (duration * 1e6f + .5f);
state.system->TriggerHapticPulse(device, 0, uSeconds);
return true;
}
static ModelData* newModelData(Path path) {
TrackedDeviceIndex_t deviceIndex = getDeviceIndexForPath(path);
if (deviceIndex == INVALID_INDEX) return false;
static ModelData* newModelData(const char* path) {
TrackedDeviceIndex_t device = pathToDevice(path, NULL);
if (device == INVALID_DEVICE) return false;
// Get model name
char renderModelName[1024];
ETrackedDeviceProperty renderModelNameProperty = ETrackedDeviceProperty_Prop_RenderModelName_String;
state.system->GetStringTrackedDeviceProperty(deviceIndex, renderModelNameProperty, renderModelName, 1024, NULL);
state.system->GetStringTrackedDeviceProperty(device, renderModelNameProperty, renderModelName, 1024, NULL);
// Load model
if (!state.deviceModels[deviceIndex]) {
while (state.renderModels->LoadRenderModel_Async(renderModelName, &state.deviceModels[deviceIndex]) == EVRRenderModelError_VRRenderModelError_Loading) {
if (!state.deviceModels[device]) {
while (state.renderModels->LoadRenderModel_Async(renderModelName, &state.deviceModels[device]) == EVRRenderModelError_VRRenderModelError_Loading) {
lovrSleep(.001);
}
}
// Load texture
if (!state.deviceTextures[deviceIndex]) {
while (state.renderModels->LoadTexture_Async(state.deviceModels[deviceIndex]->diffuseTextureId, &state.deviceTextures[deviceIndex]) == EVRRenderModelError_VRRenderModelError_Loading) {
if (!state.deviceTextures[device]) {
while (state.renderModels->LoadTexture_Async(state.deviceModels[device]->diffuseTextureId, &state.deviceTextures[device]) == EVRRenderModelError_VRRenderModelError_Loading) {
lovrSleep(.001);
}
}
RenderModel_t* vrModel = state.deviceModels[deviceIndex];
RenderModel_t* vrModel = state.deviceModels[device];
ModelData* model = lovrAlloc(ModelData);
size_t vertexSize = sizeof(RenderModel_Vertex_t);
@ -436,7 +351,7 @@ static ModelData* newModelData(Path path) {
.components = 1
};
RenderModel_TextureMap_t* vrTexture = state.deviceTextures[deviceIndex];
RenderModel_TextureMap_t* vrTexture = state.deviceTextures[device];
model->textures[0] = lovrTextureDataCreate(vrTexture->unWidth, vrTexture->unHeight, 0, FORMAT_RGBA);
memcpy(model->textures[0]->blob.data, vrTexture->rubTextureMapData, vrTexture->unWidth * vrTexture->unHeight * 4);
@ -482,7 +397,7 @@ static void renderTo(void (*callback)(void*), void* userdata) {
Camera camera = { .canvas = state.canvas, .viewMatrix = { MAT4_IDENTITY, MAT4_IDENTITY } };
float head[16], eye[16];
getTransform(HEADSET_INDEX, head);
getTransform(HEADSET, head);
for (int i = 0; i < 2; i++) {
EVREye vrEye = (i == 0) ? EVREye_Eye_Left : EVREye_Eye_Right;