aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvictorfisac <victorfisac@gmail.com>2016-02-26 14:28:05 +0100
committervictorfisac <victorfisac@gmail.com>2016-02-26 14:28:05 +0100
commit68088bc5be39beff4f9997fe0966ce30054f67c1 (patch)
treeef7a773a5cd69193abce4e635dc1555cbd9ad9b7 /src
parent233f7611da96ea6bc0b7c62f6a06dacef707f9d7 (diff)
parent0dfc7fffff68b0bfafd30a86fb322073daf7fc0e (diff)
downloadraylib-68088bc5be39beff4f9997fe0966ce30054f67c1.tar.gz
raylib-68088bc5be39beff4f9997fe0966ce30054f67c1.zip
Merge remote-tracking branch 'refs/remotes/raysan5/develop' into develop
Diffstat (limited to 'src')
-rw-r--r--src/audio.c19
-rw-r--r--src/camera.c118
-rw-r--r--src/camera.h4
-rw-r--r--src/core.c795
-rw-r--r--src/gestures.c525
-rw-r--r--src/gestures.h11
-rw-r--r--src/libraylib.bcbin0 -> 603552 bytes
-rw-r--r--src/makefile14
-rw-r--r--src/models.c104
-rw-r--r--src/physac.c61
-rw-r--r--src/physac.h11
-rw-r--r--src/raygui.c11
-rw-r--r--src/raylib.h152
-rw-r--r--src/raymath.h73
-rw-r--r--src/resourcesbin107204 -> 107204 bytes
-rw-r--r--src/rlgl.c44
-rw-r--r--src/rlgl.h5
-rw-r--r--src/shapes.c5
-rw-r--r--src/text.c2
-rw-r--r--src/textures.c10
20 files changed, 1087 insertions, 877 deletions
diff --git a/src/audio.c b/src/audio.c
index 6313c9dc..260f6778 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -166,15 +166,8 @@ void CloseAudioDevice(void)
// Load sound to memory
Sound LoadSound(char *fileName)
{
- Sound sound;
- Wave wave;
-
- // Init some default values for wave...
- wave.data = NULL;
- wave.dataSize = 0;
- wave.sampleRate = 0;
- wave.bitsPerSample = 0;
- wave.channels = 0;
+ Sound sound = { 0 };
+ Wave wave = { 0 };
// NOTE: The entire file is loaded to memory to play it all at once (no-streaming)
@@ -236,7 +229,7 @@ Sound LoadSound(char *fileName)
// Load sound from wave data
Sound LoadSoundFromWave(Wave wave)
{
- Sound sound;
+ Sound sound = { 0 };
if (wave.data != NULL)
{
@@ -287,10 +280,10 @@ Sound LoadSoundFromWave(Wave wave)
}
// Load sound to memory from rRES file (raylib Resource)
+// TODO: Maybe rresName could be directly a char array with all the data?
Sound LoadSoundFromRES(const char *rresName, int resId)
{
- // NOTE: rresName could be directly a char array with all the data!!! --> TODO
- Sound sound;
+ Sound sound = { 0 };
#if defined(AUDIO_STANDALONE)
TraceLog(WARNING, "Sound loading from rRES resource file not supported on standalone mode");
@@ -791,7 +784,7 @@ static Wave LoadWAV(const char *fileName)
WaveFormat waveFormat;
WaveData waveData;
- Wave wave;
+ Wave wave = { 0 };
FILE *wavFile;
wavFile = fopen(fileName, "rb");
diff --git a/src/camera.c b/src/camera.c
index 4768b176..517e4a2b 100644
--- a/src/camera.c
+++ b/src/camera.c
@@ -2,7 +2,7 @@
*
* raylib Camera System - Camera Modes Setup and Control Functions
*
-* Copyright (c) 2015 Marc Palau and Ramon Santamaria
+* Copyright (c) 2015 Marc Palau and Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -36,44 +36,44 @@
// Defines and Macros
//----------------------------------------------------------------------------------
// CAMERA_GENERIC
-#define CAMERA_SCROLL_SENSITIVITY 1.5
+#define CAMERA_SCROLL_SENSITIVITY 1.5f
// FREE_CAMERA
-#define FREE_CAMERA_MOUSE_SENSITIVITY 0.01
-#define FREE_CAMERA_DISTANCE_MIN_CLAMP 0.3
-#define FREE_CAMERA_DISTANCE_MAX_CLAMP 120
-#define FREE_CAMERA_MIN_CLAMP 85
-#define FREE_CAMERA_MAX_CLAMP -85
-#define FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY 0.05
-#define FREE_CAMERA_PANNING_DIVIDER 5.1
+#define FREE_CAMERA_MOUSE_SENSITIVITY 0.01f
+#define FREE_CAMERA_DISTANCE_MIN_CLAMP 0.3f
+#define FREE_CAMERA_DISTANCE_MAX_CLAMP 120.0f
+#define FREE_CAMERA_MIN_CLAMP 85.0f
+#define FREE_CAMERA_MAX_CLAMP -85.0f
+#define FREE_CAMERA_SMOOTH_ZOOM_SENSITIVITY 0.05f
+#define FREE_CAMERA_PANNING_DIVIDER 5.1f
// ORBITAL_CAMERA
-#define ORBITAL_CAMERA_SPEED 0.01
+#define ORBITAL_CAMERA_SPEED 0.01f
// FIRST_PERSON
-//#define FIRST_PERSON_MOUSE_SENSITIVITY 0.003
-#define FIRST_PERSON_FOCUS_DISTANCE 25
-#define FIRST_PERSON_MIN_CLAMP 85
-#define FIRST_PERSON_MAX_CLAMP -85
+//#define FIRST_PERSON_MOUSE_SENSITIVITY 0.003f
+#define FIRST_PERSON_FOCUS_DISTANCE 25.0f
+#define FIRST_PERSON_MIN_CLAMP 85.0f
+#define FIRST_PERSON_MAX_CLAMP -85.0f
-#define FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0
-#define FIRST_PERSON_STEP_DIVIDER 30.0
-#define FIRST_PERSON_WAVING_DIVIDER 200.0
+#define FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0f
+#define FIRST_PERSON_STEP_DIVIDER 30.0f
+#define FIRST_PERSON_WAVING_DIVIDER 200.0f
-#define FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION 0.85
+#define FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION 0.85f
// THIRD_PERSON
-//#define THIRD_PERSON_MOUSE_SENSITIVITY 0.003
-#define THIRD_PERSON_DISTANCE_CLAMP 1.2
-#define THIRD_PERSON_MIN_CLAMP 5
-#define THIRD_PERSON_MAX_CLAMP -85
-#define THIRD_PERSON_OFFSET (Vector3){ 0.4, 0, 0 }
+//#define THIRD_PERSON_MOUSE_SENSITIVITY 0.003f
+#define THIRD_PERSON_DISTANCE_CLAMP 1.2f
+#define THIRD_PERSON_MIN_CLAMP 5.0f
+#define THIRD_PERSON_MAX_CLAMP -85.0f
+#define THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f }
// PLAYER (used by camera)
-#define PLAYER_WIDTH 0.4
-#define PLAYER_HEIGHT 0.9
-#define PLAYER_DEPTH 0.4
-#define PLAYER_MOVEMENT_DIVIDER 20.0
+#define PLAYER_WIDTH 0.4f
+#define PLAYER_HEIGHT 0.9f
+#define PLAYER_DEPTH 0.4f
+#define PLAYER_MOVEMENT_DIVIDER 20.0f
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -84,11 +84,11 @@ typedef enum { MOVE_FRONT = 0, MOVE_LEFT, MOVE_BACK, MOVE_RIGHT, MOVE_UP, MOVE_D
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
-static Camera internalCamera = {{2, 0, 2}, {0, 0, 0}, {0, 1, 0}};
-static Vector2 cameraAngle = { 0, 0 };
+static Camera internalCamera = {{ 2.0f, 0.0f, 2.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }};
+static Vector2 cameraAngle = { 0.0f, 0.0f };
static float cameraTargetDistance = 5.0f;
-static Vector2 cameraMousePosition = { 0, 0 };
-static Vector2 cameraMouseVariation = { 0, 0 };
+static Vector2 cameraMousePosition = { 0.0f, 0.0f };
+static Vector2 cameraMouseVariation = { 0.0f, 0.0f };
static float mouseSensitivity = 0.003f;
static int cameraMoveControl[6] = { 'W', 'A', 'S', 'D', 'E', 'Q' };
static int cameraMoveCounter = 0;
@@ -107,7 +107,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition);
#if defined(CAMERA_STANDALONE)
// NOTE: Camera controls depend on some raylib input functions
// TODO: Set your own input functions (used in ProcessCamera())
-static Vector2 GetMousePosition() { return (Vector2){ 0, 0}; }
+static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
static void SetMousePosition(Vector2 pos) {}
static int IsMouseButtonDown(int button) { return 0;}
static int GetMouseWheelMove() { return 0; }
@@ -129,33 +129,33 @@ void SetCameraMode(int mode)
if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_FREE))
{
cameraMode = CAMERA_THIRD_PERSON;
- cameraTargetDistance = 5;
- cameraAngle.y = -40 * DEG2RAD;
+ cameraTargetDistance = 5.0f;
+ cameraAngle.y = -40*DEG2RAD;
ProcessCamera(&internalCamera, &internalCamera.position);
}
else if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_ORBITAL))
{
cameraMode = CAMERA_THIRD_PERSON;
- cameraTargetDistance = 5;
- cameraAngle.y = -40 * DEG2RAD;
+ cameraTargetDistance = 5.0f;
+ cameraAngle.y = -40*DEG2RAD;
ProcessCamera(&internalCamera, &internalCamera.position);
}
else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_FREE))
{
- cameraTargetDistance = 10;
- cameraAngle.x = 45 * DEG2RAD;
- cameraAngle.y = -40 * DEG2RAD;
- internalCamera.target = (Vector3){ 0, 0, 0 };
+ cameraTargetDistance = 10.0f;
+ cameraAngle.x = 45*DEG2RAD;
+ cameraAngle.y = -40*DEG2RAD;
+ internalCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
ProcessCamera(&internalCamera, &internalCamera.position);
ShowCursor();
}
else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_ORBITAL))
{
- cameraTargetDistance = 10;
- cameraAngle.x = 225 * DEG2RAD;
- cameraAngle.y = -40 * DEG2RAD;
- internalCamera.target = (Vector3){ 0, 0, 0};
+ cameraTargetDistance = 10.0f;
+ cameraAngle.x = 225*DEG2RAD;
+ cameraAngle.y = -40*DEG2RAD;
+ internalCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
ProcessCamera(&internalCamera, &internalCamera.position);
}
@@ -165,7 +165,7 @@ void SetCameraMode(int mode)
// Update camera (player position is ignored)
void UpdateCamera(Camera *camera)
{
- Vector3 position = { 0, 0, 0 };
+ Vector3 position = { 0.0f, 0.0f, 0.0f };
// Process internal camera and player position (if required)
if (cameraMode != CAMERA_CUSTOM) ProcessCamera(&internalCamera, &position);
@@ -244,7 +244,7 @@ void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey,
// Set camera mouse sensitivity (1st person and 3rd person cameras)
void SetCameraMouseSensitivity(float sensitivity)
{
- mouseSensitivity = (sensitivity/10000.0);
+ mouseSensitivity = (sensitivity/10000.0f);
}
//----------------------------------------------------------------------------------
@@ -375,13 +375,13 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
}
// Focus to center
- // TODO: Move this function out of the module?
- if (IsKeyDown('Z')) camera->target = (Vector3){ 0, 0, 0 };
+ // TODO: Move this function out of this module?
+ if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f };
// Camera position update
camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
- if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
+ if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
@@ -398,12 +398,12 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
if (cameraTargetDistance < THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = THIRD_PERSON_DISTANCE_CLAMP;
// Focus to center
- if (IsKeyDown('Z')) camera->target = (Vector3){ 0, 0, 0 };
+ if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f };
// Camera position update
camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
- if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
+ if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
@@ -412,7 +412,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
case CAMERA_FIRST_PERSON:
case CAMERA_THIRD_PERSON:
{
- int isMoving = 0;
+ bool isMoving = false;
// Keyboard inputs
if (IsKeyDown(cameraMoveControl[MOVE_FRONT]))
@@ -422,7 +422,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
if (!cameraUseGravity) camera->position.y += sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER;
- isMoving = 1;
+ isMoving = true;
}
else if (IsKeyDown(cameraMoveControl[MOVE_BACK]))
{
@@ -431,7 +431,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
if (!cameraUseGravity) camera->position.y -= sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER;
- isMoving = 1;
+ isMoving = true;
}
if (IsKeyDown(cameraMoveControl[MOVE_LEFT]))
@@ -439,23 +439,23 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
playerPosition->x -= cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
playerPosition->z += sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
- isMoving = 1;
+ isMoving = true;
}
else if (IsKeyDown(cameraMoveControl[MOVE_RIGHT]))
{
playerPosition->x += cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
playerPosition->z -= sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER;
- isMoving = 1;
+ isMoving = true;
}
if (IsKeyDown(cameraMoveControl[MOVE_UP]))
{
- if (!cameraUseGravity) playerPosition->y += 1/PLAYER_MOVEMENT_DIVIDER;
+ if (!cameraUseGravity) playerPosition->y += 1.0f/PLAYER_MOVEMENT_DIVIDER;
}
else if (IsKeyDown(cameraMoveControl[MOVE_DOWN]))
{
- if (!cameraUseGravity) playerPosition->y -= 1/PLAYER_MOVEMENT_DIVIDER;
+ if (!cameraUseGravity) playerPosition->y -= 1.0f/PLAYER_MOVEMENT_DIVIDER;
}
if (cameraMode == CAMERA_THIRD_PERSON)
@@ -482,7 +482,7 @@ static void ProcessCamera(Camera *camera, Vector3 *playerPosition)
// Camera position update
camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
- if (cameraAngle.y <= 0) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
+ if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
diff --git a/src/camera.h b/src/camera.h
index ed85320a..9ad09c6f 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -28,8 +28,8 @@
#define PI 3.14159265358979323846
#endif
-#define DEG2RAD (PI / 180.0f)
-#define RAD2DEG (180.0f / PI)
+#define DEG2RAD (PI/180.0f)
+#define RAD2DEG (180.0f/PI)
//----------------------------------------------------------------------------------
// Defines and Macros
diff --git a/src/core.c b/src/core.c
index 9b068300..dbcfa6bc 100644
--- a/src/core.c
+++ b/src/core.c
@@ -53,8 +53,7 @@
#include <string.h> // String function definitions, memset()
#include <errno.h> // Macros for reporting and retrieving error conditions through error codes
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
-
+#if defined(PLATFORM_DESKTOP)
#define GLAD_EXTENSIONS_LOADER
#if defined(GLEW_EXTENSIONS_LOADER)
#define GLEW_STATIC
@@ -62,14 +61,16 @@
#elif defined(GLAD_EXTENSIONS_LOADER)
#include "glad.h" // GLAD library: Manage OpenGL headers and extensions
#endif
+#endif
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
//#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3
- #include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management
+ #include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management
#ifdef __linux
- #define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting
- #define GLFW_EXPOSE_NATIVE_GLX // native functions like glfwGetX11Window
- #include <GLFW/glfw3native.h> // which are required for hiding mouse
+ #define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting
+ #define GLFW_EXPOSE_NATIVE_GLX // native functions like glfwGetX11Window
+ #include <GLFW/glfw3native.h> // which are required for hiding mouse
#endif
//#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h)
//#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version!
@@ -101,11 +102,6 @@
#include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions
#include "EGL/eglext.h" // Khronos EGL library - Extensions
#include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library
-
- #define DEFAULT_KEYBOARD_DEV "/dev/input/event0" // Not used, keyboard inputs are read raw from stdin
- #define DEFAULT_MOUSE_DEV "/dev/input/event1"
- //#define DEFAULT_MOUSE_DEV "/dev/input/mouse0"
- #define DEFAULT_GAMEPAD_DEV "/dev/input/js0"
#endif
#if defined(PLATFORM_WEB)
@@ -116,6 +112,22 @@
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
+#define STORAGE_FILENAME "storage.data"
+
+#if defined(PLATFORM_RPI)
+ // Old device inputs system
+ #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input
+ #define DEFAULT_MOUSE_DEV "/dev/input/mouse0"
+ #define DEFAULT_GAMEPAD_DEV "/dev/input/js0"
+
+ // New device input events (evdev) (must be detected)
+ //#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN"
+ //#define DEFAULT_MOUSE_DEV "/dev/input/eventN"
+ //#define DEFAULT_GAMEPAD_DEV "/dev/input/eventN"
+
+ #define MOUSE_SENSITIVITY 0.8f
+ #define MAX_GAMEPAD_BUTTONS 11
+#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -140,24 +152,24 @@ static int currentButtonState[128] = { 1 }; // Required to check if button p
#elif defined(PLATFORM_RPI)
static EGL_DISPMANX_WINDOW_T nativeWindow; // Native window (graphic device)
-// Input variables (mouse/keyboard)
-static int mouseStream = -1; // Mouse device file descriptor
-static bool mouseReady = false; // Flag to know if mouse is ready
-pthread_t mouseThreadId; // Mouse reading thread id
-
+// Keyboard input variables
// NOTE: For keyboard we will use the standard input (but reconfigured...)
+static struct termios defaultKeyboardSettings; // Used to store default keyboard settings
static int defaultKeyboardMode; // Used to store default keyboard mode
-static struct termios defaultKeyboardSettings; // Used to staore default keyboard settings
-static int keyboardMode = 0; // Keyboard mode: 1 (KEYCODES), 2 (ASCII)
-
-// This array maps Unix keycodes to ASCII equivalent and to GLFW3 equivalent for special function keys (>256)
-const short UnixKeycodeToASCII[128] = { 256, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 259, 9, 81, 87, 69, 82, 84, 89, 85, 73, 79, 80, 91, 93, 257, 341, 65, 83, 68,
- 70, 71, 72, 74, 75, 76, 59, 39, 96, 340, 92, 90, 88, 67, 86, 66, 78, 77, 44, 46, 47, 344, -1, 342, 32, -1, 290, 291, 292, 293, 294, 295, 296,
- 297, 298, 299, -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 257, 345, 47, -1,
- 346, -1, -1, 265, -1, 263, 262, -1, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+// Mouse input variables
+static int mouseStream = -1; // Mouse device file descriptor
+static bool mouseReady = false; // Flag to know if mouse is ready
+pthread_t mouseThreadId; // Mouse reading thread id
+// Gamepad input variables
static int gamepadStream = -1; // Gamepad device file descriptor
+static bool gamepadReady = false; // Flag to know if gamepad is ready
+pthread_t gamepadThreadId; // Gamepad reading thread id
+
+int gamepadButtons[MAX_GAMEPAD_BUTTONS];
+int gamepadAxisX = 0;
+int gamepadAxisY = 0;
#endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
@@ -180,7 +192,7 @@ static bool fullscreen = false; // Fullscreen mode (useful only for
static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size)
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
-static Vector2 touchPosition; // Touch position on screen
+static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen
#endif
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
@@ -208,7 +220,9 @@ static int exitKey = KEY_ESCAPE; // Default exit key (ESC)
static int lastKeyPressed = -1; // Register last key pressed
static bool cursorHidden; // Track if cursor is hidden
+#endif
+#if defined(PLATFORM_DESKTOP)
static char **dropFilesPath; // Store dropped files paths as strings
static int dropFilesCount = 0; // Count stored strings
#endif
@@ -242,17 +256,20 @@ static void LogoAnimation(void); // Plays raylib logo app
static void SetupFramebufferSize(int displayWidth, int displayHeight);
#if defined(PLATFORM_RPI)
-static void InitMouse(void); // Mouse initialization (including mouse thread)
-static void *MouseThread(void *arg); // Mouse reading thread
static void InitKeyboard(void); // Init raw keyboard system (standard input reading)
+static void ProcessKeyboard(void); // Process keyboard events
static void RestoreKeyboard(void); // Restore keyboard system
+static void InitMouse(void); // Mouse initialization (including mouse thread)
+static void *MouseThread(void *arg); // Mouse reading thread
static void InitGamepad(void); // Init raw gamepad input
+static void *GamepadThread(void *arg); // Mouse reading thread
#endif
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
+static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move
static void CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value)
static void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel
static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
@@ -320,6 +337,10 @@ void InitWindow(int width, int height, const char *title)
emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenInputCallback);
emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenInputCallback);
emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenInputCallback);
+
+ // TODO: Add gamepad support (not provided by GLFW3 on emscripten)
+ //emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenInputCallback);
+ //emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenInputCallback);
#endif
mousePosition.x = (float)screenWidth/2.0f;
@@ -355,7 +376,7 @@ void InitWindow(int width, int height, struct android_app *state)
if (orientation == ACONFIGURATION_ORIENTATION_PORT) TraceLog(INFO, "PORTRAIT window orientation");
else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TraceLog(INFO, "LANDSCAPE window orientation");
- // TODO: Review, it doesn't work...
+ // TODO: Automatic orientation doesn't seem to work
if (width <= height)
{
AConfiguration_setOrientation(app->config, ACONFIGURATION_ORIENTATION_PORT);
@@ -463,6 +484,7 @@ bool IsWindowMinimized(void)
}
// Fullscreen toggle
+// TODO: When destroying window context is lost and resources too, take care!
void ToggleFullscreen(void)
{
#if defined(PLATFORM_DESKTOP)
@@ -590,7 +612,7 @@ void Begin3dMode(Camera camera)
// Setup perspective projection
float aspect = (float)screenWidth/(float)screenHeight;
- double top = 0.1f*tan(45.0f*PI/360.0f);
+ double top = 0.1*tan(45.0*PI/360.0);
double right = top*aspect;
// NOTE: zNear and zFar values are important when computing depth buffer values
@@ -629,7 +651,7 @@ void SetTargetFPS(int fps)
// Returns current FPS
float GetFPS(void)
{
- return (float)(1/frameTime);
+ return (float)(1.0/frameTime);
}
// Returns time in seconds for one frame
@@ -754,7 +776,7 @@ void ShowLogo(void)
showLogo = true;
}
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
+#if defined(PLATFORM_DESKTOP)
// Check if a file have been dropped into window
bool IsFileDropped(void)
{
@@ -790,10 +812,10 @@ void StorageSaveValue(int position, int value)
FILE *storageFile = NULL;
// Try open existing file to append data
- storageFile = fopen("storage.data", "rb+");
+ storageFile = fopen(STORAGE_FILENAME, "rb+");
// If file doesn't exist, create a new storage data file
- if (!storageFile) storageFile = fopen("storage.data", "wb");
+ if (!storageFile) storageFile = fopen(STORAGE_FILENAME, "wb");
if (!storageFile) TraceLog(WARNING, "Storage data file could not be created");
else
@@ -821,7 +843,7 @@ int StorageLoadValue(int position)
int value = 0;
// Try open existing file to append data
- FILE *storageFile = fopen("storage.data", "rb");
+ FILE *storageFile = fopen(STORAGE_FILENAME, "rb");
if (!storageFile) TraceLog(WARNING, "Storage data file could not be found");
else
@@ -888,8 +910,8 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
MatrixInvert(&matProjView);
// Calculate far and near points
- Quaternion near = { deviceCoords.x, deviceCoords.y, 0, 1};
- Quaternion far = { deviceCoords.x, deviceCoords.y, 1, 1};
+ Quaternion near = { deviceCoords.x, deviceCoords.y, 0.0f, 1.0f};
+ Quaternion far = { deviceCoords.x, deviceCoords.y, 1.0f, 1.0f};
// Multiply points by unproject matrix
QuaternionTransform(&near, matProjView);
@@ -938,6 +960,12 @@ Vector2 WorldToScreen(Vector3 position, Camera camera)
return screenPosition;
}
+// Get transform matrix for camera
+Matrix GetCameraMatrix(Camera camera)
+{
+ return MatrixLookAt(camera.position, camera.target, camera.up);
+}
+
//----------------------------------------------------------------------------------
// Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions
//----------------------------------------------------------------------------------
@@ -1091,23 +1119,44 @@ void ShowCursor()
cursorHidden = false;
}
+// Disable mouse cursor
+void DisableCursor()
+{
+#if defined(PLATFORM_DESKTOP)
+ glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+#endif
+ cursorHidden = true;
+}
+
+// Enable mouse cursor
+void EnableCursor()
+{
+#if defined(PLATFORM_DESKTOP)
+ glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+#endif
+ cursorHidden = false;
+}
+
// Check if mouse cursor is hidden
bool IsCursorHidden()
{
return cursorHidden;
}
-#endif
-// TODO: Enable gamepad usage on Rapsberry Pi
-// NOTE: emscripten not implemented
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
+// NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB)
+
// Detect if a gamepad is available
bool IsGamepadAvailable(int gamepad)
{
- int result = glfwJoystickPresent(gamepad);
+ bool result = false;
+
+#if defined(PLATFORM_RPI)
+ if (gamepadReady && (gamepad == 0)) result = true;
+#else
+ if (glfwJoystickPresent(gamepad) == 1) result = true;
+#endif
- if (result == 1) return true;
- else return false;
+ return result;
}
// Return axis movement vector for a gamepad
@@ -1116,10 +1165,15 @@ Vector2 GetGamepadMovement(int gamepad)
Vector2 vec = { 0, 0 };
const float *axes;
- int axisCount;
-
+ int axisCount = 0;
+
+#if defined(PLATFORM_RPI)
+ // TODO: Get gamepad axis information
+ // Use gamepadAxisX, gamepadAxisY
+#else
axes = glfwGetJoystickAxes(gamepad, &axisCount);
-
+#endif
+
if (axisCount >= 2)
{
vec.x = axes[0]; // Left joystick X
@@ -1152,16 +1206,23 @@ bool IsGamepadButtonPressed(int gamepad, int button)
// Detect if a gamepad button is being pressed
bool IsGamepadButtonDown(int gamepad, int button)
{
+ bool result = false;
+
+#if defined(PLATFORM_RPI)
+ // Get gamepad buttons information
+ if ((gamepad == 0) && (gamepadButtons[button] == 1)) result = true;
+ else result = false;
+#else
const unsigned char *buttons;
int buttonsCount;
-
+
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
- if ((buttons != NULL) && (buttons[button] == GLFW_PRESS))
- {
- return true;
- }
- else return false;
+ if ((buttons != NULL) && (buttons[button] == GLFW_PRESS)) result = true;
+ else result = false;
+#endif
+
+ return result;
}
// Detect if a gamepad button has NOT been pressed once
@@ -1184,41 +1245,59 @@ bool IsGamepadButtonReleased(int gamepad, int button)
// Detect if a mouse button is NOT being pressed
bool IsGamepadButtonUp(int gamepad, int button)
{
+ bool result = false;
+
+#if defined(PLATFORM_RPI)
+ // Get gamepad buttons information
+ if ((gamepad == 0) && (gamepadButtons[button] == 0)) result = true;
+ else result = false;
+#else
const unsigned char *buttons;
int buttonsCount;
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
- if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE))
- {
- return true;
- }
- else return false;
-}
+ if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE)) result = true;
+ else result = false;
#endif
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
+ return result;
+}
+#endif //defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
+
// Returns touch position X
int GetTouchX(void)
{
- return (int)touchPosition.x;
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
+ return (int)touchPosition[0].x;
+#else // PLATFORM_DESKTOP, PLATFORM_RPI
+ return GetMouseX();
+#endif
}
// Returns touch position Y
int GetTouchY(void)
{
- return (int)touchPosition.y;
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
+ return (int)touchPosition[0].y;
+#else // PLATFORM_DESKTOP, PLATFORM_RPI
+ return GetMouseY();
+#endif
}
// Returns touch position XY
-// TODO: touch position should be scaled depending on display size and render size
-Vector2 GetTouchPosition(void)
+// TODO: Touch position should be scaled depending on display size and render size
+Vector2 GetTouchPosition(int index)
{
- Vector2 position = touchPosition;
+ Vector2 position = { -1.0f, -1.0f };
+
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
+ if (index < MAX_TOUCH_POINTS) position = touchPosition[index];
+ else TraceLog(WARNING, "Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS);
if ((screenWidth > displayWidth) || (screenHeight > displayHeight))
{
- // TODO: Seems to work ok but... review!
+ // TODO: Review touch position scaling for screenSize vs displaySize
position.x = position.x*((float)screenWidth/(float)(displayWidth - renderOffsetX)) - renderOffsetX/2;
position.y = position.y*((float)screenHeight/(float)(displayHeight - renderOffsetY)) - renderOffsetY/2;
}
@@ -1227,10 +1306,14 @@ Vector2 GetTouchPosition(void)
position.x = position.x*((float)renderWidth/(float)displayWidth) - renderOffsetX/2;
position.y = position.y*((float)renderHeight/(float)displayHeight) - renderOffsetY/2;
}
+#else // PLATFORM_DESKTOP, PLATFORM_RPI
+ if (index == 0) position = GetMousePosition();
+#endif
return position;
}
+#if defined(PLATFORM_ANDROID)
// Detect if a button has been pressed once
bool IsButtonPressed(int button)
{
@@ -1333,10 +1416,24 @@ static void InitDisplay(int width, int height)
if (fullscreen)
{
// At this point we need to manage render size vs screen size
- // NOTE: This function uses and modifies global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView
+ // NOTE: This function uses and modifies global module variables:
+ // screenWidth/screenHeight - renderWidth/renderHeight - downscaleView
SetupFramebufferSize(displayWidth, displayHeight);
+
+ // TODO: SetupFramebufferSize() does not consider properly display video modes.
+ // It setups a renderWidth/renderHeight with black bars that could not match a valid video mode,
+ // and so, framebuffer is not scaled properly to some monitors.
+
+ int count;
+ const GLFWvidmode *modes = glfwGetVideoModes(glfwGetPrimaryMonitor(), &count);
+
+ for (int i = 0; i < count; i++)
+ {
+ // TODO: Check modes[i]->width;
+ // TODO: Check modes[i]->height;
+ }
- window = glfwCreateWindow(renderWidth, renderHeight, windowTitle, glfwGetPrimaryMonitor(), NULL);
+ window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, glfwGetPrimaryMonitor(), NULL);
}
else
{
@@ -1345,10 +1442,8 @@ static void InitDisplay(int width, int height)
#if defined(PLATFORM_DESKTOP)
// Center window on screen
- const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
-
- int windowPosX = mode->width/2 - screenWidth/2;
- int windowPosY = mode->height/2 - screenHeight/2;
+ int windowPosX = displayWidth/2 - screenWidth/2;
+ int windowPosY = displayHeight/2 - screenHeight/2;
if (windowPosX < 0) windowPosX = 0;
if (windowPosY < 0) windowPosY = 0;
@@ -1379,6 +1474,7 @@ static void InitDisplay(int width, int height)
glfwSetCursorEnterCallback(window, CursorEnterCallback);
glfwSetKeyCallback(window, KeyCallback);
glfwSetMouseButtonCallback(window, MouseButtonCallback);
+ glfwSetCursorPosCallback(window, MouseCursorPosCallback); // Track mouse position changes
glfwSetCharCallback(window, CharCallback);
glfwSetScrollCallback(window, ScrollCallback);
glfwSetWindowIconifyCallback(window, WindowIconifyCallback);
@@ -1388,6 +1484,7 @@ static void InitDisplay(int width, int height)
glfwMakeContextCurrent(window);
+#if defined(PLATFORM_DESKTOP)
// Extensions initialization for OpenGL 3.3
if (rlGetVersion() == OPENGL_33)
{
@@ -1419,6 +1516,7 @@ static void InitDisplay(int width, int height)
//if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object
#endif
}
+#endif
// Enables GPU v-sync, so frames are not limited to screen refresh rate (60Hz -> 60 FPS)
// If not set, swap interval uses GPU v-sync configuration
@@ -1622,8 +1720,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
#endif
else currentKeyState[key] = action;
- // HACK for GuiTextBox, to deteck back key
- // TODO: Review...
+ // TODO: Review (and remove) this HACK for GuiTextBox, to deteck back key
if ((key == 259) && (action == GLFW_PRESS)) lastKeyPressed = 3;
}
@@ -1631,6 +1728,59 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
{
currentMouseState[button] = action;
+
+#define ENABLE_MOUSE_GESTURES
+#if defined(ENABLE_MOUSE_GESTURES)
+ // Process mouse events as touches to be able to use mouse-gestures
+ GestureEvent gestureEvent;
+
+ // Register touch actions
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_DOWN;
+ else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_UP;
+
+ // NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback()
+
+ // Assign a pointer ID
+ gestureEvent.pointerId[0] = 0;
+
+ // Register touch points count
+ gestureEvent.pointCount = 1;
+
+ // Register touch points position, only one point registered
+ gestureEvent.position[0] = GetMousePosition();
+
+ // Normalize gestureEvent.position[0] for screenWidth and screenHeight
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+
+ // Gesture data is sent to gestures system for processing
+ ProcessGestureEvent(gestureEvent);
+#endif
+}
+
+// GLFW3 Cursor Position Callback, runs on mouse move
+static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
+{
+#define ENABLE_MOUSE_GESTURES
+#if defined(ENABLE_MOUSE_GESTURES)
+ // Process mouse events as touches to be able to use mouse-gestures
+ GestureEvent gestureEvent;
+
+ gestureEvent.touchAction = TOUCH_MOVE;
+
+ // Register touch points count
+ gestureEvent.pointCount = 1;
+
+ // Register touch points position, only one point registered
+ gestureEvent.position[0] = (Vector2){ (float)x, (float)y };
+
+ // Normalize gestureEvent.position[0] for screenWidth and screenHeight
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+
+ // Gesture data is sent to gestures system for processing
+ ProcessGestureEvent(gestureEvent);
+#endif
}
// GLFW3 Char Key Callback, runs on key pressed (get char value)
@@ -1831,8 +1981,13 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
if (type == AINPUT_EVENT_TYPE_MOTION)
{
- touchPosition.x = AMotionEvent_getX(event, 0);
- touchPosition.y = AMotionEvent_getY(event, 0);
+ // Get first touch position
+ touchPosition[0].x = AMotionEvent_getX(event, 0);
+ touchPosition[0].y = AMotionEvent_getY(event, 0);
+
+ // Get second touch position
+ touchPosition[1].x = AMotionEvent_getX(event, 1);
+ touchPosition[1].y = AMotionEvent_getY(event, 1);
}
else if (type == AINPUT_EVENT_TYPE_KEY)
{
@@ -1876,11 +2031,22 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
// Register touch points count
gestureEvent.pointCount = AMotionEvent_getPointerCount(event);
+ // Register touch points id
+ gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0);
+ gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1);
+
// Register touch points position
// NOTE: Only two points registered
gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) };
gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) };
+ // Normalize gestureEvent.position[x] for screenWidth and screenHeight
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+
+ gestureEvent.position[1].x /= (float)GetScreenWidth();
+ gestureEvent.position[1].y /= (float)GetScreenHeight();
+
// Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent);
@@ -1948,7 +2114,7 @@ static bool GetKeyStatus(int key)
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
return glfwGetKey(window, key);
#elif defined(PLATFORM_ANDROID)
- // TODO: Check virtual keyboard (?)
+ // TODO: Check for virtual keyboard
return false;
#elif defined(PLATFORM_RPI)
// NOTE: Keys states are filled in PollInputEvents()
@@ -1963,10 +2129,10 @@ static bool GetMouseButtonStatus(int button)
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
return glfwGetMouseButton(window, button);
#elif defined(PLATFORM_ANDROID)
- // TODO: Check virtual keyboard (?)
+ // TODO: Check for virtual keyboard
return false;
#elif defined(PLATFORM_RPI)
- // NOTE: mouse buttons array is filled on PollInputEvents()
+ // NOTE: Mouse buttons states are filled in PollInputEvents()
return currentMouseState[button];
#endif
}
@@ -1974,11 +2140,9 @@ static bool GetMouseButtonStatus(int button)
// Poll (store) all input events
static void PollInputEvents(void)
{
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
-
- // TODO: Remove this requirement...
+ // NOTE: Gestures update must be called every frame to reset gestures correctly
+ // because ProcessGestureEvent() is just called on an event, not every frame
UpdateGestures();
-#endif
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// Mouse input polling
@@ -1990,8 +2154,7 @@ static void PollInputEvents(void)
mousePosition.x = (float)mouseX;
mousePosition.y = (float)mouseY;
- // Keyboard polling
- // Automatically managed by GLFW3 through callback
+ // Keyboard input polling (automatically managed by GLFW3 through callback)
lastKeyPressed = -1;
// Register previous keys states
@@ -2030,131 +2193,168 @@ static void PollInputEvents(void)
// NOTE: Keyboard reading could be done using input_event(s) reading or just read from stdin,
// we use method 2 (stdin) but maybe in a future we should change to method 1...
+ ProcessKeyboard();
+
+ // NOTE: Gamepad (Joystick) input events polling is done asynchonously in another pthread - GamepadThread()
+
+#endif
+}
+
+#if defined(PLATFORM_RPI)
+// Initialize Keyboard system (using standard input)
+static void InitKeyboard(void)
+{
+ // NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor
+ // Make stdin non-blocking (not enough, need to configure to non-canonical mode)
+ int flags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags
+ fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified
+
+ // Save terminal keyboard settings and reconfigure terminal with new settings
+ struct termios keyboardNewSettings;
+ tcgetattr(STDIN_FILENO, &defaultKeyboardSettings); // Get current keyboard settings
+ keyboardNewSettings = defaultKeyboardSettings;
+
+ // New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
+ // NOTE: ISIG controls if ^C and ^Z generate break signals or not
+ keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG);
+ //keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
+ keyboardNewSettings.c_cc[VMIN] = 1;
+ keyboardNewSettings.c_cc[VTIME] = 0;
+
+ // Set new keyboard settings (change occurs immediately)
+ tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings);
+
+ // NOTE: Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE, we change that! -> WHY???
+
+ // Save old keyboard mode to restore it at the end
+ if (ioctl(STDIN_FILENO, KDGKBMODE, &defaultKeyboardMode) < 0)
+ {
+ // NOTE: It could mean we are using a remote keyboard through ssh!
+ TraceLog(WARNING, "Could not change keyboard mode (SSH keyboard?)");
+ }
+ else
+ {
+ // We reconfigure keyboard mode to get:
+ // - scancodes (K_RAW)
+ // - keycodes (K_MEDIUMRAW)
+ // - ASCII chars (K_XLATE)
+ // - UNICODE chars (K_UNICODE)
+ ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
+ }
+
+ // Register keyboard restore when program finishes
+ atexit(RestoreKeyboard);
+}
+
+// Process keyboard inputs
+// TODO: Most probably input reading and processing should be in a separate thread
+static void ProcessKeyboard(void)
+{
+ #define MAX_KEYBUFFER_SIZE 32 // Max size in bytes to read
+
// Keyboard input polling (fill keys[256] array with status)
- int numKeysBuffer = 0; // Keys available on buffer
- char keysBuffer[32]; // Max keys to be read at a time
+ int bufferByteCount = 0; // Bytes available on the buffer
+ char keysBuffer[MAX_KEYBUFFER_SIZE]; // Max keys to be read at a time
// Reset pressed keys array
for (int i = 0; i < 512; i++) currentKeyState[i] = 0;
// Read availables keycodes from stdin
- numKeysBuffer = read(STDIN_FILENO, keysBuffer, 32); // POSIX system call
+ bufferByteCount = read(STDIN_FILENO, keysBuffer, MAX_KEYBUFFER_SIZE); // POSIX system call
- // Fill array with pressed keys
- for (int i = 0; i < numKeysBuffer; i++)
+ // Fill all read bytes (looking for keys)
+ for (int i = 0; i < bufferByteCount; i++)
{
- //TraceLog(INFO, "Bytes on keysBuffer: %i", numKeysBuffer);
-
- int key = keysBuffer[i];
+ TraceLog(DEBUG, "Bytes on keysBuffer: %i", bufferByteCount);
+
+ //printf("Key(s) bytes: ");
+ //for (int i = 0; i < bufferByteCount; i++) printf("0x%02x ", keysBuffer[i]);
+ //printf("\n");
- if (keyboardMode == 2) // scancodes
+ // NOTE: If (key == 0x1b), depending on next key, it could be a special keymap code!
+ // Up -> 1b 5b 41 / Left -> 1b 5b 44 / Right -> 1b 5b 43 / Down -> 1b 5b 42
+ if (keysBuffer[i] == 0x1b)
{
- // NOTE: If (key == 0x1b), depending on next key, it could be a special keymap code!
- // Up -> 1b 5b 41 / Left -> 1b 5b 44 / Right -> 1b 5b 43 / Down -> 1b 5b 42
- if (key == 0x1b)
+ // Detect ESC to stop program
+ if (bufferByteCount == 1) currentKeyState[256] = 1; // raylib key: KEY_ESCAPE
+ else
{
- if (keysBuffer[i+1] == 0x5b) // Special function key
+ if (keysBuffer[i + 1] == 0x5b) // Special function key
{
- switch (keysBuffer[i+2])
+ if ((keysBuffer[i + 2] == 0x5b) || (keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32))
{
- case 0x41: currentKeyState[265] = 1; break;
- case 0x42: currentKeyState[264] = 1; break;
- case 0x43: currentKeyState[262] = 1; break;
- case 0x44: currentKeyState[263] = 1; break;
- default: break;
+ // Process special function keys (F1 - F12)
+ switch (keysBuffer[i + 3])
+ {
+ case 0x41: currentKeyState[290] = 1; break; // raylib KEY_F1
+ case 0x42: currentKeyState[291] = 1; break; // raylib KEY_F2
+ case 0x43: currentKeyState[292] = 1; break; // raylib KEY_F3
+ case 0x44: currentKeyState[293] = 1; break; // raylib KEY_F4
+ case 0x45: currentKeyState[294] = 1; break; // raylib KEY_F5
+ case 0x37: currentKeyState[295] = 1; break; // raylib KEY_F6
+ case 0x38: currentKeyState[296] = 1; break; // raylib KEY_F7
+ case 0x39: currentKeyState[297] = 1; break; // raylib KEY_F8
+ case 0x30: currentKeyState[298] = 1; break; // raylib KEY_F9
+ case 0x31: currentKeyState[299] = 1; break; // raylib KEY_F10
+ case 0x33: currentKeyState[300] = 1; break; // raylib KEY_F11
+ case 0x34: currentKeyState[301] = 1; break; // raylib KEY_F12
+ default: break;
+ }
+
+ if (keysBuffer[i + 2] == 0x5b) i += 4;
+ else if ((keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32)) i += 5;
}
+ else
+ {
+ switch (keysBuffer[i + 2])
+ {
+ case 0x41: currentKeyState[265] = 1; break; // raylib KEY_UP
+ case 0x42: currentKeyState[264] = 1; break; // raylib KEY_DOWN
+ case 0x43: currentKeyState[262] = 1; break; // raylib KEY_RIGHT
+ case 0x44: currentKeyState[263] = 1; break; // raylib KEY_LEFT
+ default: break;
+ }
- i += 2; // Jump to next key
-
- // NOTE: Other special function keys (F1, F2...) are not contempled for this keyboardMode...
- // ...or they are just not directly keymapped (CTRL, ALT, SHIFT)
+ i += 3; // Jump to next key
+ }
+
+ // NOTE: Some keys are not directly keymapped (CTRL, ALT, SHIFT)
}
}
- else if (key == 0x0a) currentKeyState[257] = 1; // raylib KEY_ENTER (don't mix with <linux/input.h> KEY_*)
- else if (key == 0x7f) currentKeyState[259] = 1;
- else
- {
- TraceLog(DEBUG, "Pressed key (ASCII): 0x%02x", key);
-
- currentKeyState[key] = 1;
- }
-
- // Detect ESC to stop program
- if ((key == 0x1b) && (numKeysBuffer == 1)) windowShouldClose = true;
}
- else if (keyboardMode == 1) // keycodes (K_MEDIUMRAW mode)
+ else if (keysBuffer[i] == 0x0a) currentKeyState[257] = 1; // raylib KEY_ENTER (don't mix with <linux/input.h> KEY_*)
+ else if (keysBuffer[i] == 0x7f) currentKeyState[259] = 1; // raylib KEY_BACKSPACE
+ else
{
- TraceLog(DEBUG, "Pressed key (keycode): 0x%02x", key);
+ TraceLog(DEBUG, "Pressed key (ASCII): 0x%02x", keysBuffer[i]);
- // NOTE: Each key is 7-bits (high bit in the byte is 0 for down, 1 for up)
-
- // TODO: Review (or rewrite) this code... not clear... replace by events!
-
- int asciiKey = -1;
-
- // Convert keycode to some recognized key (ASCII or GLFW3 equivalent)
- if (key < 128) asciiKey = (int)UnixKeycodeToASCII[key];
-
- // Record equivalent key state
- if ((asciiKey >= 0) && (asciiKey < 512)) currentKeyState[asciiKey] = 1;
-
- // In case of letter, we also activate lower case version
- if ((asciiKey >= 65) && (asciiKey <=90)) currentKeyState[asciiKey + 32] = 1;
-
- // Detect KEY_ESC to stop program
- if (key == 0x01) windowShouldClose = true;
- }
-
-
- // Same fucnionality as GLFW3 KeyCallback()
- /*
- if (asciiKey == exitKey) windowShouldClose = true;
- else if (key == GLFW_KEY_F12 && action == GLFW_PRESS)
- {
- TakeScreenshot();
- }
- */
- }
-
- // TODO: Gamepad support (use events, easy!)
-/*
- struct js_event gamepadEvent;
-
- read(gamepadStream, &gamepadEvent, sizeof(struct js_event));
-
- if (gamepadEvent.type == JS_EVENT_BUTTON)
- {
- switch (gamepadEvent.number)
- {
- case 0: // 1st Axis X
- case 1: // 1st Axis Y
- case 2: // 2st Axis X
- case 3: // 2st Axis Y
- case 4:
+ // Translate lowercase a-z letters to A-Z
+ if ((keysBuffer[i] >= 97) && (keysBuffer[i] <= 122))
{
- if (gamepadEvent.value == 1) // Button pressed, 0 release
-
- } break;
- // Buttons is similar, variable for every joystick
- }
- }
- else if (gamepadEvent.type == JS_EVENT_AXIS)
- {
- switch (gamepadEvent.number)
- {
- case 0: // 1st Axis X
- case 1: // 1st Axis Y
- case 2: // 2st Axis X
- case 3: // 2st Axis Y
- // Buttons is similar, variable for every joystick
+ currentKeyState[(int)keysBuffer[i] - 32] = 1;
+ }
+ else currentKeyState[(int)keysBuffer[i]] = 1;
}
}
-*/
-#endif
+
+ // Check exit key (same functionality as GLFW3 KeyCallback())
+ if (currentKeyState[exitKey] == 1) windowShouldClose = true;
+
+ // Check screen capture key
+ if (currentKeyState[301] == 1) TakeScreenshot(); // raylib key: KEY_F12 (GLFW_KEY_F12)
+}
+
+// Restore default keyboard input
+static void RestoreKeyboard(void)
+{
+ // Reset to default keyboard settings
+ tcsetattr(STDIN_FILENO, TCSANOW, &defaultKeyboardSettings);
+
+ // Reconfigure keyboard to default mode
+ ioctl(STDIN_FILENO, KDSKBMODE, defaultKeyboardMode);
}
-#if defined(PLATFORM_RPI)
// Mouse initialization (including mouse thread)
static void InitMouse(void)
{
@@ -2179,116 +2379,137 @@ static void InitMouse(void)
// if too much time passes between reads, queue gets full and new events override older ones...
static void *MouseThread(void *arg)
{
- struct input_event mouseEvent;
+ const unsigned char XSIGN = 1<<4, YSIGN = 1<<5;
+
+ typedef struct {
+ char buttons;
+ char dx, dy;
+ } MouseEvent;
+
+ MouseEvent mouse;
+
+ int mouseRelX = 0;
+ int mouseRelY = 0;
while(1)
{
- // NOTE: read() will return -1 if the events queue is empty
- read(mouseStream, &mouseEvent, sizeof(struct input_event));
-
- // Check event types
- if (mouseEvent.type == EV_REL) // Relative motion event
+ if (read(mouseStream, &mouse, sizeof(MouseEvent)) == (int)sizeof(MouseEvent))
{
- if (mouseEvent.code == REL_X)
- {
- mousePosition.x += (float)mouseEvent.value;
-
- // Screen limits X check
- if (mousePosition.x < 0) mousePosition.x = 0;
- if (mousePosition.x > screenWidth) mousePosition.x = screenWidth;
- }
-
- if (mouseEvent.code == REL_Y)
- {
- mousePosition.y += (float)mouseEvent.value;
+ if ((mouse.buttons & 0x08) == 0) break; // This bit should always be set
+
+ // Check Left button pressed
+ if ((mouse.buttons & 0x01) > 0) currentMouseState[0] = 1;
+ else currentMouseState[0] = 0;
- // Screen limits Y check
- if (mousePosition.y < 0) mousePosition.y = 0;
- if (mousePosition.y > screenHeight) mousePosition.y = screenHeight;
- }
+ // Check Right button pressed
+ if ((mouse.buttons & 0x02) > 0) currentMouseState[1] = 1;
+ else currentMouseState[1] = 0;
+
+ // Check Middle button pressed
+ if ((mouse.buttons & 0x04) > 0) currentMouseState[2] = 1;
+ else currentMouseState[2] = 0;
+
+ mouseRelX = (int)mouse.dx;
+ mouseRelY = (int)mouse.dy;
+
+ if ((mouse.buttons & XSIGN) > 0) mouseRelX = -1*(255 - mouseRelX);
+ if ((mouse.buttons & YSIGN) > 0) mouseRelY = -1*(255 - mouseRelY);
+
+ // NOTE: Mouse movement is normalized to not be screen resolution dependant
+ // We suppose 2*255 (max relative movement) is equivalent to screenWidth (max pixels width)
+ // Result after normalization is multiplied by MOUSE_SENSITIVITY factor
- if (mouseEvent.code == REL_WHEEL)
- {
- // mouseEvent.value give 1 or -1 (direction)
- }
- }
- else if (mouseEvent.type == EV_KEY) // Mouse button event
- {
- if (mouseEvent.code == BTN_LEFT) currentMouseState[0] = mouseEvent.value;
- if (mouseEvent.code == BTN_RIGHT) currentMouseState[1] = mouseEvent.value;
- if (mouseEvent.code == BTN_MIDDLE) currentMouseState[2] = mouseEvent.value;
- }
+ mousePosition.x += (float)mouseRelX*((float)screenWidth/(2*255))*MOUSE_SENSITIVITY;
+ mousePosition.y -= (float)mouseRelY*((float)screenHeight/(2*255))*MOUSE_SENSITIVITY;
+
+ if (mousePosition.x < 0) mousePosition.x = 0;
+ if (mousePosition.y < 0) mousePosition.y = 0;
+
+ if (mousePosition.x > screenWidth) mousePosition.x = screenWidth;
+ if (mousePosition.y > screenHeight) mousePosition.y = screenHeight;
+ }
+ //else read(mouseStream, &mouse, 1); // Try to sync up again
}
return NULL;
}
-// Initialize Keyboard system (using standard input)
-static void InitKeyboard(void)
+// Init gamepad system
+static void InitGamepad(void)
{
- // NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor
-
- // Make stdin non-blocking (not enough, need to configure to non-canonical mode)
- int flags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags
- fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified
-
- // Save terminal keyboard settings and reconfigure terminal with new settings
- struct termios keyboardNewSettings;
- tcgetattr(STDIN_FILENO, &defaultKeyboardSettings); // Get current keyboard settings
- keyboardNewSettings = defaultKeyboardSettings;
-
- // New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
- // NOTE: ISIG controls if ^C and ^Z generate break signals or not
- keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG);
- //keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
- keyboardNewSettings.c_cc[VMIN] = 1;
- keyboardNewSettings.c_cc[VTIME] = 0;
-
- // Set new keyboard settings (change occurs immediately)
- tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings);
-
- // NOTE: Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE, we change that!
-
- // Save old keyboard mode to restore it at the end
- if (ioctl(STDIN_FILENO, KDGKBMODE, &defaultKeyboardMode) < 0)
+ if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0)
{
- // NOTE: It could mean we are using a remote keyboard through ssh!
- TraceLog(WARNING, "Could not change keyboard mode (SSH keyboard?)");
-
- keyboardMode = 2; // ASCII
+ TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available");
}
else
{
- // We reconfigure keyboard mode to get:
- // - scancodes (K_RAW)
- // - keycodes (K_MEDIUMRAW)
- // - ASCII chars (K_XLATE)
- // - UNICODE chars (K_UNICODE)
- ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW);
+ gamepadReady = true;
- keyboardMode = 1; // keycodes
- }
+ int error = pthread_create(&gamepadThreadId, NULL, &GamepadThread, NULL);
- // Register keyboard restore when program finishes
- atexit(RestoreKeyboard);
+ if (error != 0) TraceLog(WARNING, "Error creating gamepad input event thread");
+ else TraceLog(INFO, "Gamepad device initialized successfully");
+ }
}
-// Restore default keyboard input
-static void RestoreKeyboard(void)
+// Process Gamepad (/dev/input/js0)
+static void *GamepadThread(void *arg)
{
- // Reset to default keyboard settings
- tcsetattr(STDIN_FILENO, TCSANOW, &defaultKeyboardSettings);
-
- // Reconfigure keyboard to default mode
- ioctl(STDIN_FILENO, KDSKBMODE, defaultKeyboardMode);
-}
+ #define JS_EVENT_BUTTON 0x01 // Button pressed/released
+ #define JS_EVENT_AXIS 0x02 // Joystick axis moved
+ #define JS_EVENT_INIT 0x80 // Initial state of device
-// Init gamepad system
-static void InitGamepad(void)
-{
- // TODO: Gamepad support
- if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available");
- else TraceLog(INFO, "Gamepad device initialized successfully");
+ struct js_event {
+ unsigned int time; // event timestamp in milliseconds
+ short value; // event value
+ unsigned char type; // event type
+ unsigned char number; // event axis/button number
+ };
+
+ // These values are sensible on Logitech Dual Action Rumble and Xbox360 controller
+ const int joystickAxisX = 0;
+ const int joystickAxisY = 1;
+
+ // Read gamepad event
+ struct js_event gamepadEvent;
+
+ while (1)
+ {
+ if (read(gamepadStream, &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event))
+ {
+ gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events
+
+ // Process gamepad events by type
+ if (gamepadEvent.type == JS_EVENT_BUTTON)
+ {
+ TraceLog(DEBUG, "Gamepad button: %i, value: %i", gamepadEvent.number, gamepadEvent.value);
+
+ if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS)
+ {
+ // 1 - button pressed, 0 - button released
+ gamepadButtons[gamepadEvent.number] = (int)gamepadEvent.value;
+ }
+ }
+ else if (gamepadEvent.type == JS_EVENT_AXIS)
+ {
+ TraceLog(DEBUG, "Gamepad axis: %i, value: %i", gamepadEvent.number, gamepadEvent.value);
+
+ if (gamepadEvent.number == joystickAxisX) gamepadAxisX = (int)gamepadEvent.value;
+ if (gamepadEvent.number == joystickAxisY) gamepadAxisY = (int)gamepadEvent.value;
+ /*
+ switch (gamepadEvent.number)
+ {
+ case 0: // 1st Axis X
+ case 1: // 1st Axis Y
+ case 2: // 2st Axis X
+ case 3: // 2st Axis Y
+ }
+ */
+ }
+ }
+ }
+
+ return NULL;
}
#endif
@@ -2306,6 +2527,10 @@ static void SwapBuffers(void)
// NOTE: Global variables renderWidth/renderHeight can be modified
static void SetupFramebufferSize(int displayWidth, int displayHeight)
{
+ // TODO: SetupFramebufferSize() does not consider properly display video modes.
+ // It setups a renderWidth/renderHeight with black bars that could not match a valid video mode,
+ // and so, framebuffer is not scaled properly to some monitors.
+
// Calculate renderWidth and renderHeight, we have the display size (input params) and the desired screen size (global var)
if ((screenWidth > displayWidth) || (screenHeight > displayHeight))
{
@@ -2436,6 +2661,10 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent
// Register touch points count
gestureEvent.pointCount = touchEvent->numTouches;
+ // Register touch points id
+ gestureEvent.pointerId[0] = touchEvent->touches[0].identifier;
+ gestureEvent.pointerId[1] = touchEvent->touches[1].identifier;
+
// Register touch points position
// NOTE: Only two points registered
// TODO: Touch data should be scaled accordingly!
@@ -2444,8 +2673,16 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent
gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY };
gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY };
- touchPosition = gestureEvent.position[0];
+ touchPosition[0] = gestureEvent.position[0];
+ touchPosition[1] = gestureEvent.position[1];
+ // Normalize gestureEvent.position[x] for screenWidth and screenHeight
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+
+ gestureEvent.position[1].x /= (float)GetScreenWidth();
+ gestureEvent.position[1].y /= (float)GetScreenHeight();
+
// Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent); // Process obtained gestures data
@@ -2469,7 +2706,6 @@ static void LogoAnimation(void)
int bottomSideRecWidth = 16;
int rightSideRecHeight = 16;
- char raylib[8] = " "; // raylib text array, max 8 letters
int state = 0; // Tracking animation states (State Machine)
float alpha = 1.0f; // Useful for fading
@@ -2511,17 +2747,6 @@ static void LogoAnimation(void)
framesCounter = 0;
}
- switch (lettersCount)
- {
- case 1: raylib[0] = 'r'; break;
- case 2: raylib[1] = 'a'; break;
- case 3: raylib[2] = 'y'; break;
- case 4: raylib[3] = 'l'; break;
- case 5: raylib[4] = 'i'; break;
- case 6: raylib[5] = 'b'; break;
- default: break;
- }
-
if (lettersCount >= 10) // When all letters have appeared, just fade out everything
{
alpha -= 0.02f;
@@ -2568,7 +2793,7 @@ static void LogoAnimation(void)
DrawRectangle(screenWidth/2 - 112, screenHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha));
- DrawText(raylib, screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha));
+ DrawText(SubText("raylib", 0, lettersCount), screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha));
}
EndDrawing();
diff --git a/src/gestures.c b/src/gestures.c
index ea744555..e615c06d 100644
--- a/src/gestures.c
+++ b/src/gestures.c
@@ -1,8 +1,10 @@
/**********************************************************************************************
*
-* raylib Gestures System - Gestures Detection and Usage Functions (Android and HTML5)
+* raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse)
*
-* Copyright (c) 2015 Marc Palau and Ramon Santamaria
+* Initial design by Marc Palau
+* Redesigned by Albert Martos and Ian Eito
+* Reviewed by Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -29,9 +31,7 @@
#include "raylib.h" // Required for typedef(s): Vector2, Gestures
#endif
-#include <stdlib.h> // malloc(), free()
-#include <stdio.h> // printf(), fprintf()
-#include <math.h> // Used for ...
+#include <math.h> // Used for: atan2(), sqrt()
#include <stdint.h> // Defines int32_t, int64_t
#if defined(_WIN32)
@@ -39,72 +39,73 @@
int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount);
int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency);
#elif defined(__linux)
+ #include <sys/time.h> // Declares storage size of ‘now’
#include <time.h> // Used for clock functions
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
-#define FORCE_TO_SWIPE 20
-#define TAP_TIMEOUT 300
-//#define MAX_TOUCH_POINTS 4
+#define FORCE_TO_SWIPE 0.0005f // Measured in normalized pixels / time
+#define MINIMUM_DRAG 0.015f // Measured in normalized pixels [0..1]
+#define MINIMUM_PINCH 0.005f // Measured in normalized pixels [0..1]
+#define TAP_TIMEOUT 300 // Time in milliseconds
+#define PINCH_TIMEOUT 300 // Time in milliseconds
+#define DOUBLETAP_RANGE 0.03f
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
-typedef enum {
- TYPE_MOTIONLESS,
- TYPE_DRAG,
- TYPE_DUAL_INPUT
-} GestureType;
+// ...
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
-static GestureType gestureType = TYPE_MOTIONLESS;
-static double eventTime = 0;
-//static int32_t touchId; // Not used...
-// Tap gesture variables
-static Vector2 initialTapPosition = { 0, 0 };
+// Touch gesture variables
+static Vector2 touchDownPosition = { 0.0f, 0.0f };
+static Vector2 touchDownPosition2 = { 0.0f, 0.0f };
+static Vector2 touchDownDragPosition = { 0.0f, 0.0f };
+static Vector2 touchUpPosition = { 0.0f, 0.0f };
+static Vector2 moveDownPosition = { 0.0f, 0.0f };
+static Vector2 moveDownPosition2 = { 0.0f, 0.0f };
+static int numTap = 0;
-// Double Tap gesture variables
-static bool doubleTapping = false;
-static bool untap = false; // Check if recently done a tap
+static int pointCount = 0;
+static int touchId = -1;
-// Drag gesture variables
-static Vector2 initialDragPosition = { 0, 0 };
-static Vector2 endDragPosition = { 0, 0 };
-static Vector2 lastDragPosition = { 0, 0 };
-static Vector2 dragVector = { 0, 0 };
+static double eventTime = 0.0;
+static double swipeTime = 0.0;
+
+// Hold gesture variables
+static int numHold = 0;
+static float timeHold = 0.0f;
-static float magnitude = 0; // Distance traveled dragging
-static float angle = 0; // Angle direction of the drag
-static float intensity = 0; // How fast we did the drag (pixels per frame)
-static int draggingTimeCounter = 0; // Time that have passed while dragging
+// Drag gesture variables
+static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position)
+static float dragAngle = 0.0f; // DRAG angle (relative to x-axis)
+static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) (normalized [0..1])
+static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame)
+static bool startMoving = false; // SWIPE used to define when start measuring swipeTime
// Pinch gesture variables
-static Vector2 firstInitialPinchPosition = { 0, 0 };
-static Vector2 secondInitialPinchPosition = { 0, 0 };
-static Vector2 firstEndPinchPosition = { 0, 0 };
-static Vector2 secondEndPinchPosition = { 0, 0 };
-static float pinchDelta = 0; // Pinch delta displacement
+static Vector2 pinchVector = { 0.0f , 0.0f }; // PINCH vector (between first and second touch points)
+static float pinchAngle = 0.0f; // PINCH angle (relative to x-axis)
+static float pinchDistance = 0.0f; // PINCH displacement distance (normalized [0..1])
// Detected gestures
static int previousGesture = GESTURE_NONE;
static int currentGesture = GESTURE_NONE;
// Enabled gestures flags, all gestures enabled by default
-static unsigned int enabledGestures = 0b0000011111111111;
+static unsigned int enabledGestures = 0b0000001111111111;
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
-static void InitPinchGesture(Vector2 posA, Vector2 posB);
-static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, float magnitude);
-static float VectorDistance(Vector2 v1, Vector2 v2);
-static float VectorDotProduct(Vector2 v1, Vector2 v2);
-static double GetCurrentTime();
+static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition);
+static float Vector2Distance(Vector2 v1, Vector2 v2);
+static double GetCurrentTime(void);
//----------------------------------------------------------------------------------
// Module Functions Definition
@@ -113,179 +114,185 @@ static double GetCurrentTime();
// Process gesture event and translate it into gestures
void ProcessGestureEvent(GestureEvent event)
{
- // Resets
- dragVector = (Vector2){ 0, 0 };
- pinchDelta = 0;
-
+ // Reset required variables
previousGesture = currentGesture;
- switch (gestureType)
- {
- case TYPE_MOTIONLESS: // Detect TAP, DOUBLE_TAP and HOLD events
+ pointCount = event.pointCount; // Required on UpdateGestures()
+
+ if (pointCount < 2)
+ {
+ touchId = event.pointerId[0];
+
+ if (event.touchAction == TOUCH_DOWN)
{
- if (event.touchAction == TOUCH_DOWN)
+ numTap++; // Tap counter
+
+ // Detect GESTURE_DOUBLE_TAP
+ if ((currentGesture == GESTURE_NONE) && (numTap >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE))
{
- if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]);
- else
- {
- // Set the press position
- initialTapPosition = event.position[0];
-
- // If too much time have passed, we reset the double tap
- if (GetCurrentTime() - eventTime > TAP_TIMEOUT) untap = false;
-
- // If we are in time, we detect the double tap
- if (untap) doubleTapping = true;
-
- // Update our event time
- eventTime = GetCurrentTime();
-
- // Set hold
- if (doubleTapping) currentGesture = GESTURE_DOUBLETAP;
- else currentGesture = GESTURE_TAP;
- }
+ currentGesture = GESTURE_DOUBLETAP;
+ numTap = 0;
}
- else if (event.touchAction == TOUCH_UP)
+ else // Detect GESTURE_TAP
{
- currentGesture = GESTURE_NONE;
-
- // Detect that we are tapping instead of holding
- if (GetCurrentTime() - eventTime < TAP_TIMEOUT)
- {
- if (doubleTapping) untap = false;
- else untap = true;
- }
+ numTap = 1;
+ currentGesture = GESTURE_TAP;
+ }
+
+ touchDownPosition = event.position[0];
+ touchDownDragPosition = event.position[0];
+
+ touchUpPosition = touchDownPosition;
+ eventTime = GetCurrentTime();
+
+ dragVector = (Vector2){ 0.0f, 0.0f };
+ }
+ else if (event.touchAction == TOUCH_UP)
+ {
+ if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0];
+
+ // NOTE: dragIntensity dependend on the resolution of the screen
+ dragDistance = Vector2Distance(touchDownPosition, touchUpPosition);
+ dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime));
+
+ startMoving = false;
+
+ // Detect GESTURE_SWIPE
+ if ((dragIntensity > FORCE_TO_SWIPE) && (touchId == 0)) // RAY: why check (touchId == 0)???
+ {
+ // NOTE: Angle should be inverted in Y
+ dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition);
- // Tap finished
- doubleTapping = false;
-
- // Update our event time
- eventTime = GetCurrentTime();
+ if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right
+ else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up
+ else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left
+ else if ((dragAngle > 210) && (dragAngle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down
+ else currentGesture = GESTURE_NONE;
}
- // Begin dragging
- else if (event.touchAction == TOUCH_MOVE)
+ else
{
- if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]);
- else
- {
- // Set the drag starting position
- initialDragPosition = initialTapPosition;
- endDragPosition = initialDragPosition;
-
- // Initialize drag
- draggingTimeCounter = 0;
- gestureType = TYPE_DRAG;
- currentGesture = GESTURE_NONE;
- }
+ dragDistance = 0.0f;
+ dragIntensity = 0.0f;
+ dragAngle = 0.0f;
+
+ currentGesture = GESTURE_NONE;
}
- } break;
- case TYPE_DRAG: // Detect DRAG and SWIPE events
+
+ touchDownDragPosition = (Vector2){ 0.0f, 0.0f };
+ }
+ else if (event.touchAction == TOUCH_MOVE)
{
- // end of the drag
- if (event.touchAction == TOUCH_UP)
+ if (currentGesture == GESTURE_DRAG) eventTime = GetCurrentTime();
+
+ if (!startMoving)
{
- // Return Swipe if we have enough sensitivity
- if (intensity > FORCE_TO_SWIPE)
- {
- if (angle < 30 || angle > 330) currentGesture = GESTURE_SWIPE_RIGHT; // Right
- else if (angle > 60 && angle < 120) currentGesture = GESTURE_SWIPE_UP; // Up
- else if (angle > 150 && angle < 210) currentGesture = GESTURE_SWIPE_LEFT; // Left
- else if (angle > 240 && angle < 300) currentGesture = GESTURE_SWIPE_DOWN; // Down
- }
-
- magnitude = 0;
- angle = 0;
- intensity = 0;
-
- gestureType = TYPE_MOTIONLESS;
+ swipeTime = GetCurrentTime();
+ startMoving = true;
}
- // Update while we are dragging
- else if (event.touchAction == TOUCH_MOVE)
+
+ moveDownPosition = event.position[0];
+
+ if (currentGesture == GESTURE_HOLD)
{
- if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]);
- else
+ if (numHold == 1) touchDownPosition = event.position[0];
+
+ numHold = 2;
+
+ // Detect GESTURE_DRAG
+ if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG)
{
- lastDragPosition = endDragPosition;
- endDragPosition = event.position[0];
-
- //endDragPosition.x = AMotionEvent_getX(event, 0);
- //endDragPosition.y = AMotionEvent_getY(event, 0);
-
- // Calculate attributes
- dragVector = (Vector2){ endDragPosition.x - lastDragPosition.x, endDragPosition.y - lastDragPosition.y };
- magnitude = sqrt(pow(endDragPosition.x - initialDragPosition.x, 2) + pow(endDragPosition.y - initialDragPosition.y, 2));
- angle = CalculateAngle(initialDragPosition, endDragPosition, magnitude);
- intensity = magnitude / (float)draggingTimeCounter;
-
- // Check if drag movement is less than minimum to keep it as hold state or switch to drag state
- if(magnitude > FORCE_TO_SWIPE)
- {
- currentGesture = GESTURE_DRAG;
- draggingTimeCounter++;
- }
- else currentGesture = GESTURE_HOLD;
+ eventTime = GetCurrentTime();
+ currentGesture = GESTURE_DRAG;
}
}
- } break;
- case TYPE_DUAL_INPUT:
+
+ dragVector.x = moveDownPosition.x - touchDownDragPosition.x;
+ dragVector.y = moveDownPosition.y - touchDownDragPosition.y;
+ }
+ }
+ else // Two touch points
+ {
+ if (event.touchAction == TOUCH_DOWN)
{
- if (event.touchAction == TOUCH_UP)
+ touchDownPosition = event.position[0];
+ touchDownPosition2 = event.position[1];
+
+ //pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2);
+
+ pinchVector.x = touchDownPosition2.x - touchDownPosition.x;
+ pinchVector.y = touchDownPosition2.y - touchDownPosition.y;
+
+ currentGesture = GESTURE_HOLD;
+ timeHold = GetCurrentTime();
+ }
+ else if (event.touchAction == TOUCH_MOVE)
+ {
+ pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2);
+
+ touchDownPosition = moveDownPosition;
+ touchDownPosition2 = moveDownPosition2;
+
+ moveDownPosition = event.position[0];
+ moveDownPosition2 = event.position[1];
+
+ pinchVector.x = moveDownPosition2.x - moveDownPosition.x;
+ pinchVector.y = moveDownPosition2.y - moveDownPosition.y;
+
+ if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH))
{
- if (event.pointCount == 1)
- {
- // Set the drag starting position
- initialTapPosition = event.position[0];
- }
- gestureType = TYPE_MOTIONLESS;
+ if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN;
+ else currentGesture = GESTURE_PINCH_OUT;
}
- else if (event.touchAction == TOUCH_MOVE)
+ else
{
- // Adapt the ending position of the inputs
- firstEndPinchPosition = event.position[0];
- secondEndPinchPosition = event.position[1];
-
- // If there is no more than two inputs
- if (event.pointCount == 2)
- {
- // Calculate distances
- float initialDistance = VectorDistance(firstInitialPinchPosition, secondInitialPinchPosition);
- float endDistance = VectorDistance(firstEndPinchPosition, secondEndPinchPosition);
-
- // Calculate Vectors
- Vector2 firstTouchVector = { firstEndPinchPosition.x - firstInitialPinchPosition.x, firstEndPinchPosition.y - firstInitialPinchPosition.y };
- Vector2 secondTouchVector = { secondEndPinchPosition.x - secondInitialPinchPosition.x, secondEndPinchPosition.y - secondInitialPinchPosition.y };
-
- // Detect the pinch gesture
- if (VectorDotProduct(firstTouchVector, secondTouchVector) < -0.5) pinchDelta = initialDistance - endDistance;
- else pinchDelta = 0;
-
- // Pinch gesture resolution
- if (pinchDelta != 0)
- {
- if (pinchDelta > 0) currentGesture = GESTURE_PINCH_IN;
- else currentGesture = GESTURE_PINCH_OUT;
- }
- }
- else
- {
- // Set the drag starting position
- initialTapPosition = event.position[0];
-
- gestureType = TYPE_MOTIONLESS;
- }
-
- // Readapt the initial position of the inputs
- firstInitialPinchPosition = firstEndPinchPosition;
- secondInitialPinchPosition = secondEndPinchPosition;
+ currentGesture = GESTURE_HOLD;
+ timeHold = GetCurrentTime();
}
- } break;
+
+ // NOTE: Angle should be inverted in Y
+ pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2);
+ }
+ else if (event.touchAction == TOUCH_UP)
+ {
+ pinchDistance = 0.0f;
+ pinchAngle = 0.0f;
+ pinchVector = (Vector2){ 0.0f, 0.0f };
+
+ currentGesture = GESTURE_NONE;
+ }
+ }
+}
+
+// Update gestures detected (must be called every frame)
+void UpdateGestures(void)
+{
+ // NOTE: Gestures are processed through system callbacks on touch events
+
+ // Detect GESTURE_HOLD
+ if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && (pointCount < 2))
+ {
+ currentGesture = GESTURE_HOLD;
+ timeHold = GetCurrentTime();
+ }
+
+ if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2))
+ {
+ currentGesture = GESTURE_HOLD;
+ timeHold = GetCurrentTime();
+ numHold = 1;
+ }
+
+ // Detect GESTURE_NONE
+ if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN))
+ {
+ currentGesture = GESTURE_NONE;
}
}
// Check if a gesture have been detected
bool IsGestureDetected(void)
{
- if (currentGesture != GESTURE_NONE) return true;
+ if ((enabledGestures & currentGesture) != GESTURE_NONE) return true;
else return false;
}
@@ -296,124 +303,86 @@ int GetGestureType(void)
return (enabledGestures & currentGesture);
}
-void SetGesturesEnabled(unsigned int gestureFlags)
+// Get number of touch points
+int GetTouchPointsCount(void)
{
- enabledGestures = enabledGestures | gestureFlags;
+ // NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called
+
+ return pointCount;
}
-// Get drag intensity (pixels per frame)
-float GetGestureDragIntensity(void)
+// Enable only desired getures to be detected
+void SetGesturesEnabled(unsigned int gestureFlags)
{
- return intensity;
+ enabledGestures = gestureFlags;
}
-// Get drag angle
-// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
-float GetGestureDragAngle(void)
+// Hold time measured in ms
+float GetGestureHoldDuration(void)
{
- return angle;
+ // NOTE: time is calculated on current gesture HOLD
+
+ float time = 0.0f;
+
+ if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold;
+
+ return time;
}
-// Get drag vector (between initial and final position)
+// Get drag vector (between initial touch point to current)
Vector2 GetGestureDragVector(void)
{
+ // NOTE: drag vector is calculated on one touch points TOUCH_MOVE
+
return dragVector;
}
-// Hold time measured in frames
-int GetGestureHoldDuration(void)
+// Get drag angle
+// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
+float GetGestureDragAngle(void)
{
- return 0;
+ // NOTE: drag angle is calculated on one touch points TOUCH_UP
+
+ return dragAngle;
}
-// Get magnitude between two pinch points
-float GetGesturePinchDelta(void)
+// Get distance between two pinch points
+Vector2 GetGesturePinchVector(void)
{
- return pinchDelta;
+ // NOTE: The position values used for pinchDistance are not modified like the position values of [core.c]-->GetTouchPosition(int index)
+ // NOTE: pinch distance is calculated on two touch points TOUCH_MOVE
+
+ return pinchVector;
}
// Get angle beween two pinch points
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
float GetGesturePinchAngle(void)
{
- return 0;
-}
-
-// Update gestures detected (must be called every frame)
-void UpdateGestures(void)
-{
- // NOTE: Gestures are processed through system callbacks on touch events
-
- // When screen is touched, in first frame GESTURE_TAP is called but in next frame touch event callback is not called (if touch position doesn't change),
- // so we need to store previous frame gesture type manually in this update function to switch to HOLD if current gesture is
- // GESTURE_TAP two frames in a row. Due to current gesture is set to HOLD, current gesture doesn't need to be reset to NONE every frame.
- // It will be reset when UP is called.
- if(currentGesture == GESTURE_TAP) previousGesture = currentGesture;
+ // NOTE: pinch angle is calculated on two touch points TOUCH_MOVE
- if(previousGesture == GESTURE_TAP && currentGesture == GESTURE_TAP) currentGesture = GESTURE_HOLD;
+ return pinchAngle;
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
-static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, float magnitude)
+// Returns angle from two-points vector with X-axis
+static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition)
{
float angle;
-
- // Calculate arcsinus of the movement
- angle = asin((finalPosition.y - initialPosition.y)/magnitude);
- angle *= RAD2DEG;
-
- // Calculate angle depending on the sector
- if ((finalPosition.x - initialPosition.x) >= 0)
- {
- // Sector 4
- if ((finalPosition.y - initialPosition.y) >= 0)
- {
- angle *= -1;
- angle += 360;
- }
- // Sector 1
- else angle *= -1;
- }
- else
- {
- // Sector 3
- if ((finalPosition.y - initialPosition.y) >= 0) angle += 180;
- // Sector 2
- else
- {
- angle *= -1;
- angle = 180 - angle;
- }
- }
-
- return angle;
-}
-static void InitPinchGesture(Vector2 posA, Vector2 posB)
-{
- initialDragPosition = (Vector2){ 0, 0 };
- endDragPosition = (Vector2){ 0, 0 };
- lastDragPosition = (Vector2){ 0, 0 };
-
- // Initialize positions
- firstInitialPinchPosition = posA;
- secondInitialPinchPosition = posB;
-
- firstEndPinchPosition = firstInitialPinchPosition;
- secondEndPinchPosition = secondInitialPinchPosition;
+ angle = atan2(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x);
+ angle *= RAD2DEG;
- // Resets
- magnitude = 0;
- angle = 0;
- intensity = 0;
+ if (angle < 0) angle += 360.0f;
- gestureType = TYPE_DUAL_INPUT;
+ return angle;
}
-static float VectorDistance(Vector2 v1, Vector2 v2)
+// Calculate distance between two Vector2
+static float Vector2Distance(Vector2 v1, Vector2 v2)
{
float result;
@@ -425,22 +394,8 @@ static float VectorDistance(Vector2 v1, Vector2 v2)
return result;
}
-static float VectorDotProduct(Vector2 v1, Vector2 v2)
-{
- float result;
-
- float v1Module = sqrt(v1.x*v1.x + v1.y*v1.y);
- float v2Module = sqrt(v2.x*v2.x + v2.y*v2.y);
-
- Vector2 v1Normalized = { v1.x / v1Module, v1.y / v1Module };
- Vector2 v2Normalized = { v2.x / v2Module, v2.y / v2Module };
-
- result = v1Normalized.x*v2Normalized.x + v1Normalized.y*v2Normalized.y;
-
- return result;
-}
-
-static double GetCurrentTime()
+// Time measure returned are milliseconds
+static double GetCurrentTime(void)
{
double time = 0;
@@ -450,16 +405,16 @@ static double GetCurrentTime()
QueryPerformanceFrequency(&clockFrequency);
QueryPerformanceCounter(&currentTime);
- time = (double)currentTime/clockFrequency*1000.0f; // time in miliseconds
+ time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds
#endif
#if defined(__linux)
// NOTE: Only for Linux-based systems
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
- uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time provided in nanoseconds
+ uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds
- time = ((double)nowTime/1000000.0); // time in miliseconds
+ time = ((double)nowTime/1000000.0); // Time in miliseconds
#endif
return time;
diff --git a/src/gestures.h b/src/gestures.h
index b5cf2767..5468eb54 100644
--- a/src/gestures.h
+++ b/src/gestures.h
@@ -90,19 +90,20 @@ extern "C" { // Prevents name mangling of functions
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
+void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
void UpdateGestures(void); // Update gestures detected (must be called every frame)
bool IsGestureDetected(void); // Check if a gesture have been detected
int GetGestureType(void); // Get latest detected gesture
void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags
-void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
+int GetTouchPointsCount(void); // Get touch points count
-float GetGestureDragIntensity(void); // Get gesture drag intensity
-float GetGestureDragAngle(void); // Get gesture drag angle
+float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds
Vector2 GetGestureDragVector(void); // Get gesture drag vector
-int GetGestureHoldDuration(void); // Get gesture hold time in frames
-float GetGesturePinchDelta(void); // Get gesture pinch delta
+float GetGestureDragAngle(void); // Get gesture drag angle
+Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
float GetGesturePinchAngle(void); // Get gesture pinch angle
+
#ifdef __cplusplus
}
#endif
diff --git a/src/libraylib.bc b/src/libraylib.bc
new file mode 100644
index 00000000..21039250
--- /dev/null
+++ b/src/libraylib.bc
Binary files differ
diff --git a/src/makefile b/src/makefile
index 70fbca7c..cab2ced0 100644
--- a/src/makefile
+++ b/src/makefile
@@ -91,7 +91,13 @@ else
endif
# define all object files required
-OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o camera.o gestures.o stb_vorbis.o
+ifeq ($(PLATFORM),PLATFORM_DESKTOP)
+ OBJS = core.o rlgl.o glad.o shapes.o text.o textures.o models.o audio.o utils.o camera.o gestures.o stb_vorbis.o
+else
+ #GLAD only required on desktop platform
+ OBJS = core.o rlgl.o shapes.o text.o textures.o models.o audio.o stb_vorbis.o utils.o camera.o gestures.o
+endif
+
# typing 'make' will invoke the first target entry in the file,
# in this case, the 'default' target entry is raylib
@@ -114,9 +120,9 @@ core.o: core.c
rlgl.o: rlgl.c
$(CC) -c rlgl.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM) -D$(GRAPHICS)
-# compile raymath module
-raymath.o: raymath.c
- $(CC) -c raymath.c $(CFLAGS) $(INCLUDES)
+# compile glad module
+glad.o: glad.c
+ $(CC) -c glad.c $(CFLAGS) $(INCLUDES)
# compile shapes module
shapes.o: shapes.c
diff --git a/src/models.c b/src/models.c
index 80d9a13a..8a36c279 100644
--- a/src/models.c
+++ b/src/models.c
@@ -55,7 +55,6 @@ extern unsigned int whiteTexture;
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
-static float GetHeightValue(Color pixel);
static Mesh LoadOBJ(const char *fileName);
//----------------------------------------------------------------------------------
@@ -557,7 +556,7 @@ void DrawGizmo(Vector3 position)
// Load a 3d model (from file)
Model LoadModel(const char *fileName)
{
- Model model;
+ Model model = { 0 };
Mesh mesh = { 0 };
// NOTE: Initialize default data for model in case loading fails, maybe a cube?
@@ -608,17 +607,19 @@ Model LoadModelEx(Mesh data)
}
// Load a heightmap image as a 3d model
-Model LoadHeightmap(Image heightmap, float maxHeight)
+// NOTE: model map size is defined in generic units
+Model LoadHeightmap(Image heightmap, Vector3 size)
{
+ #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3)
+
Mesh mesh;
int mapX = heightmap.width;
int mapZ = heightmap.height;
- Color *heightmapPixels = GetImageData(heightmap);
+ Color *pixels = GetImageData(heightmap);
// NOTE: One vertex per pixel
- // TODO: Consider resolution when generating model data?
int numTriangles = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
mesh.vertexCount = numTriangles*3;
@@ -634,7 +635,7 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
int trisCounter = 0;
- float scaleFactor = maxHeight/255; // TODO: Review scaleFactor calculation
+ Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
for(int z = 0; z < mapZ-1; z++)
{
@@ -644,17 +645,17 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
//----------------------------------------------------------
// one triangle - 3 vertex
- mesh.vertices[vCounter] = x;
- mesh.vertices[vCounter + 1] = GetHeightValue(heightmapPixels[x + z*mapX])*scaleFactor;
- mesh.vertices[vCounter + 2] = z;
+ mesh.vertices[vCounter] = (float)x*scaleFactor.x;
+ mesh.vertices[vCounter + 1] = (float)GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y;
+ mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z;
- mesh.vertices[vCounter + 3] = x;
- mesh.vertices[vCounter + 4] = GetHeightValue(heightmapPixels[x + (z+1)*mapX])*scaleFactor;
- mesh.vertices[vCounter + 5] = z+1;
+ mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x;
+ mesh.vertices[vCounter + 4] = (float)GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y;
+ mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z;
- mesh.vertices[vCounter + 6] = x+1;
- mesh.vertices[vCounter + 7] = GetHeightValue(heightmapPixels[(x+1) + z*mapX])*scaleFactor;
- mesh.vertices[vCounter + 8] = z;
+ mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x;
+ mesh.vertices[vCounter + 7] = (float)GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y;
+ mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z;
// another triangle - 3 vertex
mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6];
@@ -665,21 +666,21 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
mesh.vertices[vCounter + 13] = mesh.vertices[vCounter + 4];
mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5];
- mesh.vertices[vCounter + 15] = x+1;
- mesh.vertices[vCounter + 16] = GetHeightValue(heightmapPixels[(x+1) + (z+1)*mapX])*scaleFactor;
- mesh.vertices[vCounter + 17] = z+1;
+ mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x;
+ mesh.vertices[vCounter + 16] = (float)GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y;
+ mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z;
vCounter += 18; // 6 vertex, 18 floats
// Fill texcoords array with data
//--------------------------------------------------------------
- mesh.texcoords[tcCounter] = (float)x / (mapX-1);
- mesh.texcoords[tcCounter + 1] = (float)z / (mapZ-1);
+ mesh.texcoords[tcCounter] = (float)x/(mapX - 1);
+ mesh.texcoords[tcCounter + 1] = (float)z/(mapZ - 1);
- mesh.texcoords[tcCounter + 2] = (float)x / (mapX-1);
- mesh.texcoords[tcCounter + 3] = (float)(z+1) / (mapZ-1);
+ mesh.texcoords[tcCounter + 2] = (float)x/(mapX - 1);
+ mesh.texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1);
- mesh.texcoords[tcCounter + 4] = (float)(x+1) / (mapX-1);
- mesh.texcoords[tcCounter + 5] = (float)z / (mapZ-1);
+ mesh.texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1);
+ mesh.texcoords[tcCounter + 5] = (float)z/(mapZ - 1);
mesh.texcoords[tcCounter + 6] = mesh.texcoords[tcCounter + 4];
mesh.texcoords[tcCounter + 7] = mesh.texcoords[tcCounter + 5];
@@ -687,13 +688,12 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
mesh.texcoords[tcCounter + 8] = mesh.texcoords[tcCounter + 2];
mesh.texcoords[tcCounter + 9] = mesh.texcoords[tcCounter + 3];
- mesh.texcoords[tcCounter + 10] = (float)(x+1) / (mapX-1);
- mesh.texcoords[tcCounter + 11] = (float)(z+1) / (mapZ-1);
+ mesh.texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1);
+ mesh.texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1);
tcCounter += 12; // 6 texcoords, 12 floats
// Fill normals array with data
//--------------------------------------------------------------
- // NOTE: Current Model implementation doe not use normals!
for (int i = 0; i < 18; i += 3)
{
mesh.normals[nCounter + i] = 0.0f;
@@ -704,12 +704,11 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
// TODO: Calculate normals in an efficient way
nCounter += 18; // 6 vertex, 18 floats
-
trisCounter += 2;
}
}
- free(heightmapPixels);
+ free(pixels);
// Fill color data
// NOTE: Not used any more... just one plain color defined at DrawModel()
@@ -1149,14 +1148,14 @@ void DrawModel(Model model, Vector3 position, float scale, Color tint)
Vector3 vScale = { scale, scale, scale };
Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f };
- DrawModelEx(model, position, 0.0f, rotationAxis, vScale, tint);
+ DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
}
// Draw a model with extended parameters
-void DrawModelEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint)
+void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
{
// NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel()
- rlglDrawModel(model, position, rotationAngle, rotationAxis, scale, tint, false);
+ rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, false);
}
// Draw a model wires (with texture if set)
@@ -1165,14 +1164,14 @@ void DrawModelWires(Model model, Vector3 position, float scale, Color color)
Vector3 vScale = { scale, scale, scale };
Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f };
- rlglDrawModel(model, position, 0.0f, rotationAxis, vScale, color, true);
+ rlglDrawModel(model, position, rotationAxis, 0.0f, vScale, color, true);
}
// Draw a model wires (with texture if set) with extended parameters
-void DrawModelWiresEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint)
+void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
{
// NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel()
- rlglDrawModel(model, position, rotationAngle, rotationAxis, scale, tint, true);
+ rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, true);
}
// Draw a billboard
@@ -1275,6 +1274,20 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec
rlDisableTexture();
}
+// Draw a bounding box with wires
+void DrawBoundingBox(BoundingBox box)
+{
+ Vector3 size;
+
+ size.x = fabsf(box.max.x - box.min.x);
+ size.y = fabsf(box.max.y - box.min.y);
+ size.z = fabsf(box.max.z - box.min.z);
+
+ Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
+
+ DrawCubeWires(center, size.x, size.y, size.z, GREEN);
+}
+
// Detect collision between two spheres
bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB)
{
@@ -1401,10 +1414,8 @@ bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox)
return collision;
}
-// TODO: Useful function to check collision area?
-//BoundingBox GetCollisionArea(BoundingBox box1, BoundingBox box2)
-
// Calculate mesh bounding box limits
+// NOTE: minVertex and maxVertex should be transformed by model transform matrix (position, scale, rotate)
BoundingBox CalculateBoundingBox(Mesh mesh)
{
// Get min and max vertex to construct bounds (AABB)
@@ -1413,15 +1424,10 @@ BoundingBox CalculateBoundingBox(Mesh mesh)
for (int i = 1; i < mesh.vertexCount; i++)
{
- // TODO: Compare min and max with previous vertex
- //minVertex = Vector3.Min(minVertex, mesh.vertices[i]);
- //maxVertex = Vector3.Max(maxVertex, mesh.vertices[i]);
+ minVertex = VectorMin(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
+ maxVertex = VectorMax(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
}
-
- // NOTE: For OBB, transform mesh by model transform matrix
- //minVertex = VectorTransform(meshMin, mesh.transform);
- //maxVertex = VectorTransform(meshMax, mesh.transform);
-
+
// Create the bounding box
BoundingBox box;
box.min = minVertex;
@@ -1681,12 +1687,6 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
// Module specific Functions Definition
//----------------------------------------------------------------------------------
-// Get current vertex y altitude (proportional to pixel colors in grayscale)
-static float GetHeightValue(Color pixel)
-{
- return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3);
-}
-
// Load OBJ mesh data
static Mesh LoadOBJ(const char *fileName)
{
diff --git a/src/physac.c b/src/physac.c
index 891f0123..4c50dd41 100644
--- a/src/physac.c
+++ b/src/physac.c
@@ -30,13 +30,12 @@
#endif
#include <math.h>
-#include <stdio.h>
+#include <stdlib.h> // Required for: malloc(), free()
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
-#define MAX_ELEMENTS 1024 // Stored rigidbodies and colliders array length
-#define DECIMAL_FIX 0.26f // Decimal margin for collision checks (avoid rigidbodies shake)
+#define DECIMAL_FIX 0.26f // Decimal margin for collision checks (avoid rigidbodies shake)
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -46,10 +45,13 @@
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
-static Physics physics;
-static Collider colliders[MAX_ELEMENTS];
-static Rigidbody rigidbodies[MAX_ELEMENTS];
-static bool collisionChecker = false;
+static Collider *colliders; // Colliders array, dynamically allocated at runtime
+static Rigidbody *rigidbodies; // Rigitbody array, dynamically allocated at runtime
+static bool collisionChecker;
+
+static int maxElements; // Max physic elements to compute
+static bool enabled; // Physics enabled? (true by default)
+static Vector2 gravity; // Gravity value used for physic calculations
//----------------------------------------------------------------------------------
// Module specific Functions Declarations
@@ -61,30 +63,39 @@ static void Vector2Normalize(Vector2 *vector);
//----------------------------------------------------------------------------------
// Module Functions Definitions
//----------------------------------------------------------------------------------
-void InitPhysics(void)
-{
- for (int i = 0; i < MAX_ELEMENTS; i++)
+void InitPhysics(int maxPhysicElements)
+{
+ maxElements = maxPhysicElements;
+
+ colliders = (Collider *)malloc(maxElements*sizeof(Collider));
+ rigidbodies = (Rigidbody *)malloc(maxElements*sizeof(Rigidbody));
+
+ for (int i = 0; i < maxElements; i++)
{
+ colliders[i].enabled = false;
+ colliders[i].bounds = (Rectangle){ 0, 0, 0, 0 };
+ colliders[i].radius = 0;
+
rigidbodies[i].enabled = false;
rigidbodies[i].mass = 0.0f;
- rigidbodies[i].velocity = (Vector2){0, 0};
- rigidbodies[i].acceleration = (Vector2){0, 0};
+ rigidbodies[i].velocity = (Vector2){ 0.0f, 0.0f };
+ rigidbodies[i].acceleration = (Vector2){ 0.0f, 0.0f };
rigidbodies[i].isGrounded = false;
rigidbodies[i].isContact = false;
rigidbodies[i].friction = 0.0f;
-
- colliders[i].enabled = false;
- colliders[i].bounds = (Rectangle){0, 0, 0, 0};
- colliders[i].radius = 0;
}
+
+ collisionChecker = false;
+ enabled = true;
+
+ // NOTE: To get better results, gravity needs to be 1:10 from original parameter
+ gravity = (Vector2){ 0.0f, -9.81f/10.0f }; // By default, standard gravity
}
-void SetPhysics(Physics settings)
+void UnloadPhysics()
{
- physics = settings;
-
- // To get good results, gravity needs to be 1:10 from original parameter
- physics.gravity = (Vector2){physics.gravity.x / 10, physics.gravity.y / 10};
+ free(colliders);
+ free(rigidbodies);
}
void AddCollider(int index, Collider collider)
@@ -159,8 +170,8 @@ void ApplyPhysics(int index, Vector2 *position)
}
// Apply gravity
- rigidbodies[index].velocity.y += physics.gravity.y;
- rigidbodies[index].velocity.x += physics.gravity.x;
+ rigidbodies[index].velocity.y += gravity.y;
+ rigidbodies[index].velocity.x += gravity.x;
// Apply acceleration
rigidbodies[index].velocity.y += rigidbodies[index].acceleration.y;
@@ -177,7 +188,7 @@ void ApplyPhysics(int index, Vector2 *position)
// Check collision with other colliders
collisionChecker = false;
rigidbodies[index].isContact = false;
- for (int j = 0; j < MAX_ELEMENTS; j++)
+ for (int j = 0; j < maxElements; j++)
{
if (index != j)
{
@@ -269,7 +280,7 @@ void AddRigidbodyForce(int index, Vector2 force)
void AddForceAtPosition(Vector2 position, float intensity, float radius)
{
- for(int i = 0; i < MAX_ELEMENTS; i++)
+ for(int i = 0; i < maxElements; i++)
{
if(rigidbodies[i].enabled)
{
diff --git a/src/physac.h b/src/physac.h
index 12209987..9e1b0b88 100644
--- a/src/physac.h
+++ b/src/physac.h
@@ -35,13 +35,6 @@
// Collider types
typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType;
-// Physics struct
-typedef struct Physics {
- bool enabled;
- bool debug; // Should be used by programmer for testing purposes
- Vector2 gravity;
-} Physics;
-
// Transform struct
typedef struct Transform {
Vector2 position;
@@ -77,8 +70,8 @@ extern "C" { // Prevents name mangling of functions
//----------------------------------------------------------------------------------
// Module Functions Declarations
//----------------------------------------------------------------------------------
-void InitPhysics(void); // Initialize all internal physics values
-void SetPhysics(Physics settings); // Set physics settings values using Physics data type to overwrite internal physics settings
+void InitPhysics(int maxPhysicElements); // Initialize all internal physics values
+void UnloadPhysics(); // Unload physic elements arrays
void AddRigidbody(int index, Rigidbody rigidbody); // Initialize a new rigidbody with parameters to internal index slot
void AddCollider(int index, Collider collider); // Initialize a new Collider with parameters to internal index slot
diff --git a/src/raygui.c b/src/raygui.c
index 2c68c96f..60df2121 100644
--- a/src/raygui.c
+++ b/src/raygui.c
@@ -2,7 +2,8 @@
*
* raygui - raylib IMGUI system (Immedite Mode GUI)
*
-* Copyright (c) 2015 Kevin Gato, Daniel Nicolás, Sergio Martinez and Ramon Santamaria
+* Initial design by Kevin Gato and Daniel Nicolás
+* Reviewed by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -856,10 +857,6 @@ char *GuiTextBox(Rectangle bounds, char *text)
return text;
}
-// TODO: GuiBox?
-// TODO: GuiWindow?
-// TODO: GuiPanel?
-
// Save current GUI style into a text file
void SaveGuiStyle(const char *fileName)
{
@@ -873,12 +870,14 @@ void SaveGuiStyle(const char *fileName)
// Load GUI style from a text file
void LoadGuiStyle(const char *fileName)
{
+ #define MAX_STYLE_PROPERTIES 128
+
typedef struct {
char id[64];
int value;
} StyleProperty;
- StyleProperty *styleProp = (StyleProperty *)malloc(128*sizeof(StyleProperty));;
+ StyleProperty *styleProp = (StyleProperty *)malloc(MAX_STYLE_PROPERTIES*sizeof(StyleProperty));;
int counter = 0;
FILE *styleFile = fopen(fileName, "rt");
diff --git a/src/raylib.h b/src/raylib.h
index bebf4bc5..c598ec30 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -7,10 +7,10 @@
* Features:
* Library written in plain C code (C99)
* Uses C# PascalCase/camelCase notation
-* Hardware accelerated with OpenGL (1.1, 3.3+ or ES2)
+* Hardware accelerated with OpenGL (1.1, 3.3 or ES2)
* Unique OpenGL abstraction layer [rlgl]
-* Powerful fonts module with SpriteFonts support
-* Multiple textures support, including DDS and mipmaps generation
+* Powerful fonts module with SpriteFonts support (including AngelCode fonts and TTF)
+* Multiple textures support, including compressed formats and mipmaps generation
* Basic 3d support for Shapes, Models, Heightmaps and Billboards
* Powerful math module for Vector and Matrix operations [raymath]
* Audio loading and playing with streaming support (WAV and OGG)
@@ -18,20 +18,21 @@
*
* Used external libs:
* GLFW3 (www.glfw.org) for window/context management and input
-* GLEW for OpenGL extensions loading (3.3+ and ES2)
+* GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP)
* stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC)
* stb_image_write (Sean Barret) for image writting (PNG)
* stb_vorbis (Sean Barret) for ogg audio loading
+* stb_truetype (Sean Barret) for ttf fonts loading
* OpenAL Soft for audio device/context management
* tinfl for data decompression (DEFLATE algorithm)
*
* Some design decisions:
-* 32bit Colors - All defined color are always RGBA
-* SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures
+* 32bit Colors - All defined color are always RGBA (struct Color is 4 byte)
* One custom default font is loaded automatically when InitWindow()
-* If using OpenGL 3.3+ or ES2, one default shader is loaded automatically (internally defined)
+* If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads
+* If using OpenGL 3.3 or ES2, two default shaders are loaded automatically (internally defined)
*
-* -- LICENSE (raylib v1.2, September 2014) --
+* -- LICENSE --
*
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software:
@@ -80,8 +81,8 @@
#define PI 3.14159265358979323846
#endif
-#define DEG2RAD (PI / 180.0f)
-#define RAD2DEG (180.0f / PI)
+#define DEG2RAD (PI/180.0f)
+#define RAD2DEG (180.0f/PI)
// raylib Config Flags
#define FLAG_FULLSCREEN_MODE 1
@@ -110,6 +111,8 @@
#define KEY_F8 297
#define KEY_F9 298
#define KEY_F10 299
+#define KEY_F11 300
+#define KEY_F12 301
#define KEY_LEFT_SHIFT 340
#define KEY_LEFT_CONTROL 341
#define KEY_LEFT_ALT 342
@@ -117,7 +120,7 @@
#define KEY_RIGHT_CONTROL 345
#define KEY_RIGHT_ALT 346
-// Keyboard Alhpa Numeric Keys
+// Keyboard Alpha Numeric Keys
#define KEY_ZERO 48
#define KEY_ONE 49
#define KEY_TWO 50
@@ -165,6 +168,9 @@
#define MOUSE_MIDDLE_BUTTON 2
#endif
+// Touch points registered
+#define MAX_TOUCH_POINTS 2
+
// Gamepad Number
#define GAMEPAD_PLAYER1 0
#define GAMEPAD_PLAYER2 1
@@ -347,9 +353,6 @@ typedef struct Shader {
// Uniforms
int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader)
-
- int modelLoc; // Model transformation matrix uniform location point (vertex shader)
- int viewLoc; // View transformation matrix uniform location point (vertex shader)
int tintColorLoc; // Color uniform location point (fragment shader)
int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader)
@@ -357,12 +360,31 @@ typedef struct Shader {
int mapSpecularLoc; // Specular map texture uniform location point (fragment shader)
} Shader;
+// Material type
+// TODO: Redesign material-shaders-textures system
+typedef struct Material {
+ //Shader shader;
+
+ //Texture2D texDiffuse; // Diffuse texture
+ //Texture2D texNormal; // Normal texture
+ //Texture2D texSpecular; // Specular texture
+
+ Color colDiffuse;
+ Color colAmbient;
+ Color colSpecular;
+
+ float glossiness;
+ float normalDepth;
+} Material;
+
// 3d Model type
+// TODO: Replace shader/testure by material
typedef struct Model {
Mesh mesh;
Matrix transform;
Texture2D texture; // Only for OpenGL 1.1, on newer versions this should be in the shader
Shader shader;
+ //Material material;
} Model;
// Ray type (useful for raycast)
@@ -386,26 +408,6 @@ typedef struct Wave {
short channels;
} Wave;
-// Light type
-typedef struct Light {
- Vector3 position;
- Vector3 direction;
- float intensity;
- float specIntensity;
- Color diffuse;
- Color ambient;
- Color specular;
-} Light;
-
-// Material type
-typedef struct Material {
- Color diffuse;
- Color ambient;
- Color specular;
- float glossiness;
- float normalDepth;
-} Material;
-
// Texture formats
// NOTE: Support depends on OpenGL version and platform
typedef enum {
@@ -435,28 +437,29 @@ typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
// Gestures type
// NOTE: It could be used as flags to enable only some gestures
typedef enum {
- GESTURE_NONE = 1,
- GESTURE_TAP = 2,
- GESTURE_DOUBLETAP = 4,
- GESTURE_HOLD = 8,
- GESTURE_DRAG = 16,
- GESTURE_SWIPE_RIGHT = 32,
- GESTURE_SWIPE_LEFT = 64,
- GESTURE_SWIPE_UP = 128,
- GESTURE_SWIPE_DOWN = 256,
- GESTURE_PINCH_IN = 512,
- GESTURE_PINCH_OUT = 1024
+ GESTURE_NONE = 0,
+ GESTURE_TAP = 1,
+ GESTURE_DOUBLETAP = 2,
+ GESTURE_HOLD = 4,
+ GESTURE_DRAG = 8,
+ GESTURE_SWIPE_RIGHT = 16,
+ GESTURE_SWIPE_LEFT = 32,
+ GESTURE_SWIPE_UP = 64,
+ GESTURE_SWIPE_DOWN = 128,
+ GESTURE_PINCH_IN = 256,
+ GESTURE_PINCH_OUT = 512
} Gestures;
+// Touch action (fingers or mouse)
typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction;
// Gesture events
-// NOTE: MAX_TOUCH_POINTS fixed to 4
+// NOTE: MAX_TOUCH_POINTS fixed to 2
typedef struct {
int touchAction;
int pointCount;
- int pointerId[4];
- Vector2 position[4];
+ int pointerId[MAX_TOUCH_POINTS];
+ Vector2 position[MAX_TOUCH_POINTS];
} GestureEvent;
// Camera system modes
@@ -465,13 +468,6 @@ typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERS
// Collider types
typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType;
-// Physics struct
-typedef struct Physics {
- bool enabled;
- bool debug; // Should be used by programmer for testing purposes
- Vector2 gravity;
-} Physics;
-
// Transform struct
typedef struct Transform {
Vector2 position;
@@ -534,11 +530,12 @@ void BeginDrawing(void); // Setup drawing can
void BeginDrawingEx(int blendMode, Shader shader, Matrix transform); // Setup drawing canvas with extended parameters
void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering)
-void Begin3dMode(Camera cam); // Initializes 3D mode for drawing (Camera setup)
+void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup)
void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode
Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position
Vector2 WorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position
+Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix)
void SetTargetFPS(int fps); // Set target FPS (maximum)
float GetFPS(void); // Returns current FPS
@@ -585,10 +582,10 @@ int GetMouseWheelMove(void); // Returns mouse wheel m
void ShowCursor(void); // Shows cursor
void HideCursor(void); // Hides cursor
+void EnableCursor(void); // Enables cursor
+void DisableCursor(void); // Disables cursor
bool IsCursorHidden(void); // Returns true if cursor is not visible
-#endif
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available
Vector2 GetGamepadMovement(int gamepad); // Return axis movement vector for a gamepad
bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once
@@ -597,30 +594,31 @@ bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad b
bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed
#endif
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
-int GetTouchX(void); // Returns touch position X (relative to screen size)
-int GetTouchY(void); // Returns touch position Y (relative to screen size)
-Vector2 GetTouchPosition(void); // Returns touch position XY (relative to screen size)
+int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size)
+int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size)
+Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size)
+
+#if defined(PLATFORM_ANDROID)
bool IsButtonPressed(int button); // Detect if an android physic button has been pressed
bool IsButtonDown(int button); // Detect if an android physic button is being pressed
bool IsButtonReleased(int button); // Detect if an android physic button has been released
+#endif
//------------------------------------------------------------------------------------
// Gestures and Touch Handling Functions (Module: gestures)
//------------------------------------------------------------------------------------
+void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
void UpdateGestures(void); // Update gestures detected (must be called every frame)
bool IsGestureDetected(void); // Check if a gesture have been detected
int GetGestureType(void); // Get latest detected gesture
void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags
-void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
+int GetTouchPointsCount(void); // Get touch points count
-float GetGestureDragIntensity(void); // Get gesture drag intensity
-float GetGestureDragAngle(void); // Get gesture drag angle
+float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds
Vector2 GetGestureDragVector(void); // Get gesture drag vector
-int GetGestureHoldDuration(void); // Get gesture hold time in frames
-float GetGesturePinchDelta(void); // Get gesture pinch delta
+float GetGestureDragAngle(void); // Get gesture drag angle
+Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
float GetGesturePinchAngle(void); // Get gesture pinch angle
-#endif
//------------------------------------------------------------------------------------
// Camera System Functions (Module: camera)
@@ -699,7 +697,7 @@ void ImageFlipVertical(Image *image);
void ImageFlipHorizontal(Image *image); // Flip image horizontally
void ImageColorTint(Image *image, Color color); // Modify image color: tint
void ImageColorInvert(Image *image); // Modify image color: invert
-void ImageColorGrayscale(Image *image); // Modify bimage color: grayscale
+void ImageColorGrayscale(Image *image); // Modify image color: grayscale
void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100)
void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255)
void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture
@@ -754,19 +752,21 @@ void DrawGizmo(Vector3 position);
Model LoadModel(const char *fileName); // Load a 3d model (.OBJ)
Model LoadModelEx(Mesh data); // Load a 3d model (from vertex data)
//Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource)
-Model LoadHeightmap(Image heightmap, float maxHeight); // Load a heightmap image as a 3d model
+Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model
Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based)
void UnloadModel(Model model); // Unload 3d model from memory
void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model
void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set)
-void DrawModelEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint); // Draw a model with extended parameters
+void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters
void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set)
-void DrawModelWiresEx(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
+void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
+void DrawBoundingBox(BoundingBox box); // Draw bounding box (wires)
void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture
void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec
+BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits
bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres
bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, Vector3 maxBBox2); // Detect collision between two boxes
bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere
@@ -775,7 +775,6 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi
bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox); // Detect collision between ray and box
Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius); // Detect collision of player radius with cubicmap
// NOTE: Return the normal vector of the impacted surface
-
//------------------------------------------------------------------------------------
// Shaders System Functions (Module: rlgl)
// NOTE: This functions are useless when using OpenGL 1.1
@@ -792,6 +791,7 @@ bool IsPosproShaderEnabled(void); // Check if
int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)
void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int)
+void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
void SetShaderMapDiffuse(Shader *shader, Texture2D texture); // Default diffuse shader map texture assignment
void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D texture); // Normal map texture shader assignment
void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture); // Specular map texture shader assignment
@@ -800,10 +800,10 @@ void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textur
void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied)
//----------------------------------------------------------------------------------
-// Physics System Functions (engine-module: physics)
+// Physics System Functions (engine-module: physac)
//----------------------------------------------------------------------------------
-void InitPhysics(void); // Initialize all internal physics values
-void SetPhysics(Physics settings); // Set physics settings values using Physics data type to overwrite internal physics settings
+void InitPhysics(int maxPhysicElements); // Initialize all internal physics values
+void UnloadPhysics(); // Unload physic elements arrays
void AddRigidbody(int index, Rigidbody rigidbody); // Initialize a new rigidbody with parameters to internal index slot
void AddCollider(int index, Collider collider); // Initialize a new Collider with parameters to internal index slot
diff --git a/src/raymath.h b/src/raymath.h
index f5448504..35cee39f 100644
--- a/src/raymath.h
+++ b/src/raymath.h
@@ -126,6 +126,8 @@ RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount); // Calculate lin
RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal); // Calculate reflected vector to normal
RMDEF void VectorTransform(Vector3 *v, Matrix mat); // Transforms a Vector3 by a given Matrix
RMDEF Vector3 VectorZero(void); // Return a Vector3 init to zero
+RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2); // Return min value for each pair of components
+RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2); // Return max value for each pair of components
//------------------------------------------------------------------------------------
// Functions Declaration to work with Matrix
@@ -139,7 +141,7 @@ RMDEF Matrix MatrixIdentity(void); // Returns identit
RMDEF Matrix MatrixAdd(Matrix left, Matrix right); // Add two matrices
RMDEF Matrix MatrixSubstract(Matrix left, Matrix right); // Substract two matrices (left - right)
RMDEF Matrix MatrixTranslate(float x, float y, float z); // Returns translation matrix
-RMDEF Matrix MatrixRotate(float angle, Vector3 axis); // Returns rotation matrix for an angle around an specified axis (angle in radians)
+RMDEF Matrix MatrixRotate(Vector3 axis, float angle); // Returns rotation matrix for an angle around an specified axis (angle in radians)
RMDEF Matrix MatrixRotateX(float angle); // Returns x-rotation matrix (angle in radians)
RMDEF Matrix MatrixRotateY(float angle); // Returns y-rotation matrix (angle in radians)
RMDEF Matrix MatrixRotateZ(float angle); // Returns z-rotation matrix (angle in radians)
@@ -160,8 +162,8 @@ RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2); // Calcula
RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float slerp); // Calculates spherical linear interpolation between two quaternions
RMDEF Quaternion QuaternionFromMatrix(Matrix matrix); // Returns a quaternion for a given rotation matrix
RMDEF Matrix QuaternionToMatrix(Quaternion q); // Returns a matrix for a given quaternion
-RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis); // Returns rotation quaternion for an angle and axis
-RMDEF void QuaternionToAxisAngle(Quaternion q, float *outAngle, Vector3 *outAxis); // Returns the rotation angle and axis for a given quaternion
+RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle); // Returns rotation quaternion for an angle and axis
+RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle); // Returns the rotation angle and axis for a given quaternion
RMDEF void QuaternionTransform(Quaternion *q, Matrix mat); // Transform a quaternion given a transformation matrix
#ifdef __cplusplus
@@ -361,6 +363,30 @@ RMDEF Vector3 VectorZero(void)
return zero;
}
+// Return min value for each pair of components
+RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2)
+{
+ Vector3 result;
+
+ result.x = fminf(vec1.x, vec2.x);
+ result.y = fminf(vec1.y, vec2.y);
+ result.z = fminf(vec1.z, vec2.z);
+
+ return result;
+}
+
+// Return max value for each pair of components
+RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2)
+{
+ Vector3 result;
+
+ result.x = fmaxf(vec1.x, vec2.x);
+ result.y = fmaxf(vec1.y, vec2.y);
+ result.z = fmaxf(vec1.z, vec2.z);
+
+ return result;
+}
+
//----------------------------------------------------------------------------------
// Module Functions Definition - Matrix math
//----------------------------------------------------------------------------------
@@ -561,7 +587,7 @@ RMDEF Matrix MatrixTranslate(float x, float y, float z)
// Create rotation matrix from axis and angle
// NOTE: Angle should be provided in radians
-RMDEF Matrix MatrixRotate(float angle, Vector3 axis)
+RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
{
Matrix result;
@@ -579,9 +605,9 @@ RMDEF Matrix MatrixRotate(float angle, Vector3 axis)
z *= length;
}
- float s = sinf(angle);
- float c = cosf(angle);
- float t = 1.0f - c;
+ float sinres = sinf(angle);
+ float cosres = cosf(angle);
+ float t = 1.0f - cosres;
// Cache some matrix values (speed optimization)
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
@@ -589,9 +615,9 @@ RMDEF Matrix MatrixRotate(float angle, Vector3 axis)
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
// Construct the elements of the rotation matrix
- float b00 = x*x*t + c, b01 = y*x*t + z*s, b02 = z*x*t - y*s;
- float b10 = x*y*t - z*s, b11 = y*y*t + c, b12 = z*y*t + x*s;
- float b20 = x*z*t + y*s, b21 = y*z*t - x*s, b22 = z*z*t + c;
+ float b00 = x*x*t + cosres, b01 = y*x*t + z*sinres, b02 = z*x*t - y*sinres;
+ float b10 = x*y*t - z*sinres, b11 = y*y*t + cosres, b12 = z*y*t + x*sinres;
+ float b20 = x*z*t + y*sinres, b21 = y*z*t - x*sinres, b22 = z*z*t + cosres;
// Perform rotation-specific matrix multiplication
result.m0 = a00*b00 + a10*b01 + a20*b02;
@@ -662,8 +688,8 @@ RMDEF Matrix MatrixRotateX(float angle)
{
Matrix result = MatrixIdentity();
- float cosres = (float)cos(angle);
- float sinres = (float)sin(angle);
+ float cosres = cosf(angle);
+ float sinres = sinf(angle);
result.m5 = cosres;
result.m6 = -sinres;
@@ -694,8 +720,8 @@ RMDEF Matrix MatrixRotateZ(float angle)
{
Matrix result = MatrixIdentity();
- float cosres = (float)cos(angle);
- float sinres = (float)sin(angle);
+ float cosres = cosf(angle);
+ float sinres = sinf(angle);
result.m0 = cosres;
result.m1 = -sinres;
@@ -920,8 +946,8 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
}
else
{
- float ratioA = sin((1 - amount)*halfTheta)/sinHalfTheta;
- float ratioB = sin(amount*halfTheta)/sinHalfTheta;
+ float ratioA = sinf((1 - amount)*halfTheta)/sinHalfTheta;
+ float ratioB = sinf(amount*halfTheta)/sinHalfTheta;
result.x = (q1.x*ratioA + q2.x*ratioB);
result.y = (q1.y*ratioA + q2.y*ratioB);
@@ -1034,7 +1060,7 @@ RMDEF Matrix QuaternionToMatrix(Quaternion q)
// Returns rotation quaternion for an angle and axis
// NOTE: angle must be provided in radians
-RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis)
+RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
{
Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
@@ -1043,11 +1069,14 @@ RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis)
angle *= 0.5f;
VectorNormalize(&axis);
+
+ float sinres = sinf(angle);
+ float cosres = cosf(angle);
- result.x = axis.x*(float)sin(angle);
- result.y = axis.y*(float)sin(angle);
- result.z = axis.z*(float)sin(angle);
- result.w = (float)cos(angle);
+ result.x = axis.x*sinres;
+ result.y = axis.y*sinres;
+ result.z = axis.z*sinres;
+ result.w = cosres;
QuaternionNormalize(&result);
@@ -1055,7 +1084,7 @@ RMDEF Quaternion QuaternionFromAxisAngle(float angle, Vector3 axis)
}
// Returns the rotation angle and axis for a given quaternion
-RMDEF void QuaternionToAxisAngle(Quaternion q, float *outAngle, Vector3 *outAxis)
+RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
{
if (fabs(q.w) > 1.0f) QuaternionNormalize(&q);
diff --git a/src/resources b/src/resources
index b41637ff..6fc578e0 100644
--- a/src/resources
+++ b/src/resources
Binary files differ
diff --git a/src/rlgl.c b/src/rlgl.c
index ec909385..8ea7d0f2 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -171,7 +171,7 @@ typedef struct {
typedef struct {
GLuint textureId;
int vertexCount;
- // TODO: DrawState state -> Blending mode, shader
+ // TODO: Store draw state -> blending mode, shader
} DrawCall;
// pixel type (same as Color type)
@@ -411,7 +411,7 @@ void rlRotatef(float angleDeg, float x, float y, float z)
Vector3 axis = (Vector3){ x, y, z };
VectorNormalize(&axis);
- matRotation = MatrixRotate(angleDeg*DEG2RAD, axis);
+ matRotation = MatrixRotate(axis, angleDeg*DEG2RAD);
MatrixTranspose(&matRotation);
@@ -981,7 +981,7 @@ void rlglInit(void)
else TraceLog(WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported");
if (npotSupported) TraceLog(INFO, "[EXTENSION] NPOT textures extension detected, full NPOT textures supported");
- else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, NPOT textures support is limited (no-mipmaps, no-repeat)");
+ else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)");
#endif
if (texCompDXTSupported) TraceLog(INFO, "[EXTENSION] DXT compressed textures supported");
@@ -1406,13 +1406,13 @@ void rlglDrawPostpro(void)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
- rlglDrawModel(postproQuad, (Vector3){0,0,0}, 0.0f, (Vector3){0,0,0}, (Vector3){1.0f, 1.0f, 1.0f}, (Color){ 255, 255, 255, 255 }, false);
+ rlglDrawModel(postproQuad, (Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.0f, (Vector3){1.0f, 1.0f, 1.0f}, (Color){ 255, 255, 255, 255 }, false);
#endif
}
// Draw a 3d model
// NOTE: Model transform can come within model struct
-void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires)
+void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires)
{
#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
@@ -1461,10 +1461,10 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r
// Calculate transformation matrix from function parameters
// Get transform matrix (rotation -> scale -> translation)
- Matrix matRotation = MatrixRotate(rotationAngle*DEG2RAD, rotationAxis);
+ Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
- Matrix matTransform = MatrixMultiply(MatrixMultiply(matRotation, matScale), matTranslation);
+ Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
// Combine model internal transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates
@@ -1475,11 +1475,7 @@ void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 r
// Calculate model-view-projection matrix (MVP)
Matrix matMVP = MatrixMultiply(matModelView, matProjection); // Transform to screen-space coordinates
- // NOTE: Drawing in OpenGL 3.3+, matrices are passed to shader
- // TODO: Reduce number of matrices passed to shaders, use only matMVP
- glUniformMatrix4fv(model.shader.modelLoc, 1, false, MatrixToFloat(matModel));
- glUniformMatrix4fv(model.shader.viewLoc, 1, false, MatrixToFloat(matView));
-
+ // Send combined model-view-projection matrix to shader
glUniformMatrix4fv(model.shader.mvpLoc, 1, false, MatrixToFloat(matMVP));
// Apply color tinting to model
@@ -1615,7 +1611,6 @@ void rlglInitGraphics(int offsetX, int offsetY, int width, int height)
}
// Get world coordinates from screen coordinates
-// TODO: It doesn't work! It drives me crazy!
// NOTE: Using global variables: screenWidth, screenHeight
Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view)
{
@@ -1900,7 +1895,7 @@ void rlglGenerateMipmaps(Texture2D texture)
int mipmapCount = GenerateMipmaps(data, texture.width, texture.height);
// TODO: Adjust mipmap size depending on texture format!
- int size = texture.width*texture.height*4;
+ int size = texture.width*texture.height*4; // RGBA 32bit only
int offset = size;
int mipWidth = texture.width/2;
@@ -2201,9 +2196,6 @@ Shader LoadShader(char *vsFileName, char *fsFileName)
// Get handles to GLSL uniform locations (vertex shader)
shader.mvpLoc = glGetUniformLocation(shader.id, "mvpMatrix");
-
- shader.modelLoc = glGetUniformLocation(shader.id, "modelMatrix");
- shader.viewLoc = glGetUniformLocation(shader.id, "viewMatrix");
// Get handles to GLSL uniform locations (fragment shader)
shader.tintColorLoc = glGetUniformLocation(shader.id, "fragTintColor");
@@ -2503,6 +2495,18 @@ void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size)
#endif
}
+// Set shader uniform value (matrix 4x4)
+void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+ glUseProgram(shader.id);
+
+ glUniformMatrix4fv(uniformLoc, 1, false, MatrixToFloat(mat));
+
+ glUseProgram(0);
+#endif
+}
+
// Default diffuse shader map texture assignment
void SetShaderMapDiffuse(Shader *shader, Texture2D texture)
{
@@ -2741,9 +2745,6 @@ static Shader LoadDefaultShader(void)
// Get handles to GLSL uniform locations (vertex shader)
shader.mvpLoc = glGetUniformLocation(shader.id, "mvpMatrix");
-
- shader.modelLoc = glGetUniformLocation(shader.id, "modelMatrix");
- shader.viewLoc = glGetUniformLocation(shader.id, "viewMatrix");
// Get handles to GLSL uniform locations (fragment shader)
shader.tintColorLoc = -1;
@@ -2822,9 +2823,6 @@ static Shader LoadSimpleShader(void)
// Get handles to GLSL uniform locations (vertex shader)
shader.mvpLoc = glGetUniformLocation(shader.id, "mvpMatrix");
-
- shader.modelLoc = glGetUniformLocation(shader.id, "modelMatrix");
- shader.viewLoc = glGetUniformLocation(shader.id, "viewMatrix");
// Get handles to GLSL uniform locations (fragment shader)
shader.tintColorLoc = glGetUniformLocation(shader.id, "fragTintColor");
diff --git a/src/rlgl.h b/src/rlgl.h
index 76cae987..9e0aaaaa 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -167,9 +167,6 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
// Uniforms
int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader)
-
- int modelLoc; // Model transformation matrix uniform location point (vertex shader)
- int viewLoc; // View transformation matrix uniform location point (vertex shader)
int tintColorLoc; // Color uniform location point (fragment shader)
int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader)
@@ -265,7 +262,7 @@ void rlglInitPostpro(void); // Initialize postprocessing sys
void rlglDrawPostpro(void); // Draw with postprocessing shader
Model rlglLoadModel(Mesh mesh); // Upload vertex data into GPU and provided VAO/VBO ids
-void rlglDrawModel(Model model, Vector3 position, float rotationAngle, Vector3 rotationAxis, Vector3 scale, Color color, bool wires);
+void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires);
Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
diff --git a/src/shapes.c b/src/shapes.c
index a4761536..65e3621b 100644
--- a/src/shapes.c
+++ b/src/shapes.c
@@ -397,8 +397,8 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
int recCenterX = rec.x + rec.width/2;
int recCenterY = rec.y + rec.height/2;
- float dx = abs(center.x - recCenterX);
- float dy = abs(center.y - recCenterY);
+ float dx = fabs(center.x - recCenterX);
+ float dy = fabs(center.y - recCenterY);
if (dx > (rec.width/2 + radius)) { return false; }
if (dy > (rec.height/2 + radius)) { return false; }
@@ -412,6 +412,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
}
// Get collision rectangle for two rectangles collision
+// TODO: Depending on rec1 and rec2 order, it fails -> Review!
Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
{
Rectangle retRec = { 0, 0, 0, 0 };
diff --git a/src/text.c b/src/text.c
index 3755932d..e4c7bbf3 100644
--- a/src/text.c
+++ b/src/text.c
@@ -346,7 +346,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, int f
for(int i = 0; i < length; i++)
{
- // TODO: Right now we are supposing characters follow a continous order and start at FONT_FIRST_CHAR,
+ // TODO: Right now we are supposing characters that follow a continous order and start at FONT_FIRST_CHAR,
// this sytem can be improved to support any characters order and init value...
// An intermediate table could be created to link char values with predefined char position index in chars rectangle array
diff --git a/src/textures.c b/src/textures.c
index f03d2d9a..36819daf 100644
--- a/src/textures.c
+++ b/src/textures.c
@@ -712,7 +712,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
{
oldpixel = pixels[y*image->width + x];
- // TODO: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
+ // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
newpixel.r = oldpixel.r>>(8 - rBpp); // R bits
newpixel.g = oldpixel.g>>(8 - gBpp); // G bits
newpixel.b = oldpixel.b>>(8 - bBpp); // B bits
@@ -769,7 +769,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
}
// Convert image to POT (power-of-two)
-// NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5)
+// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
void ImageToPOT(Image *image, Color fillColor)
{
Color *pixels = GetImageData(*image); // Get pixels data
@@ -784,7 +784,7 @@ void ImageToPOT(Image *image, Color fillColor)
Color *pixelsPOT = NULL;
// Generate POT array from NPOT data
- pixelsPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color));
+ pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color));
for (int j = 0; j < potHeight; j++)
{
@@ -896,7 +896,9 @@ void ImageCrop(Image *image, Rectangle crop)
}
// Resize and image to new size
-// NOTE: Uses stb default scaling filter
+// NOTE: Uses stb default scaling filters (both bicubic):
+// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
+// STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL (high-quality Catmull-Rom)
void ImageResize(Image *image, int newWidth, int newHeight)
{
// Get data as Color pixels array to work with it