Browse Source

Merge branch 'master' of https://github.com/raysan5/raylib

Ray 9 months ago
parent
commit
09570a05b3

+ 67 - 71
build.zig

@@ -2,7 +2,7 @@ const std = @import("std");
 const builtin = @import("builtin");
 
 /// Minimum supported version of Zig
-const min_ver = "0.12.0";
+const min_ver = "0.13.0";
 
 comptime {
     const order = std.SemanticVersion.order;
@@ -11,36 +11,6 @@ comptime {
         @compileError("Raylib requires zig version " ++ min_ver);
 }
 
-// NOTE(freakmangd): I don't like using a global here, but it prevents having to
-// get the flags a second time when adding raygui
-var raylib_flags_arr: std.ArrayListUnmanaged([]const u8) = .{};
-
-// This has been tested with zig version 0.12.0
-pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
-    const raylib_dep = b.dependencyFromBuildZig(@This(), .{
-        .target = target,
-        .optimize = optimize,
-        .raudio = options.raudio,
-        .rmodels = options.rmodels,
-        .rshapes = options.rshapes,
-        .rtext = options.rtext,
-        .rtextures = options.rtextures,
-        .platform = options.platform,
-        .shared = options.shared,
-        .linux_display_backend = options.linux_display_backend,
-        .opengl_version = options.opengl_version,
-        .config = options.config,
-    });
-    const raylib = raylib_dep.artifact("raylib");
-
-    if (options.raygui) {
-        const raygui_dep = b.dependency(options.raygui_dependency_name, .{});
-        addRaygui(b, raylib, raygui_dep);
-    }
-
-    return raylib;
-}
-
 fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void {
     raylib.defineCMacro("PLATFORM_DESKTOP", null);
 
@@ -52,6 +22,30 @@ fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend
     }
 }
 
+fn createEmsdkStep(b: *std.Build, emsdk: *std.Build.Dependency) *std.Build.Step.Run {
+    if (builtin.os.tag == .windows) {
+        return b.addSystemCommand(&.{emsdk.path("emsdk.bat").getPath(b)});
+    } else {
+        return b.addSystemCommand(&.{emsdk.path("emsdk").getPath(b)});
+    }
+}
+
+fn emSdkSetupStep(b: *std.Build, emsdk: *std.Build.Dependency) !?*std.Build.Step.Run {
+    const dot_emsc_path = emsdk.path(".emscripten").getPath(b);
+    const dot_emsc_exists = !std.meta.isError(std.fs.accessAbsolute(dot_emsc_path, .{}));
+
+    if (!dot_emsc_exists) {
+        const emsdk_install = createEmsdkStep(b, emsdk);
+        emsdk_install.addArgs(&.{ "install", "latest" });
+        const emsdk_activate = createEmsdkStep(b, emsdk);
+        emsdk_activate.addArgs(&.{ "activate", "latest" });
+        emsdk_activate.step.dependOn(&emsdk_install.step);
+        return emsdk_activate;
+    } else {
+        return null;
+    }
+}
+
 /// A list of all flags from `src/config.h` that one may override
 const config_h_flags = outer: {
     // Set this value higher if compile errors happen as `src/config.h` gets larger
@@ -83,21 +77,26 @@ const config_h_flags = outer: {
 };
 
 fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
-    raylib_flags_arr.clearRetainingCapacity();
+    var raylib_flags_arr = std.ArrayList([]const u8).init(b.allocator);
+    defer raylib_flags_arr.deinit();
 
-    const shared_flags = &[_][]const u8{
-        "-fPIC",
-        "-DBUILD_LIBTYPE_SHARED",
-    };
-    try raylib_flags_arr.appendSlice(b.allocator, &[_][]const u8{
+    try raylib_flags_arr.appendSlice(&[_][]const u8{
         "-std=gnu99",
         "-D_GNU_SOURCE",
         "-DGL_SILENCE_DEPRECATION=199309L",
         "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674
     });
+
+    if (options.shared) {
+        try raylib_flags_arr.appendSlice(&[_][]const u8{
+            "-fPIC",
+            "-DBUILD_LIBTYPE_SHARED",
+        });
+    }
+
     if (options.config.len > 0) {
         // Sets a flag indiciating the use of a custom `config.h`
-        try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
+        try raylib_flags_arr.append("-DEXTERNAL_CONFIG_FLAGS");
 
         // Splits a space-separated list of config flags into multiple flags
         //
@@ -107,7 +106,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
 
         // Apply config flags supplied by the user
         while (config_iter.next()) |config_flag|
-            try raylib_flags_arr.append(b.allocator, config_flag);
+            try raylib_flags_arr.append(config_flag);
 
         // Apply all relevant configs from `src/config.h` *except* the user-specified ones
         //
@@ -125,14 +124,10 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
             }
 
             // Otherwise, append default value from config.h to compile flags
-            try raylib_flags_arr.append(b.allocator, flag);
+            try raylib_flags_arr.append(flag);
         }
     }
 
-    if (options.shared) {
-        try raylib_flags_arr.appendSlice(b.allocator, shared_flags);
-    }
-
     const raylib = if (options.shared)
         b.addSharedLibrary(.{
             .name = "raylib",
@@ -223,6 +218,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
                     waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol");
                     waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol");
                 }
+
                 setDesktopPlatform(raylib, options.platform);
             } else {
                 if (options.opengl_version == .auto) {
@@ -255,8 +251,15 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
             setDesktopPlatform(raylib, options.platform);
         },
         .macos => {
+            // Include xcode_frameworks for cross compilation
+            if (b.lazyDependency("xcode_frameworks", .{})) |dep| {
+                raylib.addSystemFrameworkPath(dep.path("Frameworks"));
+                raylib.addSystemIncludePath(dep.path("include"));
+                raylib.addLibraryPath(dep.path("lib"));
+            }
+
             // On macos rglfw.c include Objective-C files.
-            try raylib_flags_arr.append(b.allocator, "-ObjC");
+            try raylib_flags_arr.append("-ObjC");
             raylib.root_module.addCSourceFile(.{
                 .file = b.path("src/rglfw.c"),
                 .flags = raylib_flags_arr.items,
@@ -271,20 +274,19 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
             setDesktopPlatform(raylib, options.platform);
         },
         .emscripten => {
+            // Include emscripten for cross compilation
+            if (b.lazyDependency("emsdk", .{})) |dep| {
+                if (try emSdkSetupStep(b, dep)) |emSdkStep| {
+                    raylib.step.dependOn(&emSdkStep.step);
+                }
+
+                raylib.addIncludePath(dep.path("upstream/emscripten/cache/sysroot/include"));
+            }
+
             raylib.defineCMacro("PLATFORM_WEB", null);
             if (options.opengl_version == .auto) {
                 raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null);
             }
-
-            if (b.sysroot == null) {
-                @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'");
-            }
-
-            const cache_include = b.pathJoin(&.{ b.sysroot.?, "cache", "sysroot", "include" });
-
-            var dir = std.fs.openDirAbsolute(cache_include, std.fs.Dir.OpenDirOptions{ .access_sub_paths = true, .no_follow = true }) catch @panic("No emscripten cache. Generate it!");
-            dir.close();
-            raylib.addIncludePath(.{ .cwd_relative = cache_include });
         },
         else => {
             @panic("Unsupported OS");
@@ -296,25 +298,19 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
         .flags = raylib_flags_arr.items,
     });
 
-    return raylib;
-}
-
-/// This function does not need to be called if you passed .raygui = true to addRaylib
-pub fn addRaygui(b: *std.Build, raylib: *std.Build.Step.Compile, raygui_dep: *std.Build.Dependency) void {
-    if (raylib_flags_arr.items.len == 0) {
-        @panic(
-            \\argument 2 `raylib` in `addRaygui` must come from b.dependency("raylib", ...).artifact("raylib")
-        );
-    }
+    if (options.raygui) {
+        const raygui_dep = b.dependency(options.raygui_dependency_name, .{});
 
-    var gen_step = b.addWriteFiles();
-    raylib.step.dependOn(&gen_step.step);
+        var gen_step = b.addWriteFiles();
+        raylib.step.dependOn(&gen_step.step);
 
-    const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n");
-    raylib.addCSourceFile(.{ .file = raygui_c_path, .flags = raylib_flags_arr.items });
-    raylib.addIncludePath(raygui_dep.path("src"));
+        const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n");
+        raylib.addCSourceFile(.{ .file = raygui_c_path, .flags = raylib_flags_arr.items });
+        raylib.addIncludePath(raygui_dep.path("src"));
+        raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h");
+    }
 
-    raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h");
+    return raylib;
 }
 
 pub const Options = struct {

+ 24 - 0
build.zig.zon

@@ -0,0 +1,24 @@
+.{
+    .name = "raylib",
+    .version = "5.5.0",
+    .minimum_zig_version = "0.13.0",
+
+    .dependencies = .{
+        .xcode_frameworks = .{
+            .url = "git+https://github.com/hexops/xcode-frameworks#a6bf82e032d4d9923ad5c222d466710fcc05f249",
+            .hash = "12208da4dfcd9b53fb367375fb612ec73f38e53015f1ce6ae6d6e8437a637078e170",
+            .lazy = true,
+        },
+        .emsdk = .{
+            .url = "git+https://github.com/emscripten-core/emsdk#3.1.50",
+            .hash = "1220e8fe9509f0843e5e22326300ca415c27afbfbba3992f3c3184d71613540b5564",
+            .lazy = true,
+        },
+    },
+
+    .paths = .{
+        "build.zig",
+        "build.zig.zon",
+        "src",
+    },
+}

+ 12 - 6
examples/Makefile

@@ -87,6 +87,8 @@ USE_EXTERNAL_GLFW     ?= FALSE
 # WARNING: Library is not included in raylib, it MUST be configured by users
 SDL_INCLUDE_PATH      ?= $(RAYLIB_SRC_PATH)/external/SDL2/include
 SDL_LIBRARY_PATH      ?= $(RAYLIB_SRC_PATH)/external/SDL2/lib
+SDL_LIBRARIES         ?= -lSDL2 -lSDL2main
+
 
 # Use Wayland display server protocol on Linux desktop (by default it uses X11 windowing system)
 # NOTE: This variable is only used for PLATFORM_OS: LINUX
@@ -263,9 +265,9 @@ endif
 # Define include paths for required headers: INCLUDE_PATHS
 # NOTE: Some external/extras libraries could be required (stb, easings...)
 #------------------------------------------------------------------------------------------------
-INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external
-
+INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external $(EXTRA_INCLUDE_PATHS)
 # Define additional directories containing required header files
+
 ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
     ifeq ($(PLATFORM_OS),BSD)
         INCLUDE_PATHS += -I$(RAYLIB_INCLUDE_PATH) -I/usr/pkg/include -I/usr/X11R7/include
@@ -415,12 +417,12 @@ endif
 ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
     ifeq ($(PLATFORM_OS),WINDOWS)
         # Libraries for Windows desktop compilation
-        LDLIBS = -lraylib -lSDL2 -lSDL2main -lopengl32 -lgdi32
+        LDLIBS = -lraylib $(SDL_LIBRARIES) -lopengl32 -lgdi32
     endif
     ifeq ($(PLATFORM_OS),LINUX)
         # Libraries for Debian GNU/Linux desktop compiling
         # NOTE: Required packages: libegl1-mesa-dev
-        LDLIBS = -lraylib -lSDL2 -lSDL2main -lGL -lm -lpthread -ldl -lrt
+        LDLIBS = -lraylib $(SDL_LIBRARIES) -lGL -lm -lpthread -ldl -lrt
 
         # On X11 requires also below libraries
         LDLIBS += -lX11
@@ -646,8 +648,12 @@ OTHERS = \
     others/embedded_files_loading \
     others/raylib_opengl_interop \
     others/raymath_vector_angle \
-    others/rlgl_compute_shader \
-    others/rlgl_standalone
+    others/rlgl_compute_shader
+
+ifeq ($(TARGET_PLATFORM), PLATFORM_DESKTOP_GFLW)
+    OTHERS += others/rlgl_standalone
+endif
+    
 
 CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST))
 

