packages feed

h-raylib 4.6.0.5 → 4.6.0.6

raw patch · 23 files changed

+1000/−371 lines, 23 filesPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

API changes (from Hackage documentation)

+ Raylib.Core: setWindowFocused :: IO ()
+ Raylib.Core.Text: setTextLineSpacing :: Int -> IO ()

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # h-raylib changelog
 
+## Version 4.6.0.6
+_24 July, 2023_
+
+- Updated raylib to the master branch
+
 ## Version 4.6.0.5
 _29 June, 2023_
 
h-raylib.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4
 name:               h-raylib
-version:            4.6.0.5
+version:            4.6.0.6
 synopsis:           Raylib bindings for Haskell
 category:           graphics
 description:
+ raylib/examples/core/core_input_gestures_web.c view
@@ -0,0 +1,338 @@+/*******************************************************************************************
+*
+*   raylib [core] example - Input Gestures for Web
+*
+*   Example originally created with raylib 4.6-dev, last time updated with raylib 4.6-dev
+*
+*   Example contributed by ubkp (@ubkp) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2023 ubkp (@ubkp)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "math.h"       // Required for the protractor angle graphic drawing
+
+#if defined(PLATFORM_WEB)
+    #include <emscripten/emscripten.h> // Required for the Web/HTML5
+#endif
+
+//--------------------------------------------------------------------------------------
+// Global definitions and declarations
+//--------------------------------------------------------------------------------------
+
+// Common variables definitions
+//--------------------------------------------------------------------------------------
+int screenWidth = 800;                  // Update depending on web canvas
+const int screenHeight = 450;
+Vector2 messagePosition = { 160, 7 };
+
+// Last gesture variables definitions
+//--------------------------------------------------------------------------------------
+int lastGesture = 0;
+Vector2 lastGesturePosition = { 165, 130 };
+
+// Gesture log variables definitions and functions declarations
+//--------------------------------------------------------------------------------------
+#define GESTURE_LOG_SIZE 20
+char gestureLog[GESTURE_LOG_SIZE][12] = { "" }; // The gesture log uses an array (as an inverted circular queue) to store the performed gestures
+int gestureLogIndex = GESTURE_LOG_SIZE;         // The index for the inverted circular queue (moving from last to first direction, then looping around)
+int previousGesture = 0;
+
+char const *GetGestureName(int i)
+{
+   switch (i)  {
+      case 0:   return "None";        break;
+      case 1:   return "Tap";         break;
+      case 2:   return "Double Tap";  break;
+      case 4:   return "Hold";        break;
+      case 8:   return "Drag";        break;
+      case 16:  return "Swipe Right"; break;
+      case 32:  return "Swipe Left";  break;
+      case 64:  return "Swipe Up";    break;
+      case 128: return "Swipe Down";  break;
+      case 256: return "Pinch In";    break;
+      case 512: return "Pinch Out";   break;
+      default:  return "Unknown";     break;
+   }
+}
+
+Color GetGestureColor(int i)
+{
+   switch (i)  {
+      case 0:   return BLACK;   break;
+      case 1:   return BLUE;    break;
+      case 2:   return SKYBLUE; break;
+      case 4:   return BLACK;   break;
+      case 8:   return LIME;    break;
+      case 16:  return RED;     break;
+      case 32:  return RED;     break;
+      case 64:  return RED;     break;
+      case 128: return RED;     break;
+      case 256: return VIOLET;  break;
+      case 512: return ORANGE;  break;
+      default:  return BLACK;   break;
+   }
+}
+
+int logMode = 1; // Log mode values: 0 shows repeated events; 1 hides repeated events; 2 shows repeated events but hide hold events; 3 hides repeated events and hide hold events
+
+Color gestureColor = { 0, 0, 0, 255 };
+Rectangle logButton1 = { 53, 7, 48, 26 };
+Rectangle logButton2 = { 108, 7, 36, 26 };
+Vector2 gestureLogPosition = { 10, 10 };
+
+// Protractor variables definitions
+//--------------------------------------------------------------------------------------
+float angleLength = 90.0f;
+float currentAngleDegrees = 0.0f;
+Vector2 finalVector = { 0.0f, 0.0f };
+char currentAngleStr[7] = "";
+Vector2 protractorPosition = { 266.0f, 315.0f };
+
+// Update
+//--------------------------------------------------------------------------------------
+void Update(void)
+{
+    // Handle common
+    //--------------------------------------------------------------------------------------
+    int i, ii; // Iterators that will be reused by all for loops
+    const int currentGesture = GetGestureDetected();
+    const float currentDragDegrees = GetGestureDragAngle();
+    const float currentPitchDegrees = GetGesturePinchAngle();
+    const int touchCount = GetTouchPointCount();
+
+    // Handle last gesture
+    //--------------------------------------------------------------------------------------
+    if ((currentGesture != 0) && (currentGesture != 4) && (currentGesture != previousGesture)) lastGesture = currentGesture; // Filter the meaningful gestures (1, 2, 8 to 512) for the display
+
+    // Handle gesture log
+    //--------------------------------------------------------------------------------------
+    if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT))
+    {
+        if (CheckCollisionPointRec(GetMousePosition(), logButton1))
+        {
+            switch (logMode)
+            {
+                case 3:  logMode=2; break;
+                case 2:  logMode=3; break;
+                case 1:  logMode=0; break;
+                default: logMode=1; break;
+            }
+        }
+        else if (CheckCollisionPointRec(GetMousePosition(), logButton2))
+        {
+            switch (logMode)
+            {
+                case 3:  logMode=1; break;
+                case 2:  logMode=0; break;
+                case 1:  logMode=3; break;
+                default: logMode=2; break;
+            }
+        }
+    }
+    
+    int fillLog = 0; // Gate variable to be used to allow or not the gesture log to be filled
+    if (currentGesture !=0)
+    {
+        if (logMode == 3) // 3 hides repeated events and hide hold events
+        {
+            if (((currentGesture != 4) && (currentGesture != previousGesture)) || (currentGesture < 3)) fillLog = 1;
+        }
+        else if (logMode == 2) // 2 shows repeated events but hide hold events
+        {
+            if (currentGesture != 4) fillLog = 1;
+        }
+        else if (logMode == 1) // 1 hides repeated events
+        {
+            if (currentGesture != previousGesture) fillLog = 1;
+        }
+        else  // 0 shows repeated events
+        {
+            fillLog = 1;
+        }
+    }
+    
+    if (fillLog) // If one of the conditions from logMode was met, fill the gesture log
+    {
+        previousGesture = currentGesture;
+        gestureColor = GetGestureColor(currentGesture);
+        if (gestureLogIndex <= 0) gestureLogIndex = GESTURE_LOG_SIZE;
+        gestureLogIndex--;
+        
+        // Copy the gesture respective name to the gesture log array
+        TextCopy(gestureLog[gestureLogIndex], GetGestureName(currentGesture)); 
+    }
+
+    // Handle protractor
+    //--------------------------------------------------------------------------------------
+    if (currentGesture > 255) // aka Pinch In and Pinch Out
+    {
+        currentAngleDegrees = currentPitchDegrees;
+    }
+    else if (currentGesture > 15) // aka Swipe Right, Swipe Left, Swipe Up and Swipe Down
+    {
+        currentAngleDegrees = currentDragDegrees;
+    }
+    else if (currentGesture > 0) // aka Tap, Doubletap, Hold and Grab
+    {
+        currentAngleDegrees = 0.0f;
+    }
+    
+    float currentAngleRadians = ((currentAngleDegrees +90.0f)*PI/180); // Convert the current angle to Radians
+    finalVector = (Vector2){ (angleLength*sinf(currentAngleRadians)) + protractorPosition.x, (angleLength*cosf(currentAngleRadians)) + protractorPosition.y }; // Calculate the final vector for display
+
+    // Handle touch and mouse pointer points
+    //--------------------------------------------------------------------------------------
+    #define MAX_TOUCH_COUNT     32
+    
+    Vector2 touchPosition[MAX_TOUCH_COUNT] = { 0 };
+    Vector2 mousePosition = {0, 0};
+    if (currentGesture != GESTURE_NONE)
+    {
+        if (touchCount != 0)
+        {
+            for (i = 0; i < touchCount; i++) touchPosition[i] = GetTouchPosition(i); // Fill the touch positions
+        }
+        else mousePosition = GetMousePosition();
+    }
+
+    // Draw
+    //--------------------------------------------------------------------------------------
+    BeginDrawing();
+        
+        ClearBackground(RAYWHITE);
+
+        // Draw common
+        //--------------------------------------------------------------------------------------
+        DrawText("*", messagePosition.x + 5, messagePosition.y + 5, 10, BLACK);
+        DrawText("Example optimized for Web/HTML5\non Smartphones with Touch Screen.", messagePosition.x + 15, messagePosition.y + 5, 10, BLACK);
+        DrawText("*", messagePosition.x + 5, messagePosition.y + 35, 10, BLACK);
+        DrawText("While running on Desktop Web Browsers,\ninspect and turn on Touch Emulation.", messagePosition.x + 15,  messagePosition.y + 35, 10, BLACK);
+
+        // Draw last gesture
+        //--------------------------------------------------------------------------------------
+        DrawText("Last gesture", lastGesturePosition.x + 33, lastGesturePosition.y - 47, 20, BLACK);
+        DrawText("Swipe         Tap       Pinch  Touch", lastGesturePosition.x + 17, lastGesturePosition.y - 18, 10, BLACK);
+        DrawRectangle(lastGesturePosition.x + 20, lastGesturePosition.y, 20, 20, lastGesture == GESTURE_SWIPE_UP ? RED : LIGHTGRAY);
+        DrawRectangle(lastGesturePosition.x, lastGesturePosition.y + 20, 20, 20, lastGesture == GESTURE_SWIPE_LEFT ? RED : LIGHTGRAY);
+        DrawRectangle(lastGesturePosition.x + 40, lastGesturePosition.y + 20, 20, 20, lastGesture == GESTURE_SWIPE_RIGHT ? RED : LIGHTGRAY);
+        DrawRectangle(lastGesturePosition.x + 20, lastGesturePosition.y + 40, 20, 20, lastGesture == GESTURE_SWIPE_DOWN ? RED : LIGHTGRAY);
+        DrawCircle(lastGesturePosition.x + 80, lastGesturePosition.y + 16, 10, lastGesture == GESTURE_TAP ? BLUE : LIGHTGRAY);
+        DrawRing( (Vector2){lastGesturePosition.x + 103, lastGesturePosition.y + 16}, 6.0f, 11.0f, 0.0f, 360.0f, 0, lastGesture == GESTURE_DRAG ? LIME : LIGHTGRAY);
+        DrawCircle(lastGesturePosition.x + 80, lastGesturePosition.y + 43, 10, lastGesture == GESTURE_DOUBLETAP ? SKYBLUE : LIGHTGRAY);
+        DrawCircle(lastGesturePosition.x + 103, lastGesturePosition.y + 43, 10, lastGesture == GESTURE_DOUBLETAP ? SKYBLUE : LIGHTGRAY);
+        DrawTriangle((Vector2){ lastGesturePosition.x + 122, lastGesturePosition.y + 16 }, (Vector2){ lastGesturePosition.x + 137, lastGesturePosition.y + 26 }, (Vector2){ lastGesturePosition.x + 137, lastGesturePosition.y + 6 }, lastGesture == GESTURE_PINCH_OUT? ORANGE : LIGHTGRAY);
+        DrawTriangle((Vector2){ lastGesturePosition.x + 147, lastGesturePosition.y + 6 }, (Vector2){ lastGesturePosition.x + 147, lastGesturePosition.y + 26 }, (Vector2){ lastGesturePosition.x + 162, lastGesturePosition.y + 16 }, lastGesture == GESTURE_PINCH_OUT? ORANGE : LIGHTGRAY);
+        DrawTriangle((Vector2){ lastGesturePosition.x + 125, lastGesturePosition.y + 33 }, (Vector2){ lastGesturePosition.x + 125, lastGesturePosition.y + 53 }, (Vector2){ lastGesturePosition.x + 140, lastGesturePosition.y + 43 }, lastGesture == GESTURE_PINCH_IN? VIOLET : LIGHTGRAY);
+        DrawTriangle((Vector2){ lastGesturePosition.x + 144, lastGesturePosition.y + 43 }, (Vector2){ lastGesturePosition.x + 159, lastGesturePosition.y + 53 }, (Vector2){ lastGesturePosition.x + 159, lastGesturePosition.y + 33 }, lastGesture == GESTURE_PINCH_IN? VIOLET : LIGHTGRAY);
+        for (i = 0; i < 4; i++) DrawCircle(lastGesturePosition.x + 180, lastGesturePosition.y + 7 + i*15, 5, touchCount <= i? LIGHTGRAY : gestureColor);
+
+        // Draw gesture log
+        //--------------------------------------------------------------------------------------
+        DrawText("Log", gestureLogPosition.x, gestureLogPosition.y, 20, BLACK);
+        
+        // Loop in both directions to print the gesture log array in the inverted order (and looping around if the index started somewhere in the middle)
+        for (i = 0, ii = gestureLogIndex; i < GESTURE_LOG_SIZE; i++, ii = (ii + 1) % GESTURE_LOG_SIZE) DrawText(gestureLog[ii], gestureLogPosition.x, gestureLogPosition.y + 410 - i*20, 20, (i == 0 ? gestureColor : LIGHTGRAY));
+        Color logButton1Color, logButton2Color;
+        switch (logMode)
+        {
+            case 3:  logButton1Color=MAROON; logButton2Color=MAROON; break;
+            case 2:  logButton1Color=GRAY;   logButton2Color=MAROON; break;
+            case 1:  logButton1Color=MAROON; logButton2Color=GRAY;   break;
+            default: logButton1Color=GRAY;   logButton2Color=GRAY;   break;
+        }
+        DrawRectangleRec(logButton1, logButton1Color);
+        DrawText("Hide", logButton1.x + 7, logButton1.y + 3, 10, WHITE);
+        DrawText("Repeat", logButton1.x + 7, logButton1.y + 13, 10, WHITE);
+        DrawRectangleRec(logButton2, logButton2Color);
+        DrawText("Hide", logButton1.x + 62, logButton1.y + 3, 10, WHITE);
+        DrawText("Hold", logButton1.x + 62, logButton1.y + 13, 10, WHITE);
+
+        // Draw protractor
+        //--------------------------------------------------------------------------------------
+        DrawText("Angle", protractorPosition.x + 55, protractorPosition.y + 76, 10, BLACK);
+        const char *angleString = TextFormat("%f", currentAngleDegrees);
+        const int angleStringDot = TextFindIndex(angleString, ".");
+        const char *angleStringTrim = TextSubtext(angleString, 0, angleStringDot + 3);
+        DrawText( angleStringTrim, protractorPosition.x + 55, protractorPosition.y + 92, 20, gestureColor);
+        DrawCircle(protractorPosition.x, protractorPosition.y, 80.0f, WHITE);
+        DrawLineEx((Vector2){ protractorPosition.x - 90, protractorPosition.y }, (Vector2){ protractorPosition.x + 90, protractorPosition.y }, 3.0f, LIGHTGRAY);
+        DrawLineEx((Vector2){ protractorPosition.x, protractorPosition.y - 90 }, (Vector2){ protractorPosition.x, protractorPosition.y + 90 }, 3.0f, LIGHTGRAY);
+        DrawLineEx((Vector2){ protractorPosition.x - 80, protractorPosition.y - 45 }, (Vector2){ protractorPosition.x + 80, protractorPosition.y + 45 }, 3.0f, GREEN);
+        DrawLineEx((Vector2){ protractorPosition.x - 80, protractorPosition.y + 45 }, (Vector2){ protractorPosition.x + 80, protractorPosition.y - 45 }, 3.0f, GREEN);
+        DrawText("0", protractorPosition.x + 96, protractorPosition.y - 9, 20, BLACK);
+        DrawText("30", protractorPosition.x + 74, protractorPosition.y - 68, 20, BLACK);
+        DrawText("90", protractorPosition.x - 11, protractorPosition.y - 110, 20, BLACK);
+        DrawText("150", protractorPosition.x - 100, protractorPosition.y - 68, 20, BLACK);
+        DrawText("180", protractorPosition.x - 124, protractorPosition.y - 9, 20, BLACK);
+        DrawText("210", protractorPosition.x - 100, protractorPosition.y + 50, 20, BLACK);
+        DrawText("270", protractorPosition.x - 18, protractorPosition.y + 92, 20, BLACK);
+        DrawText("330", protractorPosition.x + 72, protractorPosition.y + 50, 20, BLACK);
+        if (currentAngleDegrees != 0.0f) DrawLineEx(protractorPosition, finalVector, 3.0f, gestureColor);
+
+        // Draw touch and mouse pointer points
+        //--------------------------------------------------------------------------------------
+        if (currentGesture != GESTURE_NONE)
+        {
+            if ( touchCount != 0 )
+            {
+                for (i = 0; i < touchCount; i++)
+                {
+                    DrawCircleV(touchPosition[i], 50.0f, Fade(gestureColor, 0.5f));
+                    DrawCircleV(touchPosition[i], 5.0f, gestureColor);
+                }
+                
+                if (touchCount == 2) DrawLineEx(touchPosition[0], touchPosition[1], ((currentGesture == 512)? 8 : 12), gestureColor);
+            }
+            else
+            {
+                DrawCircleV(mousePosition, 35.0f, Fade(gestureColor, 0.5f));
+                DrawCircleV(mousePosition, 5.0f, gestureColor);
+            }
+        }
+
+    EndDrawing();
+    //--------------------------------------------------------------------------------------
+
+}
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    #if defined( PLATFORM_WEB )
+        // Using Emscripten EM_ASM_INT macro, get the page canvas width
+        const int canvasWidth = EM_ASM_INT( return document.getElementById('canvas').getBoundingClientRect().width; );
+        
+        if (canvasWidth > 400) screenWidth = canvasWidth;
+        else screenWidth = 400; // Set a minimum width for the screen
+    #endif
+
+    InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures web");
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    //--------------------------------------------------------------------------------------
+    #if defined(PLATFORM_WEB)
+        emscripten_set_main_loop(Update, 0, 1);
+    #else
+        SetTargetFPS(60);
+        while (!WindowShouldClose()) Update(); // Detect window close button or ESC key
+    #endif
+    //--------------------------------------------------------------------------------------
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow(); // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
raylib/examples/examples_template.c view
@@ -41,7 +41,7 @@ *
 *   raylib [core] example - Basic window
 *
-*   Example originally created with raylib 4.2, last time updated with raylib 4.2
+*   Example originally created with raylib 4.5, last time updated with raylib 4.5
 *
 *   Example contributed by <user_name> (@<user_github>) and reviewed by Ramon Santamaria (@raysan5)
 *
+ raylib/examples/others/raymath_vector_angle.c view
@@ -0,0 +1,106 @@+/*******************************************************************************************
+*
+*   raylib [shapes] example - Vector Angle
+*
+*   Example originally created with raylib 1.0, last time updated with raylib 4.2
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2023 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [math] example - vector angle");
+
+    Vector2 v0 = { screenWidth/2, screenHeight/2 };
+    Vector2 v1 = { 100.0f, 80.0f };
+    Vector2 v2 = { 0 };             // Updated with mouse position
+    
+    float angle = 0.0f;             // Angle in degrees
+    int angleMode = 0;              // 0-Vector2Angle(), 1-Vector2LineAngle()
+
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (IsKeyPressed(KEY_SPACE)) angleMode = !angleMode;
+        
+        if (angleMode == 0)
+        {
+            // Calculate angle between two vectors, considering a common origin (v0)
+            v1 = Vector2Add(v0, (Vector2){ 100.0f, 80.0f });
+            v2 = GetMousePosition();
+            angle = Vector2Angle(Vector2Normalize(Vector2Subtract(v1, v0)), Vector2Normalize(Vector2Subtract(v2, v0)))*RAD2DEG;
+        }
+        else if (angleMode == 1)
+        {
+            // Calculate angle defined by a two vectors line, in reference to horizontal line
+            v1 = (Vector2){ screenWidth/2, screenHeight/2 };
+            v2 = GetMousePosition();
+            angle = Vector2LineAngle(v1, v2)*RAD2DEG;
+        }
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+            
+            if (angleMode == 0) DrawText("v0", v0.x, v0.y, 10, DARKGRAY);
+            DrawText("v1", v1.x, v1.y, 10, DARKGRAY);
+            DrawText("v2", v2.x, v2.y, 10, DARKGRAY);
+
+            if (angleMode == 0)
+            {
+                DrawText("MODE: Angle between V1 and V2", 10, 10, 20, BLACK);
+                
+                DrawLineEx(v0, v1, 2.0f, BLACK);
+                DrawLineEx(v0, v2, 2.0f, RED);
+                
+                float startangle = 90 - Vector2LineAngle(v0, v1)*RAD2DEG;
+                DrawCircleSector(v0, 40.0f, startangle, startangle + angle - 360.0f*(angle > 180.0f), 32, Fade(GREEN, 0.6f));
+            }
+            else if (angleMode == 1)
+            {
+                DrawText("MODE: Angle formed by line V1 to V2", 10, 10, 20, BLACK);
+                
+                DrawLine(0, screenHeight/2, screenWidth, screenHeight/2, LIGHTGRAY);
+                DrawLineEx(v1, v2, 2.0f, RED);
+                
+                DrawCircleSector(v1, 40.0f, 90.0f, 180 - angle - 90, 32, Fade(GREEN, 0.6f));
+            }
+            
+            DrawText("Press SPACE to change MODE", 460, 10, 20, DARKGRAY);
+            DrawText(TextFormat("ANGLE: %2.2f", angle), 10, 40, 20, LIME);
+            
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
raylib/src/config.h view
@@ -181,6 +181,11 @@ // If not defined, still some functions are supported: TextLength(), TextFormat()
 #define SUPPORT_TEXT_MANIPULATION       1
 
+// On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
+// at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
+// drawing text and shapes with a single draw call [SetShapesTexture()].
+#define SUPPORT_FONT_ATLAS_WHITE_REC    1
+
 // rtext: Configuration values
 //------------------------------------------------------------------------------------
 #define MAX_TEXT_BUFFER_LENGTH       1024       // Size of internal static buffers used on some functions:
raylib/src/external/sdefl.h view
@@ -71,7 +71,7 @@ This software is available under 2 licenses -- choose whichever you prefer.
 ------------------------------------------------------------------------------
 ALTERNATIVE A - MIT License
-Copyright (c) 2020 Micha Mettke
+Copyright (c) 2020-2023 Micha Mettke
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
@@ -125,7 +125,7 @@ 
 #define SDEFL_MIN_MATCH 4
 #define SDEFL_BLK_MAX   (256*1024)
-#define SDEFL_SEQ_SIZ   ((SDEFL_BLK_MAX + SDEFL_MIN_MATCH)/SDEFL_MIN_MATCH)
+#define SDEFL_SEQ_SIZ   ((SDEFL_BLK_MAX+2)/3)
 
 #define SDEFL_SYM_MAX   (288)
 #define SDEFL_OFF_MAX   (32)
@@ -185,6 +185,7 @@ #define SDEFL_MAX_CODE_LEN      (15)
 #define SDEFL_SYM_BITS          (10u)
 #define SDEFL_SYM_MSK           ((1u << SDEFL_SYM_BITS)-1u)
+#define SDEFL_RAW_BLK_SIZE      (65535)
 #define SDEFL_LIT_LEN_CODES     (14)
 #define SDEFL_OFF_CODES         (15)
 #define SDEFL_PRE_CODES         (7)
@@ -192,6 +193,7 @@ #define SDEFL_EOB               (256)
 
 #define sdefl_npow2(n) (1 << (sdefl_ilog2((n)-1) + 1))
+#define sdefl_div_round_up(n,d) (((n)+((d)-1))/(d))
 
 static int
 sdefl_ilog2(int n) {
@@ -438,12 +440,12 @@   } while (run_start != total);
   cnt->items = (int)(at - items);
 }
-struct sdefl_match_codes {
+struct sdefl_match_codest {
   int ls, lc;
   int dc, dx;
 };
 static void
-sdefl_match_codes(struct sdefl_match_codes *cod, int dist, int len) {
+sdefl_match_codes(struct sdefl_match_codest *cod, int dist, int len) {
   static const short dxmax[] = {0,6,12,24,48,96,192,384,768,1536,3072,6144,12288,24576};
   static const unsigned char lslot[258+1] = {
     0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12,
@@ -471,7 +473,45 @@   cod->dx = sdefl_ilog2(sdefl_npow2(dist) >> 2);
   cod->dc = cod->dx ? ((cod->dx + 1) << 1) + (dist > dxmax[cod->dx]) : dist-1;
 }
+enum sdefl_blk_type {
+  SDEFL_BLK_UCOMPR,
+  SDEFL_BLK_DYN
+};
+static enum sdefl_blk_type
+sdefl_blk_type(const struct sdefl *s, int blk_len, int pre_item_len,
+               const unsigned *pre_freq, const unsigned char *pre_len) {
+  static const unsigned char x_pre_bits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+  static const unsigned char x_len_bits[] = {0,0,0,0,0,0,0,0, 1,1,1,1,2,2,2,2,
+    3,3,3,3,4,4,4,4, 5,5,5,5,0};
+  static const unsigned char x_off_bits[] = {0,0,0,0,1,1,2,2, 3,3,4,4,5,5,6,6,
+    7,7,8,8,9,9,10,10, 11,11,12,12,13,13};
+
+  int dyn_cost = 0;
+  int fix_cost = 0;
+  int sym = 0;
+
+  dyn_cost += 5 + 5 + 4 + (3 * pre_item_len);
+  for (sym = 0; sym < SDEFL_PRE_MAX; sym++)
+    dyn_cost += pre_freq[sym] * (x_pre_bits[sym] + pre_len[sym]);
+  for (sym = 0; sym < 256; sym++)
+    dyn_cost += s->freq.lit[sym] * s->cod.len.lit[sym];
+  dyn_cost += s->cod.len.lit[SDEFL_EOB];
+  for (sym = 257; sym < 286; sym++)
+    dyn_cost += s->freq.lit[sym] * (x_len_bits[sym - 257] + s->cod.len.lit[sym]);
+  for (sym = 0; sym < 30; sym++)
+    dyn_cost += s->freq.off[sym] * (x_off_bits[sym] + s->cod.len.off[sym]);
+
+  fix_cost += 8*(5 * sdefl_div_round_up(blk_len, SDEFL_RAW_BLK_SIZE) + blk_len + 1 + 2);
+  return (dyn_cost < fix_cost) ? SDEFL_BLK_DYN : SDEFL_BLK_UCOMPR;
+}
 static void
+sdefl_put16(unsigned char **dst, unsigned short x) {
+  unsigned char *val = *dst;
+  val[0] = (unsigned char)(x & 0xff);
+  val[1] = (unsigned char)(x >> 8);
+  *dst = val + 2;
+}
+static void
 sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) {
   static const char lxn[] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
   static const short lmin[] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,
@@ -479,7 +519,7 @@   static const short dmin[] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,
       385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577};
 
-  struct sdefl_match_codes cod;
+  struct sdefl_match_codest cod;
   sdefl_match_codes(&cod, dist, len);
   sdefl_put(dst, s, (int)s->cod.word.lit[cod.lc], s->cod.len.lit[cod.lc]);
   sdefl_put(dst, s, len - lmin[cod.ls], lxn[cod.ls]);
@@ -488,7 +528,8 @@ }
 static void
 sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last,
-            const unsigned char *in) {
+            const unsigned char *in, int blk_begin, int blk_end) {
+  int blk_len = blk_end - blk_begin;
   int j, i = 0, item_cnt = 0;
   struct sdefl_symcnt symcnt = {0};
   unsigned codes[SDEFL_PRE_MAX];
@@ -498,7 +539,7 @@   static const unsigned char perm[SDEFL_PRE_MAX] = {16,17,18,0,8,7,9,6,10,5,11,
       4,12,3,13,2,14,1,15};
 
-  /* huffman codes */
+  /* calculate huffman codes */
   s->freq.lit[SDEFL_EOB]++;
   sdefl_huff(s->cod.len.lit, s->cod.word.lit, s->freq.lit, SDEFL_SYM_MAX, SDEFL_LIT_LEN_CODES);
   sdefl_huff(s->cod.len.off, s->cod.word.off, s->freq.off, SDEFL_OFF_MAX, SDEFL_OFF_CODES);
