minesweeper

A minewseeper implementation to play around with Hare and Raylib
git clone https://git.tronto.net/minesweeper
Download | Log | Files | Refs | README | LICENSE

rcore_android.c (55092B)


      1 /**********************************************************************************************
      2 *
      3 *   rcore_android - Functions to manage window, graphics device and inputs
      4 *
      5 *   PLATFORM: ANDROID
      6 *       - Android (ARM, ARM64)
      7 *
      8 *   LIMITATIONS:
      9 *       - Limitation 01
     10 *       - Limitation 02
     11 *
     12 *   POSSIBLE IMPROVEMENTS:
     13 *       - Improvement 01
     14 *       - Improvement 02
     15 *
     16 *   ADDITIONAL NOTES:
     17 *       - TRACELOG() function is located in raylib [utils] module
     18 *
     19 *   CONFIGURATION:
     20 *       #define RCORE_PLATFORM_CUSTOM_FLAG
     21 *           Custom flag for rcore on target platform -not used-
     22 *
     23 *   DEPENDENCIES:
     24 *       - Android NDK: Provides C API to access Android functionality
     25 *       - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
     26 *
     27 *
     28 *   LICENSE: zlib/libpng
     29 *
     30 *   Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors
     31 *
     32 *   This software is provided "as-is", without any express or implied warranty. In no event
     33 *   will the authors be held liable for any damages arising from the use of this software.
     34 *
     35 *   Permission is granted to anyone to use this software for any purpose, including commercial
     36 *   applications, and to alter it and redistribute it freely, subject to the following restrictions:
     37 *
     38 *     1. The origin of this software must not be misrepresented; you must not claim that you
     39 *     wrote the original software. If you use this software in a product, an acknowledgment
     40 *     in the product documentation would be appreciated but is not required.
     41 *
     42 *     2. Altered source versions must be plainly marked as such, and must not be misrepresented
     43 *     as being the original software.
     44 *
     45 *     3. This notice may not be removed or altered from any source distribution.
     46 *
     47 **********************************************************************************************/
     48 
     49 #include <android_native_app_glue.h>    // Required for: android_app struct and activity management
     50 #include <android/window.h>             // Required for: AWINDOW_FLAG_FULLSCREEN definition and others
     51 //#include <android/sensor.h>           // Required for: Android sensors functions (accelerometer, gyroscope, light...)
     52 #include <jni.h>                        // Required for: JNIEnv and JavaVM [Used in OpenURL()]
     53 
     54 #include <EGL/egl.h>                    // Native platform windowing system interface
     55 
     56 //----------------------------------------------------------------------------------
     57 // Types and Structures Definition
     58 //----------------------------------------------------------------------------------
     59 typedef struct {
     60     // Application data
     61     struct android_app *app;            // Android activity
     62     struct android_poll_source *source; // Android events polling source
     63     bool appEnabled;                    // Flag to detect if app is active ** = true
     64     bool contextRebindRequired;         // Used to know context rebind required
     65 
     66     // Display data
     67     EGLDisplay device;                  // Native display device (physical screen connection)
     68     EGLSurface surface;                 // Surface to draw on, framebuffers (connected to context)
     69     EGLContext context;                 // Graphic context, mode in which drawing can be done
     70     EGLConfig config;                   // Graphic config
     71 } PlatformData;
     72 
     73 //----------------------------------------------------------------------------------
     74 // Global Variables Definition
     75 //----------------------------------------------------------------------------------
     76 extern CoreData CORE;                   // Global CORE state context
     77 extern bool isGpuReady;                 // Flag to note GPU has been initialized successfully
     78 static PlatformData platform = { 0 };   // Platform specific data
     79 
     80 //----------------------------------------------------------------------------------
     81 // Local Variables Definition
     82 //----------------------------------------------------------------------------------
     83 #define KEYCODE_MAP_SIZE 162
     84 static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = {
     85     KEY_NULL,           // AKEYCODE_UNKNOWN
     86     0,                  // AKEYCODE_SOFT_LEFT
     87     0,                  // AKEYCODE_SOFT_RIGHT
     88     0,                  // AKEYCODE_HOME
     89     KEY_BACK,           // AKEYCODE_BACK
     90     0,                  // AKEYCODE_CALL
     91     0,                  // AKEYCODE_ENDCALL
     92     KEY_ZERO,           // AKEYCODE_0
     93     KEY_ONE,            // AKEYCODE_1
     94     KEY_TWO,            // AKEYCODE_2
     95     KEY_THREE,          // AKEYCODE_3
     96     KEY_FOUR,           // AKEYCODE_4
     97     KEY_FIVE,           // AKEYCODE_5
     98     KEY_SIX,            // AKEYCODE_6
     99     KEY_SEVEN,          // AKEYCODE_7
    100     KEY_EIGHT,          // AKEYCODE_8
    101     KEY_NINE,           // AKEYCODE_9
    102     0,                  // AKEYCODE_STAR
    103     0,                  // AKEYCODE_POUND
    104     KEY_UP,             // AKEYCODE_DPAD_UP
    105     KEY_DOWN,           // AKEYCODE_DPAD_DOWN
    106     KEY_LEFT,           // AKEYCODE_DPAD_LEFT
    107     KEY_RIGHT,          // AKEYCODE_DPAD_RIGHT
    108     0,                  // AKEYCODE_DPAD_CENTER
    109     KEY_VOLUME_UP,      // AKEYCODE_VOLUME_UP
    110     KEY_VOLUME_DOWN,    // AKEYCODE_VOLUME_DOWN
    111     0,                  // AKEYCODE_POWER
    112     0,                  // AKEYCODE_CAMERA
    113     0,                  // AKEYCODE_CLEAR
    114     KEY_A,              // AKEYCODE_A
    115     KEY_B,              // AKEYCODE_B
    116     KEY_C,              // AKEYCODE_C
    117     KEY_D,              // AKEYCODE_D
    118     KEY_E,              // AKEYCODE_E
    119     KEY_F,              // AKEYCODE_F
    120     KEY_G,              // AKEYCODE_G
    121     KEY_H,              // AKEYCODE_H
    122     KEY_I,              // AKEYCODE_I
    123     KEY_J,              // AKEYCODE_J
    124     KEY_K,              // AKEYCODE_K
    125     KEY_L,              // AKEYCODE_L
    126     KEY_M,              // AKEYCODE_M
    127     KEY_N,              // AKEYCODE_N
    128     KEY_O,              // AKEYCODE_O
    129     KEY_P,              // AKEYCODE_P
    130     KEY_Q,              // AKEYCODE_Q
    131     KEY_R,              // AKEYCODE_R
    132     KEY_S,              // AKEYCODE_S
    133     KEY_T,              // AKEYCODE_T
    134     KEY_U,              // AKEYCODE_U
    135     KEY_V,              // AKEYCODE_V
    136     KEY_W,              // AKEYCODE_W
    137     KEY_X,              // AKEYCODE_X
    138     KEY_Y,              // AKEYCODE_Y
    139     KEY_Z,              // AKEYCODE_Z
    140     KEY_COMMA,          // AKEYCODE_COMMA
    141     KEY_PERIOD,         // AKEYCODE_PERIOD
    142     KEY_LEFT_ALT,       // AKEYCODE_ALT_LEFT
    143     KEY_RIGHT_ALT,      // AKEYCODE_ALT_RIGHT
    144     KEY_LEFT_SHIFT,     // AKEYCODE_SHIFT_LEFT
    145     KEY_RIGHT_SHIFT,    // AKEYCODE_SHIFT_RIGHT
    146     KEY_TAB,            // AKEYCODE_TAB
    147     KEY_SPACE,          // AKEYCODE_SPACE
    148     0,                  // AKEYCODE_SYM
    149     0,                  // AKEYCODE_EXPLORER
    150     0,                  // AKEYCODE_ENVELOPE
    151     KEY_ENTER,          // AKEYCODE_ENTER
    152     KEY_BACKSPACE,      // AKEYCODE_DEL
    153     KEY_GRAVE,          // AKEYCODE_GRAVE
    154     KEY_MINUS,          // AKEYCODE_MINUS
    155     KEY_EQUAL,          // AKEYCODE_EQUALS
    156     KEY_LEFT_BRACKET,   // AKEYCODE_LEFT_BRACKET
    157     KEY_RIGHT_BRACKET,  // AKEYCODE_RIGHT_BRACKET
    158     KEY_BACKSLASH,      // AKEYCODE_BACKSLASH
    159     KEY_SEMICOLON,      // AKEYCODE_SEMICOLON
    160     KEY_APOSTROPHE,     // AKEYCODE_APOSTROPHE
    161     KEY_SLASH,          // AKEYCODE_SLASH
    162     0,                  // AKEYCODE_AT
    163     0,                  // AKEYCODE_NUM
    164     0,                  // AKEYCODE_HEADSETHOOK
    165     0,                  // AKEYCODE_FOCUS
    166     0,                  // AKEYCODE_PLUS
    167     KEY_MENU,           // AKEYCODE_MENU
    168     0,                  // AKEYCODE_NOTIFICATION
    169     0,                  // AKEYCODE_SEARCH
    170     0,                  // AKEYCODE_MEDIA_PLAY_PAUSE
    171     0,                  // AKEYCODE_MEDIA_STOP
    172     0,                  // AKEYCODE_MEDIA_NEXT
    173     0,                  // AKEYCODE_MEDIA_PREVIOUS
    174     0,                  // AKEYCODE_MEDIA_REWIND
    175     0,                  // AKEYCODE_MEDIA_FAST_FORWARD
    176     0,                  // AKEYCODE_MUTE
    177     KEY_PAGE_UP,        // AKEYCODE_PAGE_UP
    178     KEY_PAGE_DOWN,      // AKEYCODE_PAGE_DOWN
    179     0,                  // AKEYCODE_PICTSYMBOLS
    180     0,                  // AKEYCODE_SWITCH_CHARSET
    181     0,                  // AKEYCODE_BUTTON_A
    182     0,                  // AKEYCODE_BUTTON_B
    183     0,                  // AKEYCODE_BUTTON_C
    184     0,                  // AKEYCODE_BUTTON_X
    185     0,                  // AKEYCODE_BUTTON_Y
    186     0,                  // AKEYCODE_BUTTON_Z
    187     0,                  // AKEYCODE_BUTTON_L1
    188     0,                  // AKEYCODE_BUTTON_R1
    189     0,                  // AKEYCODE_BUTTON_L2
    190     0,                  // AKEYCODE_BUTTON_R2
    191     0,                  // AKEYCODE_BUTTON_THUMBL
    192     0,                  // AKEYCODE_BUTTON_THUMBR
    193     0,                  // AKEYCODE_BUTTON_START
    194     0,                  // AKEYCODE_BUTTON_SELECT
    195     0,                  // AKEYCODE_BUTTON_MODE
    196     KEY_ESCAPE,         // AKEYCODE_ESCAPE
    197     KEY_DELETE,         // AKEYCODE_FORWARD_DELL
    198     KEY_LEFT_CONTROL,   // AKEYCODE_CTRL_LEFT
    199     KEY_RIGHT_CONTROL,  // AKEYCODE_CTRL_RIGHT
    200     KEY_CAPS_LOCK,      // AKEYCODE_CAPS_LOCK
    201     KEY_SCROLL_LOCK,    // AKEYCODE_SCROLL_LOCK
    202     KEY_LEFT_SUPER,     // AKEYCODE_META_LEFT
    203     KEY_RIGHT_SUPER,    // AKEYCODE_META_RIGHT
    204     0,                  // AKEYCODE_FUNCTION
    205     KEY_PRINT_SCREEN,   // AKEYCODE_SYSRQ
    206     KEY_PAUSE,          // AKEYCODE_BREAK
    207     KEY_HOME,           // AKEYCODE_MOVE_HOME
    208     KEY_END,            // AKEYCODE_MOVE_END
    209     KEY_INSERT,         // AKEYCODE_INSERT
    210     0,                  // AKEYCODE_FORWARD
    211     0,                  // AKEYCODE_MEDIA_PLAY
    212     0,                  // AKEYCODE_MEDIA_PAUSE
    213     0,                  // AKEYCODE_MEDIA_CLOSE
    214     0,                  // AKEYCODE_MEDIA_EJECT
    215     0,                  // AKEYCODE_MEDIA_RECORD
    216     KEY_F1,             // AKEYCODE_F1
    217     KEY_F2,             // AKEYCODE_F2
    218     KEY_F3,             // AKEYCODE_F3
    219     KEY_F4,             // AKEYCODE_F4
    220     KEY_F5,             // AKEYCODE_F5
    221     KEY_F6,             // AKEYCODE_F6
    222     KEY_F7,             // AKEYCODE_F7
    223     KEY_F8,             // AKEYCODE_F8
    224     KEY_F9,             // AKEYCODE_F9
    225     KEY_F10,            // AKEYCODE_F10
    226     KEY_F11,            // AKEYCODE_F11
    227     KEY_F12,            // AKEYCODE_F12
    228     KEY_NUM_LOCK,       // AKEYCODE_NUM_LOCK
    229     KEY_KP_0,           // AKEYCODE_NUMPAD_0
    230     KEY_KP_1,           // AKEYCODE_NUMPAD_1
    231     KEY_KP_2,           // AKEYCODE_NUMPAD_2
    232     KEY_KP_3,           // AKEYCODE_NUMPAD_3
    233     KEY_KP_4,           // AKEYCODE_NUMPAD_4
    234     KEY_KP_5,           // AKEYCODE_NUMPAD_5
    235     KEY_KP_6,           // AKEYCODE_NUMPAD_6
    236     KEY_KP_7,           // AKEYCODE_NUMPAD_7
    237     KEY_KP_8,           // AKEYCODE_NUMPAD_8
    238     KEY_KP_9,           // AKEYCODE_NUMPAD_9
    239     KEY_KP_DIVIDE,      // AKEYCODE_NUMPAD_DIVIDE
    240     KEY_KP_MULTIPLY,    // AKEYCODE_NUMPAD_MULTIPLY
    241     KEY_KP_SUBTRACT,    // AKEYCODE_NUMPAD_SUBTRACT
    242     KEY_KP_ADD,         // AKEYCODE_NUMPAD_ADD
    243     KEY_KP_DECIMAL,     // AKEYCODE_NUMPAD_DOT
    244     0,                  // AKEYCODE_NUMPAD_COMMA
    245     KEY_KP_ENTER,       // AKEYCODE_NUMPAD_ENTER
    246     KEY_KP_EQUAL        // AKEYCODE_NUMPAD_EQUALS
    247 };
    248 
    249 //----------------------------------------------------------------------------------
    250 // Module Internal Functions Declaration
    251 //----------------------------------------------------------------------------------
    252 int InitPlatform(void);          // Initialize platform (graphics, inputs and more)
    253 void ClosePlatform(void);        // Close platform
    254 
    255 static void AndroidCommandCallback(struct android_app *app, int32_t cmd);           // Process Android activity lifecycle commands
    256 static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event);   // Process Android inputs
    257 static GamepadButton AndroidTranslateGamepadButton(int button);                     // Map Android gamepad button to raylib gamepad button
    258 
    259 //----------------------------------------------------------------------------------
    260 // Module Functions Declaration
    261 //----------------------------------------------------------------------------------
    262 // NOTE: Functions declaration is provided by raylib.h
    263 
    264 //----------------------------------------------------------------------------------
    265 // Module Functions Definition: Application
    266 //----------------------------------------------------------------------------------
    267 
    268 // To allow easier porting to android, we allow the user to define a
    269 // main function which we call from android_main, defined by ourselves
    270 extern int main(int argc, char *argv[]);
    271 
    272 // Android main function
    273 void android_main(struct android_app *app)
    274 {
    275     char arg0[] = "raylib";     // NOTE: argv[] are mutable
    276     platform.app = app;
    277 
    278     // NOTE: Return from main is ignored
    279     (void)main(1, (char *[]) { arg0, NULL });
    280 
    281     // Request to end the native activity
    282     ANativeActivity_finish(app->activity);
    283 
    284     // Android ALooper_pollOnce() variables
    285     int pollResult = 0;
    286     int pollEvents = 0;
    287 
    288     // Waiting for application events before complete finishing
    289     while (!app->destroyRequested)
    290     {
    291         // Poll all events until we reach return value TIMEOUT, meaning no events left to process
    292         while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, (void **)&platform.source)) > ALOOPER_POLL_TIMEOUT)
    293         {
    294             if (platform.source != NULL) platform.source->process(app, platform.source);
    295         }
    296     }
    297 }
    298 
    299 // NOTE: Add this to header (if apps really need it)
    300 struct android_app *GetAndroidApp(void)
    301 {
    302     return platform.app;
    303 }
    304 
    305 //----------------------------------------------------------------------------------
    306 // Module Functions Definition: Window and Graphics Device
    307 //----------------------------------------------------------------------------------
    308 
    309 // Check if application should close
    310 bool WindowShouldClose(void)
    311 {
    312     if (CORE.Window.ready) return CORE.Window.shouldClose;
    313     else return true;
    314 }
    315 
    316 // Toggle fullscreen mode
    317 void ToggleFullscreen(void)
    318 {
    319     TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform");
    320 }
    321 
    322 // Toggle borderless windowed mode
    323 void ToggleBorderlessWindowed(void)
    324 {
    325     TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
    326 }
    327 
    328 // Set window state: maximized, if resizable
    329 void MaximizeWindow(void)
    330 {
    331     TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform");
    332 }
    333 
    334 // Set window state: minimized
    335 void MinimizeWindow(void)
    336 {
    337     TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
    338 }
    339 
    340 // Set window state: not minimized/maximized
    341 void RestoreWindow(void)
    342 {
    343     TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
    344 }
    345 
    346 // Set window configuration state using flags
    347 void SetWindowState(unsigned int flags)
    348 {
    349     TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform");
    350 }
    351 
    352 // Clear window configuration state flags
    353 void ClearWindowState(unsigned int flags)
    354 {
    355     TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform");
    356 }
    357 
    358 // Set icon for window
    359 void SetWindowIcon(Image image)
    360 {
    361     TRACELOG(LOG_WARNING, "SetWindowIcon() not available on target platform");
    362 }
    363 
    364 // Set icon for window
    365 void SetWindowIcons(Image *images, int count)
    366 {
    367     TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform");
    368 }
    369 
    370 // Set title for window
    371 void SetWindowTitle(const char *title)
    372 {
    373     CORE.Window.title = title;
    374 }
    375 
    376 // Set window position on screen (windowed mode)
    377 void SetWindowPosition(int x, int y)
    378 {
    379     TRACELOG(LOG_WARNING, "SetWindowPosition() not available on target platform");
    380 }
    381 
    382 // Set monitor for the current window
    383 void SetWindowMonitor(int monitor)
    384 {
    385     TRACELOG(LOG_WARNING, "SetWindowMonitor() not available on target platform");
    386 }
    387 
    388 // Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
    389 void SetWindowMinSize(int width, int height)
    390 {
    391     CORE.Window.screenMin.width = width;
    392     CORE.Window.screenMin.height = height;
    393 }
    394 
    395 // Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
    396 void SetWindowMaxSize(int width, int height)
    397 {
    398     CORE.Window.screenMax.width = width;
    399     CORE.Window.screenMax.height = height;
    400 }
    401 
    402 // Set window dimensions
    403 void SetWindowSize(int width, int height)
    404 {
    405     TRACELOG(LOG_WARNING, "SetWindowSize() not available on target platform");
    406 }
    407 
    408 // Set window opacity, value opacity is between 0.0 and 1.0
    409 void SetWindowOpacity(float opacity)
    410 {
    411     TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform");
    412 }
    413 
    414 // Set window focused
    415 void SetWindowFocused(void)
    416 {
    417     TRACELOG(LOG_WARNING, "SetWindowFocused() not available on target platform");
    418 }
    419 
    420 // Get native window handle
    421 void *GetWindowHandle(void)
    422 {
    423     TRACELOG(LOG_WARNING, "GetWindowHandle() not implemented on target platform");
    424     return NULL;
    425 }
    426 
    427 // Get number of monitors
    428 int GetMonitorCount(void)
    429 {
    430     TRACELOG(LOG_WARNING, "GetMonitorCount() not implemented on target platform");
    431     return 1;
    432 }
    433 
    434 // Get number of monitors
    435 int GetCurrentMonitor(void)
    436 {
    437     TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
    438     return 0;
    439 }
    440 
    441 // Get selected monitor position
    442 Vector2 GetMonitorPosition(int monitor)
    443 {
    444     TRACELOG(LOG_WARNING, "GetMonitorPosition() not implemented on target platform");
    445     return (Vector2){ 0, 0 };
    446 }
    447 
    448 // Get selected monitor width (currently used by monitor)
    449 int GetMonitorWidth(int monitor)
    450 {
    451     TRACELOG(LOG_WARNING, "GetMonitorWidth() not implemented on target platform");
    452     return 0;
    453 }
    454 
    455 // Get selected monitor height (currently used by monitor)
    456 int GetMonitorHeight(int monitor)
    457 {
    458     TRACELOG(LOG_WARNING, "GetMonitorHeight() not implemented on target platform");
    459     return 0;
    460 }
    461 
    462 // Get selected monitor physical width in millimetres
    463 int GetMonitorPhysicalWidth(int monitor)
    464 {
    465     TRACELOG(LOG_WARNING, "GetMonitorPhysicalWidth() not implemented on target platform");
    466     return 0;
    467 }
    468 
    469 // Get selected monitor physical height in millimetres
    470 int GetMonitorPhysicalHeight(int monitor)
    471 {
    472     TRACELOG(LOG_WARNING, "GetMonitorPhysicalHeight() not implemented on target platform");
    473     return 0;
    474 }
    475 
    476 // Get selected monitor refresh rate
    477 int GetMonitorRefreshRate(int monitor)
    478 {
    479     TRACELOG(LOG_WARNING, "GetMonitorRefreshRate() not implemented on target platform");
    480     return 0;
    481 }
    482 
    483 // Get the human-readable, UTF-8 encoded name of the selected monitor
    484 const char *GetMonitorName(int monitor)
    485 {
    486     TRACELOG(LOG_WARNING, "GetMonitorName() not implemented on target platform");
    487     return "";
    488 }
    489 
    490 // Get window position XY on monitor
    491 Vector2 GetWindowPosition(void)
    492 {
    493     TRACELOG(LOG_WARNING, "GetWindowPosition() not implemented on target platform");
    494     return (Vector2){ 0, 0 };
    495 }
    496 
    497 // Get window scale DPI factor for current monitor
    498 Vector2 GetWindowScaleDPI(void)
    499 {
    500     TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
    501     return (Vector2){ 1.0f, 1.0f };
    502 }
    503 
    504 // Set clipboard text content
    505 void SetClipboardText(const char *text)
    506 {
    507     TRACELOG(LOG_WARNING, "SetClipboardText() not implemented on target platform");
    508 }
    509 
    510 // Get clipboard text content
    511 // NOTE: returned string is allocated and freed by GLFW
    512 const char *GetClipboardText(void)
    513 {
    514     TRACELOG(LOG_WARNING, "GetClipboardText() not implemented on target platform");
    515     return NULL;
    516 }
    517 
    518 // Show mouse cursor
    519 void ShowCursor(void)
    520 {
    521     CORE.Input.Mouse.cursorHidden = false;
    522 }
    523 
    524 // Hides mouse cursor
    525 void HideCursor(void)
    526 {
    527     CORE.Input.Mouse.cursorHidden = true;
    528 }
    529 
    530 // Enables cursor (unlock cursor)
    531 void EnableCursor(void)
    532 {
    533     // Set cursor position in the middle
    534     SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
    535 
    536     CORE.Input.Mouse.cursorHidden = false;
    537 }
    538 
    539 // Disables cursor (lock cursor)
    540 void DisableCursor(void)
    541 {
    542     // Set cursor position in the middle
    543     SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
    544 
    545     CORE.Input.Mouse.cursorHidden = true;
    546 }
    547 
    548 // Swap back buffer with front buffer (screen drawing)
    549 void SwapScreenBuffer(void)
    550 {
    551     eglSwapBuffers(platform.device, platform.surface);
    552 }
    553 
    554 //----------------------------------------------------------------------------------
    555 // Module Functions Definition: Misc
    556 //----------------------------------------------------------------------------------
    557 
    558 // Get elapsed time measure in seconds since InitTimer()
    559 double GetTime(void)
    560 {
    561     double time = 0.0;
    562     struct timespec ts = { 0 };
    563     clock_gettime(CLOCK_MONOTONIC, &ts);
    564     unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
    565 
    566     time = (double)(nanoSeconds - CORE.Time.base)*1e-9;  // Elapsed time since InitTimer()
    567 
    568     return time;
    569 }
    570 
    571 // Open URL with default system browser (if available)
    572 // NOTE: This function is only safe to use if you control the URL given.
    573 // A user could craft a malicious string performing another action.
    574 // Only call this function yourself not with user input or make sure to check the string yourself.
    575 // Ref: https://github.com/raysan5/raylib/issues/686
    576 void OpenURL(const char *url)
    577 {
    578     // Security check to (partially) avoid malicious code
    579     if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
    580     else
    581     {
    582         JNIEnv *env = NULL;
    583         JavaVM *vm = platform.app->activity->vm;
    584         (*vm)->AttachCurrentThread(vm, &env, NULL);
    585 
    586         jstring urlString = (*env)->NewStringUTF(env, url);
    587         jclass uriClass = (*env)->FindClass(env, "android/net/Uri");
    588         jmethodID uriParse = (*env)->GetStaticMethodID(env, uriClass, "parse", "(Ljava/lang/String;)Landroid/net/Uri;");
    589         jobject uri = (*env)->CallStaticObjectMethod(env, uriClass, uriParse, urlString);
    590 
    591         jclass intentClass = (*env)->FindClass(env, "android/content/Intent");
    592         jfieldID actionViewId = (*env)->GetStaticFieldID(env, intentClass, "ACTION_VIEW", "Ljava/lang/String;");
    593         jobject actionView = (*env)->GetStaticObjectField(env, intentClass, actionViewId);
    594         jmethodID newIntent = (*env)->GetMethodID(env, intentClass, "<init>", "(Ljava/lang/String;Landroid/net/Uri;)V");
    595         jobject intent = (*env)->AllocObject(env, intentClass);
    596 
    597         (*env)->CallVoidMethod(env, intent, newIntent, actionView, uri);
    598         jclass activityClass = (*env)->FindClass(env, "android/app/Activity");
    599         jmethodID startActivity = (*env)->GetMethodID(env, activityClass, "startActivity", "(Landroid/content/Intent;)V");
    600         (*env)->CallVoidMethod(env, platform.app->activity->clazz, startActivity, intent);
    601 
    602         (*vm)->DetachCurrentThread(vm);
    603     }
    604 }
    605 
    606 //----------------------------------------------------------------------------------
    607 // Module Functions Definition: Inputs
    608 //----------------------------------------------------------------------------------
    609 
    610 // Set internal gamepad mappings
    611 int SetGamepadMappings(const char *mappings)
    612 {
    613     TRACELOG(LOG_WARNING, "SetGamepadMappings() not implemented on target platform");
    614     return 0;
    615 }
    616 
    617 // Set gamepad vibration
    618 void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
    619 {
    620     TRACELOG(LOG_WARNING, "GamepadSetVibration() not implemented on target platform");
    621 }
    622 
    623 // Set mouse position XY
    624 void SetMousePosition(int x, int y)
    625 {
    626     CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
    627     CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
    628 }
    629 
    630 // Set mouse cursor
    631 void SetMouseCursor(int cursor)
    632 {
    633     TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
    634 }
    635 
    636 // Get physical key name.
    637 const char *GetKeyName(int key)
    638 {
    639     TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
    640     return "";
    641 }
    642 
    643 // Register all input events
    644 void PollInputEvents(void)
    645 {
    646 #if defined(SUPPORT_GESTURES_SYSTEM)
    647     // NOTE: Gestures update must be called every frame to reset gestures correctly
    648     // because ProcessGestureEvent() is just called on an event, not every frame
    649     UpdateGestures();
    650 #endif
    651 
    652     // Reset keys/chars pressed registered
    653     CORE.Input.Keyboard.keyPressedQueueCount = 0;
    654     CORE.Input.Keyboard.charPressedQueueCount = 0;
    655     // Reset key repeats
    656     for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
    657 
    658     // Reset last gamepad button/axis registered state
    659     CORE.Input.Gamepad.lastButtonPressed = 0;       // GAMEPAD_BUTTON_UNKNOWN
    660     //CORE.Input.Gamepad.axisCount = 0;
    661 
    662     for (int i = 0; i < MAX_GAMEPADS; i++)
    663     {
    664         if (CORE.Input.Gamepad.ready[i])     // Check if gamepad is available
    665         {
    666             // Register previous gamepad states
    667             for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++)
    668                 CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
    669         }
    670     }
    671 
    672     // Register previous touch states
    673     for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
    674 
    675     // Reset touch positions
    676     //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 };
    677 
    678     // Register previous keys states
    679     // NOTE: Android supports up to 260 keys
    680     for (int i = 0; i < 260; i++)
    681     {
    682         CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
    683         CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
    684     }
    685 
    686     // Android ALooper_pollOnce() variables
    687     int pollResult = 0;
    688     int pollEvents = 0;
    689 
    690     // Poll Events (registered events) until we reach TIMEOUT which indicates there are no events left to poll
    691     // NOTE: Activity is paused if not enabled (platform.appEnabled)
    692     while ((pollResult = ALooper_pollOnce(platform.appEnabled? 0 : -1, NULL, &pollEvents, (void**)&platform.source)) > ALOOPER_POLL_TIMEOUT)
    693     {
    694         // Process this event
    695         if (platform.source != NULL) platform.source->process(platform.app, platform.source);
    696 
    697         // NOTE: Allow closing the window in case a configuration change happened.
    698         // The android_main function should be allowed to return to its caller in order for the
    699         // Android OS to relaunch the activity.
    700         if (platform.app->destroyRequested != 0)
    701         {
    702             CORE.Window.shouldClose = true;
    703         }
    704     }
    705 }
    706 
    707 //----------------------------------------------------------------------------------
    708 // Module Internal Functions Definition
    709 //----------------------------------------------------------------------------------
    710 
    711 // Initialize platform: graphics, inputs and more
    712 int InitPlatform(void)
    713 {
    714     // Initialize display basic configuration
    715     //----------------------------------------------------------------------------
    716     CORE.Window.currentFbo.width = CORE.Window.screen.width;
    717     CORE.Window.currentFbo.height = CORE.Window.screen.height;
    718 
    719     // Set desired windows flags before initializing anything
    720     ANativeActivity_setWindowFlags(platform.app->activity, AWINDOW_FLAG_FULLSCREEN, 0);  //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
    721 
    722     int orientation = AConfiguration_getOrientation(platform.app->config);
    723 
    724     if (orientation == ACONFIGURATION_ORIENTATION_PORT) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as portrait");
    725     else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as landscape");
    726 
    727     // TODO: Automatic orientation doesn't seem to work
    728     if (CORE.Window.screen.width <= CORE.Window.screen.height)
    729     {
    730         AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_PORT);
    731         TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to portrait");
    732     }
    733     else
    734     {
    735         AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_LAND);
    736         TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to landscape");
    737     }
    738 
    739     //AConfiguration_getDensity(platform.app->config);
    740     //AConfiguration_getKeyboard(platform.app->config);
    741     //AConfiguration_getScreenSize(platform.app->config);
    742     //AConfiguration_getScreenLong(platform.app->config);
    743 
    744     // Set some default window flags
    745     CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN;       // false
    746     CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;    // false
    747     CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;     // true
    748     CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;    // false
    749     //----------------------------------------------------------------------------
    750 
    751     // Initialize App command system
    752     // NOTE: On APP_CMD_INIT_WINDOW -> InitGraphicsDevice(), InitTimer(), LoadFontDefault()...
    753     //----------------------------------------------------------------------------
    754     platform.app->onAppCmd = AndroidCommandCallback;
    755     //----------------------------------------------------------------------------
    756 
    757     // Initialize input events system
    758     //----------------------------------------------------------------------------
    759     platform.app->onInputEvent = AndroidInputCallback;
    760     //----------------------------------------------------------------------------
    761 
    762     // Initialize storage system
    763     //----------------------------------------------------------------------------
    764     InitAssetManager(platform.app->activity->assetManager, platform.app->activity->internalDataPath);   // Initialize assets manager
    765 
    766     CORE.Storage.basePath = platform.app->activity->internalDataPath;   // Define base path for storage
    767     //----------------------------------------------------------------------------
    768 
    769     TRACELOG(LOG_INFO, "PLATFORM: ANDROID: Initialized successfully");
    770 
    771     // Android ALooper_pollOnce() variables
    772     int pollResult = 0;
    773     int pollEvents = 0;
    774 
    775     // Wait for window to be initialized (display and context)
    776     while (!CORE.Window.ready)
    777     {
    778         // Process events until we reach TIMEOUT, which indicates no more events queued.
    779         while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, (void**)&platform.source)) > ALOOPER_POLL_TIMEOUT)
    780         {
    781             // Process this event
    782             if (platform.source != NULL) platform.source->process(platform.app, platform.source);
    783 
    784             // NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle.
    785             //if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true;
    786         }
    787     }
    788 
    789     return 0;
    790 }
    791 
    792 // Close platform
    793 void ClosePlatform(void)
    794 {
    795     // Close surface, context and display
    796     if (platform.device != EGL_NO_DISPLAY)
    797     {
    798         eglMakeCurrent(platform.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    799 
    800         if (platform.surface != EGL_NO_SURFACE)
    801         {
    802             eglDestroySurface(platform.device, platform.surface);
    803             platform.surface = EGL_NO_SURFACE;
    804         }
    805 
    806         if (platform.context != EGL_NO_CONTEXT)
    807         {
    808             eglDestroyContext(platform.device, platform.context);
    809             platform.context = EGL_NO_CONTEXT;
    810         }
    811 
    812         eglTerminate(platform.device);
    813         platform.device = EGL_NO_DISPLAY;
    814     }
    815 
    816     // NOTE: Reset global state in case the activity is being relaunched.
    817     if (platform.app->destroyRequested != 0) {
    818         CORE = (CoreData){0};
    819         platform = (PlatformData){0};
    820     }
    821 }
    822 
    823 // Initialize display device and framebuffer
    824 // NOTE: width and height represent the screen (framebuffer) desired size, not actual display size
    825 // If width or height are 0, default display size will be used for framebuffer size
    826 // NOTE: returns false in case graphic device could not be created
    827 static int InitGraphicsDevice(void)
    828 {
    829     CORE.Window.fullscreen = true;
    830     CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
    831 
    832     EGLint samples = 0;
    833     EGLint sampleBuffer = 0;
    834     if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
    835     {
    836         samples = 4;
    837         sampleBuffer = 1;
    838         TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
    839     }
    840 
    841     const EGLint framebufferAttribs[] =
    842     {
    843         EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT,      // Type of context support
    844         EGL_RED_SIZE, 8,            // RED color bit depth (alternative: 5)
    845         EGL_GREEN_SIZE, 8,          // GREEN color bit depth (alternative: 6)
    846         EGL_BLUE_SIZE, 8,           // BLUE color bit depth (alternative: 5)
    847         //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
    848         EGL_DEPTH_SIZE, 16,         // Depth buffer size (Required to use Depth testing!)
    849         //EGL_STENCIL_SIZE, 8,      // Stencil buffer size
    850         EGL_SAMPLE_BUFFERS, sampleBuffer,    // Activate MSAA
    851         EGL_SAMPLES, samples,       // 4x Antialiasing if activated (Free on MALI GPUs)
    852         EGL_NONE
    853     };
    854 
    855     const EGLint contextAttribs[] =
    856     {
    857         EGL_CONTEXT_CLIENT_VERSION, 2,
    858         EGL_NONE
    859     };
    860 
    861     EGLint numConfigs = 0;
    862 
    863     // Get an EGL device connection
    864     platform.device = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    865     if (platform.device == EGL_NO_DISPLAY)
    866     {
    867         TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
    868         return -1;
    869     }
    870 
    871     // Initialize the EGL device connection
    872     if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE)
    873     {
    874         // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
    875         TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
    876         return -1;
    877     }
    878 
    879     // Get an appropriate EGL framebuffer configuration
    880     eglChooseConfig(platform.device, framebufferAttribs, &platform.config, 1, &numConfigs);
    881 
    882     // Set rendering API
    883     eglBindAPI(EGL_OPENGL_ES_API);
    884 
    885     // Create an EGL rendering context
    886     platform.context = eglCreateContext(platform.device, platform.config, EGL_NO_CONTEXT, contextAttribs);
    887     if (platform.context == EGL_NO_CONTEXT)
    888     {
    889         TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context");
    890         return -1;
    891     }
    892 
    893     // Create an EGL window surface
    894     //---------------------------------------------------------------------------------
    895     EGLint displayFormat = 0;
    896 
    897     // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry()
    898     // As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID
    899     eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat);
    900 
    901     // At this point we need to manage render size vs screen size
    902     // NOTE: This function use and modify global module variables:
    903     //  -> CORE.Window.screen.width/CORE.Window.screen.height
    904     //  -> CORE.Window.render.width/CORE.Window.render.height
    905     //  -> CORE.Window.screenScale
    906     SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
    907 
    908     ANativeWindow_setBuffersGeometry(platform.app->window, CORE.Window.render.width, CORE.Window.render.height, displayFormat);
    909     //ANativeWindow_setBuffersGeometry(platform.app->window, 0, 0, displayFormat);       // Force use of native display size
    910 
    911     platform.surface = eglCreateWindowSurface(platform.device, platform.config, platform.app->window, NULL);
    912 
    913     // There must be at least one frame displayed before the buffers are swapped
    914     //eglSwapInterval(platform.device, 1);
    915 
    916     if (eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context) == EGL_FALSE)
    917     {
    918         TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface");
    919         return -1;
    920     }
    921     else
    922     {
    923         CORE.Window.render.width = CORE.Window.screen.width;
    924         CORE.Window.render.height = CORE.Window.screen.height;
    925         CORE.Window.currentFbo.width = CORE.Window.render.width;
    926         CORE.Window.currentFbo.height = CORE.Window.render.height;
    927 
    928         TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
    929         TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
    930         TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
    931         TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
    932         TRACELOG(LOG_INFO, "    > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
    933     }
    934 
    935     // Load OpenGL extensions
    936     // NOTE: GL procedures address loader is required to load extensions
    937     rlLoadExtensions(eglGetProcAddress);
    938 
    939     CORE.Window.ready = true;
    940 
    941     if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
    942 
    943     return 0;
    944 }
    945 
    946 // ANDROID: Process activity lifecycle commands
    947 static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
    948 {
    949     switch (cmd)
    950     {
    951         case APP_CMD_START:
    952         {
    953             //rendering = true;
    954         } break;
    955         case APP_CMD_RESUME: break;
    956         case APP_CMD_INIT_WINDOW:
    957         {
    958             if (app->window != NULL)
    959             {
    960                 if (platform.contextRebindRequired)
    961                 {
    962                     // Reset screen scaling to full display size
    963                     EGLint displayFormat = 0;
    964                     eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat);
    965 
    966                     // Adding renderOffset here feels rather hackish, but the viewport scaling is wrong after the
    967                     // context rebinding if the screen is scaled unless offsets are added. There's probably a more
    968                     // appropriate way to fix this
    969                     ANativeWindow_setBuffersGeometry(app->window,
    970                         CORE.Window.render.width + CORE.Window.renderOffset.x,
    971                         CORE.Window.render.height + CORE.Window.renderOffset.y,
    972                         displayFormat);
    973 
    974                     // Recreate display surface and re-attach OpenGL context
    975                     platform.surface = eglCreateWindowSurface(platform.device, platform.config, app->window, NULL);
    976                     eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context);
    977 
    978                     platform.contextRebindRequired = false;
    979                 }
    980                 else
    981                 {
    982                     CORE.Window.display.width = ANativeWindow_getWidth(platform.app->window);
    983                     CORE.Window.display.height = ANativeWindow_getHeight(platform.app->window);
    984 
    985                     // Initialize graphics device (display device and OpenGL context)
    986                     InitGraphicsDevice();
    987 
    988                     // Initialize OpenGL context (states and resources)
    989                     // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
    990                     rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
    991                     isGpuReady = true;
    992 
    993                     // Setup default viewport
    994                     // NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
    995                     SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
    996 
    997                     // Initialize hi-res timer
    998                     InitTimer();
    999 
   1000                 #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
   1001                     // Load default font
   1002                     // WARNING: External function: Module required: rtext
   1003                     LoadFontDefault();
   1004                     #if defined(SUPPORT_MODULE_RSHAPES)
   1005                     // Set font white rectangle for shapes drawing, so shapes and text can be batched together
   1006                     // WARNING: rshapes module is required, if not available, default internal white rectangle is used
   1007                     Rectangle rec = GetFontDefault().recs[95];
   1008                     if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
   1009                     {
   1010                         // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
   1011                         SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
   1012                     }
   1013                     else
   1014                     {
   1015                         // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
   1016                         SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
   1017                     }
   1018                     #endif
   1019                 #else
   1020                     #if defined(SUPPORT_MODULE_RSHAPES)
   1021                     // Set default texture and rectangle to be used for shapes drawing
   1022                     // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
   1023                     Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
   1024                     SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f });    // WARNING: Module required: rshapes
   1025                     #endif
   1026                 #endif
   1027 
   1028                     // Initialize random seed
   1029                     SetRandomSeed((unsigned int)time(NULL));
   1030 
   1031                     // TODO: GPU assets reload in case of lost focus (lost context)
   1032                     // NOTE: This problem has been solved just unbinding and rebinding context from display
   1033                     /*
   1034                     if (assetsReloadRequired)
   1035                     {
   1036                         for (int i = 0; i < assetCount; i++)
   1037                         {
   1038                             // TODO: Unload old asset if required
   1039 
   1040                             // Load texture again to pointed texture
   1041                             (*textureAsset + i) = LoadTexture(assetPath[i]);
   1042                         }
   1043                     }
   1044                     */
   1045                 }
   1046             }
   1047         } break;
   1048         case APP_CMD_GAINED_FOCUS:
   1049         {
   1050             platform.appEnabled = true;
   1051             CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
   1052             //ResumeMusicStream();
   1053         } break;
   1054         case APP_CMD_PAUSE: break;
   1055         case APP_CMD_LOST_FOCUS:
   1056         {
   1057             platform.appEnabled = false;
   1058             CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
   1059             //PauseMusicStream();
   1060         } break;
   1061         case APP_CMD_TERM_WINDOW:
   1062         {
   1063             // Detach OpenGL context and destroy display surface
   1064             // NOTE 1: This case is used when the user exits the app without closing it. We detach the context to ensure everything is recoverable upon resuming.
   1065             // NOTE 2: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...)
   1066             // NOTE 3: In some cases (too many context loaded), OS could unload context automatically... :(
   1067             if (platform.device != EGL_NO_DISPLAY)
   1068             {
   1069                 eglMakeCurrent(platform.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   1070 
   1071                 if (platform.surface != EGL_NO_SURFACE)
   1072                 {
   1073                     eglDestroySurface(platform.device, platform.surface);
   1074                     platform.surface = EGL_NO_SURFACE;
   1075                 }
   1076 
   1077                 platform.contextRebindRequired = true;
   1078             }
   1079             // If 'platform.device' is already set to 'EGL_NO_DISPLAY'
   1080             // this means that the user has already called 'CloseWindow()'
   1081 
   1082         } break;
   1083         case APP_CMD_SAVE_STATE: break;
   1084         case APP_CMD_STOP: break;
   1085         case APP_CMD_DESTROY: break;
   1086         case APP_CMD_CONFIG_CHANGED:
   1087         {
   1088             //AConfiguration_fromAssetManager(platform.app->config, platform.app->activity->assetManager);
   1089             //print_cur_config(platform.app);
   1090 
   1091             // Check screen orientation here!
   1092         } break;
   1093         default: break;
   1094     }
   1095 }
   1096 
   1097 // ANDROID: Map Android gamepad button to raylib gamepad button
   1098 static GamepadButton AndroidTranslateGamepadButton(int button)
   1099 {
   1100     switch (button)
   1101     {
   1102         case AKEYCODE_BUTTON_A: return GAMEPAD_BUTTON_RIGHT_FACE_DOWN;
   1103         case AKEYCODE_BUTTON_B: return GAMEPAD_BUTTON_RIGHT_FACE_RIGHT;
   1104         case AKEYCODE_BUTTON_X: return GAMEPAD_BUTTON_RIGHT_FACE_LEFT;
   1105         case AKEYCODE_BUTTON_Y: return GAMEPAD_BUTTON_RIGHT_FACE_UP;
   1106         case AKEYCODE_BUTTON_L1: return GAMEPAD_BUTTON_LEFT_TRIGGER_1;
   1107         case AKEYCODE_BUTTON_R1: return GAMEPAD_BUTTON_RIGHT_TRIGGER_1;
   1108         case AKEYCODE_BUTTON_L2: return GAMEPAD_BUTTON_LEFT_TRIGGER_2;
   1109         case AKEYCODE_BUTTON_R2: return GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
   1110         case AKEYCODE_BUTTON_THUMBL: return GAMEPAD_BUTTON_LEFT_THUMB;
   1111         case AKEYCODE_BUTTON_THUMBR: return GAMEPAD_BUTTON_RIGHT_THUMB;
   1112         case AKEYCODE_BUTTON_START: return GAMEPAD_BUTTON_MIDDLE_RIGHT;
   1113         case AKEYCODE_BUTTON_SELECT: return GAMEPAD_BUTTON_MIDDLE_LEFT;
   1114         case AKEYCODE_BUTTON_MODE: return GAMEPAD_BUTTON_MIDDLE;
   1115         // On some (most?) gamepads dpad events are reported as axis motion instead
   1116         case AKEYCODE_DPAD_DOWN: return GAMEPAD_BUTTON_LEFT_FACE_DOWN;
   1117         case AKEYCODE_DPAD_RIGHT: return GAMEPAD_BUTTON_LEFT_FACE_RIGHT;
   1118         case AKEYCODE_DPAD_LEFT: return GAMEPAD_BUTTON_LEFT_FACE_LEFT;
   1119         case AKEYCODE_DPAD_UP: return GAMEPAD_BUTTON_LEFT_FACE_UP;
   1120         default: return GAMEPAD_BUTTON_UNKNOWN;
   1121     }
   1122 }
   1123 
   1124 // ANDROID: Get input events
   1125 static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
   1126 {
   1127     // If additional inputs are required check:
   1128     // https://developer.android.com/ndk/reference/group/input
   1129     // https://developer.android.com/training/game-controllers/controller-input
   1130 
   1131     int type = AInputEvent_getType(event);
   1132     int source = AInputEvent_getSource(event);
   1133 
   1134     if (type == AINPUT_EVENT_TYPE_MOTION)
   1135     {
   1136         if (((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) ||
   1137             ((source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD))
   1138         {
   1139             // For now we'll assume a single gamepad which we "detect" on its input event
   1140             CORE.Input.Gamepad.ready[0] = true;
   1141 
   1142             CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_X] = AMotionEvent_getAxisValue(
   1143                     event, AMOTION_EVENT_AXIS_X, 0);
   1144             CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_Y] = AMotionEvent_getAxisValue(
   1145                     event, AMOTION_EVENT_AXIS_Y, 0);
   1146             CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_X] = AMotionEvent_getAxisValue(
   1147                     event, AMOTION_EVENT_AXIS_Z, 0);
   1148             CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_Y] = AMotionEvent_getAxisValue(
   1149                     event, AMOTION_EVENT_AXIS_RZ, 0);
   1150             CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_TRIGGER] = AMotionEvent_getAxisValue(
   1151                     event, AMOTION_EVENT_AXIS_BRAKE, 0)*2.0f - 1.0f;
   1152             CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_RIGHT_TRIGGER] = AMotionEvent_getAxisValue(
   1153                     event, AMOTION_EVENT_AXIS_GAS, 0)*2.0f - 1.0f;
   1154 
   1155             // dpad is reported as an axis on android
   1156             float dpadX = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_HAT_X, 0);
   1157             float dpadY = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_HAT_Y, 0);
   1158 
   1159             if (dpadX == 1.0f)
   1160             {
   1161                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_RIGHT] = 1;
   1162                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_LEFT] = 0;
   1163             }
   1164             else if (dpadX == -1.0f)
   1165             {
   1166                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_RIGHT] = 0;
   1167                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_LEFT] = 1;
   1168             }
   1169             else
   1170             {
   1171                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_RIGHT] = 0;
   1172                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_LEFT] = 0;
   1173             }
   1174 
   1175             if (dpadY == 1.0f)
   1176             {
   1177                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_DOWN] = 1;
   1178                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_UP] = 0;
   1179             }
   1180             else if (dpadY == -1.0f)
   1181             {
   1182                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_DOWN] = 0;
   1183                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_UP] = 1;
   1184             }
   1185             else
   1186             {
   1187                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_DOWN] = 0;
   1188                 CORE.Input.Gamepad.currentButtonState[0][GAMEPAD_BUTTON_LEFT_FACE_UP] = 0;
   1189             }
   1190 
   1191             return 1; // Handled gamepad axis motion
   1192         }
   1193     }
   1194     else if (type == AINPUT_EVENT_TYPE_KEY)
   1195     {
   1196         int32_t keycode = AKeyEvent_getKeyCode(event);
   1197         //int32_t AKeyEvent_getMetaState(event);
   1198 
   1199         // Handle gamepad button presses and releases
   1200         if (((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) ||
   1201             ((source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD))
   1202         {
   1203             // For now we'll assume a single gamepad which we "detect" on its input event
   1204             CORE.Input.Gamepad.ready[0] = true;
   1205 
   1206             GamepadButton button = AndroidTranslateGamepadButton(keycode);
   1207 
   1208             if (button == GAMEPAD_BUTTON_UNKNOWN) return 1;
   1209 
   1210             if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
   1211             {
   1212                 CORE.Input.Gamepad.currentButtonState[0][button] = 1;
   1213             }
   1214             else CORE.Input.Gamepad.currentButtonState[0][button] = 0;  // Key up
   1215 
   1216             return 1; // Handled gamepad button
   1217         }
   1218 
   1219         KeyboardKey key = (keycode > 0 && keycode < KEYCODE_MAP_SIZE)? mapKeycode[keycode] : KEY_NULL;
   1220         if (key != KEY_NULL)
   1221         {
   1222             // Save current key and its state
   1223             // NOTE: Android key action is 0 for down and 1 for up
   1224             if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
   1225             {
   1226                 CORE.Input.Keyboard.currentKeyState[key] = 1;   // Key down
   1227 
   1228                 CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
   1229                 CORE.Input.Keyboard.keyPressedQueueCount++;
   1230             }
   1231             else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_MULTIPLE) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
   1232             else CORE.Input.Keyboard.currentKeyState[key] = 0;  // Key up
   1233         }
   1234 
   1235         if (keycode == AKEYCODE_POWER)
   1236         {
   1237             // Let the OS handle input to avoid app stuck. Behaviour: CMD_PAUSE -> CMD_SAVE_STATE -> CMD_STOP -> CMD_CONFIG_CHANGED -> CMD_LOST_FOCUS
   1238             // Resuming Behaviour: CMD_START -> CMD_RESUME -> CMD_CONFIG_CHANGED -> CMD_CONFIG_CHANGED -> CMD_GAINED_FOCUS
   1239             // It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected.
   1240             // NOTE: AndroidManifest.xml must have <activity android:configChanges="orientation|keyboardHidden|screenSize" >
   1241             // Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour
   1242             return 0;
   1243         }
   1244         else if ((keycode == AKEYCODE_BACK) || (keycode == AKEYCODE_MENU))
   1245         {
   1246             // Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS!
   1247             return 1;
   1248         }
   1249         else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN))
   1250         {
   1251             // Set default OS behaviour
   1252             return 0;
   1253         }
   1254 
   1255         return 0;
   1256     }
   1257 
   1258     // Register touch points count
   1259     CORE.Input.Touch.pointCount = AMotionEvent_getPointerCount(event);
   1260 
   1261     for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
   1262     {
   1263         // Register touch points id
   1264         CORE.Input.Touch.pointId[i] = AMotionEvent_getPointerId(event, i);
   1265 
   1266         // Register touch points position
   1267         CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
   1268 
   1269         // Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
   1270         float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
   1271         float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
   1272         CORE.Input.Touch.position[i].x = CORE.Input.Touch.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
   1273         CORE.Input.Touch.position[i].y = CORE.Input.Touch.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
   1274     }
   1275 
   1276     int32_t action = AMotionEvent_getAction(event);
   1277     unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
   1278 
   1279 #if defined(SUPPORT_GESTURES_SYSTEM)
   1280     GestureEvent gestureEvent = { 0 };
   1281 
   1282     gestureEvent.pointCount = CORE.Input.Touch.pointCount;
   1283 
   1284     // Register touch actions
   1285     if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
   1286     else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_ACTION_UP;
   1287     else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE;
   1288     else if (flags == AMOTION_EVENT_ACTION_CANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL;
   1289 
   1290     for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++)
   1291     {
   1292         gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
   1293         gestureEvent.position[i] = CORE.Input.Touch.position[i];
   1294         gestureEvent.position[i].x /= (float)GetScreenWidth();
   1295         gestureEvent.position[i].y /= (float)GetScreenHeight();
   1296     }
   1297 
   1298     // Gesture data is sent to gestures system for processing
   1299     ProcessGestureEvent(gestureEvent);
   1300 #endif
   1301 
   1302     int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
   1303 
   1304     if (flags == AMOTION_EVENT_ACTION_POINTER_UP || flags == AMOTION_EVENT_ACTION_UP)
   1305     {
   1306         // One of the touchpoints is released, remove it from touch point arrays
   1307         for (int i = pointerIndex; (i < CORE.Input.Touch.pointCount - 1) && (i < MAX_TOUCH_POINTS); i++)
   1308         {
   1309             CORE.Input.Touch.pointId[i] = CORE.Input.Touch.pointId[i+1];
   1310             CORE.Input.Touch.position[i] = CORE.Input.Touch.position[i+1];
   1311         }
   1312 
   1313         CORE.Input.Touch.pointCount--;
   1314     }
   1315 
   1316     // When all touchpoints are tapped and released really quickly, this event is generated
   1317     if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;
   1318 
   1319     if (CORE.Input.Touch.pointCount > 0) CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 1;
   1320     else CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 0;
   1321 
   1322     // Stores the previous position of touch[0] only while it's active to calculate the delta.
   1323     if (flags == AMOTION_EVENT_ACTION_MOVE)
   1324     {
   1325         CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
   1326     }
   1327     else
   1328     {
   1329         CORE.Input.Mouse.previousPosition = CORE.Input.Touch.position[0];
   1330     }
   1331 
   1332     // Map touch[0] as mouse input for convenience
   1333     CORE.Input.Mouse.currentPosition = CORE.Input.Touch.position[0];
   1334     CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f };
   1335 
   1336     return 0;
   1337 }
   1338 
   1339 // EOF