+ 5 - 0
parser/output/raylib_api.json

@@ -3520,6 +3520,11 @@
       "description": "Get clipboard text content",
       "returnType": "const char *"
     },
+    {
+      "name": "GetClipboardImage",
+      "description": "Get clipboard image",
+      "returnType": "Image"
+    },
     {
       "name": "EnableEventWaiting",
       "description": "Enable waiting for events on EndDrawing(), no automatic event polling",

+ 5 - 0
parser/output/raylib_api.lua

@@ -3397,6 +3397,11 @@ return {
       description = "Get clipboard text content",
       returnType = "const char *"
     },
+    {
+      name = "GetClipboardImage",
+      description = "Get clipboard image",
+      returnType = "Image"
+    },
     {
       name = "EnableEventWaiting",
       description = "Enable waiting for events on EndDrawing(), no automatic event polling",

File diff suppressed because it is too large
+ 167 - 162
parser/output/raylib_api.txt


+ 3 - 1
parser/output/raylib_api.xml

@@ -674,7 +674,7 @@
             <Param type="unsigned int" name="frames" desc="" />
         </Callback>
     </Callbacks>
-    <Functions count="580">
+    <Functions count="581">
         <Function name="InitWindow" retType="void" paramCount="3" desc="Initialize window and OpenGL context">
             <Param type="int" name="width" desc="" />
             <Param type="int" name="height" desc="" />
@@ -795,6 +795,8 @@
         </Function>
         <Function name="GetClipboardText" retType="const char *" paramCount="0" desc="Get clipboard text content">
         </Function>
+        <Function name="GetClipboardImage" retType="Image" paramCount="0" desc="Get clipboard image">
+        </Function>
         <Function name="EnableEventWaiting" retType="void" paramCount="0" desc="Enable waiting for events on EndDrawing(), no automatic event polling">
         </Function>
         <Function name="DisableEventWaiting" retType="void" paramCount="0" desc="Disable waiting for events on EndDrawing(), automatic events polling">

+ 4 - 2
src/Makefile

@@ -118,6 +118,8 @@ GLFW_LINUX_ENABLE_X11      ?= TRUE
 # WARNING: Library is not included in raylib, it MUST be configured by users
 SDL_INCLUDE_PATH      ?= $(RAYLIB_SRC_PATH)/external/SDL2/include
 SDL_LIBRARY_PATH      ?= $(RAYLIB_SRC_PATH)/external/SDL2/lib
+SDL_LIBRARIES         ?= -lSDL2 -lSDL2main
+
 
 # Determine if the file has root access (only required to install raylib)
 # "whoami" prints the name of the user that calls him (so, if it is the root user, "whoami" prints "root")
@@ -460,7 +462,7 @@ CFLAGS += $(CUSTOM_CFLAGS)
 # Define include paths for required headers: INCLUDE_PATHS
 # NOTE: Several external required libraries (stb and others)
 #------------------------------------------------------------------------------------------------
-INCLUDE_PATHS = -I. 
+INCLUDE_PATHS = -I. $(EXTRA_INCLUDE_PATHS)
 
 # Define additional directories containing required header files
 ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
@@ -586,7 +588,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
             LDLIBS += -lX11
         endif
     endif
-    LDLIBS += -lSDL2 -lSDL2main
+    LDLIBS += $(SDL_LIBRARIES)
 endif
 ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
     ifeq ($(PLATFORM_OS),WINDOWS)

+ 28 - 0
src/config.h

@@ -71,6 +71,7 @@
 // Enabling this flag allows manual control of the frame processes, use at your own risk
 //#define SUPPORT_CUSTOM_FRAME_CONTROL    1
 
+
 // rcore: Configuration values
 //------------------------------------------------------------------------------------
 #define MAX_FILEPATH_CAPACITY        8192       // Maximum file paths capacity
@@ -272,4 +273,31 @@
 //------------------------------------------------------------------------------------
 #define MAX_TRACELOG_MSG_LENGTH       256       // Max length of one trace-log message
 
+
+// Enable partial support for clipboard image, only working on SDL3 or
+// being on both Windows OS + GLFW or Windows OS + RGFW
+#define SUPPORT_CLIPBOARD_IMAGE    1
+
+#if defined(SUPPORT_CLIPBOARD_IMAGE)
+    #ifndef STBI_REQUIRED
+        #define STBI_REQUIRED
+    #endif
+
+    #ifndef SUPPORT_FILEFORMAT_BMP // For clipboard image on Windows
+        #define SUPPORT_FILEFORMAT_BMP 1
+    #endif
+
+    #ifndef SUPPORT_FILEFORMAT_PNG // Wayland uses png for prints, at least it was on 22 LTS ubuntu
+        #define SUPPORT_FILEFORMAT_PNG 1
+    #endif
+
+    #ifndef SUPPORT_FILEFORMAT_JPG
+        #define SUPPORT_FILEFORMAT_JPG 1
+    #endif
+
+    #ifndef SUPPORT_MODULE_RTEXTURES
+        #define SUPPORT_MODULE_RTEXTURES 1
+    #endif
+#endif
+
 #endif // CONFIG_H

+ 374 - 0
src/external/win32_clipboard.h

@@ -0,0 +1,374 @@
+#if !defined(_WIN32)
+#   error "This module is only made for Windows OS"
+#endif
+
+#ifndef WIN32_CLIPBOARD_
+#define WIN32_CLIPBOARD_
+unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize);
+#endif // WIN32_CLIPBOARD_
+
+#ifdef WIN32_CLIPBOARD_IMPLEMENTATION
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <assert.h>
+
+// NOTE: These search for architecture is taken from "Windows.h", and it's necessary if we really don't wanna import windows.h 
+// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. <minwindef.h>) can cause problems is these are not defined.
+#if !defined(_X86_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IX86)
+#define _X86_
+#if !defined(_CHPE_X86_ARM64_) && defined(_M_HYBRID)
+#define _CHPE_X86_ARM64_
+#endif
+#endif
+
+#if !defined(_AMD64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && (defined(_M_AMD64) || defined(_M_ARM64EC))
+#define _AMD64_
+#endif
+
+#if !defined(_ARM_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM)
+#define _ARM_
+#endif
+
+#if !defined(_ARM64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64EC_) && defined(_M_ARM64)
+#define _ARM64_
+#endif
+
+#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM64EC)
+#define _ARM64EC_
+#endif
+
+#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_M68K)
+#define _68K_
+#endif
+
+#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_MPPC)
+#define _MPPC_
+#endif
+
+#if !defined(_IA64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_M_IX86) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IA64)
+#define _IA64_
+#endif
+
+
+#define WIN32_LEAN_AND_MEAN
+// #include <sdkddkver.h>
+// #include <windows.h>
+// #include <winuser.h>
+#include <minwindef.h>
+// #include <minwinbase.h>
+
+#ifndef WINAPI
+#if defined(_ARM_)
+#define WINAPI
+#else
+#define WINAPI __stdcall
+#endif
+#endif
+
+#ifndef WINAPI
+#if defined(_ARM_)
+#define WINAPI
+#else
+#define WINAPI __stdcall
+#endif
+#endif
+
+#ifndef WINBASEAPI
+#ifndef _KERNEL32_
+#define WINBASEAPI DECLSPEC_IMPORT
+#else
+#define WINBASEAPI
+#endif
+#endif
+
+#ifndef WINUSERAPI
+#ifndef _USER32_
+#define WINUSERAPI __declspec (dllimport)
+#else
+#define WINUSERAPI
+#endif
+#endif
+
+typedef int WINBOOL;
+
+
+
+// typedef HANDLE HGLOBAL;
+
+#ifndef HWND
+#define HWND void*
+#endif
+
+
+#if !defined(_WINUSER_) || !defined(WINUSER_ALREADY_INCLUDED)
+WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner);
+WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID);
+WINUSERAPI DWORD   WINAPI GetClipboardSequenceNumber(VOID);
+WINUSERAPI HWND    WINAPI GetClipboardOwner(VOID);
+WINUSERAPI HWND    WINAPI SetClipboardViewer(HWND hWndNewViewer);
+WINUSERAPI HWND    WINAPI GetClipboardViewer(VOID);
+WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext);
+WINUSERAPI HANDLE  WINAPI SetClipboardData(UINT uFormat, HANDLE hMem);
+WINUSERAPI HANDLE  WINAPI GetClipboardData(UINT uFormat);
+WINUSERAPI UINT    WINAPI RegisterClipboardFormatA(LPCSTR  lpszFormat);
+WINUSERAPI UINT    WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat);
+WINUSERAPI int     WINAPI CountClipboardFormats(VOID);
+WINUSERAPI UINT    WINAPI EnumClipboardFormats(UINT format);
+WINUSERAPI int     WINAPI GetClipboardFormatNameA(UINT format, LPSTR  lpszFormatName, int cchMaxCount);
+WINUSERAPI int     WINAPI GetClipboardFormatNameW(UINT format, LPWSTR lpszFormatName, int cchMaxCount);
+WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID);
+WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format);
+WINUSERAPI int     WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList, int cFormats);
+WINUSERAPI HWND    WINAPI GetOpenClipboardWindow(VOID);
+#endif
+
+#ifndef HGLOBAL
+#define HGLOBAL void*
+#endif
+
+#if !defined(_WINBASE_) || !defined(WINBASE_ALREADY_INCLUDED)
+WINBASEAPI SIZE_T  WINAPI GlobalSize (HGLOBAL hMem);
+WINBASEAPI LPVOID  WINAPI GlobalLock (HGLOBAL hMem);
+WINBASEAPI WINBOOL WINAPI GlobalUnlock (HGLOBAL hMem);
+#endif
+
+
+#if !defined(_WINGDI_) || !defined(WINGDI_ALREADY_INCLUDED)
+#ifndef BITMAPINFOHEADER_ALREADY_DEFINED
+#define BITMAPINFOHEADER_ALREADY_DEFINED
+// Does this header need to be packed ? by the windowps header it doesnt seem to be
+#pragma pack(push, 1)
+typedef struct tagBITMAPINFOHEADER {
+    DWORD biSize;
+    LONG biWidth;
+    LONG biHeight;
+    WORD biPlanes;
+    WORD biBitCount;
+    DWORD biCompression;
+    DWORD biSizeImage;
+    LONG biXPelsPerMeter;
+    LONG biYPelsPerMeter;
+    DWORD biClrUsed;
+    DWORD biClrImportant;
+} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;
+#pragma pack(pop)
+#endif
+
+#ifndef BITMAPFILEHEADER_ALREADY_DEFINED
+#define BITMAPFILEHEADER_ALREADY_DEFINED
+#pragma pack(push, 1)
+typedef struct tagBITMAPFILEHEADER {
+    WORD bfType;
+    DWORD bfSize;
+    WORD bfReserved1;
+    WORD bfReserved2;
+    DWORD bfOffBits;
+} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER;
+#pragma pack(pop)
+#endif
+
+#ifndef RGBQUAD_ALREADY_DEFINED
+#define RGBQUAD_ALREADY_DEFINED
+typedef struct tagRGBQUAD {
+  BYTE rgbBlue;
+  BYTE rgbGreen;
+  BYTE rgbRed;
+  BYTE rgbReserved;
+} RGBQUAD, *LPRGBQUAD;
+#endif
+
+
+// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57
+#define BI_RGB       0x0000
+#define BI_RLE8      0x0001
+#define BI_RLE4      0x0002
+#define BI_BITFIELDS 0x0003
+#define BI_JPEG      0x0004
+#define BI_PNG       0x0005
+#define BI_CMYK      0x000B
+#define BI_CMYKRLE8  0x000C
+#define BI_CMYKRLE4  0x000D
+
+#endif
+
+// https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats
+#define CF_DIB 8
+
+// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setsystemcursor
+// #define OCR_NORMAL      32512 // Normal     select
+// #define OCR_IBEAM       32513 // Text       select
+// #define OCR_WAIT        32514 // Busy
+// #define OCR_CROSS       32515 // Precision  select
+// #define OCR_UP          32516 // Alternate  select
+// #define OCR_SIZENWSE    32642 // Diagonal   resize 1
+// #define OCR_SIZENESW    32643 // Diagonal   resize 2
+// #define OCR_SIZEWE      32644 // Horizontal resize
+// #define OCR_SIZENS      32645 // Vertical   resize
+// #define OCR_SIZEALL     32646 // Move
+// #define OCR_NO          32648 // Unavailable
+// #define OCR_HAND        32649 // Link       select
+// #define OCR_APPSTARTING 32650 //
+
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+
+
+static BOOL           OpenClipboardRetrying(HWND handle); // Open clipboard with a number of retries
+static int            GetPixelDataOffset(BITMAPINFOHEADER bih);
+
+unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize)
+{
+    HWND win = NULL; // Get from somewhere but is doesnt seem to matter
+    const char* msgString = "";
+    int severity = LOG_INFO;
+    BYTE* bmpData = NULL;
+    if (!OpenClipboardRetrying(win)) {
+        severity = LOG_ERROR;
+        msgString = "Couldn't open clipboard";
+        goto end;
+    }
+
+    HGLOBAL clipHandle = (HGLOBAL)GetClipboardData(CF_DIB);
+    if (!clipHandle) {
+        severity = LOG_ERROR;
+        msgString = "Clipboard data is not an Image";
+        goto close;
+    }
+
+    BITMAPINFOHEADER *bmpInfoHeader = (BITMAPINFOHEADER *)GlobalLock(clipHandle);
+    if (!bmpInfoHeader) {
+        // Mapping from HGLOBAL to our local *address space* failed
+        severity = LOG_ERROR;
+        msgString = "Clipboard data failed to be locked";
+        goto unlock;
+    }
+
+    *width = bmpInfoHeader->biWidth;
+    *height = bmpInfoHeader->biHeight;
+
+    SIZE_T clipDataSize = GlobalSize(clipHandle);
+    if (clipDataSize < sizeof(BITMAPINFOHEADER)) {
+        // Format CF_DIB needs space for BITMAPINFOHEADER struct.
+        msgString = "Clipboard has Malformed data";
+        severity = LOG_ERROR;
+        goto unlock;
+    }
+
+    // Denotes where the pixel data starts from the bmpInfoHeader pointer
+    int pixelOffset = GetPixelDataOffset(*bmpInfoHeader);
+
+    //--------------------------------------------------------------------------------//
+    //
+    // The rest of the section is about create the bytes for a correct BMP file
+    // Then we copy the data and to a pointer
+    //
+    //--------------------------------------------------------------------------------//
+
+    BITMAPFILEHEADER bmpFileHeader = {0};
+    SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize;
+    *dataSize = bmpFileSize;
+
+    bmpFileHeader.bfType = 0x4D42; //https://stackoverflow.com/questions/601430/multibyte-character-constants-and-bitmap-file-header-type-constants#601536
+
+    bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine
+    bmpFileHeader.bfOffBits = sizeof(bmpFileHeader) + pixelOffset;
+
+    //
+    // Each process has a default heap provided by the system
+    // Memory objects allocated by GlobalAlloc and LocalAlloc are in private,
+    // committed pages with read/write access that cannot be accessed by other processes.
+    //
+    // This may be wrong since we might be allocating in a DLL and freeing from another module, the main application
+    // that may cause heap corruption. We could create a FreeImage function
+    //
+    bmpData = malloc(sizeof(bmpFileHeader) + clipDataSize);
+    // First we add the header for a bmp file
+    memcpy(bmpData, &bmpFileHeader, sizeof(bmpFileHeader));
+    // Then we add the header for the bmp itself + the pixel data
+    memcpy(bmpData + sizeof(bmpFileHeader), bmpInfoHeader, clipDataSize);
+    msgString = "Clipboad image acquired successfully";
+
+
+unlock:
+    GlobalUnlock(clipHandle);
+close:
+    CloseClipboard();
+end:
+
+    TRACELOG(severity, msgString);
+    return bmpData;
+}
+
+static BOOL OpenClipboardRetrying(HWND hWnd)
+{
+    static const int maxTries = 20;
+    static const int sleepTimeMS = 60;
+    for (int _ = 0; _ < maxTries; ++_)
+    {
+        // Might be being hold by another process
+        // Or yourself forgot to CloseClipboard
+        if (OpenClipboard(hWnd)) {
+            return true;
+        }
+        Sleep(sleepTimeMS);
+    }
+    return false;
+}
+
+// Based off of researching microsoft docs and reponses from this question https://stackoverflow.com/questions/30552255/how-to-read-a-bitmap-from-the-windows-clipboard#30552856
+// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
+// Get the byte offset where does the pixels data start (from a packed DIB)
+static int GetPixelDataOffset(BITMAPINFOHEADER bih)
+{
+    int offset = 0;
+    const unsigned int rgbaSize = sizeof(RGBQUAD);
+
+    // biSize Specifies the number of bytes required by the structure
+    // We expect to always be 40 because it should be packed
+    if (40 == bih.biSize && 40 == sizeof(BITMAPINFOHEADER))
+    {
+        //
+        // biBitCount Specifies the number of bits per pixel.
+        // Might exist some bit masks *after* the header and *before* the pixel offset
+        // we're looking, but only if we have more than
+        // 8 bits per pixel, so we need to ajust for that
+        //
+        if (bih.biBitCount > 8)
+        {
+            // if bih.biCompression is RBG we should NOT offset more
+
+            if (bih.biCompression == BI_BITFIELDS)
+            {
+                offset += 3 * rgbaSize;
+            } else if (bih.biCompression == 6 /* BI_ALPHABITFIELDS */)
+            {
+                // Not widely supported, but valid.
+                offset += 4 * rgbaSize;
+            }
+        }
+    }
+
+    //
+    // biClrUsed Specifies the number of color indices in the color table that are actually used by the bitmap.
+    // If this value is zero, the bitmap uses the maximum number of colors
+    // corresponding to the value of the biBitCount member for the compression mode specified by biCompression.
+    // If biClrUsed is nonzero and the biBitCount member is less than 16
+    // the biClrUsed member specifies the actual number of colors
+    //
+    if (bih.biClrUsed > 0) {
+        offset += bih.biClrUsed * rgbaSize;
+    } else {
+        if (bih.biBitCount < 16)
+        {
+            offset = offset + (rgbaSize << bih.biBitCount);
+        }
+    }
+
+    return bih.biSize + offset;
+}
+#endif // WIN32_CLIPBOARD_IMPLEMENTATION
+// EOF
+