@@ -509,35 +550,58 @@       break;
     }
   }
-  /* block header */
-  sdefl_put(dst, s, is_last ? 0x01 : 0x00, 1); /* block */
-  sdefl_put(dst, s, 0x02, 2); /* dynamic huffman */
-  sdefl_put(dst, s, symcnt.lit - 257, 5);
-  sdefl_put(dst, s, symcnt.off - 1, 5);
-  sdefl_put(dst, s, item_cnt - 4, 4);
-  for (i = 0; i < item_cnt; ++i) {
-    sdefl_put(dst, s, lens[perm[i]], 3);
-  }
-  for (i = 0; i < symcnt.items; ++i) {
-    unsigned sym = items[i] & 0x1F;
-    sdefl_put(dst, s, (int)codes[sym], lens[sym]);
-    if (sym < 16) continue;
-    if (sym == 16) sdefl_put(dst, s, items[i] >> 5, 2);
-    else if(sym == 17) sdefl_put(dst, s, items[i] >> 5, 3);
-    else sdefl_put(dst, s, items[i] >> 5, 7);
-  }
-  /* block sequences */
-  for (i = 0; i < s->seq_cnt; ++i) {
-    if (s->seq[i].off >= 0) {
-      for (j = 0; j < s->seq[i].len; ++j) {
-        int c = in[s->seq[i].off + j];
-        sdefl_put(dst, s, (int)s->cod.word.lit[c], s->cod.len.lit[c]);
+  /* write block */
+  switch (sdefl_blk_type(s, blk_len, item_cnt, freqs, lens)) {
+  case SDEFL_BLK_UCOMPR: {
+    /* uncompressed blocks */
+    int n = sdefl_div_round_up(blk_len, SDEFL_RAW_BLK_SIZE);
+    for (i = 0; i < n; ++i) {
+      int fin = is_last && (i + 1 == n);
+      int amount = blk_len < SDEFL_RAW_BLK_SIZE ? blk_len : SDEFL_RAW_BLK_SIZE;
+      sdefl_put(dst, s, !!fin, 1); /* block */
+      sdefl_put(dst, s, 0x00, 2); /* stored block */
+      if (s->bitcnt) {
+        sdefl_put(dst, s, 0x00, 8 - s->bitcnt);
       }
-    } else {
-      sdefl_match(dst, s, -s->seq[i].off, s->seq[i].len);
+      assert(s->bitcnt == 0);
+      sdefl_put16(dst, (unsigned short)amount);
+      sdefl_put16(dst, ~(unsigned short)amount);
+      memcpy(*dst, in + blk_begin + i * SDEFL_RAW_BLK_SIZE, amount);
+      *dst = *dst + amount;
+      blk_len -= amount;
     }
-  }
-  sdefl_put(dst, s, (int)(s)->cod.word.lit[SDEFL_EOB], (s)->cod.len.lit[SDEFL_EOB]);
+  } break;
+  case SDEFL_BLK_DYN: {
+    /* dynamic huffman block */
+    sdefl_put(dst, s, !!is_last, 1); /* block */
+    sdefl_put(dst, s, 0x02, 2); /* dynamic huffman */
+    sdefl_put(dst, s, symcnt.lit - 257, 5);
+    sdefl_put(dst, s, symcnt.off - 1, 5);
+    sdefl_put(dst, s, item_cnt - 4, 4);
+    for (i = 0; i < item_cnt; ++i) {
+      sdefl_put(dst, s, lens[perm[i]], 3);
+    }
+    for (i = 0; i < symcnt.items; ++i) {
+      unsigned sym = items[i] & 0x1F;
+      sdefl_put(dst, s, (int)codes[sym], lens[sym]);
+      if (sym < 16) continue;
+      if (sym == 16) sdefl_put(dst, s, items[i] >> 5, 2);
+      else if(sym == 17) sdefl_put(dst, s, items[i] >> 5, 3);
+      else sdefl_put(dst, s, items[i] >> 5, 7);
+    }
+    /* block sequences */
+    for (i = 0; i < s->seq_cnt; ++i) {
+      if (s->seq[i].off >= 0) {
+        for (j = 0; j < s->seq[i].len; ++j) {
+          int c = in[s->seq[i].off + j];
+          sdefl_put(dst, s, (int)s->cod.word.lit[c], s->cod.len.lit[c]);
+        }
+      } else {
+        sdefl_match(dst, s, -s->seq[i].off, s->seq[i].len);
+      }
+    }
+    sdefl_put(dst, s, (int)(s)->cod.word.lit[SDEFL_EOB], (s)->cod.len.lit[SDEFL_EOB]);
+  } break;}
   memset(&s->freq, 0, sizeof(s->freq));
   s->seq_cnt = 0;
 }
@@ -550,8 +614,12 @@ }
 static void
 sdefl_reg_match(struct sdefl *s, int off, int len) {
-  struct sdefl_match_codes cod;
+  struct sdefl_match_codest cod;
   sdefl_match_codes(&cod, off, len);
+
+  assert(cod.lc < SDEFL_SYM_MAX);
+  assert(cod.dc < SDEFL_OFF_MAX);
+
   s->freq.lit[cod.lc]++;
   s->freq.off[cod.dc]++;
 }
