From abfbc42df703c382a56cf1e06e4302cadbfe3395 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 25 Sep 2018 12:53:31 +0200 Subject: PNG image size optimization --- src/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index fc1a5a09..5f155a0a 100644 --- a/src/core.c +++ b/src/core.c @@ -1375,8 +1375,7 @@ const char *GetDirectoryPath(const char *fileName) memset(filePath, 0, 256); lastSlash = strprbrk(fileName, "\\/"); - if (!lastSlash) - return NULL; + if (!lastSlash) return NULL; strncpy(filePath, fileName, strlen(fileName) - (strlen(lastSlash) - 1)); filePath[strlen(fileName) - strlen(lastSlash)] = '\0'; -- cgit v1.2.3 From 29eddb9ff3fda090ed416a2736a6d2db4cca77e9 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 26 Sep 2018 16:02:42 +0200 Subject: Updated icon data --- raylib.rc.o | Bin 107260 -> 11190 bytes src/raylib.ico | Bin 105907 -> 9752 bytes src/raylib.rc | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/raylib.rc.o b/raylib.rc.o index 28005c73..fa27177d 100644 Binary files a/raylib.rc.o and b/raylib.rc.o differ diff --git a/src/raylib.ico b/src/raylib.ico index afeb12b9..0cedcc55 100644 Binary files a/src/raylib.ico and b/src/raylib.ico differ diff --git a/src/raylib.rc b/src/raylib.rc index ee2a5fab..2aaa5e26 100644 --- a/src/raylib.rc +++ b/src/raylib.rc @@ -9,7 +9,7 @@ BEGIN //BLOCK "080904E4" // English UK BLOCK "040904E4" // English US BEGIN - VALUE "CompanyName", "raylib technologies" + //VALUE "CompanyName", "raylib technologies" VALUE "FileDescription", "Created using raylib (www.raylib.com)" VALUE "FileVersion", "2.0.0" VALUE "InternalName", "raylib app" -- cgit v1.2.3 From 1836e02c1ef9909d25bbb89b9d9fdd6ec934aada Mon Sep 17 00:00:00 2001 From: ChrisDill Date: Thu, 27 Sep 2018 15:52:56 +0100 Subject: Added monitor functions - Get number of monitors - Get size, physical size and name of primary monitor. Could pass monitor id instead not sure. --- src/core.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/raylib.h | 6 ++++++ 2 files changed, 55 insertions(+) (limited to 'src') diff --git a/src/core.c b/src/core.c index fc1a5a09..e785e735 100644 --- a/src/core.c +++ b/src/core.c @@ -770,6 +770,55 @@ int GetScreenHeight(void) return screenHeight; } +// Get number of monitors +int GetMonitorCount(void) +{ + int monitorCount; + glfwGetMonitors(&monitorCount); + return monitorCount; +} + +// Get primary monitor width +int GetMonitorWidth(void) +{ + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode * mode = glfwGetVideoMode(monitor); + return mode->width; +} + +// Get primary monitor height +int GetMonitorHeight(void) +{ + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode * mode = glfwGetVideoMode(monitor); + return mode->height; +} + +// Get primary montior physical width in millimetres +int GetMonitorPhysicalWidth(void) +{ + int physicalWidth; + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + glfwGetMonitorPhysicalSize(monitor, &physicalWidth, NULL); + return physicalWidth; +} + +// Get primary monitor physical height in millimetres +int GetMonitorPhysicalHeight(void) +{ + int physicalHeight; + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + glfwGetMonitorPhysicalSize(monitor, NULL, &physicalHeight); + return physicalHeight; +} + +// Get the human-readable, UTF-8 encoded name of the primary monitor +const char *GetMonitorName(void) +{ + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + return glfwGetMonitorName(monitor); +} + // Show mouse cursor void ShowCursor() { diff --git a/src/raylib.h b/src/raylib.h index a44b77ee..ee8744e7 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -814,6 +814,12 @@ RLAPI void SetWindowMinSize(int width, int height); // Set window RLAPI void SetWindowSize(int width, int height); // Set window dimensions RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height +RLAPI int GetMonitorCount(void); // Get number of connected monitors +RLAPI int GetMonitorWidth(void); // Get primary monitor width +RLAPI int GetMonitorHeight(void); // Get primary monitor height +RLAPI int GetMonitorPhysicalWidth(void); // Get primary monitor physical width in millimetres +RLAPI int GetMonitorPhysicalHeight(void); // Get primary monitor physical height in millimetres +RLAPI const char *GetMonitorName(void); // Get the human-readable, UTF-8 encoded name of the primary monitor // Cursor-related functions RLAPI void ShowCursor(void); // Shows cursor -- cgit v1.2.3 From ed79d53e1a177596d312453db8db4bc69f2b8656 Mon Sep 17 00:00:00 2001 From: ChrisDill Date: Thu, 27 Sep 2018 16:23:11 +0100 Subject: Changed tabs to spaces - Fixed tabs used instead of 4 spaces --- src/core.c | 32 ++++++++++++++++---------------- src/raylib.h | 10 +++++----- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 5b9db9fa..9086ad65 100644 --- a/src/core.c +++ b/src/core.c @@ -773,9 +773,9 @@ int GetScreenHeight(void) // Get number of monitors int GetMonitorCount(void) { - int monitorCount; - glfwGetMonitors(&monitorCount); - return monitorCount; + int monitorCount; + glfwGetMonitors(&monitorCount); + return monitorCount; } // Get primary monitor width @@ -789,34 +789,34 @@ int GetMonitorWidth(void) // Get primary monitor height int GetMonitorHeight(void) { - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - const GLFWvidmode * mode = glfwGetVideoMode(monitor); - return mode->height; + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode * mode = glfwGetVideoMode(monitor); + return mode->height; } // Get primary montior physical width in millimetres int GetMonitorPhysicalWidth(void) { - int physicalWidth; - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - glfwGetMonitorPhysicalSize(monitor, &physicalWidth, NULL); - return physicalWidth; + int physicalWidth; + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + glfwGetMonitorPhysicalSize(monitor, &physicalWidth, NULL); + return physicalWidth; } // Get primary monitor physical height in millimetres int GetMonitorPhysicalHeight(void) { - int physicalHeight; - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - glfwGetMonitorPhysicalSize(monitor, NULL, &physicalHeight); - return physicalHeight; + int physicalHeight; + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + glfwGetMonitorPhysicalSize(monitor, NULL, &physicalHeight); + return physicalHeight; } // Get the human-readable, UTF-8 encoded name of the primary monitor const char *GetMonitorName(void) { - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - return glfwGetMonitorName(monitor); + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + return glfwGetMonitorName(monitor); } // Show mouse cursor diff --git a/src/raylib.h b/src/raylib.h index ee8744e7..fb4fb842 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -814,11 +814,11 @@ RLAPI void SetWindowMinSize(int width, int height); // Set window RLAPI void SetWindowSize(int width, int height); // Set window dimensions RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height -RLAPI int GetMonitorCount(void); // Get number of connected monitors -RLAPI int GetMonitorWidth(void); // Get primary monitor width -RLAPI int GetMonitorHeight(void); // Get primary monitor height -RLAPI int GetMonitorPhysicalWidth(void); // Get primary monitor physical width in millimetres -RLAPI int GetMonitorPhysicalHeight(void); // Get primary monitor physical height in millimetres +RLAPI int GetMonitorCount(void); // Get number of connected monitors +RLAPI int GetMonitorWidth(void); // Get primary monitor width +RLAPI int GetMonitorHeight(void); // Get primary monitor height +RLAPI int GetMonitorPhysicalWidth(void); // Get primary monitor physical width in millimetres +RLAPI int GetMonitorPhysicalHeight(void); // Get primary monitor physical height in millimetres RLAPI const char *GetMonitorName(void); // Get the human-readable, UTF-8 encoded name of the primary monitor // Cursor-related functions -- cgit v1.2.3 From ed95337eb884baac8de84ae0e973a5ecb0d530e2 Mon Sep 17 00:00:00 2001 From: ChrisDill Date: Sat, 29 Sep 2018 14:10:29 +0100 Subject: Added platform check - Added PLATFORM_DESKTOP check for Monitor functions to try to fix issue on android. - Not sure what return types should be when not on desktop. Added rough guess for now. --- src/core.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src') diff --git a/src/core.c b/src/core.c index 9086ad65..65c18fec 100644 --- a/src/core.c +++ b/src/core.c @@ -773,50 +773,68 @@ int GetScreenHeight(void) // Get number of monitors int GetMonitorCount(void) { +#if defined(PLATFORM_DESKTOP) int monitorCount; glfwGetMonitors(&monitorCount); return monitorCount; +#endif + return 1; } // Get primary monitor width int GetMonitorWidth(void) { +#if defined(PLATFORM_DESKTOP) GLFWmonitor *monitor = glfwGetPrimaryMonitor(); const GLFWvidmode * mode = glfwGetVideoMode(monitor); return mode->width; +#endif + return GetScreenWidth(); } // Get primary monitor height int GetMonitorHeight(void) { +#if defined(PLATFORM_DESKTOP) GLFWmonitor *monitor = glfwGetPrimaryMonitor(); const GLFWvidmode * mode = glfwGetVideoMode(monitor); return mode->height; +#endif + return GetScreenHeight(); } // Get primary montior physical width in millimetres int GetMonitorPhysicalWidth(void) { +#if defined(PLATFORM_DESKTOP) int physicalWidth; GLFWmonitor *monitor = glfwGetPrimaryMonitor(); glfwGetMonitorPhysicalSize(monitor, &physicalWidth, NULL); return physicalWidth; +#endif + return 0; } // Get primary monitor physical height in millimetres int GetMonitorPhysicalHeight(void) { +#if defined(PLATFORM_DESKTOP) int physicalHeight; GLFWmonitor *monitor = glfwGetPrimaryMonitor(); glfwGetMonitorPhysicalSize(monitor, NULL, &physicalHeight); return physicalHeight; +#endif + return 0; } // Get the human-readable, UTF-8 encoded name of the primary monitor const char *GetMonitorName(void) { +#if defined(PLATFORM_DESKTOP) GLFWmonitor *monitor = glfwGetPrimaryMonitor(); return glfwGetMonitorName(monitor); +#endif + return ""; } // Show mouse cursor -- cgit v1.2.3 From 6b84b76b70be35b471ef31afc0f0dc4e16cfe383 Mon Sep 17 00:00:00 2001 From: ChrisDill Date: Sat, 29 Sep 2018 14:28:07 +0100 Subject: Forgot #else in platform check - Added else so return not compiled twice. --- src/core.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 65c18fec..e370d5e3 100644 --- a/src/core.c +++ b/src/core.c @@ -777,8 +777,9 @@ int GetMonitorCount(void) int monitorCount; glfwGetMonitors(&monitorCount); return monitorCount; -#endif +#else return 1; +#endif } // Get primary monitor width @@ -788,8 +789,9 @@ int GetMonitorWidth(void) GLFWmonitor *monitor = glfwGetPrimaryMonitor(); const GLFWvidmode * mode = glfwGetVideoMode(monitor); return mode->width; -#endif +#else return GetScreenWidth(); +#endif } // Get primary monitor height @@ -799,8 +801,9 @@ int GetMonitorHeight(void) GLFWmonitor *monitor = glfwGetPrimaryMonitor(); const GLFWvidmode * mode = glfwGetVideoMode(monitor); return mode->height; -#endif +#else return GetScreenHeight(); +#endif } // Get primary montior physical width in millimetres @@ -811,8 +814,9 @@ int GetMonitorPhysicalWidth(void) GLFWmonitor *monitor = glfwGetPrimaryMonitor(); glfwGetMonitorPhysicalSize(monitor, &physicalWidth, NULL); return physicalWidth; -#endif +#else return 0; +#endif } // Get primary monitor physical height in millimetres @@ -823,8 +827,9 @@ int GetMonitorPhysicalHeight(void) GLFWmonitor *monitor = glfwGetPrimaryMonitor(); glfwGetMonitorPhysicalSize(monitor, NULL, &physicalHeight); return physicalHeight; -#endif +#else return 0; +#endif } // Get the human-readable, UTF-8 encoded name of the primary monitor @@ -833,8 +838,9 @@ const char *GetMonitorName(void) #if defined(PLATFORM_DESKTOP) GLFWmonitor *monitor = glfwGetPrimaryMonitor(); return glfwGetMonitorName(monitor); -#endif +#else return ""; +#endif } // Show mouse cursor -- cgit v1.2.3 From 67dc50ef0077b194fa51014880e531b126d0b059 Mon Sep 17 00:00:00 2001 From: ChrisDill Date: Sun, 30 Sep 2018 15:20:02 +0100 Subject: Changed monitor functions to use a index - Using same idea as SetWindowMonitor to take in a index with 0 being the primary monitor. --- src/core.c | 93 ++++++++++++++++++++++++++++++++++++++---------------------- src/raylib.h | 10 +++---- 2 files changed, 64 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index e370d5e3..203da4d9 100644 --- a/src/core.c +++ b/src/core.c @@ -783,64 +783,89 @@ int GetMonitorCount(void) } // Get primary monitor width -int GetMonitorWidth(void) +int GetMonitorWidth(int monitor) { #if defined(PLATFORM_DESKTOP) - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - const GLFWvidmode * mode = glfwGetVideoMode(monitor); - return mode->width; -#else - return GetScreenWidth(); + int monitorCount; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); + return mode->width; + } + else TraceLog(LOG_WARNING, "Selected monitor not found"); #endif + return 0; } -// Get primary monitor height -int GetMonitorHeight(void) -{ +// Get primary monitor width +int GetMonitorHeight(int monitor) +{ #if defined(PLATFORM_DESKTOP) - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - const GLFWvidmode * mode = glfwGetVideoMode(monitor); - return mode->height; -#else - return GetScreenHeight(); + int monitorCount; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); + return mode->height; + } + else TraceLog(LOG_WARNING, "Selected monitor not found"); #endif + return 0; } // Get primary montior physical width in millimetres -int GetMonitorPhysicalWidth(void) +int GetMonitorPhysicalWidth(int monitor) { #if defined(PLATFORM_DESKTOP) - int physicalWidth; - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - glfwGetMonitorPhysicalSize(monitor, &physicalWidth, NULL); - return physicalWidth; -#else - return 0; + int monitorCount; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + int physicalWidth; + glfwGetMonitorPhysicalSize(monitors[monitor], &physicalWidth, NULL); + return physicalWidth; + } + else TraceLog(LOG_WARNING, "Selected monitor not found"); #endif + return 0; } // Get primary monitor physical height in millimetres -int GetMonitorPhysicalHeight(void) +int GetMonitorPhysicalHeight(int monitor) { -#if defined(PLATFORM_DESKTOP) - int physicalHeight; - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - glfwGetMonitorPhysicalSize(monitor, NULL, &physicalHeight); - return physicalHeight; -#else - return 0; +#if defined(PLATFORM_DESKTOP) + int monitorCount; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + int physicalHeight; + glfwGetMonitorPhysicalSize(monitors[monitor], NULL, &physicalHeight); + return physicalHeight; + } + else TraceLog(LOG_WARNING, "Selected monitor not found"); #endif + return 0; } // Get the human-readable, UTF-8 encoded name of the primary monitor -const char *GetMonitorName(void) +const char *GetMonitorName(int monitor) { #if defined(PLATFORM_DESKTOP) - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - return glfwGetMonitorName(monitor); -#else - return ""; + int monitorCount; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + return glfwGetMonitorName(monitors[monitor]); + } + else TraceLog(LOG_WARNING, "Selected monitor not found"); #endif + return ""; } // Show mouse cursor diff --git a/src/raylib.h b/src/raylib.h index fb4fb842..17c4234e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -815,11 +815,11 @@ RLAPI void SetWindowSize(int width, int height); // Set window RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height RLAPI int GetMonitorCount(void); // Get number of connected monitors -RLAPI int GetMonitorWidth(void); // Get primary monitor width -RLAPI int GetMonitorHeight(void); // Get primary monitor height -RLAPI int GetMonitorPhysicalWidth(void); // Get primary monitor physical width in millimetres -RLAPI int GetMonitorPhysicalHeight(void); // Get primary monitor physical height in millimetres -RLAPI const char *GetMonitorName(void); // Get the human-readable, UTF-8 encoded name of the primary monitor +RLAPI int GetMonitorWidth(int monitor); // Get primary monitor width +RLAPI int GetMonitorHeight(int monitor); // Get primary monitor height +RLAPI int GetMonitorPhysicalWidth(int monitor); // Get primary monitor physical width in millimetres +RLAPI int GetMonitorPhysicalHeight(int monitor); // Get primary monitor physical height in millimetres +RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor // Cursor-related functions RLAPI void ShowCursor(void); // Shows cursor -- cgit v1.2.3 From ecb787d76f2b18d44570ddfd1774d1140c9ab03a Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 1 Oct 2018 15:29:34 +0200 Subject: Update version number (internally) --- src/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/config.h b/src/config.h index c2238a79..47cc8068 100644 --- a/src/config.h +++ b/src/config.h @@ -25,7 +25,7 @@ * **********************************************************************************************/ -#define RAYLIB_VERSION "2.0" +#define RAYLIB_VERSION "2.1-dev" // Edit to control what features Makefile'd raylib is compiled with #if defined(RAYLIB_CMAKE) -- cgit v1.2.3 From d67edb591a578063b96e2207d087fe669c0ebaa2 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 1 Oct 2018 15:30:48 +0200 Subject: Support KXT image file export [textures] Added SaveKTX() [rlgl] Exposed rlGetGlTextureFormats() --- src/rlgl.h | 128 ++++++++++++++++++++++++++++----------------------------- src/textures.c | 93 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 154 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/rlgl.h b/src/rlgl.h index 75246cab..3f5c67a9 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -446,9 +446,11 @@ void rlLoadExtensions(void *loader); // Load OpenGL extensions Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates // Textures data management -unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU -void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data -void rlUnloadTexture(unsigned int id); +unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU +void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data +void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType); // Get OpenGL internal formats +void rlUnloadTexture(unsigned int id); // Unload texture from GPU memory + void rlGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture void *rlReadTexturePixels(Texture2D texture); // Read texture pixel data unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) @@ -913,9 +915,6 @@ static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); / #endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -// Get OpenGL internal formats and data type from raylib PixelFormat -static void GetGlFormats(int format, int *glInternalFormat, int *glFormat, int *glType); - #if defined(GRAPHICS_API_OPENGL_11) static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight); static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight); @@ -2015,8 +2014,8 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi { unsigned int mipSize = GetPixelDataSize(mipWidth, mipHeight, format); - int glInternalFormat, glFormat, glType; - GetGlFormats(format, &glInternalFormat, &glFormat, &glType); + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); TraceLog(LOG_DEBUG, "Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset); @@ -2105,8 +2104,8 @@ void rlUpdateTexture(unsigned int id, int width, int height, int format, const v { glBindTexture(GL_TEXTURE_2D, id); - int glInternalFormat, glFormat, glType; - GetGlFormats(format, &glInternalFormat, &glFormat, &glType); + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); if ((glInternalFormat != -1) && (format < COMPRESSED_DXT1_RGB)) { @@ -2115,13 +2114,64 @@ void rlUpdateTexture(unsigned int id, int width, int height, int format, const v else TraceLog(LOG_WARNING, "Texture format updating not supported"); } +// Get OpenGL internal formats and data type from raylib PixelFormat +void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType) +{ + *glInternalFormat = -1; + *glFormat = -1; + *glType = -1; + + switch (format) + { + #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA + case UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_UNSIGNED_BYTE; break; + case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_LUMINANCE_ALPHA; *glFormat = GL_LUMINANCE_ALPHA; *glType = GL_UNSIGNED_BYTE; break; + case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; + case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; + case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; + case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; + case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; + #if !defined(GRAPHICS_API_OPENGL_11) + case UNCOMPRESSED_R32: if (texFloatSupported) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + case UNCOMPRESSED_R32G32B32: if (texFloatSupported) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + #endif + #elif defined(GRAPHICS_API_OPENGL_33) + case UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_R8; *glFormat = GL_RED; *glType = GL_UNSIGNED_BYTE; break; + case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_RG8; *glFormat = GL_RG; *glType = GL_UNSIGNED_BYTE; break; + case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB565; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; + case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB8; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; + case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGB5_A1; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; + case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA4; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; + case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA8; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; + case UNCOMPRESSED_R32: if (texFloatSupported) *glInternalFormat = GL_R32F; *glFormat = GL_RED; *glType = GL_FLOAT; break; + case UNCOMPRESSED_R32G32B32: if (texFloatSupported) *glInternalFormat = GL_RGB32F; *glFormat = GL_RGB; *glType = GL_FLOAT; break; + case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) *glInternalFormat = GL_RGBA32F; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; + #endif + #if !defined(GRAPHICS_API_OPENGL_11) + case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; + case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; + case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; + case COMPRESSED_DXT5_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; + case COMPRESSED_ETC1_RGB: if (texCompETC1Supported) *glInternalFormat = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3 + case COMPRESSED_ETC2_RGB: if (texCompETC2Supported) *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case COMPRESSED_ETC2_EAC_RGBA: if (texCompETC2Supported) *glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case COMPRESSED_PVRT_RGB: if (texCompPVRTSupported) *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU + case COMPRESSED_PVRT_RGBA: if (texCompPVRTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU + case COMPRESSED_ASTC_4x4_RGBA: if (texCompASTCSupported) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 + case COMPRESSED_ASTC_8x8_RGBA: if (texCompASTCSupported) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 + #endif + default: TraceLog(LOG_WARNING, "Texture format not supported"); break; + } +} + // Unload texture from GPU memory void rlUnloadTexture(unsigned int id) { if (id > 0) glDeleteTextures(1, &id); } - // Load a texture to be used for rendering (fbo with color and depth attachments) RenderTexture2D rlLoadRenderTexture(int width, int height) { @@ -2745,8 +2795,8 @@ void *rlReadTexturePixels(Texture2D texture) // GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.) glPixelStorei(GL_PACK_ALIGNMENT, 1); - int glInternalFormat, glFormat, glType; - GetGlFormats(texture.format, &glInternalFormat, &glFormat, &glType); + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(texture.format, &glInternalFormat, &glFormat, &glType); unsigned int size = GetPixelDataSize(texture.width, texture.height, texture.format); if ((glInternalFormat != -1) && (texture.format < COMPRESSED_DXT1_RGB)) @@ -4591,58 +4641,6 @@ static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView) #endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -// Get OpenGL internal formats and data type from raylib PixelFormat -static void GetGlFormats(int format, int *glInternalFormat, int *glFormat, int *glType) -{ - *glInternalFormat = -1; - *glFormat = -1; - *glType = -1; - - switch (format) - { - #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA - case UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_LUMINANCE_ALPHA; *glFormat = GL_LUMINANCE_ALPHA; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; - case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; - case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; - case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; - #if !defined(GRAPHICS_API_OPENGL_11) - case UNCOMPRESSED_R32: if (texFloatSupported) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - case UNCOMPRESSED_R32G32B32: if (texFloatSupported) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - #endif - #elif defined(GRAPHICS_API_OPENGL_33) - case UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_R8; *glFormat = GL_RED; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_RG8; *glFormat = GL_RG; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB565; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; - case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB8; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGB5_A1; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; - case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA4; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; - case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA8; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R32: if (texFloatSupported) *glInternalFormat = GL_R32F; *glFormat = GL_RED; *glType = GL_FLOAT; break; - case UNCOMPRESSED_R32G32B32: if (texFloatSupported) *glInternalFormat = GL_RGB32F; *glFormat = GL_RGB; *glType = GL_FLOAT; break; - case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) *glInternalFormat = GL_RGBA32F; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; - #endif - #if !defined(GRAPHICS_API_OPENGL_11) - case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; - case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; - case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; - case COMPRESSED_DXT5_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; - case COMPRESSED_ETC1_RGB: if (texCompETC1Supported) *glInternalFormat = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3 - case COMPRESSED_ETC2_RGB: if (texCompETC2Supported) *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 - case COMPRESSED_ETC2_EAC_RGBA: if (texCompETC2Supported) *glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 - case COMPRESSED_PVRT_RGB: if (texCompPVRTSupported) *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU - case COMPRESSED_PVRT_RGBA: if (texCompPVRTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU - case COMPRESSED_ASTC_4x4_RGBA: if (texCompASTCSupported) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 - case COMPRESSED_ASTC_8x8_RGBA: if (texCompASTCSupported) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 - #endif - default: TraceLog(LOG_WARNING, "Texture format not supported"); break; - } -} - #if defined(GRAPHICS_API_OPENGL_11) // Mipmaps data is generated after image data // NOTE: Only works with RGBA (4 bytes) data! diff --git a/src/textures.c b/src/textures.c index a7b9d3e2..bffe347a 100644 --- a/src/textures.c +++ b/src/textures.c @@ -148,6 +148,7 @@ static Image LoadPKM(const char *fileName); // Load PKM file #endif #if defined(SUPPORT_FILEFORMAT_KTX) static Image LoadKTX(const char *fileName); // Load KTX file +static void SaveKTX(Image image, const char *fileName); // Save image data as KTX file #endif #if defined(SUPPORT_FILEFORMAT_PVR) static Image LoadPVR(const char *fileName); // Load PVR file @@ -726,10 +727,11 @@ void ExportImage(Image image, const char *fileName) if (IsFileExtension(fileName, ".png")) success = stbi_write_png(fileName, image.width, image.height, 4, imgData, image.width*4); else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, 4, imgData); else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, 4, imgData); - else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, 4, imgData, 80); // Between 1 and 100 + else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, 4, imgData, 80); // JPG quality: between 1 and 100 + else if (IsFileExtension(fileName, ".ktx")) SaveKTX(image, fileName); else if (IsFileExtension(fileName, ".raw")) { - // Export raw pixel data + // Export raw pixel data (without header) // NOTE: It's up to the user to track image parameters FILE *rawFile = fopen(fileName, "wb"); fwrite(image.data, GetPixelDataSize(image.width, image.height, image.format), 1, rawFile); @@ -2932,6 +2934,93 @@ static Image LoadKTX(const char *fileName) return image; } + +// Save image data as KTX file +// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018) +static void SaveKTX(Image image, const char *fileName) +{ + // KTX file Header (64 bytes) + // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ + // v2.0 - http://github.khronos.org/KTX-Specification/ - still on draft, not ready for implementation + + typedef struct { + char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n" + unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04 + unsigned int glType; // For compressed textures, glType must equal 0 + unsigned int glTypeSize; // For compressed texture data, usually 1 + unsigned int glFormat; // For compressed textures is 0 + unsigned int glInternalFormat; // Compressed internal format + unsigned int glBaseInternalFormat; // Same as glFormat (RGB, RGBA, ALPHA...) // KTX 2.0: UInt32 vkFormat + unsigned int width; // Texture image width in pixels + unsigned int height; // Texture image height in pixels + unsigned int depth; // For 2D textures is 0 + unsigned int elements; // Number of array elements, usually 0 + unsigned int faces; // Cubemap faces, for no-cubemap = 1 + unsigned int mipmapLevels; // Non-mipmapped textures = 1 + unsigned int keyValueDataSize; // Used to encode any arbitrary data... // KTX 2.0: UInt32 levelOrder - ordering of the mipmap levels, usually 0 + // KTX 2.0: UInt32 supercompressionScheme - 0 (None), 1 (Crunch CRN), 2 (Zlib DEFLATE)... + // KTX 2.0 defines additional header elements... + } KTXHeader; + + // NOTE: Before start of every mipmap data block, we have: unsigned int dataSize + + FILE *ktxFile = fopen(fileName, "wb"); + + if (ktxFile == NULL) TraceLog(LOG_WARNING, "[%s] KTX image file could not be created", fileName); + else + { + KTXHeader ktxHeader; + + // KTX identifier (v2.2) + //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' }; + //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; + + // Get the image header + strcpy(ktxHeader.id, "«KTX 11»\r\n\x1A\n"); // KTX 1.1 signature + ktxHeader.endianness = 0; + ktxHeader.glType = 0; // Obtained from image.format + ktxHeader.glTypeSize = 1; + ktxHeader.glFormat = 0; // Obtained from image.format + ktxHeader.glInternalFormat = 0; // Obtained from image.format + ktxHeader.glBaseInternalFormat = 0; + ktxHeader.width = image.width; + ktxHeader.height = image.height; + ktxHeader.depth = 0; + ktxHeader.elements = 0; + ktxHeader.faces = 1; + ktxHeader.mipmapLevels = image.mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats) + ktxHeader.keyValueDataSize = 0; // No extra data after the header + + rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function + ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only + + // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC + + if (ktxHeader.glFormat == -1) TraceLog(LOG_WARNING, "Image format not supported for KTX export."); + else + { + fwrite(&ktxHeader, 1, sizeof(KTXHeader), ktxFile); + + int width = image.width; + int height = image.height; + int dataOffset = 0; + + // Save all mipmaps data + for (int i = 0; i < image.mipmaps; i++) + { + unsigned int dataSize = GetPixelDataSize(width, height, image.format); + fwrite(&dataSize, 1, sizeof(unsigned int), ktxFile); + fwrite(image.data + dataOffset, 1, dataSize, ktxFile); + + width /= 2; + height /= 2; + dataOffset += dataSize; + } + } + + fclose(ktxFile); // Close file pointer + } +} #endif #if defined(SUPPORT_FILEFORMAT_PVR) -- cgit v1.2.3 From 589152b658b68065495087fc4174eb5a6d447b74 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 1 Oct 2018 15:45:01 +0200 Subject: Review void pointer incrementation --- src/textures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/textures.c b/src/textures.c index bffe347a..3099bf65 100644 --- a/src/textures.c +++ b/src/textures.c @@ -3010,7 +3010,7 @@ static void SaveKTX(Image image, const char *fileName) { unsigned int dataSize = GetPixelDataSize(width, height, image.format); fwrite(&dataSize, 1, sizeof(unsigned int), ktxFile); - fwrite(image.data + dataOffset, 1, dataSize, ktxFile); + fwrite((unsigned char *)image.data + dataOffset, 1, dataSize, ktxFile); width /= 2; height /= 2; -- cgit v1.2.3 From 35634f37c85ddc0e0f78b8e007250fa0acbd2365 Mon Sep 17 00:00:00 2001 From: Pablo Marcos Oltra Date: Sun, 23 Sep 2018 13:55:39 +0200 Subject: Fix physac's fixed time step --- examples/physac/physics_restitution.c | 3 ++ src/physac.h | 71 +++++++++++++++++------------------ 2 files changed, 37 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/examples/physac/physics_restitution.c b/examples/physac/physics_restitution.c index d2ec49db..197e6eb5 100644 --- a/examples/physac/physics_restitution.c +++ b/examples/physac/physics_restitution.c @@ -51,6 +51,9 @@ int main() circleC->restitution = 1; SetTargetFPS(60); + + // Restitution demo needs a very tiny physics time step for a proper simulation + SetPhysicsTimeStep(1.0/60.0/100 * 1000); //-------------------------------------------------------------------------------------- // Main game loop diff --git a/src/physac.h b/src/physac.h index 38789a6d..ab975e28 100644 --- a/src/physac.h +++ b/src/physac.h @@ -96,8 +96,6 @@ #define PHYSAC_MAX_VERTICES 24 #define PHYSAC_CIRCLE_VERTICES 24 -#define PHYSAC_DESIRED_DELTATIME 1.0/60.0 -#define PHYSAC_MAX_TIMESTEP 0.02 #define PHYSAC_COLLISION_ITERATIONS 100 #define PHYSAC_PENETRATION_ALLOWANCE 0.05f #define PHYSAC_PENETRATION_CORRECTION 0.4f @@ -197,6 +195,7 @@ extern "C" { // Prevents name mangling of fun //---------------------------------------------------------------------------------- PHYSACDEF void InitPhysics(void); // Initializes physics values, pointers and creates physics loop thread PHYSACDEF void RunPhysicsStep(void); // Run physics step, to be used if PHYSICS_NO_THREADS is set in your main loop +PHYSACDEF void SetPhysicsTimeStep(double delta); // Sets physics fixed time step in milliseconds. 1.666666 by default PHYSACDEF bool IsPhysicsEnabled(void); // Returns true if physics thread is currently enabled PHYSACDEF void SetPhysicsGravity(float x, float y); // Sets physics global gravity force PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density); // Creates a new circle physics body with generic parameters @@ -279,16 +278,15 @@ static pthread_t physicsThreadId; // Physics thread id #endif static unsigned int usedMemory = 0; // Total allocated dynamic memory static bool physicsThreadEnabled = false; // Physics thread enabled state - static double baseTime = 0.0; // Offset time for MONOTONIC clock static double startTime = 0.0; // Start time in milliseconds -static double deltaTime = 0.0; // Delta time used for physics steps +static double deltaTime = 1.0/60.0/10.0 * 1000; // Delta time used for physics steps, in milliseconds static double currentTime = 0.0; // Current time in milliseconds static uint64_t frequency = 0; // Hi-res clock frequency static double accumulator = 0.0; // Physics time step delta time accumulator static unsigned int stepsCount = 0; // Total physics steps processed -static Vector2 gravityForce = { 0.0f, 9.81f/1000 }; // Physics world gravity force +static Vector2 gravityForce = { 0.0f, 9.81f }; // Physics world gravity force static PhysicsBody bodies[PHYSAC_MAX_BODIES]; // Physics bodies pointers array static unsigned int physicsBodiesCount = 0; // Physics world current bodies counter static PhysicsManifold contacts[PHYSAC_MAX_MANIFOLDS]; // Physics bodies pointers array @@ -322,13 +320,12 @@ static bool BiasGreaterThan(float valueA, float valueB); static Vector2 TriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3); // Returns the barycenter of a triangle given by 3 points static void InitTimer(void); // Initializes hi-resolution MONOTONIC timer -static uint64_t GetTimeCount(void); // Get hi-res MONOTONIC time measure in seconds -static double GetCurrentTime(void); // // Get hi-res MONOTONIC time measure in seconds +static uint64_t GetTimeCount(void); // Get hi-res MONOTONIC time measure in mseconds +static double GetCurrentTime(void); // Get current time measure in milliseconds static int GetRandomNumber(int min, int max); // Returns a random number between min and max (both included) // Math functions -static void MathClamp(double *value, double min, double max); // Clamp a value in a range static Vector2 MathCross(float value, Vector2 vector); // Returns the cross product of a vector and a value static float MathCrossVector2(Vector2 v1, Vector2 v2); // Returns the cross product of two vectors static float MathLenSqr(Vector2 vector); // Returns the len square root of a vector @@ -363,6 +360,8 @@ PHYSACDEF void InitPhysics(void) #if defined(PHYSAC_DEBUG) printf("[PHYSAC] physics module initialized successfully\n"); #endif + + accumulator = 0.0; } // Returns true if physics thread is currently enabled @@ -917,6 +916,18 @@ PHYSACDEF void ClosePhysics(void) #if !defined(PHYSAC_NO_THREADS) pthread_join(physicsThreadId, NULL); #endif + + // Unitialize physics manifolds dynamic memory allocations + for (int i = physicsManifoldsCount - 1; i >= 0; i--) DestroyPhysicsManifold(contacts[i]); + + // Unitialize physics bodies dynamic memory allocations + for (int i = physicsBodiesCount - 1; i >= 0; i--) DestroyPhysicsBody(bodies[i]); + + #if defined(PHYSAC_DEBUG) + if (physicsBodiesCount > 0 || usedMemory != 0) printf("[PHYSAC] physics module closed with %i still allocated bodies [MEMORY: %i bytes]\n", physicsBodiesCount, usedMemory); + else if (physicsManifoldsCount > 0 || usedMemory != 0) printf("[PHYSAC] physics module closed with %i still allocated manifolds [MEMORY: %i bytes]\n", physicsManifoldsCount, usedMemory); + else printf("[PHYSAC] physics module closed successfully\n"); + #endif } //---------------------------------------------------------------------------------- @@ -1011,7 +1022,6 @@ static void *PhysicsLoop(void *arg) // Initialize physics loop thread values physicsThreadEnabled = true; - accumulator = 0; // Physics update loop while (physicsThreadEnabled) @@ -1019,18 +1029,6 @@ static void *PhysicsLoop(void *arg) RunPhysicsStep(); } - // Unitialize physics manifolds dynamic memory allocations - for (int i = physicsManifoldsCount - 1; i >= 0; i--) DestroyPhysicsManifold(contacts[i]); - - // Unitialize physics bodies dynamic memory allocations - for (int i = physicsBodiesCount - 1; i >= 0; i--) DestroyPhysicsBody(bodies[i]); - - #if defined(PHYSAC_DEBUG) - if (physicsBodiesCount > 0 || usedMemory != 0) printf("[PHYSAC] physics module closed with %i still allocated bodies [MEMORY: %i bytes]\n", physicsBodiesCount, usedMemory); - else if (physicsManifoldsCount > 0 || usedMemory != 0) printf("[PHYSAC] physics module closed with %i still allocated manifolds [MEMORY: %i bytes]\n", physicsManifoldsCount, usedMemory); - else printf("[PHYSAC] physics module closed successfully\n"); - #endif - return NULL; } @@ -1147,17 +1145,18 @@ PHYSACDEF void RunPhysicsStep(void) currentTime = GetCurrentTime(); // Calculate current delta time - deltaTime = currentTime - startTime; + const double delta = currentTime - startTime; // Store the time elapsed since the last frame began - accumulator += deltaTime; - - // Clamp accumulator to max time step to avoid bad performance - MathClamp(&accumulator, 0.0, PHYSAC_MAX_TIMESTEP); + accumulator += delta; // Fixed time stepping loop - while (accumulator >= PHYSAC_DESIRED_DELTATIME) + while (accumulator >= deltaTime) { +#ifdef PHYSAC_DEBUG + //printf("currentTime %f, startTime %f, accumulator-pre %f, accumulator-post %f, delta %f, deltaTime %f\n", + // currentTime, startTime, accumulator, accumulator-deltaTime, delta, deltaTime); +#endif PhysicsStep(); accumulator -= deltaTime; } @@ -1166,6 +1165,11 @@ PHYSACDEF void RunPhysicsStep(void) startTime = currentTime; } +PHYSACDEF void SetPhysicsTimeStep(double delta) +{ + deltaTime = delta; +} + // Finds a valid index for a new manifold initialization static int FindAvailableManifoldIndex() { @@ -1557,8 +1561,8 @@ static void IntegratePhysicsForces(PhysicsBody body) if (body->useGravity) { - body->velocity.x += gravityForce.x*(deltaTime/2.0); - body->velocity.y += gravityForce.y*(deltaTime/2.0); + body->velocity.x += gravityForce.x*(deltaTime/1000/2.0); + body->velocity.y += gravityForce.y*(deltaTime/1000/2.0); } if (!body->freezeOrient) body->angularVelocity += body->torque*body->inverseInertia*(deltaTime/2.0); @@ -1592,7 +1596,7 @@ static void InitializePhysicsManifolds(PhysicsManifold manifold) // Determine if we should perform a resting collision or not; // The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution - if (MathLenSqr(radiusV) < (MathLenSqr((Vector2){ gravityForce.x*deltaTime, gravityForce.y*deltaTime }) + PHYSAC_EPSILON)) manifold->restitution = 0; + if (MathLenSqr(radiusV) < (MathLenSqr((Vector2){ gravityForce.x*deltaTime/1000, gravityForce.y*deltaTime/1000 }) + PHYSAC_EPSILON)) manifold->restitution = 0; } } @@ -1953,13 +1957,6 @@ static int GetRandomNumber(int min, int max) return (rand()%(abs(max - min) + 1) + min); } -// Clamp a value in a range -static inline void MathClamp(double *value, double min, double max) -{ - if (*value < min) *value = min; - else if (*value > max) *value = max; -} - // Returns the cross product of a vector and a value static inline Vector2 MathCross(float value, Vector2 vector) { -- cgit v1.2.3 From a56b3c21942737208a4f54f869b239b1d293cb00 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sun, 7 Oct 2018 00:33:05 +0200 Subject: CMake: suppress OpenGL deprecation warnings on macOS Mojave A single warning at configuration time is enough. --- src/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c86cc0e7..a8d8635f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,6 +73,10 @@ if(${PLATFORM} MATCHES "Desktop") find_library(OPENGL_LIBRARY OpenGL) set(LIBS_PRIVATE ${OPENGL_LIBRARY}) link_libraries("${LIBS_PRIVATE}") + if (NOT CMAKE_SYSTEM STRLESS "Darwin-18.0.0") + add_definitions(-DGL_SILENCE_DEPRECATION) + MESSAGE(AUTHOR_WARNING "OpenGL is deprecated starting with macOS 10.14 (Mojave)!") + endif() elseif(WIN32) add_definitions(-D_CRT_SECURE_NO_WARNINGS) else() -- cgit v1.2.3 From 6572d5ff8c3299d3915f2b3155ef2275baa971fd Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sun, 7 Oct 2018 00:34:50 +0200 Subject: raylib.h: include if available Previously, if was #included prior to another header that defined bool, the compilation would fail. This is e.g. the case for and which both fall back to the if C99 is available. The following commit includes in src/core.c, which causes the same problem. Avoid this by checking for C99 bool like we already do for C++'s. --- src/raylib.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/raylib.h b/src/raylib.h index 17c4234e..20a3ca26 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -354,11 +354,11 @@ //---------------------------------------------------------------------------------- // Structures Definition //---------------------------------------------------------------------------------- -#ifndef __cplusplus // Boolean type - #ifndef bool - typedef enum { false, true } bool; - #endif +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L + #include +#elif !defined(__cplusplus) && !defined(bool) + typedef enum { false, true } bool; #endif // Vector2 type -- cgit v1.2.3 From 1fe6d9fc06156257d5210cfa71ecb839fb190722 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sun, 7 Oct 2018 00:47:57 +0200 Subject: core: workaround window not being rendered till moved on macOS Mojave Apple ought to fix their OpenGL implementation, but with OpenGL now deprecated this might not happen. This has been reported upstream in GLFW in glfw/glfw#1334. The workaround comes from kovidgoyal/kitty@b82e74f99 This also fixes the HiDPI (Retina) scaling issues reported in #497, so the workaround is enabled anywhere __APPLE__ is defined. --- src/core.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 203da4d9..558cc854 100644 --- a/src/core.c +++ b/src/core.c @@ -134,12 +134,6 @@ #define CHDIR chdir #endif -#if defined(__linux__) || defined(PLATFORM_WEB) - #include // Required for: timespec, nanosleep(), select() - POSIX -#elif defined(__APPLE__) - #include // Required for: usleep() -#endif - #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_WEB) #define GLFW_INCLUDE_ES2 @@ -155,6 +149,15 @@ #endif #endif +#if defined(__linux__) || defined(PLATFORM_WEB) + #include // Required for: timespec, nanosleep(), select() - POSIX +#elif defined(__APPLE__) + #include // Required for: usleep() + #include // Required for: objc_msgsend(), sel_registerName() + #define GLFW_EXPOSE_NATIVE_NSGL + #include // Required for: glfwGetNSGLContext() +#endif + #if defined(PLATFORM_ANDROID) //#include // Android sensors functions (accelerometer, gyroscope, light...) #include // Defines AWINDOW_FLAG_FULLSCREEN and others @@ -233,6 +236,11 @@ static bool windowReady = false; // Check if window has been init static bool windowMinimized = false; // Check if window has been minimized static const char *windowTitle = NULL; // Window text title... +#if defined(__APPLE__) +static int windowNeedsUpdating = 2; // Times the Cocoa window needs to be updated initially +#endif + + #if defined(PLATFORM_ANDROID) static struct android_app *androidApp; // Android activity static struct android_poll_source *source; // Android events polling source @@ -2870,6 +2878,15 @@ static void SwapBuffers(void) { #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) glfwSwapBuffers(window); +#if __APPLE__ + // workaround for missing/erroneous initial rendering on macOS + if (windowNeedsUpdating) { + // Desugared version of Objective C: [glfwGetNSGLContext(window) update] + ((id (*)(id, SEL))objc_msgSend)(glfwGetNSGLContext(window), + sel_registerName("update")); + windowNeedsUpdating--; + } +#endif #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) -- cgit v1.2.3 From 2981713e4f368e1ddaca4340b0e3bafa3b41b604 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sun, 7 Oct 2018 19:09:05 +0200 Subject: CMake: accept standard -DBUILD_SHARED_LIBS as well -DBUILD_SHARED_LIBS=OFF == -DSHARED=OFF -DSTATIC=ON -DBUILD_SHARED_LIBS=ON == -DSHARED=ON -DSTATIC=OFF Fixes #626. --- src/CMakeOptions.txt | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/CMakeOptions.txt b/src/CMakeOptions.txt index 84643b28..d4ecb392 100644 --- a/src/CMakeOptions.txt +++ b/src/CMakeOptions.txt @@ -84,6 +84,14 @@ if(NOT (STATIC OR SHARED)) message(FATAL_ERROR "Nothing to do if both -DSHARED=OFF and -DSTATIC=OFF...") endif() +if (DEFINED BUILD_SHARED_LIBS) + set(SHARED ${BUILD_SHARED_LIBS}) + if (${BUILD_SHARED_LIBS}) + set(STATIC OFF) + else() + set(STATIC ON) + endif() +endif() if(DEFINED SHARED_RAYLIB) set(SHARED ${SHARED_RAYLIB}) message(DEPRECATION "-DSHARED_RAYLIB is deprecated. Please use -DSHARED instead.") -- cgit v1.2.3 From c4b7d175163f0365110b37834c58be3cf2bd1ccf Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sun, 7 Oct 2018 19:35:31 +0200 Subject: CMake: report what kind of libraries will be built --- src/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a8d8635f..9b745cfe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -150,6 +150,7 @@ include(LibraryPathToLinkerFlags) library_path_to_linker_flags(__PKG_CONFIG_LIBS_PRIVATE "${LIBS_PRIVATE}") if(STATIC) + MESSAGE(STATUS "Building raylib static library") if(${PLATFORM} MATCHES "Web") set(CMAKE_STATIC_LIBRARY_SUFFIX ".bc") endif() @@ -186,6 +187,7 @@ endif(STATIC) if(SHARED) + MESSAGE(STATUS "Building raylib shared library") add_library(raylib SHARED ${sources}) target_compile_definitions(raylib -- cgit v1.2.3 From 2feea87b616292b5bce4454a42c2d048f1cce7d8 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 12:29:02 +0200 Subject: Multiple changes, check description REVIEW: Reorganized global variables for consistency ADDED: GetWindowHandle() to get native window handle ADDED: GetDirectoryFiles() to get files list for a DIR --- src/core.c | 244 +++++++++++++++++++-------- src/external/glfw/include/GLFW/glfw3native.h | 7 +- src/raylib.h | 7 +- 3 files changed, 181 insertions(+), 77 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 558cc854..45524988 100644 --- a/src/core.c +++ b/src/core.c @@ -123,6 +123,7 @@ #include // Required for: strrchr(), strcmp() //#include // Macros for reporting and retrieving error conditions through error codes #include // Required for: tolower() [Used in IsFileExtension()] +#include // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] #if defined(_WIN32) #include // Required for: _getch(), _chdir() @@ -141,6 +142,18 @@ //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 #include // GLFW3 library: Windows, OpenGL context and Input management // NOTE: GLFW3 already includes gl.h (OpenGL) headers + + // Support retrieving native window handlers + #if defined(_WIN32) + #define GLFW_EXPOSE_NATIVE_WIN32 + #elif defined(__linux__) + #define GLFW_EXPOSE_NATIVE_X11 + //GLFW_EXPOSE_NATIVE_WAYLAND + //GLFW_EXPOSE_NATIVE_MIR + #elif defined(__APPLE__) + #define GLFW_EXPOSE_NATIVE_COCOA + #endif + #include // WARNING: It requires customization to avoid windows.h inclusion! #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) // NOTE: Those functions require linking with winmm library @@ -228,10 +241,12 @@ //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- + +// Window/Graphics related variables +//----------------------------------------------------------------------------------- #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) static GLFWwindow *window; // Native window (graphic device) #endif - static bool windowReady = false; // Check if window has been initialized successfully static bool windowMinimized = false; // Check if window has been minimized static const char *windowTitle = NULL; // Window text title... @@ -240,6 +255,31 @@ static const char *windowTitle = NULL; // Window text title... static int windowNeedsUpdating = 2; // Times the Cocoa window needs to be updated initially #endif +static unsigned int displayWidth, displayHeight;// Display width and height (monitor, device-screen, LCD, ...) +static int screenWidth, screenHeight; // Screen width and height (used render area) +static int renderWidth, renderHeight; // Framebuffer width and height (render area, including black bars if required) +static int renderOffsetX = 0; // Offset X from render area (must be divided by 2) +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_RPI) +static EGL_DISPMANX_WINDOW_T nativeWindow; // Native window (graphic device) +#endif + +#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 +static EGLConfig config; // Graphic config +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) +extern EGLNativeWindowType uwpWindow; // Native EGL window handler for UWP (external, defined in UWP App) +#endif +//----------------------------------------------------------------------------------- #if defined(PLATFORM_ANDROID) static struct android_app *androidApp; // Android activity @@ -251,104 +291,86 @@ static bool appEnabled = true; // Used to detec if app is activ static bool contextRebindRequired = false; // Used to know context rebind required #endif -#if defined(PLATFORM_RPI) -static EGL_DISPMANX_WINDOW_T nativeWindow; // Native window (graphic device) +// Inputs related variables +//----------------------------------------------------------------------------------- +// Keyboard states +static char previousKeyState[512] = { 0 }; // Registers previous frame key state +static char currentKeyState[512] = { 0 }; // Registers current frame key state +static int lastKeyPressed = -1; // Register last key pressed +static int exitKey = KEY_ESCAPE; // Default exit key (ESC) -// Keyboard input variables +#if defined(PLATFORM_RPI) // 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 +#endif + +// Mouse states +static Vector2 mousePosition; // Mouse position on screen +static float mouseScale = 1.0f; // Mouse default scale +static bool cursorHidden = false; // Track if cursor is hidden +static bool cursorOnScreen = false; // Tracks if cursor is inside client area +static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) +static char previousMouseState[3] = { 0 }; // Registers previous mouse button state +static char currentMouseState[3] = { 0 }; // Registers current mouse button state +static int previousMouseWheelY = 0; // Registers previous mouse wheel variation +static int currentMouseWheelY = 0; // Registers current mouse wheel variation +#endif -// Mouse input variables +#if defined(PLATFORM_RPI) static int mouseStream = -1; // Mouse device file descriptor static bool mouseReady = false; // Flag to know if mouse is ready static pthread_t mouseThreadId; // Mouse reading thread id - -// Touch input variables static int touchStream = -1; // Touch device file descriptor static bool touchReady = false; // Flag to know if touch interface is ready static pthread_t touchThreadId; // Touch reading thread id - -// Gamepad input variables -static int gamepadStream[MAX_GAMEPADS] = { -1 };// Gamepad device file descriptor -static pthread_t gamepadThreadId; // Gamepad reading thread id -static char gamepadName[64]; // Gamepad name holder #endif - -#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 -static EGLConfig config; // Graphic config -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) -extern EGLNativeWindowType uwpWindow; // Native EGL window handler for UWP (external, defined in UWP App) +#if defined(PLATFORM_WEB) +static bool toggleCursorLock = false; // Ask for cursor pointer lock on next click #endif -// Screen related variables -static unsigned int displayWidth, displayHeight; // Display width and height (monitor, device-screen, LCD, ...) -static int screenWidth, screenHeight; // Screen width and height (used render area) -static int renderWidth, renderHeight; // Framebuffer width and height (render area, including black bars if required) -static int renderOffsetX = 0; // Offset X from render area (must be divided by 2) -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) - -static bool cursorHidden = false; // Track if cursor is hidden -static bool cursorOnScreen = false; // Tracks if cursor is inside client area +// Gamepads states +static int lastGamepadButtonPressed = -1; // Register last gamepad button pressed +static int gamepadAxisCount = 0; // Register number of available gamepad axis #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) -// Register mouse states -static char previousMouseState[3] = { 0 }; // Registers previous mouse button state -static char currentMouseState[3] = { 0 }; // Registers current mouse button state -static int previousMouseWheelY = 0; // Registers previous mouse wheel variation -static int currentMouseWheelY = 0; // Registers current mouse wheel variation - -// Register gamepads states static bool gamepadReady[MAX_GAMEPADS] = { false }; // Flag to know if gamepad is ready static float gamepadAxisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state static char previousGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state - -// Keyboard configuration -static int exitKey = KEY_ESCAPE; // Default exit key (ESC) #endif -// Register keyboard states -static char previousKeyState[512] = { 0 }; // Registers previous frame key state -static char currentKeyState[512] = { 0 }; // Registers current frame key state - -static int lastKeyPressed = -1; // Register last key pressed -static int lastGamepadButtonPressed = -1; // Register last gamepad button pressed -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 - -static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen - -#if defined(PLATFORM_DESKTOP) -static char **dropFilesPath; // Store dropped files paths as strings -static int dropFilesCount = 0; // Count stored strings +#if defined(PLATFORM_RPI) +static int gamepadStream[MAX_GAMEPADS] = { -1 };// Gamepad device file descriptor +static pthread_t gamepadThreadId; // Gamepad reading thread id +static char gamepadName[64]; // Gamepad name holder #endif +//----------------------------------------------------------------------------------- +// Timming system variables +//----------------------------------------------------------------------------------- static double currentTime = 0.0; // Current time measure static double previousTime = 0.0; // Previous time measure static double updateTime = 0.0; // Time measure for frame update static double drawTime = 0.0; // Time measure for frame 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 +//----------------------------------------------------------------------------------- +// Config internal variables +//----------------------------------------------------------------------------------- static unsigned char configFlags = 0; // Configuration flags (bit based) static bool showLogo = false; // Track if showing logo at init is enabled +#if defined(PLATFORM_DESKTOP) +static char **dropFilesPath; // Store dropped files paths as strings +static int dropFilesCount = 0; // Count dropped files strings +#endif +static char **dirFilesPath; // Store directory files paths as strings +static int dirFilesCount = 0; // Count directory files strings + #if defined(SUPPORT_SCREEN_CAPTURE) static int screenshotCounter = 0; // Screenshots counter #endif @@ -357,6 +379,7 @@ static int screenshotCounter = 0; // Screenshots counter static int gifFramesCounter = 0; // GIF frames counter static bool gifRecording = false; // GIF recording state #endif +//----------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- // Other Modules Functions Declaration (required by core) @@ -370,15 +393,18 @@ extern void UnloadDefaultFont(void); // [Module: text] Unloads default fo // Module specific Functions Declaration //---------------------------------------------------------------------------------- static bool InitGraphicsDevice(int width, int height); // Initialize graphics device -static void SetupFramebufferSize(int displayWidth, int displayHeight); +static void SetupFramebuffer(int width, int height); // Setup main framebuffer +static void SetupViewport(void); // Set viewport parameters +static void SwapBuffers(void); // Copy back buffer to front buffers + static void InitTimer(void); // Initialize timer 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 static void PollInputEvents(void); // Register user events -static void SwapBuffers(void); // Copy back buffer to front buffers + static void LogoAnimation(void); // Plays raylib logo appearing animation -static void SetupViewport(void); // Set viewport parameters #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error @@ -391,7 +417,6 @@ static void CursorEnterCallback(GLFWwindow *window, int enter); static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored #endif - #if defined(PLATFORM_DESKTOP) static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window #endif @@ -778,6 +803,26 @@ int GetScreenHeight(void) return screenHeight; } +// Get native window handle +void *GetWindowHandle(void) +{ +#if defined(_WIN32) + // NOTE: Returned handle is: void *HWND (windows.h) + return glfwGetWin32Window(window); +#elif defined(__linux__) + // NOTE: Returned handle is: unsigned long Window (X.h) + // typedef unsigned long XID; + // typedef XID Window; + unsigned long id = (unsigned long)glfwGetX11Window(window); + return NULL; // TODO: Find a way to return value... cast to void *? +#elif defined(__APPLE__) + // NOTE: Returned handle is: void *id + return glfwGetCocoaWindow(window); +#else + return NULL; +#endif +} + // Get number of monitors int GetMonitorCount(void) { @@ -1500,6 +1545,57 @@ const char *GetWorkingDirectory(void) return currentDir; } +// Get filenames in a directory path (max 256 files) +// NOTE: Files count is returned by parameters pointer +char **GetDirectoryFiles(const char *dirPath, int *fileCount) +{ + #define MAX_FILEPATH_LENGTH 256 + #define MAX_DIRECTORY_FILES 512 + + ClearDirectoryFiles(); + + // Memory allocation for MAX_DIRECTORY_FILES + dirFilesPath = (char **)malloc(sizeof(char *)*MAX_DIRECTORY_FILES); + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)malloc(sizeof(char)*MAX_FILEPATH_LENGTH); + + int counter = 0; + struct dirent *ent; + DIR *dir = opendir(dirPath); + + if (dir != NULL) // It's a directory + { + // TODO: Reading could be done in two passes, + // first one to count files and second one to read names + // That way we can allocate required memory, instead of a limited pool + + while ((ent = readdir(dir)) != NULL) + { + strcpy(dirFilesPath[counter], ent->d_name); + counter++; + } + + closedir(dir); + } + else TraceLog(LOG_WARNING, "Can not open directory...\n"); // Maybe it's a file... + + dirFilesCount = counter; + *fileCount = dirFilesCount; + + return dirFilesPath; +} + +// Clear directory files paths buffers +void ClearDirectoryFiles(void) +{ + if (dirFilesCount > 0) + { + for (int i = 0; i < dirFilesCount; i++) free(dirFilesPath[i]); + + free(dirFilesPath); + dirFilesCount = 0; + } +} + // Change working directory, returns true if success bool ChangeDirectory(const char *dir) { @@ -2099,7 +2195,7 @@ static bool InitGraphicsDevice(int width, int height) // At this point we need to manage render size vs screen size // NOTE: This function uses and modifies global module variables: // screenWidth/screenHeight - renderWidth/renderHeight - downscaleView - SetupFramebufferSize(displayWidth, displayHeight); + SetupFramebuffer(displayWidth, displayHeight); window = glfwCreateWindow(displayWidth, displayHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); @@ -2333,7 +2429,7 @@ static bool InitGraphicsDevice(int width, int height) } } - //SetupFramebufferSize(displayWidth, displayHeight); + //SetupFramebuffer(displayWidth, displayHeight); EGLint numConfigs = 0; if ((eglChooseConfig(display, framebufferAttribs, &config, 1, &numConfigs) == EGL_FALSE) || (numConfigs == 0)) @@ -2439,7 +2535,7 @@ static bool InitGraphicsDevice(int width, int height) // At this point we need to manage render size vs screen size // NOTE: This function use and modify global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView - SetupFramebufferSize(displayWidth, displayHeight); + SetupFramebuffer(displayWidth, displayHeight); ANativeWindow_setBuffersGeometry(androidApp->window, renderWidth, renderHeight, displayFormat); //ANativeWindow_setBuffersGeometry(androidApp->window, 0, 0, displayFormat); // Force use of native display size @@ -2452,7 +2548,7 @@ static bool InitGraphicsDevice(int width, int height) // At this point we need to manage render size vs screen size // NOTE: This function use and modify global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView - SetupFramebufferSize(displayWidth, displayHeight); + SetupFramebuffer(displayWidth, displayHeight); dstRect.x = 0; dstRect.y = 0; @@ -2554,7 +2650,7 @@ static void SetupViewport(void) // Compute framebuffer size relative to screen size and display size // NOTE: Global variables renderWidth/renderHeight and renderOffsetX/renderOffsetY can be modified -static void SetupFramebufferSize(int displayWidth, int displayHeight) +static void SetupFramebuffer(int width, int height) { // Calculate renderWidth and renderHeight, we have the display size (input params) and the desired screen size (global var) if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) diff --git a/src/external/glfw/include/GLFW/glfw3native.h b/src/external/glfw/include/GLFW/glfw3native.h index 4372cb76..84bb3399 100644 --- a/src/external/glfw/include/GLFW/glfw3native.h +++ b/src/external/glfw/include/GLFW/glfw3native.h @@ -90,7 +90,12 @@ extern "C" { #undef APIENTRY #undef GLFW_APIENTRY_DEFINED #endif - #include +// RAY: Actually, only HWND handler needs to be defined +// Including windows.h could suppose symbols re-definition issues (i.e Rectangle type) +//#include + typedef void *PVOID; + typedef PVOID HANDLE; + typedef HANDLE HWND; #elif defined(GLFW_EXPOSE_NATIVE_COCOA) #include #if defined(__OBJC__) diff --git a/src/raylib.h b/src/raylib.h index 20a3ca26..6549ba1d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -814,6 +814,7 @@ RLAPI void SetWindowMinSize(int width, int height); // Set window RLAPI void SetWindowSize(int width, int height); // Set window dimensions RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height +RLAPI void *GetWindowHandle(void); // Get native window handle RLAPI int GetMonitorCount(void); // Get number of connected monitors RLAPI int GetMonitorWidth(int monitor); // Get primary monitor width RLAPI int GetMonitorHeight(int monitor); // Get primary monitor height @@ -872,10 +873,12 @@ RLAPI const char *GetExtension(const char *fileName); // Get pointer RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string RLAPI const char *GetDirectoryPath(const char *fileName); // Get full path for a given fileName (uses static string) RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) +RLAPI char **GetDirectoryFiles(const char *dirPath, int *count); // Get filenames in a directory path (memory should be freed) +RLAPI void ClearDirectoryFiles(void); // Clear directory files paths buffers (free memory) RLAPI bool ChangeDirectory(const char *dir); // Change working directory, returns true if success RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window -RLAPI char **GetDroppedFiles(int *count); // Get dropped files names -RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer +RLAPI char **GetDroppedFiles(int *count); // Get dropped files names (memory should be freed) +RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer (free memory) // Persistent storage management RLAPI void StorageSaveValue(int position, int value); // Save integer value to storage file (to defined position) -- cgit v1.2.3 From ca1e309d9d132debb40f55f57a177af085e49194 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 13:14:15 +0200 Subject: Corrected issue with GetWindowHandle() Not supported for the moment, issues with Linux (symbol `Font` redefined) and OSX (NSGL type redefined) --- src/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 45524988..e9de01d6 100644 --- a/src/core.c +++ b/src/core.c @@ -147,11 +147,11 @@ #if defined(_WIN32) #define GLFW_EXPOSE_NATIVE_WIN32 #elif defined(__linux__) - #define GLFW_EXPOSE_NATIVE_X11 + //#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type //GLFW_EXPOSE_NATIVE_WAYLAND //GLFW_EXPOSE_NATIVE_MIR #elif defined(__APPLE__) - #define GLFW_EXPOSE_NATIVE_COCOA + //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: NSGL typedef redefinition with different types ('struct objc_object *' vs 'void *') > glfw3native issue? #endif #include // WARNING: It requires customization to avoid windows.h inclusion! @@ -813,11 +813,11 @@ void *GetWindowHandle(void) // NOTE: Returned handle is: unsigned long Window (X.h) // typedef unsigned long XID; // typedef XID Window; - unsigned long id = (unsigned long)glfwGetX11Window(window); + //unsigned long id = (unsigned long)glfwGetX11Window(window); return NULL; // TODO: Find a way to return value... cast to void *? #elif defined(__APPLE__) // NOTE: Returned handle is: void *id - return glfwGetCocoaWindow(window); + return NULL; //glfwGetCocoaWindow(window); #else return NULL; #endif -- cgit v1.2.3 From 97f6454982e439850ff86b2552c9c6b4e0d8076b Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 13:29:42 +0200 Subject: Corrected issue with native handler on OSX --- src/core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index e9de01d6..f1505691 100644 --- a/src/core.c +++ b/src/core.c @@ -145,15 +145,14 @@ // Support retrieving native window handlers #if defined(_WIN32) - #define GLFW_EXPOSE_NATIVE_WIN32 + #define GLFW_EXPOSE_NATIVE_WIN32 + #include // WARNING: It requires customization to avoid windows.h inclusion! #elif defined(__linux__) //#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type //GLFW_EXPOSE_NATIVE_WAYLAND //GLFW_EXPOSE_NATIVE_MIR - #elif defined(__APPLE__) - //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: NSGL typedef redefinition with different types ('struct objc_object *' vs 'void *') > glfw3native issue? #endif - #include // WARNING: It requires customization to avoid windows.h inclusion! + #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) // NOTE: Those functions require linking with winmm library @@ -167,8 +166,9 @@ #elif defined(__APPLE__) #include // Required for: usleep() #include // Required for: objc_msgsend(), sel_registerName() + #define GLFW_EXPOSE_NATIVE_COCOA #define GLFW_EXPOSE_NATIVE_NSGL - #include // Required for: glfwGetNSGLContext() + #include // Required for: glfwGetCocoaWindow(), glfwGetNSGLContext() #endif #if defined(PLATFORM_ANDROID) @@ -817,7 +817,7 @@ void *GetWindowHandle(void) return NULL; // TODO: Find a way to return value... cast to void *? #elif defined(__APPLE__) // NOTE: Returned handle is: void *id - return NULL; //glfwGetCocoaWindow(window); + return glfwGetCocoaWindow(window); #else return NULL; #endif -- cgit v1.2.3 From 2d324f22a7d0e91ce5592f9529d92791797ee7df Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 16:12:09 +0200 Subject: Corrected issue with native window handler on OSX Could not be retrieved for now... --- src/core.c | 65 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index f1505691..1324b883 100644 --- a/src/core.c +++ b/src/core.c @@ -135,42 +135,38 @@ #define CHDIR chdir #endif -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - #if defined(PLATFORM_WEB) - #define GLFW_INCLUDE_ES2 - #endif +#if defined(PLATFORM_DESKTOP) //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 #include // GLFW3 library: Windows, OpenGL context and Input management // NOTE: GLFW3 already includes gl.h (OpenGL) headers - + // Support retrieving native window handlers #if defined(_WIN32) #define GLFW_EXPOSE_NATIVE_WIN32 #include // WARNING: It requires customization to avoid windows.h inclusion! + + #if !defined(SUPPORT_BUSY_WAIT_LOOP) + // NOTE: Those functions require linking with winmm library + unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); + unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); + #endif #elif defined(__linux__) - //#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type - //GLFW_EXPOSE_NATIVE_WAYLAND - //GLFW_EXPOSE_NATIVE_MIR - #endif - - - #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) - // NOTE: Those functions require linking with winmm library - unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); - unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); + #include // Required for: timespec, nanosleep(), select() - POSIX + + //#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type + //#define GLFW_EXPOSE_NATIVE_WAYLAND + //#define GLFW_EXPOSE_NATIVE_MIR + #include // Required for: glfwGetX11Window() + #elif defined(__APPLE__) + #include // Required for: usleep() + #include // Required for: objc_msgsend(), sel_registerName() + + //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: typedef redefinition with different types ('void *' vs 'struct objc_object *') + #define GLFW_EXPOSE_NATIVE_NSGL + #include // Required for: glfwGetCocoaWindow(), glfwGetNSGLContext() #endif #endif -#if defined(__linux__) || defined(PLATFORM_WEB) - #include // Required for: timespec, nanosleep(), select() - POSIX -#elif defined(__APPLE__) - #include // Required for: usleep() - #include // Required for: objc_msgsend(), sel_registerName() - #define GLFW_EXPOSE_NATIVE_COCOA - #define GLFW_EXPOSE_NATIVE_NSGL - #include // Required for: glfwGetCocoaWindow(), glfwGetNSGLContext() -#endif - #if defined(PLATFORM_ANDROID) //#include // Android sensors functions (accelerometer, gyroscope, light...) #include // Defines AWINDOW_FLAG_FULLSCREEN and others @@ -205,8 +201,12 @@ #endif #if defined(PLATFORM_WEB) - #include - #include + #define GLFW_INCLUDE_ES2 // GLFW3: Enable OpenGL ES 2.0 (translated to WebGL) + #include // GLFW3 library: Windows, OpenGL context and Input management + #include // Required for: timespec, nanosleep(), select() - POSIX + + #include // Emscripten library - LLVM to JavaScript compiler + #include // Emscripten HTML5 library #endif //---------------------------------------------------------------------------------- @@ -817,7 +817,7 @@ void *GetWindowHandle(void) return NULL; // TODO: Find a way to return value... cast to void *? #elif defined(__APPLE__) // NOTE: Returned handle is: void *id - return glfwGetCocoaWindow(window); + return NULL; //glfwGetCocoaWindow(window); // #else return NULL; #endif @@ -2975,11 +2975,12 @@ static void SwapBuffers(void) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) glfwSwapBuffers(window); #if __APPLE__ - // workaround for missing/erroneous initial rendering on macOS - if (windowNeedsUpdating) { + // Workaround for missing/erroneous initial rendering on macOS + if (windowNeedsUpdating) + { // Desugared version of Objective C: [glfwGetNSGLContext(window) update] - ((id (*)(id, SEL))objc_msgSend)(glfwGetNSGLContext(window), - sel_registerName("update")); + ((id (*)(id, SEL))objc_msgSend)(glfwGetNSGLContext(window), sel_registerName("update")); + windowNeedsUpdating--; } #endif -- cgit v1.2.3 From 6e4bd60978d880d57808317e0890f14614dcc215 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 16:25:47 +0200 Subject: Trying to include dirent.h for MSVC --- src/core.c | 7 ++- src/external/dirent.h | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/external/dirent.h (limited to 'src') diff --git a/src/core.c b/src/core.c index 1324b883..bd21c143 100644 --- a/src/core.c +++ b/src/core.c @@ -123,7 +123,12 @@ #include // Required for: strrchr(), strcmp() //#include // Macros for reporting and retrieving error conditions through error codes #include // Required for: tolower() [Used in IsFileExtension()] -#include // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] + +#if defined(_MSC_VER) + #include // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] +#else + #include // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] +#endif #if defined(_WIN32) #include // Required for: _getch(), _chdir() diff --git a/src/external/dirent.h b/src/external/dirent.h new file mode 100644 index 00000000..2d7a1b73 --- /dev/null +++ b/src/external/dirent.h @@ -0,0 +1,127 @@ +/* + * DIRENT.H (formerly DIRLIB.H) + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within the package. + * + */ + +#ifndef _DIRENT_H_ +#define _DIRENT_H_ + +/* All the headers include this file. */ +#include + +#include + +#ifndef RC_INVOKED + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +struct dirent +{ + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + char d_name[260]; /* [FILENAME_MAX] */ /* File name. */ +}; + +/* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + * dd_stat field is now int (was short in older versions). + */ +typedef struct +{ + /* disk transfer area for this dir */ + struct _finddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /* _findnext handle */ + intptr_t dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + char dd_name[1]; +} DIR; + +DIR* __cdecl __MINGW_NOTHROW opendir (const char*); +struct dirent* __cdecl __MINGW_NOTHROW readdir (DIR*); +int __cdecl __MINGW_NOTHROW closedir (DIR*); +void __cdecl __MINGW_NOTHROW rewinddir (DIR*); +long __cdecl __MINGW_NOTHROW telldir (DIR*); +void __cdecl __MINGW_NOTHROW seekdir (DIR*, long); + + +/* wide char versions */ + +struct _wdirent +{ + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + wchar_t d_name[260]; /* [FILENAME_MAX] */ /* File name. */ +}; + +/* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + */ +typedef struct +{ + /* disk transfer area for this dir */ + struct _wfinddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct _wdirent dd_dir; + + /* _findnext handle */ + intptr_t dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + wchar_t dd_name[1]; +} _WDIR; + +_WDIR* __cdecl __MINGW_NOTHROW _wopendir (const wchar_t*); +struct _wdirent* __cdecl __MINGW_NOTHROW _wreaddir (_WDIR*); +int __cdecl __MINGW_NOTHROW _wclosedir (_WDIR*); +void __cdecl __MINGW_NOTHROW _wrewinddir (_WDIR*); +long __cdecl __MINGW_NOTHROW _wtelldir (_WDIR*); +void __cdecl __MINGW_NOTHROW _wseekdir (_WDIR*, long); + + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#endif /* Not RC_INVOKED */ + +#endif /* Not _DIRENT_H_ */ + -- cgit v1.2.3 From 81d28c5784f300b0d2437b004a09fd0fe391dda9 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 16:55:01 +0200 Subject: dirent.h implementation for MSVC This implementation is a bit limited, does not support wide characters directories but it's a temporal solution... This solution uses "io.h" (like MinGW provided one) while other modern solutions use the "windows.h", that result in duplicate symbols issues... need to review it carefully. --- src/external/dirent.h | 266 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 169 insertions(+), 97 deletions(-) (limited to 'src') diff --git a/src/external/dirent.h b/src/external/dirent.h index 2d7a1b73..70973fb2 100644 --- a/src/external/dirent.h +++ b/src/external/dirent.h @@ -1,127 +1,199 @@ -/* - * DIRENT.H (formerly DIRLIB.H) - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within the package. - * - */ - -#ifndef _DIRENT_H_ -#define _DIRENT_H_ - -/* All the headers include this file. */ -#include +#ifndef DIRENT_H +#define DIRENT_H -#include +/* -#ifndef RC_INVOKED + Declaration of POSIX directory browsing functions and types for Win32. -#pragma pack(push,_CRT_PACKING) + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + Rights: See end of file. + +*/ #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif +typedef struct DIR DIR; + struct dirent { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - char d_name[260]; /* [FILENAME_MAX] */ /* File name. */ + char *d_name; }; +DIR *opendir(const char *); +int closedir(DIR *); +struct dirent *readdir(DIR *); +void rewinddir(DIR *); + /* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - * dd_stat field is now int (was short in older versions). - */ -typedef struct -{ - /* disk transfer area for this dir */ - struct _finddata_t dd_dta; - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. - /* _findnext handle */ - intptr_t dd_handle; +*/ - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; +#ifdef __cplusplus +} +#endif + +#endif // DIRENT_H + +/* + + Implementation of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003 and July 2012. + Rights: See end of file. - /* given path for dir with search pattern (struct is extended) */ - char dd_name[1]; -} DIR; +*/ -DIR* __cdecl __MINGW_NOTHROW opendir (const char*); -struct dirent* __cdecl __MINGW_NOTHROW readdir (DIR*); -int __cdecl __MINGW_NOTHROW closedir (DIR*); -void __cdecl __MINGW_NOTHROW rewinddir (DIR*); -long __cdecl __MINGW_NOTHROW telldir (DIR*); -void __cdecl __MINGW_NOTHROW seekdir (DIR*, long); +#include +#include +#include /* _findfirst and _findnext set errno iff they return -1 */ +#include +#include +#ifdef __cplusplus +extern "C" +{ +#endif -/* wide char versions */ +typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ -struct _wdirent +struct DIR { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - wchar_t d_name[260]; /* [FILENAME_MAX] */ /* File name. */ + handle_type handle; /* -1 for failed rewind */ + struct _finddata_t info; + struct dirent result; /* d_name null iff first time */ + char *name; /* null-terminated char string */ }; -/* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - */ -typedef struct +DIR *opendir(const char *name) +{ + DIR *dir = 0; + + if(name && name[0]) + { + size_t base_length = strlen(name); + const char *all = /* search pattern must end with suitable wildcard */ + strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if((dir = (DIR *) malloc(sizeof *dir)) != 0 && + (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) + { + strcat(strcpy(dir->name, name), all); + + if((dir->handle = + (handle_type) _findfirst(dir->name, &dir->info)) != -1) + { + dir->result.d_name = 0; + } + else /* rollback */ + { + free(dir->name); + free(dir); + dir = 0; + } + } + else /* rollback */ + { + free(dir); + dir = 0; + errno = ENOMEM; + } + } + else + { + errno = EINVAL; + } + + return dir; +} + +int closedir(DIR *dir) +{ + int result = -1; + + if(dir) + { + if(dir->handle != -1) + { + result = _findclose(dir->handle); + } + + free(dir->name); + free(dir); + } + + if(result == -1) /* map all errors to EBADF */ + { + errno = EBADF; + } + + return result; +} + +struct dirent *readdir(DIR *dir) +{ + struct dirent *result = 0; + + if(dir && dir->handle != -1) + { + if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) + { + result = &dir->result; + result->d_name = dir->info.name; + } + } + else + { + errno = EBADF; + } + + return result; +} + +void rewinddir(DIR *dir) { - /* disk transfer area for this dir */ - struct _wfinddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct _wdirent dd_dir; - - /* _findnext handle */ - intptr_t dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - wchar_t dd_name[1]; -} _WDIR; - -_WDIR* __cdecl __MINGW_NOTHROW _wopendir (const wchar_t*); -struct _wdirent* __cdecl __MINGW_NOTHROW _wreaddir (_WDIR*); -int __cdecl __MINGW_NOTHROW _wclosedir (_WDIR*); -void __cdecl __MINGW_NOTHROW _wrewinddir (_WDIR*); -long __cdecl __MINGW_NOTHROW _wtelldir (_WDIR*); -void __cdecl __MINGW_NOTHROW _wseekdir (_WDIR*, long); - - -#ifdef __cplusplus + if(dir && dir->handle != -1) + { + _findclose(dir->handle); + dir->handle = (handle_type) _findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + } + else + { + errno = EBADF; + } +} + +#ifdef __cplusplus } #endif -#pragma pack(pop) +/* + + Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved. -#endif /* Not RC_INVOKED */ + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. -#endif /* Not _DIRENT_H_ */ + But that said, if there are any problems please get in touch. +*/ -- cgit v1.2.3 From 2652e7d1c1051852e7f2ebf0e71396ac645c6713 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 18:08:39 +0200 Subject: Avoid multiple gl.h inclusions Expose native Cocoa Window again... --- src/core.c | 9 +++++---- src/external/glfw/include/GLFW/glfw3native.h | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index bd21c143..356e6821 100644 --- a/src/core.c +++ b/src/core.c @@ -141,7 +141,8 @@ #endif #if defined(PLATFORM_DESKTOP) - //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 + #define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 + // NOTE: Already provided by rlgl implementation (on glad.h) #include // GLFW3 library: Windows, OpenGL context and Input management // NOTE: GLFW3 already includes gl.h (OpenGL) headers @@ -166,7 +167,7 @@ #include // Required for: usleep() #include // Required for: objc_msgsend(), sel_registerName() - //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: typedef redefinition with different types ('void *' vs 'struct objc_object *') + #define GLFW_EXPOSE_NATIVE_COCOA #define GLFW_EXPOSE_NATIVE_NSGL #include // Required for: glfwGetCocoaWindow(), glfwGetNSGLContext() #endif @@ -821,8 +822,8 @@ void *GetWindowHandle(void) //unsigned long id = (unsigned long)glfwGetX11Window(window); return NULL; // TODO: Find a way to return value... cast to void *? #elif defined(__APPLE__) - // NOTE: Returned handle is: void *id - return NULL; //glfwGetCocoaWindow(window); // + // NOTE: Returned handle is: (objc_object *) + return (void *)glfwGetCocoaWindow(window); #else return NULL; #endif diff --git a/src/external/glfw/include/GLFW/glfw3native.h b/src/external/glfw/include/GLFW/glfw3native.h index 84bb3399..463a7a71 100644 --- a/src/external/glfw/include/GLFW/glfw3native.h +++ b/src/external/glfw/include/GLFW/glfw3native.h @@ -101,7 +101,10 @@ extern "C" { #if defined(__OBJC__) #import #else - typedef void* id; + // RAY: Added protection in case OBJC types defined + #if !defined(OBJC_TYPES_DEFINED) + typedef void* id; + #endif #endif #elif defined(GLFW_EXPOSE_NATIVE_X11) #include -- cgit v1.2.3 From 717cf77129bd30099e489a29ae19dc053923264d Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 18:38:39 +0200 Subject: Corrected issue with dirent.h inclusion... ...and MacOSX OBJC types definition... --- src/core.c | 2 +- src/external/glfw/include/GLFW/glfw3native.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 356e6821..cdbed2f8 100644 --- a/src/core.c +++ b/src/core.c @@ -125,7 +125,7 @@ #include // Required for: tolower() [Used in IsFileExtension()] #if defined(_MSC_VER) - #include // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] + #include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] #else #include // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] #endif diff --git a/src/external/glfw/include/GLFW/glfw3native.h b/src/external/glfw/include/GLFW/glfw3native.h index 463a7a71..d585496c 100644 --- a/src/external/glfw/include/GLFW/glfw3native.h +++ b/src/external/glfw/include/GLFW/glfw3native.h @@ -102,7 +102,7 @@ extern "C" { #import #else // RAY: Added protection in case OBJC types defined - #if !defined(OBJC_TYPES_DEFINED) + #if !OBJC_TYPES_DEFINED typedef void* id; #endif #endif -- cgit v1.2.3 From 4f5937e89bc0cfddd6c3a36292d3262a9b75de92 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 18:51:41 +0200 Subject: OSX native window keeps breaking... --- src/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index cdbed2f8..f9de55e5 100644 --- a/src/core.c +++ b/src/core.c @@ -167,7 +167,7 @@ #include // Required for: usleep() #include // Required for: objc_msgsend(), sel_registerName() - #define GLFW_EXPOSE_NATIVE_COCOA + //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition #define GLFW_EXPOSE_NATIVE_NSGL #include // Required for: glfwGetCocoaWindow(), glfwGetNSGLContext() #endif @@ -823,7 +823,7 @@ void *GetWindowHandle(void) return NULL; // TODO: Find a way to return value... cast to void *? #elif defined(__APPLE__) // NOTE: Returned handle is: (objc_object *) - return (void *)glfwGetCocoaWindow(window); + return NULL; // TODO: return (void *)glfwGetCocoaWindow(window); #else return NULL; #endif -- cgit v1.2.3 From 2320c2febf50c76f0bc45b2d24ac455d6d7fbd79 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Oct 2018 18:57:33 +0200 Subject: ADDED: ImageExtractPalette() --- src/raylib.h | 1 + src/textures.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'src') diff --git a/src/raylib.h b/src/raylib.h index 6549ba1d..2bc37906 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1024,6 +1024,7 @@ RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color color); // Resize canvas and fill with color RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) +RLAPI Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount); // Extract color palette from image to maximum size (memory should be freed) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font) RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image diff --git a/src/textures.c b/src/textures.c index 3099bf65..7ee07d12 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1445,6 +1445,57 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) } } +// Extract color palette from image to maximum size +// NOTE: Memory allocated should be freed manually! +Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount) +{ + #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) + + Color *pixels = GetImageData(image); + Color *palette = (Color *)malloc(maxPaletteSize*sizeof(Color)); + + int palCount = 0; + for (int i = 0; i < maxPaletteSize; i++) palette[i] = BLANK; // Set all colors to BLANK + + for (int i = 0; i < image.width*image.height; i++) + { + if (pixels[i].a > 0) + { + bool colorInPalette = false; + + // Check if the color is already on palette + for (int j = 0; j < maxPaletteSize; j++) + { + if (COLOR_EQUAL(pixels[i], palette[j])) + { + colorInPalette = true; + break; + } + } + + // Store color if not on the palette + if (!colorInPalette) + { + palette[palCount] = pixels[i]; // Add pixels[i] to palette + palCount++; + + // We reached the limit of colors supported by palette + if (palCount >= maxPaletteSize) + { + i = image.width*image.height; // Finish palette get + printf("WARNING: Image palette is greater than %i colors!\n", maxPaletteSize); + } + } + } + } + + free(pixels); + + *extractCount = palCount; + + return palette; +} + // Draw an image (source) within an image (destination) // TODO: Feel this function could be simplified... void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) -- cgit v1.2.3 From 555fdec9585ae116291c388ca105915da26bc968 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 9 Oct 2018 00:20:39 +0200 Subject: Corrected issues with VS2017 compilation --- projects/VS2017/examples/core_basic_window.vcxproj | 8 ++++---- projects/VS2017/examples/core_basic_window_cpp.vcxproj | 8 ++++---- src/external/dirent.h | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/projects/VS2017/examples/core_basic_window.vcxproj b/projects/VS2017/examples/core_basic_window.vcxproj index e7f28fb9..48e06e44 100644 --- a/projects/VS2017/examples/core_basic_window.vcxproj +++ b/projects/VS2017/examples/core_basic_window.vcxproj @@ -98,7 +98,7 @@ Disabled WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC - $(SolutionDir)..\..\release\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) Console @@ -115,7 +115,7 @@ Disabled WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) CompileAsC - $(SolutionDir)..\..\release\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) Console @@ -133,7 +133,7 @@ true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\release\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true @@ -155,7 +155,7 @@ true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\release\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsC true diff --git a/projects/VS2017/examples/core_basic_window_cpp.vcxproj b/projects/VS2017/examples/core_basic_window_cpp.vcxproj index 0467ee22..39a2aee7 100644 --- a/projects/VS2017/examples/core_basic_window_cpp.vcxproj +++ b/projects/VS2017/examples/core_basic_window_cpp.vcxproj @@ -97,7 +97,7 @@ Level3 Disabled WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(SolutionDir)..\..\release\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsCpp @@ -114,7 +114,7 @@ Level3 Disabled WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(SolutionDir)..\..\release\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) CompileAsCpp @@ -134,7 +134,7 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) CompileAsCpp - $(SolutionDir)..\..\release\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) Console @@ -155,7 +155,7 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) CompileAsCpp - $(SolutionDir)..\..\release\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) Console diff --git a/src/external/dirent.h b/src/external/dirent.h index 70973fb2..a955253e 100644 --- a/src/external/dirent.h +++ b/src/external/dirent.h @@ -59,7 +59,6 @@ void rewinddir(DIR *); */ -#include #include #include /* _findfirst and _findnext set errno iff they return -1 */ #include -- cgit v1.2.3 From a511337ce880f6e910cc0b5b20195c6cf1ec70e7 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Oct 2018 12:01:59 +0200 Subject: ADDED: GetFileNameWithoutExt --- src/core.c | 35 +++++++++++++++++++++++++++++++++++ src/raylib.h | 1 + 2 files changed, 36 insertions(+) (limited to 'src') diff --git a/src/core.c b/src/core.c index f9de55e5..37772e7e 100644 --- a/src/core.c +++ b/src/core.c @@ -1523,6 +1523,41 @@ const char *GetFileName(const char *filePath) return fileName + 1; } +// Get filename string without extension (memory should be freed) +const char *GetFileNameWithoutExt(const char *filePath) +{ + char *result, *lastDot, *lastSep; + + char nameDot = '.'; // Default filename to extension separator character + char pathSep = '/'; // Default filepath separator character + + // Error checks and allocate string + if (filePath == NULL) return NULL; + + // Try to allocate new string, same size as original + // NOTE: By default strlen() does not count the '\0' character + if ((result = malloc(strlen(filePath) + 1)) == NULL) return NULL; + + strcpy(result, filePath); // Make a copy of the string + + // NOTE: strrchr() returns a pointer to the last occurrence of character + lastDot = strrchr(result, nameDot); + lastSep = (pathSep == 0) ? NULL : strrchr(result, pathSep); + + if (lastDot != NULL) // Check if it has an extension separator... + { + if (lastSep != NULL) // ...and it's before the extenstion separator... + { + if (lastSep < lastDot) + { + *lastDot = '\0'; // ...then remove it + } + } + else *lastDot = '\0'; // Has extension separator with no path separator + } + + return result; // Return the modified string +} // Get directory for a given fileName (with path) const char *GetDirectoryPath(const char *fileName) diff --git a/src/raylib.h b/src/raylib.h index 2bc37906..3bd16f00 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -871,6 +871,7 @@ RLAPI int GetRandomValue(int min, int max); // Returns a r RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string +RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (memory should be freed) RLAPI const char *GetDirectoryPath(const char *fileName); // Get full path for a given fileName (uses static string) RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) RLAPI char **GetDirectoryFiles(const char *dirPath, int *count); // Get filenames in a directory path (memory should be freed) -- cgit v1.2.3 From f238b9ea3c6b2b380a07d37ebe82d7fcde4a1ce1 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Oct 2018 12:31:55 +0200 Subject: Small tweak to avoid warning --- src/audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/audio.c b/src/audio.c index 9e44d709..95e59931 100644 --- a/src/audio.c +++ b/src/audio.c @@ -2402,7 +2402,7 @@ static Wave LoadMP3(const char *fileName) // Decode an entire MP3 file in one go uint64_t totalSampleCount; - drmp3_config *config; + drmp3_config *config = NULL; wave.data = drmp3_open_and_decode_file_f32(fileName, config, &totalSampleCount); wave.channels = config->outputChannels; -- cgit v1.2.3 From 7f7f3b7cd531cdb1a52e75e364c5447653ebddb4 Mon Sep 17 00:00:00 2001 From: noshbar Date: Wed, 10 Oct 2018 21:52:50 +0200 Subject: Physac.h fix for variable array size declaration. Generating the projects using CMake, targeting VS2017, results in an error when compiling. This is due to physac.h trying to make a 'vertices' array of size 'int count', making it const does not work, either. This changes the static declaration to a malloc/free combo. Tested using the physics-demo. --- src/physac.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/physac.h b/src/physac.h index ab975e28..038361a4 100644 --- a/src/physac.h +++ b/src/physac.h @@ -606,7 +606,7 @@ PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force) { int count = vertexData.vertexCount; Vector2 bodyPos = body->position; - Vector2 vertices[count]; + Vector2 *vertices = (Vector2*)malloc(sizeof(Vector2) * count); Mat2 trans = body->shape.transform; for (int i = 0; i < count; i++) vertices[i] = vertexData.positions[i]; @@ -698,6 +698,8 @@ PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force) // Apply force to new physics body PhysicsAddForce(newBody, forceDirection); } + + free(vertices); } } } -- cgit v1.2.3 From ccaf462cbf4d56886372b720238ad8aa9718ad06 Mon Sep 17 00:00:00 2001 From: noshbar Date: Wed, 10 Oct 2018 22:28:17 +0200 Subject: GenImageFontAtlas prototype in raylib.h is incorrect. The prototype of GenImageFontAtlas() in the main raylib.h header has a set of swapped parameter names. Going through the usage of the function within raylib itself, it appears as if the correct order is: 1) charsCount 2) fontSize However, it's exposed to the world as the other way around, which may cause some major confusion. --- src/raylib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/raylib.h b/src/raylib.h index 3bd16f00..9d870255 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1075,7 +1075,7 @@ RLAPI Font GetFontDefault(void); RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) RLAPI Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load font from file with extended parameters RLAPI CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, int type); // Load font data for further use -RLAPI Image GenImageFontAtlas(CharInfo *chars, int fontSize, int charsCount, int padding, int packMethod); // Generate image font atlas using chars info +RLAPI Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) // Text drawing functions -- cgit v1.2.3 From ec6b21bd91b72650c98ac3f76059a72f274ccb60 Mon Sep 17 00:00:00 2001 From: noshbar Date: Wed, 10 Oct 2018 22:41:20 +0200 Subject: Fixes memory leak in text.c GenImageFontAtlas() allocates an array of stbrp_rect for the packing functions, but it never frees them. --- src/text.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/text.c b/src/text.c index 3dbb261b..d8fb3c98 100644 --- a/src/text.c +++ b/src/text.c @@ -527,6 +527,7 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi else TraceLog(LOG_WARNING, "Character could not be packed: %i", i); } + free(rects); free(nodes); free(context); } -- cgit v1.2.3 From 126ab49221ff4cc988ed83efc110d88e96c7f962 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Oct 2018 23:55:36 +0200 Subject: Minor tweaks --- src/core.c | 3 ++- src/rlgl.h | 14 +++++--------- src/textures.c | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 37772e7e..e99b24b5 100644 --- a/src/core.c +++ b/src/core.c @@ -1569,8 +1569,9 @@ const char *GetDirectoryPath(const char *fileName) lastSlash = strprbrk(fileName, "\\/"); if (!lastSlash) return NULL; + // NOTE: Be careful, strncpy() is not safe, it does not care about '\0' strncpy(filePath, fileName, strlen(fileName) - (strlen(lastSlash) - 1)); - filePath[strlen(fileName) - strlen(lastSlash)] = '\0'; + filePath[strlen(fileName) - strlen(lastSlash)] = '\0'; // Add '\0' manually return filePath; } diff --git a/src/rlgl.h b/src/rlgl.h index 3f5c67a9..61834f83 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1631,17 +1631,13 @@ void rlglInit(int width, int height) #elif defined(GRAPHICS_API_OPENGL_ES2) char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big const string - // NOTE: We have to duplicate string because glGetString() returns a const value - // If not duplicated, it fails in some systems (Raspberry Pi) - // Equivalent to function: char *strdup(const char *str) - char *extensionsDup; - size_t len = strlen(extensions) + 1; - void *newstr = malloc(len); - if (newstr == NULL) extensionsDup = NULL; - extensionsDup = (char *)memcpy(newstr, extensions, len); + // NOTE: We have to duplicate string because glGetString() returns a const string + int len = strlen(extensions) + 1; + char *extensionsDup = (char *)malloc(len); + strcpy(extensionsDup, extensions); // NOTE: String could be splitted using strtok() function (string.h) - // NOTE: strtok() modifies the received string, it can not be const + // NOTE: strtok() modifies the passed string, it can not be const char *extList[512]; // Allocate 512 strings pointers (2 KB) diff --git a/src/textures.c b/src/textures.c index 7ee07d12..4c276324 100644 --- a/src/textures.c +++ b/src/textures.c @@ -323,7 +323,7 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int // NOTE: fread() returns num read elements instead of bytes, // to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element) - size_t bytes = fread(image.data, 1, size, rawFile); + int bytes = fread(image.data, 1, size, rawFile); // Check if data has been read successfully if (bytes < size) -- cgit v1.2.3 From 9b25da5f98475e13359d47da4aa64a969b56dac5 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 11 Oct 2018 13:39:23 +0200 Subject: CMake: Fix build breakage trying to set OpenGL version Fixes #660. --- src/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b745cfe..21a10a64 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -125,6 +125,7 @@ elseif(${PLATFORM} MATCHES "Raspberry Pi") endif() if (${OPENGL_VERSION}) + MESSAGE(STATUS "Detected OpenGL version: ${OPENGL_VERSION}") set(${SUGGESTED_GRAPHICS} "${GRAPHICS}") if (${OPENGL_VERSION} MATCHES "3.3") set(GRAPHICS "GRAPHICS_API_OPENGL_33") @@ -135,7 +136,7 @@ if (${OPENGL_VERSION}) elseif (${OPENGL_VERSION} MATCHES "ES 2.0") set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") endif() - if (${SUGGESTED_GRAPHICS} AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}") + if ("${SUGGESTED_GRAPHICS}" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}") message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail") endif() endif() -- cgit v1.2.3 From 5945805b1567c20546ae294705454733f8c071f8 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 11 Oct 2018 13:52:25 +0200 Subject: CMake: remove erroneous status message OPENGL_VERSION is the version requested by the user, not the detected one... --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 21a10a64..005b22cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -125,7 +125,6 @@ elseif(${PLATFORM} MATCHES "Raspberry Pi") endif() if (${OPENGL_VERSION}) - MESSAGE(STATUS "Detected OpenGL version: ${OPENGL_VERSION}") set(${SUGGESTED_GRAPHICS} "${GRAPHICS}") if (${OPENGL_VERSION} MATCHES "3.3") set(GRAPHICS "GRAPHICS_API_OPENGL_33") -- cgit v1.2.3 From c2b36af60f1b2823cdeb6c8ae73a4957026d46ce Mon Sep 17 00:00:00 2001 From: ChrisDill Date: Fri, 12 Oct 2018 13:53:36 +0100 Subject: Added GetLastWriteTime to allow for file reloading - Added a function to get the last write time of a file. I used this so I can reload files or resources if the time since they were last loaded changes. --- src/core.c | 13 +++++++++++++ src/raylib.h | 1 + 2 files changed, 14 insertions(+) (limited to 'src') diff --git a/src/core.c b/src/core.c index e99b24b5..3b54c05c 100644 --- a/src/core.c +++ b/src/core.c @@ -123,6 +123,7 @@ #include // Required for: strrchr(), strcmp() //#include // Macros for reporting and retrieving error conditions through error codes #include // Required for: tolower() [Used in IsFileExtension()] +#include // Required for stat() [Used in GetLastWriteTime()] #if defined(_MSC_VER) #include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] @@ -1681,6 +1682,18 @@ void ClearDroppedFiles(void) #endif } +// Get the last write time of a file +long GetLastWriteTime(const char *fileName) +{ + struct stat result = {0}; + if (stat(fileName, &result) == 0) + { + time_t mod = result.st_mtime; + return mod; + } + return 0; +} + // Save integer value to storage file (to defined position) // NOTE: Storage positions is directly related to file memory layout (4 bytes each integer) void StorageSaveValue(int position, int value) diff --git a/src/raylib.h b/src/raylib.h index 9d870255..1765b40b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -880,6 +880,7 @@ RLAPI bool ChangeDirectory(const char *dir); // Change work RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI char **GetDroppedFiles(int *count); // Get dropped files names (memory should be freed) RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer (free memory) +RLAPI long GetLastWriteTime(const char *fileName); // Get last write time of a file // Persistent storage management RLAPI void StorageSaveValue(int position, int value); // Save integer value to storage file (to defined position) -- cgit v1.2.3 From c7b601b62465c7d38daed6fcc916bd94fdead1cf Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 13 Oct 2018 15:59:17 +0200 Subject: Renamed new PR function RENAME: GetLastWriteTime() to GetFileModTime() --- src/core.c | 11 +++++++---- src/raylib.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 3b54c05c..7162f47d 100644 --- a/src/core.c +++ b/src/core.c @@ -1682,15 +1682,18 @@ void ClearDroppedFiles(void) #endif } -// Get the last write time of a file -long GetLastWriteTime(const char *fileName) +// Get file modification time (last write time) +RLAPI long GetFileModTime(const char *fileName) { - struct stat result = {0}; + struct stat result = { 0 }; + if (stat(fileName, &result) == 0) { time_t mod = result.st_mtime; - return mod; + + return (long)mod; } + return 0; } diff --git a/src/raylib.h b/src/raylib.h index 1765b40b..e0b6a5a4 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -880,7 +880,7 @@ RLAPI bool ChangeDirectory(const char *dir); // Change work RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI char **GetDroppedFiles(int *count); // Get dropped files names (memory should be freed) RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer (free memory) -RLAPI long GetLastWriteTime(const char *fileName); // Get last write time of a file +RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time) // Persistent storage management RLAPI void StorageSaveValue(int position, int value); // Save integer value to storage file (to defined position) -- cgit v1.2.3 From cd6c36248531e9fe4b9e3220f34fd1d4a66c6533 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 13 Oct 2018 16:00:54 +0200 Subject: Corrected func name typo --- src/raymath.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/raymath.h b/src/raymath.h index 33116532..1d5e26f9 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -300,7 +300,7 @@ RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2) return result; } -// Substract two vectors +// Subtract two vectors RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) { Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; @@ -720,8 +720,8 @@ RMDEF Matrix MatrixAdd(Matrix left, Matrix right) return result; } -// Substract two matrices (left - right) -RMDEF Matrix MatrixSubstract(Matrix left, Matrix right) +// Subtract two matrices (left - right) +RMDEF Matrix MatrixSubtract(Matrix left, Matrix right) { Matrix result = MatrixIdentity(); -- cgit v1.2.3 From 68d2b0c071f29f85fd14445fa490cab9abd80d18 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 13 Oct 2018 16:30:44 +0200 Subject: Corrected description --- src/raylib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/raylib.h b/src/raylib.h index e0b6a5a4..963df077 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1021,7 +1021,7 @@ RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle -RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (bilinear filtering) +RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm) RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color color); // Resize canvas and fill with color RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image -- cgit v1.2.3 From d8331bde3a6c9781278106497be023b349b0a3fa Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Sun, 14 Oct 2018 14:14:04 +0200 Subject: Add FileExists() function --- src/core.c | 18 +++++++++++++++++- src/raylib.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 7162f47d..54a788bf 100644 --- a/src/core.c +++ b/src/core.c @@ -135,8 +135,9 @@ #include // Required for: _getch(), _chdir() #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir() #define CHDIR _chdir + #include // Required for _access() [Used in FileExists()] #else - #include "unistd.h" // Required for: getch(), chdir() (POSIX) + #include "unistd.h" // Required for: getch(), chdir() (POSIX), access() #define GETCWD getcwd #define CHDIR chdir #endif @@ -1514,6 +1515,21 @@ static const char *strprbrk(const char *s, const char *charset) return latestMatch; } +// Return true if the file exists +bool FileExists(const char *fileName) +{ + bool result = false; + +#if defined(_WIN32) + if (_access(fileName, 0) != -1) +#else + if (access(fileName, F_OK) != -1) +#endif + result = true; + + return result; +} + // Get pointer to filename for a path string const char *GetFileName(const char *filePath) { diff --git a/src/raylib.h b/src/raylib.h index 963df077..8aa5e7be 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -870,6 +870,7 @@ RLAPI int GetRandomValue(int min, int max); // Returns a r // Files management functions RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string +RLAPI bool FileExists(const char *fileName); // Return true if file exists RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (memory should be freed) RLAPI const char *GetDirectoryPath(const char *fileName); // Get full path for a given fileName (uses static string) -- cgit v1.2.3 From b8b8936cd780b34edb2899eb32b756a1aebef9d3 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 16 Oct 2018 10:53:01 +0200 Subject: Review defines --- src/audio.c | 2 +- src/core.c | 32 ++++++++++++++++---------------- src/raylib.h | 8 ++++---- src/rlgl.h | 12 ++++++------ 4 files changed, 27 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/audio.c b/src/audio.c index 95e59931..f3db1124 100644 --- a/src/audio.c +++ b/src/audio.c @@ -132,7 +132,7 @@ #include "external/dr_mp3.h" // MP3 loading functions #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) #undef bool #endif diff --git a/src/core.c b/src/core.c index 54a788bf..70a7bf68 100644 --- a/src/core.c +++ b/src/core.c @@ -125,7 +125,7 @@ #include // Required for: tolower() [Used in IsFileExtension()] #include // Required for stat() [Used in GetLastWriteTime()] -#if defined(_MSC_VER) +#if defined(_WIN32) && defined(_MSC_VER) #include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] #else #include // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] @@ -1465,6 +1465,21 @@ void TakeScreenshot(const char *fileName) #endif } +// Check if the file exists +bool FileExists(const char *fileName) +{ + bool result = false; + +#if defined(_WIN32) + if (_access(fileName, 0) != -1) +#else + if (access(fileName, F_OK) != -1) +#endif + result = true; + + return result; +} + // Check file extension bool IsFileExtension(const char *fileName, const char *ext) { @@ -1515,21 +1530,6 @@ static const char *strprbrk(const char *s, const char *charset) return latestMatch; } -// Return true if the file exists -bool FileExists(const char *fileName) -{ - bool result = false; - -#if defined(_WIN32) - if (_access(fileName, 0) != -1) -#else - if (access(fileName, F_OK) != -1) -#endif - result = true; - - return result; -} - // Get pointer to filename for a path string const char *GetFileName(const char *filePath) { diff --git a/src/raylib.h b/src/raylib.h index 8aa5e7be..42bc38e7 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -311,7 +311,7 @@ // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. -#ifdef __cplusplus +#if defined(__cplusplus) #define CLITERAL #else #define CLITERAL (Color) @@ -786,7 +786,7 @@ typedef enum { // Callbacks to be implemented by users typedef void (*TraceLogCallback)(int msgType, const char *text, va_list args); -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { // Prevents name mangling of functions #endif @@ -868,9 +868,9 @@ RLAPI void TakeScreenshot(const char *fileName); // Takes a scr RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) // Files management functions +RLAPI bool FileExists(const char *fileName); // Check if file exists RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string -RLAPI bool FileExists(const char *fileName); // Return true if file exists RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (memory should be freed) RLAPI const char *GetDirectoryPath(const char *fileName); // Get full path for a given fileName (uses static string) @@ -1277,7 +1277,7 @@ RLAPI void StopAudioStream(AudioStream stream); // Stop au RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) -#ifdef __cplusplus +#if defined(__cplusplus) } #endif diff --git a/src/rlgl.h b/src/rlgl.h index 61834f83..d2b52a47 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -378,7 +378,7 @@ typedef unsigned char byte; } VrDevice; #endif -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { // Prevents name mangling of functions #endif @@ -516,7 +516,7 @@ void TraceLog(int msgType, const char *text, ...); // Show trace log messag int GetPixelDataSize(int width, int height, int format);// Get pixel data size in bytes (image or texture) #endif -#ifdef __cplusplus +#if defined(__cplusplus) } #endif @@ -553,7 +553,7 @@ int GetPixelDataSize(int width, int height, int format);// Get pixel data size i #else // APIENTRY for OpenGL function pointer declarations is required #ifndef APIENTRY - #ifdef _WIN32 + #if defined(_WIN32) #define APIENTRY __stdcall #else #define APIENTRY @@ -1620,7 +1620,7 @@ void rlglInit(int width, int height) // NOTE: We don't need to check again supported extensions but we do (GLAD already dealt with that) glGetIntegerv(GL_NUM_EXTENSIONS, &numExt); -#ifdef _MSC_VER +#if defined(_MSC_VER) const char **extList = malloc(sizeof(const char *)*numExt); #else const char *extList[numExt]; @@ -3803,7 +3803,7 @@ static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShad glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); -#ifdef _MSC_VER +#if defined(_MSC_VER) char *log = malloc(maxLength); #else char log[maxLength]; @@ -3812,7 +3812,7 @@ static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShad TraceLog(LOG_INFO, "%s", log); -#ifdef _MSC_VER +#if defined(_MSC_VER) free(log); #endif glDeleteProgram(program); -- cgit v1.2.3 From 8a88e65a94c41006e010f22d3c78fa0ef9ec85e4 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 17 Oct 2018 19:37:53 +0200 Subject: Update src/external/dr_mp3.h --- src/external/dr_mp3.h | 322 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 237 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/external/dr_mp3.h b/src/external/dr_mp3.h index 467d319d..cd8920a1 100644 --- a/src/external/dr_mp3.h +++ b/src/external/dr_mp3.h @@ -1,5 +1,5 @@ // MP3 audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_mp3 - v0.2.5 - 2018-06-22 +// dr_mp3 - v0.3.2 - 2018-09-11 // // David Reid - mackron@gmail.com // @@ -99,28 +99,26 @@ typedef drmp3_uint32 drmp3_bool32; // ================== typedef struct { - int frame_bytes; - int channels; - int hz; - int layer; - int bitrate_kbps; + int frame_bytes, channels, hz, layer, bitrate_kbps; } drmp3dec_frame_info; typedef struct { - float mdct_overlap[2][9*32]; - float qmf_state[15*2*32]; - int reserv; - int free_format_bytes; - unsigned char header[4]; - unsigned char reserv_buf[511]; + float mdct_overlap[2][9*32], qmf_state[15*2*32]; + int reserv, free_format_bytes; + unsigned char header[4], reserv_buf[511]; } drmp3dec; // Initializes a low level decoder. void drmp3dec_init(drmp3dec *dec); // Reads a frame from a low level decoder. -int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes, short *pcm, drmp3dec_frame_info *info); +int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info); + +// Helper for converting between f32 and s16. +void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, int num_samples); + + // Main API (Pull API) @@ -220,7 +218,7 @@ typedef struct drmp3_uint32 frameSampleRate; // The sample rate of the currently loaded MP3 frame. Internal use only. drmp3_uint32 framesConsumed; drmp3_uint32 framesRemaining; - drmp3_int16 frames[DRMP3_MAX_SAMPLES_PER_FRAME]; + drmp3_uint8 frames[sizeof(float)*DRMP3_MAX_SAMPLES_PER_FRAME]; // <-- Multipled by sizeof(float) to ensure there's enough room for DR_MP3_FLOAT_OUTPUT. drmp3_src src; size_t dataSize; size_t dataCapacity; @@ -314,8 +312,12 @@ void drmp3_free(void* p); #define DR_MP3_NO_SIMD #endif +#define DRMP3_OFFSET_PTR(p, offset) ((void*)((drmp3_uint8*)(p) + (offset))) + #define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */ +#ifndef DRMP3_MAX_FRAME_SYNC_MATCHES #define DRMP3_MAX_FRAME_SYNC_MATCHES 10 +#endif #define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES DRMP3_MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */ @@ -361,7 +363,7 @@ void drmp3_free(void* p); #if defined(_MSC_VER) #include #endif -#include +#include #define DRMP3_HAVE_SSE 1 #define DRMP3_HAVE_SIMD 1 #define DRMP3_VSTORE _mm_storeu_ps @@ -462,44 +464,27 @@ static int drmp3_have_simd() typedef struct { const drmp3_uint8 *buf; - int pos; - int limit; + int pos, limit; } drmp3_bs; typedef struct { - drmp3_uint8 total_bands; - drmp3_uint8 stereo_bands; - drmp3_uint8 bitalloc[64]; - drmp3_uint8 scfcod[64]; float scf[3*64]; + drmp3_uint8 total_bands, stereo_bands, bitalloc[64], scfcod[64]; } drmp3_L12_scale_info; typedef struct { - drmp3_uint8 tab_offset; - drmp3_uint8 code_tab_width; - drmp3_uint8 band_count; + drmp3_uint8 tab_offset, code_tab_width, band_count; } drmp3_L12_subband_alloc; typedef struct { const drmp3_uint8 *sfbtab; - drmp3_uint16 part_23_length; - drmp3_uint16 big_values; - drmp3_uint16 scalefac_compress; - drmp3_uint8 global_gain; - drmp3_uint8 block_type; - drmp3_uint8 mixed_block_flag; - drmp3_uint8 n_long_sfb; - drmp3_uint8 n_short_sfb; - drmp3_uint8 table_select[3]; - drmp3_uint8 region_count[3]; - drmp3_uint8 subblock_gain[3]; - drmp3_uint8 preflag; - drmp3_uint8 scalefac_scale; - drmp3_uint8 count1_table; - drmp3_uint8 scfsi; + drmp3_uint16 part_23_length, big_values, scalefac_compress; + drmp3_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; + drmp3_uint8 table_select[3], region_count[3], subblock_gain[3]; + drmp3_uint8 preflag, scalefac_scale, count1_table, scfsi; } drmp3_L3_gr_info; typedef struct @@ -507,10 +492,8 @@ typedef struct drmp3_bs bs; drmp3_uint8 maindata[DRMP3_MAX_BITRESERVOIR_BYTES + DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES]; drmp3_L3_gr_info gr_info[4]; - float grbuf[2][576]; - float scf[40]; + float grbuf[2][576], scf[40], syn[18 + 15][2*32]; drmp3_uint8 ist_pos[2][39]; - float syn[18 + 15][2*32]; } drmp3dec_scratch; static void drmp3_bs_init(drmp3_bs *bs, const drmp3_uint8 *data, int bytes) @@ -988,17 +971,19 @@ static void drmp3_L3_decode_scalefactors(const drmp3_uint8 *hdr, drmp3_uint8 *is } } +static const float g_drmp3_pow43[129 + 16] = { + 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, + 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f +}; + static float drmp3_L3_pow_43(int x) { - static const float g_pow43[129] = { - 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f - }; float frac; int sign, mult = 256; if (x < 129) { - return g_pow43[x]; + return g_drmp3_pow43[16 + x]; } if (x < 1024) @@ -1009,12 +994,11 @@ static float drmp3_L3_pow_43(int x) sign = 2*x & 64; frac = (float)((x & 63) - sign) / ((x & ~63) + sign); - return g_pow43[(x + sign) >> 6]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; + return g_drmp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; } static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit) { - static const float g_pow43_signed[32] = { 0,0,1,-1,2.519842f,-2.519842f,4.326749f,-4.326749f,6.349604f,-6.349604f,8.549880f,-8.549880f,10.902724f,-10.902724f,13.390518f,-13.390518f,16.000000f,-16.000000f,18.720754f,-18.720754f,21.544347f,-21.544347f,24.463781f,-24.463781f,27.473142f,-27.473142f,30.567351f,-30.567351f,33.741992f,-33.741992f,36.993181f,-36.993181f }; static const drmp3_int16 tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 785,785,785,785,784,784,784,784,513,513,513,513,513,513,513,513,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256, -255,1313,1298,1282,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,290,288, @@ -1053,7 +1037,7 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g { int tab_num = gr_info->table_select[ireg]; int sfb_cnt = gr_info->region_count[ireg++]; - const short *codebook = tabs + tabindex[tab_num]; + const drmp3_int16 *codebook = tabs + tabindex[tab_num]; int linbits = g_linbits[tab_num]; do { @@ -1083,7 +1067,7 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g *dst = one*drmp3_L3_pow_43(lsb)*((int32_t)bs_cache < 0 ? -1: 1); } else { - *dst = g_pow43_signed[lsb*2 + (bs_cache >> 31)]*one; + *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; } DRMP3_FLUSH_BITS(lsb ? 1 : 0); } @@ -1659,18 +1643,27 @@ static void drmp3d_DCT_II(float *grbuf, int n) #endif } -static short drmp3d_scale_pcm(float sample) +#ifndef DR_MP3_FLOAT_OUTPUT +typedef drmp3_int16 drmp3d_sample_t; + +static drmp3_int16 drmp3d_scale_pcm(float sample) { - if (sample > 32767.0) return (short) 32767; - if (sample < -32768.0) return (short)-32768; - int s = (int)(sample + .5f); + if (sample >= 32766.5) return (drmp3_int16) 32767; + if (sample <= -32767.5) return (drmp3_int16)-32768; + drmp3_int16 s = (drmp3_int16)(sample + .5f); s -= (s < 0); /* away from zero, to be compliant */ - if (s > 32767) return (short) 32767; - if (s < -32768) return (short)-32768; - return (short)s; + return (drmp3_int16)s; } +#else +typedef float drmp3d_sample_t; -static void drmp3d_synth_pair(short *pcm, int nch, const float *z) +static float drmp3d_scale_pcm(float sample) +{ + return sample*(1.f/32768.f); +} +#endif + +static void drmp3d_synth_pair(drmp3d_sample_t *pcm, int nch, const float *z) { float a; a = (z[14*64] - z[ 0]) * 29; @@ -1695,11 +1688,11 @@ static void drmp3d_synth_pair(short *pcm, int nch, const float *z) pcm[16*nch] = drmp3d_scale_pcm(a); } -static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) +static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins) { int i; float *xr = xl + 576*(nch - 1); - short *dstr = dstl + (nch - 1); + drmp3d_sample_t *dstr = dstl + (nch - 1); static const float g_win[] = { -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992, @@ -1756,19 +1749,20 @@ static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) DRMP3_V0(0) DRMP3_V2(1) DRMP3_V1(2) DRMP3_V2(3) DRMP3_V1(4) DRMP3_V2(5) DRMP3_V1(6) DRMP3_V2(7) { +#ifndef DR_MP3_FLOAT_OUTPUT #if DRMP3_HAVE_SSE static const drmp3_f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; static const drmp3_f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); - dstr[(15 - i)*nch] = (short)_mm_extract_epi16(pcm8, 1); - dstr[(17 + i)*nch] = (short)_mm_extract_epi16(pcm8, 5); - dstl[(15 - i)*nch] = (short)_mm_extract_epi16(pcm8, 0); - dstl[(17 + i)*nch] = (short)_mm_extract_epi16(pcm8, 4); - dstr[(47 - i)*nch] = (short)_mm_extract_epi16(pcm8, 3); - dstr[(49 + i)*nch] = (short)_mm_extract_epi16(pcm8, 7); - dstl[(47 - i)*nch] = (short)_mm_extract_epi16(pcm8, 2); - dstl[(49 + i)*nch] = (short)_mm_extract_epi16(pcm8, 6); + dstr[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 1); + dstr[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 5); + dstl[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 0); + dstl[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 4); + dstr[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 3); + dstr[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 7); + dstl[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 2); + dstl[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 6); #else int16x4_t pcma, pcmb; a = DRMP3_VADD(a, DRMP3_VSET(0.5f)); @@ -1784,6 +1778,30 @@ static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2); vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); #endif +#else + static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; + a = DRMP3_VMUL(a, g_scale); + b = DRMP3_VMUL(b, g_scale); +#if DRMP3_HAVE_SSE + _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2))); + _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2))); +#else + vst1q_lane_f32(dstr + (15 - i)*nch, a, 1); + vst1q_lane_f32(dstr + (17 + i)*nch, b, 1); + vst1q_lane_f32(dstl + (15 - i)*nch, a, 0); + vst1q_lane_f32(dstl + (17 + i)*nch, b, 0); + vst1q_lane_f32(dstr + (47 - i)*nch, a, 3); + vst1q_lane_f32(dstr + (49 + i)*nch, b, 3); + vst1q_lane_f32(dstl + (47 - i)*nch, a, 2); + vst1q_lane_f32(dstl + (49 + i)*nch, b, 2); +#endif +#endif /* DR_MP3_FLOAT_OUTPUT */ } } else #endif @@ -1821,7 +1839,7 @@ static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) #endif } -static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, short *pcm, float *lins) +static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, drmp3d_sample_t *pcm, float *lins) { int i; for (i = 0; i < nch; i++) @@ -1906,7 +1924,7 @@ void drmp3dec_init(drmp3dec *dec) dec->header[0] = 0; } -int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes, short *pcm, drmp3dec_frame_info *info) +int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info) { int i = 0, igr, frame_size = 0, success = 1; const drmp3_uint8 *hdr; @@ -1940,6 +1958,11 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes info->layer = 4 - DRMP3_HDR_GET_LAYER(hdr); info->bitrate_kbps = drmp3_hdr_bitrate_kbps(hdr); + if (!pcm) + { + return drmp3_hdr_frame_samples(hdr); + } + drmp3_bs_init(bs_frame, hdr + DRMP3_HDR_SIZE, frame_size - DRMP3_HDR_SIZE); if (DRMP3_HDR_IS_CRC(hdr)) { @@ -1957,11 +1980,11 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes success = drmp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); if (success) { - for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm += 576*info->channels) + for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels)) { memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); - drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, pcm, scratch.syn[0]); + drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]); } } drmp3_L3_save_reservoir(dec, &scratch); @@ -1980,9 +2003,9 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes { i = 0; drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); - drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, pcm, scratch.syn[0]); + drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]); memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); - pcm += 384*info->channels; + pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels); } if (bs_frame->pos > bs_frame->limit) { @@ -1995,6 +2018,64 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes return success*drmp3_hdr_frame_samples(dec->header); } +void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, int num_samples) +{ + if(num_samples > 0) + { + int i = 0; +#if DRMP3_HAVE_SIMD + int aligned_count = num_samples & ~7; + for(; i < aligned_count; i+=8) + { + static const drmp3_f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f }; + drmp3_f4 a = DRMP3_VMUL(DRMP3_VLD(&in[i ]), g_scale); + drmp3_f4 b = DRMP3_VMUL(DRMP3_VLD(&in[i+4]), g_scale); +#if DRMP3_HAVE_SSE + static const drmp3_f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const drmp3_f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + out[i ] = (drmp3_int16)_mm_extract_epi16(pcm8, 0); + out[i+1] = (drmp3_int16)_mm_extract_epi16(pcm8, 1); + out[i+2] = (drmp3_int16)_mm_extract_epi16(pcm8, 2); + out[i+3] = (drmp3_int16)_mm_extract_epi16(pcm8, 3); + out[i+4] = (drmp3_int16)_mm_extract_epi16(pcm8, 4); + out[i+5] = (drmp3_int16)_mm_extract_epi16(pcm8, 5); + out[i+6] = (drmp3_int16)_mm_extract_epi16(pcm8, 6); + out[i+7] = (drmp3_int16)_mm_extract_epi16(pcm8, 7); +#else + int16x4_t pcma, pcmb; + a = DRMP3_VADD(a, DRMP3_VSET(0.5f)); + b = DRMP3_VADD(b, DRMP3_VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, DRMP3_VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, DRMP3_VSET(0))))); + vst1_lane_s16(out+i , pcma, 0); + vst1_lane_s16(out+i+1, pcma, 1); + vst1_lane_s16(out+i+2, pcma, 2); + vst1_lane_s16(out+i+3, pcma, 3); + vst1_lane_s16(out+i+4, pcmb, 0); + vst1_lane_s16(out+i+5, pcmb, 1); + vst1_lane_s16(out+i+6, pcmb, 2); + vst1_lane_s16(out+i+7, pcmb, 3); +#endif + } +#endif + for(; i < num_samples; i++) + { + float sample = in[i] * 32768.0f; + if (sample >= 32766.5) + out[i] = (drmp3_int16) 32767; + else if (sample <= -32767.5) + out[i] = (drmp3_int16)-32768; + else + { + short s = (drmp3_int16)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ + out[i] = s; + } + } + } +} @@ -2004,6 +2085,16 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes // /////////////////////////////////////////////////////////////////////////////// +#if defined(SIZE_MAX) + #define DRMP3_SIZE_MAX SIZE_MAX +#else + #if defined(_WIN64) || defined(_LP64) || defined(__LP64__) + #define DRMP3_SIZE_MAX ((drmp3_uint64)0xFFFFFFFFFFFFFFFF) + #else + #define DRMP3_SIZE_MAX 0xFFFFFFFF + #endif +#endif + // Options. #ifndef DR_MP3_DEFAULT_CHANNELS #define DR_MP3_DEFAULT_CHANNELS 2 @@ -2311,8 +2402,10 @@ static drmp3_bool32 drmp3_decode_next_frame(drmp3* pMP3) size_t bytesRead = pMP3->onRead(pMP3->pUserData, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { - pMP3->atEnd = DRMP3_TRUE; - return DRMP3_FALSE; // No data. + if (pMP3->dataSize == 0) { + pMP3->atEnd = DRMP3_TRUE; + return DRMP3_FALSE; // No data. + } } pMP3->dataSize += bytesRead; @@ -2324,7 +2417,7 @@ static drmp3_bool32 drmp3_decode_next_frame(drmp3* pMP3) } drmp3dec_frame_info info; - drmp3_uint32 samplesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData, (int)pMP3->dataSize, pMP3->frames, &info); // <-- Safe size_t -> int conversion thanks to the check above. + drmp3_uint32 samplesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData, (int)pMP3->dataSize, (drmp3d_sample_t*)pMP3->frames, &info); // <-- Safe size_t -> int conversion thanks to the check above. if (samplesRead != 0) { size_t leftoverDataSize = (pMP3->dataSize - (size_t)info.frame_bytes); for (size_t i = 0; i < leftoverDataSize; ++i) { @@ -2377,28 +2470,54 @@ static drmp3_uint64 drmp3_read_src(drmp3_src* pSRC, drmp3_uint64 frameCount, voi while (frameCount > 0) { // Read from the in-memory buffer first. while (pMP3->framesRemaining > 0 && frameCount > 0) { + drmp3d_sample_t* frames = (drmp3d_sample_t*)pMP3->frames; +#ifndef DR_MP3_FLOAT_OUTPUT + if (pMP3->frameChannels == 1) { + if (pMP3->channels == 1) { + // Mono -> Mono. + pFramesOutF[0] = frames[pMP3->framesConsumed] / 32768.0f; + } else { + // Mono -> Stereo. + pFramesOutF[0] = frames[pMP3->framesConsumed] / 32768.0f; + pFramesOutF[1] = frames[pMP3->framesConsumed] / 32768.0f; + } + } else { + if (pMP3->channels == 1) { + // Stereo -> Mono + float sample = 0; + sample += frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f; + sample += frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f; + pFramesOutF[0] = sample * 0.5f; + } else { + // Stereo -> Stereo + pFramesOutF[0] = frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f; + pFramesOutF[1] = frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f; + } + } +#else if (pMP3->frameChannels == 1) { if (pMP3->channels == 1) { // Mono -> Mono. - pFramesOutF[0] = pMP3->frames[pMP3->framesConsumed] / 32768.0f; + pFramesOutF[0] = frames[pMP3->framesConsumed]; } else { // Mono -> Stereo. - pFramesOutF[0] = pMP3->frames[pMP3->framesConsumed] / 32768.0f; - pFramesOutF[1] = pMP3->frames[pMP3->framesConsumed] / 32768.0f; + pFramesOutF[0] = frames[pMP3->framesConsumed]; + pFramesOutF[1] = frames[pMP3->framesConsumed]; } } else { if (pMP3->channels == 1) { // Stereo -> Mono float sample = 0; - sample += pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f; - sample += pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f; + sample += frames[(pMP3->framesConsumed*pMP3->frameChannels)+0]; + sample += frames[(pMP3->framesConsumed*pMP3->frameChannels)+1]; pFramesOutF[0] = sample * 0.5f; } else { // Stereo -> Stereo - pFramesOutF[0] = pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f; - pFramesOutF[1] = pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f; + pFramesOutF[0] = frames[(pMP3->framesConsumed*pMP3->frameChannels)+0]; + pFramesOutF[1] = frames[(pMP3->framesConsumed*pMP3->frameChannels)+1]; } } +#endif pMP3->framesConsumed += 1; pMP3->framesRemaining -= 1; @@ -2466,11 +2585,13 @@ drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek srcConfig.channels = pMP3->channels; srcConfig.algorithm = drmp3_src_algorithm_linear; if (!drmp3_src_init(&srcConfig, drmp3_read_src, pMP3, &pMP3->src)) { + drmp3_uninit(pMP3); return DRMP3_FALSE; } // Decode the first frame to confirm that it is indeed a valid MP3 stream. if (!drmp3_decode_next_frame(pMP3)) { + drmp3_uninit(pMP3); return DRMP3_FALSE; // Not a valid MP3 stream. } @@ -2681,7 +2802,7 @@ float* drmp3__full_decode_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp } drmp3_uint64 newFramesBufferSize = framesCapacity*pMP3->channels*sizeof(float); - if (newFramesBufferSize > SIZE_MAX) { + if (newFramesBufferSize > DRMP3_SIZE_MAX) { break; } @@ -2771,6 +2892,37 @@ void drmp3_free(void* p) // REVISION HISTORY // =============== // +// v0.3.2 - 2018-09-11 +// - Fix a couple of memory leaks. +// - Bring up to date with minimp3. +// +// v0.3.1 - 2018-08-25 +// - Fix C++ build. +// +// v0.3.0 - 2018-08-25 +// - Bring up to date with minimp3. This has a minor API change: the "pcm" parameter of drmp3dec_decode_frame() has +// been changed from short* to void* because it can now output both s16 and f32 samples, depending on whether or +// not the DR_MP3_FLOAT_OUTPUT option is set. +// +// v0.2.11 - 2018-08-08 +// - Fix a bug where the last part of a file is not read. +// +// v0.2.10 - 2018-08-07 +// - Improve 64-bit detection. +// +// v0.2.9 - 2018-08-05 +// - Fix C++ build on older versions of GCC. +// - Bring up to date with minimp3. +// +// v0.2.8 - 2018-08-02 +// - Fix compilation errors with older versions of GCC. +// +// v0.2.7 - 2018-07-13 +// - Bring up to date with minimp3. +// +// v0.2.6 - 2018-07-12 +// - Bring up to date with minimp3. +// // v0.2.5 - 2018-06-22 // - Bring up to date with minimp3. // -- cgit v1.2.3 From 8bac72f4fa7b08d77ae1c47570612e29d5007bb6 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 17 Oct 2018 19:39:16 +0200 Subject: Working on MP3 loading Loading full mp3 file works but loading for music streaming does not work, it seems total number of samples is not obtained correctly from mp3 file... --- src/audio.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/audio.c b/src/audio.c index f3db1124..fc65127b 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1463,21 +1463,25 @@ Music LoadMusicStream(const char *fileName) #if defined(SUPPORT_FILEFORMAT_MP3) else if (IsFileExtension(fileName, ".mp3")) { - drmp3_init_file(&music->ctxMp3, fileName, NULL); + int result = drmp3_init_file(&music->ctxMp3, fileName, NULL); - if (music->ctxMp3.framesRemaining <= 0) musicLoaded = false; + if (!result) musicLoaded = false; else { - music->stream = InitAudioStream(music->ctxMp3.sampleRate, 16, music->ctxMp3.channels); + TraceLog(LOG_INFO, "[%s] MP3 sample rate: %i", fileName, music->ctxMp3.sampleRate); + TraceLog(LOG_INFO, "[%s] MP3 bits per sample: %i", fileName, 32); + TraceLog(LOG_INFO, "[%s] MP3 channels: %i", fileName, music->ctxMp3.channels); + TraceLog(LOG_INFO, "[%s] MP3 frames remaining: %i", fileName, (unsigned int)music->ctxMp3.framesRemaining); + + music->stream = InitAudioStream(music->ctxMp3.sampleRate, 32, music->ctxMp3.channels); + + // TODO: It seems the total number of samples is not obtained correctly... music->totalSamples = (unsigned int)music->ctxMp3.framesRemaining*music->ctxMp3.channels; music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_MP3; music->loopCount = -1; // Infinite loop by default - - TraceLog(LOG_DEBUG, "[%s] MP3 total samples: %i", fileName, music->totalSamples); - TraceLog(LOG_DEBUG, "[%s] MP3 sample rate: %i", fileName, music->ctxMp3.sampleRate); - //TraceLog(LOG_DEBUG, "[%s] MP3 bits per sample: %i", fileName, music->ctxMp3.bitsPerSample); - TraceLog(LOG_DEBUG, "[%s] MP3 channels: %i", fileName, music->ctxMp3.channels); + + TraceLog(LOG_INFO, "[%s] MP3 total samples: %i", fileName, music->totalSamples); } } #endif @@ -1940,7 +1944,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un mal_format formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); // The size of a streaming buffer must be at least double the size of a period. - unsigned int periodSize = device.bufferSizeInFrames / device.periods; + unsigned int periodSize = device.bufferSizeInFrames/device.periods; unsigned int subBufferSize = AUDIO_BUFFER_SIZE; if (subBufferSize < periodSize) subBufferSize = periodSize; @@ -1951,7 +1955,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un return stream; } - audioBuffer->looping = true; // Always loop for streaming buffers. + audioBuffer->looping = true; // Always loop for streaming buffers. stream.audioBuffer = audioBuffer; #else // Setup OpenAL format @@ -2398,17 +2402,17 @@ static Wave LoadFLAC(const char *fileName) // NOTE: Using dr_mp3 library static Wave LoadMP3(const char *fileName) { - Wave wave; + Wave wave = { 0 }; // Decode an entire MP3 file in one go - uint64_t totalSampleCount; - drmp3_config *config = NULL; - wave.data = drmp3_open_and_decode_file_f32(fileName, config, &totalSampleCount); + uint64_t totalSampleCount = 0; + drmp3_config config = { 0 }; + wave.data = drmp3_open_and_decode_file_f32(fileName, &config, &totalSampleCount); - wave.channels = config->outputChannels; - wave.sampleRate = config->outputSampleRate; - wave.sampleCount = (int)totalSampleCount/wave.channels; - wave.sampleSize = 16; + wave.channels = config.outputChannels; + wave.sampleRate = config.outputSampleRate; + wave.sampleCount = (int)totalSampleCount; + wave.sampleSize = 32; // NOTE: Only support up to 2 channels (mono, stereo) if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] MP3 channels number (%i) not supported", fileName, wave.channels); -- cgit v1.2.3 From c2aa1fed7b4b75c9bb560ffb9ff6cd8c99d7dd41 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Oct 2018 11:38:42 +0200 Subject: Removed OpenAL backend --- .travis.yml | 1 - src/CMakeLists.txt | 9 +- src/CMakeOptions.txt | 5 - src/Makefile | 24 +- src/audio.c | 613 +-------------------------------------------------- src/config.h.in | 2 - 6 files changed, 12 insertions(+), 642 deletions(-) (limited to 'src') diff --git a/.travis.yml b/.travis.yml index ec4a8ebd..c27b6582 100644 --- a/.travis.yml +++ b/.travis.yml @@ -120,7 +120,6 @@ script: -DBUILD_EXAMPLES=ON -DBUILD_GAMES=ON -DUSE_EXTERNAL_GLFW=$USE_EXTERNAL_GLFW -DUSE_WAYLAND=$WAYLAND - -DUSE_OPENAL_BACKEND=$OPENAL -DINCLUDE_EVERYTHING=ON .. - $RUNNER make VERBOSE=1 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 005b22cb..1b1d0d06 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -45,13 +45,8 @@ endif() add_definitions("-DRAYLIB_CMAKE=1") if(USE_AUDIO) - if (NOT USE_OPENAL_BACKEND) - file(GLOB mini_al external/mini_al.c) - MESSAGE(STATUS "Audio Backend: mini_al") - else() - find_package(OpenAL REQUIRED) - MESSAGE(STATUS "Audio Backend: OpenAL") - endif() + file(GLOB mini_al external/mini_al.c) + MESSAGE(STATUS "Audio Backend: mini_al") file(GLOB stb_vorbis external/stb_vorbis.c) set(sources ${raylib_sources} ${mini_al} ${stb_vorbis}) else() diff --git a/src/CMakeOptions.txt b/src/CMakeOptions.txt index d4ecb392..eee3f1a9 100644 --- a/src/CMakeOptions.txt +++ b/src/CMakeOptions.txt @@ -12,11 +12,6 @@ option(SHARED "Build raylib as a dynamic library" OFF) option(STATIC "Build raylib as a static library" ON) option(MACOS_FATLIB "Build fat library for both i386 and x86_64 on macOS" OFF) option(USE_AUDIO "Build raylib with audio module" ON) -if(${PLATFORM} MATCHES "Web") - cmake_dependent_option(USE_OPENAL_BACKEND "Link raylib with openAL instead of mini-al" ON "USE_AUDIO" OFF) -else() - cmake_dependent_option(USE_OPENAL_BACKEND "Link raylib with openAL instead of mini-al" OFF "USE_AUDIO" OFF) -endif() enum_option(USE_EXTERNAL_GLFW "OFF;IF_POSSIBLE;ON" "Link raylib against system GLFW instead of embedded one") if(UNIX AND NOT APPLE) diff --git a/src/Makefile b/src/Makefile index ac4b15b4..28b73beb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -63,14 +63,6 @@ RAYLIB_BUILD_MODE ?= RELEASE # NOTE: Some programs like tools could not require audio support INCLUDE_AUDIO_MODULE ?= TRUE -# Use OpenAL Soft backend for audio -USE_OPENAL_BACKEND ?= FALSE - -# OpenAL Soft audio backend forced on HTML5 and OSX (see below) -ifeq ($(PLATFORM),PLATFORM_WEB) - USE_OPENAL_BACKEND = TRUE -endif - # Use external GLFW library instead of rglfw module # TODO: Review usage of examples on Linux. USE_EXTERNAL_GLFW ?= FALSE @@ -154,13 +146,6 @@ endif # RAYLIB_PATH ?= /home/pi/raylib #endif -# Force OpenAL Soft audio backend for OSX platform -# NOTE 1: mini_al library does not support CoreAudio yet -# NOTE 2: Required OpenAL libraries should be available on OSX -ifeq ($(PLATFORM_OS),OSX) - USE_OPENAL_BACKEND = TRUE -endif - ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH = C:/emsdk @@ -343,11 +328,6 @@ ifeq ($(RAYLIB_LIBTYPE),SHARED) CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED endif -# Use OpenAL Soft backend instead of mini_al -ifeq ($(USE_OPENAL_BACKEND),TRUE) - CFLAGS += -DUSE_OPENAL_BACKEND -endif - # Use Wayland display on Linux desktop ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS), LINUX) @@ -426,9 +406,7 @@ endif ifeq ($(INCLUDE_AUDIO_MODULE),TRUE) OBJS += audio.o OBJS += stb_vorbis.o - ifeq ($(USE_OPENAL_BACKEND),FALSE) - OBJS += mini_al.o - endif + OBJS += mini_al.o endif ifeq ($(PLATFORM),PLATFORM_ANDROID) diff --git a/src/audio.c b/src/audio.c index fc65127b..a646c981 100644 --- a/src/audio.c +++ b/src/audio.c @@ -16,9 +16,6 @@ * Define to use the module as standalone library (independently of raylib). * Required types and functions are defined in the same module. * -* #define USE_OPENAL_BACKEND -* Use OpenAL Soft audio backend -* * #define SUPPORT_FILEFORMAT_WAV * #define SUPPORT_FILEFORMAT_OGG * #define SUPPORT_FILEFORMAT_XM @@ -82,25 +79,9 @@ #include "utils.h" // Required for: fopen() Android mapping #endif -#if !defined(USE_OPENAL_BACKEND) - #define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL. -#endif - -#include "external/mini_al.h" // Implemented in mini_al.c. Cannot implement this here because it conflicts with Win32 APIs such as CloseWindow(), etc. - -#if !defined(USE_MINI_AL) || (USE_MINI_AL == 0) - #if defined(__APPLE__) - #include "OpenAL/al.h" // OpenAL basic header - #include "OpenAL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) - #else - #include "AL/al.h" // OpenAL basic header - #include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) - //#include "AL/alext.h" // OpenAL extensions header, required for AL_EXT_FLOAT32 and AL_EXT_MCFORMATS - #endif - - // OpenAL extension: AL_EXT_FLOAT32 - Support for 32bit float samples - // OpenAL extension: AL_EXT_MCFORMATS - Support for multi-channel formats (Quad, 5.1, 6.1, 7.1) -#endif +#include "external/mini_al.h" // mini_al audio library + // NOTE: Cannot be implement here because it conflicts with + // Win32 APIs: Rectangle, CloseWindow(), ShowCursor(), PlaySoundA() #include // Required for: malloc(), free() #include // Required for: strcmp(), strncmp() @@ -147,15 +128,6 @@ // In case of music-stalls, just increase this number #define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. 16bit, Mono: 8Kb) -// Support uncompressed PCM data in 32-bit float IEEE format -// NOTE: This definition is included in "AL/alext.h", but some OpenAL implementations -// could not provide the extensions header (Android), so its defined here -#if !defined(AL_EXT_float32) - #define AL_EXT_float32 1 - #define AL_FORMAT_MONO_FLOAT32 0x10010 - #define AL_FORMAT_STEREO_FLOAT32 0x10011 -#endif - //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -233,8 +205,6 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo //---------------------------------------------------------------------------------- // mini_al AudioBuffer Functionality //---------------------------------------------------------------------------------- -#if USE_MINI_AL - #define DEVICE_FORMAT mal_format_f32 #define DEVICE_CHANNELS 2 #define DEVICE_SAMPLE_RATE 44100 @@ -487,7 +457,6 @@ static void MixAudioFrames(float *framesOut, const float *framesIn, mal_uint32 f } } } -#endif //---------------------------------------------------------------------------------- // Module Functions Definition - Audio Device initialization and Closing @@ -495,7 +464,6 @@ static void MixAudioFrames(float *framesOut, const float *framesIn, mal_uint32 f // Initialize audio device void InitAudioDevice(void) { -#if USE_MINI_AL // Context. mal_context_config contextConfig = mal_context_config_init(OnLog); mal_result result = mal_context_init(NULL, 0, &contextConfig, &context); @@ -545,45 +513,11 @@ void InitAudioDevice(void) TraceLog(LOG_INFO, "Audio buffer size: %d", device.bufferSizeInFrames); isAudioInitialized = MAL_TRUE; -#else - // Open and initialize a device with default settings - ALCdevice *device = alcOpenDevice(NULL); - - if (!device) TraceLog(LOG_ERROR, "Audio device could not be opened"); - else - { - ALCcontext *context = alcCreateContext(device, NULL); - - if ((context == NULL) || (alcMakeContextCurrent(context) == ALC_FALSE)) - { - if (context != NULL) alcDestroyContext(context); - - alcCloseDevice(device); - - TraceLog(LOG_ERROR, "Could not initialize audio context"); - } - else - { - TraceLog(LOG_INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER)); - - // Listener definition (just for 2D) - alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f); - alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f); - alListener3f(AL_ORIENTATION, 0.0f, 0.0f, -1.0f); - - alListenerf(AL_GAIN, 1.0f); - - if (alIsExtensionPresent("AL_EXT_float32")) TraceLog(LOG_INFO, "[EXTENSION] AL_EXT_float32 supported"); - else TraceLog(LOG_INFO, "[EXTENSION] AL_EXT_float32 not supported"); - } - } -#endif } // Close the audio device for all contexts void CloseAudioDevice(void) { -#if USE_MINI_AL if (!isAudioInitialized) { TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized"); @@ -593,18 +527,6 @@ void CloseAudioDevice(void) mal_mutex_uninit(&audioLock); mal_device_uninit(&device); mal_context_uninit(&context); -#else - ALCdevice *device; - ALCcontext *context = alcGetCurrentContext(); - - if (context == NULL) TraceLog(LOG_WARNING, "Could not get current audio context for closing"); - - device = alcGetContextsDevice(context); - - alcMakeContextCurrent(NULL); - alcDestroyContext(context); - alcCloseDevice(device); -#endif TraceLog(LOG_INFO, "Audio device closed successfully"); } @@ -612,20 +534,7 @@ void CloseAudioDevice(void) // Check if device has been initialized successfully bool IsAudioDeviceReady(void) { -#if USE_MINI_AL return isAudioInitialized; -#else - ALCcontext *context = alcGetCurrentContext(); - - if (context == NULL) return false; - else - { - ALCdevice *device = alcGetContextsDevice(context); - - if (device == NULL) return false; - else return true; - } -#endif } // Set master volume (listener) @@ -634,17 +543,13 @@ void SetMasterVolume(float volume) if (volume < 0.0f) volume = 0.0f; else if (volume > 1.0f) volume = 1.0f; -#if USE_MINI_AL masterVolume = volume; -#else - alListenerf(AL_GAIN, volume); -#endif } //---------------------------------------------------------------------------------- // Module Functions Definition - Audio Buffer management //---------------------------------------------------------------------------------- -#if USE_MINI_AL + // Create a new audio buffer. Initially filled with silence AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage) { @@ -843,7 +748,6 @@ void UntrackAudioBuffer(AudioBuffer *audioBuffer) mal_mutex_unlock(&audioLock); } -#endif //---------------------------------------------------------------------------------- // Module Functions Definition - Sounds loading and playing (.WAV) @@ -909,7 +813,6 @@ Sound LoadSoundFromWave(Wave wave) if (wave.data != NULL) { -#if USE_MINI_AL // When using mini_al we need to do our own mixing. To simplify this we need convert the format of each sound to be consistent with // the format used to open the playback device. We can do this two ways: // @@ -931,61 +834,6 @@ Sound LoadSoundFromWave(Wave wave) if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Format conversion failed"); sound.audioBuffer = audioBuffer; -#else - ALenum format = 0; - - // The OpenAL format is worked out by looking at the number of channels and the sample size (bits per sample) - if (wave.channels == 1) - { - switch (wave.sampleSize) - { - case 8: format = AL_FORMAT_MONO8; break; - case 16: format = AL_FORMAT_MONO16; break; - case 32: format = AL_FORMAT_MONO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32 - default: TraceLog(LOG_WARNING, "Wave sample size not supported: %i", wave.sampleSize); break; - } - } - else if (wave.channels == 2) - { - switch (wave.sampleSize) - { - case 8: format = AL_FORMAT_STEREO8; break; - case 16: format = AL_FORMAT_STEREO16; break; - case 32: format = AL_FORMAT_STEREO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32 - default: TraceLog(LOG_WARNING, "Wave sample size not supported: %i", wave.sampleSize); break; - } - } - else TraceLog(LOG_WARNING, "Wave number of channels not supported: %i", wave.channels); - - // Create an audio source - ALuint source; - alGenSources(1, &source); // Generate pointer to audio source - - alSourcef(source, AL_PITCH, 1.0f); - alSourcef(source, AL_GAIN, 1.0f); - alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - alSourcei(source, AL_LOOPING, AL_FALSE); - - // Convert loaded data to OpenAL buffer - //---------------------------------------- - ALuint buffer; - alGenBuffers(1, &buffer); // Generate pointer to buffer - - unsigned int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8; // Size in bytes - - // Upload sound data to buffer - alBufferData(buffer, format, wave.data, dataSize, wave.sampleRate); - - // Attach sound buffer to source - alSourcei(source, AL_BUFFER, buffer); - - TraceLog(LOG_INFO, "[SND ID %i][BUFR ID %i] Sound data loaded successfully (%i Hz, %i bit, %s)", source, buffer, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); - - sound.source = source; - sound.buffer = buffer; - sound.format = format; -#endif } return sound; @@ -1002,14 +850,7 @@ void UnloadWave(Wave wave) // Unload sound void UnloadSound(Sound sound) { -#if USE_MINI_AL DeleteAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - alSourceStop(sound.source); - - alDeleteSources(1, &sound.source); - alDeleteBuffers(1, &sound.buffer); -#endif TraceLog(LOG_INFO, "[SND ID %i][BUFR ID %i] Unloaded sound data from RAM", sound.source, sound.buffer); } @@ -1018,8 +859,8 @@ void UnloadSound(Sound sound) // NOTE: data must match sound.format void UpdateSound(Sound sound, const void *data, int samplesCount) { -#if USE_MINI_AL AudioBuffer *audioBuffer = (AudioBuffer *)sound.audioBuffer; + if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer"); @@ -1030,29 +871,6 @@ void UpdateSound(Sound sound, const void *data, int samplesCount) // TODO: May want to lock/unlock this since this data buffer is read at mixing time. memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.formatConverterIn.config.channels*mal_get_bytes_per_sample(audioBuffer->dsp.formatConverterIn.config.formatIn)); -#else - ALint sampleRate, sampleSize, channels; - alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); - alGetBufferi(sound.buffer, AL_BITS, &sampleSize); // It could also be retrieved from sound.format - alGetBufferi(sound.buffer, AL_CHANNELS, &channels); // It could also be retrieved from sound.format - - TraceLog(LOG_DEBUG, "UpdateSound() : AL_FREQUENCY: %i", sampleRate); - TraceLog(LOG_DEBUG, "UpdateSound() : AL_BITS: %i", sampleSize); - TraceLog(LOG_DEBUG, "UpdateSound() : AL_CHANNELS: %i", channels); - - unsigned int dataSize = samplesCount*channels*sampleSize/8; // Size of data in bytes - - alSourceStop(sound.source); // Stop sound - alSourcei(sound.source, AL_BUFFER, 0); // Unbind buffer from sound to update - //alDeleteBuffers(1, &sound.buffer); // Delete current buffer data - //alGenBuffers(1, &sound.buffer); // Generate new buffer - - // Upload new data to sound buffer - alBufferData(sound.buffer, sound.format, data, dataSize, sampleRate); - - // Attach sound buffer to source again - alSourcei(sound.source, AL_BUFFER, sound.buffer); -#endif } // Export wave data to file @@ -1141,102 +959,48 @@ void ExportWave(Wave wave, const char *fileName) // Play a sound void PlaySound(Sound sound) { -#if USE_MINI_AL PlayAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - alSourcePlay(sound.source); // Play the sound -#endif - - //TraceLog(LOG_INFO, "Playing sound"); - - // Find the current position of the sound being played - // NOTE: Only work when the entire file is in a single buffer - //int byteOffset; - //alGetSourcei(sound.source, AL_BYTE_OFFSET, &byteOffset); - // - //int sampleRate; - //alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); // AL_CHANNELS, AL_BITS (bps) - - //float seconds = (float)byteOffset/sampleRate; // Number of seconds since the beginning of the sound - //or - //float result; - //alGetSourcef(sound.source, AL_SEC_OFFSET, &result); // AL_SAMPLE_OFFSET } // Pause a sound void PauseSound(Sound sound) { -#if USE_MINI_AL PauseAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - alSourcePause(sound.source); -#endif } // Resume a paused sound void ResumeSound(Sound sound) { -#if USE_MINI_AL ResumeAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - ALenum state; - - alGetSourcei(sound.source, AL_SOURCE_STATE, &state); - - if (state == AL_PAUSED) alSourcePlay(sound.source); -#endif } // Stop reproducing a sound void StopSound(Sound sound) { -#if USE_MINI_AL StopAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - alSourceStop(sound.source); -#endif } // Check if a sound is playing bool IsSoundPlaying(Sound sound) { -#if USE_MINI_AL return IsAudioBufferPlaying((AudioBuffer *)sound.audioBuffer); -#else - bool playing = false; - ALint state; - - alGetSourcei(sound.source, AL_SOURCE_STATE, &state); - if (state == AL_PLAYING) playing = true; - - return playing; -#endif } // Set volume for a sound void SetSoundVolume(Sound sound, float volume) { -#if USE_MINI_AL SetAudioBufferVolume((AudioBuffer *)sound.audioBuffer, volume); -#else - alSourcef(sound.source, AL_GAIN, volume); -#endif } // Set pitch for a sound void SetSoundPitch(Sound sound, float pitch) { -#if USE_MINI_AL SetAudioBufferPitch((AudioBuffer *)sound.audioBuffer, pitch); -#else - alSourcef(sound.source, AL_PITCH, pitch); -#endif } // Convert wave data to desired format void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) { -#if USE_MINI_AL mal_format formatIn = ((wave->sampleSize == 8) ? mal_format_u8 : ((wave->sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatOut = (( sampleSize == 8) ? mal_format_u8 : (( sampleSize == 16) ? mal_format_s16 : mal_format_f32)); @@ -1264,87 +1028,6 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) wave->channels = channels; free(wave->data); wave->data = data; - -#else - // Format sample rate - // NOTE: Only supported 22050 <--> 44100 - if (wave->sampleRate != sampleRate) - { - // TODO: Resample wave data (upsampling or downsampling) - // NOTE 1: To downsample, you have to drop samples or average them. - // NOTE 2: To upsample, you have to interpolate new samples. - - wave->sampleRate = sampleRate; - } - - // Format sample size - // NOTE: Only supported 8 bit <--> 16 bit <--> 32 bit - if (wave->sampleSize != sampleSize) - { - void *data = malloc(wave->sampleCount*wave->channels*sampleSize/8); - - for (int i = 0; i < wave->sampleCount; i++) - { - for (int j = 0; j < wave->channels; j++) - { - if (sampleSize == 8) - { - if (wave->sampleSize == 16) ((unsigned char *)data)[wave->channels*i + j] = (unsigned char)(((float)(((short *)wave->data)[wave->channels*i + j])/32767.0f)*256); - else if (wave->sampleSize == 32) ((unsigned char *)data)[wave->channels*i + j] = (unsigned char)(((float *)wave->data)[wave->channels*i + j]*127.0f + 127); - } - else if (sampleSize == 16) - { - if (wave->sampleSize == 8) ((short *)data)[wave->channels*i + j] = (short)(((float)(((unsigned char *)wave->data)[wave->channels*i + j] - 127)/256.0f)*32767); - else if (wave->sampleSize == 32) ((short *)data)[wave->channels*i + j] = (short)((((float *)wave->data)[wave->channels*i + j])*32767); - } - else if (sampleSize == 32) - { - if (wave->sampleSize == 8) ((float *)data)[wave->channels*i + j] = (float)(((unsigned char *)wave->data)[wave->channels*i + j] - 127)/256.0f; - else if (wave->sampleSize == 16) ((float *)data)[wave->channels*i + j] = (float)(((short *)wave->data)[wave->channels*i + j])/32767.0f; - } - } - } - - wave->sampleSize = sampleSize; - free(wave->data); - wave->data = data; - } - - // Format channels (interlaced mode) - // NOTE: Only supported mono <--> stereo - if (wave->channels != channels) - { - void *data = malloc(wave->sampleCount*wave->sampleSize/8*channels); - - if ((wave->channels == 1) && (channels == 2)) // mono ---> stereo (duplicate mono information) - { - for (int i = 0; i < wave->sampleCount; i++) - { - for (int j = 0; j < channels; j++) - { - if (wave->sampleSize == 8) ((unsigned char *)data)[channels*i + j] = ((unsigned char *)wave->data)[i]; - else if (wave->sampleSize == 16) ((short *)data)[channels*i + j] = ((short *)wave->data)[i]; - else if (wave->sampleSize == 32) ((float *)data)[channels*i + j] = ((float *)wave->data)[i]; - } - } - } - else if ((wave->channels == 2) && (channels == 1)) // stereo ---> mono (mix stereo channels) - { - for (int i = 0, j = 0; i < wave->sampleCount; i++, j += 2) - { - if (wave->sampleSize == 8) ((unsigned char *)data)[i] = (((unsigned char *)wave->data)[j] + ((unsigned char *)wave->data)[j + 1])/2; - else if (wave->sampleSize == 16) ((short *)data)[i] = (((short *)wave->data)[j] + ((short *)wave->data)[j + 1])/2; - else if (wave->sampleSize == 32) ((float *)data)[i] = (((float *)wave->data)[j] + ((float *)wave->data)[j + 1])/2.0f; - } - } - - // TODO: Add/remove additional interlaced channels - - wave->channels = channels; - free(wave->data); - wave->data = data; - } -#endif } // Copy a wave to a new wave @@ -1578,8 +1261,8 @@ void UnloadMusicStream(Music music) // Start music playing (open stream) void PlayMusicStream(Music music) { -#if USE_MINI_AL AudioBuffer *audioBuffer = (AudioBuffer *)music->stream.audioBuffer; + if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer"); @@ -1595,61 +1278,25 @@ void PlayMusicStream(Music music) PlayAudioStream(music->stream); // <-- This resets the cursor position. audioBuffer->frameCursorPos = frameCursorPos; -#else - alSourcePlay(music->stream.source); -#endif } // Pause music playing void PauseMusicStream(Music music) { -#if USE_MINI_AL PauseAudioStream(music->stream); -#else - alSourcePause(music->stream.source); -#endif } // Resume music playing void ResumeMusicStream(Music music) { -#if USE_MINI_AL ResumeAudioStream(music->stream); -#else - ALenum state; - alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); - - if (state == AL_PAUSED) - { - TraceLog(LOG_INFO, "[AUD ID %i] Resume music stream playing", music->stream.source); - alSourcePlay(music->stream.source); - } -#endif } // Stop music playing (close stream) // TODO: To clear a buffer, make sure they have been already processed! void StopMusicStream(Music music) { -#if USE_MINI_AL StopAudioStream(music->stream); -#else - alSourceStop(music->stream.source); - - /* - // Clear stream buffers - // WARNING: Queued buffers must have been processed before unqueueing and reloaded with data!!! - void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, 1); - - for (int i = 0; i < MAX_STREAM_BUFFERS; i++) - { - //UpdateAudioStream(music->stream, pcm, AUDIO_BUFFER_SIZE); // Update one buffer at a time - alBufferData(music->stream.buffers[i], music->stream.format, pcm, AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, music->stream.sampleRate); - } - - free(pcm); - */ -#endif // Restart music context switch (music->ctxType) @@ -1677,7 +1324,6 @@ void StopMusicStream(Music music) // TODO: Make sure buffers are ready for update... check music state void UpdateMusicStream(Music music) { -#if USE_MINI_AL bool streamEnding = false; unsigned int subBufferSizeInFrames = ((AudioBuffer *)music->stream.audioBuffer)->bufferSizeInFrames/2; @@ -1761,139 +1407,24 @@ void UpdateMusicStream(Music music) // just make sure to play again on window restore if (IsMusicPlaying(music)) PlayMusicStream(music); } -#else - ALenum state; - ALint processed = 0; - - alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); // Get music stream state - alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); // Get processed buffers - - if (processed > 0) - { - bool streamEnding = false; - - // NOTE: Using dynamic allocation because it could require more than 16KB - void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, 1); - - int numBuffersToProcess = processed; - int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, - // individual L or R for ogg shorts - - for (int i = 0; i < numBuffersToProcess; i++) - { - if (music->samplesLeft >= AUDIO_BUFFER_SIZE) samplesCount = AUDIO_BUFFER_SIZE; - else samplesCount = music->samplesLeft; - - // TODO: Really don't like ctxType thingy... - switch (music->ctxType) - { - case MUSIC_AUDIO_OGG: - { - // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) - int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels); - - } break; - #if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: - { - // NOTE: Returns the number of samples to process - unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, samplesCount*music->stream.channels, (short *)pcm); - - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_MP3) - case MUSIC_AUDIO_MP3: - { - // NOTE: Returns the number of samples to process - unsigned int numSamplesMp3 = (unsigned int)drmp3_read_f32(&music->ctxMp3, samplesCount*music->stream.channels, (float *)pcm); - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_XM) - case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break; - #endif - #if defined(SUPPORT_FILEFORMAT_MOD) - case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, samplesCount, 0); break; - #endif - default: break; - } - - UpdateAudioStream(music->stream, pcm, samplesCount); - music->samplesLeft -= samplesCount; - - if (music->samplesLeft <= 0) - { - streamEnding = true; - break; - } - } - - // Free allocated pcm data - free(pcm); - - // Reset audio stream for looping - if (streamEnding) - { - StopMusicStream(music); // Stop music (and reset) - - // Decrease loopCount to stop when required - if (music->loopCount > 0) - { - music->loopCount--; // Decrease loop count - PlayMusicStream(music); // Play again - } - else - { - if (music->loopCount == -1) - { - PlayMusicStream(music); - } - } - } - else - { - // NOTE: In case window is minimized, music stream is stopped, - // just make sure to play again on window restore - if (state != AL_PLAYING) PlayMusicStream(music); - } - } -#endif } // Check if any music is playing bool IsMusicPlaying(Music music) { -#if USE_MINI_AL return IsAudioStreamPlaying(music->stream); -#else - bool playing = false; - ALint state; - - alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); - - if (state == AL_PLAYING) playing = true; - - return playing; -#endif } // Set volume for music void SetMusicVolume(Music music, float volume) { -#if USE_MINI_AL SetAudioStreamVolume(music->stream, volume); -#else - alSourcef(music->stream.source, AL_GAIN, volume); -#endif } // Set pitch for music void SetMusicPitch(Music music, float pitch) { -#if USE_MINI_AL SetAudioStreamPitch(music->stream, pitch); -#else - alSourcef(music->stream.source, AL_PITCH, pitch); -#endif } // Set music loop count (loop repeats) @@ -1939,8 +1470,6 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un stream.channels = 1; // Fallback to mono channel } - -#if USE_MINI_AL mal_format formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); // The size of a streaming buffer must be at least double the size of a period. @@ -1957,52 +1486,6 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un audioBuffer->looping = true; // Always loop for streaming buffers. stream.audioBuffer = audioBuffer; -#else - // Setup OpenAL format - if (stream.channels == 1) - { - switch (sampleSize) - { - case 8: stream.format = AL_FORMAT_MONO8; break; - case 16: stream.format = AL_FORMAT_MONO16; break; - case 32: stream.format = AL_FORMAT_MONO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32 - default: TraceLog(LOG_WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break; - } - } - else if (stream.channels == 2) - { - switch (sampleSize) - { - case 8: stream.format = AL_FORMAT_STEREO8; break; - case 16: stream.format = AL_FORMAT_STEREO16; break; - case 32: stream.format = AL_FORMAT_STEREO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32 - default: TraceLog(LOG_WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break; - } - } - - // Create an audio source - alGenSources(1, &stream.source); - alSourcef(stream.source, AL_PITCH, 1.0f); - alSourcef(stream.source, AL_GAIN, 1.0f); - alSource3f(stream.source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(stream.source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - // Create Buffers (double buffering) - alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers); - - // Initialize buffer with zeros by default - // NOTE: Using dynamic allocation because it requires more than 16KB - void *pcm = calloc(AUDIO_BUFFER_SIZE*stream.sampleSize/8*stream.channels, 1); - - for (int i = 0; i < MAX_STREAM_BUFFERS; i++) - { - alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*stream.sampleSize/8*stream.channels, stream.sampleRate); - } - - free(pcm); - - alSourceQueueBuffers(stream.source, MAX_STREAM_BUFFERS, stream.buffers); -#endif TraceLog(LOG_INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1) ? "Mono" : "Stereo"); @@ -2012,28 +1495,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un // Close audio stream and free memory void CloseAudioStream(AudioStream stream) { -#if USE_MINI_AL DeleteAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - // Stop playing channel - alSourceStop(stream.source); - - // Flush out all queued buffers - int queued = 0; - alGetSourcei(stream.source, AL_BUFFERS_QUEUED, &queued); - - ALuint buffer = 0; - - while (queued > 0) - { - alSourceUnqueueBuffers(stream.source, 1, &buffer); - queued--; - } - - // Delete source and buffers - alDeleteSources(1, &stream.source); - alDeleteBuffers(MAX_STREAM_BUFFERS, stream.buffers); -#endif TraceLog(LOG_INFO, "[AUD ID %i] Unloaded audio stream data", stream.source); } @@ -2043,7 +1505,6 @@ void CloseAudioStream(AudioStream stream) // NOTE 2: To unqueue a buffer it needs to be processed: IsAudioBufferProcessed() void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) { -#if USE_MINI_AL AudioBuffer *audioBuffer = (AudioBuffer *)stream.audioBuffer; if (audioBuffer == NULL) { @@ -2054,6 +1515,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1]) { mal_uint32 subBufferToUpdate; + if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1]) { // Both buffers are available for updating. Update the first one and make sure the cursor is moved back to the front. @@ -2073,6 +1535,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) if (subBufferSizeInFrames >= (mal_uint32)samplesCount) { mal_uint32 framesToWrite = subBufferSizeInFrames; + if (framesToWrite > (mal_uint32)samplesCount) framesToWrite = (mal_uint32)samplesCount; mal_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8); @@ -2080,6 +1543,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) // Any leftover frames should be filled with zeros. mal_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; + if (leftoverFrameCount > 0) { memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8)); @@ -2098,24 +1562,11 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) TraceLog(LOG_ERROR, "Audio buffer not available for updating"); return; } -#else - ALuint buffer = 0; - alSourceUnqueueBuffers(stream.source, 1, &buffer); - - // Check if any buffer was available for unqueue - if (alGetError() != AL_INVALID_VALUE) - { - alBufferData(buffer, stream.format, data, samplesCount*stream.sampleSize/8*stream.channels, stream.sampleRate); - alSourceQueueBuffers(stream.source, 1, &buffer); - } - else TraceLog(LOG_WARNING, "[AUD ID %i] Audio buffer not available for unqueuing", stream.source); -#endif } // Check if any audio stream buffers requires refill bool IsAudioBufferProcessed(AudioStream stream) { -#if USE_MINI_AL AudioBuffer *audioBuffer = (AudioBuffer *)stream.audioBuffer; if (audioBuffer == NULL) { @@ -2124,92 +1575,46 @@ bool IsAudioBufferProcessed(AudioStream stream) } return audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1]; -#else - ALint processed = 0; - - // Determine if music stream is ready to be written - alGetSourcei(stream.source, AL_BUFFERS_PROCESSED, &processed); - - return (processed > 0); -#endif } // Play audio stream void PlayAudioStream(AudioStream stream) { -#if USE_MINI_AL PlayAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - alSourcePlay(stream.source); -#endif } // Play audio stream void PauseAudioStream(AudioStream stream) { -#if USE_MINI_AL PauseAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - alSourcePause(stream.source); -#endif } // Resume audio stream playing void ResumeAudioStream(AudioStream stream) { -#if USE_MINI_AL ResumeAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - ALenum state; - alGetSourcei(stream.source, AL_SOURCE_STATE, &state); - - if (state == AL_PAUSED) alSourcePlay(stream.source); -#endif } // Check if audio stream is playing. bool IsAudioStreamPlaying(AudioStream stream) { -#if USE_MINI_AL return IsAudioBufferPlaying((AudioBuffer *)stream.audioBuffer); -#else - bool playing = false; - ALint state; - - alGetSourcei(stream.source, AL_SOURCE_STATE, &state); - - if (state == AL_PLAYING) playing = true; - - return playing; -#endif } // Stop audio stream void StopAudioStream(AudioStream stream) { -#if USE_MINI_AL StopAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - alSourceStop(stream.source); -#endif } void SetAudioStreamVolume(AudioStream stream, float volume) { -#if USE_MINI_AL SetAudioBufferVolume((AudioBuffer *)stream.audioBuffer, volume); -#else - alSourcef(stream.source, AL_GAIN, volume); -#endif } void SetAudioStreamPitch(AudioStream stream, float pitch) { -#if USE_MINI_AL SetAudioBufferPitch((AudioBuffer *)stream.audioBuffer, pitch); -#else - alSourcef(stream.source, AL_PITCH, pitch); -#endif } //---------------------------------------------------------------------------------- diff --git a/src/config.h.in b/src/config.h.in index 742067ce..b0e62480 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -1,7 +1,5 @@ /* config.h.in */ -#cmakedefine USE_OPENAL_BACKEND 1 - // core.c /* Camera module is included (camera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital */ #cmakedefine SUPPORT_CAMERA_SYSTEM 1 -- cgit v1.2.3 From 59bbad9360ef87f66532cc665435a883e88b7e1e Mon Sep 17 00:00:00 2001 From: Dillon Jones Date: Thu, 18 Oct 2018 07:28:57 -0400 Subject: Remove non-Windows includes from Makefile --- src/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 28b73beb..2932e7bb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -339,9 +339,12 @@ endif # Define include paths for required headers # NOTE: Several external required libraries (stb and others) -INCLUDE_PATHS = -I. -Iexternal -Iexternal/glfw/include +INCLUDE_PATHS = -I. -Iexternal/glfw/include ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),WINDOWS) + INCLUDE_PATHS += -Iexternal + endif ifeq ($(PLATFORM_OS),BSD) INCLUDE_PATHS += -I/usr/local/include LDFLAGS += -L. -Lsrc -L/usr/local/lib -L$(RAYLIB_RELEASE_PATH) -- cgit v1.2.3 From 764766bfb2160cdbe3196abe3c90ad86197fc8d6 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Oct 2018 16:00:11 +0200 Subject: Some formatting tweaks --- src/audio.c | 4 ++-- src/core.c | 2 +- src/raylib.h | 2 +- src/text.c | 21 +++++++++++---------- src/textures.c | 8 ++++---- 5 files changed, 19 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/audio.c b/src/audio.c index a646c981..dcde6e65 100644 --- a/src/audio.c +++ b/src/audio.c @@ -431,7 +431,7 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi mal_uint32 totalFramesRemaining = (frameCount - framesRead); if (totalFramesRemaining > 0) { - memset((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes); + memset((unsigned char *)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes); // For static buffers we can fill the remaining frames with silence for safety, but we don't want // to report those frames as "read". The reason for this is that the caller uses the return value @@ -1062,7 +1062,7 @@ void WaveCrop(Wave *wave, int initSample, int finalSample) void *data = malloc(sampleCount*wave->sampleSize/8*wave->channels); - memcpy(data, (unsigned char*)wave->data + (initSample*wave->channels*wave->sampleSize/8), sampleCount*wave->channels*wave->sampleSize/8); + memcpy(data, (unsigned char *)wave->data + (initSample*wave->channels*wave->sampleSize/8), sampleCount*wave->channels*wave->sampleSize/8); free(wave->data); wave->data = data; diff --git a/src/core.c b/src/core.c index 70a7bf68..41aa181b 100644 --- a/src/core.c +++ b/src/core.c @@ -478,7 +478,7 @@ void android_main(struct android_app *app) androidApp = app; // TODO: Should we maybe report != 0 return codes somewhere? - (void)main(1, (char*[]) { arg0, NULL }); + (void)main(1, (char *[]) { arg0, NULL }); } // TODO: Add this to header (if apps really need it) diff --git a/src/raylib.h b/src/raylib.h index 42bc38e7..aa5bd16f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1083,7 +1083,7 @@ RLAPI void UnloadFont(Font font); // Text drawing functions RLAPI void DrawFPS(int posX, int posY); // Shows current FPS RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters +RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters // Text misc. functions RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font diff --git a/src/text.c b/src/text.c index d8fb3c98..5d5de6fa 100644 --- a/src/text.c +++ b/src/text.c @@ -589,10 +589,10 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f int length = strlen(text); int textOffsetX = 0; // Offset between characters int textOffsetY = 0; // Required for line break! - float scaleFactor; + float scaleFactor = 0.0f; - unsigned char letter; // Current character - int index; // Index position in sprite font + unsigned char letter = 0; // Current character + int index = 0; // Index position in sprite font scaleFactor = fontSize/font.baseSize; @@ -656,7 +656,7 @@ const char *FormatText(const char *text, ...) // Get a piece of a text string const char *SubText(const char *text, int position, int length) { - static char buffer[MAX_SUBTEXT_LENGTH]; + static char buffer[MAX_SUBTEXT_LENGTH] = { 0 }; int textLength = strlen(text); if (position >= textLength) @@ -703,8 +703,8 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing int tempLen = 0; // Used to count longer text line num chars int lenCounter = 0; - float textWidth = 0; - float tempTextWidth = 0; // Used to count longer text line width + float textWidth = 0.0f; + float tempTextWidth = 0.0f; // Used to count longer text line width float textHeight = (float)font.baseSize; float scaleFactor = fontSize/(float)font.baseSize; @@ -912,17 +912,18 @@ static Font LoadBMFont(const char *fileName) Font font = { 0 }; font.texture.id = 0; - char buffer[MAX_BUFFER_SIZE]; + char buffer[MAX_BUFFER_SIZE] = { 0 }; char *searchPoint = NULL; int fontSize = 0; - int texWidth, texHeight; + int texWidth = 0; + int texHeight = 0; char texFileName[129]; int charsCount = 0; - int base; // Useless data + int base = 0; // Useless data - FILE *fntFile; + FILE *fntFile = NULL; fntFile = fopen(fileName, "rt"); diff --git a/src/textures.c b/src/textures.c index 4c276324..a0e74637 100644 --- a/src/textures.c +++ b/src/textures.c @@ -2780,7 +2780,7 @@ static Image LoadDDS(const char *fileName) TraceLog(LOG_DEBUG, "Pitch or linear size: %i", ddsHeader.pitchOrLinearSize); - image.data = (unsigned char*)malloc(size*sizeof(unsigned char)); + image.data = (unsigned char *)malloc(size*sizeof(unsigned char)); fread(image.data, size, 1, ddsFile); @@ -2877,7 +2877,7 @@ static Image LoadPKM(const char *fileName) int size = image.width*image.height*bpp/8; // Total data size in bytes - image.data = (unsigned char*)malloc(size*sizeof(unsigned char)); + image.data = (unsigned char *)malloc(size*sizeof(unsigned char)); fread(image.data, size, 1, pkmFile); @@ -2971,7 +2971,7 @@ static Image LoadKTX(const char *fileName) int dataSize; fread(&dataSize, sizeof(unsigned int), 1, ktxFile); - image.data = (unsigned char*)malloc(dataSize*sizeof(unsigned char)); + image.data = (unsigned char *)malloc(dataSize*sizeof(unsigned char)); fread(image.data, dataSize, 1, ktxFile); @@ -3213,7 +3213,7 @@ static Image LoadPVR(const char *fileName) } int dataSize = image.width*image.height*bpp/8; // Total data size in bytes - image.data = (unsigned char*)malloc(dataSize*sizeof(unsigned char)); + image.data = (unsigned char *)malloc(dataSize*sizeof(unsigned char)); // Read data from file fread(image.data, dataSize, 1, pvrFile); -- cgit v1.2.3 From 3b674cd2810499d05a8edb0a7392cb90d0b95e3f Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Oct 2018 17:48:33 +0200 Subject: Some security checks on font loading --- src/text.c | 162 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 82 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/text.c b/src/text.c index 5d5de6fa..51e93b72 100644 --- a/src/text.c +++ b/src/text.c @@ -276,15 +276,7 @@ Font LoadFont(const char *fileName) Font font = { 0 }; #if defined(SUPPORT_FILEFORMAT_TTF) - if (IsFileExtension(fileName, ".ttf")) - { - font.baseSize = DEFAULT_TTF_FONTSIZE; - font.charsCount = DEFAULT_TTF_NUMCHARS; - font.chars = LoadFontData(fileName, font.baseSize, NULL, font.charsCount, FONT_DEFAULT); - Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 4, 0); - font.texture = LoadTextureFromImage(atlas); - UnloadImage(atlas); - } + if (IsFileExtension(fileName, ".ttf")) font = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, DEFAULT_TTF_NUMCHARS, NULL); else #endif #if defined(SUPPORT_FILEFORMAT_FNT) @@ -317,9 +309,13 @@ Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontCha font.baseSize = fontSize; font.charsCount = (charsCount > 0) ? charsCount : 95; font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT); - Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 2, 0); - font.texture = LoadTextureFromImage(atlas); - UnloadImage(atlas); + + if (font.chars != NULL) + { + Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 2, 0); + font.texture = LoadTextureFromImage(atlas); + UnloadImage(atlas); + } return font; } @@ -335,91 +331,97 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c #define SDF_PIXEL_DIST_SCALE 64.0f #define BITMAP_ALPHA_THRESHOLD 80 - - // In case no chars count provided, default to 95 - charsCount = (charsCount > 0) ? charsCount : 95; - - CharInfo *chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); + + CharInfo *chars = NULL; // Load font data (including pixel data) from TTF file // NOTE: Loaded information should be enough to generate font image atlas, // using any packaging method FILE *fontFile = fopen(fileName, "rb"); // Load font file - fseek(fontFile, 0, SEEK_END); - long size = ftell(fontFile); // Get file size - fseek(fontFile, 0, SEEK_SET); // Reset file pointer - - unsigned char *fontBuffer = (unsigned char *)malloc(size); - - fread(fontBuffer, size, 1, fontFile); - fclose(fontFile); - - // Init font for data reading - stbtt_fontinfo fontInfo; - if (!stbtt_InitFont(&fontInfo, fontBuffer, 0)) TraceLog(LOG_WARNING, "Failed to init font!"); + if (fontFile != NULL) + { + fseek(fontFile, 0, SEEK_END); + long size = ftell(fontFile); // Get file size + fseek(fontFile, 0, SEEK_SET); // Reset file pointer + + unsigned char *fontBuffer = (unsigned char *)malloc(size); + + fread(fontBuffer, size, 1, fontFile); + fclose(fontFile); + + // Init font for data reading + stbtt_fontinfo fontInfo; + if (!stbtt_InitFont(&fontInfo, fontBuffer, 0)) TraceLog(LOG_WARNING, "Failed to init font!"); - // Calculate font scale factor - float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize); + // Calculate font scale factor + float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize); - // Calculate font basic metrics - // NOTE: ascent is equivalent to font baseline - int ascent, descent, lineGap; - stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); - - // Fill fontChars in case not provided externally - // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) - int genFontChars = false; - if (fontChars == NULL) genFontChars = true; - if (genFontChars) - { - fontChars = (int *)malloc(charsCount*sizeof(int)); - for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32; - } - - // NOTE: Using simple packaging, one char after another - for (int i = 0; i < charsCount; i++) - { - int chw = 0, chh = 0; // Character width and height (on generation) - int ch = fontChars[i]; // Character value to get info for - chars[i].value = ch; + // Calculate font basic metrics + // NOTE: ascent is equivalent to font baseline + int ascent, descent, lineGap; + stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); - // Render a unicode codepoint to a bitmap - // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap - // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be - // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide + // In case no chars count provided, default to 95 + charsCount = (charsCount > 0) ? charsCount : 95; - if (type != FONT_SDF) chars[i].data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); - else if (ch != 32) chars[i].data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); + // Fill fontChars in case not provided externally + // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) + int genFontChars = false; + if (fontChars == NULL) genFontChars = true; + if (genFontChars) + { + fontChars = (int *)malloc(charsCount*sizeof(int)); + for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32; + } + + chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); - if (type == FONT_BITMAP) + // NOTE: Using simple packaging, one char after another + for (int i = 0; i < charsCount; i++) { - // Aliased bitmap (black & white) font generation, avoiding anti-aliasing - // NOTE: For optimum results, bitmap font should be generated at base pixel size - for (int p = 0; p < chw*chh; p++) + int chw = 0, chh = 0; // Character width and height (on generation) + int ch = fontChars[i]; // Character value to get info for + chars[i].value = ch; + + // Render a unicode codepoint to a bitmap + // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap + // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be + // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide + + if (type != FONT_SDF) chars[i].data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); + else if (ch != 32) chars[i].data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); + + if (type == FONT_BITMAP) { - if (chars[i].data[p] < BITMAP_ALPHA_THRESHOLD) chars[i].data[p] = 0; - else chars[i].data[p] = 255; + // Aliased bitmap (black & white) font generation, avoiding anti-aliasing + // NOTE: For optimum results, bitmap font should be generated at base pixel size + for (int p = 0; p < chw*chh; p++) + { + if (chars[i].data[p] < BITMAP_ALPHA_THRESHOLD) chars[i].data[p] = 0; + else chars[i].data[p] = 255; + } } - } - - chars[i].rec.width = (float)chw; - chars[i].rec.height = (float)chh; - chars[i].offsetY += (int)((float)ascent*scaleFactor); - - // Get bounding box for character (may be offset to account for chars that dip above or below the line) - int chX1, chY1, chX2, chY2; - stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2); + + chars[i].rec.width = (float)chw; + chars[i].rec.height = (float)chh; + chars[i].offsetY += (int)((float)ascent*scaleFactor); - TraceLog(LOG_DEBUG, "Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1); - TraceLog(LOG_DEBUG, "Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1); + // Get bounding box for character (may be offset to account for chars that dip above or below the line) + int chX1, chY1, chX2, chY2; + stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2); + + TraceLog(LOG_DEBUG, "Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1); + TraceLog(LOG_DEBUG, "Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1); - stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); - chars[i].advanceX *= scaleFactor; + stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); + chars[i].advanceX *= scaleFactor; + } + + free(fontBuffer); + if (genFontChars) free(fontChars); } - - free(fontBuffer); - if (genFontChars) free(fontChars); + else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName); return chars; } -- cgit v1.2.3 From 27592183681cdcaf0378406fbfbb93b60f84bc98 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Oct 2018 16:17:44 +0200 Subject: Added comment on issue --- src/audio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/audio.c b/src/audio.c index dcde6e65..f0362b2d 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1158,8 +1158,9 @@ Music LoadMusicStream(const char *fileName) music->stream = InitAudioStream(music->ctxMp3.sampleRate, 32, music->ctxMp3.channels); - // TODO: It seems the total number of samples is not obtained correctly... - music->totalSamples = (unsigned int)music->ctxMp3.framesRemaining*music->ctxMp3.channels; + // TODO: There is not an easy way to compute the total number of samples available + // in an MP3, frames size could be variable... we tried with a 60 seconds music... but crashes... + music->totalSamples = 60*music->ctxMp3.sampleRate*music->ctxMp3.channels; music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_MP3; music->loopCount = -1; // Infinite loop by default -- cgit v1.2.3 From 16914dfaa2e663b7c862be51b80ce8ea28399c55 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Oct 2018 21:40:34 +0200 Subject: Reviewed possible issue with... ...disposing RenderTexture. --- src/rlgl.h | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/rlgl.h b/src/rlgl.h index d2b52a47..5bba7238 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1506,9 +1506,17 @@ void rlDeleteTextures(unsigned int id) void rlDeleteRenderTextures(RenderTexture2D target) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (target.id > 0) glDeleteFramebuffers(1, &target.id); if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id); - if (target.depth.id > 0) glDeleteTextures(1, &target.depth.id); + if (target.depth.id > 0) + { +#if defined(GRAPHICS_API_OPENGL_ES2) + glDeleteRenderBuffers(1, &target.depth.id); +#elif defined(GRAPHICS_API_OPENGL_33) + glDeleteTextures(1, &target.depth.id); +#endif + } + + if (target.id > 0) glDeleteFramebuffers(1, &target.id); TraceLog(LOG_INFO, "[FBO ID %i] Unloaded render texture data from VRAM (GPU)", target.id); #endif @@ -2171,7 +2179,7 @@ void rlUnloadTexture(unsigned int id) // Load a texture to be used for rendering (fbo with color and depth attachments) RenderTexture2D rlLoadRenderTexture(int width, int height) { - RenderTexture2D target; + RenderTexture2D target = { 0 }; target.id = 0; @@ -2251,8 +2259,16 @@ RenderTexture2D rlLoadRenderTexture(int width, int height) default: break; } - glDeleteTextures(1, &target.texture.id); - glDeleteTextures(1, &target.depth.id); + if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id); + if (target.depth.id > 0) + { +#if defined(GRAPHICS_API_OPENGL_ES2) + glDeleteRenderBuffers(1, &target.depth.id); +#elif defined(GRAPHICS_API_OPENGL_33) + glDeleteTextures(1, &target.depth.id); +#endif + } + glDeleteFramebuffers(1, &target.id); } else TraceLog(LOG_INFO, "[FBO ID %i] Framebuffer object created successfully", target.id); -- cgit v1.2.3 From 1f4866276aca19ab138c9938ed5ea782b211c00c Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Oct 2018 21:50:50 +0200 Subject: Corrected typo --- src/rlgl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/rlgl.h b/src/rlgl.h index 5bba7238..96c91d02 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1510,7 +1510,7 @@ void rlDeleteRenderTextures(RenderTexture2D target) if (target.depth.id > 0) { #if defined(GRAPHICS_API_OPENGL_ES2) - glDeleteRenderBuffers(1, &target.depth.id); + glDeleteRenderbuffers(1, &target.depth.id); #elif defined(GRAPHICS_API_OPENGL_33) glDeleteTextures(1, &target.depth.id); #endif @@ -2263,7 +2263,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height) if (target.depth.id > 0) { #if defined(GRAPHICS_API_OPENGL_ES2) - glDeleteRenderBuffers(1, &target.depth.id); + glDeleteRenderbuffers(1, &target.depth.id); #elif defined(GRAPHICS_API_OPENGL_33) glDeleteTextures(1, &target.depth.id); #endif -- cgit v1.2.3 From 161b18edea6649a108ef3f7aa37464688adcba07 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Oct 2018 12:30:37 +0200 Subject: Reviewed possible issue with external libs --- src/Makefile | 3 --- src/core.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 2932e7bb..0cfc82c1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -342,9 +342,6 @@ endif INCLUDE_PATHS = -I. -Iexternal/glfw/include ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),WINDOWS) - INCLUDE_PATHS += -Iexternal - endif ifeq ($(PLATFORM_OS),BSD) INCLUDE_PATHS += -I/usr/local/include LDFLAGS += -L. -Lsrc -L/usr/local/lib -L$(RAYLIB_RELEASE_PATH) diff --git a/src/core.c b/src/core.c index 41aa181b..91022b11 100644 --- a/src/core.c +++ b/src/core.c @@ -125,7 +125,7 @@ #include // Required for: tolower() [Used in IsFileExtension()] #include // Required for stat() [Used in GetLastWriteTime()] -#if defined(_WIN32) && defined(_MSC_VER) +#if defined(PLATFORM_DESKTOP) && defined(_WIN32) && defined(_MSC_VER) #include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] #else #include // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()] -- cgit v1.2.3 From bd383fe2191da416c62ab0ae2e642eac834f58c2 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Oct 2018 12:48:03 +0200 Subject: Tweak for OpenGL 2.1 Why am I still supporting this??? --- src/rlgl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/rlgl.h b/src/rlgl.h index 96c91d02..d97d888e 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1509,7 +1509,7 @@ void rlDeleteRenderTextures(RenderTexture2D target) if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id); if (target.depth.id > 0) { -#if defined(GRAPHICS_API_OPENGL_ES2) +#if defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2) glDeleteRenderbuffers(1, &target.depth.id); #elif defined(GRAPHICS_API_OPENGL_33) glDeleteTextures(1, &target.depth.id); @@ -2262,9 +2262,9 @@ RenderTexture2D rlLoadRenderTexture(int width, int height) if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id); if (target.depth.id > 0) { -#if defined(GRAPHICS_API_OPENGL_ES2) +#if defined(USE_DEPTH_RENDERBUFFER) glDeleteRenderbuffers(1, &target.depth.id); -#elif defined(GRAPHICS_API_OPENGL_33) +#elif defined(USE_DEPTH_TEXTURE) glDeleteTextures(1, &target.depth.id); #endif } -- cgit v1.2.3 From e07ec6a2e8facaa6dd4d9229c0e4c8e080e1fcf4 Mon Sep 17 00:00:00 2001 From: Berni8k Date: Sun, 21 Oct 2018 00:09:17 +0100 Subject: Overhaul mouse and touch for RaspberryPi \n\nNow all '/dev/input/event*' devices are now used for input. No longer uses '/dev/input/mouse*', keyboard and gamepad continue to use existing method\nMultitouch is now supported on RPi with 10 point multitouch\nFixed bugs with IsMouseButtonPressed(Used to constantly fire when holding button) and GetMouseWheelMove(Did not work)\n Fixed exesive CPU usage of GamepadThread --- src/core.c | 492 ++++++++++++++++++++++++++++++++++++++++++----------------- src/raylib.h | 2 +- 2 files changed, 349 insertions(+), 145 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index 91022b11..cb6c7e41 100644 --- a/src/core.c +++ b/src/core.c @@ -189,6 +189,7 @@ #include // POSIX standard function definitions - read(), close(), STDIN_FILENO #include // POSIX terminal control definitions - tcgetattr(), tcsetattr() #include // POSIX threads management (mouse input) + #include // POSIX directory browsing #include // UNIX System call for device-specific input/output operations - ioctl() #include // Linux: KDSKBMODE, K_MEDIUMRAM constants definition @@ -223,9 +224,8 @@ #if defined(PLATFORM_RPI) // Old device inputs system #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input - #define DEFAULT_MOUSE_DEV "/dev/input/mouse0" // Mouse input - #define DEFAULT_TOUCH_DEV "/dev/input/event4" // Touch input virtual device (created by ts_uinput) #define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...) + #define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events // New device input events (evdev) (must be detected) //#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN" @@ -329,11 +329,22 @@ static int currentMouseWheelY = 0; // Registers current mouse wheel #if defined(PLATFORM_RPI) static int mouseStream = -1; // Mouse device file descriptor -static bool mouseReady = false; // Flag to know if mouse is ready -static pthread_t mouseThreadId; // Mouse reading thread id -static int touchStream = -1; // Touch device file descriptor -static bool touchReady = false; // Flag to know if touch interface is ready -static pthread_t touchThreadId; // Touch reading thread id +static char currentMouseStateEvdev[3] = { 0 }; // Holds the new mouse state for the next polling event to grab (Can't be written directly due to multithreading, app could miss the update) +typedef struct { + pthread_t threadId; // Event reading thread id + int fd; // File descriptor to the device it is assigned to + float sensitivity; // Sensitivitzy multiplier for relative mouse movements + Rectangle absRange; // Range of values for absolute pointing devices (touchscreens) + int touchSlot; // Hold the touch slot number of the currently being sent multitouch block + bool isMouse; // True if device supports relative X Y movements + bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH + bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH + bool isKeyboard; // True if device has letter keycodes + bool isGamepad; // True if device has gamepad buttons +}InputEventWorker; + +static InputEventWorker eventWorkers[10]; // List of worker threads for every monitored "/dev/input/event" + #endif #if defined(PLATFORM_WEB) static bool toggleCursorLock = false; // Ask for cursor pointer lock on next click @@ -447,9 +458,8 @@ static void InitKeyboard(void); // Init raw keyboard sys 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 InitTouch(void); // Touch device initialization (including touch thread) -static void *TouchThread(void *arg); // Touch device reading thread +static void EventThreadSpawn(char* device); // Indetifies a input device and spawns a thread to handle it if needed +static void *EventThread(void *arg); // Input device event reading thread static void InitGamepad(void); // Init raw gamepad input static void *GamepadThread(void *arg); // Mouse reading thread #endif @@ -566,7 +576,6 @@ void InitWindow(int width, int height, const char *title) #if defined(PLATFORM_RPI) // Init raw input system InitMouse(); // Mouse init - InitTouch(); // Touch init InitKeyboard(); // Keyboard init InitGamepad(); // Gamepad init #endif @@ -661,8 +670,13 @@ void CloseWindow(void) windowShouldClose = true; // Added to force threads to exit when the close window is called - pthread_join(mouseThreadId, NULL); - pthread_join(touchThreadId, NULL); + for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) + { + if(eventWorkers[i].threadId == 0) + { + pthread_join(eventWorkers[i].threadId, NULL); + } + } pthread_join(gamepadThreadId, NULL); #endif @@ -1984,7 +1998,7 @@ bool IsMouseButtonPressed(int button) #else if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true; #endif - + return pressed; } @@ -2128,7 +2142,9 @@ Vector2 GetTouchPosition(int index) 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 +#elif defined(PLATFORM_RPI) + position = touchPosition[index]; +#else // PLATFORM_DESKTOP if (index == 0) position = GetMousePosition(); #endif @@ -2895,6 +2911,21 @@ static void PollInputEvents(void) gamepadAxisCount = 0; #endif +#if defined(PLATFORM_RPI) + // Register previous keys states + for (int i = 0; i < 512; i++) previousKeyState[i] = currentKeyState[i]; + + // Register previous mouse states + previousMouseWheelY = currentMouseWheelY; + currentMouseWheelY = 0; + for (int i = 0; i < 3; i++) + { + previousMouseState[i] = currentMouseState[i]; + currentMouseState[i] = currentMouseStateEvdev[i]; + } + +#endif + #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling double mouseX; @@ -3829,182 +3860,351 @@ static void RestoreKeyboard(void) // Mouse initialization (including mouse thread) static void InitMouse(void) { - // NOTE: We can use /dev/input/mice to read from all available mice - if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0) + char Path[256]; + DIR *d; + struct dirent *dir; + + // Reset variables + for (int i = 0; i < MAX_TOUCH_POINTS; ++i) + { + touchPosition[i].x = -1; + touchPosition[i].y = -1; + } + + // Open the linux directory of "/dev/input" + d = opendir(DEFAULT_EVDEV_PATH); + if (d) { - TraceLog(LOG_WARNING, "Mouse device could not be opened, no mouse available"); + while ((dir = readdir(d)) != NULL) + { + if(strncmp("event", dir->d_name, strlen("event")) == 0) // Search for devices named "event*" + { + sprintf(Path, "%s%s", DEFAULT_EVDEV_PATH, dir->d_name); + EventThreadSpawn(Path); // Identify the device and spawn a thread for it + } + } + closedir(d); } else { - mouseReady = true; - - int error = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL); - - if (error != 0) TraceLog(LOG_WARNING, "Error creating mouse input event thread"); - else TraceLog(LOG_INFO, "Mouse device initialized successfully"); + TraceLog(LOG_WARNING, "Unable to open linux event directory %s", DEFAULT_EVDEV_PATH); } } -// Mouse reading thread -// NOTE: We need a separate thread to avoid loosing mouse events, -// if too much time passes between reads, queue gets full and new events override older ones... -static void *MouseThread(void *arg) -{ - const unsigned char XSIGN = (1 << 4); - const unsigned char YSIGN = (1 << 5); - - typedef struct { - char buttons; - char dx, dy; - } MouseEvent; - - MouseEvent mouse; +static void EventThreadSpawn(char* device) +{ + #define BITS_PER_LONG (sizeof(long) * 8) + #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) + #define OFF(x) ((x)%BITS_PER_LONG) + #define BIT(x) (1UL<> OFF(bit)) & 1) + struct input_absinfo absinfo; + unsigned long ev_bits[NBITS(EV_MAX)]; + unsigned long abs_bits[NBITS(ABS_MAX)]; + unsigned long rel_bits[NBITS(REL_MAX)]; + unsigned long key_bits[NBITS(KEY_MAX)]; + bool hasAbs = false; + bool hasRel = false; + bool hasAbsMulti = false; + int FreeWorkerId = -1; + int fd = -1; + InputEventWorker* Worker; + + /////////////////////////////////// Open the device and allocate worker ///////////////////////////////////////////// + + // Find a free spot in the workers array + for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) + { + if(eventWorkers[i].threadId == 0) + { + FreeWorkerId = i; + break; + } + } - int mouseRelX = 0; - int mouseRelY = 0; + // Select the free worker from array + if(FreeWorkerId >= 0) + { + Worker = &(eventWorkers[FreeWorkerId]); // Grab a pointer to the worker + memset(Worker, 0, sizeof(InputEventWorker)); // Clear the worker + } + else + { + TraceLog(LOG_WARNING, "Error creating input device thread for '%s': Out of worker slots", device); + return; + } - while (!windowShouldClose) + // Open the device + fd = open(device, O_RDONLY | O_NONBLOCK); + if(fd < 0) { - if (read(mouseStream, &mouse, sizeof(MouseEvent)) == (int)sizeof(MouseEvent)) - { - if ((mouse.buttons & 0x08) == 0) break; // This bit should always be set + TraceLog(LOG_WARNING, "Error creating input device thread for '%s': Can't open device (Err: %d)", device, Worker->fd); + return; + } + Worker->fd = fd; - // Check Left button pressed - if ((mouse.buttons & 0x01) > 0) currentMouseState[0] = 1; - else currentMouseState[0] = 0; + // At this point we have a connection to the device, + // but we don't yet know what the device is (Could be + // many things, even as simple as a power button) - // Check Right button pressed - if ((mouse.buttons & 0x02) > 0) currentMouseState[1] = 1; - else currentMouseState[1] = 0; + /////////////////////////////////// Identify the device ///////////////////////////////////////////// - // Check Middle button pressed - if ((mouse.buttons & 0x04) > 0) currentMouseState[2] = 1; - else currentMouseState[2] = 0; + ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits); // Read a bitfield of the avalable device properties + + // Check for absolute input devices + if (TEST_BIT(ev_bits, EV_ABS)) + { + ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)),abs_bits); - mouseRelX = (int)mouse.dx; - mouseRelY = (int)mouse.dy; + // Check for absolute movement support (usualy touchscreens, but also joysticks) + if (TEST_BIT(abs_bits, ABS_X) && TEST_BIT(abs_bits, ABS_Y)) + { + hasAbs = true; + // Get the scaling values + ioctl(fd, EVIOCGABS(ABS_X), &absinfo); + Worker->absRange.x = absinfo.minimum; + Worker->absRange.width = absinfo.maximum - absinfo.minimum; + ioctl(fd, EVIOCGABS(ABS_Y), &absinfo); + Worker->absRange.y = absinfo.minimum; + Worker->absRange.height = absinfo.maximum - absinfo.minimum; + } + + // Check for multiple absolute movement support (usualy multitouch touchscreens) + if (TEST_BIT(abs_bits, ABS_MT_POSITION_X) && TEST_BIT(abs_bits, ABS_MT_POSITION_Y)) + { + hasAbsMulti = true; + // Get the scaling values + ioctl(fd, EVIOCGABS(ABS_X), &absinfo); + Worker->absRange.x = absinfo.minimum; + Worker->absRange.width = absinfo.maximum - absinfo.minimum; + ioctl(fd, EVIOCGABS(ABS_Y), &absinfo); + Worker->absRange.y = absinfo.minimum; + Worker->absRange.height = absinfo.maximum - absinfo.minimum; + } + } - if ((mouse.buttons & XSIGN) > 0) mouseRelX = -1*(255 - mouseRelX); - if ((mouse.buttons & YSIGN) > 0) mouseRelY = -1*(255 - mouseRelY); + // Check for relative movement support (usualy mouse) + if (TEST_BIT(ev_bits, EV_REL)) + { + ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)),rel_bits); + if (TEST_BIT(rel_bits, REL_X) && TEST_BIT(rel_bits, REL_Y)) + { + hasRel = true; + } + } - // 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 + // Check for button support to determine the device type(usualy on all input devices) + if (TEST_BIT(ev_bits, EV_KEY)) + { + ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)),key_bits); - mousePosition.x += (float)mouseRelX*((float)screenWidth/(2*255))*MOUSE_SENSITIVITY; - mousePosition.y -= (float)mouseRelY*((float)screenHeight/(2*255))*MOUSE_SENSITIVITY; + if(hasAbs || hasAbsMulti) + { + if(TEST_BIT(key_bits, BTN_TOUCH)) + Worker->isTouch = true; // This is a touchscreen + if(TEST_BIT(key_bits, BTN_TOOL_FINGER)) + Worker->isTouch = true; // This is a drawing tablet + if(TEST_BIT(key_bits, BTN_TOOL_PEN)) + Worker->isTouch = true; // This is a drawing tablet + if(TEST_BIT(key_bits, BTN_STYLUS)) + Worker->isTouch = true; // This is a drawing tablet + if(Worker->isTouch || hasAbsMulti) + Worker->isMultitouch = true; // This is a multitouch capable device + } - if (mousePosition.x < 0) mousePosition.x = 0; - if (mousePosition.y < 0) mousePosition.y = 0; + if(hasRel) + { + if (TEST_BIT(key_bits, BTN_LEFT)) + Worker->isMouse = true; // This is a mouse + if (TEST_BIT(key_bits, BTN_RIGHT)) + Worker->isMouse = true; // This is a mouse + } - if (mousePosition.x > screenWidth) mousePosition.x = screenWidth; - if (mousePosition.y > screenHeight) mousePosition.y = screenHeight; - } - //else read(mouseStream, &mouse, 1); // Try to sync up again + if (TEST_BIT(key_bits, BTN_A)) + Worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(key_bits, BTN_TRIGGER)) + Worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(key_bits, BTN_START)) + Worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(key_bits, BTN_TL)) + Worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(key_bits, BTN_TL)) + Worker->isGamepad = true; // This is a gamepad + + if (TEST_BIT(key_bits, KEY_SPACE)) + Worker->isKeyboard = true; // This is a keyboard } - return NULL; -} -// Touch initialization (including touch thread) -static void InitTouch(void) -{ - if ((touchStream = open(DEFAULT_TOUCH_DEV, O_RDONLY|O_NONBLOCK)) < 0) + /////////////////////////////////// Decide what to do with the device ///////////////////////////////////////////// + if(Worker->isTouch || Worker->isMouse) { - TraceLog(LOG_WARNING, "Touch device could not be opened, no touchscreen available"); + // Looks like a interesting device + TraceLog(LOG_INFO, "Opening input device '%s' (%s%s%s%s%s)", device, + Worker->isMouse ? "mouse " : "", + Worker->isMultitouch ? "multitouch " : "", + Worker->isTouch ? "touchscreen " : "", + Worker->isGamepad ? "gamepad " : "", + Worker->isKeyboard ? "keyboard " : "" + ); + // Create a thread for this device + int error = pthread_create(&Worker->threadId, NULL, &EventThread, (void*)Worker); + if(error != 0) + { + TraceLog(LOG_WARNING, "Error creating input device thread for '%s': Can't create thread (Err: %d)", device, error); + Worker->threadId = 0; + close(fd); + } } else { - touchReady = true; - - int error = pthread_create(&touchThreadId, NULL, &TouchThread, NULL); - - if (error != 0) TraceLog(LOG_WARNING, "Error creating touch input event thread"); - else TraceLog(LOG_INFO, "Touch device initialized successfully"); + // We are not interested in this device + close(fd); } } -// Touch reading thread. -// This reads from a Virtual Input Event /dev/input/event4 which is -// created by the ts_uinput daemon. This takes, filters and scales -// raw input from the Touchscreen (which appears in /dev/input/event3) -// based on the Calibration data referenced by tslib. -static void *TouchThread(void *arg) +static void *EventThread(void *arg) { struct input_event ev; GestureEvent gestureEvent; + InputEventWorker* Worker = (InputEventWorker*)arg; + bool GestureNeedsUpdate = false; while (!windowShouldClose) { - if (read(touchStream, &ev, sizeof(ev)) == (int)sizeof(ev)) + if (read(Worker->fd, &ev, sizeof(ev)) == (int)sizeof(ev)) { - // if pressure > 0 then simulate left mouse button click - if (ev.type == EV_ABS && ev.code == 24 && ev.value == 0 && currentMouseState[0] == 1) + /////////////////////////////// Relative movement parsing //////////////////////////////////// + if(ev.type == EV_REL) { - currentMouseState[0] = 0; - gestureEvent.touchAction = TOUCH_UP; - gestureEvent.pointCount = 1; - gestureEvent.pointerId[0] = 0; - gestureEvent.pointerId[1] = 1; - gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - gestureEvent.position[1].x /= (float)GetScreenWidth(); - gestureEvent.position[1].y /= (float)GetScreenHeight(); - ProcessGestureEvent(gestureEvent); + if(ev.code == REL_X) + { + mousePosition.x += ev.value; + touchPosition[0].x = mousePosition.x; + gestureEvent.touchAction = TOUCH_MOVE; + GestureNeedsUpdate = true; + } + + if(ev.code == REL_Y) + { + mousePosition.y += ev.value; + touchPosition[0].y = mousePosition.y; + gestureEvent.touchAction = TOUCH_MOVE; + GestureNeedsUpdate = true; + } + + if(ev.code == REL_WHEEL) + { + currentMouseWheelY += ev.value; + } } - if (ev.type == EV_ABS && ev.code == 24 && ev.value > 0 && currentMouseState[0] == 0) + + /////////////////////////////// Absolute movement parsing //////////////////////////////////// + if(ev.type == EV_ABS) { - currentMouseState[0] = 1; - gestureEvent.touchAction = TOUCH_DOWN; - gestureEvent.pointCount = 1; - gestureEvent.pointerId[0] = 0; - gestureEvent.pointerId[1] = 1; - gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - gestureEvent.position[1].x /= (float)GetScreenWidth(); - gestureEvent.position[1].y /= (float)GetScreenHeight(); - ProcessGestureEvent(gestureEvent); + // Basic movement + if(ev.code == ABS_X) + { + mousePosition.x = (ev.value - Worker->absRange.x) * screenWidth / Worker->absRange.width; //Scale acording to absRange + gestureEvent.touchAction = TOUCH_MOVE; + GestureNeedsUpdate = true; + } + + if(ev.code == ABS_Y) + { + mousePosition.y = (ev.value - Worker->absRange.y) * screenHeight / Worker->absRange.height; //Scale acording to absRange + gestureEvent.touchAction = TOUCH_MOVE; + GestureNeedsUpdate = true; + } + + //Multitouch movement + if(ev.code == ABS_MT_SLOT) + { + Worker->touchSlot = ev.value; //Remeber the slot number for the folowing events + } + + if(ev.code == ABS_MT_POSITION_X) + { + if(Worker->touchSlot < MAX_TOUCH_POINTS) + touchPosition[Worker->touchSlot].x = (ev.value - Worker->absRange.x) * screenWidth / Worker->absRange.width; //Scale acording to absRange + } + + if(ev.code == ABS_MT_POSITION_Y) + { + if(Worker->touchSlot < MAX_TOUCH_POINTS) + touchPosition[Worker->touchSlot].y = (ev.value - Worker->absRange.y) * screenHeight / Worker->absRange.height; //Scale acording to absRange + } + + if(ev.code == ABS_MT_TRACKING_ID) + { + if( (ev.value < 0) && (Worker->touchSlot < MAX_TOUCH_POINTS) ) + { + //Touch has ended for this point + touchPosition[Worker->touchSlot].x = -1; + touchPosition[Worker->touchSlot].y = -1; + } + } } - // x & y values supplied by event4 have been scaled & de-jittered using tslib calibration data - if (ev.type == EV_ABS && ev.code == 0) + + /////////////////////////////// Button parsing //////////////////////////////////// + if(ev.type == EV_KEY) { - mousePosition.x = ev.value; - if (mousePosition.x < 0) mousePosition.x = 0; - if (mousePosition.x > screenWidth) mousePosition.x = screenWidth; - gestureEvent.touchAction = TOUCH_MOVE; - gestureEvent.pointCount = 1; - gestureEvent.pointerId[0] = 0; - gestureEvent.pointerId[1] = 1; - gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - gestureEvent.position[1].x /= (float)GetScreenWidth(); - gestureEvent.position[1].y /= (float)GetScreenHeight(); - ProcessGestureEvent(gestureEvent); + if((ev.code == BTN_TOUCH) || (ev.code == BTN_LEFT)) + { + currentMouseStateEvdev[MOUSE_LEFT_BUTTON] = ev.value; + if(ev.value > 0) + gestureEvent.touchAction = TOUCH_DOWN; + else + gestureEvent.touchAction = TOUCH_UP; + GestureNeedsUpdate = true; + } + + if(ev.code == BTN_RIGHT) + { + currentMouseStateEvdev[MOUSE_RIGHT_BUTTON] = ev.value; + } + + if(ev.code == BTN_MIDDLE) + { + currentMouseStateEvdev[MOUSE_MIDDLE_BUTTON] = ev.value; + } + } - if (ev.type == EV_ABS && ev.code == 1) + + /////////////////////////////// Screen confinement //////////////////////////////////// + if(mousePosition.x < 0) + mousePosition.x = 0; + if(mousePosition.x > screenWidth / mouseScale) + mousePosition.x = screenWidth / mouseScale; + + if(mousePosition.y < 0) + mousePosition.y = 0; + if(mousePosition.y > screenHeight / mouseScale) + mousePosition.y = screenHeight / mouseScale; + + /////////////////////////////// Gesture update //////////////////////////////////// + if(GestureNeedsUpdate) { - mousePosition.y = ev.value; - if (mousePosition.y < 0) mousePosition.y = 0; - if (mousePosition.y > screenHeight) mousePosition.y = screenHeight; - gestureEvent.touchAction = TOUCH_MOVE; - gestureEvent.pointCount = 1; + gestureEvent.pointCount = 0; + if(touchPosition[0].x >= 0) gestureEvent.pointCount++; + if(touchPosition[1].x >= 0) gestureEvent.pointCount++; + if(touchPosition[2].x >= 0) gestureEvent.pointCount++; + if(touchPosition[3].x >= 0) gestureEvent.pointCount++; gestureEvent.pointerId[0] = 0; gestureEvent.pointerId[1] = 1; - gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - gestureEvent.position[1].x /= (float)GetScreenWidth(); - gestureEvent.position[1].y /= (float)GetScreenHeight(); + gestureEvent.pointerId[2] = 2; + gestureEvent.pointerId[3] = 3; + gestureEvent.position[0] = touchPosition[0]; + gestureEvent.position[1] = touchPosition[1]; + gestureEvent.position[2] = touchPosition[2]; + gestureEvent.position[3] = touchPosition[3]; ProcessGestureEvent(gestureEvent); } - + } + else + { + usleep(5000); //Sleep for 5ms to avoid hogging CPU time } } return NULL; @@ -4090,6 +4290,10 @@ static void *GamepadThread(void *arg) } } } + else + { + usleep(1000); //Sleep for 1ms to avoid hogging CPU time + } } } diff --git a/src/raylib.h b/src/raylib.h index aa5bd16f..8256b745 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -223,7 +223,7 @@ #define MOUSE_MIDDLE_BUTTON 2 // Touch points registered -#define MAX_TOUCH_POINTS 2 +#define MAX_TOUCH_POINTS 10 // Gamepad Number #define GAMEPAD_PLAYER1 0 -- cgit v1.2.3 From 3d825eb973096a1b1271374d02f3cbfa7200ee28 Mon Sep 17 00:00:00 2001 From: Berni8k Date: Sun, 21 Oct 2018 15:06:40 +0100 Subject: Added RaspberryPi option to ignore duplicate touchscreens (On by default) --- src/core.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index cb6c7e41..cc292012 100644 --- a/src/core.c +++ b/src/core.c @@ -226,6 +226,7 @@ #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input #define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...) #define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events + #define USE_LAST_TOUCH_DEVICE true // If true: When multiple touchscreens are connected then only use the one with the highest event number // New device input events (evdev) (must be detected) //#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN" @@ -328,12 +329,11 @@ static int currentMouseWheelY = 0; // Registers current mouse wheel #endif #if defined(PLATFORM_RPI) -static int mouseStream = -1; // Mouse device file descriptor static char currentMouseStateEvdev[3] = { 0 }; // Holds the new mouse state for the next polling event to grab (Can't be written directly due to multithreading, app could miss the update) typedef struct { pthread_t threadId; // Event reading thread id int fd; // File descriptor to the device it is assigned to - float sensitivity; // Sensitivitzy multiplier for relative mouse movements + int eventNum; // Number of 'event' device Rectangle absRange; // Range of values for absolute pointing devices (touchscreens) int touchSlot; // Hold the touch slot number of the currently being sent multitouch block bool isMouse; // True if device supports relative X Y movements @@ -3944,6 +3944,16 @@ static void EventThreadSpawn(char* device) } Worker->fd = fd; + //Grab number on the end of the devices name "event" + int DevNum; + char* ptrDevName = strrchr(device, 't'); + Worker->eventNum = -1; + if(ptrDevName != NULL) + { + if(sscanf(ptrDevName, "t%d", &DevNum) == 1) + Worker->eventNum = DevNum; + } + // At this point we have a connection to the device, // but we don't yet know what the device is (Could be // many things, even as simple as a power button) @@ -4048,6 +4058,7 @@ static void EventThreadSpawn(char* device) Worker->isGamepad ? "gamepad " : "", Worker->isKeyboard ? "keyboard " : "" ); + // Create a thread for this device int error = pthread_create(&Worker->threadId, NULL, &EventThread, (void*)Worker); if(error != 0) @@ -4056,6 +4067,31 @@ static void EventThreadSpawn(char* device) Worker->threadId = 0; close(fd); } + + // Kill off duplicate touchscreens if needed + if(USE_LAST_TOUCH_DEVICE) + { + // Find touchscreen with the highest index + int MaxTouchNumber = -1; + for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) + { + if(eventWorkers[i].isTouch && (eventWorkers[i].eventNum > MaxTouchNumber)) + MaxTouchNumber = eventWorkers[i].eventNum; + } + // Find toucnscreens with lower indexes + for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) + { + if(eventWorkers[i].isTouch && (eventWorkers[i].eventNum < MaxTouchNumber)) + { + if(eventWorkers[i].threadId != 0) + { + TraceLog(LOG_WARNING, "Duplicate touchscreen found, killing toucnscreen on event%d", i); + pthread_cancel(eventWorkers[i].threadId); + close(eventWorkers[i].fd); + } + } + } + } } else { @@ -4207,6 +4243,7 @@ static void *EventThread(void *arg) usleep(5000); //Sleep for 5ms to avoid hogging CPU time } } + close(Worker->fd); return NULL; } -- cgit v1.2.3 From b5bcf2c934a6b0c6b3e8bc9766abc658905fd694 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 22 Oct 2018 11:48:16 +0200 Subject: Review code formatting for RPI inputs --- src/core.c | 353 ++++++++++++++++++++++++++++--------------------------------- 1 file changed, 164 insertions(+), 189 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index cc292012..a0e53c87 100644 --- a/src/core.c +++ b/src/core.c @@ -222,11 +222,12 @@ // Defines and Macros //---------------------------------------------------------------------------------- #if defined(PLATFORM_RPI) + #define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event number + // Old device inputs system #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input #define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...) #define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events - #define USE_LAST_TOUCH_DEVICE true // If true: When multiple touchscreens are connected then only use the one with the highest event number // New device input events (evdev) (must be detected) //#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN" @@ -458,7 +459,7 @@ static void InitKeyboard(void); // Init raw keyboard sys 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 EventThreadSpawn(char* device); // Indetifies a input device and spawns a thread to handle it if needed +static void EventThreadSpawn(char *device); // Indetifies a input device and spawns a thread to handle it if needed static void *EventThread(void *arg); // Input device event reading thread static void InitGamepad(void); // Init raw gamepad input static void *GamepadThread(void *arg); // Mouse reading thread @@ -672,7 +673,7 @@ void CloseWindow(void) for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) { - if(eventWorkers[i].threadId == 0) + if (eventWorkers[i].threadId == 0) { pthread_join(eventWorkers[i].threadId, NULL); } @@ -785,7 +786,7 @@ void SetWindowMonitor(int monitor) { #if defined(PLATFORM_DESKTOP) int monitorCount; - GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); if ((monitor >= 0) && (monitor < monitorCount)) { @@ -862,7 +863,7 @@ int GetMonitorWidth(int monitor) { #if defined(PLATFORM_DESKTOP) int monitorCount; - GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); if ((monitor >= 0) && (monitor < monitorCount)) { @@ -879,7 +880,7 @@ int GetMonitorHeight(int monitor) { #if defined(PLATFORM_DESKTOP) int monitorCount; - GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); if ((monitor >= 0) && (monitor < monitorCount)) { @@ -896,7 +897,7 @@ int GetMonitorPhysicalWidth(int monitor) { #if defined(PLATFORM_DESKTOP) int monitorCount; - GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); if ((monitor >= 0) && (monitor < monitorCount)) { @@ -914,7 +915,7 @@ int GetMonitorPhysicalHeight(int monitor) { #if defined(PLATFORM_DESKTOP) int monitorCount; - GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); if ((monitor >= 0) && (monitor < monitorCount)) { @@ -932,7 +933,7 @@ const char *GetMonitorName(int monitor) { #if defined(PLATFORM_DESKTOP) int monitorCount; - GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); if ((monitor >= 0) && (monitor < monitorCount)) { @@ -3268,7 +3269,7 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height) } // GLFW3 WindowIconify Callback, runs when window is minimized/restored -static void WindowIconifyCallback(GLFWwindow* window, int iconified) +static void WindowIconifyCallback(GLFWwindow *window, int iconified) { if (iconified) windowMinimized = true; // The window was iconified else windowMinimized = false; // The window was restored @@ -3861,8 +3862,8 @@ static void RestoreKeyboard(void) static void InitMouse(void) { char Path[256]; - DIR *d; - struct dirent *dir; + DIR *directory; + struct dirent *entity; // Reset variables for (int i = 0; i < MAX_TOUCH_POINTS; ++i) @@ -3872,18 +3873,19 @@ static void InitMouse(void) } // Open the linux directory of "/dev/input" - d = opendir(DEFAULT_EVDEV_PATH); - if (d) + directory = opendir(DEFAULT_EVDEV_PATH); + if (directory) { - while ((dir = readdir(d)) != NULL) + while ((entity = readdir(directory)) != NULL) { - if(strncmp("event", dir->d_name, strlen("event")) == 0) // Search for devices named "event*" + if (strncmp("event", entity->d_name, strlen("event")) == 0) // Search for devices named "event*" { - sprintf(Path, "%s%s", DEFAULT_EVDEV_PATH, dir->d_name); - EventThreadSpawn(Path); // Identify the device and spawn a thread for it + sprintf(Path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name); + EventThreadSpawn(Path); // Identify the device and spawn a thread for it } } - closedir(d); + + closedir(directory); } else { @@ -3891,43 +3893,45 @@ static void InitMouse(void) } } -static void EventThreadSpawn(char* device) +static void EventThreadSpawn(char *device) { - #define BITS_PER_LONG (sizeof(long) * 8) - #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) - #define OFF(x) ((x)%BITS_PER_LONG) - #define BIT(x) (1UL<> OFF(bit)) & 1) + struct input_absinfo absinfo; - unsigned long ev_bits[NBITS(EV_MAX)]; - unsigned long abs_bits[NBITS(ABS_MAX)]; - unsigned long rel_bits[NBITS(REL_MAX)]; - unsigned long key_bits[NBITS(KEY_MAX)]; + unsigned long evBits[NBITS(EV_MAX)]; + unsigned long absBits[NBITS(ABS_MAX)]; + unsigned long relBits[NBITS(REL_MAX)]; + unsigned long keyBits[NBITS(KEY_MAX)]; bool hasAbs = false; bool hasRel = false; bool hasAbsMulti = false; - int FreeWorkerId = -1; + int freeWorkerId = -1; int fd = -1; - InputEventWorker* Worker; + + InputEventWorker *worker; /////////////////////////////////// Open the device and allocate worker ///////////////////////////////////////////// // Find a free spot in the workers array for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) { - if(eventWorkers[i].threadId == 0) + if (eventWorkers[i].threadId == 0) { - FreeWorkerId = i; + freeWorkerId = i; break; } } // Select the free worker from array - if(FreeWorkerId >= 0) + if (freeWorkerId >= 0) { - Worker = &(eventWorkers[FreeWorkerId]); // Grab a pointer to the worker - memset(Worker, 0, sizeof(InputEventWorker)); // Clear the worker + worker = &(eventWorkers[freeWorkerId]); // Grab a pointer to the worker + memset(worker, 0, sizeof(InputEventWorker)); // Clear the worker } else { @@ -3937,296 +3941,265 @@ static void EventThreadSpawn(char* device) // Open the device fd = open(device, O_RDONLY | O_NONBLOCK); - if(fd < 0) + if (fd < 0) { - TraceLog(LOG_WARNING, "Error creating input device thread for '%s': Can't open device (Err: %d)", device, Worker->fd); + TraceLog(LOG_WARNING, "Error creating input device thread for '%s': Can't open device (Err: %d)", device, worker->fd); return; } - Worker->fd = fd; + worker->fd = fd; //Grab number on the end of the devices name "event" - int DevNum; - char* ptrDevName = strrchr(device, 't'); - Worker->eventNum = -1; - if(ptrDevName != NULL) + int devNum = 0; + char *ptrDevName = strrchr(device, 't'); + worker->eventNum = -1; + + if (ptrDevName != NULL) { - if(sscanf(ptrDevName, "t%d", &DevNum) == 1) - Worker->eventNum = DevNum; + if (sscanf(ptrDevName, "t%d", &devNum) == 1) + worker->eventNum = devNum; } // At this point we have a connection to the device, // but we don't yet know what the device is (Could be // many things, even as simple as a power button) - /////////////////////////////////// Identify the device ///////////////////////////////////////////// + /////////////////////////////////// Identify the device ///////////////////////////////////////////// - ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits); // Read a bitfield of the avalable device properties + ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits); // Read a bitfield of the avalable device properties // Check for absolute input devices - if (TEST_BIT(ev_bits, EV_ABS)) + if (TEST_BIT(evBits, EV_ABS)) { - ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)),abs_bits); + ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits); // Check for absolute movement support (usualy touchscreens, but also joysticks) - if (TEST_BIT(abs_bits, ABS_X) && TEST_BIT(abs_bits, ABS_Y)) + if (TEST_BIT(absBits, ABS_X) && TEST_BIT(absBits, ABS_Y)) { hasAbs = true; + // Get the scaling values ioctl(fd, EVIOCGABS(ABS_X), &absinfo); - Worker->absRange.x = absinfo.minimum; - Worker->absRange.width = absinfo.maximum - absinfo.minimum; + worker->absRange.x = absinfo.minimum; + worker->absRange.width = absinfo.maximum - absinfo.minimum; ioctl(fd, EVIOCGABS(ABS_Y), &absinfo); - Worker->absRange.y = absinfo.minimum; - Worker->absRange.height = absinfo.maximum - absinfo.minimum; + worker->absRange.y = absinfo.minimum; + worker->absRange.height = absinfo.maximum - absinfo.minimum; } // Check for multiple absolute movement support (usualy multitouch touchscreens) - if (TEST_BIT(abs_bits, ABS_MT_POSITION_X) && TEST_BIT(abs_bits, ABS_MT_POSITION_Y)) + if (TEST_BIT(absBits, ABS_MT_POSITION_X) && TEST_BIT(absBits, ABS_MT_POSITION_Y)) { hasAbsMulti = true; + // Get the scaling values ioctl(fd, EVIOCGABS(ABS_X), &absinfo); - Worker->absRange.x = absinfo.minimum; - Worker->absRange.width = absinfo.maximum - absinfo.minimum; + worker->absRange.x = absinfo.minimum; + worker->absRange.width = absinfo.maximum - absinfo.minimum; ioctl(fd, EVIOCGABS(ABS_Y), &absinfo); - Worker->absRange.y = absinfo.minimum; - Worker->absRange.height = absinfo.maximum - absinfo.minimum; + worker->absRange.y = absinfo.minimum; + worker->absRange.height = absinfo.maximum - absinfo.minimum; } } // Check for relative movement support (usualy mouse) - if (TEST_BIT(ev_bits, EV_REL)) + if (TEST_BIT(evBits, EV_REL)) { - ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)),rel_bits); - if (TEST_BIT(rel_bits, REL_X) && TEST_BIT(rel_bits, REL_Y)) - { - hasRel = true; - } + ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits); + + if (TEST_BIT(relBits, REL_X) && TEST_BIT(relBits, REL_Y)) hasRel = true; } // Check for button support to determine the device type(usualy on all input devices) - if (TEST_BIT(ev_bits, EV_KEY)) + if (TEST_BIT(evBits, EV_KEY)) { - ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)),key_bits); + ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits); - if(hasAbs || hasAbsMulti) + if (hasAbs || hasAbsMulti) { - if(TEST_BIT(key_bits, BTN_TOUCH)) - Worker->isTouch = true; // This is a touchscreen - if(TEST_BIT(key_bits, BTN_TOOL_FINGER)) - Worker->isTouch = true; // This is a drawing tablet - if(TEST_BIT(key_bits, BTN_TOOL_PEN)) - Worker->isTouch = true; // This is a drawing tablet - if(TEST_BIT(key_bits, BTN_STYLUS)) - Worker->isTouch = true; // This is a drawing tablet - if(Worker->isTouch || hasAbsMulti) - Worker->isMultitouch = true; // This is a multitouch capable device + if (TEST_BIT(keyBits, BTN_TOUCH)) worker->isTouch = true; // This is a touchscreen + if (TEST_BIT(keyBits, BTN_TOOL_FINGER)) worker->isTouch = true; // This is a drawing tablet + if (TEST_BIT(keyBits, BTN_TOOL_PEN)) worker->isTouch = true; // This is a drawing tablet + if (TEST_BIT(keyBits, BTN_STYLUS)) worker->isTouch = true; // This is a drawing tablet + if (worker->isTouch || hasAbsMulti) worker->isMultitouch = true; // This is a multitouch capable device } - if(hasRel) + if (hasRel) { - if (TEST_BIT(key_bits, BTN_LEFT)) - Worker->isMouse = true; // This is a mouse - if (TEST_BIT(key_bits, BTN_RIGHT)) - Worker->isMouse = true; // This is a mouse + if (TEST_BIT(keyBits, BTN_LEFT)) worker->isMouse = true; // This is a mouse + if (TEST_BIT(keyBits, BTN_RIGHT)) worker->isMouse = true; // This is a mouse } - if (TEST_BIT(key_bits, BTN_A)) - Worker->isGamepad = true; // This is a gamepad - if (TEST_BIT(key_bits, BTN_TRIGGER)) - Worker->isGamepad = true; // This is a gamepad - if (TEST_BIT(key_bits, BTN_START)) - Worker->isGamepad = true; // This is a gamepad - if (TEST_BIT(key_bits, BTN_TL)) - Worker->isGamepad = true; // This is a gamepad - if (TEST_BIT(key_bits, BTN_TL)) - Worker->isGamepad = true; // This is a gamepad - - if (TEST_BIT(key_bits, KEY_SPACE)) - Worker->isKeyboard = true; // This is a keyboard + if (TEST_BIT(keyBits, BTN_A)) worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(keyBits, BTN_TRIGGER)) worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(keyBits, BTN_START)) worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(keyBits, BTN_TL)) worker->isGamepad = true; // This is a gamepad + if (TEST_BIT(keyBits, BTN_TL)) worker->isGamepad = true; // This is a gamepad + + if (TEST_BIT(keyBits, KEY_SPACE)) worker->isKeyboard = true; // This is a keyboard } /////////////////////////////////// Decide what to do with the device ///////////////////////////////////////////// - if(Worker->isTouch || Worker->isMouse) + if (worker->isTouch || worker->isMouse) { // Looks like a interesting device TraceLog(LOG_INFO, "Opening input device '%s' (%s%s%s%s%s)", device, - Worker->isMouse ? "mouse " : "", - Worker->isMultitouch ? "multitouch " : "", - Worker->isTouch ? "touchscreen " : "", - Worker->isGamepad ? "gamepad " : "", - Worker->isKeyboard ? "keyboard " : "" - ); + worker->isMouse ? "mouse " : "", + worker->isMultitouch ? "multitouch " : "", + worker->isTouch ? "touchscreen " : "", + worker->isGamepad ? "gamepad " : "", + worker->isKeyboard ? "keyboard " : ""); // Create a thread for this device - int error = pthread_create(&Worker->threadId, NULL, &EventThread, (void*)Worker); - if(error != 0) + int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker); + if (error != 0) { TraceLog(LOG_WARNING, "Error creating input device thread for '%s': Can't create thread (Err: %d)", device, error); - Worker->threadId = 0; + worker->threadId = 0; close(fd); } - // Kill off duplicate touchscreens if needed - if(USE_LAST_TOUCH_DEVICE) +#if defined(USE_LAST_TOUCH_DEVICE) + // Find touchscreen with the highest index + int maxTouchNumber = -1; + + for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) { - // Find touchscreen with the highest index - int MaxTouchNumber = -1; - for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) - { - if(eventWorkers[i].isTouch && (eventWorkers[i].eventNum > MaxTouchNumber)) - MaxTouchNumber = eventWorkers[i].eventNum; - } - // Find toucnscreens with lower indexes - for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) + if (eventWorkers[i].isTouch && (eventWorkers[i].eventNum > maxTouchNumber)) maxTouchNumber = eventWorkers[i].eventNum; + } + + // Find toucnscreens with lower indexes + for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) + { + if (eventWorkers[i].isTouch && (eventWorkers[i].eventNum < maxTouchNumber)) { - if(eventWorkers[i].isTouch && (eventWorkers[i].eventNum < MaxTouchNumber)) + if (eventWorkers[i].threadId != 0) { - if(eventWorkers[i].threadId != 0) - { - TraceLog(LOG_WARNING, "Duplicate touchscreen found, killing toucnscreen on event%d", i); - pthread_cancel(eventWorkers[i].threadId); - close(eventWorkers[i].fd); - } + TraceLog(LOG_WARNING, "Duplicate touchscreen found, killing toucnscreen on event%d", i); + pthread_cancel(eventWorkers[i].threadId); + close(eventWorkers[i].fd); } } } +#endif } - else - { - // We are not interested in this device - close(fd); - } + else close(fd); // We are not interested in this device } static void *EventThread(void *arg) { - struct input_event ev; + struct input_event event; GestureEvent gestureEvent; - InputEventWorker* Worker = (InputEventWorker*)arg; + InputEventWorker *worker = (InputEventWorker *)arg; bool GestureNeedsUpdate = false; while (!windowShouldClose) { - if (read(Worker->fd, &ev, sizeof(ev)) == (int)sizeof(ev)) + if (read(worker->fd, &event, sizeof(event)) == (int)sizeof(event)) { /////////////////////////////// Relative movement parsing //////////////////////////////////// - if(ev.type == EV_REL) + if (event.type == EV_REL) { - if(ev.code == REL_X) + if (event.code == REL_X) { - mousePosition.x += ev.value; + mousePosition.x += event.value; touchPosition[0].x = mousePosition.x; gestureEvent.touchAction = TOUCH_MOVE; GestureNeedsUpdate = true; } - if(ev.code == REL_Y) + if (event.code == REL_Y) { - mousePosition.y += ev.value; + mousePosition.y += event.value; touchPosition[0].y = mousePosition.y; gestureEvent.touchAction = TOUCH_MOVE; GestureNeedsUpdate = true; } - if(ev.code == REL_WHEEL) + if (event.code == REL_WHEEL) { - currentMouseWheelY += ev.value; + currentMouseWheelY += event.value; } } /////////////////////////////// Absolute movement parsing //////////////////////////////////// - if(ev.type == EV_ABS) + if (event.type == EV_ABS) { // Basic movement - if(ev.code == ABS_X) + if (event.code == ABS_X) { - mousePosition.x = (ev.value - Worker->absRange.x) * screenWidth / Worker->absRange.width; //Scale acording to absRange + mousePosition.x = (event.value - worker->absRange.x)*screenWidth/worker->absRange.width; // Scale acording to absRange gestureEvent.touchAction = TOUCH_MOVE; GestureNeedsUpdate = true; } - if(ev.code == ABS_Y) + if (event.code == ABS_Y) { - mousePosition.y = (ev.value - Worker->absRange.y) * screenHeight / Worker->absRange.height; //Scale acording to absRange + mousePosition.y = (event.value - worker->absRange.y)*screenHeight/worker->absRange.height; // Scale acording to absRange gestureEvent.touchAction = TOUCH_MOVE; GestureNeedsUpdate = true; } - //Multitouch movement - if(ev.code == ABS_MT_SLOT) + // Multitouch movement + if (event.code == ABS_MT_SLOT) { - Worker->touchSlot = ev.value; //Remeber the slot number for the folowing events + worker->touchSlot = event.value; // Remeber the slot number for the folowing events } - if(ev.code == ABS_MT_POSITION_X) + if (event.code == ABS_MT_POSITION_X) { - if(Worker->touchSlot < MAX_TOUCH_POINTS) - touchPosition[Worker->touchSlot].x = (ev.value - Worker->absRange.x) * screenWidth / Worker->absRange.width; //Scale acording to absRange + if (worker->touchSlot < MAX_TOUCH_POINTS) + touchPosition[worker->touchSlot].x = (event.value - worker->absRange.x)*screenWidth/worker->absRange.width; // Scale acording to absRange } - if(ev.code == ABS_MT_POSITION_Y) + if (event.code == ABS_MT_POSITION_Y) { - if(Worker->touchSlot < MAX_TOUCH_POINTS) - touchPosition[Worker->touchSlot].y = (ev.value - Worker->absRange.y) * screenHeight / Worker->absRange.height; //Scale acording to absRange + if (worker->touchSlot < MAX_TOUCH_POINTS) + touchPosition[worker->touchSlot].y = (event.value - worker->absRange.y)*screenHeight/worker->absRange.height; // Scale acording to absRange } - if(ev.code == ABS_MT_TRACKING_ID) + if (event.code == ABS_MT_TRACKING_ID) { - if( (ev.value < 0) && (Worker->touchSlot < MAX_TOUCH_POINTS) ) + if ( (event.value < 0) && (worker->touchSlot < MAX_TOUCH_POINTS) ) { - //Touch has ended for this point - touchPosition[Worker->touchSlot].x = -1; - touchPosition[Worker->touchSlot].y = -1; + // Touch has ended for this point + touchPosition[worker->touchSlot].x = -1; + touchPosition[worker->touchSlot].y = -1; } } } /////////////////////////////// Button parsing //////////////////////////////////// - if(ev.type == EV_KEY) + if (event.type == EV_KEY) { - if((ev.code == BTN_TOUCH) || (ev.code == BTN_LEFT)) + if((event.code == BTN_TOUCH) || (event.code == BTN_LEFT)) { - currentMouseStateEvdev[MOUSE_LEFT_BUTTON] = ev.value; - if(ev.value > 0) - gestureEvent.touchAction = TOUCH_DOWN; - else - gestureEvent.touchAction = TOUCH_UP; + currentMouseStateEvdev[MOUSE_LEFT_BUTTON] = event.value; + if (event.value > 0) gestureEvent.touchAction = TOUCH_DOWN; + else gestureEvent.touchAction = TOUCH_UP; GestureNeedsUpdate = true; } - if(ev.code == BTN_RIGHT) - { - currentMouseStateEvdev[MOUSE_RIGHT_BUTTON] = ev.value; - } - - if(ev.code == BTN_MIDDLE) - { - currentMouseStateEvdev[MOUSE_MIDDLE_BUTTON] = ev.value; - } + if (event.code == BTN_RIGHT) currentMouseStateEvdev[MOUSE_RIGHT_BUTTON] = event.value; + if (event.code == BTN_MIDDLE) currentMouseStateEvdev[MOUSE_MIDDLE_BUTTON] = event.value; } /////////////////////////////// Screen confinement //////////////////////////////////// - if(mousePosition.x < 0) - mousePosition.x = 0; - if(mousePosition.x > screenWidth / mouseScale) - mousePosition.x = screenWidth / mouseScale; + if (mousePosition.x < 0) mousePosition.x = 0; + if (mousePosition.x > screenWidth/mouseScale) mousePosition.x = screenWidth/mouseScale; - if(mousePosition.y < 0) - mousePosition.y = 0; - if(mousePosition.y > screenHeight / mouseScale) - mousePosition.y = screenHeight / mouseScale; + if (mousePosition.y < 0) mousePosition.y = 0; + if (mousePosition.y > screenHeight/mouseScale) mousePosition.y = screenHeight/mouseScale; /////////////////////////////// Gesture update //////////////////////////////////// - if(GestureNeedsUpdate) + if (GestureNeedsUpdate) { gestureEvent.pointCount = 0; - if(touchPosition[0].x >= 0) gestureEvent.pointCount++; - if(touchPosition[1].x >= 0) gestureEvent.pointCount++; - if(touchPosition[2].x >= 0) gestureEvent.pointCount++; - if(touchPosition[3].x >= 0) gestureEvent.pointCount++; + if (touchPosition[0].x >= 0) gestureEvent.pointCount++; + if (touchPosition[1].x >= 0) gestureEvent.pointCount++; + if (touchPosition[2].x >= 0) gestureEvent.pointCount++; + if (touchPosition[3].x >= 0) gestureEvent.pointCount++; gestureEvent.pointerId[0] = 0; gestureEvent.pointerId[1] = 1; gestureEvent.pointerId[2] = 2; @@ -4240,10 +4213,12 @@ static void *EventThread(void *arg) } else { - usleep(5000); //Sleep for 5ms to avoid hogging CPU time + usleep(5000); // Sleep for 5ms to avoid hogging CPU time } } - close(Worker->fd); + + close(worker->fd); + return NULL; } -- cgit v1.2.3 From 550dd40cb324896138dde9ee43bb44c0b9723345 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 23 Oct 2018 15:43:19 +0200 Subject: ADDED: SplitText() function --- src/raylib.h | 7 ++- src/text.c | 140 +++++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 93 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/raylib.h b/src/raylib.h index 8256b745..be2383b1 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1088,10 +1088,13 @@ RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontS // Text misc. functions RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font -RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' -RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on font +// Text string edition functions +RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' +RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string +RLAPI char **SplitText(char *text, char delimiter, int *strCount); // Split text string into multiple strings (memory should be freed manually!) + //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) //------------------------------------------------------------------------------------ diff --git a/src/text.c b/src/text.c index 51e93b72..6e86958e 100644 --- a/src/text.c +++ b/src/text.c @@ -566,6 +566,28 @@ void UnloadFont(Font font) } } +// Shows current FPS on top-left corner +// NOTE: Uses default font +void DrawFPS(int posX, int posY) +{ + // NOTE: We are rendering fps every second for better viewing on high framerates + + static int fps = 0; + static int counter = 0; + static int refreshRate = 20; + + if (counter < refreshRate) counter++; + else + { + fps = GetFPS(); + refreshRate = fps; + counter = 0; + } + + // NOTE: We have rounding errors every frame, so it oscillates a lot + DrawText(FormatText("%2i FPS", fps), posX, posY, 20, LIME); +} + // Draw text (using default font) // NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used // NOTE: chars spacing is proportional to fontSize @@ -642,44 +664,6 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f } } -// Formatting of text with variables to 'embed' -const char *FormatText(const char *text, ...) -{ - static char buffer[MAX_FORMATTEXT_LENGTH]; - - va_list args; - va_start(args, text); - vsprintf(buffer, text, args); - va_end(args); - - return buffer; -} - -// Get a piece of a text string -const char *SubText(const char *text, int position, int length) -{ - static char buffer[MAX_SUBTEXT_LENGTH] = { 0 }; - int textLength = strlen(text); - - if (position >= textLength) - { - position = textLength - 1; - length = 0; - } - - if (length >= textLength) length = textLength; - - for (int c = 0 ; c < length ; c++) - { - *(buffer + c) = *(text + position); - text++; - } - - *(buffer + length) = '\0'; - - return buffer; -} - // Measure string width for default font int MeasureText(const char *text, int fontSize) { @@ -764,26 +748,78 @@ int GetGlyphIndex(Font font, int character) #endif } -// Shows current FPS on top-left corner -// NOTE: Uses default font -void DrawFPS(int posX, int posY) +// Formatting of text with variables to 'embed' +const char *FormatText(const char *text, ...) { - // NOTE: We are rendering fps every second for better viewing on high framerates + static char buffer[MAX_FORMATTEXT_LENGTH]; - static int fps = 0; - static int counter = 0; - static int refreshRate = 20; + va_list args; + va_start(args, text); + vsprintf(buffer, text, args); + va_end(args); - if (counter < refreshRate) counter++; - else + return buffer; +} + +// Get a piece of a text string +const char *SubText(const char *text, int position, int length) +{ + static char buffer[MAX_SUBTEXT_LENGTH] = { 0 }; + int textLength = strlen(text); + + if (position >= textLength) { - fps = GetFPS(); - refreshRate = fps; - counter = 0; + position = textLength - 1; + length = 0; } + + if (length >= textLength) length = textLength; + + for (int c = 0 ; c < length ; c++) + { + *(buffer + c) = *(text + position); + text++; + } + + *(buffer + length) = '\0'; + + return buffer; +} + +// Split string into multiple strings +// NOTE: Files count is returned by parameters pointer +// NOTE: Allocated memory should be manually freed +char **SplitText(char *text, char delimiter, int *strCount) +{ + #define MAX_SUBSTRING_LENGTH 128 + + char **strings = NULL; + int len = strlen(text); + char *strDup = (char *)malloc(len + 1); + strcpy(strDup, text); + int counter = 1; - // NOTE: We have rounding errors every frame, so it oscillates a lot - DrawText(FormatText("%2i FPS", fps), posX, posY, 20, LIME); + // Count how many substrings we have on string + for (int i = 0; i < len; i++) if (text[i] == delimiter) counter++; + + // Memory allocation for substrings + strings = (char **)malloc(sizeof(char *)*counter); + for (int i = 0; i < counter; i++) strings[i] = (char *)malloc(sizeof(char)*MAX_SUBSTRING_LENGTH); + + char *substrPtr = NULL; + char delimiters[1] = { delimiter }; // Only caring for one delimiter + substrPtr = strtok(strDup, delimiters); + + for (int i = 0; (i < counter) && (substrPtr != NULL); i++) + { + strcpy(strings[i], substrPtr); + substrPtr = strtok(NULL, delimiters); + } + + *strCount = counter; + free(strDup); + + return strings; } //---------------------------------------------------------------------------------- -- cgit v1.2.3 From 72431c6c36a166b00e52527962ab4d978ab0111d Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 24 Oct 2018 13:45:17 +0200 Subject: Code tweaks --- src/core.c | 23 ++++++++++++----------- src/text.c | 13 +++++++------ 2 files changed, 19 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/core.c b/src/core.c index a0e53c87..ffbf110e 100644 --- a/src/core.c +++ b/src/core.c @@ -331,18 +331,19 @@ static int currentMouseWheelY = 0; // Registers current mouse wheel #if defined(PLATFORM_RPI) static char currentMouseStateEvdev[3] = { 0 }; // Holds the new mouse state for the next polling event to grab (Can't be written directly due to multithreading, app could miss the update) + typedef struct { - pthread_t threadId; // Event reading thread id - int fd; // File descriptor to the device it is assigned to - int eventNum; // Number of 'event' device - Rectangle absRange; // Range of values for absolute pointing devices (touchscreens) - int touchSlot; // Hold the touch slot number of the currently being sent multitouch block - bool isMouse; // True if device supports relative X Y movements - bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH - bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH - bool isKeyboard; // True if device has letter keycodes - bool isGamepad; // True if device has gamepad buttons -}InputEventWorker; + pthread_t threadId; // Event reading thread id + int fd; // File descriptor to the device it is assigned to + int eventNum; // Number of 'event' device + Rectangle absRange; // Range of values for absolute pointing devices (touchscreens) + int touchSlot; // Hold the touch slot number of the currently being sent multitouch block + bool isMouse; // True if device supports relative X Y movements + bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH + bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH + bool isKeyboard; // True if device has letter keycodes + bool isGamepad; // True if device has gamepad buttons +} InputEventWorker; static InputEventWorker eventWorkers[10]; // List of worker threads for every monitored "/dev/input/event" diff --git a/src/text.c b/src/text.c index 6e86958e..a010666e 100644 --- a/src/text.c +++ b/src/text.c @@ -316,6 +316,7 @@ Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontCha font.texture = LoadTextureFromImage(atlas); UnloadImage(atlas); } + else font = GetFontDefault(); return font; } @@ -331,9 +332,9 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c #define SDF_PIXEL_DIST_SCALE 64.0f #define BITMAP_ALPHA_THRESHOLD 80 - + CharInfo *chars = NULL; - + // Load font data (including pixel data) from TTF file // NOTE: Loaded information should be enough to generate font image atlas, // using any packaging method @@ -349,7 +350,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c fread(fontBuffer, size, 1, fontFile); fclose(fontFile); - + // Init font for data reading stbtt_fontinfo fontInfo; if (!stbtt_InitFont(&fontInfo, fontBuffer, 0)) TraceLog(LOG_WARNING, "Failed to init font!"); @@ -368,11 +369,11 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c // Fill fontChars in case not provided externally // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) int genFontChars = false; - if (fontChars == NULL) genFontChars = true; - if (genFontChars) + if (fontChars == NULL) { fontChars = (int *)malloc(charsCount*sizeof(int)); for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32; + genFontChars = true; } chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); @@ -417,7 +418,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); chars[i].advanceX *= scaleFactor; } - + free(fontBuffer); if (genFontChars) free(fontChars); } -- cgit v1.2.3