bool cursor_on_shape(Matrix4 const& model_view_projection, std::vector<Vector3> const& vertices, Vector2 const& cursor) { for (int i = 0; i < vertices.size(); i+=3) { Vector2 p0 = point_on_screen(model_view_projection, vertices[i+0]); Vector2 p1 = point_on_screen(model_view_projection, vertices[i+1]); Vector2 p2 = point_on_screen(model_view_projection, vertices[i+2]); if (area(p0, p1, cursor) <= 0.0f && area(p1, p2, cursor) <= 0.0f && area(p2, p0, cursor) <= 0.0f) { return true; } } return false; }
Rect2 rect_on_screen(Matrix4 const& view_projection, std::vector<Vector3> const& vertices) { Vector2 p = point_on_screen(view_projection, vertices[0]); Vector2 min = p; Vector2 max = p; for (Vector3 const& v : vertices) { p = point_on_screen(view_projection, v); min = minimum(min, p); max = maximum(max, p); } return Rect2{min, max - min}; }
/** * Set the devices' cursor position to the given x/y position. * * This function is called during the pointer update path in * GetPointerEvents and friends (and the same in the xwin DDX). * * The coordinates provided are always absolute. The parameter mode whether * it was relative or absolute movement that landed us at those coordinates. * * @param pDev The device to move * @param mode Movement mode (Absolute or Relative) * @param[in,out] screenx The x coordinate in desktop coordinates * @param[in,out] screeny The y coordinate in desktop coordinates */ ScreenPtr miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx, double *screeny, int *nevents, InternalEvent* events) { miPointerScreenPtr pScreenPriv; ScreenPtr pScreen; ScreenPtr newScreen; int x, y; Bool switch_screen = FALSE; Bool should_constrain_barriers = FALSE; int i; miPointerPtr pPointer; pPointer = MIPOINTER(pDev); pScreen = pPointer->pScreen; x = trunc(*screenx); y = trunc(*screeny); switch_screen = !point_on_screen(pScreen, x, y); /* Switch to per-screen coordinates for CursorOffScreen and * Pointer->limits */ x -= pScreen->x; y -= pScreen->y; should_constrain_barriers = (mode == Relative); if (should_constrain_barriers) { /* coordinates after clamped to a barrier */ int constrained_x, constrained_y; int current_x, current_y; /* current position in per-screen coord */ current_x = MIPOINTER(pDev)->x - pScreen->y; current_y = MIPOINTER(pDev)->y - pScreen->x; input_constrain_cursor(pDev, pScreen, current_x, current_y, x, y, &constrained_x, &constrained_y, nevents, events); x = constrained_x; y = constrained_y; } if (switch_screen) { pScreenPriv = GetScreenPrivate(pScreen); if (!pPointer->confined) { newScreen = pScreen; (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y); if (newScreen != pScreen) { pScreen = newScreen; (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE); /* Smash the confine to the new screen */ pPointer->limits.x2 = pScreen->width; pPointer->limits.y2 = pScreen->height; } } } /* Constrain the sprite to the current limits. */ if (x < pPointer->limits.x1) x = pPointer->limits.x1; if (x >= pPointer->limits.x2) x = pPointer->limits.x2 - 1; if (y < pPointer->limits.y1) y = pPointer->limits.y1; if (y >= pPointer->limits.y2) y = pPointer->limits.y2 - 1; if (pScreen->ConstrainCursorHarder) pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y); if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen) miPointerMoveNoEvent(pDev, pScreen, x, y); /* check if we generated any barrier events and if so, update root x/y * to the fully constrained coords */ if (should_constrain_barriers) { for (i = 0; i < *nevents; i++) { if (events[i].any.type == ET_BarrierHit || events[i].any.type == ET_BarrierLeave) { events[i].barrier_event.root_x = x; events[i].barrier_event.root_y = y; } } } /* Convert to desktop coordinates again */ x += pScreen->x; y += pScreen->y; /* In the event we actually change screen or we get confined, we just * drop the float component on the floor * FIXME: only drop remainder for ConstrainCursorHarder, not for screen * crossings */ if (x != trunc(*screenx)) *screenx = x; if (y != trunc(*screeny)) *screeny = y; return pScreen; }
/** * Set the devices' cursor position to the given x/y position. * * This function is called during the pointer update path in * GetPointerEvents and friends (and the same in the xwin DDX). * * The coordinates provided are always absolute. The parameter mode whether * it was relative or absolute movement that landed us at those coordinates. * * @param pDev The device to move * @param mode Movement mode (Absolute or Relative) * @param[in,out] screenx The x coordinate in desktop coordinates * @param[in,out] screeny The y coordinate in desktop coordinates */ ScreenPtr miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx, double *screeny) { miPointerScreenPtr pScreenPriv; ScreenPtr pScreen; ScreenPtr newScreen; int x, y; Bool switch_screen = FALSE; miPointerPtr pPointer; if (!pDev || !pDev->coreEvents) return NULL; pPointer = MIPOINTER(pDev); pScreen = pPointer->pScreen; if (!pScreen) return NULL; /* called before ready */ x = trunc(*screenx); y = trunc(*screeny); switch_screen = !point_on_screen(pScreen, x, y); /* Switch to per-screen coordinates for CursorOffScreen and * Pointer->limits */ x -= pScreen->x; y -= pScreen->y; if (switch_screen) { pScreenPriv = GetScreenPrivate (pScreen); if (!pPointer->confined) { newScreen = pScreen; (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y); if (newScreen != pScreen) { pScreen = newScreen; (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE); /* Smash the confine to the new screen */ pPointer->limits.x2 = pScreen->width; pPointer->limits.y2 = pScreen->height; } } } /* Constrain the sprite to the current limits. */ if (x < pPointer->limits.x1) x = pPointer->limits.x1; if (x >= pPointer->limits.x2) x = pPointer->limits.x2 - 1; if (y < pPointer->limits.y1) y = pPointer->limits.y1; if (y >= pPointer->limits.y2) y = pPointer->limits.y2 - 1; if (pScreen->ConstrainCursorHarder) pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y); if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen) miPointerMoveNoEvent(pDev, pScreen, x, y); /* Convert to desktop coordinates again */ x += pScreen->x; y += pScreen->y; /* In the event we actually change screen or we get confined, we just * drop the float component on the floor * FIXME: only drop remainder for ConstrainCursorHarder, not for screen * crossings */ if (x != trunc(*screenx)) *screenx = x; if (y != trunc(*screeny)) *screeny = y; return pScreen; }