@@ -560,22 +628,35 @@   int len;
 };
 static void
-sdefl_fnd(struct sdefl_match *m, const struct sdefl *s,
-          int chain_len, int max_match, const unsigned char *in, int p) {
-  int i = s->tbl[sdefl_hash32(&in[p])];
-  int limit = ((p-SDEFL_WIN_SIZ)<SDEFL_NIL)?SDEFL_NIL:(p-SDEFL_WIN_SIZ);
+sdefl_fnd(struct sdefl_match *m, const struct sdefl *s, int chain_len,
+          int max_match, const unsigned char *in, int p, int e) {
+  int i = s->tbl[sdefl_hash32(in + p)];
+  int limit = ((p - SDEFL_WIN_SIZ) < SDEFL_NIL) ? SDEFL_NIL : (p-SDEFL_WIN_SIZ);
+
+  assert(p < e);
+  assert(p + max_match <= e);
   while (i > limit) {
-    if (in[i+m->len] == in[p+m->len] &&
-        (sdefl_uload32(&in[i]) == sdefl_uload32(&in[p]))){
+    assert(i + m->len < e);
+    assert(p + m->len < e);
+    assert(i + SDEFL_MIN_MATCH < e);
+    assert(p + SDEFL_MIN_MATCH < e);
+
+    if (in[i + m->len] == in[p + m->len] &&
+      (sdefl_uload32(&in[i]) == sdefl_uload32(&in[p]))) {
       int n = SDEFL_MIN_MATCH;
-      while (n < max_match && in[i+n] == in[p+n]) n++;
+      while (n < max_match && in[i + n] == in[p + n]) {
+        assert(i + n < e);
+        assert(p + n < e);
+        n++;
+      }
       if (n > m->len) {
         m->len = n, m->off = p - i;
-        if (n == max_match) break;
+        if (n == max_match)
+          break;
       }
     }
     if (!(--chain_len)) break;
-    i = s->prv[i&SDEFL_WIN_MSK];
+    i = s->prv[i & SDEFL_WIN_MSK];
   }
 }
 static int
@@ -588,19 +669,20 @@   for (n = 0; n < SDEFL_HASH_SIZ; ++n) {
     s->tbl[n] = SDEFL_NIL;
   }
-  do {int blk_end = ((i + SDEFL_BLK_MAX) < in_len) ? (i + SDEFL_BLK_MAX) : in_len;
+  do {int blk_begin = i;
+    int blk_end = ((i + SDEFL_BLK_MAX) < in_len) ? (i + SDEFL_BLK_MAX) : in_len;
     while (i < blk_end) {
       struct sdefl_match m = {0};
       int left = blk_end - i;
-      int max_match = (left >= SDEFL_MAX_MATCH) ? SDEFL_MAX_MATCH : left;
+      int max_match = (left > SDEFL_MAX_MATCH) ? SDEFL_MAX_MATCH : left;
       int nice_match = pref[lvl] < max_match ? pref[lvl] : max_match;
       int run = 1, inc = 1, run_inc = 0;
       if (max_match > SDEFL_MIN_MATCH) {
-        sdefl_fnd(&m, s, max_chain, max_match, in, i);
+        sdefl_fnd(&m, s, max_chain, max_match, in, i, in_len);
       }
-      if (lvl >= 5 && m.len >= SDEFL_MIN_MATCH && m.len < nice_match){
+      if (lvl >= 5 && m.len >= SDEFL_MIN_MATCH && m.len + 1 < nice_match){
         struct sdefl_match m2 = {0};
-        sdefl_fnd(&m2, s, max_chain, m.len+1, in, i+1);
+        sdefl_fnd(&m2, s, max_chain, m.len + 1, in, i + 1, in_len);
         m.len = (m2.len > m.len) ? 0 : m.len;
       }
       if (m.len >= SDEFL_MIN_MATCH) {
@@ -636,12 +718,12 @@       sdefl_seq(s, i - litlen, litlen);
       litlen = 0;
     }
-    sdefl_flush(&q, s, blk_end == in_len, in);
+    sdefl_flush(&q, s, blk_end == in_len, in, blk_begin, blk_end);
   } while (i < in_len);
-
-  if (s->bitcnt > 0)
+  if (s->bitcnt) {
     sdefl_put(&q, s, 0x00, 8 - s->bitcnt);
-
+  }
+  assert(s->bitcnt == 0);
   return (int)(q - out);
 }
 extern int
@@ -701,9 +783,8 @@ }
 extern int
 sdefl_bound(int len) {
-  int a = 128 + (len * 110) / 100;
-  int b = 128 + len + ((len / (31 * 1024)) + 1) * 5;
-  return (a > b) ? a : b;
+  int max_blocks = 1 + sdefl_div_round_up(len, SDEFL_RAW_BLK_SIZE);
+  int bound = 5 * max_blocks + len + 1 + 4 + 8;
+  return bound;
 }
 #endif /* SDEFL_IMPLEMENTATION */
-
raylib/src/external/sinfl.h view
@@ -72,7 +72,7 @@ This software is available under 2 licenses -- choose whichever you prefer.
 ------------------------------------------------------------------------------
 ALTERNATIVE A - MIT License
-Copyright (c) 2020 Micha Mettke
+Copyright (c) 2020-2023 Micha Mettke
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
@@ -400,17 +400,21 @@     } break;
     case stored: {
       /* uncompressed block */
-      int len, nlen;
-      sinfl_refill(&s);
+      unsigned len, nlen;
       sinfl__get(&s,s.bitcnt & 7);
-      len = sinfl__get(&s,16);
-      nlen = sinfl__get(&s,16);
-      in -= 2; s.bitcnt = 0;
+      len = (unsigned short)sinfl__get(&s,16);
+      nlen = (unsigned short)sinfl__get(&s,16);
+      s.bitptr -= s.bitcnt / 8;
+      s.bitbuf = s.bitcnt = 0;
 
-      if (len > (e-in) || !len)
+      if ((unsigned short)len != (unsigned short)~nlen)
         return (int)(out-o);
-      memcpy(out, in, (size_t)len);
-      in += len, out += len;
+      if (len > (e - s.bitptr) || !len)
+        return (int)(out-o);
+
+      memcpy(out, s.bitptr, (size_t)len);
+      s.bitptr += len, out += len;
+      if (last) return (int)(out-o);
       state = hdr;
     } break;
     case fixed: {
@@ -443,8 +447,9 @@ 
       /* decode code lengths */
       for (n = 0; n < nlit + ndist;) {
+        int sym = 0;
         sinfl_refill(&s);
-        int sym = sinfl_decode(&s, hlens, 7);
+        sym = sinfl_decode(&s, hlens, 7);
         switch (sym) {default: lens[n++] = (unsigned char)sym; break;
         case 16: for (i=3+sinfl_get(&s,2);i;i--,n++) lens[n]=lens[n-1]; break;
         case 17: for (i=3+sinfl_get(&s,3);i;i--,n++) lens[n]=0; break;
@@ -458,8 +463,9 @@     case blk: {
       /* decompress block */
       while (1) {
+        int sym;
         sinfl_refill(&s);
-        int sym = sinfl_decode(&s, s.lits, 10);
+        sym = sinfl_decode(&s, s.lits, 10);
         if (sym < 256) {
           /* literal */
           if (sinfl_unlikely(out >= oe)) {
raylib/src/raylib.h view
@@ -958,6 +958,7 @@ RLAPI void SetWindowMinSize(int width, int height);               // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)
 RLAPI void SetWindowSize(int width, int height);                  // Set window dimensions
 RLAPI void SetWindowOpacity(float opacity);                       // Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP)
+RLAPI void SetWindowFocused(void);                                // Set window focused (only PLATFORM_DESKTOP)
 RLAPI void *GetWindowHandle(void);                                // Get native window handle
 RLAPI int GetScreenWidth(void);                                   // Get current screen width
 RLAPI int GetScreenHeight(void);                                  // Get current screen height
@@ -973,7 +974,7 @@ RLAPI int GetMonitorRefreshRate(int monitor);                     // Get specified monitor refresh rate
 RLAPI Vector2 GetWindowPosition(void);                            // Get window position XY on monitor
 RLAPI Vector2 GetWindowScaleDPI(void);                            // Get window scale DPI factor
-RLAPI const char *GetMonitorName(int monitor);                    // Get the human-readable, UTF-8 encoded name of the primary monitor
+RLAPI const char *GetMonitorName(int monitor);                    // Get the human-readable, UTF-8 encoded name of the specified monitor
 RLAPI void SetClipboardText(const char *text);                    // Set clipboard text content
 RLAPI const char *GetClipboardText(void);                         // Get clipboard text content
 RLAPI void EnableEventWaiting(void);                              // Enable waiting for events on EndDrawing(), no automatic event polling
@@ -1277,7 +1278,7 @@ RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp);                            // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
 RLAPI void ImageFlipVertical(Image *image);                                                              // Flip image vertically
 RLAPI void ImageFlipHorizontal(Image *image);                                                            // Flip image horizontally
-RLAPI void ImageRotate(Image *image, int degrees);                                                       // Rotate image by input angle in degrees (-359 to 359) 
+RLAPI void ImageRotate(Image *image, int degrees);                                                       // Rotate image by input angle in degrees (-359 to 359)
 RLAPI void ImageRotateCW(Image *image);                                                                  // Rotate image clockwise 90deg
 RLAPI void ImageRotateCCW(Image *image);                                                                 // Rotate image counter-clockwise 90deg
 RLAPI void ImageColorTint(Image *image, Color color);                                                    // Modify image color: tint
@@ -1381,6 +1382,7 @@ RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint)
 
 // Text font info functions
+RLAPI void SetTextLineSpacing(int spacing);                                                 // Set vertical line spacing when drawing with line-breaks
 RLAPI int MeasureText(const char *text, int fontSize);                                      // Measure string width for default font
 RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing);    // Measure string size for Font
 RLAPI int GetGlyphIndex(Font font, int codepoint);                                          // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found
@@ -1586,10 +1588,10 @@ RLAPI void SetAudioStreamBufferSizeDefault(int size);                 // Default size for new audio streams
 RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback);  // Audio thread callback to request new data
 
-RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream
+RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream, receives the samples as <float>s
 RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream
 
-RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline
+RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives the samples as <float>s
 RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline
 
 #if defined(__cplusplus)
raylib/src/raymath.h view
@@ -314,8 +314,12 @@ // NOTE: Angle is calculated from origin point (0, 0)
 RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
 {
-    float result = atan2f(v2.y - v1.y, v2.x - v1.x);
-
+    float result = 0.0f;
+    
+    float dot = v1.x*v2.x + v1.y*v2.y;
+    float det = v1.x*v2.y - v1.y*v2.x;
+    result = -atan2f(det, dot);
+    
     return result;
 }
 
@@ -325,18 +329,8 @@ RMAPI float Vector2LineAngle(Vector2 start, Vector2 end)
 {
     float result = 0.0f;
-
-    float dot = start.x*end.x + start.y*end.y;      // Dot product
-
-    float dotClamp = (dot < -1.0f)? -1.0f : dot;    // Clamp
-    if (dotClamp > 1.0f) dotClamp = 1.0f;
-
-    result = acosf(dotClamp);
-
-    // Alternative implementation, more costly
-    //float v1Length = sqrtf((start.x*start.x) + (start.y*start.y));
-    //float v2Length = sqrtf((end.x*end.x) + (end.y*end.y));
-    //float result = -acosf((start.x*end.x + start.y*end.y)/(v1Length*v2Length));
+    
+    result = atan2f(end.y - start.y, end.x - start.x);
 
     return result;
 }
@@ -1515,11 +1509,11 @@ 
 // Get perspective projection matrix
 // NOTE: Fovy angle must be provided in radians
-RMAPI Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
+RMAPI Matrix MatrixPerspective(double fovY, double aspect, double nearPlane, double farPlane)
 {
     Matrix result = { 0 };
 
-    double top = near*tan(fovy*0.5);
+    double top = nearPlane*tan(fovY*0.5);
     double bottom = -top;
     double right = top*aspect;
     double left = -right;
@@ -1527,27 +1521,27 @@     // MatrixFrustum(-right, right, -top, top, near, far);
     float rl = (float)(right - left);
     float tb = (float)(top - bottom);
-    float fn = (float)(far - near);
+    float fn = (float)(farPlane - nearPlane);
 
-    result.m0 = ((float)near*2.0f)/rl;
-    result.m5 = ((float)near*2.0f)/tb;
+    result.m0 = ((float)nearPlane*2.0f)/rl;
+    result.m5 = ((float)nearPlane*2.0f)/tb;
     result.m8 = ((float)right + (float)left)/rl;
     result.m9 = ((float)top + (float)bottom)/tb;
-    result.m10 = -((float)far + (float)near)/fn;
+    result.m10 = -((float)farPlane + (float)nearPlane)/fn;
     result.m11 = -1.0f;
-    result.m14 = -((float)far*(float)near*2.0f)/fn;
+    result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn;
 
     return result;
 }
 
 // Get orthographic projection matrix
-RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far)
+RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane)
 {
     Matrix result = { 0 };
 
     float rl = (float)(right - left);
     float tb = (float)(top - bottom);
-    float fn = (float)(far - near);
+    float fn = (float)(farPlane - nearPlane);
 
     result.m0 = 2.0f/rl;
     result.m1 = 0.0f;
@@ -1563,7 +1557,7 @@     result.m11 = 0.0f;
     result.m12 = -((float)left + (float)right)/rl;
     result.m13 = -((float)top + (float)bottom)/tb;
-    result.m14 = -((float)far + (float)near)/fn;
+    result.m14 = -((float)farPlane + (float)nearPlane)/fn;
     result.m15 = 1.0f;
 
     return result;
raylib/src/rcamera.h view
@@ -3,12 +3,12 @@ *   rcamera - Basic camera system with support for multiple camera modes
 *
 *   CONFIGURATION:
-*       #define CAMERA_IMPLEMENTATION
+*       #define RCAMERA_IMPLEMENTATION
 *           Generates the implementation of the library into the included file.
 *           If not defined, the library is in header only mode and can be included in other headers
 *           or source files without problems. But only ONE file should hold the implementation.
 *
-*       #define CAMERA_STANDALONE
+*       #define RCAMERA_STANDALONE
 *           If defined, the library can be used as standalone as a camera system but some
 *           functions must be redefined to manage inputs accordingly.
 *
@@ -50,7 +50,7 @@     #define RLAPI       // Functions defined as 'extern' by default (implicit specifiers)
 #endif
 
-#if defined(CAMERA_STANDALONE)
+#if defined(RCAMERA_STANDALONE)
     #define CAMERA_CULL_DISTANCE_NEAR      0.01
     #define CAMERA_CULL_DISTANCE_FAR    1000.0
 #else
@@ -60,9 +60,9 @@ 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
-// NOTE: Below types are required for CAMERA_STANDALONE usage
+// NOTE: Below types are required for standalone usage
 //----------------------------------------------------------------------------------
-#if defined(CAMERA_STANDALONE)
+#if defined(RCAMERA_STANDALONE)
     // Vector2, 2 components
     typedef struct Vector2 {
         float x;                // Vector x component
@@ -76,6 +76,14 @@         float z;                // Vector z component
     } Vector3;
 
+    // Matrix, 4x4 components, column major, OpenGL style, right-handed
+    typedef struct Matrix {
+        float m0, m4, m8, m12;  // Matrix first row (4 components)
+        float m1, m5, m9, m13;  // Matrix second row (4 components)
+        float m2, m6, m10, m14; // Matrix third row (4 components)
+        float m3, m7, m11, m15; // Matrix fourth row (4 components)
+    } Matrix;
+
     // Camera type, defines a camera position/orientation in 3d space
     typedef struct Camera3D {
         Vector3 position;       // Camera position
@@ -138,7 +146,7 @@ }
 #endif
 
-#endif // CAMERA_H
+#endif // RCAMERA_H
 
 
 /***********************************************************************************
@@ -147,7 +155,7 @@ *
 ************************************************************************************/
 
-#if defined(CAMERA_IMPLEMENTATION)
+#if defined(RCAMERA_IMPLEMENTATION)
 
 #include "raymath.h"        // Required for vector maths:
                             // Vector3Add()
@@ -417,7 +425,7 @@     return MatrixIdentity();
 }
 
-#ifndef CAMERA_STANDALONE
+#if !defined(RCAMERA_STANDALONE)
 // Update camera position for selected mode
 // Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM
 void UpdateCamera(Camera *camera, int mode)
@@ -483,7 +491,7 @@         if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f);
     }
 }