+ 32 - 0
src/platforms/rcore_desktop_glfw.c

@@ -58,6 +58,7 @@
 #if defined(_WIN32)
     typedef void *PVOID;
     typedef PVOID HANDLE;
+    #include "../external/win32_clipboard.h"
     typedef HANDLE HWND;
     #define GLFW_EXPOSE_NATIVE_WIN32
     #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h
@@ -966,6 +967,33 @@ const char *GetClipboardText(void)
     return glfwGetClipboardString(platform.handle);
 }
 
+#if defined(SUPPORT_CLIPBOARD_IMAGE)
+// Get clipboard image
+Image GetClipboardImage(void)
+{
+    Image image = {0};
+    unsigned long long int dataSize = 0;
+    void* fileData = NULL;
+
+#ifdef _WIN32
+    int width, height;
+    fileData  = (void*)Win32GetClipboardImageData(&width, &height, &dataSize);
+#else
+    TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_GLFW doesn't implement `GetClipboardImage` for this OS");
+#endif
+
+    if (fileData == NULL)
+    {
+        TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
+    }
+    else
+    {
+        image = LoadImageFromMemory(".bmp", fileData, dataSize);
+    }
+    return image;
+}
+#endif // SUPPORT_CLIPBOARD_IMAGE
+
 // Show mouse cursor
 void ShowCursor(void)
 {
@@ -1898,4 +1926,8 @@ static void JoystickCallback(int jid, int event)
     }
 }
 
