summaryrefslogtreecommitdiffhomepage
path: root/src/core.c
diff options
context:
space:
mode:
authorvictorfisac <[email protected]>2018-03-10 19:10:37 +0100
committervictorfisac <[email protected]>2018-03-10 19:10:37 +0100
commit8f1d6f38506ff6449866913c6d88b0f25ca2d8f4 (patch)
tree659719ef12dbdedd9a51c85af0e43ac327c84b40 /src/core.c
parentdd50348b4dffe59be03538bdbaf2a3d084426e1f (diff)
parentdf50eada531b54d6771eff81cbe140f9453d54d9 (diff)
downloadraylib-8f1d6f38506ff6449866913c6d88b0f25ca2d8f4.tar.gz
raylib-8f1d6f38506ff6449866913c6d88b0f25ca2d8f4.zip
Merge branch 'master' of github.com:raysan5/raylib into fork/master
Diffstat (limited to 'src/core.c')
-rw-r--r--src/core.c619
1 files changed, 481 insertions, 138 deletions
diff --git a/src/core.c b/src/core.c
index 78c0a7ef..f4fdf78b 100644
--- a/src/core.c
+++ b/src/core.c
@@ -3,17 +3,19 @@
* raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms
*
* PLATFORMS SUPPORTED:
-* - Windows (win32/Win64)
-* - Linux (tested on Ubuntu)
-* - OSX (Mac)
-* - Android (ARM or ARM64)
-* - Raspberry Pi (Raspbian)
-* - HTML5 (Chrome, Firefox)
+* - PLATFORM_DESKTOP: Windows (Win32, Win64)
+* - PLATFORM_DESKTOP: Linux (X11 desktop mode)
+* - PLATFORM_DESKTOP: FreeBSD (X11 desktop)
+* - PLATFORM_DESKTOP: OSX/macOS
+* - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64)
+* - PLATFORM_RPI: Raspberry Pi 0,1,2,3 (Raspbian)
+* - PLATFORM_WEB: HTML5 with asm.js (Chrome, Firefox)
+* - PLATFORM_UWP: Windows 10 App, Windows Phone, Xbox One
*
* CONFIGURATION:
*
* #define PLATFORM_DESKTOP
-* Windowing and input system configured for desktop platforms: Windows, Linux, OSX (managed by GLFW3 library)
+* Windowing and input system configured for desktop platforms: Windows, Linux, OSX, FreeBSD
* NOTE: Oculus Rift CV1 requires PLATFORM_DESKTOP for mirror rendering - View [rlgl] module to enable it
*
* #define PLATFORM_ANDROID
@@ -21,13 +23,17 @@
* NOTE: OpenGL ES 2.0 is required and graphic device is managed by EGL
*
* #define PLATFORM_RPI
-* Windowing and input system configured for Raspberry Pi (tested on Raspbian), graphic device is managed by EGL
-* and inputs are processed is raw mode, reading from /dev/input/
+* Windowing and input system configured for Raspberry Pi i native mode (no X.org required, tested on Raspbian),
+* graphic device is managed by EGL and inputs are processed is raw mode, reading from /dev/input/
*
* #define PLATFORM_WEB
* Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js
* using emscripten compiler. OpenGL ES 2.0 required for direct translation to WebGL equivalent code.
*
+* #define PLATFORM_UWP
+* Universal Windows Platform support, using OpenGL ES 2.0 through ANGLE on multiple Windows platforms,
+* including Windows 10 App, Windows Phone and Xbox One platforms.
+*
* #define SUPPORT_DEFAULT_FONT (default)
* Default font is loaded on window initialization to be available for the user to render simple text.
* NOTE: If enabled, uses external module functions to load default raylib font (module: text)
@@ -48,15 +54,15 @@
* Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
*
* DEPENDENCIES:
-* GLFW3 - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX)
-* raymath - 3D math functionality (Vector3, Matrix, Quaternion)
+* rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD)
+* raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion)
* camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person)
* gestures - Gestures system for touch-ready devices (or simulated from mouse inputs)
*
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
+* Copyright (c) 2014-2018 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.
@@ -87,6 +93,11 @@
#include "raylib.h"
+#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L
+ #undef _POSIX_C_SOURCE
+ #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
+#endif
+
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
#include "utils.h" // Required for: fopen() Android mapping
@@ -105,12 +116,8 @@
#endif
#if defined(SUPPORT_GIF_RECORDING)
- #define GIF_IMPLEMENTATION
- #include "external/gif.h" // Support GIF recording
-#endif
-
-#if defined(__linux__) || defined(PLATFORM_WEB)
- #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
+ #define RGIF_IMPLEMENTATION
+ #include "external/rgif.h" // Support GIF recording
#endif
#include <stdio.h> // Standard input / output lib
@@ -121,7 +128,7 @@
#include <string.h> // Required for: strrchr(), strcmp()
//#include <errno.h> // Macros for reporting and retrieving error conditions through error codes
-#ifdef _WIN32
+#if defined(_WIN32)
#include <direct.h> // Required for: _getch(), _chdir()
#define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir()
#define CHDIR _chdir
@@ -147,12 +154,11 @@
#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!
-
+
#if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32)
// NOTE: Those functions require linking with winmm library
- __stdcall unsigned int timeBeginPeriod(unsigned int uPeriod);
- __stdcall unsigned int timeEndPeriod(unsigned int uPeriod);
+ unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
+ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
#endif
#endif
@@ -183,6 +189,12 @@
#include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library
#endif
+#if defined(PLATFORM_UWP)
+ #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
+#endif
+
#if defined(PLATFORM_WEB)
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
@@ -222,16 +234,17 @@
//----------------------------------------------------------------------------------
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
static GLFWwindow *window; // Native window (graphic device)
-static bool windowMinimized = false;
#endif
+static bool windowReady = false; // Check if window has been initialized successfully
+static bool windowMinimized = false; // Check if window has been minimized
+
#if defined(PLATFORM_ANDROID)
static struct android_app *app; // Android activity
static struct android_poll_source *source; // Android events polling source
static int ident, events; // Android ALooper_pollAll() variables
static const char *internalDataPath; // Android internal data path to write data (/data/data/<package>/files)
-static bool windowReady = false; // Used to detect display initialization
static bool appEnabled = true; // Used to detec if app is active
static bool contextRebindRequired = false; // Used to know context rebind required
#endif
@@ -260,7 +273,7 @@ static pthread_t gamepadThreadId; // Gamepad reading thread id
static char gamepadName[64]; // Gamepad name holder
#endif
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
static EGLDisplay display; // Native display device (physical screen connection)
static EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
static EGLContext context; // Graphic context, mode in which drawing can be done
@@ -269,6 +282,10 @@ static uint64_t baseTime; // Base time measure for hi-res timer
static bool windowShouldClose = false; // Flag to set window for closing
#endif
+#if defined(PLATFORM_UWP)
+static EGLNativeWindowType uwpWindow;
+#endif
+
// Display size-related data
static unsigned int displayWidth, displayHeight; // Display width and height (monitor, device-screen, LCD, ...)
static int screenWidth, screenHeight; // Screen width and height (used render area)
@@ -277,11 +294,11 @@ static int renderOffsetX = 0; // Offset X from render area (must b
static int renderOffsetY = 0; // Offset Y from render area (must be divided by 2)
static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP)
static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size)
-
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
-static const char *windowTitle; // Window text title...
-static bool cursorOnScreen = false; // Tracks if cursor is inside client area
static bool cursorHidden = false; // Track if cursor is hidden
+static bool cursorOnScreen = false; // Tracks if cursor is inside client area
+
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
+static const char *windowTitle = NULL; // Window text title...
static int screenshotCounter = 0; // Screenshots counter
// Register mouse states
@@ -309,14 +326,13 @@ static int lastGamepadButtonPressed = -1; // Register last gamepad button pres
static int gamepadAxisCount = 0; // Register number of available gamepad axis
static Vector2 mousePosition; // Mouse position on screen
+static float mouseScale = 1.0f; // Mouse default scale
#if defined(PLATFORM_WEB)
static bool toggleCursorLock = false; // Ask for cursor pointer lock on next click
#endif
-#if defined(SUPPORT_GESTURES_SYSTEM)
static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen
-#endif
#if defined(PLATFORM_DESKTOP)
static char **dropFilesPath; // Store dropped files paths as strings
@@ -328,7 +344,7 @@ static double updateTime, drawTime; // Time measures for update and draw
static double frameTime = 0.0; // Time measure for one frame
static double targetTime = 0.0; // Desired time for one frame, if 0 not applied
-static char configFlags = 0; // Configuration flags (bit based)
+static unsigned char configFlags = 0; // Configuration flags (bit based)
static bool showLogo = false; // Track if showing logo at init is enabled
#if defined(SUPPORT_GIF_RECORDING)
@@ -347,10 +363,9 @@ extern void UnloadDefaultFont(void); // [Module: text] Unloads default fo
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
-static void InitGraphicsDevice(int width, int height); // Initialize graphics device
+static bool InitGraphicsDevice(int width, int height); // Initialize graphics device
static void SetupFramebufferSize(int displayWidth, int displayHeight);
static void InitTimer(void); // Initialize timer
-static double GetTime(void); // Returns time since InitTimer() was run
static void Wait(float ms); // Wait for some milliseconds (stop program execution)
static bool GetKeyStatus(int key); // Returns if a key has been pressed
static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed
@@ -400,6 +415,10 @@ static void InitGamepad(void); // Init raw gamepad inpu
static void *GamepadThread(void *arg); // Mouse reading thread
#endif
+#if defined(PLATFORM_UWP)
+// Define functions required to manage inputs
+#endif
+
#if defined(_WIN32)
// NOTE: We include Sleep() function signature here to avoid windows.h inclusion
void __stdcall Sleep(unsigned long msTimeout); // Required for Wait()
@@ -408,17 +427,28 @@ static void *GamepadThread(void *arg); // Mouse reading thread
//----------------------------------------------------------------------------------
// Module Functions Definition - Window and OpenGL Context Functions
//----------------------------------------------------------------------------------
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
// Initialize window and OpenGL context
-void InitWindow(int width, int height, const char *title)
+// NOTE: data parameter could be used to pass any kind of required data to the initialization
+void InitWindow(int width, int height, void *data)
{
- TraceLog(LOG_INFO, "Initializing raylib (v1.8.0)");
+ TraceLog(LOG_INFO, "Initializing raylib (v1.9.4-dev)");
- // Store window title (could be useful...)
- windowTitle = title;
+#if defined(PLATFORM_DESKTOP)
+ windowTitle = (char *)data;
+#endif
+
+#if defined(PLATFORM_UWP)
+ uwpWindow = (EGLNativeWindowType)data;
+#endif
+
+ // Init hi-res timer
+ InitTimer();
// Init graphics device (display device and OpenGL context)
- InitGraphicsDevice(width, height);
+ // NOTE: returns true if window and graphic device has been initialized successfully
+ windowReady = InitGraphicsDevice(width, height);
+ if (!windowReady) return;
#if defined(SUPPORT_DEFAULT_FONT)
// Load default font
@@ -426,9 +456,6 @@ void InitWindow(int width, int height, const char *title)
LoadDefaultFont();
#endif
- // Init hi-res timer
- InitTimer();
-
#if defined(PLATFORM_RPI)
// Init raw input system
InitMouse(); // Mouse init
@@ -472,17 +499,17 @@ void InitWindow(int width, int height, const char *title)
#endif
#if defined(PLATFORM_ANDROID)
-// Initialize Android activity
-void InitWindow(int width, int height, void *state)
+// Initialize window and OpenGL context (and Android activity)
+// NOTE: data parameter could be used to pass any kind of required data to the initialization
+void InitWindow(int width, int height, void *data)
{
- TraceLog(LOG_INFO, "Initializing raylib (v1.8.0)");
-
- app_dummy();
+ TraceLog(LOG_INFO, "Initializing raylib (v1.9.4-dev)");
screenWidth = width;
screenHeight = height;
- app = (struct android_app *)state;
+ // Input data is android app pointer
+ app = (struct android_app *)data;
internalDataPath = app->activity->internalDataPath;
// Set desired windows flags before initializing anything
@@ -511,7 +538,6 @@ void InitWindow(int width, int height, void *state)
//AConfiguration_getScreenSize(app->config);
//AConfiguration_getScreenLong(app->config);
- //state->userData = &engine;
app->onAppCmd = AndroidCommandCallback;
app->onInputEvent = AndroidInputCallback;
@@ -561,7 +587,7 @@ void CloseWindow(void)
timeEndPeriod(1); // Restore time period
#endif
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
// Close surface, context and display
if (display != EGL_NO_DISPLAY)
{
@@ -599,25 +625,36 @@ void CloseWindow(void)
TraceLog(LOG_INFO, "Window closed successfully");
}
+// Check if window has been initialized successfully
+bool IsWindowReady(void)
+{
+ return windowReady;
+}
+
// Check if KEY_ESCAPE pressed or Close icon pressed
bool WindowShouldClose(void)
{
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
- // While window minimized, stop loop execution
- while (windowMinimized) glfwWaitEvents();
+ if (windowReady)
+ {
+ // While window minimized, stop loop execution
+ while (windowMinimized) glfwWaitEvents();
- return (glfwWindowShouldClose(window));
+ return (glfwWindowShouldClose(window));
+ }
+ else return true;
#endif
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
- return windowShouldClose;
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
+ if (windowReady) return windowShouldClose;
+ else return true;
#endif
}
// Check if window has been minimized (or lost focus)
bool IsWindowMinimized(void)
{
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
return windowMinimized;
#else
return false;
@@ -659,6 +696,14 @@ void SetWindowIcon(Image image)
#endif
}
+// Set title for window (only PLATFORM_DESKTOP)
+void SetWindowTitle(const char *title)
+{
+#if defined(PLATFORM_DESKTOP)
+ glfwSetWindowTitle(window, title);
+#endif
+}
+
// Set window position on screen (windowed mode)
void SetWindowPosition(int x, int y)
{
@@ -676,7 +721,7 @@ void SetWindowMonitor(int monitor)
if ((monitor >= 0) && (monitor < monitorCount))
{
- glfwSetWindowMonitor(window, monitors[monitor], 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE);
+ //glfwSetWindowMonitor(window, monitors[monitor], 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE);
TraceLog(LOG_INFO, "Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
}
else TraceLog(LOG_WARNING, "Selected monitor not found");
@@ -692,6 +737,15 @@ void SetWindowMinSize(int width, int height)
#endif
}
+// Set window dimensions
+void SetWindowSize(int width, int height)
+{
+#if defined(PLATFORM_DESKTOP)
+ glfwSetWindowSize(window, width, height);
+#endif
+}
+
+
// Get current screen width
int GetScreenWidth(void)
{
@@ -704,16 +758,11 @@ int GetScreenHeight(void)
return screenHeight;
}
-#if !defined(PLATFORM_ANDROID)
// Show mouse cursor
void ShowCursor()
{
#if defined(PLATFORM_DESKTOP)
- #if defined(__linux__)
- XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window));
- #else
- glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
- #endif
+ glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
#endif
cursorHidden = false;
}
@@ -722,18 +771,7 @@ void ShowCursor()
void HideCursor()
{
#if defined(PLATFORM_DESKTOP)
- #if defined(__linux__)
- XColor col;
- const char nil[] = {0};
-
- Pixmap pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), nil, 1, 1);
- Cursor cur = XCreatePixmapCursor(glfwGetX11Display(), pix, pix, &col, &col, 0, 0);
-
- XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), cur);
- XFreeCursor(glfwGetX11Display(), cur);
- #else
- glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
- #endif
+ glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
#endif
cursorHidden = true;
}
@@ -767,23 +805,21 @@ void DisableCursor()
#endif
cursorHidden = true;
}
-#endif // !defined(PLATFORM_ANDROID)
// Set background color (framebuffer clear color)
void ClearBackground(Color color)
{
- // Clear full framebuffer (not only render area) to color
- rlClearColor(color.r, color.g, color.b, color.a);
+ rlClearColor(color.r, color.g, color.b, color.a); // Set clear color
+ rlClearScreenBuffers(); // Clear current framebuffers
}
// Setup canvas (framebuffer) to start drawing
void BeginDrawing(void)
{
- currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called
+ currentTime = GetTime(); // Number of elapsed seconds since InitTimer()
updateTime = currentTime - previousTime;
previousTime = currentTime;
- rlClearScreenBuffers(); // Clear current framebuffers
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
rlMultMatrixf(MatrixToFloat(downscaleView)); // If downscale required, apply it here
@@ -921,7 +957,7 @@ void BeginTextureMode(RenderTexture2D target)
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
rlEnableRenderTexture(target.id); // Enable render target
-
+
rlClearScreenBuffers(); // Clear render texture buffers
// Set viewport to framebuffer size
@@ -1053,7 +1089,25 @@ float GetFrameTime(void)
return (float)frameTime;
}
-// Converts Color to float array and normalizes
+// Get elapsed time measure in seconds since InitTimer()
+// NOTE: On PLATFORM_DESKTOP InitTimer() is called on InitWindow()
+// NOTE: On PLATFORM_DESKTOP, timer is initialized on glfwInit()
+double GetTime(void)
+{
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
+ return glfwGetTime(); // Elapsed time since glfwInit()
+#endif
+
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ uint64_t time = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec;
+
+ return (double)(time - baseTime)*1e-9; // Elapsed time since InitTimer()
+#endif
+}
+
+// Returns normalized float array for a Color
float *ColorToFloat(Color color)
{
static float buffer[4];
@@ -1066,6 +1120,64 @@ float *ColorToFloat(Color color)
return buffer;
}
+// Returns hexadecimal value for a Color
+int ColorToInt(Color color)
+{
+ return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
+}
+
+// Returns HSV values for a Color
+// NOTE: Hue is returned as degrees [0..360]
+Vector3 ColorToHSV(Color color)
+{
+ Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+ Vector3 hsv = { 0.0f, 0.0f, 0.0f };
+ float min, max, delta;
+
+ min = rgb.x < rgb.y ? rgb.x : rgb.y;
+ min = min < rgb.z ? min : rgb.z;
+
+ max = rgb.x > rgb.y ? rgb.x : rgb.y;
+ max = max > rgb.z ? max : rgb.z;
+
+ hsv.z = max; // Value
+ delta = max - min;
+
+ if (delta < 0.00001f)
+ {
+ hsv.y = 0.0f;
+ hsv.x = 0.0f; // Undefined, maybe NAN?
+ return hsv;
+ }
+
+ if (max > 0.0f)
+ {
+ // NOTE: If max is 0, this divide would cause a crash
+ hsv.y = (delta/max); // Saturation
+ }
+ else
+ {
+ // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
+ hsv.y = 0.0f;
+ hsv.x = NAN; // Undefined
+ return hsv;
+ }
+
+ // NOTE: Comparing float values could not work properly
+ if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
+ else
+ {
+ if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
+ else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
+ }
+
+ hsv.x *= 60.0f; // Convert to degrees
+
+ if (hsv.x < 0.0f) hsv.x += 360.0f;
+
+ return hsv;
+}
+
// Returns a Color struct from hexadecimal value
Color GetColor(int hexValue)
{
@@ -1079,11 +1191,7 @@ Color GetColor(int hexValue)
return color;
}
-// Returns hexadecimal value for a Color
-int GetHexValue(Color color)
-{
- return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
-}
+
// Returns a random value between min and max (both included)
int GetRandomValue(int min, int max)
@@ -1104,9 +1212,7 @@ Color Fade(Color color, float alpha)
if (alpha < 0.0f) alpha = 0.0f;
else if (alpha > 1.0f) alpha = 1.0f;
- float colorAlpha = (float)color.a*alpha;
-
- return (Color){color.r, color.g, color.b, (unsigned char)colorAlpha};
+ return (Color){color.r, color.g, color.b, (unsigned char)(255.0f*alpha)};
}
// Activate raylib logo at startup (can be done with flags)
@@ -1116,7 +1222,7 @@ void ShowLogo(void)
}
// Setup window configuration flags (view FLAGS)
-void SetConfigFlags(char flags)
+void SetConfigFlags(unsigned char flags)
{
configFlags = flags;
@@ -1152,6 +1258,27 @@ bool IsFileExtension(const char *fileName, const char *ext)
return result;
}
+// Get pointer to extension for a filename string
+const char *GetExtension(const char *fileName)
+{
+ const char *dot = strrchr(fileName, '.');
+
+ if (!dot || dot == fileName) return NULL;
+
+ return (dot + 1);
+}
+
+// Get pointer to filename for a path string
+const char *GetFileName(const char *filePath)
+{
+ const char *fileName = strrchr(filePath, '\\');
+
+ if (!fileName || fileName == filePath) return filePath;
+
+ return fileName + 1;
+}
+
+
// Get directory for a given fileName (with path)
const char *GetDirectoryPath(const char *fileName)
{
@@ -1477,6 +1604,7 @@ bool IsMouseButtonPressed(int button)
{
bool pressed = false;
+// TODO: Review, gestures could be not supported despite being on Android platform!
#if defined(PLATFORM_ANDROID)
if (IsGestureDetected(GESTURE_TAP)) pressed = true;
#else
@@ -1530,7 +1658,7 @@ int GetMouseX(void)
#if defined(PLATFORM_ANDROID)
return (int)touchPosition[0].x;
#else
- return (int)mousePosition.x;
+ return (int)(mousePosition.x*mouseScale);
#endif
}
@@ -1540,7 +1668,7 @@ int GetMouseY(void)
#if defined(PLATFORM_ANDROID)
return (int)touchPosition[0].x;
#else
- return (int)mousePosition.y;
+ return (int)(mousePosition.y*mouseScale);
#endif
}
@@ -1550,7 +1678,7 @@ Vector2 GetMousePosition(void)
#if defined(PLATFORM_ANDROID)
return GetTouchPosition(0);
#else
- return mousePosition;
+ return (Vector2){ mousePosition.x*mouseScale, mousePosition.y*mouseScale };
#endif
}
@@ -1564,6 +1692,15 @@ void SetMousePosition(Vector2 position)
#endif
}
+// Set mouse scaling
+// NOTE: Useful when rendering to different size targets
+void SetMouseScale(float scale)
+{
+#if !defined(PLATFORM_ANDROID)
+ mouseScale = scale;
+#endif
+}
+
// Returns mouse wheel movement Y
int GetMouseWheelMove(void)
{
@@ -1631,7 +1768,8 @@ Vector2 GetTouchPosition(int index)
// Initialize display device and framebuffer
// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size
// If width or height are 0, default display size will be used for framebuffer size
-static void InitGraphicsDevice(int width, int height)
+// NOTE: returns false in case graphic device could not be created
+static bool InitGraphicsDevice(int width, int height)
{
screenWidth = width; // User desired width
screenHeight = height; // User desired height
@@ -1645,12 +1783,22 @@ static void InitGraphicsDevice(int width, int height)
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
glfwSetErrorCallback(ErrorCallback);
- if (!glfwInit()) TraceLog(LOG_ERROR, "Failed to initialize GLFW");
+ if (!glfwInit())
+ {
+ TraceLog(LOG_WARNING, "Failed to initialize GLFW");
+ return false;
+ }
// NOTE: Getting video modes is not implemented in emscripten GLFW3 version
#if defined(PLATFORM_DESKTOP)
// Find monitor resolution
- const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
+ GLFWmonitor *monitor = glfwGetPrimaryMonitor();
+ if (!monitor)
+ {
+ TraceLog(LOG_WARNING, "Failed to get monitor");
+ return false;
+ }
+ const GLFWvidmode *mode = glfwGetVideoMode(monitor);
displayWidth = mode->width;
displayHeight = mode->height;
@@ -1756,24 +1904,28 @@ static void InitGraphicsDevice(int width, int height)
// No-fullscreen window creation
window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, NULL, NULL);
+ if (window)
+ {
#if defined(PLATFORM_DESKTOP)
- // Center window on screen
- int windowPosX = displayWidth/2 - screenWidth/2;
- int windowPosY = displayHeight/2 - screenHeight/2;
+ // Center window on screen
+ int windowPosX = displayWidth/2 - screenWidth/2;
+ int windowPosY = displayHeight/2 - screenHeight/2;
- if (windowPosX < 0) windowPosX = 0;
- if (windowPosY < 0) windowPosY = 0;
+ if (windowPosX < 0) windowPosX = 0;
+ if (windowPosY < 0) windowPosY = 0;
- glfwSetWindowPos(window, windowPosX, windowPosY);
+ glfwSetWindowPos(window, windowPosX, windowPosY);
#endif
- renderWidth = screenWidth;
- renderHeight = screenHeight;
+ renderWidth = screenWidth;
+ renderHeight = screenHeight;
+ }
}
if (!window)
{
glfwTerminate();
- TraceLog(LOG_ERROR, "GLFW Failed to initialize Window");
+ TraceLog(LOG_WARNING, "GLFW Failed to initialize Window");
+ return false;
}
else
{
@@ -1819,7 +1971,7 @@ static void InitGraphicsDevice(int width, int height)
}
#endif // defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
fullscreen = true;
// Screen size security check
@@ -1862,19 +2014,194 @@ static void InitGraphicsDevice(int width, int height)
EGL_NONE
};
- EGLint contextAttribs[] =
+ const EGLint contextAttribs[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
+#if defined(PLATFORM_UWP)
+ const EGLint surfaceAttributes[] =
+ {
+ // EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is part of the same optimization as EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER (see above).
+ // If you have compilation issues with it then please update your Visual Studio templates.
+ EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
+ EGL_NONE
+ };
+
+ const EGLint defaultDisplayAttributes[] =
+ {
+ // These are the default display attributes, used to request ANGLE's D3D11 renderer.
+ // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+.
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+
+ // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices.
+ // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it.
+ EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
+
+ // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call
+ // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended.
+ // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement.
+ EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
+ EGL_NONE,
+ };
+
+ const EGLint fl9_3DisplayAttributes[] =
+ {
+ // These can be used to request ANGLE's D3D11 renderer, with D3D11 Feature Level 9_3.
+ // These attributes are used if the call to eglInitialize fails with the default display attributes.
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
+ EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
+ EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
+ EGL_NONE,
+ };
+
+ const EGLint warpDisplayAttributes[] =
+ {
+ // These attributes can be used to request D3D11 WARP.
+ // They are used if eglInitialize fails with both the default display attributes and the 9_3 display attributes.
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+ EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
+ EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
+ EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
+ EGL_NONE,
+ };
+
+ EGLConfig config = NULL;
+
+ // eglGetPlatformDisplayEXT is an alternative to eglGetDisplay. It allows us to pass in display attributes, used to configure D3D11.
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)(eglGetProcAddress("eglGetPlatformDisplayEXT"));
+ if (!eglGetPlatformDisplayEXT)
+ {
+ TraceLog(LOG_WARNING, "Failed to get function eglGetPlatformDisplayEXT");
+ return false;
+ }
+
+ //
+ // To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize, with varying
+ // parameters passed to eglGetPlatformDisplayEXT:
+ // 1) The first calls uses "defaultDisplayAttributes" as a parameter. This corresponds to D3D11 Feature Level 10_0+.
+ // 2) If eglInitialize fails for step 1 (e.g. because 10_0+ isn't supported by the default GPU), then we try again
+ // using "fl9_3DisplayAttributes". This corresponds to D3D11 Feature Level 9_3.
+ // 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
+ // using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
+ //
+
+ // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
+ display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
+ if (display == EGL_NO_DISPLAY)
+ {
+ TraceLog(LOG_WARNING, "Failed to initialize EGL display");
+ return false;
+ }
+
+ if (eglInitialize(display, NULL, NULL) == EGL_FALSE)
+ {
+ // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices).
+ display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
+ if (display == EGL_NO_DISPLAY)
+ {
+ TraceLog(LOG_WARNING, "Failed to initialize EGL display");
+ return false;
+ }
+
+ if (eglInitialize(display, NULL, NULL) == EGL_FALSE)
+ {
+ // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU.
+ display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
+ if (display == EGL_NO_DISPLAY)
+ {
+ TraceLog(LOG_WARNING, "Failed to initialize EGL display");
+ return false;
+ }
+
+ if (eglInitialize(display, NULL, NULL) == EGL_FALSE)
+ {
+ // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
+ TraceLog(LOG_WARNING, "Failed to initialize EGL");
+ return false;
+ }
+ }
+ }
+
+ //SetupFramebufferSize(displayWidth, displayHeight);
+
+ EGLint numConfigs = 0;
+ if ((eglChooseConfig(display, framebufferAttribs, &config, 1, &numConfigs) == EGL_FALSE) || (numConfigs == 0))
+ {
+ TraceLog(LOG_WARNING, "Failed to choose first EGLConfig");
+ return false;
+ }
+
+ // Create a PropertySet and initialize with the EGLNativeWindowType.
+ //PropertySet^ surfaceCreationProperties = ref new PropertySet();
+ //surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), window); // CoreWindow^ window
+
+ // You can configure the surface to render at a lower resolution and be scaled up to
+ // the full window size. The scaling is often free on mobile hardware.
+ //
+ // One way to configure the SwapChainPanel is to specify precisely which resolution it should render at.
+ // Size customRenderSurfaceSize = Size(800, 600);
+ // surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(customRenderSurfaceSize));
+ //
+ // Another way is to tell the SwapChainPanel to render at a certain scale factor compared to its size.
+ // e.g. if the SwapChainPanel is 1920x1280 then setting a factor of 0.5f will make the app render at 960x640
+ // float customResolutionScale = 0.5f;
+ // surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(customResolutionScale));
+
+
+ // eglCreateWindowSurface() requires a EGLNativeWindowType parameter,
+ // In Windows platform: typedef HWND EGLNativeWindowType;
+
+
+ // Property: EGLNativeWindowTypeProperty
+ // Type: IInspectable
+ // Description: Set this property to specify the window type to use for creating a surface.
+ // If this property is missing, surface creation will fail.
+ //
+ //const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty";
+
+ //https://stackoverflow.com/questions/46550182/how-to-create-eglsurface-using-c-winrt-and-angle
+
+ //surface = eglCreateWindowSurface(display, config, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
+ surface = eglCreateWindowSurface(display, config, uwpWindow, surfaceAttributes);
+ if (surface == EGL_NO_SURFACE)
+ {
+ TraceLog(LOG_WARNING, "Failed to create EGL fullscreen surface");
+ return false;
+ }
+
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
+ if (context == EGL_NO_CONTEXT)
+ {
+ TraceLog(LOG_WARNING, "Failed to create EGL context");
+ return false;
+ }
+
+ // Get EGL display window size
+ eglQuerySurface(display, surface, EGL_WIDTH, &screenWidth);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &screenHeight);
+
+#else // PLATFORM_ANDROID, PLATFORM_RPI
EGLint numConfigs;
// Get an EGL display connection
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (display == EGL_NO_DISPLAY)
+ {
+ TraceLog(LOG_WARNING, "Failed to initialize EGL display");
+ return false;
+ }
// Initialize the EGL display connection
- eglInitialize(display, NULL, NULL);
+ if (eglInitialize(display, NULL, NULL) == EGL_FALSE)
+ {
+ // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
+ TraceLog(LOG_WARNING, "Failed to initialize EGL");
+ return false;
+ }
// Get an appropriate EGL framebuffer configuration
eglChooseConfig(display, framebufferAttribs, &config, 1, &numConfigs);
@@ -1884,6 +2211,12 @@ static void InitGraphicsDevice(int width, int height)
// Create an EGL rendering context
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
+ if (context == EGL_NO_CONTEXT)
+ {
+ TraceLog(LOG_WARNING, "Failed to create EGL context");
+ return false;
+ }
+#endif
// Create an EGL window surface
//---------------------------------------------------------------------------------
@@ -1951,7 +2284,8 @@ static void InitGraphicsDevice(int width, int height)
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
{
- TraceLog(LOG_ERROR, "Unable to attach EGL rendering context to EGL surface");
+ TraceLog(LOG_WARNING, "Unable to attach EGL rendering context to EGL surface");
+ return false;
}
else
{
@@ -1967,6 +2301,9 @@ static void InitGraphicsDevice(int width, int height)
}
#endif // defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ renderWidth = screenWidth;
+ renderHeight = screenHeight;
+
// Initialize OpenGL context (states and resources)
// NOTE: screenWidth and screenHeight not used, just stored as globals
rlglInit(screenWidth, screenHeight);
@@ -1987,6 +2324,7 @@ static void InitGraphicsDevice(int width, int height)
#if defined(PLATFORM_ANDROID)
windowReady = true; // IMPORTANT!
#endif
+ return true;
}
// Set viewport parameters
@@ -2102,22 +2440,6 @@ static void InitTimer(void)
previousTime = GetTime(); // Get time as double
}
-// Get current time measure (in seconds) since InitTimer()
-static double GetTime(void)
-{
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
- return glfwGetTime();
-#endif
-
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- uint64_t time = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec;
-
- return (double)(time - baseTime)*1e-9;
-#endif
-}
-
// Wait for some milliseconds (stop program execution)
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop
@@ -2351,7 +2673,7 @@ static void SwapBuffers(void)
glfwSwapBuffers(window);
#endif
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
eglSwapBuffers(display, surface);
#endif
}
@@ -2415,7 +2737,9 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
else
{
currentKeyState[key] = action;
- if (action == GLFW_PRESS) lastKeyPressed = key;
+
+ // NOTE: lastKeyPressed already registered on CharCallback()
+ //if (action == GLFW_PRESS) lastKeyPressed = key;
}
}
@@ -2481,12 +2805,15 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
#endif
}
-// GLFW3 Char Key Callback, runs on key pressed (get char value)
+// GLFW3 Char Key Callback, runs on key down (get unicode char value)
static void CharCallback(GLFWwindow *window, unsigned int key)
-{
+{
+ // NOTE: Registers any key down considering OS keyboard layout but
+ // do not detects action events, those should be managed by user...
+ // https://github.com/glfw/glfw/issues/668#issuecomment-166794907
+ // http://www.glfw.org/docs/latest/input_guide.html#input_char
+
lastKeyPressed = key;
-
- //TraceLog(LOG_INFO, "Char Callback Key pressed: %i\n", key);
}
// GLFW3 CursorEnter Callback, when cursor enters the window
@@ -2510,6 +2837,8 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
rlClearScreenBuffers(); // Clear screen buffers (color and depth)
// Window size must be updated to be used on 3D mode to get new aspect ratio (Begin3dMode())
+ // NOTE: Be careful! GLFW3 will choose the closest fullscreen resolution supported by current monitor,
+ // for example, if reescaling back to 800x450 (desired), it could set 720x480 (closest fullscreen supported)
screenWidth = width;
screenHeight = height;
renderWidth = width;
@@ -2584,6 +2913,9 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
{
// Init graphics device (display device and OpenGL context)
InitGraphicsDevice(screenWidth, screenHeight);
+
+ // Init hi-res timer
+ InitTimer();
#if defined(SUPPORT_DEFAULT_FONT)
// Load default font
@@ -2606,9 +2938,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
}
*/
- // Init hi-res timer
- InitTimer();
-
// raylib logo appearing animation (if enabled)
if (showLogo)
{
@@ -2730,6 +3059,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
int32_t action = AMotionEvent_getAction(event);
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
+#if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent;
// Register touch actions
@@ -2758,8 +3088,21 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
// Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent);
+#else
+
+ // Support only simple touch position
+ if (flags == AMOTION_EVENT_ACTION_DOWN)
+ {
+ // Get first touch position
+ touchPosition[0].x = AMotionEvent_getX(event, 0);
+ touchPosition[0].y = AMotionEvent_getY(event, 0);
+
+ touchPosition[0].x /= (float)GetScreenWidth();
+ touchPosition[0].y /= (float)GetScreenHeight();
+ }
+#endif
- return 0; // return 1;
+ return 0;
}
#endif