-#endif // !CAMERA_STANDALONE
+#endif // !RCAMERA_STANDALONE
 
 // Update camera movement, movement/rotation values should be provided by user
 void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom)
@@ -516,4 +524,4 @@     CameraMoveToTarget(camera, zoom);
 }
 
-#endif // CAMERA_IMPLEMENTATION
+#endif // RCAMERA_IMPLEMENTATION
raylib/src/rcore.c view
@@ -124,12 +124,12 @@ #include "raymath.h"                // Vector3, Quaternion and Matrix functionality
 
 #if defined(SUPPORT_GESTURES_SYSTEM)
-    #define GESTURES_IMPLEMENTATION
+    #define RGESTURES_IMPLEMENTATION
     #include "rgestures.h"           // Gestures detection functionality
 #endif
 
 #if defined(SUPPORT_CAMERA_SYSTEM)
-    #define CAMERA_IMPLEMENTATION
+    #define RCAMERA_IMPLEMENTATION
     #include "rcamera.h"             // Camera system functionality
 #endif
 
@@ -468,6 +468,7 @@             Vector2 currentWheelMove;       // Registers current mouse wheel variation
             Vector2 previousWheelMove;      // Registers previous mouse wheel variation
 #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
+            Vector2 eventWheelMove;         // Registers the event mouse wheel variation
             // NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update
             char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab
 #endif
@@ -717,17 +718,17 @@     char arg0[] = "raylib";     // NOTE: argv[] are mutable
     CORE.Android.app = app;
 
-    // NOTE: Return codes != 0 are skipped
-    (void)main(1, (char *[]) { arg0, NULL });
+    // NOTE: We get the main return for exit()
+    int ret = main(1, (char *[]) { arg0, NULL });
 
-    // Finish native activity
-    ANativeActivity_finish(CORE.Android.app->activity);
+    // Request to end the native activity
+    ANativeActivity_finish(app->activity);
 
     // Android ALooper_pollAll() variables
     int pollResult = 0;
     int pollEvents = 0;
 
-    // Wait for app events to close
+    // Waiting for application events before complete finishing
     while (!CORE.Android.app->destroyRequested)
     {
         while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void **)&CORE.Android.source)) >= 0)
@@ -736,8 +737,11 @@         }
     }
 
-    // WARNING: Check for deallocation and ensure no other processes are running from the application
-    exit(0);    // Closes the application completely without going through Java
+    // WARNING: Make sure you free resources properly and no other process is running from Java code or other.
+    // NOTE: You can use JNI to call a NativeLoader method (which will call finish() from the UI thread)
+    // to handle the full close from Java, without using exit(0) like here.
+
+    exit(ret);    // Close the application directly, without going through Java
 }
 
 // NOTE: Add this to header (if apps really need it)
@@ -1702,6 +1706,14 @@ #endif
 }
 
+// Set window focused
+void SetWindowFocused(void)
+{
+#if defined(PLATFORM_DESKTOP)
+    glfwFocusWindow(CORE.Window.handle);
+#endif
+}
+
 // Get current screen width
 int GetScreenWidth(void)
 {
@@ -3216,7 +3228,7 @@ 
 #if defined(_WIN32)
     int len = 0;
-#if defined (UNICODE)
+#if defined(UNICODE)
     unsigned short widePath[MAX_PATH];
     len = GetModuleFileNameW(NULL, widePath, MAX_PATH);
     len = WideCharToMultiByte(0, 0, widePath, len, appDir, MAX_PATH, NULL, NULL);
@@ -5051,7 +5063,8 @@ 
     // Register previous mouse states
     CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
-    CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f };
+    CORE.Input.Mouse.currentWheelMove = CORE.Input.Mouse.eventWheelMove;
+    CORE.Input.Mouse.eventWheelMove = (Vector2){ 0.0f, 0.0f };
     for (int i = 0; i < MAX_MOUSE_BUTTONS; i++)
     {
         CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
@@ -5582,8 +5595,14 @@     gestureEvent.position[0].y /= (float)GetScreenHeight();
 
     // Gesture data is sent to gestures-system for processing
+#if defined(PLATFORM_WEB)
+    // Prevent calling ProcessGestureEvent() when Emscripten is present and there's a touch gesture, so EmscriptenTouchCallback() can handle it itself
+    if (GetMouseX() != 0 || GetMouseY() != 0) ProcessGestureEvent(gestureEvent);
+#else
     ProcessGestureEvent(gestureEvent);
 #endif
+
+#endif
 }
 
 // GLFW3 Cursor Position Callback, runs on mouse move
@@ -6120,10 +6139,17 @@     {
         gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
         gestureEvent.position[i] = CORE.Input.Touch.position[i];
+
+        // Normalize gestureEvent.position[i]
+        gestureEvent.position[i].x /= (float)GetScreenWidth();
+        gestureEvent.position[i].y /= (float)GetScreenHeight();
     }
 
     // Gesture data is sent to gestures system for processing
     ProcessGestureEvent(gestureEvent);
+
+    // Reset the pointCount for web, if it was the last Touch End event
+    if (eventType == EMSCRIPTEN_EVENT_TOUCHEND && CORE.Input.Touch.pointCount == 1) CORE.Input.Touch.pointCount = 0;
 #endif
 
     return 1;   // The event was consumed by the callback handler
@@ -6653,7 +6679,7 @@                     gestureUpdate = true;
                 }
 
-                if (event.code == REL_WHEEL) CORE.Input.Mouse.currentWheelMove.y += event.value;
+                if (event.code == REL_WHEEL) CORE.Input.Mouse.eventWheelMove.y += event.value;
             }
 
             // Absolute movement parsing
raylib/src/rgestures.h view
@@ -3,12 +3,12 @@ *   rgestures - Gestures system, gestures processing based on input events (touch/mouse)
 *
 *   CONFIGURATION:
-*       #define GESTURES_IMPLEMENTATION
+*       #define RGESTURES_IMPLEMENTATION
 *           Generates the implementation of the library into the included file.
 *           If not defined, the library is in header only mode and can be included in other headers
 *           or source files without problems. But only ONE file should hold the implementation.
 *
-*       #define GESTURES_STANDALONE
+*       #define RGESTURES_STANDALONE
 *           If defined, the library can be used as standalone to process gesture events with
 *           no external dependencies.
 *
@@ -56,7 +56,7 @@ 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
-// NOTE: Below types are required for GESTURES_STANDALONE usage
+// NOTE: Below types are required for standalone usage
 //----------------------------------------------------------------------------------
 // Boolean type
 #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
@@ -73,7 +73,7 @@ } Vector2;
 #endif
 
-#if defined(GESTURES_STANDALONE)
+#if defined(RGESTURES_STANDALONE)
 // Gestures type
 // NOTE: It could be used as flags to enable only some gestures
 typedef enum {
@@ -122,12 +122,12 @@ void ProcessGestureEvent(GestureEvent event);           // Process gesture event and translate it into gestures
 void UpdateGestures(void);                              // Update gestures detected (must be called every frame)
 
-#if defined(GESTURES_STANDALONE)
+#if defined(RGESTURES_STANDALONE)
 void SetGesturesEnabled(unsigned int flags);            // Enable a set of gestures using flags
 bool IsGestureDetected(int gesture);                    // Check if a gesture have been detected
 int GetGestureDetected(void);                           // Get latest detected gesture
 
-float GetGestureHoldDuration(void);                     // Get gesture hold time in milliseconds
+float GetGestureHoldDuration(void);                     // Get gesture hold time in seconds
 Vector2 GetGestureDragVector(void);                     // Get gesture drag vector
 float GetGestureDragAngle(void);                        // Get gesture drag angle
 Vector2 GetGesturePinchVector(void);                    // Get gesture pinch delta
@@ -138,17 +138,17 @@ }
 #endif
 
-#endif // GESTURES_H
+#endif // RGESTURES_H
 
 /***********************************************************************************
 *
-*   GESTURES IMPLEMENTATION
+*   RGESTURES IMPLEMENTATION
 *
 ************************************************************************************/
 
-#if defined(GESTURES_IMPLEMENTATION)
+#if defined(RGESTURES_IMPLEMENTATION)
 
-#if defined(GESTURES_STANDALONE)
+#if defined(RGESTURES_STANDALONE)
 #if defined(_WIN32)
     #if defined(__cplusplus)
     extern "C" {        // Prevents name mangling of functions
@@ -178,11 +178,12 @@ //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
-#define FORCE_TO_SWIPE      0.0005f     // Swipe force, measured in normalized screen units/time
+#define FORCE_TO_SWIPE      0.2f        // Swipe force, measured in normalized screen units/time
 #define MINIMUM_DRAG        0.015f      // Drag minimum force, measured in normalized screen units (0.0f to 1.0f)
+#define DRAG_TIMEOUT        0.3f        // Drag minimum time for web, measured in seconds
 #define MINIMUM_PINCH       0.005f      // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f)
-#define TAP_TIMEOUT         300         // Tap minimum time, measured in milliseconds
-#define PINCH_TIMEOUT       300         // Pinch minimum time, measured in milliseconds
+#define TAP_TIMEOUT         0.3f        // Tap minimum time, measured in seconds
+#define PINCH_TIMEOUT       0.3f        // Pinch minimum time, measured in seconds
 #define DOUBLETAP_RANGE     0.03f       // DoubleTap range, measured in normalized screen units (0.0f to 1.0f)
 
 //----------------------------------------------------------------------------------
@@ -203,11 +204,13 @@         Vector2 downDragPosition;       // Touch drag position
         Vector2 moveDownPositionA;      // First touch down position on move
         Vector2 moveDownPositionB;      // Second touch down position on move
+        Vector2 previousPositionA;      // Previous position A to compare for pinch gestures
+        Vector2 previousPositionB;      // Previous position B to compare for pinch gestures
         int tapCounter;                 // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions)
     } Touch;
     struct {
         bool resetRequired;             // HOLD reset to get first touch point again
-        double timeDuration;            // HOLD duration in milliseconds
+        double timeDuration;            // HOLD duration in seconds
     } Hold;
     struct {
         Vector2 vector;                 // DRAG vector (between initial and current position)
@@ -216,8 +219,7 @@         float intensity;                // DRAG intensity, how far why did the DRAG (pixels per frame)
     } Drag;
     struct {
-        bool start;                     // SWIPE used to define when start measuring GESTURES.Swipe.timeDuration
-        double timeDuration;            // SWIPE time to calculate drag intensity
+        double startTime;               // SWIPE start time to calculate drag intensity
     } Swipe;
     struct {
         Vector2 vector;                 // PINCH vector (between first and second touch points)
@@ -289,30 +291,29 @@             GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA;
             GESTURES.Touch.eventTime = rgGetCurrentTime();
 
-            GESTURES.Touch.firstId = event.pointId[0];
+            GESTURES.Swipe.startTime = rgGetCurrentTime();
 
             GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f };
         }
         else if (event.touchAction == TOUCH_ACTION_UP)
         {
-            if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0];
+            // A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases
+            if (GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD) GESTURES.Touch.upPosition = event.position[0];
 
             // NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen
             GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
-            GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.timeDuration));
-
-            GESTURES.Swipe.start = false;
+            GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.startTime));
 
             // Detect GESTURE_SWIPE
