Merge branch 'master' of https://github.com/raysan5/raylib
This commit is contained in:
commit
09570a05b3
17 changed files with 1544 additions and 723 deletions
138
build.zig
138
build.zig
|
@ -2,7 +2,7 @@ const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
/// Minimum supported version of Zig
|
/// Minimum supported version of Zig
|
||||||
const min_ver = "0.12.0";
|
const min_ver = "0.13.0";
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
const order = std.SemanticVersion.order;
|
const order = std.SemanticVersion.order;
|
||||||
|
@ -11,36 +11,6 @@ comptime {
|
||||||
@compileError("Raylib requires zig version " ++ min_ver);
|
@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 {
|
fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void {
|
||||||
raylib.defineCMacro("PLATFORM_DESKTOP", null);
|
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
|
/// A list of all flags from `src/config.h` that one may override
|
||||||
const config_h_flags = outer: {
|
const config_h_flags = outer: {
|
||||||
// Set this value higher if compile errors happen as `src/config.h` gets larger
|
// 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 {
|
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{
|
try raylib_flags_arr.appendSlice(&[_][]const u8{
|
||||||
"-fPIC",
|
|
||||||
"-DBUILD_LIBTYPE_SHARED",
|
|
||||||
};
|
|
||||||
try raylib_flags_arr.appendSlice(b.allocator, &[_][]const u8{
|
|
||||||
"-std=gnu99",
|
"-std=gnu99",
|
||||||
"-D_GNU_SOURCE",
|
"-D_GNU_SOURCE",
|
||||||
"-DGL_SILENCE_DEPRECATION=199309L",
|
"-DGL_SILENCE_DEPRECATION=199309L",
|
||||||
"-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674
|
"-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) {
|
if (options.config.len > 0) {
|
||||||
// Sets a flag indiciating the use of a custom `config.h`
|
// 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
|
// 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
|
// Apply config flags supplied by the user
|
||||||
while (config_iter.next()) |config_flag|
|
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
|
// 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
|
// 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)
|
const raylib = if (options.shared)
|
||||||
b.addSharedLibrary(.{
|
b.addSharedLibrary(.{
|
||||||
.name = "raylib",
|
.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, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol");
|
||||||
waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol");
|
waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol");
|
||||||
}
|
}
|
||||||
|
|
||||||
setDesktopPlatform(raylib, options.platform);
|
setDesktopPlatform(raylib, options.platform);
|
||||||
} else {
|
} else {
|
||||||
if (options.opengl_version == .auto) {
|
if (options.opengl_version == .auto) {
|
||||||
|
@ -255,8 +251,15 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
||||||
setDesktopPlatform(raylib, options.platform);
|
setDesktopPlatform(raylib, options.platform);
|
||||||
},
|
},
|
||||||
.macos => {
|
.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.
|
// 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(.{
|
raylib.root_module.addCSourceFile(.{
|
||||||
.file = b.path("src/rglfw.c"),
|
.file = b.path("src/rglfw.c"),
|
||||||
.flags = raylib_flags_arr.items,
|
.flags = raylib_flags_arr.items,
|
||||||
|
@ -271,20 +274,19 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
||||||
setDesktopPlatform(raylib, options.platform);
|
setDesktopPlatform(raylib, options.platform);
|
||||||
},
|
},
|
||||||
.emscripten => {
|
.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);
|
raylib.defineCMacro("PLATFORM_WEB", null);
|
||||||
if (options.opengl_version == .auto) {
|
if (options.opengl_version == .auto) {
|
||||||
raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null);
|
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 => {
|
else => {
|
||||||
@panic("Unsupported OS");
|
@panic("Unsupported OS");
|
||||||
|
@ -296,25 +298,19 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
||||||
.flags = raylib_flags_arr.items,
|
.flags = raylib_flags_arr.items,
|
||||||
});
|
});
|
||||||
|
|
||||||
return raylib;
|
if (options.raygui) {
|
||||||
}
|
const raygui_dep = b.dependency(options.raygui_dependency_name, .{});
|
||||||
|
|
||||||
/// This function does not need to be called if you passed .raygui = true to addRaylib
|
var gen_step = b.addWriteFiles();
|
||||||
pub fn addRaygui(b: *std.Build, raylib: *std.Build.Step.Compile, raygui_dep: *std.Build.Dependency) void {
|
raylib.step.dependOn(&gen_step.step);
|
||||||
if (raylib_flags_arr.items.len == 0) {
|
|
||||||
@panic(
|
const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n");
|
||||||
\\argument 2 `raylib` in `addRaygui` must come from b.dependency("raylib", ...).artifact("raylib")
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
var gen_step = b.addWriteFiles();
|
return raylib;
|
||||||
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"));
|
|
||||||
|
|
||||||
raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Options = struct {
|
pub const Options = struct {
|
||||||
|
|
24
build.zig.zon
Normal file
24
build.zig.zon
Normal file
|
@ -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",
|
||||||
|
},
|
||||||
|
}
|
|
@ -87,6 +87,8 @@ USE_EXTERNAL_GLFW ?= FALSE
|
||||||
# WARNING: Library is not included in raylib, it MUST be configured by users
|
# WARNING: Library is not included in raylib, it MUST be configured by users
|
||||||
SDL_INCLUDE_PATH ?= $(RAYLIB_SRC_PATH)/external/SDL2/include
|
SDL_INCLUDE_PATH ?= $(RAYLIB_SRC_PATH)/external/SDL2/include
|
||||||
SDL_LIBRARY_PATH ?= $(RAYLIB_SRC_PATH)/external/SDL2/lib
|
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)
|
# 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
|
# NOTE: This variable is only used for PLATFORM_OS: LINUX
|
||||||
|
@ -263,9 +265,9 @@ endif
|
||||||
# Define include paths for required headers: INCLUDE_PATHS
|
# Define include paths for required headers: INCLUDE_PATHS
|
||||||
# NOTE: Some external/extras libraries could be required (stb, easings...)
|
# 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
|
# Define additional directories containing required header files
|
||||||
|
|
||||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
|
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
|
||||||
ifeq ($(PLATFORM_OS),BSD)
|
ifeq ($(PLATFORM_OS),BSD)
|
||||||
INCLUDE_PATHS += -I$(RAYLIB_INCLUDE_PATH) -I/usr/pkg/include -I/usr/X11R7/include
|
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 ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
|
||||||
ifeq ($(PLATFORM_OS),WINDOWS)
|
ifeq ($(PLATFORM_OS),WINDOWS)
|
||||||
# Libraries for Windows desktop compilation
|
# Libraries for Windows desktop compilation
|
||||||
LDLIBS = -lraylib -lSDL2 -lSDL2main -lopengl32 -lgdi32
|
LDLIBS = -lraylib $(SDL_LIBRARIES) -lopengl32 -lgdi32
|
||||||
endif
|
endif
|
||||||
ifeq ($(PLATFORM_OS),LINUX)
|
ifeq ($(PLATFORM_OS),LINUX)
|
||||||
# Libraries for Debian GNU/Linux desktop compiling
|
# Libraries for Debian GNU/Linux desktop compiling
|
||||||
# NOTE: Required packages: libegl1-mesa-dev
|
# 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
|
# On X11 requires also below libraries
|
||||||
LDLIBS += -lX11
|
LDLIBS += -lX11
|
||||||
|
@ -646,8 +648,12 @@ OTHERS = \
|
||||||
others/embedded_files_loading \
|
others/embedded_files_loading \
|
||||||
others/raylib_opengl_interop \
|
others/raylib_opengl_interop \
|
||||||
others/raymath_vector_angle \
|
others/raymath_vector_angle \
|
||||||
others/rlgl_compute_shader \
|
others/rlgl_compute_shader
|
||||||
others/rlgl_standalone
|
|
||||||
|
ifeq ($(TARGET_PLATFORM), PLATFORM_DESKTOP_GFLW)
|
||||||
|
OTHERS += others/rlgl_standalone
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST))
|
CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST))
|
||||||
|
|
||||||
|
|
|
@ -3520,6 +3520,11 @@
|
||||||
"description": "Get clipboard text content",
|
"description": "Get clipboard text content",
|
||||||
"returnType": "const char *"
|
"returnType": "const char *"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "GetClipboardImage",
|
||||||
|
"description": "Get clipboard image",
|
||||||
|
"returnType": "Image"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "EnableEventWaiting",
|
"name": "EnableEventWaiting",
|
||||||
"description": "Enable waiting for events on EndDrawing(), no automatic event polling",
|
"description": "Enable waiting for events on EndDrawing(), no automatic event polling",
|
||||||
|
|
|
@ -3397,6 +3397,11 @@ return {
|
||||||
description = "Get clipboard text content",
|
description = "Get clipboard text content",
|
||||||
returnType = "const char *"
|
returnType = "const char *"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name = "GetClipboardImage",
|
||||||
|
description = "Get clipboard image",
|
||||||
|
returnType = "Image"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name = "EnableEventWaiting",
|
name = "EnableEventWaiting",
|
||||||
description = "Enable waiting for events on EndDrawing(), no automatic event polling",
|
description = "Enable waiting for events on EndDrawing(), no automatic event polling",
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -674,7 +674,7 @@
|
||||||
<Param type="unsigned int" name="frames" desc="" />
|
<Param type="unsigned int" name="frames" desc="" />
|
||||||
</Callback>
|
</Callback>
|
||||||
</Callbacks>
|
</Callbacks>
|
||||||
<Functions count="580">
|
<Functions count="581">
|
||||||
<Function name="InitWindow" retType="void" paramCount="3" desc="Initialize window and OpenGL context">
|
<Function name="InitWindow" retType="void" paramCount="3" desc="Initialize window and OpenGL context">
|
||||||
<Param type="int" name="width" desc="" />
|
<Param type="int" name="width" desc="" />
|
||||||
<Param type="int" name="height" desc="" />
|
<Param type="int" name="height" desc="" />
|
||||||
|
@ -795,6 +795,8 @@
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="GetClipboardText" retType="const char *" paramCount="0" desc="Get clipboard text content">
|
<Function name="GetClipboardText" retType="const char *" paramCount="0" desc="Get clipboard text content">
|
||||||
</Function>
|
</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 name="EnableEventWaiting" retType="void" paramCount="0" desc="Enable waiting for events on EndDrawing(), no automatic event polling">
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="DisableEventWaiting" retType="void" paramCount="0" desc="Disable waiting for events on EndDrawing(), automatic events polling">
|
<Function name="DisableEventWaiting" retType="void" paramCount="0" desc="Disable waiting for events on EndDrawing(), automatic events polling">
|
||||||
|
|
|
@ -118,6 +118,8 @@ GLFW_LINUX_ENABLE_X11 ?= TRUE
|
||||||
# WARNING: Library is not included in raylib, it MUST be configured by users
|
# WARNING: Library is not included in raylib, it MUST be configured by users
|
||||||
SDL_INCLUDE_PATH ?= $(RAYLIB_SRC_PATH)/external/SDL2/include
|
SDL_INCLUDE_PATH ?= $(RAYLIB_SRC_PATH)/external/SDL2/include
|
||||||
SDL_LIBRARY_PATH ?= $(RAYLIB_SRC_PATH)/external/SDL2/lib
|
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)
|
# 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")
|
# "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
|
# Define include paths for required headers: INCLUDE_PATHS
|
||||||
# NOTE: Several external required libraries (stb and others)
|
# NOTE: Several external required libraries (stb and others)
|
||||||
#------------------------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------------------------
|
||||||
INCLUDE_PATHS = -I.
|
INCLUDE_PATHS = -I. $(EXTRA_INCLUDE_PATHS)
|
||||||
|
|
||||||
# Define additional directories containing required header files
|
# Define additional directories containing required header files
|
||||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
|
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
|
||||||
|
@ -586,7 +588,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
|
||||||
LDLIBS += -lX11
|
LDLIBS += -lX11
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
LDLIBS += -lSDL2 -lSDL2main
|
LDLIBS += $(SDL_LIBRARIES)
|
||||||
endif
|
endif
|
||||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
|
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
|
||||||
ifeq ($(PLATFORM_OS),WINDOWS)
|
ifeq ($(PLATFORM_OS),WINDOWS)
|
||||||
|
|
28
src/config.h
28
src/config.h
|
@ -71,6 +71,7 @@
|
||||||
// Enabling this flag allows manual control of the frame processes, use at your own risk
|
// Enabling this flag allows manual control of the frame processes, use at your own risk
|
||||||
//#define SUPPORT_CUSTOM_FRAME_CONTROL 1
|
//#define SUPPORT_CUSTOM_FRAME_CONTROL 1
|
||||||
|
|
||||||
|
|
||||||
// rcore: Configuration values
|
// rcore: Configuration values
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
#define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity
|
#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
|
#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
|
#endif // CONFIG_H
|
||||||
|
|
374
src/external/win32_clipboard.h
vendored
Normal file
374
src/external/win32_clipboard.h
vendored
Normal file
|
@ -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
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
typedef void *PVOID;
|
typedef void *PVOID;
|
||||||
typedef PVOID HANDLE;
|
typedef PVOID HANDLE;
|
||||||
|
#include "../external/win32_clipboard.h"
|
||||||
typedef HANDLE HWND;
|
typedef HANDLE HWND;
|
||||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
#define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h
|
#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);
|
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
|
// Show mouse cursor
|
||||||
void ShowCursor(void)
|
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
|
// EOF
|
||||||
|
|
|
@ -664,6 +664,43 @@ const char *GetClipboardText(void)
|
||||||
return RGFW_readClipboard(NULL);
|
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
|
// Show mouse cursor
|
||||||
void ShowCursor(void)
|
void ShowCursor(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
* Custom flag for rcore on target platform -not used-
|
* Custom flag for rcore on target platform -not used-
|
||||||
*
|
*
|
||||||
* DEPENDENCIES:
|
* 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)
|
* - 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)
|
#include "SDL.h" // SDL base library (window/rendered, input, timing... functionality)
|
||||||
|
|
||||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
|
@ -64,6 +68,13 @@
|
||||||
#define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText()
|
#define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText()
|
||||||
#endif
|
#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
|
// 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
|
//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
|
// Module Internal Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -256,7 +451,12 @@ void ToggleFullscreen(void)
|
||||||
{
|
{
|
||||||
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
|
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
|
||||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
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))
|
if ((monitor >= 0) && (monitor < monitorCount))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
|
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
|
||||||
{
|
{
|
||||||
|
@ -279,7 +479,11 @@ void ToggleBorderlessWindowed(void)
|
||||||
{
|
{
|
||||||
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
|
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
|
||||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
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))
|
if ((monitor >= 0) && (monitor < monitorCount))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
|
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 monitor = SDL_GetWindowDisplayIndex(platform.window);
|
||||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
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))
|
if ((monitor >= 0) && (monitor < monitorCount))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
|
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
|
||||||
CORE.Window.fullscreen = true;
|
CORE.Window.fullscreen = true;
|
||||||
|
@ -387,7 +595,11 @@ void SetWindowState(unsigned int flags)
|
||||||
{
|
{
|
||||||
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
|
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
|
||||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
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))
|
if ((monitor >= 0) && (monitor < monitorCount))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
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 screenWidth = CORE.Window.screen.width;
|
||||||
const int screenHeight = CORE.Window.screen.height;
|
const int screenHeight = CORE.Window.screen.height;
|
||||||
SDL_Rect usableBounds;
|
SDL_Rect usableBounds;
|
||||||
|
#ifdef PLATFORM_DESKTOP_SDL3 // Different style for success checking
|
||||||
|
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds))
|
||||||
|
#else
|
||||||
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
|
if (SDL_GetDisplayUsableBounds(monitor, &usableBounds) == 0)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen.
|
if (wasFullscreen == 1) ToggleFullscreen(); // Leave fullscreen.
|
||||||
|
|
||||||
|
@ -704,6 +920,7 @@ int GetCurrentMonitor(void)
|
||||||
{
|
{
|
||||||
int currentMonitor = 0;
|
int currentMonitor = 0;
|
||||||
|
|
||||||
|
// Be aware that this returns an ID in SDL3 and a Index in SDL2
|
||||||
currentMonitor = SDL_GetWindowDisplayIndex(platform.window);
|
currentMonitor = SDL_GetWindowDisplayIndex(platform.window);
|
||||||
|
|
||||||
return currentMonitor;
|
return currentMonitor;
|
||||||
|
@ -716,7 +933,11 @@ Vector2 GetMonitorPosition(int monitor)
|
||||||
if ((monitor >= 0) && (monitor < monitorCount))
|
if ((monitor >= 0) && (monitor < monitorCount))
|
||||||
{
|
{
|
||||||
SDL_Rect displayBounds;
|
SDL_Rect displayBounds;
|
||||||
|
#ifdef PLATFORM_DESKTOP_SDL3
|
||||||
|
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds))
|
||||||
|
#else
|
||||||
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0)
|
if (SDL_GetDisplayUsableBounds(monitor, &displayBounds) == 0)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
return (Vector2){ (float)displayBounds.x, (float)displayBounds.y };
|
return (Vector2){ (float)displayBounds.x, (float)displayBounds.y };
|
||||||
}
|
}
|
||||||
|
@ -844,10 +1065,16 @@ Vector2 GetWindowScaleDPI(void)
|
||||||
{
|
{
|
||||||
Vector2 scale = { 1.0f, 1.0f };
|
Vector2 scale = { 1.0f, 1.0f };
|
||||||
|
|
||||||
|
#ifndef PLATFORM_DESKTOP_SDL3
|
||||||
// NOTE: SDL_GetWindowDisplayScale was only added on SDL3
|
// NOTE: SDL_GetWindowDisplayScale was only added on SDL3
|
||||||
// see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
|
// see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
|
||||||
// TODO: Implement the window scale factor calculation manually.
|
// TODO: Implement the window scale factor calculation manually.
|
||||||
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
|
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;
|
return scale;
|
||||||
}
|
}
|
||||||
|
@ -877,19 +1104,68 @@ const char *GetClipboardText(void)
|
||||||
return buffer;
|
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
|
// Show mouse cursor
|
||||||
void ShowCursor(void)
|
void ShowCursor(void)
|
||||||
{
|
{
|
||||||
|
#ifdef PLATFORM_DESKTOP_SDL3
|
||||||
|
SDL_ShowCursor();
|
||||||
|
#else
|
||||||
SDL_ShowCursor(SDL_ENABLE);
|
SDL_ShowCursor(SDL_ENABLE);
|
||||||
|
#endif
|
||||||
CORE.Input.Mouse.cursorHidden = false;
|
CORE.Input.Mouse.cursorHidden = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hides mouse cursor
|
// Hides mouse cursor
|
||||||
void HideCursor(void)
|
void HideCursor(void)
|
||||||
{
|
{
|
||||||
|
#ifdef PLATFORM_DESKTOP_SDL3
|
||||||
|
SDL_HideCursor();
|
||||||
|
#else
|
||||||
SDL_ShowCursor(SDL_DISABLE);
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
|
#endif
|
||||||
CORE.Input.Mouse.cursorHidden = true;
|
CORE.Input.Mouse.cursorHidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -897,7 +1173,13 @@ void HideCursor(void)
|
||||||
void EnableCursor(void)
|
void EnableCursor(void)
|
||||||
{
|
{
|
||||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
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);
|
SDL_ShowCursor(SDL_ENABLE);
|
||||||
|
#endif
|
||||||
|
|
||||||
platform.cursorRelative = false;
|
platform.cursorRelative = false;
|
||||||
CORE.Input.Mouse.cursorHidden = false;
|
CORE.Input.Mouse.cursorHidden = false;
|
||||||
|
@ -993,6 +1275,22 @@ const char *GetKeyName(int key)
|
||||||
|
|
||||||
static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
|
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);
|
CORE.Input.Touch.pointCount = SDL_GetNumTouchFingers(event.touchId);
|
||||||
|
|
||||||
for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
|
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.position[i].y = finger->y*CORE.Window.screen.height;
|
||||||
CORE.Input.Touch.currentTouchState[i] = 1;
|
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;
|
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 = (char **)RL_CALLOC(1024, sizeof(char *));
|
||||||
|
|
||||||
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, 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);
|
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
|
||||||
SDL_free(event.drop.file);
|
SDL_free(event.drop.file);
|
||||||
|
#endif
|
||||||
|
|
||||||
CORE.Window.dropFileCount++;
|
CORE.Window.dropFileCount++;
|
||||||
}
|
}
|
||||||
else if (CORE.Window.dropFileCount < 1024)
|
else if (CORE.Window.dropFileCount < 1024)
|
||||||
{
|
{
|
||||||
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
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);
|
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
|
||||||
SDL_free(event.drop.file);
|
SDL_free(event.drop.file);
|
||||||
|
#endif
|
||||||
|
|
||||||
CORE.Window.dropFileCount++;
|
CORE.Window.dropFileCount++;
|
||||||
}
|
}
|
||||||
|
@ -1112,10 +1421,18 @@ void PollInputEvents(void)
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
// Window events are also polled (Minimized, maximized, close...)
|
// 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:
|
case SDL_WINDOWEVENT:
|
||||||
{
|
{
|
||||||
switch (event.window.event)
|
switch (event.window.event)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
case SDL_WINDOWEVENT_RESIZED:
|
case SDL_WINDOWEVENT_RESIZED:
|
||||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||||
{
|
{
|
||||||
|
@ -1143,14 +1460,23 @@ void PollInputEvents(void)
|
||||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||||
case SDL_WINDOWEVENT_RESTORED:
|
case SDL_WINDOWEVENT_RESTORED:
|
||||||
|
#ifdef PLATFORM_DESKTOP_SDL3
|
||||||
|
break;
|
||||||
|
#else
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Keyboard events
|
// Keyboard events
|
||||||
case SDL_KEYDOWN:
|
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);
|
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (key != KEY_NULL)
|
if (key != KEY_NULL)
|
||||||
{
|
{
|
||||||
|
@ -1175,7 +1501,12 @@ void PollInputEvents(void)
|
||||||
|
|
||||||
case SDL_KEYUP:
|
case SDL_KEYUP:
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef PLATFORM_DESKTOP_SDL3
|
||||||
|
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
|
||||||
|
#else
|
||||||
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
|
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
|
||||||
|
#endif
|
||||||
if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
|
if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -1527,7 +1858,11 @@ int InitPlatform(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init window
|
// 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);
|
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
|
// Init OpenGL context
|
||||||
platform.glContext = SDL_GL_CreateContext(platform.window);
|
platform.glContext = SDL_GL_CreateContext(platform.window);
|
||||||
|
@ -1611,7 +1946,12 @@ int InitPlatform(void)
|
||||||
CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
|
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");
|
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully");
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 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 void SetClipboardText(const char *text); // Set clipboard text content
|
||||||
RLAPI const char *GetClipboardText(void); // Get 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 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
|
RLAPI void DisableEventWaiting(void); // Disable waiting for events on EndDrawing(), automatic events polling
|
||||||
|
|
||||||
|
|
|
@ -512,6 +512,12 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
|
||||||
#define PLATFORM_DESKTOP_GLFW
|
#define PLATFORM_DESKTOP_GLFW
|
||||||
#endif
|
#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
|
// Include platform-specific submodules
|
||||||
#if defined(PLATFORM_DESKTOP_GLFW)
|
#if defined(PLATFORM_DESKTOP_GLFW)
|
||||||
#include "platforms/rcore_desktop_glfw.c"
|
#include "platforms/rcore_desktop_glfw.c"
|
||||||
|
|
162
src/rmodels.c
162
src/rmodels.c
|
@ -2262,108 +2262,6 @@ ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount)
|
||||||
return animations;
|
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
|
// 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],
|
// 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
|
// 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
|
// Unload animation array data
|
||||||
void UnloadModelAnimations(ModelAnimation *animations, int animCount)
|
void UnloadModelAnimations(ModelAnimation *animations, int animCount)
|
||||||
{
|
{
|
||||||
|
|
|
@ -828,15 +828,15 @@ Image GenImageGradientLinear(int width, int height, int direction, Color start,
|
||||||
float sinDir = sinf(radianDirection);
|
float sinDir = sinf(radianDirection);
|
||||||
|
|
||||||
// Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
|
// 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
|
// 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
|
// 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
|
// (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).
|
// directions that lie in the second or fourth quadrant, that point is pixel (width, 0).
|
||||||
float maxPosValue =
|
float maxPosValue =
|
||||||
((signbit(sinDir) != 0) == (signbit(cosDir) != 0))
|
((signbit(sinDir) != 0) == (signbit(cosDir) != 0))
|
||||||
? fabs(startingPos)
|
? fabsf(startingPos)
|
||||||
: fabs(startingPos+width*cosDir);
|
: fabsf(startingPos+width*cosDir);
|
||||||
for (int i = 0; i < width; i++)
|
for (int i = 0; i < width; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < height; j++)
|
for (int j = 0; j < height; j++)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue