mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 15:00:27 +02:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
827eb0fc1d | ||
|
|
a482a5f5bb | ||
|
|
81f321f959 | ||
|
|
f97ff9219f | ||
|
|
85e79a067a | ||
|
|
effeda1b7c | ||
|
|
6299503191 | ||
|
|
7242151017 | ||
|
|
4b8f8dde8b |
No files matched your search
@@ -794,6 +794,12 @@ the eyes reads it. Shown only while it is. */
|
||||
|
||||
#define WRIST_IMAGE_SIZE 512
|
||||
#define CROSSHAIR_IMAGE_SIZE 256
|
||||
/* the names layer: HALO_XR_MAXIMUM_NAMES slots of 4:1, one over another */
|
||||
#define NAMES_IMAGE_WIDTH 512
|
||||
#define NAMES_IMAGE_HEIGHT (NAMES_IMAGE_WIDTH / 4 * HALO_XR_MAXIMUM_NAMES)
|
||||
/* a name's slot, as the game draws it: wider than its image's 4:1 (the
|
||||
game's 640x480 drawn square): the height a slot shows at, to its width */
|
||||
#define NAME_SLOT_ASPECT (30.0f / 160.0f)
|
||||
#define WRIST_BEHIND_PALM 0.05f
|
||||
#define WRIST_DOWN_HANDLE 0.02f
|
||||
#define WRIST_ABOVE_HAND 0.04f
|
||||
@@ -1032,8 +1038,15 @@ int host_xr_initialize(struct halo_xr_info *info, float wanted_refresh_rate)
|
||||
{
|
||||
int size = layer == HALO_XR_LAYER_WRIST || layer == HALO_XR_LAYER_SCOPE ? WRIST_IMAGE_SIZE :
|
||||
layer == HALO_XR_LAYER_CROSSHAIR ? CROSSHAIR_IMAGE_SIZE : 0;
|
||||
int width = size ? size : xr.eye_width;
|
||||
int height = size ? size : xr.eye_height;
|
||||
|
||||
if (!swapchain_create(&xr.swapchains[layer], size ? size : xr.eye_width, size ? size : xr.eye_height))
|
||||
if (layer == HALO_XR_LAYER_NAMES)
|
||||
{
|
||||
width = NAMES_IMAGE_WIDTH;
|
||||
height = NAMES_IMAGE_HEIGHT;
|
||||
}
|
||||
if (!swapchain_create(&xr.swapchains[layer], width, height))
|
||||
return 0;
|
||||
}
|
||||
if (!copy_initialize() || !actions_initialize())
|
||||
@@ -1354,7 +1367,8 @@ int host_xr_end_frame(const struct halo_xr_submit *submit)
|
||||
XrCompositionLayerQuad wrist = { XR_TYPE_COMPOSITION_LAYER_QUAD };
|
||||
XrCompositionLayerQuad scope = { XR_TYPE_COMPOSITION_LAYER_QUAD };
|
||||
XrCompositionLayerQuad crosshair = { XR_TYPE_COMPOSITION_LAYER_QUAD };
|
||||
const XrCompositionLayerBaseHeader *layers[5];
|
||||
XrCompositionLayerQuad names[HALO_XR_MAXIMUM_NAMES];
|
||||
const XrCompositionLayerBaseHeader *layers[5 + HALO_XR_MAXIMUM_NAMES];
|
||||
uint32_t layer_count = 0;
|
||||
int eye;
|
||||
|
||||
@@ -1458,6 +1472,34 @@ int host_xr_end_frame(const struct halo_xr_submit *submit)
|
||||
layers[layer_count++] = (const XrCompositionLayerBaseHeader *)&crosshair;
|
||||
}
|
||||
|
||||
if (xr.frame_state.shouldRender && submit->name_count > 0 && xr.swapchains[HALO_XR_LAYER_NAMES].filled)
|
||||
{
|
||||
struct xr_swapchain *swapchain = &xr.swapchains[HALO_XR_LAYER_NAMES];
|
||||
int slot_height = swapchain->height / HALO_XR_MAXIMUM_NAMES;
|
||||
int name;
|
||||
|
||||
for (name = 0; name < submit->name_count && name < HALO_XR_MAXIMUM_NAMES; name++)
|
||||
{
|
||||
XrCompositionLayerQuad *quad_name = &names[name];
|
||||
|
||||
memset(quad_name, 0, sizeof(*quad_name));
|
||||
quad_name->type = XR_TYPE_COMPOSITION_LAYER_QUAD;
|
||||
quad_name->layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
||||
quad_name->space = xr.local_space;
|
||||
quad_name->eyeVisibility = XR_EYE_VISIBILITY_BOTH;
|
||||
quad_name->subImage.swapchain = swapchain->handle;
|
||||
/* (slot 0 at the image's top: GL's rows run bottom up) */
|
||||
quad_name->subImage.imageRect.offset.x = 0;
|
||||
quad_name->subImage.imageRect.offset.y = swapchain->height - (name + 1) * slot_height;
|
||||
quad_name->subImage.imageRect.extent.width = swapchain->width;
|
||||
quad_name->subImage.imageRect.extent.height = slot_height;
|
||||
quad_name->size.width = submit->name_widths[name];
|
||||
quad_name->size.height = submit->name_widths[name] * NAME_SLOT_ASPECT;
|
||||
pose_to_xr(&quad_name->pose, &submit->name_poses[name]);
|
||||
layers[layer_count++] = (const XrCompositionLayerBaseHeader *)quad_name;
|
||||
}
|
||||
}
|
||||
|
||||
end.displayTime = xr.frame_state.predictedDisplayTime;
|
||||
end.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
||||
end.layerCount = layer_count;
|
||||
|
||||
@@ -27,7 +27,10 @@ enum
|
||||
HALO_XR_LAYER_WRIST = 3, /* the motion tracker, on the left wrist */
|
||||
HALO_XR_LAYER_SCOPE = 4, /* the zoomed view, a disc over the weapon */
|
||||
HALO_XR_LAYER_CROSSHAIR = 5, /* the weapon's crosshair, where it aims */
|
||||
HALO_XR_LAYER_COUNT = 6,
|
||||
HALO_XR_LAYER_NAMES = 6, /* players' names, each a quad over a head */
|
||||
HALO_XR_LAYER_COUNT = 7,
|
||||
/* the names layer's slots, one a name, stacked from its top */
|
||||
HALO_XR_MAXIMUM_NAMES = 8,
|
||||
|
||||
/* host_xr_copy_layer's clear_alpha: the source's alpha kept, made
|
||||
opaque, or cut to a disc (premultiplied) */
|
||||
@@ -147,6 +150,12 @@ struct halo_xr_submit
|
||||
int crosshair;
|
||||
float crosshair_size;
|
||||
struct halo_xr_pose crosshair_pose;
|
||||
/* the names layer was filled: its first name_count slots, each shown
|
||||
this wide (metres, a slot's height following from its shape), here in
|
||||
LOCAL space, facing the eyes */
|
||||
int name_count;
|
||||
float name_widths[HALO_XR_MAXIMUM_NAMES];
|
||||
struct halo_xr_pose name_poses[HALO_XR_MAXIMUM_NAMES];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -140,6 +140,21 @@ out (halo_vr_scope_pass). */
|
||||
int halo_vr_scope(short local_player_index, float magnification, float position[3], float forward[3], float up[3],
|
||||
float *vertical_field_of_view);
|
||||
int halo_vr_scope_pass(void);
|
||||
/* The menus' pointer (d3d8_gl.c's halo_ui_pointer_update): where a
|
||||
controller points on the menus' screen, in their 640x480, whether that
|
||||
moved since asked, and the trigger's clicks since (nonzero while it points
|
||||
at the screen); and where it points this frame, to draw it (render.c) */
|
||||
int halo_vr_menu_pointer(int *x, int *y, int *click_x, int *click_y, int *moved, int *clicks);
|
||||
int halo_vr_menu_pointer_at(int *x, int *y);
|
||||
/* Players' names over their heads (hud.c, render.c): whether they are drawn
|
||||
apart this frame; the slot a name is drawn into (left, top, right, bottom
|
||||
of the game's 640x480); a name's place (world units, over the head),
|
||||
giving its slot (-1: no more); and the slots, drawn on the cleared back
|
||||
buffer, taken (it is cleared again) */
|
||||
int halo_vr_names_apart(void);
|
||||
void halo_vr_name_slot(int slot, short bounds[4]);
|
||||
int halo_vr_add_name(const float point[3]);
|
||||
void halo_vr_capture_names(void);
|
||||
/* how much higher than a rifle's the weapon in hand has its scope's disc
|
||||
(metres; render.c, before halo_vr_scope) */
|
||||
void halo_vr_set_scope_raise(float metres);
|
||||
|
||||
@@ -1365,11 +1365,21 @@ HRESULT WINAPI Direct3D_CreateDevice(UINT adapter, D3DDEVTYPE device_type, void
|
||||
/* ---------- the menus' pointer */
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
/* the controller pointing at the menus' screen in VR (halo_vr_menu_pointer) */
|
||||
int halo_ui_pointer_update(int menus_active, struct halo_ui_pointer *pointer)
|
||||
{
|
||||
(void)menus_active;
|
||||
(void)pointer;
|
||||
return 0;
|
||||
int x, y, click_x, click_y, moved, clicks;
|
||||
|
||||
if (!menus_active || !halo_vr_menu_pointer(&x, &y, &click_x, &click_y, &moved, &clicks))
|
||||
return 0;
|
||||
memset(pointer, 0, sizeof(*pointer));
|
||||
pointer->x = (short)(x - (halo_screen_width() - 640) / 2);
|
||||
pointer->y = (short)y;
|
||||
pointer->click_x = (short)(click_x - (halo_screen_width() - 640) / 2);
|
||||
pointer->click_y = (short)click_y;
|
||||
pointer->moved = (unsigned char)(moved != 0);
|
||||
pointer->left_clicks = (unsigned char)(clicks < 255 ? clicks : 255);
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
/* a point in the window, as SDL reports it, in the menus' coordinates: the
|
||||
|
||||
@@ -134,6 +134,11 @@ static struct
|
||||
float scope_size;
|
||||
int crosshair;
|
||||
int crosshair_captured; /* this frame (halo_vr_capture_crosshair) */
|
||||
/* players' names this frame (halo_vr_add_name), and whether their
|
||||
slots were taken (halo_vr_capture_names) */
|
||||
int name_count;
|
||||
float name_points[HALO_XR_MAXIMUM_NAMES][3];
|
||||
int names_captured;
|
||||
/* the barrel of the weapon as drawn (halo_vr_set_barrel): where shots,
|
||||
the crosshair and the laser start */
|
||||
float barrel[3];
|
||||
@@ -242,6 +247,7 @@ the target), keeping the size it has in the HUD: this part of the HUD. */
|
||||
static void cross3(const float a[3], const float b[3], float out[3]);
|
||||
static float normalize3(float v[3]);
|
||||
static int crosshair_pose(struct halo_xr_pose *pose, float *size);
|
||||
static int name_pose(const float point[3], struct halo_xr_pose *pose, float *width);
|
||||
static int weapon_hand_tracked(short local_player_index);
|
||||
static void controller_axes(float forward[3], float up[3], float right[3]);
|
||||
static void hand_offset(float out[3]);
|
||||
@@ -1021,6 +1027,8 @@ void halo_vr_frame_begin(void)
|
||||
vr.eyes_captured = 0;
|
||||
vr.scope_captured = 0;
|
||||
vr.crosshair_captured = 0;
|
||||
vr.name_count = 0;
|
||||
vr.names_captured = 0;
|
||||
vr.overlay_mode = HALO_XR_OVERLAY_SCREEN;
|
||||
vr.overlay_blend = 0;
|
||||
if (vr.frame.recentred)
|
||||
@@ -1087,6 +1095,20 @@ void halo_vr_present(unsigned int back_buffer_texture)
|
||||
weapon aims */
|
||||
if (vr.crosshair_captured && vr.overlay_mode == HALO_XR_OVERLAY_HEAD_LOCKED)
|
||||
submit.crosshair = crosshair_pose(&submit.crosshair_pose, &submit.crosshair_size);
|
||||
/* the names, each over its player's head */
|
||||
if (vr.names_captured && submit.eyes && vr.overlay_mode == HALO_XR_OVERLAY_HEAD_LOCKED)
|
||||
{
|
||||
int name;
|
||||
|
||||
for (name = 0; name < vr.name_count; name++)
|
||||
{
|
||||
if (name_pose(vr.name_points[name], &submit.name_poses[submit.name_count],
|
||||
&submit.name_widths[submit.name_count]))
|
||||
{
|
||||
submit.name_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vr.scope_captured && submit.eyes)
|
||||
{
|
||||
submit.scope = 1;
|
||||
@@ -1947,6 +1969,209 @@ static int crosshair_pose(struct halo_xr_pose *pose, float *size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ---------- the menus' pointer
|
||||
|
||||
In the menus (the screen fixed in the room), a controller points at the
|
||||
screen and its trigger clicks, as the desktop builds' mouse does
|
||||
(halo_ui_pointer.h): where its aim's line meets the screen, in the menus'
|
||||
640x480. The hand whose trigger was pressed last points; a click gives a
|
||||
short tick of the hand's rumble. */
|
||||
|
||||
static struct
|
||||
{
|
||||
int valid;
|
||||
float x, y;
|
||||
float reported_x, reported_y;
|
||||
int hand;
|
||||
int trigger_down[HALO_XR_HAND_COUNT];
|
||||
int clicks;
|
||||
/* a click is taken where it pointed as the trigger began to move
|
||||
(pulling it through tips the controller) */
|
||||
int pulling[HALO_XR_HAND_COUNT];
|
||||
float pull_x[HALO_XR_HAND_COUNT], pull_y[HALO_XR_HAND_COUNT];
|
||||
float click_x, click_y;
|
||||
} menu_pointer;
|
||||
|
||||
static void menu_pointer_update(void)
|
||||
{
|
||||
static const float forward[3] = { 0.0f, 0.0f, -1.0f };
|
||||
const struct halo_xr_hand *hand;
|
||||
float direction[3], t, hit_x, hit_y, width, height;
|
||||
int index;
|
||||
|
||||
menu_pointer.valid = 0;
|
||||
if (!vr.active || vr.last_overlay_mode != HALO_XR_OVERLAY_SCREEN || !vr.frame.focused)
|
||||
{
|
||||
menu_pointer.trigger_down[0] = menu_pointer.trigger_down[1] = 0;
|
||||
menu_pointer.pulling[0] = menu_pointer.pulling[1] = 0;
|
||||
return;
|
||||
}
|
||||
/* (the hand that clicked last points; a click counts as it goes down) */
|
||||
for (index = 0; index < HALO_XR_HAND_COUNT; index++)
|
||||
{
|
||||
int down = vr.frame.hands[index].active && (vr.frame.hands[index].buttons & HALO_XR_BUTTON_TRIGGER);
|
||||
|
||||
if (down && !menu_pointer.trigger_down[index])
|
||||
{
|
||||
menu_pointer.hand = index;
|
||||
menu_pointer.clicks++;
|
||||
}
|
||||
menu_pointer.trigger_down[index] = down;
|
||||
}
|
||||
hand = &vr.frame.hands[menu_pointer.hand];
|
||||
if (!hand->active || !(hand->flags & HALO_XR_POSE_VALID))
|
||||
{
|
||||
hand = &vr.frame.hands[1 - menu_pointer.hand];
|
||||
if (!hand->active || !(hand->flags & HALO_XR_POSE_VALID))
|
||||
return;
|
||||
}
|
||||
quaternion_rotate(hand->aim.orientation, forward, direction);
|
||||
if (direction[2] > -1e-3f)
|
||||
return;
|
||||
t = (-vr.screen_distance - hand->aim.position[2]) / direction[2];
|
||||
if (t <= 0.0f)
|
||||
return;
|
||||
hit_x = hand->aim.position[0] + direction[0] * t;
|
||||
hit_y = hand->aim.position[1] + direction[1] * t;
|
||||
width = vr.screen_width;
|
||||
height = vr.screen_width * 0.75f;
|
||||
menu_pointer.x = (hit_x / width + 0.5f) * 640.0f;
|
||||
menu_pointer.y = (0.5f - hit_y / height) * 480.0f;
|
||||
menu_pointer.valid = menu_pointer.x >= 0.0f && menu_pointer.x < 640.0f && menu_pointer.y >= 0.0f &&
|
||||
menu_pointer.y < 480.0f;
|
||||
/* (the click where the trigger began to move, if it pointed then) */
|
||||
{
|
||||
int pulling = vr.frame.hands[menu_pointer.hand].trigger > 0.1f;
|
||||
|
||||
if (pulling && !menu_pointer.pulling[menu_pointer.hand] && menu_pointer.valid)
|
||||
{
|
||||
menu_pointer.pull_x[menu_pointer.hand] = menu_pointer.x;
|
||||
menu_pointer.pull_y[menu_pointer.hand] = menu_pointer.y;
|
||||
}
|
||||
if (!pulling || !menu_pointer.pulling[menu_pointer.hand])
|
||||
{
|
||||
menu_pointer.click_x = menu_pointer.x;
|
||||
menu_pointer.click_y = menu_pointer.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_pointer.click_x = menu_pointer.pull_x[menu_pointer.hand];
|
||||
menu_pointer.click_y = menu_pointer.pull_y[menu_pointer.hand];
|
||||
}
|
||||
if (!pulling || menu_pointer.valid)
|
||||
menu_pointer.pulling[menu_pointer.hand] = pulling;
|
||||
}
|
||||
}
|
||||
|
||||
int halo_vr_menu_pointer(int *x, int *y, int *click_x, int *click_y, int *moved, int *clicks)
|
||||
{
|
||||
menu_pointer_update();
|
||||
*click_x = (int)menu_pointer.click_x;
|
||||
*click_y = (int)menu_pointer.click_y;
|
||||
*clicks = menu_pointer.clicks;
|
||||
if (menu_pointer.clicks)
|
||||
host_xr_haptic(menu_pointer.hand, 0.3f, 0.02f);
|
||||
menu_pointer.clicks = 0;
|
||||
if (!menu_pointer.valid)
|
||||
return 0;
|
||||
*x = (int)menu_pointer.x;
|
||||
*y = (int)menu_pointer.y;
|
||||
/* (moved past a hand's tremor: a few pixels) */
|
||||
*moved = fabsf(menu_pointer.x - menu_pointer.reported_x) >= 3.0f ||
|
||||
fabsf(menu_pointer.y - menu_pointer.reported_y) >= 3.0f;
|
||||
if (*moved)
|
||||
{
|
||||
menu_pointer.reported_x = menu_pointer.x;
|
||||
menu_pointer.reported_y = menu_pointer.y;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int halo_vr_menu_pointer_at(int *x, int *y)
|
||||
{
|
||||
if (!menu_pointer.valid)
|
||||
return 0;
|
||||
*x = (int)menu_pointer.x;
|
||||
*y = (int)menu_pointer.y;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ---------- players' names
|
||||
|
||||
Names over the heads (hud.c) are drawn into slots of a region of the back
|
||||
buffer, one under another, before the HUD, and each slot is shown on a quad
|
||||
of its own over its player's head, facing the eyes, as wide as the name
|
||||
looks at the HUD's distance: in VR the HUD is a screen at one distance,
|
||||
where names drawn on it hung before the eyes. */
|
||||
|
||||
#define NAME_SLOT_LEFT 240
|
||||
#define NAME_SLOT_WIDTH 160
|
||||
#define NAME_SLOT_HEIGHT 30
|
||||
/* how large a name looks against the HUD's text (smaller: over a head, not
|
||||
on the screen before the eyes) */
|
||||
#define NAME_SCALE 0.6f
|
||||
|
||||
int halo_vr_names_apart(void)
|
||||
{
|
||||
return vr.active && halo_vr_stereo_frame();
|
||||
}
|
||||
|
||||
void halo_vr_name_slot(int slot, short bounds[4])
|
||||
{
|
||||
bounds[0] = NAME_SLOT_LEFT;
|
||||
bounds[1] = (short)(slot * NAME_SLOT_HEIGHT);
|
||||
bounds[2] = NAME_SLOT_LEFT + NAME_SLOT_WIDTH;
|
||||
bounds[3] = (short)((slot + 1) * NAME_SLOT_HEIGHT);
|
||||
}
|
||||
|
||||
int halo_vr_add_name(const float point[3])
|
||||
{
|
||||
int slot = vr.name_count;
|
||||
|
||||
if (slot >= HALO_XR_MAXIMUM_NAMES)
|
||||
return -1;
|
||||
memcpy(vr.name_points[slot], point, sizeof(vr.name_points[slot]));
|
||||
vr.name_count++;
|
||||
return slot;
|
||||
}
|
||||
|
||||
void halo_vr_capture_names(void)
|
||||
{
|
||||
if (vr.name_count > 0)
|
||||
{
|
||||
vr.names_captured = host_xr_copy_layer_region(HALO_XR_LAYER_NAMES, d3d8_back_buffer_texture(),
|
||||
HALO_XR_COPY_ALPHA, NAME_SLOT_LEFT / 640.0f, 0.0f, (NAME_SLOT_LEFT + NAME_SLOT_WIDTH) / 640.0f,
|
||||
HALO_XR_MAXIMUM_NAMES * NAME_SLOT_HEIGHT / 480.0f);
|
||||
}
|
||||
d3d8_clear_back_buffer(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
static int name_pose(const float point[3], struct halo_xr_pose *pose, float *width)
|
||||
{
|
||||
static const float world_up[3] = { 0.0f, 1.0f, 0.0f };
|
||||
float x[3], y[3], z[3];
|
||||
float distance;
|
||||
float angle;
|
||||
int axis;
|
||||
|
||||
world_to_local(point, pose->position);
|
||||
for (axis = 0; axis < 3; axis++)
|
||||
z[axis] = vr.frame.head.position[axis] - pose->position[axis];
|
||||
distance = normalize3(z);
|
||||
/* (facing the eyes, upright) */
|
||||
if (distance < 0.05f)
|
||||
return 0;
|
||||
cross3(world_up, z, x);
|
||||
if (normalize3(x) < 1e-4f)
|
||||
return 0;
|
||||
cross3(z, x, y);
|
||||
quaternion_from_axes(x, y, z, pose->orientation);
|
||||
/* (as wide as the slot looks on the HUD, smaller) */
|
||||
angle = (float)NAME_SLOT_WIDTH / 640.0f * vr.hud_width / vr.hud_distance * NAME_SCALE;
|
||||
*width = 2.0f * distance * tanf(angle * 0.5f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ---------- the scope
|
||||
|
||||
Zoomed in, the weapon shows its view on a disc over the barrel, like a
|
||||
@@ -2175,6 +2400,16 @@ int halo_vr_scope(short local_player_index, float magnification, float position[
|
||||
return 0;
|
||||
}
|
||||
int halo_vr_scope_pass(void) { return 0; }
|
||||
int halo_vr_menu_pointer(int *x, int *y, int *click_x, int *click_y, int *moved, int *clicks)
|
||||
{
|
||||
(void)x; (void)y; (void)click_x; (void)click_y; (void)moved; *clicks = 0;
|
||||
return 0;
|
||||
}
|
||||
int halo_vr_menu_pointer_at(int *x, int *y) { (void)x; (void)y; return 0; }
|
||||
int halo_vr_names_apart(void) { return 0; }
|
||||
void halo_vr_name_slot(int slot, short bounds[4]) { (void)slot; (void)bounds; }
|
||||
int halo_vr_add_name(const float point[3]) { (void)point; return -1; }
|
||||
void halo_vr_capture_names(void) {}
|
||||
void halo_vr_set_scope_raise(float metres) { (void)metres; }
|
||||
void halo_vr_capture_scope(float left, float top, float right, float bottom)
|
||||
{
|
||||
|
||||
@@ -573,9 +573,10 @@ static void vr_gamepad_state(XINPUT_GAMEPAD *pad)
|
||||
if (left->buttons & HALO_XR_BUTTON_MENU) pad->wButtons |= XINPUT_GAMEPAD_START;
|
||||
if (left->buttons & HALO_XR_BUTTON_THUMBSTICK) pad->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB;
|
||||
if (right->buttons & HALO_XR_BUTTON_THUMBSTICK) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB;
|
||||
if ((BYTE)(right->trigger * 255.0f) > pad->bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER])
|
||||
/* (in the menus the triggers click the pointer: halo_vr_menu_pointer) */
|
||||
if (!menus && (BYTE)(right->trigger * 255.0f) > pad->bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER])
|
||||
pad->bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER] = (BYTE)(right->trigger * 255.0f);
|
||||
if ((BYTE)(left->trigger * 255.0f) > pad->bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER])
|
||||
if (!menus && (BYTE)(left->trigger * 255.0f) > pad->bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER])
|
||||
pad->bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER] = (BYTE)(left->trigger * 255.0f);
|
||||
if (menus)
|
||||
{
|
||||
|
||||
+56
-13
@@ -1033,13 +1033,6 @@ static short hud_player_names_setting(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
/* (the VR port's: in VR the HUD is a screen at a fixed distance before
|
||||
the eyes, so names drawn on it hang there, not over the heads; none
|
||||
until they are drawn into each eye's picture) */
|
||||
if (halo_vr_active())
|
||||
return _player_names_none;
|
||||
#endif
|
||||
return setting;
|
||||
}
|
||||
|
||||
@@ -1134,7 +1127,8 @@ static void hud_draw_player_name(
|
||||
long player_index,
|
||||
boolean ally,
|
||||
boolean indicator,
|
||||
real enemy_range)
|
||||
real enemy_range,
|
||||
boolean vr_apart)
|
||||
{
|
||||
struct player_datum const *player = player_get(player_index);
|
||||
long font_index = hud_get_font_index();
|
||||
@@ -1164,10 +1158,35 @@ static void hud_draw_player_name(
|
||||
/* (where the game draws a teammate's triangle) */
|
||||
head_position.z += 0.30000001f;
|
||||
matrix4x3_transform_point(&render.frustum.world_to_view, &head_position, &view_position);
|
||||
if (!render_camera_view_to_screen(&render.camera, &render.frustum, &view_position, &screen_position))
|
||||
return;
|
||||
x = (short)fast_ftol(screen_position.x) - render.camera.viewport_bounds.x0;
|
||||
y = (short)fast_ftol(screen_position.y) - render.camera.viewport_bounds.y0;
|
||||
#ifdef HALO_ANDROID
|
||||
if (vr_apart)
|
||||
{
|
||||
/* (VR: in a slot of its own, shown over the head: halo_vr.h) */
|
||||
float point[3];
|
||||
short slot_bounds[4];
|
||||
int slot;
|
||||
|
||||
point[0] = head_position.x;
|
||||
point[1] = head_position.y;
|
||||
point[2] = head_position.z + (indicator ? 0.15f : 0.0f);
|
||||
slot = halo_vr_add_name(point);
|
||||
if (slot < 0)
|
||||
return;
|
||||
halo_vr_name_slot(slot, slot_bounds);
|
||||
x = (short)((slot_bounds[0] + slot_bounds[2]) / 2);
|
||||
y = (short)(slot_bounds[3] - 4);
|
||||
/* (an ally's whole at any distance it is drawn at) */
|
||||
view_position.z = -1.0f;
|
||||
indicator = FALSE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (!render_camera_view_to_screen(&render.camera, &render.frustum, &view_position, &screen_position))
|
||||
return;
|
||||
x = (short)fast_ftol(screen_position.x) - render.camera.viewport_bounds.x0;
|
||||
y = (short)fast_ftol(screen_position.y) - render.camera.viewport_bounds.y0;
|
||||
}
|
||||
if (indicator)
|
||||
{
|
||||
struct bitmap_data *bitmap = bitmap_group_get_bitmap_from_sequence(
|
||||
@@ -1209,8 +1228,32 @@ static void hud_draw_player_name(
|
||||
return;
|
||||
}
|
||||
|
||||
static void hud_draw_player_names_now(
|
||||
boolean vr_apart);
|
||||
|
||||
static void hud_draw_player_names(
|
||||
void)
|
||||
{
|
||||
#ifdef HALO_ANDROID
|
||||
/* (VR: apart, before the HUD: hud_draw_player_names_vr) */
|
||||
if (halo_vr_active())
|
||||
return;
|
||||
#endif
|
||||
hud_draw_player_names_now(FALSE);
|
||||
}
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
/* VR: the names drawn into their slots, each then shown over its player's
|
||||
head (render.c, before the HUD; halo_vr_names_apart) */
|
||||
void hud_draw_player_names_vr(
|
||||
void)
|
||||
{
|
||||
hud_draw_player_names_now(TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void hud_draw_player_names_now(
|
||||
boolean vr_apart)
|
||||
{
|
||||
short setting = hud_player_names_setting();
|
||||
long player_index = local_player_get_player_index(render.local_player_index);
|
||||
@@ -1235,7 +1278,7 @@ static void hud_draw_player_names(
|
||||
continue;
|
||||
if ((ally && setting == _player_names_enemies) || (!ally && setting == _player_names_allies))
|
||||
continue;
|
||||
hud_draw_player_name(iterator.datum_index, ally, ally && indicators, enemy_range);
|
||||
hud_draw_player_name(iterator.datum_index, ally, ally && indicators, enemy_range, vr_apart);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -29,6 +29,11 @@ struct hud_scripted_globals_definition
|
||||
/* ---------- prototypes/HUD.C */
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
#ifdef HALO_ANDROID
|
||||
/* VR: players' names drawn into their slots (halo_vr_names_apart) */
|
||||
void hud_draw_player_names_vr(
|
||||
void);
|
||||
#endif
|
||||
void hud_draw_crosshair(
|
||||
void);
|
||||
#endif
|
||||
|
||||
@@ -677,6 +677,9 @@ struct widget_instance;
|
||||
#include "text/text_group.h"
|
||||
#include "text/unicode.h"
|
||||
#include "ui_widget.h"
|
||||
#ifdef HALO_ANDROID
|
||||
#include "halo_vr.h"
|
||||
#endif
|
||||
|
||||
/* ---------- constants */
|
||||
|
||||
@@ -5269,6 +5272,8 @@ struct ui_mouse_target
|
||||
rectangle2d bounds;
|
||||
short kind;
|
||||
short button_index;
|
||||
/* (a button's: where its icon begins) */
|
||||
short icon_x0;
|
||||
};
|
||||
|
||||
static struct ui_mouse_target ui_mouse_targets[UI_MOUSE_MAXIMUM_TARGETS];
|
||||
@@ -5403,6 +5408,7 @@ static void ui_mouse_note_target(
|
||||
rectangle2d bounds = definition->bounds;
|
||||
short button_index;
|
||||
short kind;
|
||||
short icon_x0;
|
||||
|
||||
if (!ui_mouse_noting_targets ||
|
||||
ui_mouse_target_count >= UI_MOUSE_MAXIMUM_TARGETS ||
|
||||
@@ -5415,13 +5421,22 @@ static void ui_mouse_note_target(
|
||||
bounds.y0 += offset.y;
|
||||
bounds.y1 += offset.y;
|
||||
button_index = ui_mouse_key_button(widget);
|
||||
icon_x0 = bounds.x0;
|
||||
if (button_index != NONE)
|
||||
{
|
||||
/* the icon and its label: the text beginning just right of it */
|
||||
struct widget_instance *sibling;
|
||||
rectangle2d label_bounds;
|
||||
short best_distance = 17;
|
||||
#ifdef HALO_ANDROID
|
||||
/* (VR: a controller points less steadily than a mouse: the label a
|
||||
little further off is the button's too) */
|
||||
short most_distance = halo_vr_active() ? 25 : 17;
|
||||
#else
|
||||
short most_distance = 17;
|
||||
#endif
|
||||
|
||||
best_distance = most_distance;
|
||||
kind = _ui_mouse_target_button;
|
||||
for (sibling = parent ? parent->child : NULL; sibling; sibling = sibling->next)
|
||||
{
|
||||
@@ -5445,12 +5460,23 @@ static void ui_mouse_note_target(
|
||||
label_bounds = sibling_bounds;
|
||||
}
|
||||
}
|
||||
if (best_distance < 17)
|
||||
if (best_distance < most_distance)
|
||||
{
|
||||
bounds.x1 = MAX(bounds.x1, label_bounds.x1);
|
||||
bounds.y0 = MIN(bounds.y0, label_bounds.y0);
|
||||
bounds.y1 = MAX(bounds.y1, label_bounds.y1);
|
||||
}
|
||||
#ifdef HALO_ANDROID
|
||||
/* (and a margin about it: above and below, little to the sides,
|
||||
where the next key is) */
|
||||
if (halo_vr_active())
|
||||
{
|
||||
bounds.x0 -= 2;
|
||||
bounds.x1 += 2;
|
||||
bounds.y0 -= 4;
|
||||
bounds.y1 += 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (parent && ui_mouse_list_shows_several(parent))
|
||||
{
|
||||
@@ -5482,6 +5508,7 @@ static void ui_mouse_note_target(
|
||||
target->bounds = bounds;
|
||||
target->kind = kind;
|
||||
target->button_index = button_index;
|
||||
target->icon_x0 = icon_x0;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -5492,16 +5519,33 @@ static struct ui_mouse_target *ui_mouse_target_at(
|
||||
short y)
|
||||
{
|
||||
long index;
|
||||
struct ui_mouse_target *button = NULL;
|
||||
|
||||
for (index = ui_mouse_target_count - 1; index >= 0; index--)
|
||||
{
|
||||
rectangle2d const *bounds = &ui_mouse_targets[index].bounds;
|
||||
struct ui_mouse_target *target = &ui_mouse_targets[index];
|
||||
rectangle2d const *bounds = &target->bounds;
|
||||
|
||||
if (x >= bounds->x0 && x < bounds->x1 && y >= bounds->y0 && y < bounds->y1)
|
||||
return &ui_mouse_targets[index];
|
||||
if (!(x >= bounds->x0 && x < bounds->x1 && y >= bounds->y0 && y < bounds->y1))
|
||||
continue;
|
||||
/* port: a key's label's text box can be far wider than its text, over
|
||||
the next key: of keys under the point, the one whose icon is nearest
|
||||
on its left (each key from its icon to the next one's) */
|
||||
if (target->kind == _ui_mouse_target_button)
|
||||
{
|
||||
if (!button ||
|
||||
(target->icon_x0 <= x + 2 && (button->icon_x0 > x + 2 || target->icon_x0 > button->icon_x0)))
|
||||
{
|
||||
button = target;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!button)
|
||||
return target;
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return button;
|
||||
}
|
||||
|
||||
static boolean ui_mouse_widget_has_focus(
|
||||
@@ -5692,6 +5736,8 @@ enum
|
||||
MAXIMUM_SHOWN_PUBLIC_GAMES = 32,
|
||||
/* the online games panel's rows: "enter a code" and the games */
|
||||
ONLINE_PANEL_ROWS = 11,
|
||||
/* (the rows before the games: "enter a code") */
|
||||
ONLINE_PANEL_FIXED_ROWS = 1,
|
||||
};
|
||||
|
||||
static struct
|
||||
@@ -5932,6 +5978,48 @@ static boolean ui_join_code_take_event(
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* the pointer over the VR port's panels: the row under it chosen, and a
|
||||
click on it as A (TRUE: a panel is open and took it) */
|
||||
static boolean ui_join_code_take_pointer(
|
||||
struct halo_ui_pointer const *pointer)
|
||||
{
|
||||
struct event_record press;
|
||||
short row;
|
||||
/* (a click where it was clicked, which may be a moment before) */
|
||||
short x = pointer->left_clicks ? pointer->click_x : pointer->x;
|
||||
short y = pointer->left_clicks ? pointer->click_y : pointer->y;
|
||||
|
||||
csmemset(&press, 0, sizeof(press));
|
||||
press.type = _event_type_button;
|
||||
press.data.button.index = _gamepad_analog_button_a;
|
||||
press.data.button.value = 1;
|
||||
if (ui_join_code_globals.panel_open)
|
||||
{
|
||||
if (x >= 48 && x < 592 && y >= 128 && y < 128 + ONLINE_PANEL_ROWS * 22)
|
||||
{
|
||||
row = (short)(ui_join_code_globals.scroll + (y - 128) / 22);
|
||||
if (row < ui_join_code_globals.game_count + ONLINE_PANEL_FIXED_ROWS)
|
||||
{
|
||||
ui_join_code_globals.selection = row;
|
||||
if (pointer->left_clicks)
|
||||
ui_join_code_panel_event(&press);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
if (ui_join_code_globals.host_panel_open)
|
||||
{
|
||||
if (x >= 148 && x < 492 && y >= 187 && y < 187 + HOST_PANEL_ROWS * 30)
|
||||
{
|
||||
ui_join_code_globals.host_selection = (short)((y - 187) / 30);
|
||||
if (pointer->left_clicks)
|
||||
ui_join_code_host_panel_event(&press);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* the keyboard closed: the code typed, looked up */
|
||||
static void ui_join_code_update(
|
||||
void)
|
||||
@@ -6186,8 +6274,9 @@ static void ui_widgets_process_mouse(
|
||||
struct ui_mouse_target *target;
|
||||
short controller_index = 0;
|
||||
|
||||
if (!halo_ui_pointer_update(ui_mouse_menus_active(), &pointer) ||
|
||||
virtual_keyboard_active())
|
||||
/* (the keyboard takes the pointer itself: virtual_keyboard.c) */
|
||||
if (virtual_keyboard_active() ||
|
||||
!halo_ui_pointer_update(ui_mouse_menus_active(), &pointer))
|
||||
{
|
||||
ui_mouse_press_count = 0;
|
||||
ui_mouse_hover_pending = FALSE;
|
||||
@@ -6195,6 +6284,11 @@ static void ui_widgets_process_mouse(
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HALO_ANDROID
|
||||
/* (the VR port's panels over the menus take the pointer themselves) */
|
||||
if (ui_join_code_take_pointer(&pointer))
|
||||
return;
|
||||
#endif
|
||||
if (pointer.moved)
|
||||
{
|
||||
ui_mouse_hover_pending = TRUE;
|
||||
|
||||
@@ -1166,6 +1166,25 @@ static boolean virtual_keyboard_select(
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
/* the key drawn at a point of the menus' 640x480, or NONE */
|
||||
static short virtual_keyboard_key_at(
|
||||
short x,
|
||||
short y)
|
||||
{
|
||||
short key;
|
||||
|
||||
for (key = 0; key < NUMBER_OF_VIRTUAL_KEYS; key++)
|
||||
{
|
||||
rectangle2d const *bounds = &keyboard_rect[key];
|
||||
|
||||
if (x >= bounds->x0 && x < bounds->x1 && y >= bounds->y0 && y < bounds->y1)
|
||||
return key;
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void virtual_keyboard_process_internal(
|
||||
void)
|
||||
{
|
||||
@@ -1304,6 +1323,56 @@ static void virtual_keyboard_process_internal(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HALO_ANDROID
|
||||
/* the VR port's: the controller's pointer (halo_ui_pointer.h) picks the
|
||||
key under it, and its click types it */
|
||||
{
|
||||
struct halo_ui_pointer pointer;
|
||||
|
||||
if (halo_ui_pointer_update(TRUE, &pointer))
|
||||
{
|
||||
short x = pointer.left_clicks ? pointer.click_x : pointer.x;
|
||||
short y = pointer.left_clicks ? pointer.click_y : pointer.y;
|
||||
short key = virtual_keyboard_key_at(x, y);
|
||||
|
||||
if (key != NONE && (pointer.moved || pointer.left_clicks))
|
||||
{
|
||||
short row, column;
|
||||
boolean found = FALSE;
|
||||
|
||||
for (row = 0; row < VIRTUAL_KEYBOARD_ROW_COUNT && !found; row++)
|
||||
{
|
||||
for (column = 0; column < VIRTUAL_KEYBOARD_COLUMN_COUNT && !found; column++)
|
||||
{
|
||||
if (virtual_keyboard_layout_table[row][column] == key)
|
||||
{
|
||||
virtual_keyboard_globals.row = row;
|
||||
virtual_keyboard_globals.column = column;
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pointer.left_clicks && key != NONE)
|
||||
action = _event_key_select;
|
||||
/* (the keys' hints under the keyboard, in its picture: B = BACK
|
||||
cancels, A = ENTER finishes, as Done does) */
|
||||
if (pointer.left_clicks && key == NONE && y >= 412 && y < 448)
|
||||
{
|
||||
if (x >= 380 && x < 480)
|
||||
{
|
||||
action = _event_cancel;
|
||||
}
|
||||
else if (x >= 488 && x < 600)
|
||||
{
|
||||
virtual_keyboard_globals.row = 0;
|
||||
virtual_keyboard_globals.column = 0;
|
||||
action = _event_key_select;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (action != NONE)
|
||||
{
|
||||
virtual_keyboard_globals.last_key = virtual_keyboard_layout_table[
|
||||
|
||||
@@ -853,6 +853,14 @@ static void render_vr_overlay(
|
||||
parameters.suppress_clear = TRUE;
|
||||
parameters.window_index = render.window_index;
|
||||
|
||||
if (!menus_active && halo_vr_names_apart())
|
||||
{
|
||||
/* the players' names, each to be shown over its head */
|
||||
rasterizer_window_begin(¶meters);
|
||||
hud_draw_player_names_vr();
|
||||
rasterizer_window_end();
|
||||
halo_vr_capture_names();
|
||||
}
|
||||
if (!menus_active && halo_vr_crosshair_apart())
|
||||
{
|
||||
/* the weapon's crosshair alone, taken to where the weapon aims */
|
||||
@@ -866,6 +874,28 @@ static void render_vr_overlay(
|
||||
interface_draw_screen();
|
||||
halo_screen_ui_offset(TRUE);
|
||||
render_ui_widgets(window->local_player_index, &window->rasterizer_camera.viewport_bounds);
|
||||
if (menus_active)
|
||||
{
|
||||
/* the controller's pointer on the menus' screen: a dot, ringed */
|
||||
int pointer_x, pointer_y;
|
||||
|
||||
if (halo_vr_menu_pointer_at(&pointer_x, &pointer_y))
|
||||
{
|
||||
rectangle2d dot;
|
||||
|
||||
pointer_x -= (int)(halo_screen_width() - 640) / 2;
|
||||
dot.x0 = (short)(pointer_x - 5);
|
||||
dot.x1 = (short)(pointer_x + 5);
|
||||
dot.y0 = (short)(pointer_y - 5);
|
||||
dot.y1 = (short)(pointer_y + 5);
|
||||
draw_quad(&dot, 0xE0102030);
|
||||
dot.x0 += 2;
|
||||
dot.x1 -= 2;
|
||||
dot.y0 += 2;
|
||||
dot.y1 -= 2;
|
||||
draw_quad(&dot, 0xFF8FD3FF);
|
||||
}
|
||||
}
|
||||
halo_screen_ui_offset(FALSE);
|
||||
|
||||
rasterizer_window_end();
|
||||
|
||||
Reference in new issue
Block a user