-            if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.Touch.firstId == event.pointId[0]))
+            if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.current != GESTURE_DRAG))
             {
                 // NOTE: Angle should be inverted in Y
                 GESTURES.Drag.angle = 360.0f - rgVector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
 
-                if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT;        // Right
-                else if ((GESTURES.Drag.angle > 30) && (GESTURES.Drag.angle < 120)) GESTURES.current = GESTURE_SWIPE_UP;      // Up
-                else if ((GESTURES.Drag.angle > 120) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT;   // Left
-                else if ((GESTURES.Drag.angle > 210) && (GESTURES.Drag.angle < 300)) GESTURES.current = GESTURE_SWIPE_DOWN;   // Down
+                if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT;          // Right
+                else if ((GESTURES.Drag.angle >= 30) && (GESTURES.Drag.angle <= 150)) GESTURES.current = GESTURE_SWIPE_UP;      // Up
+                else if ((GESTURES.Drag.angle > 150) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT;     // Left
+                else if ((GESTURES.Drag.angle >= 210) && (GESTURES.Drag.angle <= 330)) GESTURES.current = GESTURE_SWIPE_DOWN;   // Down
                 else GESTURES.current = GESTURE_NONE;
             }
             else
@@ -329,14 +330,6 @@         }
         else if (event.touchAction == TOUCH_ACTION_MOVE)
         {
-            if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.eventTime = rgGetCurrentTime();
-
-            if (!GESTURES.Swipe.start)
-            {
-                GESTURES.Swipe.timeDuration = rgGetCurrentTime();
-                GESTURES.Swipe.start = true;
-            }
-
             GESTURES.Touch.moveDownPositionA = event.position[0];
 
             if (GESTURES.current == GESTURE_HOLD)
@@ -346,7 +339,7 @@                 GESTURES.Hold.resetRequired = false;
 
                 // Detect GESTURE_DRAG
-                if (rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_DRAG)
+                if ((rgGetCurrentTime() - GESTURES.Touch.eventTime) > DRAG_TIMEOUT)
                 {
                     GESTURES.Touch.eventTime = rgGetCurrentTime();
                     GESTURES.current = GESTURE_DRAG;
@@ -364,6 +357,9 @@             GESTURES.Touch.downPositionA = event.position[0];
             GESTURES.Touch.downPositionB = event.position[1];
 
+            GESTURES.Touch.previousPositionA = GESTURES.Touch.downPositionA;
+            GESTURES.Touch.previousPositionB = GESTURES.Touch.downPositionB;
+
             //GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB);
 
             GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x;
@@ -376,18 +372,15 @@         {
             GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
 
-            GESTURES.Touch.downPositionA = GESTURES.Touch.moveDownPositionA;
-            GESTURES.Touch.downPositionB = GESTURES.Touch.moveDownPositionB;
-
             GESTURES.Touch.moveDownPositionA = event.position[0];
             GESTURES.Touch.moveDownPositionB = event.position[1];
 
             GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x;
             GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y;
 
-            if ((rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.downPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH))
+            if ((rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.previousPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH))
             {
-                if ((rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) - GESTURES.Pinch.distance) < 0) GESTURES.current = GESTURE_PINCH_IN;
+                if ( rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.previousPositionB) > rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) ) GESTURES.current = GESTURE_PINCH_IN;
                 else GESTURES.current = GESTURE_PINCH_OUT;
             }
             else
@@ -427,13 +420,6 @@         GESTURES.Hold.timeDuration = rgGetCurrentTime();
     }
 
-    if (((rgGetCurrentTime() - GESTURES.Touch.eventTime) > TAP_TIMEOUT) && (GESTURES.current == GESTURE_DRAG) && (GESTURES.Touch.pointCount < 2))
-    {
-        GESTURES.current = GESTURE_HOLD;
-        GESTURES.Hold.timeDuration = rgGetCurrentTime();
-        GESTURES.Hold.resetRequired = true;
-    }
-
     // Detect GESTURE_NONE
     if ((GESTURES.current == GESTURE_SWIPE_RIGHT) || (GESTURES.current == GESTURE_SWIPE_UP) || (GESTURES.current == GESTURE_SWIPE_LEFT) || (GESTURES.current == GESTURE_SWIPE_DOWN))
     {
@@ -520,12 +506,12 @@     return result;
 }
 
-// Time measure returned are milliseconds
+// Time measure returned are seconds
 static double rgGetCurrentTime(void)
 {
     double time = 0;
 
-#if !defined(GESTURES_STANDALONE)
+#if !defined(RGESTURES_STANDALONE)
     time = GetTime();
 #else
 #if defined(_WIN32)
@@ -534,7 +520,7 @@     QueryPerformanceFrequency(&clockFrequency);     // BE CAREFUL: Costly operation!
     QueryPerformanceCounter(&currentTime);
 
-    time = (double)currentTime/clockFrequency*1000.0f;  // Time in miliseconds
+    time = (double)currentTime/clockFrequency;  // Time in seconds
 #endif
 
 #if defined(__linux__)
@@ -543,7 +529,7 @@     clock_gettime(CLOCK_MONOTONIC, &now);
     unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;     // Time in nanoseconds
 
-    time = ((double)nowTime/1000000.0);     // Time in miliseconds
+    time = ((double)nowTime*1e-9);     // Time in seconds
 #endif
 
 #if defined(__APPLE__)
@@ -559,11 +545,11 @@     mach_port_deallocate(mach_task_self(), cclock);
     unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;     // Time in nanoseconds
 
-    time = ((double)nowTime/1000000.0);     // Time in miliseconds
+    time = ((double)nowTime*1e-9);     // Time in seconds
 #endif
 #endif
 
     return time;
 }
 
-#endif // GESTURES_IMPLEMENTATION
+#endif // RGESTURES_IMPLEMENTATION
raylib/src/rlgl.h view
@@ -390,7 +390,7 @@     RL_OPENGL_33,               // OpenGL 3.3 (GLSL 330)
     RL_OPENGL_43,               // OpenGL 4.3 (using GLSL 330)
     RL_OPENGL_ES_20,            // OpenGL ES 2.0 (GLSL 100)
-    RL_OPENGL_ES_30             // OpenGL ES 3.0 (GLSL 300 es)    
+    RL_OPENGL_ES_30             // OpenGL ES 3.0 (GLSL 300 es)
 } rlGlVersion;
 
 // Trace log level
@@ -4143,7 +4143,7 @@     glGenBuffers(1, &ssbo);
     glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
     glBufferData(GL_SHADER_STORAGE_BUFFER, size, data, usageHint? usageHint : RL_STREAM_COPY);
-    glClearBufferData(GL_SHADER_STORAGE_BUFFER, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0);
+    if (data == NULL) glClearBufferData(GL_SHADER_STORAGE_BUFFER, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL);    // Clear buffer data to 0
     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
 #endif
 
raylib/src/rmodels.c view
@@ -1857,35 +1857,34 @@ 
 #if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
 // Process obj materials
-static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount)
+static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, int materialCount)
 {
-    // Init model materials
+    // Init model mats
     for (int m = 0; m < materialCount; m++)
     {
         // Init material to default
         // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE
-        rayMaterials[m] = LoadMaterialDefault();
+        materials[m] = LoadMaterialDefault();
 
         // Get default texture, in case no texture is defined
         // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
-        rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
-
-        if (materials[m].diffuse_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname);  //char *diffuse_texname; // map_Kd
+        materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
 
-        rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(materials[m].diffuse[0]*255.0f), (unsigned char)(materials[m].diffuse[1]*255.0f), (unsigned char)(materials[m].diffuse[2] * 255.0f), 255 }; //float diffuse[3];
-        rayMaterials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
+        if (mats[m].diffuse_texname != NULL) materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(mats[m].diffuse_texname);  //char *diffuse_texname; // map_Kd
+        else materials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(mats[m].diffuse[0]*255.0f), (unsigned char)(mats[m].diffuse[1]*255.0f), (unsigned char)(mats[m].diffuse[2] * 255.0f), 255 }; //float diffuse[3];
+        materials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
 
-        if (materials[m].specular_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(materials[m].specular_texname);  //char *specular_texname; // map_Ks
-        rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(materials[m].specular[0]*255.0f), (unsigned char)(materials[m].specular[1]*255.0f), (unsigned char)(materials[m].specular[2] * 255.0f), 255 }; //float specular[3];
-        rayMaterials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f;
+        if (mats[m].specular_texname != NULL) materials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(mats[m].specular_texname);  //char *specular_texname; // map_Ks
+        materials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(mats[m].specular[0]*255.0f), (unsigned char)(mats[m].specular[1]*255.0f), (unsigned char)(mats[m].specular[2] * 255.0f), 255 }; //float specular[3];
+        materials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f;
 
-        if (materials[m].bump_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(materials[m].bump_texname);  //char *bump_texname; // map_bump, bump
-        rayMaterials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE;
-        rayMaterials[m].maps[MATERIAL_MAP_NORMAL].value = materials[m].shininess;
+        if (mats[m].bump_texname != NULL) materials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(mats[m].bump_texname);  //char *bump_texname; // map_bump, bump
+        materials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE;
+        materials[m].maps[MATERIAL_MAP_NORMAL].value = mats[m].shininess;
 
-        rayMaterials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(materials[m].emission[0]*255.0f), (unsigned char)(materials[m].emission[1]*255.0f), (unsigned char)(materials[m].emission[2] * 255.0f), 255 }; //float emission[3];
+        materials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(mats[m].emission[0]*255.0f), (unsigned char)(mats[m].emission[1]*255.0f), (unsigned char)(mats[m].emission[2] * 255.0f), 255 }; //float emission[3];
 
-        if (materials[m].displacement_texname != NULL) rayMaterials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(materials[m].displacement_texname);  //char *displacement_texname; // disp
+        if (mats[m].displacement_texname != NULL) materials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(mats[m].displacement_texname);  //char *displacement_texname; // disp
     }
 }
 #endif
@@ -5379,7 +5378,7 @@ 
                 strncpy(animations[i].name, animData.name, sizeof(animations[i].name));
                 animations[i].name[sizeof(animations[i].name) - 1] = '\0';
-                
+
                 animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY);
                 animations[i].framePoses = RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
 
raylib/src/rshapes.c view
@@ -80,7 +80,7 @@ //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-Texture2D texShapes = { 1, 1, 1, 1, 7 };                // Texture used on shapes drawing (usually a white pixel)
+Texture2D texShapes = { 1, 1, 1, 1, 7 };                // Texture used on shapes drawing (white pixel loaded by rlgl)
 Rectangle texShapesRec = { 0.0f, 0.0f, 1.0f, 1.0f };    // Texture source rectangle used on shapes drawing
 
 //----------------------------------------------------------------------------------
@@ -97,8 +97,19 @@ // defining a font char white rectangle would allow drawing everything in a single draw call
 void SetShapesTexture(Texture2D texture, Rectangle source)
 {
-    texShapes = texture;
-    texShapesRec = source;
+    // Reset texture to default pixel if required
+    // WARNING: Shapes texture should be probably better validated,
+    // it can break the rendering of all shapes if missused
+    if ((texture.id == 0) || (source.width == 0) || (source.height == 0))
+    {
+        texShapes = (Texture2D){ 1, 1, 1, 1, 7 };
+        texShapesRec = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f };
+    }
+    else
+    {
+        texShapes = texture;
+        texShapesRec = source;
+    }
 }
 
 // Draw a pixel
@@ -382,14 +393,14 @@             rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
             rlVertex2f(center.x, center.y);
 
-            rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
+            rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2))*radius);
 
             rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
 
-            rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius);
+            rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
 
             angle += (stepLength*2);
         }
@@ -402,12 +413,12 @@             rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
             rlVertex2f(center.x, center.y);
 
-            rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
-
             rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
 
+            rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+
             rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
             rlVertex2f(center.x, center.y);
         }
@@ -421,8 +432,8 @@             rlColor4ub(color.r, color.g, color.b, color.a);
 
             rlVertex2f(center.x, center.y);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
 
             angle += stepLength;
         }
@@ -464,15 +475,15 @@         {
             rlColor4ub(color.r, color.g, color.b, color.a);
             rlVertex2f(center.x, center.y);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
         }
 
         for (int i = 0; i < segments; i++)
         {
             rlColor4ub(color.r, color.g, color.b, color.a);
 
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
 
             angle += stepLength;
         }
@@ -481,7 +492,7 @@         {
             rlColor4ub(color.r, color.g, color.b, color.a);
             rlVertex2f(center.x, center.y);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
         }
     rlEnd();
 }
@@ -496,9 +507,9 @@             rlColor4ub(color1.r, color1.g, color1.b, color1.a);
             rlVertex2f((float)centerX, (float)centerY);
             rlColor4ub(color2.r, color2.g, color2.b, color2.a);
-            rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radius, (float)centerY + cosf(DEG2RAD*i)*radius);
+            rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radius, (float)centerY + sinf(DEG2RAD*(i + 10))*radius);
             rlColor4ub(color2.r, color2.g, color2.b, color2.a);
-            rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radius, (float)centerY + cosf(DEG2RAD*(i + 10))*radius);
+            rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radius, (float)centerY + sinf(DEG2RAD*i)*radius);
         }
     rlEnd();
 }
@@ -519,8 +530,8 @@         // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
         for (int i = 0; i < 360; i += 10)
         {
-            rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius);
-            rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius);
+            rlVertex2f(centerX + cosf(DEG2RAD*i)*radius, centerY + sinf(DEG2RAD*i)*radius);
+            rlVertex2f(centerX + cosf(DEG2RAD*(i + 10))*radius, centerY + sinf(DEG2RAD*(i + 10))*radius);
         }
     rlEnd();
 }
