Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,585 @@
|
||||
//input.as
|
||||
//--------
|
||||
//Various script callbacks for global input handling.
|
||||
//Also handles passing events to the GUI
|
||||
|
||||
#priority init 1
|
||||
import elements.IGuiElement;
|
||||
import targeting.targeting;
|
||||
import navigation.SmartCamera;
|
||||
import util.convar;
|
||||
from navigation.elevation import getElevationIntersect;
|
||||
|
||||
import bool onMouseEvent(const MouseEvent&) from "gui";
|
||||
import bool onKeyboardEvent(const KeyboardEvent&) from "gui";
|
||||
import bool onGuiEvent(const GuiEvent&) from "gui";
|
||||
import void onGuiNavigate(vec2d direction) from "gui";
|
||||
import IGuiElement@ getGuiFocus() from "gui";
|
||||
import bool isGuiHovered() from "gui";
|
||||
import void selectionClick(uint button, bool pressed) from "obj_selection";
|
||||
import void dragSelect(const recti&) from "obj_selection";
|
||||
import Object@ get_hoveredObject() from "obj_selection";
|
||||
import Object@ get_selectedObject() from "obj_selection";
|
||||
import Object@ get_uiObject() from "obj_selection";
|
||||
import void updateHoveredObject() from "obj_selection";
|
||||
import bool objectKeyEvent(int key, bool pressed) from "commands";
|
||||
import void switchToTab(int pos) from "tabs.tabbar";
|
||||
import bool tabEscape() from "tabs.tabbar";
|
||||
import double getAverageElevation() from "navigation.elevation";
|
||||
|
||||
ConVar FollowAI("follow_ai", 0);
|
||||
|
||||
//TODO: Anything directly using the engine camera should go through the camera module
|
||||
|
||||
const double tickZoom = 1.2;
|
||||
const double zoomPerPixel = 0.01;
|
||||
const double camAnglesPerPixel = 0.22 * twopi / 360.0;
|
||||
const double movePerPixel = 0.001;
|
||||
const double zoomPerSecond = 0.45;
|
||||
const double rollBorder = 0.4;
|
||||
const double camMotionPerSecond = 80.0;
|
||||
|
||||
vec2i dragArea, dragFrom;
|
||||
array<double> edgePanDelay = {0.0, 0.0, 0.0, 0.0};
|
||||
array<double> edgePanRampup = {0.3, 0.3, 0.3, 0.3};
|
||||
array<double> edgePanTimers = {0.0, 0.0, 0.0, 0.0};
|
||||
bool doingBoxSelect = false;
|
||||
|
||||
Joystick joystick(1);
|
||||
bool joystickConnected = false;
|
||||
bool joystickActive = false;
|
||||
|
||||
SmartCamera@ ActiveCamera;
|
||||
SmartCamera PreviousCamera;
|
||||
|
||||
SmartCamera@ get_activeCamera() {
|
||||
return ActiveCamera;
|
||||
}
|
||||
|
||||
SmartCamera@ get_lastCamera() {
|
||||
if(ActiveCamera !is null)
|
||||
return ActiveCamera;
|
||||
return PreviousCamera;
|
||||
}
|
||||
|
||||
void set_activeCamera(SmartCamera@ cam) {
|
||||
if(ActiveCamera !is null)
|
||||
PreviousCamera = ActiveCamera;
|
||||
|
||||
@ActiveCamera = cam;
|
||||
}
|
||||
|
||||
void copyPreviousCamera(SmartCamera@ cam) {
|
||||
if(ActiveCamera !is null)
|
||||
cam = ActiveCamera;
|
||||
else
|
||||
cam = PreviousCamera;
|
||||
}
|
||||
|
||||
vec3d mouseToGrid(vec2i mpos) {
|
||||
double plane = getAverageElevation();
|
||||
vec3d dest;
|
||||
line3dd ray = ActiveCamera.screenToRay(mpos);
|
||||
if(!getElevationIntersect(ray, dest))
|
||||
ray.intersectY(dest, plane, false);
|
||||
return dest;
|
||||
}
|
||||
|
||||
vec3d mouseToGrid(vec2i mpos, double plane) {
|
||||
vec3d dest;
|
||||
line3dd ray = ActiveCamera.screenToRay(mpos);
|
||||
if(!getElevationIntersect(ray, dest))
|
||||
ray.intersectY(dest, plane, false);
|
||||
return dest;
|
||||
}
|
||||
|
||||
void take_screenshot(bool pressed) {
|
||||
if(!pressed)
|
||||
takeScreenshot("screenshot");
|
||||
}
|
||||
|
||||
//Called when the platform overlay (e.g. Steam Overlay) is opened or closed
|
||||
double prevGameSpeed = 1.0;
|
||||
void onOverlayChanged(bool overlayOpen) {
|
||||
if(!mpServer && !mpClient) {
|
||||
if(overlayOpen) {
|
||||
prevGameSpeed = gameSpeed;
|
||||
gameSpeed = 0.0;
|
||||
}
|
||||
else {
|
||||
gameSpeed = prevGameSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Called whenever the mouse wheel is used on the 3D view.
|
||||
// x: Amount scrolled horizontally.
|
||||
// y: Amount scrolled vertically.
|
||||
void onMouseWheel(double x, double y) {
|
||||
if(isGuiHovered() || ActiveCamera is null) {
|
||||
MouseEvent evt;
|
||||
evt.type = MET_Scrolled;
|
||||
evt.x = int(floor(x));
|
||||
evt.y = int(floor(y));
|
||||
onMouseEvent(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
if(targetMouseWheel(x, y))
|
||||
return;
|
||||
|
||||
activeCamera.zoom(y);
|
||||
}
|
||||
|
||||
//Called when the mouse is dragged with one or more buttons
|
||||
//pressed on the 3D view.
|
||||
// buttons: Bitmask of pressed buttons (0x1 << button_num)
|
||||
// x: Mouse x position.
|
||||
// y: Mouse y position.
|
||||
// dx: Movement in the x dimension since last event.
|
||||
// dy: Movement in the y dimension since last event.
|
||||
void onMouseDragged(int buttons, int x, int y, int dx, int dy) {
|
||||
if(activeCamera is null)
|
||||
return;
|
||||
if(targetMouseDragged(buttons, x, y, dx, dy))
|
||||
return;
|
||||
|
||||
Camera@ cam = activeCamera.camera;
|
||||
vec2i screen = screenSize;
|
||||
|
||||
if(buttons == 0x1) {
|
||||
doingBoxSelect = true;
|
||||
dragArea += vec2i(dx,-dy);
|
||||
dragFrom = vec2i(x,y);
|
||||
}
|
||||
else if(buttons == 0x2) {
|
||||
double dist = sqrt(sqr(double(x)/double(screen.x) - 0.5)
|
||||
+ sqr(double(y)/double(screen.y) - 0.5));
|
||||
|
||||
if(settings::bEdgeRoll && rollBorder < dist) {
|
||||
if(x < screen.x / 2)
|
||||
activeCamera.roll(dy);
|
||||
else
|
||||
activeCamera.roll(-dy);
|
||||
}
|
||||
else {
|
||||
activeCamera.rotate(dx, dy);
|
||||
}
|
||||
}
|
||||
else if(buttons == 0x3) {
|
||||
//-- Left and right buttons
|
||||
if(settings::bInvertHorizRot)
|
||||
dx = -dx;
|
||||
|
||||
//Horizontal movement does an absolute yaw
|
||||
if(cam.inverted)
|
||||
cam.abs_yaw(double(-dx) * camAnglesPerPixel);
|
||||
else
|
||||
cam.abs_yaw(double(dx) * camAnglesPerPixel);
|
||||
|
||||
//Vertical movement zooms
|
||||
cam.zoom(1.0 + zoomPerPixel * double(-dy));
|
||||
CAM_ZOOMED = true;
|
||||
}
|
||||
else if(buttons == 0x4) {
|
||||
//-- Only middle button
|
||||
//Pan the world
|
||||
activeCamera.pan(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
//Called when a drag event thas ended
|
||||
bool onMouseDragEnd(int button) {
|
||||
if(targetMouseDragEnd(button))
|
||||
return true;
|
||||
if(doingBoxSelect) {
|
||||
if(button != 0) {
|
||||
doingBoxSelect = false;
|
||||
return false;
|
||||
}
|
||||
recti box = recti_area(dragFrom, dragArea);
|
||||
|
||||
//Make sure the rect is oriented top-down, left-right
|
||||
if(box.topLeft.x > box.botRight.x) {
|
||||
int temp = box.topLeft.x;
|
||||
box.topLeft.x = box.botRight.x;
|
||||
box.botRight.x = temp;
|
||||
}
|
||||
if(box.topLeft.y > box.botRight.y) {
|
||||
int temp = box.topLeft.y;
|
||||
box.topLeft.y = box.botRight.y;
|
||||
box.botRight.y = temp;
|
||||
}
|
||||
|
||||
dragSelect(box);
|
||||
|
||||
//Place the cursor to the dragged destination
|
||||
doingBoxSelect = false;
|
||||
mousePos = dragFrom + dragArea;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//Called when the mouse is moved over the 3d view without
|
||||
//any buttons being held.
|
||||
// x: Mouse x position.
|
||||
// y: Mouse y position.
|
||||
void onMouseMoved(int x, int y) {
|
||||
MouseEvent evt;
|
||||
evt.type = MET_Moved;
|
||||
evt.x = x;
|
||||
evt.y = y;
|
||||
if(onMouseEvent(evt))
|
||||
return;
|
||||
if(targetMouseMoved(x, y))
|
||||
return;
|
||||
}
|
||||
|
||||
//Called when a mouse button is clicked
|
||||
// buttons: Button that was clicked.
|
||||
//void onMouseClicked(int button) {
|
||||
//}
|
||||
|
||||
//Called when a mouse button is double-clicked
|
||||
// buttons: Button that was clicked.
|
||||
//void onMouseDoubleClicked(int button) {
|
||||
//}
|
||||
|
||||
//General handler for when a mouse button event occurs
|
||||
// button: Button that the event pertains to.
|
||||
// pressed: Whether the button was pressed or released.
|
||||
bool onMouseButton(int button, bool pressed) {
|
||||
MouseEvent evt;
|
||||
if(pressed)
|
||||
evt.type = MET_Button_Down;
|
||||
else
|
||||
evt.type = MET_Button_Up;
|
||||
evt.button = button;
|
||||
vec2i mpos = mousePos;
|
||||
evt.x = mpos.x;
|
||||
evt.y = mpos.y;
|
||||
|
||||
bool fromTarget = uiObject !is null;
|
||||
if(fromTarget && targetMouseButton(button, pressed))
|
||||
return false;
|
||||
if(onMouseEvent(evt))
|
||||
return true;
|
||||
if(!fromTarget && targetMouseButton(button, pressed))
|
||||
return false;
|
||||
if(pressed)
|
||||
dragArea = vec2i(0,0);
|
||||
selectionClick(button, pressed);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Called when a unicode char is typed into the main 3D view.
|
||||
// chr: Unicode code point that was typed.
|
||||
bool onCharTyped(int chr) {
|
||||
KeyboardEvent evt;
|
||||
evt.type = KET_Key_Typed;
|
||||
evt.key = chr;
|
||||
return onKeyboardEvent(evt);
|
||||
}
|
||||
|
||||
//Called when a key event occurs when the 3D view has focus.
|
||||
// key: Keyboard key that was pressed.
|
||||
// pressed: Whether the key was pressed or released.
|
||||
bool onKeyEvent(int key, int keyaction) {
|
||||
KeyboardEvent evt;
|
||||
bool pressed = (keyaction & KA_Pressed) != 0;
|
||||
if(pressed)
|
||||
evt.type = KET_Key_Down;
|
||||
else
|
||||
evt.type = KET_Key_Up;
|
||||
evt.key = key;
|
||||
if(onKeyboardEvent(evt))
|
||||
return true;
|
||||
if(objectKeyEvent(key, pressed))
|
||||
return true;
|
||||
if(targetKeyEvent(key, pressed))
|
||||
return true;
|
||||
if(pressed && key == KEY_ESC) {
|
||||
if(tabEscape())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint[] worldMove = {0, 0, 0, 0};
|
||||
void world_forward(bool pressed) {
|
||||
worldMove[3] = pressed ? 1 : 0;
|
||||
}
|
||||
|
||||
void world_left(bool pressed) {
|
||||
worldMove[0] = pressed ? 1 : 0;
|
||||
}
|
||||
|
||||
void world_right(bool pressed) {
|
||||
worldMove[2] = pressed ? 1 : 0;
|
||||
}
|
||||
|
||||
void world_backward(bool pressed) {
|
||||
worldMove[1] = pressed ? 1 : 0;
|
||||
}
|
||||
|
||||
void reset_cam(bool pressed) {
|
||||
if(!pressed && activeCamera !is null) {
|
||||
Camera@ cam = activeCamera.camera;
|
||||
activeCamera.reset();
|
||||
Object@ hw = playerEmpire.Homeworld;
|
||||
if(hw is null)
|
||||
@hw = selectedObject;
|
||||
if(hw !is null)
|
||||
activeCamera.zoomTo(hw);
|
||||
else
|
||||
activeCamera.zoomTo(vec3d());
|
||||
cam.snap();
|
||||
}
|
||||
}
|
||||
|
||||
uint[] zoom = {0, 0};
|
||||
void zoom_in(bool pressed) {
|
||||
zoom[0] = pressed ? 1 : 0;
|
||||
}
|
||||
|
||||
void zoom_out(bool pressed) {
|
||||
zoom[1] = pressed ? 1 : 0;
|
||||
}
|
||||
|
||||
void zoom_object(bool pressed) {
|
||||
if(!pressed && ActiveCamera !is null) {
|
||||
Object@ sel = selectedObject;
|
||||
if(sel !is null && sel.visible)
|
||||
ActiveCamera.zoomLockObject(sel);
|
||||
}
|
||||
}
|
||||
|
||||
double threshold(double x, double thresh) {
|
||||
if(abs(x) < thresh)
|
||||
return 0.0;
|
||||
else
|
||||
return x;
|
||||
}
|
||||
|
||||
bool leftCannon = false;
|
||||
bool movePressed = false;
|
||||
|
||||
void onControllerButton(int i, bool pressed) {
|
||||
joystickActive = true;
|
||||
if(pressed) {
|
||||
if(i == GP_LB)
|
||||
switchToTab(-1);
|
||||
else if(i == GP_RB)
|
||||
switchToTab(+1);
|
||||
}
|
||||
}
|
||||
|
||||
GuiEvent joyGuiEvent;
|
||||
|
||||
vec3d lastAIFocus;
|
||||
|
||||
void tick(double time) {
|
||||
if(game_state != GS_Game)
|
||||
return;
|
||||
|
||||
if(FollowAI.value != 0) {
|
||||
vec3d to = playerEmpire.aiFocus;
|
||||
if(to != lastAIFocus) {
|
||||
activeCamera.zoomTo(to);
|
||||
lastAIFocus = to;
|
||||
}
|
||||
}
|
||||
|
||||
double tickMotion = time * camMotionPerSecond * 60.0;
|
||||
|
||||
//Polling a disconnected joystick on Windows takes ~10ms, so avoid it
|
||||
if(joystickConnected && joystick.poll()) {
|
||||
//Send buttons to gui
|
||||
for(uint i = 0, cnt = joystick.buttonCount; i < cnt; ++i) {
|
||||
uint8 state = joystick.button[i];
|
||||
if(state == JBS_Pressed) {
|
||||
//GUI Event
|
||||
joyGuiEvent.type = GUI_Controller_Down;
|
||||
joyGuiEvent.value = i;
|
||||
@joyGuiEvent.caller = getGuiFocus();
|
||||
if(!onGuiEvent(joyGuiEvent))
|
||||
onControllerButton(i, true);
|
||||
}
|
||||
else if(state == JBS_Released) {
|
||||
//GUI Event
|
||||
joyGuiEvent.type = GUI_Controller_Up;
|
||||
joyGuiEvent.value = i;
|
||||
@joyGuiEvent.caller = getGuiFocus();
|
||||
if(!onGuiEvent(joyGuiEvent))
|
||||
onControllerButton(i, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(activeCamera !is null) {
|
||||
//Panning with left analog
|
||||
vec2d pan = vec2d(-joystick.axis[GP_AXIS_LX], joystick.axis[GP_AXIS_LY]);
|
||||
if(pan.length > 0.05) {
|
||||
pan.normalize(tickMotion * 0.7);
|
||||
activeCamera.pan(pan);
|
||||
mousePos = screenSize * 0.5;
|
||||
joystickActive = true;
|
||||
}
|
||||
|
||||
//Zoom and rotate with right analog
|
||||
double zoom = -joystick.axis[GP_AXIS_RY];
|
||||
if(abs(zoom) > 0)
|
||||
activeCamera.camera.zoom(1.0 + 7.0 * zoomPerSecond * zoom * time * settings::dZoomSpeed);
|
||||
|
||||
double yaw = -joystick.axis[GP_AXIS_RX];
|
||||
if(abs(yaw) > 0)
|
||||
activeCamera.rotate(600.0 * yaw * time, 0);
|
||||
}
|
||||
else {
|
||||
//Navigate gui with left stick
|
||||
vec2d dir = vec2d(joystick.axis[GP_AXIS_LX], -joystick.axis[GP_AXIS_LY]);
|
||||
if(dir.length > 0.25) {
|
||||
if(!movePressed)
|
||||
onGuiNavigate(dir);
|
||||
movePressed = true;
|
||||
}
|
||||
else {
|
||||
movePressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*for(uint i = 0; i < joystick.buttonCount; ++i) {
|
||||
uint8 state = joystick.button[i];
|
||||
if(state == JBS_Pressed)
|
||||
print("Joystick 1, key " + i + " pressed");
|
||||
else if(state == JBS_Released)
|
||||
print("Joystick 1, key " + i + " released");
|
||||
}
|
||||
|
||||
for(uint i = 0; i < joystick.axisCount; ++i) {
|
||||
double axis = joystick.axis[i];
|
||||
if(abs(axis) > 0.01)
|
||||
print("Joystick axis " + i + ": " + axis);
|
||||
}*/
|
||||
|
||||
if(joystickActive)
|
||||
updateHoveredObject();
|
||||
}
|
||||
|
||||
if(activeCamera is null)
|
||||
return;
|
||||
|
||||
Camera@ cam = activeCamera.camera;
|
||||
bool inverted = cam.inverted;
|
||||
|
||||
vec2d move;
|
||||
|
||||
//Handle edge panning
|
||||
vec2i mouse = mousePos;
|
||||
if(settings::bEdgePan && windowFocused && mouseOverWindow) {
|
||||
vec2i screen = screenSize;
|
||||
|
||||
if(mouse.x <= 0) {
|
||||
edgePanTimers[0] += time;
|
||||
if(edgePanTimers[0] >= edgePanDelay[0]) {
|
||||
move.x += 1;
|
||||
if(edgePanRampup[0] > 0)
|
||||
tickMotion *= clamp((edgePanTimers[0] - edgePanDelay[0]) / edgePanRampup[0], 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
edgePanTimers[0] = 0.0;
|
||||
}
|
||||
|
||||
if(mouse.x >= screen.x - 2) {
|
||||
edgePanTimers[1] += time;
|
||||
if(edgePanTimers[1] >= edgePanDelay[1]) {
|
||||
move.x -= 1;
|
||||
if(edgePanRampup[1] > 0)
|
||||
tickMotion *= clamp((edgePanTimers[1] - edgePanDelay[1]) / edgePanRampup[1], 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
edgePanTimers[1] = 0.0;
|
||||
}
|
||||
|
||||
if(mouse.y <= 0) {
|
||||
edgePanTimers[2] += time;
|
||||
if(edgePanTimers[2] >= edgePanDelay[2]) {
|
||||
move.y += 1;
|
||||
if(edgePanRampup[2] > 0)
|
||||
tickMotion *= clamp((edgePanTimers[2] - edgePanDelay[2]) / edgePanRampup[2], 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
edgePanTimers[2] = 0.0;
|
||||
}
|
||||
|
||||
if(mouse.y >= screen.y - 2) {
|
||||
edgePanTimers[3] += time;
|
||||
if(edgePanTimers[3] >= edgePanDelay[3]) {
|
||||
move.y -= 1;
|
||||
if(edgePanRampup[0] > 0)
|
||||
tickMotion *= clamp((edgePanTimers[3] - edgePanDelay[3]) / edgePanRampup[3], 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
edgePanTimers[3] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
//Move the world in the direction the keys were pressed
|
||||
if(worldMove[0] ^ worldMove[2] != 0) {
|
||||
if(worldMove[0] != 0)
|
||||
move.x += 1;
|
||||
else
|
||||
move.x += -1;
|
||||
}
|
||||
if(worldMove[1] ^ worldMove[3] != 0) {
|
||||
if(worldMove[1] != 0)
|
||||
move.y += -1;
|
||||
else
|
||||
move.y += 1;
|
||||
}
|
||||
|
||||
if(move.x != 0 || move.y != 0) {
|
||||
move.normalize(tickMotion);
|
||||
activeCamera.pan(move);
|
||||
}
|
||||
|
||||
//Zoom the camera appropriately
|
||||
if(zoom[0] ^ zoom[1] != 0) {
|
||||
if(zoom[0] != 0)
|
||||
cam.zoom(1.0 - zoomPerSecond * time * settings::dZoomSpeed);
|
||||
else
|
||||
cam.zoom(1.0 + zoomPerSecond * time * settings::dZoomSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
void init() {
|
||||
keybinds::Global.addBind(KB_WORLD_FORWARD, "world_forward");
|
||||
keybinds::Global.addBind(KB_WORLD_LEFT, "world_left");
|
||||
keybinds::Global.addBind(KB_WORLD_RIGHT, "world_right");
|
||||
keybinds::Global.addBind(KB_WORLD_BACKWARD, "world_backward");
|
||||
|
||||
keybinds::Global.addBind(KB_ZOOM_IN, "zoom_in");
|
||||
keybinds::Global.addBind(KB_ZOOM_OUT, "zoom_out");
|
||||
|
||||
keybinds::Global.addBind(KB_RESET_CAM, "reset_cam");
|
||||
keybinds::Global.addBind(KB_TAKE_SCREENSHOT, "take_screenshot");
|
||||
|
||||
keybinds::Global.addBind(KB_ZOOM_LOCK_OBJECT, "zoom_object");
|
||||
|
||||
//joystickConnected = joystick.connected();
|
||||
PreviousCamera.reset();
|
||||
|
||||
if(settings::bDelayTopEdge) {
|
||||
edgePanDelay[2] = 0.3;
|
||||
edgePanRampup[2] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if(doingBoxSelect)
|
||||
drawRectangle(recti_area(dragFrom, dragArea), Color(0x00ff0040));
|
||||
}
|
||||
Reference in New Issue
Block a user