raw mouse look. cursor hiding & clipping
This commit is contained in:
parent
bd0b22b889
commit
eda5e44d3b
@ -142,10 +142,10 @@ Struct(ControllerEvent)
|
||||
u32 text_codepoint;
|
||||
|
||||
// ControllerEventKind_CursorMove
|
||||
Vec2I32 cursor_pos;
|
||||
Vec2 cursor_pos;
|
||||
|
||||
// ControllerEventKind_MouseMove
|
||||
Vec2I32 mouse_delta;
|
||||
Vec2 mouse_delta;
|
||||
};
|
||||
|
||||
Struct(ControllerEventsArray)
|
||||
|
||||
@ -569,7 +569,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
frame->is_editing = prev_frame->is_editing;
|
||||
frame->ui_debug = prev_frame->ui_debug;
|
||||
frame->show_console = prev_frame->show_console;
|
||||
frame->look = NormRot(prev_frame->look);
|
||||
frame->look = prev_frame->look;
|
||||
frame->edit_mode = prev_frame->edit_mode;
|
||||
frame->equipped_tile = prev_frame->equipped_tile;
|
||||
frame->edit_camera_pos = prev_frame->edit_camera_pos;
|
||||
@ -653,6 +653,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
UI_Frame *ui_frame = UI_BeginFrame(ui_frame_flags);
|
||||
WND_Frame window_frame = ui_frame->window_frame;
|
||||
WND_SetCursor(window_frame, WND_CursorKind_Default);
|
||||
WND_PushCmd(window_frame, .kind = WND_CmdKind_SetLockedCursor, .v = 0);
|
||||
|
||||
// Restore window
|
||||
{
|
||||
@ -734,12 +735,15 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
b32 has_mouse_focus = UI_IsKeyNil(ui_frame->hot_box) || UI_MatchKey(ui_frame->hot_box, vis_box);
|
||||
b32 has_keyboard_focus = 1;
|
||||
Vec2 mouse_delta = Zi;
|
||||
{
|
||||
if (!window_frame.has_focus)
|
||||
{
|
||||
has_mouse_focus = 0;
|
||||
has_keyboard_focus = 0;
|
||||
}
|
||||
|
||||
//- Reset held buttons
|
||||
for (Button btn = 0; btn < countof(frame->held_buttons); ++btn)
|
||||
{
|
||||
if (btn == Button_M1 || btn == Button_M2 || btn == Button_M3)
|
||||
@ -758,9 +762,10 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < window_frame.controller_events.count; ++i)
|
||||
//- Convert events into cmds
|
||||
for (u64 cev_idx = 0; cev_idx < window_frame.controller_events.count; ++cev_idx)
|
||||
{
|
||||
ControllerEvent cev = window_frame.controller_events.events[i];
|
||||
ControllerEvent cev = window_frame.controller_events.events[cev_idx];
|
||||
b32 down = cev.kind == ControllerEventKind_ButtonDown;
|
||||
b32 up = cev.kind == ControllerEventKind_ButtonUp;
|
||||
|
||||
@ -810,6 +815,72 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
}
|
||||
|
||||
//- Compute mouse delta from events
|
||||
for (u64 cev_idx = 0; cev_idx < window_frame.controller_events.count; ++cev_idx)
|
||||
{
|
||||
ControllerEvent cev = window_frame.controller_events.events[cev_idx];
|
||||
if (cev.kind == ControllerEventKind_MouseMove)
|
||||
{
|
||||
mouse_delta = AddVec2(mouse_delta, cev.mouse_delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Compute movement & look
|
||||
|
||||
if (!frame->is_editing && !frame->palette.is_showing)
|
||||
{
|
||||
WND_PushCmd(window_frame, .kind = WND_CmdKind_SetLockedCursor, .v = 1);
|
||||
WND_SetCursor(window_frame, WND_CursorKind_Hidden);
|
||||
}
|
||||
|
||||
{
|
||||
Vec2 move = Zi;
|
||||
{
|
||||
if (frame->held_buttons[Button_A]) move.x -= 1;
|
||||
if (frame->held_buttons[Button_D]) move.x += 1;
|
||||
if (frame->held_buttons[Button_W]) move.y -= 1;
|
||||
if (frame->held_buttons[Button_S]) move.y += 1;
|
||||
}
|
||||
move = ClampVec2Len(move, 1);
|
||||
f32 fire_held = frame->held_buttons[Button_M1];
|
||||
Vec2 look = Zi;
|
||||
f32 fire_presses = fire_held && !prev_frame->held_buttons[Button_M1];
|
||||
{
|
||||
// Vec2 center = P_WorldShapeFromEnt(local_guy).centroid;
|
||||
// look = SubVec2(frame->world_cursor, center);
|
||||
|
||||
// TODO: Adjustable sensitivity
|
||||
f32 mouse_scale_factor = 0.005;
|
||||
|
||||
look = frame->look;
|
||||
look = AddVec2(look, MulVec2(mouse_delta, mouse_scale_factor));
|
||||
}
|
||||
if (frame->is_editing)
|
||||
{
|
||||
if (!frame->is_panning)
|
||||
{
|
||||
f32 edit_move_speed = 20.0 * MaxF32(frame->edit_camera_zoom, min_zoom);
|
||||
frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, MulVec2(move, edit_move_speed * frame->dt));
|
||||
}
|
||||
|
||||
// FIXME: Remove this
|
||||
frame->move = prev_frame->move;
|
||||
frame->look = prev_frame->look;
|
||||
frame->fire_held = prev_frame->fire_held;
|
||||
frame->fire_presses = prev_frame->fire_presses;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame->move = move;
|
||||
frame->look = look;
|
||||
frame->fire_held = fire_held;
|
||||
frame->fire_presses = fire_presses;
|
||||
}
|
||||
frame->look = frame->look;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Compute camera position & zoom
|
||||
|
||||
@ -858,9 +929,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
P_Ent *guy = P_EntFromKey(local_world->last_frame, player->guy);
|
||||
Vec2 guy_center = P_WorldShapeFromEnt(guy).centroid;
|
||||
Vec2 screen_center = MulVec2(frame->screen_dims, 0.5);
|
||||
Vec2 look = MulAffineBasisVec2(prev_frame->af.screen_to_world, SubVec2(ui_frame->cursor_pos, screen_center));
|
||||
// Vec2 look = MulAffineBasisVec2(prev_frame->af.screen_to_world, SubVec2(ui_frame->cursor_pos, screen_center));
|
||||
target_camera_pos = guy_center;
|
||||
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(look, look_ratio));
|
||||
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(frame->look, look_ratio));
|
||||
target_camera_zoom = 1;
|
||||
}
|
||||
target_camera_pos.x = ClampF32(target_camera_pos.x, -world_pitch / 2, world_pitch / 2);
|
||||
@ -1268,50 +1339,6 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Compute movement & look
|
||||
|
||||
{
|
||||
Vec2 move = Zi;
|
||||
{
|
||||
if (frame->held_buttons[Button_A]) move.x -= 1;
|
||||
if (frame->held_buttons[Button_D]) move.x += 1;
|
||||
if (frame->held_buttons[Button_W]) move.y -= 1;
|
||||
if (frame->held_buttons[Button_S]) move.y += 1;
|
||||
}
|
||||
move = ClampVec2Len(move, 1);
|
||||
f32 fire_held = frame->held_buttons[Button_M1];
|
||||
Vec2 look = Zi;
|
||||
f32 fire_presses = fire_held && !prev_frame->held_buttons[Button_M1];
|
||||
{
|
||||
Vec2 center = P_WorldShapeFromEnt(local_guy).centroid;
|
||||
look = SubVec2(frame->world_cursor, center);
|
||||
}
|
||||
if (frame->is_editing)
|
||||
{
|
||||
if (!frame->is_panning)
|
||||
{
|
||||
f32 edit_move_speed = 20.0 * MaxF32(frame->edit_camera_zoom, min_zoom);
|
||||
frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, MulVec2(move, edit_move_speed * frame->dt));
|
||||
}
|
||||
|
||||
// FIXME: Remove this
|
||||
frame->move = prev_frame->move;
|
||||
frame->look = prev_frame->look;
|
||||
frame->fire_held = prev_frame->fire_held;
|
||||
frame->fire_presses = prev_frame->fire_presses;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
frame->move = move;
|
||||
frame->look = look;
|
||||
frame->fire_held = fire_held;
|
||||
frame->fire_presses = fire_presses;
|
||||
}
|
||||
frame->look = NormRot(frame->look);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Determine local simulation bounds
|
||||
//
|
||||
@ -1369,7 +1396,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
control.tick = control_tick;
|
||||
control.orig_tick = control_tick;
|
||||
control.move = frame->move;
|
||||
control.look = NormRot(frame->look);
|
||||
control.look = frame->look;
|
||||
control.fire_held = frame->fire_held;
|
||||
// FIXME: Don't propagate fire presses over multiple sim frames
|
||||
control.fire_presses = frame->fire_presses;
|
||||
@ -1964,7 +1991,11 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
Vec2 line_end = AddVec2(line_start, fire_dir);
|
||||
P_DebugDrawLine(line_start, line_end, Color_Yellow);
|
||||
|
||||
Vec2 cross = fire_pos;
|
||||
// Vec2 cross = fire_pos;
|
||||
// Vec2 cross = MulAffineVec2(frame->af.screen_to_world, frame->look);
|
||||
|
||||
Vec2 cross = AddVec2(ent->xf.t, frame->look);
|
||||
|
||||
P_DebugDrawPoint(cross, Color_Red);
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ Struct(WND_Handle)
|
||||
Enum(WND_CursorKind)
|
||||
{
|
||||
WND_CursorKind_Default,
|
||||
WND_CursorKind_Hidden,
|
||||
WND_CursorKind_Text,
|
||||
WND_CursorKind_No,
|
||||
WND_CursorKind_Hand,
|
||||
@ -35,6 +36,7 @@ Enum(WND_CmdKind)
|
||||
WND_CmdKind_SetFullscreen,
|
||||
WND_CmdKind_SetForcedTop,
|
||||
WND_CmdKind_SetCursor,
|
||||
WND_CmdKind_SetLockedCursor,
|
||||
WND_CmdKind_Restore,
|
||||
};
|
||||
|
||||
|
||||
@ -226,17 +226,33 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
} break;
|
||||
|
||||
//- Cursor kind
|
||||
|
||||
case WM_SETCURSOR:
|
||||
{
|
||||
if ((HWND)wparam == hwnd && LOWORD(lparam) == HTCLIENT)
|
||||
{
|
||||
HCURSOR desired_cursor = (HCURSOR)Atomic64Fetch(&window->desired_cursor);
|
||||
b32 desired_cursor_hidden = !Atomic64Fetch(&window->desired_cursor_hidden);
|
||||
if (desired_cursor != window->active_cursor)
|
||||
{
|
||||
SetCursor(desired_cursor);
|
||||
window->active_cursor = desired_cursor;
|
||||
}
|
||||
if (desired_cursor_hidden != window->active_cursor_hidden)
|
||||
{
|
||||
if (desired_cursor_hidden)
|
||||
{
|
||||
while (ShowCursor(1) < 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (ShowCursor(0) >= 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
window->active_cursor_hidden = desired_cursor_hidden;
|
||||
}
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
@ -392,7 +408,7 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
i32 y = GET_Y_LPARAM(lparam);
|
||||
ControllerEvent event = Zi;
|
||||
event.kind = ControllerEventKind_CursorMove;
|
||||
event.cursor_pos = VEC2I32(x, y);
|
||||
event.cursor_pos = VEC2(x, y);
|
||||
WND_W32_PushEvent(window, event);
|
||||
} break;
|
||||
|
||||
@ -402,27 +418,28 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
// Read raw input buffer
|
||||
UINT buff_size;
|
||||
UINT buff_size = 0;
|
||||
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, 0, &buff_size, sizeof(RAWINPUTHEADER));
|
||||
u8 *buff = PushStructs(scratch.arena, u8, buff_size);
|
||||
if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, buff, &buff_size, sizeof(RAWINPUTHEADER)) != buff_size)
|
||||
if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, buff, &buff_size, sizeof(RAWINPUTHEADER)) == buff_size)
|
||||
{
|
||||
LogErrorF("GetRawInputData did not return correct size");
|
||||
break;
|
||||
}
|
||||
RAWINPUT raw = Zi;
|
||||
CopyBytes(&raw, buff, sizeof(RAWINPUT));
|
||||
|
||||
if (raw.header.dwType == RIM_TYPEMOUSE)
|
||||
{
|
||||
i32 x = raw.data.mouse.lLastX;
|
||||
i32 y = raw.data.mouse.lLastY;
|
||||
ControllerEvent event = Zi;
|
||||
event.kind = ControllerEventKind_MouseMove;
|
||||
event.mouse_delta = VEC2I32(x, y);
|
||||
event.mouse_delta = VEC2(x, y);
|
||||
WND_W32_PushEvent(window, event);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogErrorF("GetRawInputData did not return correct size");
|
||||
}
|
||||
}
|
||||
EndScratch(scratch);
|
||||
} break;
|
||||
}
|
||||
@ -579,6 +596,8 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
|
||||
|
||||
// Process cmds
|
||||
b32 was_restored = 0;
|
||||
b32 desires_locked_cursor = 0;
|
||||
b32 desires_hidden_cursor = 0;
|
||||
HCURSOR desired_cursor = (HCURSOR)Atomic64Fetch(&window->desired_cursor);
|
||||
for (WND_W32_CmdNode *n = window->first_cmd; n; n = n->next)
|
||||
{
|
||||
@ -649,10 +668,23 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
|
||||
SetWindowPos(hwnd, window->is_forced_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
} break;
|
||||
|
||||
//- Cursor
|
||||
//- Set cursor
|
||||
case WND_CmdKind_SetCursor:
|
||||
{
|
||||
if (cmd.cursor == WND_CursorKind_Hidden)
|
||||
{
|
||||
desires_hidden_cursor = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
desired_cursor = WND_W32.cursors[cmd.cursor];
|
||||
}
|
||||
} break;
|
||||
|
||||
//- Set locked cursor
|
||||
case WND_CmdKind_SetLockedCursor:
|
||||
{
|
||||
desires_locked_cursor = !!cmd.v;
|
||||
} break;
|
||||
|
||||
//- Restore
|
||||
@ -715,6 +747,62 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
|
||||
BringWindowToTop(hwnd);
|
||||
}
|
||||
|
||||
// Set/Clip/Hide cursor
|
||||
{
|
||||
RECT virtual_screen_rect = Zi;
|
||||
{
|
||||
virtual_screen_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
||||
virtual_screen_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
||||
virtual_screen_rect.right = virtual_screen_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||||
virtual_screen_rect.bottom = virtual_screen_rect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||||
}
|
||||
RECT client_screen_rect = Zi;
|
||||
{
|
||||
GetClientRect(hwnd, (LPRECT)&client_screen_rect);
|
||||
ClientToScreen(hwnd, (LPPOINT)&client_screen_rect.left);
|
||||
ClientToScreen(hwnd, (LPPOINT)&client_screen_rect.right);
|
||||
}
|
||||
b32 is_cursor_in_client_rect = 0;
|
||||
{
|
||||
POINT pos = Zi;
|
||||
GetCursorPos(&pos);
|
||||
is_cursor_in_client_rect = (
|
||||
pos.x >= client_screen_rect.left &&
|
||||
pos.x < client_screen_rect.right &&
|
||||
pos.y >= client_screen_rect.top &&
|
||||
pos.y < client_screen_rect.bottom
|
||||
);
|
||||
}
|
||||
RECT clipped_screen_rect = Zi;
|
||||
{
|
||||
GetClipCursor(&clipped_screen_rect);
|
||||
}
|
||||
|
||||
b32 is_cursor_clipped_any = !MatchStruct(&clipped_screen_rect, &virtual_screen_rect);
|
||||
b32 is_cursor_clipped_client = MatchStruct(&clipped_screen_rect, &client_screen_rect);
|
||||
|
||||
b32 final_desires_locked_cursor = desires_locked_cursor && frame.has_focus && is_cursor_in_client_rect;
|
||||
|
||||
// Clip cursor
|
||||
{
|
||||
if (final_desires_locked_cursor && !is_cursor_clipped_client)
|
||||
{
|
||||
RECT rect = Zi;
|
||||
{
|
||||
GetClientRect(hwnd, (LPRECT)&rect);
|
||||
ClientToScreen(hwnd, (LPPOINT)&rect.left);
|
||||
ClientToScreen(hwnd, (LPPOINT)&rect.right);
|
||||
}
|
||||
ClipCursor(&rect);
|
||||
}
|
||||
else if (!final_desires_locked_cursor && is_cursor_clipped_any)
|
||||
{
|
||||
ClipCursor(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (frame.has_focus)
|
||||
{
|
||||
// Set cursor
|
||||
{
|
||||
HCURSOR old_desired_cursor = (HCURSOR)Atomic64FetchSet(&window->desired_cursor, (i64)desired_cursor);
|
||||
@ -724,6 +812,18 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
|
||||
}
|
||||
}
|
||||
|
||||
// Hide cursor
|
||||
{
|
||||
b32 final_desires_hidden_cursor = desires_hidden_cursor && is_cursor_in_client_rect;
|
||||
b32 old_desired_cursor_hidden = !!Atomic64FetchSet(&window->desired_cursor_hidden, final_desires_hidden_cursor);
|
||||
if (old_desired_cursor_hidden != final_desires_hidden_cursor)
|
||||
{
|
||||
PostMessage(window->hwnd, WM_SETCURSOR, (WPARAM)window->hwnd, (LPARAM)HTCLIENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commit backbuffer
|
||||
G_CommitBackbuffer(frame.backbuffer, vsync);
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ Struct(WND_W32_Window)
|
||||
// Window proc state
|
||||
u16 previous_utf16_high_surrogate;
|
||||
HCURSOR active_cursor;
|
||||
b32 active_cursor_hidden;
|
||||
|
||||
// User state
|
||||
Arena *frame_arena;
|
||||
@ -27,6 +28,7 @@ Struct(WND_W32_Window)
|
||||
|
||||
// User -> Window proc
|
||||
Atomic64 desired_cursor;
|
||||
Atomic64 desired_cursor_hidden;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Loading…
Reference in New Issue
Block a user