@@ -533,8 +544,8 @@         {
             rlColor4ub(color.r, color.g, color.b, color.a);
             rlVertex2f((float)centerX, (float)centerY);
-            rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radiusH, (float)centerY + cosf(DEG2RAD*i)*radiusV);
-            rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radiusH, (float)centerY + cosf(DEG2RAD*(i + 10))*radiusV);
+            rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radiusH, (float)centerY + sinf(DEG2RAD*(i + 10))*radiusV);
+            rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radiusH, (float)centerY + sinf(DEG2RAD*i)*radiusV);
         }
     rlEnd();
 }
@@ -546,8 +557,8 @@         for (int i = 0; i < 360; i += 10)
         {
             rlColor4ub(color.r, color.g, color.b, color.a);
-            rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV);
-            rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV);
+            rlVertex2f(centerX + cosf(DEG2RAD*(i + 10))*radiusH, centerY + sinf(DEG2RAD*(i + 10))*radiusV);
+            rlVertex2f(centerX + cosf(DEG2RAD*i)*radiusH, centerY + sinf(DEG2RAD*i)*radiusV);
         }
     rlEnd();
 }
@@ -605,18 +616,18 @@         {
             rlColor4ub(color.r, color.g, color.b, color.a);
 
-            rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
-
             rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
 
-            rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
+            rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
 
             rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
 
+            rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
+
             angle += stepLength;
         }
     rlEnd();
@@ -628,13 +639,13 @@         {
             rlColor4ub(color.r, color.g, color.b, color.a);
 
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
 
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
 
             angle += stepLength;
         }
@@ -691,19 +702,19 @@         if (showCapLines)
         {
             rlColor4ub(color.r, color.g, color.b, color.a);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
         }
 
         for (int i = 0; i < segments; i++)
         {
             rlColor4ub(color.r, color.g, color.b, color.a);
 
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
 
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
 
             angle += stepLength;
         }
@@ -711,8 +722,8 @@         if (showCapLines)
         {
             rlColor4ub(color.r, color.g, color.b, color.a);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
         }
     rlEnd();
 }
@@ -971,7 +982,7 @@     };
 
     const Vector2 centers[4] = { point[8], point[9], point[10], point[11] };
-    const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f };
+    const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
 
 #if defined(SUPPORT_QUADS_DRAW_MODE)
     rlSetTexture(texShapes.id);
@@ -989,12 +1000,16 @@                 rlColor4ub(color.r, color.g, color.b, color.a);
                 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
                 rlVertex2f(center.x, center.y);
-                rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-                rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
-                rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-                rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+
                 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
-                rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius);
+                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2))*radius);
+
+                rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+
+                rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+                rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+
                 angle += (stepLength*2);
             }
 
@@ -1004,10 +1019,13 @@                 rlColor4ub(color.r, color.g, color.b, color.a);
                 rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
                 rlVertex2f(center.x, center.y);
-                rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-                rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
+
                 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-                rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+
+                rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+                rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+
                 rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
                 rlVertex2f(center.x, center.y);
             }
@@ -1082,8 +1100,8 @@             {
                 rlColor4ub(color.r, color.g, color.b, color.a);
                 rlVertex2f(center.x, center.y);
-                rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
-                rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
+                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+                rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
                 angle += stepLength;
             }
         }
@@ -1197,7 +1215,7 @@         {(float)(rec.x + rec.width) - innerRadius, (float)(rec.y + rec.height) - innerRadius}, {(float)rec.x + innerRadius, (float)(rec.y + rec.height) - innerRadius} // P18, P19
     };
 
-    const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f };
+    const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
 
     if (lineThick > 1)
     {
@@ -1214,15 +1232,19 @@                 for (int i = 0; i < segments; i++)
                 {
                     rlColor4ub(color.r, color.g, color.b, color.a);
+
                     rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
-                    rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
-                    rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-                    rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
-                    rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-                    rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
+
                     rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
-                    rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
 
+                    rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
+
+                    rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
+
                     angle += stepLength;
                 }
             }
@@ -1286,13 +1308,13 @@                 {
                     rlColor4ub(color.r, color.g, color.b, color.a);
 
-                    rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
-                    rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
-                    rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
 
-                    rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
-                    rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
-                    rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
 
                     angle += stepLength;
                 }
@@ -1350,8 +1372,8 @@                 for (int i = 0; i < segments; i++)
                 {
                     rlColor4ub(color.r, color.g, color.b, color.a);
-                    rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
-                    rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
                     angle += stepLength;
                 }
             }
@@ -1481,7 +1503,8 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
 {
     if (sides < 3) sides = 3;
-    float centralAngle = rotation;
+    float centralAngle = rotation*DEG2RAD;
+    float angleStep = 360.0f/(float)sides*DEG2RAD;
 
 #if defined(SUPPORT_QUADS_DRAW_MODE)
     rlSetTexture(texShapes.id);
@@ -1490,19 +1513,21 @@         for (int i = 0; i < sides; i++)
         {
             rlColor4ub(color.r, color.g, color.b, color.a);
+            float nextAngle = centralAngle + angleStep;
 
             rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
             rlVertex2f(center.x, center.y);
 
             rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
 
+            rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
+            rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
+
             rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
 
-            centralAngle += 360.0f/(float)sides;
-            rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
+            centralAngle = nextAngle;
         }
     rlEnd();
     rlSetTexture(0);
@@ -1513,10 +1538,10 @@             rlColor4ub(color.r, color.g, color.b, color.a);
 
             rlVertex2f(center.x, center.y);
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
+            rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius);
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
 
-            centralAngle += 360.0f/(float)sides;
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
+            centralAngle += angleStep;
         }
     rlEnd();
 #endif
@@ -1526,16 +1551,18 @@ void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color)
 {
     if (sides < 3) sides = 3;
-    float centralAngle = rotation;
+    float centralAngle = rotation*DEG2RAD;
+    float angleStep = 360.0f/(float)sides*DEG2RAD;
 
     rlBegin(RL_LINES);
         for (int i = 0; i < sides; i++)
         {
             rlColor4ub(color.r, color.g, color.b, color.a);
 
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
-            centralAngle += 360.0f/(float)sides;
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
+            rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius);
+
+            centralAngle += angleStep;
         }
     rlEnd();
 }
@@ -1543,8 +1570,8 @@ void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color)
 {
     if (sides < 3) sides = 3;
-    float centralAngle = rotation;
-    float exteriorAngle = 360.0f/(float)sides;
+    float centralAngle = rotation*DEG2RAD;
+    float exteriorAngle = 360.0f/(float)sides*DEG2RAD;
     float innerRadius = radius - (lineThick*cosf(DEG2RAD*exteriorAngle/2.0f));
 
 #if defined(SUPPORT_QUADS_DRAW_MODE)
@@ -1554,19 +1581,21 @@         for (int i = 0; i < sides; i++)
         {
             rlColor4ub(color.r, color.g, color.b, color.a);
+            float nextAngle = centralAngle + exteriorAngle;
 
+            rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
+
             rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*innerRadius, center.y + cosf(DEG2RAD*centralAngle)*innerRadius);
+            rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
 
-            rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
+            rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
 
-            centralAngle += exteriorAngle;
             rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
+            rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
 
-            rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*innerRadius, center.y + cosf(DEG2RAD*centralAngle)*innerRadius);
+            centralAngle = nextAngle;
         }
     rlEnd();
     rlSetTexture(0);
@@ -1577,13 +1606,13 @@             rlColor4ub(color.r, color.g, color.b, color.a);
             float nextAngle = centralAngle + exteriorAngle;
 
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*innerRadius, center.y + cosf(DEG2RAD*centralAngle)*innerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*nextAngle)*radius, center.y + cosf(DEG2RAD*nextAngle)*radius);
+            rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
+            rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
 
-            rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*innerRadius, center.y + cosf(DEG2RAD*centralAngle)*innerRadius);
-            rlVertex2f(center.x + sinf(DEG2RAD*nextAngle)*radius, center.y + cosf(DEG2RAD*nextAngle)*radius);
-            rlVertex2f(center.x + sinf(DEG2RAD*nextAngle)*innerRadius, center.y + cosf(DEG2RAD*nextAngle)*innerRadius);
+            rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
+            rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
+            rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
 
             centralAngle = nextAngle;
         }
raylib/src/rtext.c view
@@ -6,14 +6,19 @@ *       #define SUPPORT_MODULE_RTEXT
 *           rtext module is included in the build
 *
+*       #define SUPPORT_DEFAULT_FONT
+*           Load default raylib font on initialization to be used by DrawText() and MeasureText().
+*           If no default font loaded, DrawTextEx() and MeasureTextEx() are required.
+*
 *       #define SUPPORT_FILEFORMAT_FNT
 *       #define SUPPORT_FILEFORMAT_TTF
 *           Selected desired fileformats to be supported for loading. Some of those formats are
 *           supported by default, to remove support, just comment unrequired #define in this module
 *
-*       #define SUPPORT_DEFAULT_FONT
-*           Load default raylib font on initialization to be used by DrawText() and MeasureText().
-*           If no default font loaded, DrawTextEx() and MeasureTextEx() are required.
+*       #define SUPPORT_FONT_ATLAS_WHITE_REC
+*           On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
+*           at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
+*           drawing text and shapes with a single draw call [SetShapesTexture()].
 *
 *       #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
 *           TextSplit() function static buffer max size
@@ -111,8 +116,9 @@ // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
 #if defined(SUPPORT_FILEFORMAT_FNT)
-static Font LoadBMFont(const char *fileName);     // Load a BMFont file (AngelCode font file)
+static Font LoadBMFont(const char *fileName);   // Load a BMFont file (AngelCode font file)
 #endif
+static int textLineSpacing = 15;                // Text vertical line spacing in pixels
 
 #if defined(SUPPORT_DEFAULT_FONT)
 extern void LoadFontDefault(void);
@@ -123,7 +129,6 @@ // Module Functions Definition
 //----------------------------------------------------------------------------------
 #if defined(SUPPORT_DEFAULT_FONT)
-
 // Load raylib default font
 extern void LoadFontDefault(void)
 {
@@ -699,9 +704,11 @@     for (int i = 0; i < glyphCount; i++)
     {
         if (chars[i].image.width > maxGlyphWidth) maxGlyphWidth = chars[i].image.width;
-        totalWidth += chars[i].image.width + 2*padding;
+        totalWidth += chars[i].image.width + 4*padding;
     }
 
+//#define SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE
+#if defined(SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE)
     int rowCount = 0;
     int imageSize = 64;  // Define minimum starting value to avoid unnecessary calculation steps for very small images
 
@@ -714,6 +721,24 @@ 
     atlas.width = imageSize;   // Atlas bitmap width
     atlas.height = imageSize;  // Atlas bitmap height
+#else
+    // No need for a so-conservative atlas generation
+    float totalArea = totalWidth*fontSize*1.2f;
+    float imageMinSize = sqrtf(totalArea);
+    int imageSize = (int)powf(2, ceilf(logf(imageMinSize)/logf(2)));
+
+    if (totalArea < ((imageSize*imageSize)/2))
+    {
+        atlas.width = imageSize;    // Atlas bitmap width
+        atlas.height = imageSize/2; // Atlas bitmap height
+    }
+    else
+    {
+        atlas.width = imageSize;   // Atlas bitmap width
+        atlas.height = imageSize;  // Atlas bitmap height
+    }
+#endif
+
     atlas.data = (unsigned char *)RL_CALLOC(1, atlas.width*atlas.height);   // Create a bitmap to store characters (8 bpp)
     atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
     atlas.mipmaps = 1;
@@ -818,7 +843,20 @@         RL_FREE(nodes);
         RL_FREE(context);
     }
-
+    
+#if defined(SUPPORT_FONT_ATLAS_WHITE_REC)
+    // Add a 3x3 white rectangle at the bottom-right corner of the generated atlas,
+    // useful to use as the white texture to draw shapes with raylib, using this rectangle
+    // shapes and text can be backed into a single draw call: SetShapesTexture()
+    for (int i = 0, k = atlas.width*atlas.height - 1; i < 3; i++)
+    {
+        ((unsigned char *)atlas.data)[k - 0] = 255;
+        ((unsigned char *)atlas.data)[k - 1] = 255;
+        ((unsigned char *)atlas.data)[k - 2] = 255;
+        k -= atlas.width;
+    }
+#endif
+    
     // Convert image data from GRAYSCALE to GRAY_ALPHA
     unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels
 
@@ -1071,9 +1109,8 @@ 
         if (codepoint == '\n')
         {
-            // NOTE: Fixed line spacing of 1.5 line-height
-            // TODO: Support custom line spacing defined by user
-            textOffsetY += (int)((font.baseSize + font.baseSize/2.0f)*scaleFactor);
+            // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
+            textOffsetY += textLineSpacing;
             textOffsetX = 0.0f;
         }
         else