+#ifdef _WIN32
+#   define WIN32_CLIPBOARD_IMPLEMENTATION
+#   include "../external/win32_clipboard.h"
+#endif
 // EOF

+ 37 - 0
src/platforms/rcore_desktop_rgfw.c

@@ -664,6 +664,43 @@ const char *GetClipboardText(void)
     return RGFW_readClipboard(NULL);
 }
 
+
+#if defined(SUPPORT_CLIPBOARD_IMAGE)
+
+#ifdef _WIN32
+#   define WIN32_CLIPBOARD_IMPLEMENTATION
+#   define WINUSER_ALREADY_INCLUDED
+#   define WINBASE_ALREADY_INCLUDED
+#   define WINGDI_ALREADY_INCLUDED
+#   include "../external/win32_clipboard.h"
+#endif
+
+// Get clipboard image
+Image GetClipboardImage(void)
+{
+    Image image = {0};
+    unsigned long long int dataSize = 0;
+    void* fileData = NULL;
+
+#ifdef _WIN32
+    int width, height;
+    fileData  = (void*)Win32GetClipboardImageData(&width, &height, &dataSize);
+#else
+    TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_RGFW doesn't implement `GetClipboardImage` for this OS");
+#endif
+
+    if (fileData == NULL)
+    {
+        TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
+    }
+    else
+    {
+        image = LoadImageFromMemory(".bmp", fileData, dataSize);
+    }
+    return image;
+}
+#endif // SUPPORT_CLIPBOARD_IMAGE
+
 // Show mouse cursor
 void ShowCursor(void)
 {

+ 343 - 3
src/platforms/rcore_desktop_sdl.c

@@ -23,7 +23,7 @@
 *           Custom flag for rcore on target platform -not used-
 *
 *   DEPENDENCIES:
-*       - SDL 2 (main library): Windowing and inputs management
+*       - SDL 2 or SLD 3 (main library): Windowing and inputs management
 *       - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
 *
 *
@@ -48,6 +48,10 @@
 *
 **********************************************************************************************/
 
+
+#ifndef SDL_ENABLE_OLD_NAMES
+    #define SDL_ENABLE_OLD_NAMES    // Just in case we're on SDL3, we need some in-between compatibily
+#endif
 #include "SDL.h"                // SDL base library (window/rendered, input, timing... functionality)
 
 #if defined(GRAPHICS_API_OPENGL_ES2)
@@ -64,6 +68,13 @@
     #define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText()
 #endif
 
+#if ((defined(SDL_MAJOR_VERSION) && SDL_MAJOR_VERSION == 3) && (defined(SDL_MINOR_VERSION) && SDL_MINOR_VERSION >= 1))
+    #ifndef PLATFORM_DESKTOP_SDL3
+        #define PLATFORM_DESKTOP_SDL3
+    #endif
+#endif
+
+
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
@@ -227,6 +238,190 @@ static const int CursorsLUT[] = {
     //SDL_SYSTEM_CURSOR_WAITARROW, // No equivalent implemented on MouseCursor enum on raylib.h
 };
 
+
+// SDL3 Migration Layer made to avoid `ifdefs` inside functions when we can.
+#ifdef PLATFORM_DESKTOP_SDL3
+
+// SDL3 Migration:
+//     SDL_WINDOW_FULLSCREEN_DESKTOP has been removed,
+//     and you can call SDL_GetWindowFullscreenMode()
+//     to see whether an exclusive fullscreen mode will be used 
+//     or the borderless fullscreen desktop mode will be used
+#define SDL_WINDOW_FULLSCREEN_DESKTOP SDL_WINDOW_FULLSCREEN
+
+
+#define SDL_IGNORE  false
+#define SDL_DISABLE false
+#define SDL_ENABLE  true
+
+// SDL3 Migration: SDL_INIT_TIMER - no longer needed before calling SDL_AddTimer()
+#define SDL_INIT_TIMER 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
+
+// SDL3 Migration: The SDL_WINDOW_SHOWN flag has been removed. Windows are shown by default and can be created hidden by using the SDL_WINDOW_HIDDEN flag.
+#define SDL_WINDOW_SHOWN 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
+
+//
+// SDL3 Migration: Renamed
+// IMPORTANT:
+// Might need to call SDL_CleanupEvent somewhere see :https://github.com/libsdl-org/SDL/issues/3540#issuecomment-1793449852
+//
+#define SDL_DROPFILE  SDL_EVENT_DROP_FILE
+
+
+const char* SDL_GameControllerNameForIndex(int joystickIndex)
+{
+    // NOTE: SDL3 uses the IDs itself (SDL_JoystickID) instead of SDL2 joystick_index
+    const char* name = NULL;
+    int numJoysticks = 0;
+    SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks);
+    if (joysticks) {
+        if (joystickIndex < numJoysticks) {
+            SDL_JoystickID instance_id = joysticks[joystickIndex];
+            name = SDL_GetGamepadNameForID(instance_id);
+        }
+        SDL_free(joysticks);
+    }
+    return name;
+}
+
+int SDL_GetNumVideoDisplays(void)
+{
+    int monitorCount = 0;
+    SDL_DisplayID *displays = SDL_GetDisplays(&monitorCount);
+    // Safe because If `mem` is NULL, SDL_free does nothing.
+    SDL_free(displays);
+
+    return monitorCount;
+}
+
+
+// SLD3 Migration:
+//    To emulate SDL2 this function should return `SDL_DISABLE` or `SDL_ENABLE`
+//    representing the *processing state* of the event before this function makes any changes to it.
+Uint8 SDL_EventState(Uint32 type, int state) {
+
+    Uint8 stateBefore = SDL_EventEnabled(type);
+    switch (state)
+    {
+        case SDL_DISABLE: SDL_SetEventEnabled(type, false); break;
+        case SDL_ENABLE: SDL_SetEventEnabled(type, true); break;
+        default: TRACELOG(LOG_WARNING, "Event sate: unknow type");
+    }
+    return stateBefore;
+}
+
+void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode* mode)
+{
+    const SDL_DisplayMode* currMode = SDL_GetCurrentDisplayMode(displayID);
+    if (currMode == NULL)
+    {
+        TRACELOG(LOG_WARNING, "No current display mode");
+    }
+    else
+    {
+        *mode = *currMode;
+    }
+}
+
+// SDL3 Migration: Renamed
+#define SDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode_Adapter
+
+
+SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
+{
+    return SDL_CreateSurface(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask));
+}
+
+// SDL3 Migration:
+//     SDL_GetDisplayDPI() -
+//     not reliable across platforms, approximately replaced by multiplying
+//     SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms.
+// returns 0 on success or a negative error code on failure
+int SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi) {
+    float dpi = SDL_GetWindowDisplayScale(platform.window) * 96.0;
+    if (ddpi != NULL) *ddpi = dpi;
+    if (hdpi != NULL) *hdpi = dpi;
+    if (vdpi != NULL) *vdpi = dpi;
+    return 0;
+}
+
+SDL_Surface *SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, Uint32 format)
+{
+    return SDL_CreateSurface(width, height, format);
+}
+
+SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
+{
+    return SDL_CreateSurfaceFrom(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask), pixels, pitch);
+}
+
+SDL_Surface *SDL_CreateRGBSurfaceWithFormatFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 format)
+{
+    return SDL_CreateSurfaceFrom(width, height, format, pixels, pitch);
+}
+
+int SDL_NumJoysticks(void)
+{
+    int numJoysticks;
+    SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks);
+    SDL_free(joysticks);
+    return numJoysticks;
+}
+
+
+// SDL_SetRelativeMouseMode
+// returns 0 on success or a negative error code on failure
+// If relative mode is not supported, this returns -1.
+int SDL_SetRelativeMouseMode_Adapter(SDL_bool enabled)
+{
+
+    //
+    // SDL_SetWindowRelativeMouseMode(SDL_Window *window, bool enabled)
+    // \returns true on success or false on failure; call SDL_GetError() for more
+    //
+    if (SDL_SetWindowRelativeMouseMode(platform.window, enabled))
+    {
+        return 0; // success
+    }
+    else
+    {
+        return -1; // failure
+    }
+}
+
+#define SDL_SetRelativeMouseMode SDL_SetRelativeMouseMode_Adapter
+
+bool SDL_GetRelativeMouseMode_Adapter(void)
+{
+    return SDL_GetWindowRelativeMouseMode(platform.window);
+}
+
+#define SDL_GetRelativeMouseMode SDL_GetRelativeMouseMode_Adapter
+
+
+int SDL_GetNumTouchFingers(SDL_TouchID touchID)
+{
+    // SDL_Finger **SDL_GetTouchFingers(SDL_TouchID touchID, int *count)
+    int count = 0;
+    SDL_Finger **fingers = SDL_GetTouchFingers(touchID, &count);
+    SDL_free(fingers);
+    return count;
+}
+
+#else // We're on SDL2
+
+// Since SDL2 doesn't have this function we leave a stub
+// SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3)
+void* SDL_GetClipboardData(const char *mime_type, size_t *size) {
+    TRACELOG(LOG_WARNING, "Getting clipboard data that is not text is only available in SDL3");
+    // We could possibly implement it ourselves in this case for some easier platforms
+    return NULL;
+}
+
+#endif // PLATFORM_DESKTOP_SDL3
+
+
+
 //----------------------------------------------------------------------------------
 // Module Internal Functions Declaration
 //----------------------------------------------------------------------------------
