123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- local ffi = require 'ffi'
- local C = ffi.os == 'Windows' and ffi.load('glfw3') or ffi.C
- ffi.cdef [[
- enum {
- GLFW_CURSOR = 0x00033001,
- GLFW_CURSOR_NORMAL = 0x00034001,
- GLFW_CURSOR_HIDDEN = 0x00034002,
- GLFW_CURSOR_DISABLED = 0x00034003,
- GLFW_ARROW_CURSOR = 0x00036001,
- GLFW_IBEAM_CURSOR = 0x00036002,
- GLFW_CROSSHAIR_CURSOR = 0x00036003,
- GLFW_HAND_CURSOR = 0x00036004,
- GLFW_HRESIZE_CURSOR = 0x00036005,
- GLFW_VRESIZE_CURSOR = 0x00036006
- };
- typedef struct {
- int width;
- int height;
- unsigned char* pixels;
- } GLFWimage;
- typedef struct GLFWcursor GLFWcursor;
- typedef struct GLFWwindow GLFWwindow;
- typedef void(*GLFWmousebuttonfun)(GLFWwindow*, int, int, int);
- typedef void(*GLFWcursorposfun)(GLFWwindow*, double, double);
- typedef void(*GLFWscrollfun)(GLFWwindow*, double, double);
- GLFWwindow* os_get_glfw_window(void);
- void glfwGetInputMode(GLFWwindow* window, int mode);
- void glfwSetInputMode(GLFWwindow* window, int mode, int value);
- void glfwGetCursorPos(GLFWwindow* window, double* x, double* y);
- void glfwSetCursorPos(GLFWwindow* window, double x, double y);
- GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot);
- GLFWcursor* glfwCreateStandardCursor(int kind);
- void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
- int glfwGetMouseButton(GLFWwindow* window, int button);
- void glfwGetWindowSize(GLFWwindow* window, int* width, int* height);
- GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun callback);
- GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun callback);
- GLFWcursorposfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback);
- ]]
- local window = ffi.C.os_get_glfw_window()
- local mouse = {}
- -- LÖVR uses framebuffer scale for everything, but glfw uses window scale for events.
- -- It is necessary to convert between the two at all boundaries.
- function mouse.getScale()
- local x, _ = ffi.new('int[1]'), ffi.new('int[1]')
- C.glfwGetWindowSize(window, x, _)
- return lovr.system.getWindowWidth() / x[0]
- end
- function mouse.getX()
- local x = ffi.new('double[1]')
- C.glfwGetCursorPos(window, x, nil)
- return x[0] * mouse.getScale()
- end
- function mouse.getY()
- local y = ffi.new('double[1]')
- C.glfwGetCursorPos(window, nil, y)
- return y[0] * mouse.getScale()
- end
- function mouse.getPosition()
- local x, y = ffi.new('double[1]'), ffi.new('double[1]')
- local scale = mouse.getScale()
- C.glfwGetCursorPos(window, x, y)
- return x[0] * scale, y[0] * scale
- end
- function mouse.setX(x)
- local y = mouse.getY()
- local scale = mouse.getScale()
- C.glfwSetCursorPos(window, x / scale, y / scale)
- end
- function mouse.setY(y)
- local x = mouse.getX()
- local scale = mouse.getScale()
- C.glfwSetCursorPos(window, x / scale, y / scale)
- end
- function mouse.setPosition(x, y)
- local scale = mouse.getScale()
- C.glfwSetCursorPos(window, x / scale, y / scale)
- end
- function mouse.isDown(button, ...)
- if not button then return false end
- return C.glfwGetMouseButton(window, button - 1) > 0 or mouse.isDown(...)
- end
- function mouse.getRelativeMode()
- return C.glfwGetInputMode(window, C.GLFW_CURSOR) == C.GLFW_CURSOR_DISABLED
- end
- function mouse.setRelativeMode(enable)
- C.glfwSetInputMode(window, C.GLFW_CURSOR, enable and C.GLFW_CURSOR_DISABLED or C.GLFW_CURSOR_NORMAL)
- end
- function mouse.newCursor(source, hotx, hoty)
- if type(source) == 'string' or tostring(source) == 'Blob' then
- source = lovr.data.newImage(source, false)
- else
- assert(tostring(source) == 'Image', 'Bad argument #1 to newCursor (Image expected)')
- end
- local image = ffi.new('GLFWimage', source:getWidth(), source:getHeight(), source:getPointer())
- return C.glfwCreateCursor(image, hotx or 0, hoty or 0)
- end
- function mouse.getSystemCursor(kind)
- local kinds = {
- arrow = C.GLFW_ARROW_CURSOR,
- ibeam = C.GLFW_IBEAM_CURSOR,
- crosshair = C.GLFW_CROSSHAIR_CURSOR,
- hand = C.GLFW_HAND_CURSOR,
- sizewe = C.GLFW_HRESIZE_CURSOR,
- sizens = C.GLFW_VRESIZE_CURSOR
- }
- assert(kinds[kind], string.format('Unknown cursor %q', tostring(kind)))
- return C.glfwCreateStandardCursor(kinds[kind])
- end
- function mouse.setCursor(cursor)
- C.glfwSetCursor(window, cursor)
- end
- C.glfwSetMouseButtonCallback(window, function(target, button, action, mods)
- if target == window then
- local x, y = mouse.getPosition()
- lovr.event.push(action > 0 and 'mousepressed' or 'mousereleased', x, y, button + 1, false)
- end
- end)
- local px, py = mouse.getPosition()
- C.glfwSetCursorPosCallback(window, function(target, x, y)
- if target == window then
- local scale = mouse.getScale()
- x = x * scale
- y = y * scale
- lovr.event.push('mousemoved', x, y, x - px, y - py, false)
- px, py = x, y
- end
- end)
- C.glfwSetScrollCallback(window, function(target, x, y)
- if target == window then
- local scale = mouse.getScale()
- lovr.event.push('wheelmoved', x * scale, y * scale)
- end
- end)
- return mouse
|