Controller and camera

June 26, 2026 ยท View on GitHub

How the manual camera works and which input sources drive it.

Manual camera (Auto camera mode)

In exterior scenes with Auto camera (FollowCamera) on, the player can orbit, tilt, and zoom the follow camera. Every manual source feeds one shared routine, ApplyManualCameraNudge in SOURCES/EXTFUNC.CPP, which applies and clamps three axes and re-engages the auto-follow grace period:

AxisVariableBound
Horizontal orbitAddBetaCamwraps mod 4096
ElevationAlphaCamFOLLOW_CAM_ALPHA_MIN..MAX
Zoom (dolly)FollowCamBaseDistFOLLOW_CAM_DIST_MIN..MAX

Only horizontal orbit raises ManualCameraOrbitActive, which switches PERSO.CPP to a tight rotation lerp for a responsive feel while the player is actively turning. On release the camera drifts back behind the hero after FOLLOW_CAM_REENGAGE_FRAMES (tunables in FOLLOWCAM_CFG.H).

Manual camera is exterior plus Auto camera only. Interior scenes and the classic fixed cameras have no orbit to drive.

Input sources

Keyboard

[ / ] orbit, numpad + / - tilt elevation, numpad * / / zoom. Handled directly in GereExtKeys.

Mouse

Right-drag (or free move) orbits and tilts, the wheel zooms, and middle-click recenters behind the hero. Tunables in lba2.cfg:

KeyDefaultDescription
MouseCamera1enable (0 = off)
MouseCameraDrag11 = right-drag to orbit, 0 = free orbit on move
MouseSensitivityX4horizontal orbit speed (1-10)
MouseSensitivityY4elevation speed (1-10)
MouseInvertY0invert elevation axis
MouseCameraDivisor4pixel-to-angle scaling (lower = faster, 1-16)
MouseCameraSmoothing2orbit lerp (1 = snap, higher = laggier, 1-16)

Gamepad right stick

In exterior Auto camera scenes the right stick orbits and tilts the camera through the same ApplyManualCameraNudge routine as the mouse. While it owns the stick, UpdateJoystick (SOURCES/JOYSTICK.CPP) stops emitting the digital RSTICK_* scancodes so the analog path and the bindings never double-drive. Outside Auto camera (the classic fixed cameras) the stick falls back to the digital bindings: left/right cycle the camera (I_CAMERA), up/down change the camera preset (I_CAMERA_LEVEL). Tunables in lba2.cfg:

KeyDefaultDescription
GamepadCameraAnalog1analog right-stick camera in Auto cam (0 = digital bindings only)
GamepadCameraSensX5orbit sensitivity (1-10)
GamepadCameraSensY5elevation sensitivity (1-10)
GamepadCameraInvertY0invert elevation axis

The deadzone is shared with the rest of the gamepad (GamepadDeadzone). There is no stick zoom: the triggers are movement and the remaining buttons are bound, so zoom stays on the keyboard and mouse.

Live tuning (console cvars)

Open the console (default F12) to tune the camera live. name shows a value (bools toggle), name value sets it. Values are not clamped on set, so you can explore past the official ranges while tuning; they clamp on cfg load, and changes persist to lba2.cfg on exit. varlist lists them; tab completes names.

cvarsetting
cam_stick_x / cam_stick_yright-stick orbit / elevation sensitivity (1-10)
cam_stick_invertinvert right-stick elevation
cam_stick_analoganalog right-stick camera in Auto cam (off = digital bindings)
cam_stick_max_x / cam_stick_max_yright-stick orbit / elevation speed ceiling (at sens 10)
pad_deadzonegamepad stick deadzone (SDL units)
cam_mouse / cam_mouse_dragmouse camera enable / right-drag vs free orbit
cam_mouse_x / cam_mouse_ymouse orbit / elevation sensitivity (1-10)
cam_mouse_invert / cam_mouse_divinvert mouse elevation / pixel-to-angle divisor
cam_smoothmanual orbit lerp (1 = snap, higher = laggier)
cam_recenter_delayframes before Auto cam re-centers after a manual pan
cam_recenter_driftre-center drift divisor (higher = gentler)

The cam_stick_max_* ceilings, cam_recenter_delay, and cam_recenter_drift were the constants that previously needed a recompile to tune; they are now live.