@@ -256,7 +451,12 @@ void ToggleFullscreen(void)
 {
     const int monitor = SDL_GetWindowDisplayIndex(platform.window);
     const int monitorCount = SDL_GetNumVideoDisplays();
+
+#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+    if ((monitor > 0) && (monitor <= monitorCount))
+#else
     if ((monitor >= 0) && (monitor < monitorCount))
+#endif
     {
         if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
         {
@@ -279,7 +479,11 @@ void ToggleBorderlessWindowed(void)
 {
     const int monitor = SDL_GetWindowDisplayIndex(platform.window);
     const int monitorCount = SDL_GetNumVideoDisplays();
+#ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+    if ((monitor > 0) && (monitor <= monitorCount))
+#else
     if ((monitor >= 0) && (monitor < monitorCount))
+#endif
     {
         if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
         {
@@ -328,7 +532,11 @@ void SetWindowState(unsigned int flags)
     {
         const int monitor = SDL_GetWindowDisplayIndex(platform.window);
         const int monitorCount = SDL_GetNumVideoDisplays();
+    #ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+        if ((monitor > 0) && (monitor <= monitorCount))
+    #else
         if ((monitor >= 0) && (monitor < monitorCount))
+    #endif
         {
             SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
             CORE.Window.fullscreen = true;
@@ -387,7 +595,11 @@ void SetWindowState(unsigned int flags)
     {
         const int monitor = SDL_GetWindowDisplayIndex(platform.window);
         const int monitorCount = SDL_GetNumVideoDisplays();
+    #ifdef PLATFORM_DESKTOP_SDL3 // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+        if ((monitor > 0) && (monitor <= monitorCount))
+    #else
         if ((monitor >= 0) && (monitor < monitorCount))
+    #endif
         {
             SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
         }
@@ -606,7 +818,11 @@ void SetWindowMonitor(int monitor)
         const int screenWidth = CORE.Window.screen.width;
         const int screenHeight = CORE.Window.screen.height;
         SDL_Rect usableBounds;
+    #ifdef PLATFORM_DESKTOP_SDL3 // Different style for success checking
+        if (SDL_GetDisplayUsableBounds(monitor, &usableBounds))
+    #else
         if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
+    #endif
         {
             if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen.
 
@@ -704,6 +920,7 @@ int GetCurrentMonitor(void)
 {
     int currentMonitor = 0;
 
+    // Be aware that this returns an ID in SDL3 and a Index in SDL2
     currentMonitor = SDL_GetWindowDisplayIndex(platform.window);
 
     return currentMonitor;
@@ -716,7 +933,11 @@ Vector2 GetMonitorPosition(int monitor)
     if ((monitor >= 0) && (monitor < monitorCount))
     {
         SDL_Rect displayBounds;
+    #ifdef PLATFORM_DESKTOP_SDL3
+        if (SDL_GetDisplayUsableBounds(monitor, &displayBounds))
+    #else
         if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0)
+    #endif
         {
             return (Vector2){ (float)displayBounds.x, (float)displayBounds.y };
         }
@@ -844,10 +1065,16 @@ Vector2 GetWindowScaleDPI(void)
 {
     Vector2 scale = { 1.0f, 1.0f };
 
+#ifndef PLATFORM_DESKTOP_SDL3
     // NOTE: SDL_GetWindowDisplayScale was only added on SDL3
     //       see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
     // TODO: Implement the window scale factor calculation manually.
     TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
+#else
+    scale.x = SDL_GetWindowDisplayScale(platform.window);
+    scale.y = scale.x;
+    TRACELOG(LOG_INFO, "WindowScaleDPI is %f", scale.x);
+#endif
 
     return scale;
 }
@@ -877,19 +1104,68 @@ const char *GetClipboardText(void)
     return buffer;
 }
 
+
+#if defined(SUPPORT_CLIPBOARD_IMAGE)
+// Get clipboard image
+Image GetClipboardImage(void)
+{
+    // Let's hope compiler put these arrays in static memory
+    const char *image_formats[] = {
+        "image/bmp",
+        "image/png",
+        "image/jpg",
+        "image/tiff",
+    };
+    const char *image_extensions[] = {
+        ".bmp",
+        ".png",
+        ".jpg",
+        ".tiff",
+    };
+
+
+    Image image = {0};
+    size_t dataSize = 0;
+    void  *fileData = NULL;
+    for (int i = 0; i < SDL_arraysize(image_formats); ++i)
+    {
+        // NOTE: This pointer should be free with SDL_free() at some point.
+        fileData = SDL_GetClipboardData(image_formats[i], &dataSize);
+        if (fileData) {
+            image = LoadImageFromMemory(image_extensions[i], fileData, dataSize);
+            if (IsImageValid(image))
+            {
+                TRACELOG(LOG_INFO, "Clipboard image: Got image from clipboard as a `%s` successfully", image_extensions[i]);
+                return image;
+            }
+        }
+    }
+
+    TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data. %s", SDL_GetError());
+    return image;
+}
+#endif
+
+
 // Show mouse cursor
 void ShowCursor(void)
 {
+#ifdef PLATFORM_DESKTOP_SDL3
+    SDL_ShowCursor();
+#else
     SDL_ShowCursor(SDL_ENABLE);
-
+#endif
     CORE.Input.Mouse.cursorHidden = false;
 }
 
 // Hides mouse cursor
 void HideCursor(void)
 {
+#ifdef PLATFORM_DESKTOP_SDL3
+    SDL_HideCursor();
+#else
     SDL_ShowCursor(SDL_DISABLE);
-
+#endif
     CORE.Input.Mouse.cursorHidden = true;
 }
 
@@ -897,7 +1173,13 @@ void HideCursor(void)
 void EnableCursor(void)
 {
     SDL_SetRelativeMouseMode(SDL_FALSE);
+
+#ifdef PLATFORM_DESKTOP_SDL3
+    // SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
+    SDL_ShowCursor();
+#else
     SDL_ShowCursor(SDL_ENABLE);
+#endif
 
     platform.cursorRelative = false;
     CORE.Input.Mouse.cursorHidden = false;
@@ -993,6 +1275,22 @@ const char *GetKeyName(int key)
 
 static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
 {
+#ifdef PLATFORM_DESKTOP_SDL3 // SDL3
+    int count = 0;
+    SDL_Finger **fingers = SDL_GetTouchFingers(event.touchID, &count);
+    CORE.Input.Touch.pointCount = count;
+
+    for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
+    {
+        SDL_Finger *finger = fingers[i];
+        CORE.Input.Touch.pointId[i] = finger->id;
+        CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
+        CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
+        CORE.Input.Touch.currentTouchState[i] = 1;
+    }
+    SDL_free(fingers);
+#else // SDL2
+
     CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId);
 
     for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
@@ -1003,6 +1301,7 @@ static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
         CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
         CORE.Input.Touch.currentTouchState[i] = 1;
     }
+#endif
 
     for (int i = CORE.Input.Touch.pointCount; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.currentTouchState[i] = 0;
 }
@@ -1094,16 +1393,26 @@ void PollInputEvents(void)
                     CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *));
 
                     CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
+                #ifdef PLATFORM_DESKTOP_SDL3
+                    // const char *data;   /**< The text for SDL_EVENT_DROP_TEXT and the file name for SDL_EVENT_DROP_FILE, NULL for other events */
+                    // Event memory is now managed by SDL, so you should not free the data in SDL_EVENT_DROP_FILE, and if you want to hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events, you should make a copy of it. SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed.
+                    strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
+                #else
                     strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
                     SDL_free(event.drop.file);
+                #endif
 
                     CORE.Window.dropFileCount++;
                 }
                 else if (CORE.Window.dropFileCount < 1024)
                 {
                     CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
+                #ifdef PLATFORM_DESKTOP_SDL3
+                    strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
+                #else
                     strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
                     SDL_free(event.drop.file);
+                #endif
 
                     CORE.Window.dropFileCount++;
                 }
@@ -1112,10 +1421,18 @@ void PollInputEvents(void)
             } break;
 
             // Window events are also polled (Minimized, maximized, close...)
+
+        #ifndef PLATFORM_DESKTOP_SDL3
+            // SDL3 states:
+            //     The SDL_WINDOWEVENT_* events have been moved to top level events,
+            //     and SDL_WINDOWEVENT has been removed.
+            //     In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
+            //     and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event.
             case SDL_WINDOWEVENT:
             {
                 switch (event.window.event)
                 {
+        #endif
                     case SDL_WINDOWEVENT_RESIZED:
                     case SDL_WINDOWEVENT_SIZE_CHANGED:
                     {
@@ -1143,14 +1460,23 @@ void PollInputEvents(void)
                     case SDL_WINDOWEVENT_FOCUS_GAINED:
                     case SDL_WINDOWEVENT_MAXIMIZED:
                     case SDL_WINDOWEVENT_RESTORED:
+            #ifdef PLATFORM_DESKTOP_SDL3
+                        break;
+            #else
                     default: break;
                 }
             } break;
+            #endif
 
             // Keyboard events
             case SDL_KEYDOWN:
             {
+            #ifdef PLATFORM_DESKTOP_SDL3
+                // SDL3 Migration: The following structures have been removed: * SDL_Keysym
+                KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
+            #else
                 KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
+            #endif
 
                 if (key != KEY_NULL)
                 {
@@ -1175,7 +1501,12 @@ void PollInputEvents(void)
 
             case SDL_KEYUP:
             {
+
+            #ifdef PLATFORM_DESKTOP_SDL3
+                KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
+            #else
                 KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
+            #endif
                 if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
             } break;
 
@@ -1527,7 +1858,11 @@ int InitPlatform(void)
     }
 
     // Init window
+#ifdef PLATFORM_DESKTOP_SDL3
+    platform.window = SDL_CreateWindow(CORE.Window.title, CORE.Window.screen.width, CORE.Window.screen.height, flags);
+#else
     platform.window = SDL_CreateWindow(CORE.Window.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, CORE.Window.screen.width, CORE.Window.screen.height, flags);
+#endif
 
     // Init OpenGL context
     platform.glContext = SDL_GL_CreateContext(platform.window);
@@ -1611,7 +1946,12 @@ int InitPlatform(void)
     CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
     //----------------------------------------------------------------------------
 
+
+#ifdef PLATFORM_DESKTOP_SDL3
+    TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL3): Initialized successfully");
+#else
     TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully");
+#endif
 
     return 0;
 }

+ 1 - 0
src/raylib.h

@@ -1011,6 +1011,7 @@ RLAPI Vector2 GetWindowScaleDPI(void);                            // Get window
 RLAPI const char *GetMonitorName(int monitor);                    // Get the human-readable, UTF-8 encoded name of the specified monitor
 RLAPI void SetClipboardText(const char *text);                    // Set clipboard text content
 RLAPI const char *GetClipboardText(void);                         // Get clipboard text content
+RLAPI Image GetClipboardImage(void);                              // Get clipboard image
 RLAPI void EnableEventWaiting(void);                              // Enable waiting for events on EndDrawing(), no automatic event polling
 RLAPI void DisableEventWaiting(void);                             // Disable waiting for events on EndDrawing(), automatic events polling
 

+ 6 - 0
src/rcore.c

@@ -512,6 +512,12 @@ const char *TextFormat(const char *text, ...);              // Formatting of tex
     #define PLATFORM_DESKTOP_GLFW
 #endif
 
+#if defined(SUPPORT_CLIPBOARD_IMAGE)
+    #if !defined(SUPPORT_FILEFORMAT_BMP) || !defined(STBI_REQUIRED) || !defined(SUPPORT_MODULE_RTEXTURES)
+        #error "To enabled SUPPORT_CLIPBOARD_IMAGE, it also needs SUPPORT_FILEFORMAT_BMP, SUPPORT_MODULE_RTEXTURES and STBI_REQUIRED to be defined. It should have been defined earlier"
+    #endif
+#endif // SUPPORT_CLIPBOARD_IMAGE
+
 // Include platform-specific submodules
 #if defined(PLATFORM_DESKTOP_GLFW)
     #include "platforms/rcore_desktop_glfw.c"

+ 60 - 102
src/rmodels.c

@@ -2262,108 +2262,6 @@ ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount)
     return animations;
 }
 
-// Update model animated vertex data (positions and normals) for a given frame
-// NOTE: Updated data is uploaded to GPU
-void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
-{
-    if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL))
-    {
-        if (frame >= anim.frameCount) frame = frame%anim.frameCount;
-
-        for (int m = 0; m < model.meshCount; m++)
-        {
-            Mesh mesh = model.meshes[m];
-
-            if (mesh.boneIds == NULL || mesh.boneWeights == NULL)
-            {
-                TRACELOG(LOG_WARNING, "MODEL: UpdateModelAnimation(): Mesh %i has no connection to bones", m);
-                continue;
-            }
-
-            bool updated = false;           // Flag to check when anim vertex information is updated
-            Vector3 animVertex = { 0 };
-            Vector3 animNormal = { 0 };
-
-            Vector3 inTranslation = { 0 };
-            Quaternion inRotation = { 0 };
-            // Vector3 inScale = { 0 };
-
-            Vector3 outTranslation = { 0 };
-            Quaternion outRotation = { 0 };
-            Vector3 outScale = { 0 };
-
-            int boneId = 0;
-            int boneCounter = 0;
-            float boneWeight = 0.0;
-
-            const int vValues = mesh.vertexCount*3;
-            for (int vCounter = 0; vCounter < vValues; vCounter += 3)
-            {
-                mesh.animVertices[vCounter] = 0;
-                mesh.animVertices[vCounter + 1] = 0;
-                mesh.animVertices[vCounter + 2] = 0;
-
-                if (mesh.animNormals != NULL)
-                {
-                    mesh.animNormals[vCounter] = 0;
-                    mesh.animNormals[vCounter + 1] = 0;
-                    mesh.animNormals[vCounter + 2] = 0;
-                }
-
-                // Iterates over 4 bones per vertex
-                for (int j = 0; j < 4; j++, boneCounter++)
-                {
-                    boneWeight = mesh.boneWeights[boneCounter];
-
-                    // Early stop when no transformation will be applied
-                    if (boneWeight == 0.0f) continue;
-
-                    boneId = mesh.boneIds[boneCounter];
-                    //int boneIdParent = model.bones[boneId].parent;
-                    inTranslation = model.bindPose[boneId].translation;
-                    inRotation = model.bindPose[boneId].rotation;
-                    //inScale = model.bindPose[boneId].scale;
-                    outTranslation = anim.framePoses[frame][boneId].translation;
-                    outRotation = anim.framePoses[frame][boneId].rotation;
-                    outScale = anim.framePoses[frame][boneId].scale;
-
-                    // Vertices processing
-                    // NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position)
-                    animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
-                    animVertex = Vector3Subtract(animVertex, inTranslation);
-                    animVertex = Vector3Multiply(animVertex, outScale);
-                    animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
-                    animVertex = Vector3Add(animVertex, outTranslation);
-                    //animVertex = Vector3Transform(animVertex, model.transform);
-                    mesh.animVertices[vCounter] += animVertex.x*boneWeight;
-                    mesh.animVertices[vCounter + 1] += animVertex.y*boneWeight;
-                    mesh.animVertices[vCounter + 2] += animVertex.z*boneWeight;
-                    updated = true;
-
-                    // Normals processing
-                    // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
-                    if (mesh.normals != NULL)
-                    {
-                        animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
-                        animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
-                        mesh.animNormals[vCounter] += animNormal.x*boneWeight;
-                        mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
-                        mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
-                    }
-                }
-            }
-
-            // Upload new vertex data to GPU for model drawing
-            // NOTE: Only update data when values changed
-            if (updated)
-            {
-                rlUpdateVertexBuffer(mesh.vboId[0], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); // Update vertex position
-                rlUpdateVertexBuffer(mesh.vboId[2], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0);  // Update vertex normals
-            }
-        }
-    }
-}
-
 // Update model animated bones transform matrices for a given frame
 // NOTE: Updated data is not uploaded to GPU but kept at model.meshes[i].boneMatrices[boneId],
 // to be uploaded to shader at drawing, in case GPU skinning is enabled
@@ -2411,6 +2309,66 @@ void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame)
     }
 }
 