@@ -1143,9 +1180,8 @@ 
         if (codepoints[i] == '\n')
         {
-            // NOTE: Fixed line spacing of 1.5 line-height
-            // TODO: Support custom line spacing defined by user
-            textOffsetY += (int)((font.baseSize + font.baseSize/2.0f)*scaleFactor);
+            // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
+            textOffsetY += textLineSpacing;
             textOffsetX = 0.0f;
         }
         else
@@ -1161,6 +1197,12 @@     }
 }
 
+// Set vertical line spacing when drawing with line-breaks
+void SetTextLineSpacing(int spacing)
+{
+    textLineSpacing = spacing;
+}
+
 // Measure string width for default font
 int MeasureText(const char *text, int fontSize)
 {
@@ -1219,7 +1261,9 @@             if (tempTextWidth < textWidth) tempTextWidth = textWidth;
             byteCounter = 0;
             textWidth = 0;
-            textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines
+
+            // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
+            textHeight += (float)textLineSpacing;
         }
 
         if (tempByteCounter < byteCounter) tempByteCounter = byteCounter;
@@ -1227,7 +1271,7 @@ 
     if (tempTextWidth < textWidth) tempTextWidth = textWidth;
 
-    textSize.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing); // Adds chars spacing to measure
+    textSize.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing);
     textSize.y = textHeight*scaleFactor;
 
     return textSize;
@@ -1574,7 +1618,8 @@ }
 
 // Get upper case version of provided string
-// REQUIRES: toupper()
+// WARNING: Limited functionality, only basic characters set
+// TODO: Support UTF-8 diacritics to upper-case, check codepoints
 const char *TextToUpper(const char *text)
 {
     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
@@ -1582,17 +1627,10 @@ 
     if (text != NULL)
     {
-        for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
+        for (int i = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++)
         {
-            if (text[i] != '\0')
-            {
-                buffer[i] = (char)toupper(text[i]);
-                //if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
-
-                // TODO: Support UTF-8 diacritics to upper-case
-                //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32;
-            }
-            else { buffer[i] = '\0'; break; }
+            if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
+            else buffer[i] = text[i];
         }
     }
 
@@ -1600,7 +1638,7 @@ }
 
 // Get lower case version of provided string
-// REQUIRES: tolower()
+// WARNING: Limited functionality, only basic characters set
 const char *TextToLower(const char *text)
 {
     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
@@ -1608,14 +1646,10 @@ 
     if (text != NULL)
     {
-        for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
+        for (int i = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++)
         {
-            if (text[i] != '\0')
-            {
-                buffer[i] = (char)tolower(text[i]);
-                //if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
-            }
-            else { buffer[i] = '\0'; break; }
+            if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
+            else buffer[i] = text[i];
         }
     }
 
@@ -1623,7 +1657,7 @@ }
 
 // Get Pascal case notation version of provided string
-// REQUIRES: toupper()
+// WARNING: Limited functionality, only basic characters set
 const char *TextToPascal(const char *text)
 {
     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
@@ -1631,20 +1665,18 @@ 
     if (text != NULL)
     {
-        buffer[0] = (char)toupper(text[0]);
+        // Upper case first character
+        if ((text[0] >= 'a') && (text[0] <= 'z')) buffer[0] = text[0] - 32;
 
-        for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++)
+        // Check for next separator to upper case another character
+        for (int i = 1, j = 1; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++)
         {
-            if (text[j] != '\0')
+            if (text[j] != '_') buffer[i] = text[j];
+            else
             {
-                if (text[j] != '_') buffer[i] = text[j];
-                else
-                {
-                    j++;
-                    buffer[i] = (char)toupper(text[j]);
-                }
+                j++;
+                if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32;
             }
-            else { buffer[i] = '\0'; break; }
         }
     }
 
raylib/src/rtextures.c view
@@ -610,7 +610,7 @@ {
     unsigned char *fileData = NULL;
     *dataSize = 0;
-    
+
     if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return NULL;
 
 #if defined(SUPPORT_IMAGE_EXPORT)
@@ -629,7 +629,7 @@ #endif
 
 #endif
-    
+
     return fileData;
 }
 
@@ -713,7 +713,7 @@ 
 #if defined(SUPPORT_IMAGE_GENERATION)
 // Generate image: linear gradient
-// The direction value specifies the direction of the gradient (in degrees) 
+// The direction value specifies the direction of the gradient (in degrees)
 // with 0 being vertical (from top to bottom), 90 being horizontal (from left to right).
 // The gradient effectively rotates counter-clockwise by the specified amount.
 Image GenImageGradientLinear(int width, int height, int direction, Color start, Color end)
@@ -721,8 +721,8 @@     Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
 
     float radianDirection = (float)(90 - direction)/180.f*3.14159f;
-    float cosDir = cos(radianDirection);
-    float sinDir = sin(radianDirection);
+    float cosDir = cosf(radianDirection);
+    float sinDir = sinf(radianDirection);
 
     for (int i = 0; i < width; i++)
     {
@@ -812,7 +812,7 @@             float normalizedDistY = distY / centerY;
 
             // Calculate the total normalized Manhattan distance
-            float manhattanDist = fmax(normalizedDistX, normalizedDistY);
+            float manhattanDist = fmaxf(normalizedDistX, normalizedDistY);
 
             // Subtract the density from the manhattanDist, then divide by (1 - density)
             // This makes the gradient start from the center when density is 0, and from the edge when density is 1
@@ -898,21 +898,21 @@         {
             float nx = (float)(x + offsetX)*(scale/(float)width);
             float ny = (float)(y + offsetY)*(scale/(float)height);
-            
+
             // Basic perlin noise implementation (not used)
             //float p = (stb_perlin_noise3(nx, ny, 0.0f, 0, 0, 0);
-            
+
             // Calculate a better perlin noise using fbm (fractal brownian motion)
             // Typical values to start playing with:
             //   lacunarity = ~2.0   -- spacing between successive octaves (use exactly 2.0 for wrapping output)
             //   gain       =  0.5   -- relative weighting applied to each successive octave
             //   octaves    =  6     -- number of "octaves" of noise3() to sum
             float p = stb_perlin_fbm_noise3(nx, ny, 1.0f, 2.0f, 0.5f, 6);
-            
+
             // Clamp between -1.0f and 1.0f
             if (p < -1.0f) p = -1.0f;
             if (p > 1.0f) p = 1.0f;
-            
+
             // We need to normalize the data from [-1..1] to [0..1]
             float np = (p + 1.0f)/2.0f;
 
@@ -2157,11 +2157,11 @@     else
     {
         float rad = degrees*PI/180.0f;
-        float sinRadius = sin(rad);
-        float cosRadius = cos(rad);
+        float sinRadius = sinf(rad);
+        float cosRadius = cosf(rad);
 
-        int width = fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius);
-        int height = fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius);
+        int width = (int)(fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius));
+        int height = (int)(fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius));
 
         int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
         unsigned char *rotatedData = (unsigned char *)RL_CALLOC(width*height, bytesPerPixel);
@@ -3135,26 +3135,28 @@     if (rec.height < 0) rec.height = 0;
 
     int sy = (int)rec.y;
-    int ey = sy + (int)rec.height;
-
     int sx = (int)rec.x;
 
     int bytesPerPixel = GetPixelDataSize(1, 1, dst->format);
 
-    for (int y = sy; y < ey; y++)
-    {
-        // Fill in the first pixel of the row based on image format
-        ImageDrawPixel(dst, sx, y, color);
+    // Fill in the first pixel of the first row based on image format
+    ImageDrawPixel(dst, sx, sy, color);
 
-        int bytesOffset = ((y*dst->width) + sx)*bytesPerPixel;
-        unsigned char *pSrcPixel = (unsigned char *)dst->data + bytesOffset;
+    int bytesOffset = ((sy*dst->width) + sx)*bytesPerPixel;
+    unsigned char *pSrcPixel = (unsigned char *)dst->data + bytesOffset;
 
-        // Repeat the first pixel data throughout the row
-        for (int x = 1; x < (int)rec.width; x++)
-        {
-            memcpy(pSrcPixel + x*bytesPerPixel, pSrcPixel, bytesPerPixel);
-        }
+    // Repeat the first pixel data throughout the row
+    for (int x = 1; x < (int)rec.width; x++)
+    {
+        memcpy(pSrcPixel + x*bytesPerPixel, pSrcPixel, bytesPerPixel);
     }
+	
+	// Repeat the first row data for all other rows
+	int bytesPerRow = bytesPerPixel * (int)rec.width;
+	for (int y = 1; y < (int)rec.height; y++)
+	{
+		memcpy(pSrcPixel + (y*dst->width)*bytesPerPixel, pSrcPixel, bytesPerRow);
+	}
 }
 
 // Draw rectangle lines within an image
@@ -3290,8 +3292,7 @@     if (GetFontDefault().texture.id == 0) LoadFontDefault();
 
     Vector2 position = { (float)posX, (float)posY };
-    // NOTE: For default font, spacing is set to desired font size / default font size (10)
-    ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, (float)fontSize/10, color);   // WARNING: Module required: rtext
+    ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, 1.0f, color);   // WARNING: Module required: rtext
 #else
     TRACELOG(LOG_WARNING, "IMAGE: ImageDrawText() requires module: rtext");
 #endif
raylib/src/utils.c view
@@ -348,7 +348,7 @@             if (size > 0)
             {
                 text = (char *)RL_MALLOC((size + 1)*sizeof(char));
-                
+
                 if (text != NULL)
                 {
                     unsigned int count = (unsigned int)fread(text, sizeof(char), size, file);
src/Raylib/Core.hs view
@@ -291,6 +291,10 @@ setWindowOpacity :: Float -> IO ()
 setWindowOpacity opacity = c'setWindowOpacity $ realToFrac opacity
 
+foreign import ccall safe "raylib.h SetWindowFocused"
+  setWindowFocused ::
+    IO ()
+
 foreign import ccall safe "raylib.h GetWindowHandle"
   getWindowHandle ::
     IO (Ptr ())
src/Raylib/Core/Text.hs view
@@ -47,7 +47,7 @@     c'loadFontFromMemory,
     c'loadUTF8,
     c'measureText,
-    c'measureTextEx,
+    c'measureTextEx, c'setTextLineSpacing
   )
 import Raylib.Types
   ( Color,
@@ -123,6 +123,9 @@ 
 drawTextCodepoints :: Font -> [Int] -> Vector2 -> Float -> Float -> Color -> IO ()
 drawTextCodepoints font codepoints position fontSize spacing tint = withFreeable font (\f -> withFreeableArrayLen (map fromIntegral codepoints) (\count cp -> withFreeable position (\p -> withFreeable tint (c'drawTextCodepoints f cp (fromIntegral count) p (realToFrac fontSize) (realToFrac spacing)))))
+
+setTextLineSpacing :: Int -> IO ()
+setTextLineSpacing = c'setTextLineSpacing . fromIntegral
 
 measureText :: String -> Int -> IO Int
 measureText text fontSize = fromIntegral <$> withCString text (\t -> c'measureText t (fromIntegral fontSize))
src/Raylib/Native.hs view
@@ -1020,6 +1020,10 @@ 
 foreign import ccall safe "rl_bindings.h DrawTextCodepoints_" c'drawTextCodepoints :: Ptr Font -> Ptr CInt -> CInt -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()
 
+foreign import ccall safe "raylib.h SetTextLineSpacing"
+  c'setTextLineSpacing ::
+    CInt -> IO ()
+
 foreign import ccall safe "raylib.h MeasureText"
   c'measureText ::
     CString -> CInt -> IO CInt
src/Raylib/Util/Math.hs view
@@ -329,11 +329,11 @@ 
 -- | Angle between two 2D vectors
 vector2Angle :: Vector2 -> Vector2 -> Float
-vector2Angle (Vector2 x1 y1) (Vector2 x2 y2) = atan2 (y2 - y1) (x2 - x1)
+vector2Angle (Vector2 x1 y1) (Vector2 x2 y2) = - atan2 (x1 * x2 + y1 * y2) (x1 * y2 - y1 * x2)
 
 -- | Angle created by the line between two 2D vectors (parameters must be normalized)
 vector2LineAngle :: Vector2 -> Vector2 -> Float
-vector2LineAngle a b = acos $ clamp (a |.| b) (-1) 1
+vector2LineAngle (Vector2 sx sy) (Vector2 ex ey) = atan2 (ey - sy) (ex - sx)
 
 -- | Transform a 2D vector by the given matrix
 vector2Transform :: Vector2 -> Matrix -> Vector2