diff options
Diffstat (limited to 'src/core.c')
| -rw-r--r-- | src/core.c | 315 |
1 files changed, 260 insertions, 55 deletions
@@ -8,6 +8,7 @@ * PLATFORM_DESKTOP - Windows, Linux, Mac (OSX) * PLATFORM_ANDROID - Only OpenGL ES 2.0 devices * PLATFORM_RPI - Rapsberry Pi (tested on Raspbian) +* PLATFORM_WEB - Emscripten, HTML5 * * On PLATFORM_DESKTOP, the external lib GLFW3 (www.glfw.com) is used to manage graphic * device, OpenGL context and input on multiple operating systems (Windows, Linux, OSX). @@ -49,7 +50,7 @@ #include <string.h> // String function definitions, memset() #include <errno.h> // Macros for reporting and retrieving error conditions through error codes -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management //#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h) //#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version! @@ -91,7 +92,7 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -// ... +#define MAX_TOUCH_POINTS 256 //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -101,7 +102,7 @@ //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) static GLFWwindow *window; // Native window (graphic device) #elif defined(PLATFORM_ANDROID) static struct android_app *app; // Android activity @@ -111,7 +112,14 @@ static bool windowReady = false; // Used to detect display initia // Gestures detection variables static float tapTouchX, tapTouchY; +static int64_t lastTapTime = 0; +static float lastTapX = 0, lastTapY = 0; static bool touchTap = false; +static bool doubleTap = false; +static bool drag = false; +static int stdVector[MAX_TOUCH_POINTS]; +static int indexPosition = 0; +const AInputEvent* eventDrag; static int32_t touchId; const int32_t DOUBLE_TAP_TIMEOUT = 300*1000000; const int32_t DOUBLE_TAP_SLOP = 100; @@ -160,12 +168,12 @@ static int renderOffsetY = 0; // Offset Y from render area (must b static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP) static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) static const char *windowTitle; // Window text title... static char configFlags = 0; static bool customCursor = false; // Tracks if custom cursor has been set -static bool cursorOnScreen = true; // Tracks if cursor is inside client area +static bool cursorOnScreen = false; // Tracks if cursor is inside client area static Texture2D cursor; // Cursor texture static Vector2 mousePosition; @@ -183,6 +191,7 @@ static int previousMouseWheelY = 0; // Required to track mouse wheel var static int currentMouseWheelY = 0; // Required to track mouse wheel variation static int exitKey = KEY_ESCAPE; // Default exit key (ESC) +static int lastKeyPressed = -1; #endif #if defined(PLATFORM_ANDROID) @@ -226,12 +235,17 @@ static void RestoreKeyboard(void); // Restore keyboard syst static void InitGamepad(void); // Init raw gamepad input #endif -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed +static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed +static void CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value) static void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized +#endif + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) static void TakeScreenshot(void); // Takes a screenshot and saves it in the same folder as executable #endif @@ -243,7 +257,7 @@ static void CommandCallback(struct android_app *app, int32_t cmd); // //---------------------------------------------------------------------------------- // Module Functions Definition - Window and OpenGL Context Functions //---------------------------------------------------------------------------------- -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // Initialize Window and Graphics Context (OpenGL) void InitWindow(int width, int height, const char *title) { @@ -348,7 +362,7 @@ void CloseWindow(void) rlglClose(); // De-init rlgl -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) glfwDestroyWindow(window); glfwTerminate(); #elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -380,7 +394,7 @@ void CloseWindow(void) // Detect if KEY_ESCAPE pressed or Close icon pressed bool WindowShouldClose(void) { -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return (glfwWindowShouldClose(window)); #elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) return windowShouldClose; @@ -402,7 +416,7 @@ void ToggleFullscreen(void) #endif } -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // Set a custom cursor icon/image void SetCustomCursor(const char *cursorImage) { @@ -411,6 +425,7 @@ void SetCustomCursor(const char *cursorImage) cursor = LoadTexture(cursorImage); #if defined(PLATFORM_DESKTOP) + // NOTE: emscripten not implemented glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); #endif customCursor = true; @@ -436,6 +451,12 @@ int GetScreenHeight(void) return screenHeight; } +// Get the last key pressed +int GetKeyPressed(void) +{ + return lastKeyPressed; +} + // Sets Background Color void ClearBackground(Color color) { @@ -612,19 +633,13 @@ void ShowLogo(void) //---------------------------------------------------------------------------------- // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions //---------------------------------------------------------------------------------- -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // Detect if a key has been pressed once bool IsKeyPressed(int key) { bool pressed = false; - currentKeyState[key] = IsKeyDown(key); - - if (currentKeyState[key] != previousKeyState[key]) - { - if (currentKeyState[key]) pressed = true; - previousKeyState[key] = currentKeyState[key]; - } + if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 1)) pressed = true; else pressed = false; return pressed; @@ -642,13 +657,7 @@ bool IsKeyReleased(int key) { bool released = false; - currentKeyState[key] = IsKeyUp(key); - - if (currentKeyState[key] != previousKeyState[key]) - { - if (currentKeyState[key]) released = true; - previousKeyState[key] = currentKeyState[key]; - } + if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 0)) released = true; else released = false; return released; @@ -666,13 +675,7 @@ bool IsMouseButtonPressed(int button) { bool pressed = false; - currentMouseState[button] = IsMouseButtonDown(button); - - if (currentMouseState[button] != previousMouseState[button]) - { - if (currentMouseState[button]) pressed = true; - previousMouseState[button] = currentMouseState[button]; - } + if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true; else pressed = false; return pressed; @@ -690,13 +693,7 @@ bool IsMouseButtonReleased(int button) { bool released = false; - currentMouseState[button] = IsMouseButtonUp(button); - - if (currentMouseState[button] != previousMouseState[button]) - { - if (currentMouseState[button]) released = true; - previousMouseState[button] = currentMouseState[button]; - } + if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 0)) released = true; else released = false; return released; @@ -727,6 +724,16 @@ Vector2 GetMousePosition(void) return mousePosition; } +// Set mouse position XY +void SetMousePosition(Vector2 position) +{ + mousePosition = position; +#if defined(PLATFORM_DESKTOP) + // NOTE: emscripten not implemented + glfwSetCursorPos(window, position.x, position.y); +#endif +} + // Returns mouse wheel movement Y int GetMouseWheelMove(void) { @@ -738,7 +745,8 @@ int GetMouseWheelMove(void) } #endif -// TODO: Enable gamepad usage on Rapsberr Pi +// TODO: Enable gamepad usage on Rapsberry Pi +// NOTE: emscripten not implemented #if defined(PLATFORM_DESKTOP) // Detect if a gamepad is available bool IsGamepadAvailable(int gamepad) @@ -842,6 +850,18 @@ bool IsScreenTouched(void) return touchTap; } +bool IsDoubleTap(void) +{ + if (doubleTap) TraceLog(INFO, "DOUBLE TAP gesture detected"); + + return doubleTap; +} + +bool IsDragGesture(void) +{ + return drag; +} + // Returns touch position X int GetTouchX(void) { @@ -861,6 +881,27 @@ Vector2 GetTouchPosition(void) return position; } + +/*bool GetPointer(Vector2 *dragPositions) +{ + //static int stdVector[MAX_TOUCH_POINTS]; + //static int indexPosition = 0; + //if (indexPosition == 0) return false; + Vector2 vec_pointers_[]; + + //eventDrag + int32_t iIndex = FindIndex( eventDrag, vec_pointers_[0] ); + + if (iIndex == -1) return false; + + float x = AMotionEvent_getX(eventDrag, iIndex); + float y = AMotionEvent_getY(eventDrag, iIndex); + + *dragPositions = Vector2( x, y ); + + + return true; +}*/ #endif //---------------------------------------------------------------------------------- @@ -881,11 +922,13 @@ static void InitDisplay(int width, int height) // Downscale matrix is required in case desired screen area is bigger than display area downscaleView = MatrixIdentity(); -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) glfwSetErrorCallback(ErrorCallback); if (!glfwInit()) TraceLog(ERROR, "Failed to initialize GLFW"); + // NOTE: Getting video modes is not implemented in emscripten GLFW3 version +#if defined(PLATFORM_DESKTOP) // Find monitor resolution const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); @@ -895,7 +938,11 @@ static void InitDisplay(int width, int height) // Screen size security check if (screenWidth <= 0) screenWidth = displayWidth; if (screenHeight <= 0) screenHeight = displayHeight; - +#elif defined(PLATFORM_WEB) + displayWidth = screenWidth; + displayHeight = screenHeight; +#endif + glfwDefaultWindowHints(); // Set default windows hints glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable @@ -944,7 +991,9 @@ static void InitDisplay(int width, int height) else { TraceLog(INFO, "Display device initialized successfully"); +#if defined(PLATFORM_DESKTOP) TraceLog(INFO, "Display size: %i x %i", displayWidth, displayHeight); +#endif TraceLog(INFO, "Render size: %i x %i", renderWidth, renderHeight); TraceLog(INFO, "Screen size: %i x %i", screenWidth, screenHeight); TraceLog(INFO, "Viewport offsets: %i, %i", renderOffsetX, renderOffsetY); @@ -953,6 +1002,8 @@ static void InitDisplay(int width, int height) glfwSetWindowSizeCallback(window, WindowSizeCallback); glfwSetCursorEnterCallback(window, CursorEnterCallback); glfwSetKeyCallback(window, KeyCallback); + glfwSetMouseButtonCallback(window, MouseButtonCallback); + glfwSetCharCallback(window, CharCallback); glfwSetScrollCallback(window, ScrollCallback); glfwMakeContextCurrent(window); @@ -1116,7 +1167,7 @@ void InitGraphics(void) #endif } -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // GLFW3 Error Callback, runs on GLFW3 error static void ErrorCallback(int error, const char *description) { @@ -1138,10 +1189,31 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i // NOTE: Before closing window, while loop must be left! } +#if defined(PLATFORM_DESKTOP) else if (key == GLFW_KEY_F12 && action == GLFW_PRESS) { TakeScreenshot(); } +#endif + else currentKeyState[key] = action; + + // HACK for GuiTextBox, to deteck back key + // TODO: Review... + if ((key == 259) && (action == GLFW_PRESS)) lastKeyPressed = 3; +} + +// GLFW3 Mouse Button Callback, runs on mouse button pressed +static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) +{ + currentMouseState[button] = action; +} + +// GLFW3 Char Key Callback, runs on key pressed (get char value) +static void CharCallback(GLFWwindow *window, unsigned int key) +{ + lastKeyPressed = key; + + //TraceLog(INFO, "Char Callback Key pressed: %i\n", key); } // GLFW3 CursorEnter Callback, when cursor enters the window @@ -1177,6 +1249,7 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) if (type == AINPUT_EVENT_TYPE_MOTION) { + // Detect TOUCH position if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) { // TODO: Seems to work ok but... review! @@ -1240,7 +1313,124 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) //size_t pointerCount = AMotionEvent_getPointerCount(event); //float AMotionEvent_getPressure(const AInputEvent *motion_event, size_t pointer_index); // 0 to 1 //float AMotionEvent_getSize(const AInputEvent *motion_event, size_t pointer_index); // Pressed area + + // Detect DOUBLE TAP event + bool tapDetected = touchTap; + + switch (flags) + { + case AMOTION_EVENT_ACTION_DOWN: + { + int64_t eventTime = AMotionEvent_getEventTime(event); + + if (eventTime - lastTapTime <= DOUBLE_TAP_TIMEOUT) + { + float x = AMotionEvent_getX(event, 0) - lastTapX; + float y = AMotionEvent_getY(event, 0) - lastTapY; + + float densityFactor = 1.0f; + + if ((x*x + y*y) < (DOUBLE_TAP_SLOP*DOUBLE_TAP_SLOP*densityFactor)) + { + // Doubletap detected + doubleTap = true; + + } + } + } break; + case AMOTION_EVENT_ACTION_UP: + { + if (tapDetected) + { + lastTapTime = AMotionEvent_getEventTime(event); + lastTapX = AMotionEvent_getX(event, 0); + lastTapY = AMotionEvent_getY(event, 0); + + } + } break; + } + + + // Detect DRAG event + //int32_t action = AMotionEvent_getAction(event); + + int32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + //uint32_t flags = action & AMOTION_EVENT_ACTION_MASK; + //event_ = event; + int32_t count = AMotionEvent_getPointerCount(event); + + switch (flags) + { + case AMOTION_EVENT_ACTION_DOWN: + { + stdVector[indexPosition] = AMotionEvent_getPointerId(event, 0); + indexPosition++; + TraceLog(INFO, "ACTION_DOWN"); + + //ret = GESTURE_STATE_START; + } break; + case AMOTION_EVENT_ACTION_POINTER_DOWN: + { + stdVector[indexPosition] = AMotionEvent_getPointerId(event, index); + indexPosition++; + TraceLog(INFO, "ACTION_POINTER_DOWN"); + + } break; + case AMOTION_EVENT_ACTION_UP: + { + //int value = stdVector[indexPosition]; + indexPosition--; + //ret = GESTURE_STATE_END; + TraceLog(INFO, "ACTION_UP"); + + } break; + case AMOTION_EVENT_ACTION_POINTER_UP: + { + int32_t releasedPointerId = AMotionEvent_getPointerId(event, index); + + int i = 0; + for (i = 0; i < MAX_TOUCH_POINTS; i++) + { + if (stdVector[i] == releasedPointerId) + { + for (int k = i; k < indexPosition - 1; k++) + { + stdVector[k] = stdVector[k + 1]; + } + + //indexPosition--; + indexPosition = 0; + break; + } + } + + if (i <= 1) + { + // Reset pinch or drag + //if (count == 2) //ret = GESTURE_STATE_START; + } + TraceLog(INFO, "ACTION_POINTER_UP"); + + } break; + case AMOTION_EVENT_ACTION_MOVE: + { + if (count == 1) + { + //TraceLog(INFO, "DRAG gesture detected"); + + drag = true; //ret = GESTURE_STATE_MOVE; + } + else break; + TraceLog(INFO, "ACTION_MOVE"); + + } break; + case AMOTION_EVENT_ACTION_CANCEL: break; + default: break; + } + + //-------------------------------------------------------------------- + return 1; } else if (type == AINPUT_EVENT_TYPE_KEY) @@ -1386,7 +1576,7 @@ static void InitTimer(void) // Get current time measure since InitTimer() static double GetTime(void) { -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetTime(); #elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) struct timespec ts; @@ -1400,7 +1590,7 @@ static double GetTime(void) // Get one key state static bool GetKeyStatus(int key) { -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetKey(window, key); #elif defined(PLATFORM_ANDROID) // TODO: Check virtual keyboard (?) @@ -1415,7 +1605,7 @@ static bool GetKeyStatus(int key) // Get one mouse button state static bool GetMouseButtonStatus(int button) { -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetMouseButton(window, button); #elif defined(PLATFORM_ANDROID) // TODO: Check virtual keyboard (?) @@ -1429,7 +1619,7 @@ static bool GetMouseButtonStatus(int button) // Poll (store) all input events static void PollInputEvents(void) { -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling double mouseX; double mouseY; @@ -1441,14 +1631,23 @@ static void PollInputEvents(void) // Keyboard polling // Automatically managed by GLFW3 through callback - + lastKeyPressed = -1; + + // Register previous keys states + for (int i = 0; i < 512; i++) previousKeyState[i] = currentKeyState[i]; + + // Register previous mouse states + for (int i = 0; i < 3; i++) previousMouseState[i] = currentMouseState[i]; + glfwPollEvents(); // Register keyboard/mouse events #elif defined(PLATFORM_ANDROID) // TODO: Check virtual keyboard (?) - // Reset touchTap event + // Reset touch events touchTap = false; + doubleTap = false; + drag = false; // Poll Events (registered events) while ((ident = ALooper_pollAll(0, NULL, &events,(void**)&source)) >= 0) @@ -1597,14 +1796,17 @@ static void PollInputEvents(void) static void InitMouse(void) { // NOTE: We can use /dev/input/mice to read from all available mice - if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Could not open mouse device, no mouse available"); + if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0) + { + TraceLog(WARNING, "Mouse device could not be opened, no mouse available"); + } else { mouseReady = true; - int err = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL); + int error = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL); - if (err != 0) TraceLog(WARNING, "Error creating mouse input event thread"); + if (error != 0) TraceLog(WARNING, "Error creating mouse input event thread"); else TraceLog(INFO, "Mouse device initialized successfully"); } } @@ -1715,7 +1917,7 @@ static void RestoreKeyboard(void) static void InitGamepad(void) { // TODO: Gamepad support - if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Could not open gamepad device, no gamepad available"); + if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available"); else TraceLog(INFO, "Gamepad device initialized successfully"); } #endif @@ -1723,7 +1925,7 @@ static void InitGamepad(void) // Copy back buffer to front buffers static void SwapBuffers(void) { -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) glfwSwapBuffers(window); #elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) eglSwapBuffers(display, surface); @@ -1737,7 +1939,7 @@ static void SetupFramebufferSize(int displayWidth, int displayHeight) // Calculate renderWidth and renderHeight, we have the display size (input params) and the desired screen size (global var) if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) { - TraceLog(WARNING, "DOWNSCALING: Required screen size (%i x %i) is bigger than display size (%i x %i)", screenWidth, screenHeight, displayWidth, displayHeight); + TraceLog(WARNING, "DOWNSCALING: Required screen size (%ix%i) is bigger than display size (%ix%i)", screenWidth, screenHeight, displayWidth, displayHeight); // Downscaling to fit display with border-bars float widthRatio = (float)displayWidth/(float)screenWidth; @@ -1806,6 +2008,7 @@ static void SetupFramebufferSize(int displayWidth, int displayHeight) // Plays raylib logo appearing animation static void LogoAnimation(void) { +#ifndef PLATFORM_WEB int logoPositionX = screenWidth/2 - 128; int logoPositionY = screenHeight/2 - 128; @@ -1923,6 +2126,8 @@ static void LogoAnimation(void) EndDrawing(); //---------------------------------------------------------------------------------- } +#endif showLogo = false; // Prevent for repeating when reloading window (Android) } + |