+// at least 2x speed up vs the old method 
+// Update model animated vertex data (positions and normals) for a given frame
+// NOTE: Updated data is uploaded to GPU
+void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
+{
+    UpdateModelAnimationBones(model,anim,frame);
+    for (int m = 0; m < model.meshCount; m++)
+    {
+        Mesh mesh = model.meshes[m];
+        Vector3 animVertex = { 0 };
+        Vector3 animNormal = { 0 };
+        int boneId = 0;
+        int boneCounter = 0;
+        float boneWeight = 0.0;
+        bool updated = false;           // Flag to check when anim vertex information is updated
+        const int vValues = mesh.vertexCount*3;
+        for (int vCounter = 0; vCounter < vValues; vCounter += 3)
+        {
+            mesh.animVertices[vCounter] = 0;
+            mesh.animVertices[vCounter + 1] = 0;
+            mesh.animVertices[vCounter + 2] = 0;
+            if (mesh.animNormals != NULL)
+            {
+                mesh.animNormals[vCounter] = 0;
+                mesh.animNormals[vCounter + 1] = 0;
+                mesh.animNormals[vCounter + 2] = 0;
+            }
+                // Iterates over 4 bones per vertex
+            for (int j = 0; j < 4; j++, boneCounter++)
+            {
+                boneWeight = mesh.boneWeights[boneCounter];
+                boneId = mesh.boneIds[boneCounter];
+                // Early stop when no transformation will be applied
+                if (boneWeight == 0.0f) continue;
+                animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
+                animVertex = Vector3Transform(animVertex,model.meshes[m].boneMatrices[boneId]);
+                mesh.animVertices[vCounter] += animVertex.x * boneWeight;
+                mesh.animVertices[vCounter+1] += animVertex.y * boneWeight;
+                mesh.animVertices[vCounter+2] += animVertex.z * boneWeight;
+                updated = true;
+                // Normals processing
+                // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
+                if (mesh.normals != NULL)
+                {
+                    animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
+                    animNormal = Vector3Transform(animNormal,model.meshes[m].boneMatrices[boneId]);
+                    mesh.animNormals[vCounter] += animNormal.x*boneWeight;
+                    mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
+                    mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
+                }
+            }
+        }
+        if (updated)
+        {
+            rlUpdateVertexBuffer(mesh.vboId[0], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); // Update vertex position
+            rlUpdateVertexBuffer(mesh.vboId[2], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0);  // Update vertex normals
+        }
+    }
+}
+
 // Unload animation array data
 void UnloadModelAnimations(ModelAnimation *animations, int animCount)
 {

+ 3 - 3
src/rtextures.c

@@ -828,15 +828,15 @@ Image GenImageGradientLinear(int width, int height, int direction, Color start,
     float sinDir = sinf(radianDirection);
 
     // Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
-    float startingPos = 0.5 - (cosDir*width/2) - (sinDir*height/2);
+    float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2);
     // With directions that lie in the first or third quadrant (i.e. from top-left to 
     // bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient
     // (i.e. the pixel which should become one of the gradient's ends color); while for
     // directions that lie in the second or fourth quadrant, that point is pixel (width, 0).
     float maxPosValue = 
             ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))
-            ? fabs(startingPos)
-            : fabs(startingPos+width*cosDir);
+            ? fabsf(startingPos)
+            : fabsf(startingPos+width*cosDir);
     for (int i = 0; i < width; i++)
     {
         for (int j = 0; j < height; j++)

Some files were not shown because too many files changed in this diff