Merge branch 'master' into mikes-input

This commit is contained in:
MichaelFiber 2023-10-14 13:48:32 -04:00 committed by GitHub
commit 32576c398c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 11190 additions and 3882 deletions

View File

@ -81,6 +81,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to
| rayed-bqn | **auto** | [BQN](https://mlochbaum.github.io/BQN/) | MIT | https://github.com/Brian-ED/rayed-bqn |
| rayjs | 4.6-dev | [QuickJS](https://bellard.org/quickjs/) | MIT | https://github.com/mode777/rayjs |
| raylib-raku | **auto** | [Raku](https://www.raku.org/) | Artistic License 2.0 | https://github.com/vushu/raylib-raku |
| Raylib.lean | 4.5 | [Lean4](https://lean-lang.org/) | BSD-3-Clause | https://github.com/KislyjKisel/Raylib.lean |
### Utility Wrapers
These are utility wrappers for specific languages, they are not required to use raylib in the language but may adapt the raylib API to be more inline with the language's pardigm.

View File

@ -1,7 +1,7 @@
const std = @import("std");
const raylib = @import("src/build.zig");
// This has been tested to work with zig master branch as of commit 87de821 or May 14 2023
// This has been tested to work with zig 0.11.0 (67709b6, Aug 4 2023)
pub fn build(b: *std.Build) void {
raylib.build(b);
}

View File

@ -1,7 +1,7 @@
const std = @import("std");
const builtin = @import("builtin");
// This has been tested to work with zig master branch as of commit 87de821 or May 14 2023
// This has been tested to work with zig 0.11.0 (67709b6, Aug 4 2023)
fn add_module(comptime module: []const u8, b: *std.Build, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode) !*std.Build.Step {
if (target.getOsTag() == .emscripten) {
@panic("Emscripten building via Zig unsupported");
@ -11,7 +11,7 @@ fn add_module(comptime module: []const u8, b: *std.Build, target: std.zig.CrossT
const dir = try std.fs.cwd().openIterableDir(module, .{});
var iter = dir.iterate();
while (try iter.next()) |entry| {
if (entry.kind != .File) continue;
if (entry.kind != .file) continue;
const extension_idx = std.mem.lastIndexOf(u8, entry.name, ".c") orelse continue;
const name = entry.name[0..extension_idx];
const path = try std.fs.path.join(b.allocator, &.{ module, entry.name });
@ -24,26 +24,26 @@ fn add_module(comptime module: []const u8, b: *std.Build, target: std.zig.CrossT
.target = target,
.optimize = optimize,
});
exe.addCSourceFile(path, &[_][]const u8{});
exe.addCSourceFile(.{ .file = .{ .path = path }, .flags = &.{} });
exe.linkLibC();
exe.addObjectFile(switch (target.getOsTag()) {
.windows => "../src/zig-out/lib/raylib.lib",
.linux => "../src/zig-out/lib/libraylib.a",
.macos => "../src/zig-out/lib/libraylib.a",
.emscripten => "../src/zig-out/lib/libraylib.a",
.windows => .{ .path = "../zig-out/lib/raylib.lib" },
.linux => .{ .path = "../zig-out/lib/libraylib.a" },
.macos => .{ .path = "../zig-out/lib/libraylib.a" },
.emscripten => .{ .path = "../zig-out/lib/libraylib.a" },
else => @panic("Unsupported OS"),
});
exe.addIncludePath("../src");
exe.addIncludePath("../src/external");
exe.addIncludePath("../src/external/glfw/include");
exe.addIncludePath(.{ .path = "../src" });
exe.addIncludePath(.{ .path = "../src/external" });
exe.addIncludePath(.{ .path = "../src/external/glfw/include" });
switch (target.getOsTag()) {
.windows => {
exe.linkSystemLibrary("winmm");
exe.linkSystemLibrary("gdi32");
exe.linkSystemLibrary("opengl32");
exe.addIncludePath("external/glfw/deps/mingw");
exe.addIncludePath(.{ .path = "external/glfw/deps/mingw" });
exe.defineCMacro("PLATFORM_DESKTOP", null);
},
@ -71,11 +71,15 @@ fn add_module(comptime module: []const u8, b: *std.Build, target: std.zig.CrossT
},
}
b.installArtifact(exe);
var run = b.addRunArtifact(exe);
run.cwd = module;
b.step(name, name).dependOn(&run.step);
all.dependOn(&exe.step);
const install_cmd = b.addInstallArtifact(exe, .{});
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(&install_cmd.step);
const run_step = b.step(name, name);
run_step.dependOn(&run_cmd.step);
all.dependOn(&install_cmd.step);
}
return all;
}

View File

@ -1,18 +1,18 @@
/*******************************************************************************************
*
* raylib [core] example - Gamepad information
*
* NOTE: This example requires a Gamepad connected to the system
* Check raylib.h for buttons configuration
*
* Example originally created with raylib 4.6, last time updated with raylib 4.6
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
*
* raylib [core] example - Gamepad information
*
* NOTE: This example requires a Gamepad connected to the system
* Check raylib.h for buttons configuration
*
* Example originally created with raylib 4.6, last time updated with raylib 4.6
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
@ -26,14 +26,14 @@ int main(void)
const int screenWidth = 800;
const int screenHeight = 450;
SetConfigFlags(FLAG_MSAA_4X_HINT); // Set MSAA 4X hint before windows creation
SetConfigFlags(FLAG_MSAA_4X_HINT); // Set MSAA 4X hint before windows creation
InitWindow(screenWidth, screenHeight, "raylib [core] example - gamepad information");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
while (!WindowShouldClose()) // Detect window close button or ESC key
{
int y = 10;
@ -69,6 +69,6 @@ int main(void)
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
}

View File

@ -1,6 +1,6 @@
const std = @import("std");
// This has been tested to work with zig master branch as of commit 87de821 or May 14 2023
// This has been tested to work with zig 0.11.0 (67709b6, Aug 4 2023)
pub fn addRaylib(b: *std.Build, target: std.zig.CrossTarget, optimize: std.builtin.OptimizeMode, options: Options) *std.Build.CompileStep {
const raylib_flags = &[_][]const u8{
"-std=gnu99",

File diff suppressed because it is too large Load Diff

10303
src/external/stb_image_resize2.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -981,14 +981,14 @@ void UnloadSoundAlias(Sound alias)
}
// Update sound buffer with new data
void UpdateSound(Sound sound, const void *data, int sampleCount)
void UpdateSound(Sound sound, const void *data, int frameCount)
{
if (sound.stream.buffer != NULL)
{
StopAudioBuffer(sound.stream.buffer);
// TODO: May want to lock/unlock this since this data buffer is read at mixing time
memcpy(sound.stream.buffer->data, data, sampleCount*ma_get_bytes_per_frame(sound.stream.buffer->converter.formatIn, sound.stream.buffer->converter.channelsIn));
memcpy(sound.stream.buffer->data, data, frameCount*ma_get_bytes_per_frame(sound.stream.buffer->converter.formatIn, sound.stream.buffer->converter.channelsIn));
}
}

View File

@ -986,14 +986,6 @@ RLAPI const char *GetClipboardText(void); // Get clipboa
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
// Custom frame control functions
// NOTE: Those functions are intended for advance users that want full control over the frame processing
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL
RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing)
RLAPI void PollInputEvents(void); // Register all input events
RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution)
// Cursor-related functions
RLAPI void ShowCursor(void); // Shows cursor
RLAPI void HideCursor(void); // Hides cursor
@ -1049,9 +1041,17 @@ RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Get the
// Timing-related functions
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
RLAPI int GetFPS(void); // Get current FPS
RLAPI float GetFrameTime(void); // Get time in seconds for last frame drawn (delta time)
RLAPI double GetTime(void); // Get elapsed time in seconds since InitWindow()
RLAPI int GetFPS(void); // Get current FPS
// Custom frame control functions
// NOTE: Those functions are intended for advance users that want full control over the frame processing
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL
RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing)
RLAPI void PollInputEvents(void); // Register all input events
RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution)
// Misc. functions
RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included)

View File

@ -322,18 +322,15 @@ const char *TextFormat(const char *text, ...); // Formatting of text with
//void InitWindow(int width, int height, const char *title)
//void CloseWindow(void)
//bool WindowShouldClose(void)
//bool IsWindowHidden(void)
//bool IsWindowMinimized(void)
//bool IsWindowMaximized(void)
//bool IsWindowFocused(void)
//bool IsWindowResized(void)
//void ToggleFullscreen(void)
//void ToggleBorderlessWindowed(void)
//void MaximizeWindow(void)
//void MinimizeWindow(void)
//void RestoreWindow(void)
//void ToggleBorderlessWindowed(void)
//void SetWindowState(unsigned int flags)
//void ClearWindowState(unsigned int flags)
//void SetWindowIcon(Image image)
//void SetWindowIcons(Image *images, int count)
//void SetWindowTitle(const char *title)
@ -345,25 +342,27 @@ const char *TextFormat(const char *text, ...); // Formatting of text with
//void SetWindowOpacity(float opacity)
//void SetWindowFocused(void)
//void *GetWindowHandle(void)
//Vector2 GetWindowPosition(void)
//Vector2 GetWindowScaleDPI(void)
//int GetMonitorCount(void)
//int GetCurrentMonitor(void)
//Vector2 GetMonitorPosition(int monitor)
//int GetMonitorWidth(int monitor)
//int GetMonitorHeight(int monitor)
//int GetMonitorPhysicalWidth(int monitor)
//int GetMonitorPhysicalHeight(int monitor)
//int GetMonitorRefreshRate(int monitor)
//Vector2 GetMonitorPosition(int monitor)
//const char *GetMonitorName(int monitor)
//Vector2 GetWindowPosition(void)
//Vector2 GetWindowScaleDPI(void)
//void SetClipboardText(const char *text)
//const char *GetClipboardText(void)
//void ShowCursor(void)
//void HideCursor(void)
//void EnableCursor(void)
//void DisableCursor(void)
// Check if window has been initialized successfully
bool IsWindowReady(void)
{
@ -376,6 +375,36 @@ bool IsWindowFullscreen(void)
return CORE.Window.fullscreen;
}
// Check if window is currently hidden
bool IsWindowHidden(void)
{
return ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0);
}
// Check if window has been minimized
bool IsWindowMinimized(void)
{
return ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0);
}
// Check if window has been maximized
bool IsWindowMaximized(void)
{
return ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0);
}
// Check if window has the focus
bool IsWindowFocused(void)
{
return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0);
}
// Check if window has been resizedLastFrame
bool IsWindowResized(void)
{
return CORE.Window.resizedLastFrame;
}
// Check if one specific window flag is enabled
bool IsWindowState(unsigned int flag)
{
@ -394,13 +423,13 @@ int GetScreenHeight(void)
return CORE.Window.screen.height;
}
// Get current render width which is equal to screen width * dpi scale
// Get current render width which is equal to screen width*dpi scale
int GetRenderWidth(void)
{
return CORE.Window.render.width;
}
// Get current screen height which is equal to screen height * dpi scale
// Get current screen height which is equal to screen height*dpi scale
int GetRenderHeight(void)
{
return CORE.Window.render.height;
@ -430,15 +459,6 @@ bool IsCursorOnScreen(void)
return CORE.Input.Mouse.cursorOnScreen;
}
//----------------------------------------------------------------------------------
// Module Functions Definition: Custom frame control
//----------------------------------------------------------------------------------
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//void SwapScreenBuffer(void);
//void PollInputEvents(void);
//void WaitTime(double seconds);
//----------------------------------------------------------------------------------
// Module Functions Definition: Screen Drawing
//----------------------------------------------------------------------------------
@ -1236,6 +1256,60 @@ float GetFrameTime(void)
return (float)CORE.Time.frame;
}
//----------------------------------------------------------------------------------
// Module Functions Definition: Custom frame control
//----------------------------------------------------------------------------------
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//void SwapScreenBuffer(void);
//void PollInputEvents(void);
// Wait for some time (stop program execution)
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop
// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
void WaitTime(double seconds)
{
if (seconds < 0) return;
#if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double destinationTime = GetTime() + seconds;
#endif
#if defined(SUPPORT_BUSY_WAIT_LOOP)
while (GetTime() < destinationTime) { }
#else
#if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double sleepSeconds = seconds - seconds*0.05; // NOTE: We reserve a percentage of the time for busy waiting
#else
double sleepSeconds = seconds;
#endif
// System halt functions
#if defined(_WIN32)
Sleep((unsigned long)(sleepSeconds*1000.0));
#endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec req = { 0 };
time_t sec = sleepSeconds;
long nsec = (sleepSeconds - sec)*1000000000L;
req.tv_sec = sec;
req.tv_nsec = nsec;
// NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated.
while (nanosleep(&req, &req) == -1) continue;
#endif
#if defined(__APPLE__)
usleep(sleepSeconds*1000000.0);
#endif
#if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
while (GetTime() < destinationTime) { }
#endif
#endif
}
//----------------------------------------------------------------------------------
// Module Functions Definition: Misc
//----------------------------------------------------------------------------------
@ -2023,8 +2097,6 @@ void SetExitKey(int key)
//----------------------------------------------------------------------------------
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//int GetGamepadAxisCount(int gamepad) **
//const char *GetGamepadName(int gamepad) **
//int SetGamepadMappings(const char *mappings)
// Check if a gamepad is available
@ -2038,10 +2110,10 @@ bool IsGamepadAvailable(int gamepad)
}
// Get gamepad internal name id
//const char *GetGamepadName(int gamepad)
//{
// return CORE.Input.Gamepad.ready[gamepad];
//}
const char *GetGamepadName(int gamepad)
{
return CORE.Input.Gamepad.name[gamepad];
}
// Check if a gamepad button has been pressed once
bool IsGamepadButtonPressed(int gamepad, int button)
@ -2094,10 +2166,10 @@ int GetGamepadButtonPressed(void)
}
// Get gamepad axis count
//int GetGamepadAxisCount(int gamepad)
//{
// return CORE.Input.Gamepad.axisCount;
//}
int GetGamepadAxisCount(int gamepad)
{
return CORE.Input.Gamepad.axisCount;
}
// Get axis movement vector for a gamepad
float GetGamepadAxisMovement(int gamepad, int axis)
@ -2115,11 +2187,7 @@ float GetGamepadAxisMovement(int gamepad, int axis)
//----------------------------------------------------------------------------------
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//int GetMouseX(void) **
//int GetMouseY(void) **
//Vector2 GetMousePosition(void) **
//void SetMousePosition(int x, int y)
//float GetMouseWheelMove(void) **
//void SetMouseCursor(int cursor)
// Check if a mouse button has been pressed once
@ -2174,6 +2242,29 @@ bool IsMouseButtonUp(int button)
return up;
}
// Get mouse position X
int GetMouseX(void)
{
return (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x);
}
// Get mouse position Y
int GetMouseY(void)
{
return (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y);
}
// Get mouse position XY
Vector2 GetMousePosition(void)
{
Vector2 position = { 0 };
position.x = (CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x;
position.y = (CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y;
return position;
}
// Get mouse delta between frames
Vector2 GetMouseDelta(void)
{
@ -2199,6 +2290,17 @@ void SetMouseScale(float scaleX, float scaleY)
CORE.Input.Mouse.scale = (Vector2){ scaleX, scaleY };
}
// Get mouse wheel movement Y
float GetMouseWheelMove(void)
{
float result = 0.0f;
if (fabsf(CORE.Input.Mouse.currentWheelMove.x) > fabsf(CORE.Input.Mouse.currentWheelMove.y)) result = (float)CORE.Input.Mouse.currentWheelMove.x;
else result = (float)CORE.Input.Mouse.currentWheelMove.y;
return result;
}
// Get mouse wheel movement X/Y as a vector
Vector2 GetMouseWheelMoveV(void)
{
@ -2213,10 +2315,29 @@ Vector2 GetMouseWheelMoveV(void)
// Module Functions Definition: Input Handling: Touch
//----------------------------------------------------------------------------------
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//int GetTouchX(void)
//int GetTouchY(void)
//Vector2 GetTouchPosition(int index)
// Get touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
return (int)CORE.Input.Touch.position[0].x;
}
// Get touch position Y for touch point 0 (relative to screen size)
int GetTouchY(void)
{
return (int)CORE.Input.Touch.position[0].y;
}
// Get touch position XY for a touch point index (relative to screen size)
// TODO: Touch position should be scaled depending on display size and render size
Vector2 GetTouchPosition(int index)
{
Vector2 position = { -1.0f, -1.0f };
if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index];
else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS);
return position;
}
// Get touch point identifier for given index
int GetTouchPointId(int index)
@ -2238,8 +2359,32 @@ int GetTouchPointCount(void)
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Platform-specific functions
//static bool InitGraphicsDevice(int width, int height)
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//static bool InitPlatform(void)
// Initialize hi-resolution timer
void InitTimer(void)
{
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
// High resolutions can also prevent the CPU power management system from entering power-saving modes.
// Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.
#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
#endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec now = { 0 };
if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
{
CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;
}
else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available");
#endif
CORE.Time.previous = GetTime(); // Get time as double
}
// Set viewport for a provided width and height
void SetupViewport(int width, int height)
@ -2348,76 +2493,6 @@ void SetupFramebuffer(int width, int height)
}
}
// Initialize hi-resolution timer
void InitTimer(void)
{
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
// High resolutions can also prevent the CPU power management system from entering power-saving modes.
// Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.
#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
#endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec now = { 0 };
if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
{
CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;
}
else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available");
#endif
CORE.Time.previous = GetTime(); // Get time as double
}
// Wait for some time (stop program execution)
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop
// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
void WaitTime(double seconds)
{
if (seconds < 0) return;
#if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double destinationTime = GetTime() + seconds;
#endif
#if defined(SUPPORT_BUSY_WAIT_LOOP)
while (GetTime() < destinationTime) { }
#else
#if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double sleepSeconds = seconds - seconds*0.05; // NOTE: We reserve a percentage of the time for busy waiting
#else
double sleepSeconds = seconds;
#endif
// System halt functions
#if defined(_WIN32)
Sleep((unsigned long)(sleepSeconds*1000.0));
#endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec req = { 0 };
time_t sec = sleepSeconds;
long nsec = (sleepSeconds - sec)*1000000000L;
req.tv_sec = sec;
req.tv_nsec = nsec;
// NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated.
while (nanosleep(&req, &req) == -1) continue;
#endif
#if defined(__APPLE__)
usleep(sleepSeconds*1000000.0);
#endif
#if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
while (GetTime() < destinationTime) { }
#endif
#endif
}
// Scan all files and directories in a base path
// WARNING: files.paths[] must be previously allocated and
// contain enough space to store all required paths
@ -2737,7 +2812,7 @@ static void RecordAutomationEvent(unsigned int frame)
// INPUT_GAMEPAD_CONNECT
/*
if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
(CORE.Input.Gamepad.currentState[gamepad] == true)) // Check if changed to ready
(CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to ready
{
// TODO: Save gamepad connect event
}
@ -2746,7 +2821,7 @@ static void RecordAutomationEvent(unsigned int frame)
// INPUT_GAMEPAD_DISCONNECT
/*
if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
(CORE.Input.Gamepad.currentState[gamepad] == false)) // Check if changed to not-ready
(!CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to not-ready
{
// TODO: Save gamepad disconnect event
}
@ -2894,12 +2969,21 @@ const char *TextFormat(const char *text, ...)
va_list args;
va_start(args, text);
vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
va_end(args);
// If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occured
if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH)
{
// Inserting "..." at the end of the string to mark as truncated
char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0"
sprintf(truncBuffer, "...");
}
index += 1; // Move to next buffer for next function call
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
return currentBuffer;
}
#endif // !SUPPORT_MODULE_RTEXT

View File

@ -127,8 +127,6 @@ typedef struct CoreData {
Point renderOffset; // Offset from render area (must be divided by 2)
Size screenMin; // Screen minimum width and height (for resizable window)
Size screenMax; // Screen maximum width and height (for resizable window)
Size windowMin; // Window minimum width and height
Size windowMax; // Window maximum width and height
Matrix screenScale; // Matrix to scale screen (framebuffer rendering)
char **dropFilepaths; // Store dropped files paths pointers (provided by GLFW)

View File

@ -82,7 +82,8 @@ static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
static bool InitGraphicsDevice(int width, int height); // Initialize graphics device
static int InitPlatform(void); // Initialize platform (graphics, inputs and more)
static void ClosePlatform(void); // Close platform
static void AndroidCommandCallback(struct android_app *app, int32_t cmd); // Process Android activity lifecycle commands
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); // Process Android inputs
@ -172,81 +173,23 @@ void InitWindow(int width, int height, const char *title)
TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
#endif
// NOTE: Keep internal pointer to input title string (no copy)
// Initialize window data
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
CORE.Window.eventWaiting = false;
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
// Initialize global input state
memset(&CORE.Input, 0, sizeof(CORE.Input));
memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
CORE.Window.eventWaiting = false;
CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
CORE.Window.currentFbo.width = width;
CORE.Window.currentFbo.height = height;
// Platform specific init window
// Initialize platform
//--------------------------------------------------------------
// Set desired windows flags before initializing anything
ANativeActivity_setWindowFlags(platform.app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
int orientation = AConfiguration_getOrientation(platform.app->config);
if (orientation == ACONFIGURATION_ORIENTATION_PORT) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as portrait");
else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as landscape");
// TODO: Automatic orientation doesn't seem to work
if (width <= height)
{
AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_PORT);
TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to portrait");
}
else
{
AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_LAND);
TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to landscape");
}
//AConfiguration_getDensity(platform.app->config);
//AConfiguration_getKeyboard(platform.app->config);
//AConfiguration_getScreenSize(platform.app->config);
//AConfiguration_getScreenLong(platform.app->config);
// Initialize App command system
// NOTE: On APP_CMD_INIT_WINDOW -> InitGraphicsDevice(), InitTimer(), LoadFontDefault()...
platform.app->onAppCmd = AndroidCommandCallback;
// Initialize input events system
platform.app->onInputEvent = AndroidInputCallback;
// Initialize assets manager
InitAssetManager(platform.app->activity->assetManager, platform.app->activity->internalDataPath);
// Initialize base path for storage
CORE.Storage.basePath = platform.app->activity->internalDataPath;
TRACELOG(LOG_INFO, "PLATFORM: ANDROID: Application initialized successfully");
// Android ALooper_pollAll() variables
int pollResult = 0;
int pollEvents = 0;
// Wait for window to be initialized (display and context)
while (!CORE.Window.ready)
{
// Process events loop
while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void**)&platform.source)) >= 0)
{
// Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
// NOTE: Never close window, native activity is controlled by the system!
//if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true;
}
}
InitPlatform();
//--------------------------------------------------------------
}
@ -272,28 +215,9 @@ void CloseWindow(void)
timeEndPeriod(1); // Restore time period
#endif
// Platform specific close window
// De-initialize platform
//--------------------------------------------------------------
// Close surface, context and display
if (platform.device != EGL_NO_DISPLAY)
{
eglMakeCurrent(platform.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (platform.surface != EGL_NO_SURFACE)
{
eglDestroySurface(platform.device, platform.surface);
platform.surface = EGL_NO_SURFACE;
}
if (platform.context != EGL_NO_CONTEXT)
{
eglDestroyContext(platform.device, platform.context);
platform.context = EGL_NO_CONTEXT;
}
eglTerminate(platform.device);
platform.device = EGL_NO_DISPLAY;
}
ClosePlatform();
//--------------------------------------------------------------
#if defined(SUPPORT_EVENTS_AUTOMATION)
@ -311,42 +235,18 @@ bool WindowShouldClose(void)
else return true;
}
// Check if window is currently hidden
bool IsWindowHidden(void)
{
return false;
}
// Check if window has been minimized
bool IsWindowMinimized(void)
{
return false;
}
// Check if window has been maximized
bool IsWindowMaximized(void)
{
return false;
}
// Check if window has the focus
bool IsWindowFocused(void)
{
return platform.appEnabled;
}
// Check if window has been resizedLastFrame
bool IsWindowResized(void)
{
return false;
}
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform");
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
}
// Set window state: maximized, if resizable
void MaximizeWindow(void)
{
@ -365,12 +265,6 @@ void RestoreWindow(void)
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
}
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
@ -416,15 +310,15 @@ void SetWindowMonitor(int monitor)
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
void SetWindowMinSize(int width, int height)
{
CORE.Window.windowMin.width = width;
CORE.Window.windowMin.height = height;
CORE.Window.screenMin.width = width;
CORE.Window.screenMin.height = height;
}
// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
void SetWindowMaxSize(int width, int height)
{
CORE.Window.windowMax.width = width;
CORE.Window.windowMax.height = height;
CORE.Window.screenMax.width = width;
CORE.Window.screenMax.height = height;
}
// Set window dimensions
@ -635,18 +529,6 @@ void OpenURL(const char *url)
// Module Functions Definition: Inputs
//----------------------------------------------------------------------------------
// Get gamepad internal name id
const char *GetGamepadName(int gamepad)
{
return CORE.Input.Gamepad.name[gamepad];
}
// Get gamepad axis count
int GetGamepadAxisCount(int gamepad)
{
return CORE.Input.Gamepad.axisCount;
}
// Set internal gamepad mappings
int SetGamepadMappings(const char *mappings)
{
@ -654,24 +536,6 @@ int SetGamepadMappings(const char *mappings)
return 0;
}
// Get mouse position X
int GetMouseX(void)
{
return (int)CORE.Input.Touch.position[0].x;
}
// Get mouse position Y
int GetMouseY(void)
{
return (int)CORE.Input.Touch.position[0].y;
}
// Get mouse position XY
Vector2 GetMousePosition(void)
{
return GetTouchPosition(0);
}
// Set mouse position XY
void SetMousePosition(int x, int y)
{
@ -679,43 +543,12 @@ void SetMousePosition(int x, int y)
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
// Get mouse wheel movement Y
float GetMouseWheelMove(void)
{
TRACELOG(LOG_WARNING, "GetMouseWheelMove() not implemented on target platform");
return 0.0f;
}
// Set mouse cursor
void SetMouseCursor(int cursor)
{
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
}
// Get touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
return (int)CORE.Input.Touch.position[0].x;
}
// Get touch position Y for touch point 0 (relative to screen size)
int GetTouchY(void)
{
return (int)CORE.Input.Touch.position[0].y;
}
// Get touch position XY for a touch point index (relative to screen size)
// TODO: Touch position should be scaled depending on display size and render size
Vector2 GetTouchPosition(int index)
{
Vector2 position = { -1.0f, -1.0f };
if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index];
else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS);
return position;
}
// Register all input events
void PollInputEvents(void)
{
@ -774,25 +607,108 @@ void PollInputEvents(void)
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Initialize platform: graphics, inputs and more
static int InitPlatform(void)
{
CORE.Window.currentFbo.width = CORE.Window.screen.width;
CORE.Window.currentFbo.height = CORE.Window.screen.height;
// Set desired windows flags before initializing anything
ANativeActivity_setWindowFlags(platform.app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
int orientation = AConfiguration_getOrientation(platform.app->config);
if (orientation == ACONFIGURATION_ORIENTATION_PORT) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as portrait");
else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TRACELOG(LOG_INFO, "ANDROID: Window orientation set as landscape");
// TODO: Automatic orientation doesn't seem to work
if (CORE.Window.screen.width <= CORE.Window.screen.height)
{
AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_PORT);
TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to portrait");
}
else
{
AConfiguration_setOrientation(platform.app->config, ACONFIGURATION_ORIENTATION_LAND);
TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to landscape");
}
//AConfiguration_getDensity(platform.app->config);
//AConfiguration_getKeyboard(platform.app->config);
//AConfiguration_getScreenSize(platform.app->config);
//AConfiguration_getScreenLong(platform.app->config);
// Initialize App command system
// NOTE: On APP_CMD_INIT_WINDOW -> InitGraphicsDevice(), InitTimer(), LoadFontDefault()...
platform.app->onAppCmd = AndroidCommandCallback;
// Initialize input events system
platform.app->onInputEvent = AndroidInputCallback;
// Initialize assets manager
InitAssetManager(platform.app->activity->assetManager, platform.app->activity->internalDataPath);
// Initialize base path for storage
CORE.Storage.basePath = platform.app->activity->internalDataPath;
// Set some default window flags
CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // false
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
TRACELOG(LOG_INFO, "PLATFORM: ANDROID: Application initialized successfully");
// Android ALooper_pollAll() variables
int pollResult = 0;
int pollEvents = 0;
// Wait for window to be initialized (display and context)
while (!CORE.Window.ready)
{
// Process events loop
while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void**)&platform.source)) >= 0)
{
// Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
// NOTE: Never close window, native activity is controlled by the system!
//if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true;
}
}
}
// Close platform
static void ClosePlatform(void)
{
// Close surface, context and display
if (platform.device != EGL_NO_DISPLAY)
{
eglMakeCurrent(platform.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (platform.surface != EGL_NO_SURFACE)
{
eglDestroySurface(platform.device, platform.surface);
platform.surface = EGL_NO_SURFACE;
}
if (platform.context != EGL_NO_CONTEXT)
{
eglDestroyContext(platform.device, platform.context);
platform.context = EGL_NO_CONTEXT;
}
eglTerminate(platform.device);
platform.device = EGL_NO_DISPLAY;
}
}
// Initialize display device and framebuffer
// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size
// If width or height are 0, default display size will be used for framebuffer size
// NOTE: returns false in case graphic device could not be created
static bool InitGraphicsDevice(int width, int height)
static bool InitGraphicsDevice(void)
{
CORE.Window.screen.width = width; // User desired width
CORE.Window.screen.height = height; // User desired height
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
// Set the screen minimum and maximum default values to 0
CORE.Window.screenMin.width = 0;
CORE.Window.screenMin.height = 0;
CORE.Window.screenMax.width = 0;
CORE.Window.screenMax.height = 0;
// NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars...
// ...in top-down or left-right to match display aspect ratio (no weird scaling)
CORE.Window.fullscreen = true;
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
@ -832,7 +748,7 @@ static bool InitGraphicsDevice(int width, int height)
if (platform.device == EGL_NO_DISPLAY)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
return false;
return -1;
}
// Initialize the EGL device connection
@ -840,7 +756,7 @@ static bool InitGraphicsDevice(int width, int height)
{
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
return false;
return -1;
}
// Get an appropriate EGL framebuffer configuration
@ -854,7 +770,7 @@ static bool InitGraphicsDevice(int width, int height)
if (platform.context == EGL_NO_CONTEXT)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context");
return false;
return -1;
}
// Create an EGL window surface
@ -883,7 +799,7 @@ static bool InitGraphicsDevice(int width, int height)
if (eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context) == EGL_FALSE)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface");
return false;
return -1;
}
else
{
@ -903,19 +819,11 @@ static bool InitGraphicsDevice(int width, int height)
// NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(eglGetProcAddress);
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
CORE.Window.ready = true;
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
return true;
return 0;
}
// ANDROID: Process activity lifecycle commands
@ -958,25 +866,50 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
CORE.Window.display.height = ANativeWindow_getHeight(platform.app->window);
// Initialize graphics device (display device and OpenGL context)
InitGraphicsDevice(CORE.Window.screen.width, CORE.Window.screen.height);
InitGraphicsDevice();
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Initialize hi-res timer
InitTimer();
// Initialize random seed
srand((unsigned int)time(NULL));
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
// Load default font
// WARNING: External function: Module required: rtext
LoadFontDefault();
Rectangle rec = GetFontDefault().recs[95];
// NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
#if defined(SUPPORT_MODULE_RSHAPES)
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); // WARNING: Module required: rshapes
// Set font white rectangle for shapes drawing, so shapes and text can be batched together
// WARNING: rshapes module is required, if not available, default internal white rectangle is used
Rectangle rec = GetFontDefault().recs[95];
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
{
// NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
}
else
{
// NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
}
#endif
#else
#if defined(SUPPORT_MODULE_RSHAPES)
// Set default texture and rectangle to be used for shapes drawing
// NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); // WARNING: Module required: rshapes
#endif
#endif
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
// TODO: GPU assets reload in case of lost focus (lost context)
// NOTE: This problem has been solved just unbinding and rebinding context from display
/*
@ -997,12 +930,14 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
case APP_CMD_GAINED_FOCUS:
{
platform.appEnabled = true;
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
//ResumeMusicStream();
} break;
case APP_CMD_PAUSE: break;
case APP_CMD_LOST_FOCUS:
{
platform.appEnabled = false;
CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
//PauseMusicStream();
} break;
case APP_CMD_TERM_WINDOW:
@ -1234,6 +1169,8 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
{
gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
gestureEvent.position[i] = CORE.Input.Touch.position[i];
gestureEvent.position[i].x /= (float)GetScreenWidth();
gestureEvent.position[i].y /= (float)GetScreenHeight();
}
// Gesture data is sent to gestures system for processing
@ -1260,6 +1197,20 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
if (CORE.Input.Touch.pointCount > 0) CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 1;
else CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 0;
// Stores the previous position of touch[0] only while it's active to calculate the delta.
if (flags == AMOTION_EVENT_ACTION_MOVE)
{
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
else
{
CORE.Input.Mouse.previousPosition = CORE.Input.Touch.position[0];
}
// Map touch[0] as mouse input for convenience
CORE.Input.Mouse.currentPosition = CORE.Input.Touch.position[0];
CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f };
return 0;
}

View File

@ -2,7 +2,7 @@
*
* rcore_desktop - Functions to manage window, graphics device and inputs
*
* PLATFORM: DESKTOP
* PLATFORM: DESKTOP: GLFW
* - Windows (Win32, Win64)
* - Linux (X11/Wayland desktop mode)
* - FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop)
@ -111,7 +111,8 @@ static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
static bool InitGraphicsDevice(int width, int height); // Initialize graphics device
static int InitPlatform(void); // Initialize platform (graphics, inputs and more)
static void ClosePlatform(void); // Close platform
// Error callback event
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
@ -176,33 +177,31 @@ void InitWindow(int width, int height, const char *title)
TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
#endif
// NOTE: Keep internal pointer to input title string (no copy)
// Initialize window data
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
CORE.Window.eventWaiting = false;
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
// Initialize global input state
memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE structure to 0
memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
CORE.Window.eventWaiting = false;
CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
// Initialize graphics device
// NOTE: returns true if window and graphic device has been initialized successfully
CORE.Window.ready = InitGraphicsDevice(width, height);
// Initialize platform
//--------------------------------------------------------------
InitPlatform();
//--------------------------------------------------------------
// If graphic device is no properly initialized, we end program
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return; }
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
// Initialize rlgl default data (buffers and shaders)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Initialize hi-res timer
InitTimer();
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
// Initialize base path for storage
CORE.Storage.basePath = GetWorkingDirectory();
// Setup default viewport
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
// Load default font
@ -246,6 +245,9 @@ void InitWindow(int width, int height, const char *title)
CORE.Time.frameCounter = 0;
#endif
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP: Application initialized successfully");
}
@ -267,14 +269,9 @@ void CloseWindow(void)
rlglClose(); // De-init rlgl
// Platform specific close window
// De-initialize platform
//--------------------------------------------------------------
glfwDestroyWindow(platform.handle);
glfwTerminate();
#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
timeEndPeriod(1); // Restore time period
#endif
ClosePlatform();
//--------------------------------------------------------------
#if defined(SUPPORT_EVENTS_AUTOMATION)
@ -304,36 +301,6 @@ bool WindowShouldClose(void)
else return true;
}
// Check if window is currently hidden
bool IsWindowHidden(void)
{
return ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0);
}
// Check if window has been minimized
bool IsWindowMinimized(void)
{
return ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0);
}
// Check if window has been maximized
bool IsWindowMaximized(void)
{
return ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0);
}
// Check if window has the focus
bool IsWindowFocused(void)
{
return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0);
}
// Check if window has been resizedLastFrame
bool IsWindowResized(void)
{
return CORE.Window.resizedLastFrame;
}
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
@ -380,35 +347,6 @@ void ToggleFullscreen(void)
if (CORE.Window.flags & FLAG_VSYNC_HINT) glfwSwapInterval(1);
}
// Set window state: maximized, if resizable
void MaximizeWindow(void)
{
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
{
glfwMaximizeWindow(platform.handle);
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
}
}
// Set window state: minimized
void MinimizeWindow(void)
{
// NOTE: Following function launches callback that sets appropriate flag!
glfwIconifyWindow(platform.handle);
}
// Set window state: not minimized/maximized
void RestoreWindow(void)
{
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
{
// Restores the specified window if it was previously iconified (minimized) or maximized
glfwRestoreWindow(platform.handle);
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;
CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
}
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
@ -484,6 +422,35 @@ void ToggleBorderlessWindowed(void)
else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
}
// Set window state: maximized, if resizable
void MaximizeWindow(void)
{
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
{
glfwMaximizeWindow(platform.handle);
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
}
}
// Set window state: minimized
void MinimizeWindow(void)
{
// NOTE: Following function launches callback that sets appropriate flag!
glfwIconifyWindow(platform.handle);
}
// Set window state: not minimized/maximized
void RestoreWindow(void)
{
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
{
// Restores the specified window if it was previously iconified (minimized) or maximized
glfwRestoreWindow(platform.handle);
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;
CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
}
}
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
@ -1222,47 +1189,12 @@ void OpenURL(const char *url)
// Module Functions Definition: Inputs
//----------------------------------------------------------------------------------
// Get gamepad internal name id
const char *GetGamepadName(int gamepad)
{
return CORE.Input.Gamepad.name[gamepad];
}
// Get gamepad axis count
int GetGamepadAxisCount(int gamepad)
{
return CORE.Input.Gamepad.axisCount;
}
// Set internal gamepad mappings
int SetGamepadMappings(const char *mappings)
{
return glfwUpdateGamepadMappings(mappings);
}
// Get mouse position X
int GetMouseX(void)
{
return (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x);
}
// Get mouse position Y
int GetMouseY(void)
{
return (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y);
}
// Get mouse position XY
Vector2 GetMousePosition(void)
{
Vector2 position = { 0 };
position.x = (CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x;
position.y = (CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y;
return position;
}
// Set mouse position XY
void SetMousePosition(int x, int y)
{
@ -1273,17 +1205,6 @@ void SetMousePosition(int x, int y)
glfwSetCursorPos(platform.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y);
}
// Get mouse wheel movement Y
float GetMouseWheelMove(void)
{
float result = 0.0f;
if (fabsf(CORE.Input.Mouse.currentWheelMove.x) > fabsf(CORE.Input.Mouse.currentWheelMove.y)) result = (float)CORE.Input.Mouse.currentWheelMove.x;
else result = (float)CORE.Input.Mouse.currentWheelMove.y;
return result;
}
// Set mouse cursor
void SetMouseCursor(int cursor)
{
@ -1296,32 +1217,6 @@ void SetMouseCursor(int cursor)
}
}
// Get touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
return GetMouseX();
}
// Get touch position Y for touch point 0 (relative to screen size)
int GetTouchY(void)
{
return GetMouseY();
}
// Get touch position XY for a touch point index (relative to screen size)
// TODO: Touch position should be scaled depending on display size and render size
Vector2 GetTouchPosition(int index)
{
Vector2 position = { -1.0f, -1.0f };
// TODO: GLFW does not support multi-touch input just yet
// https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch
// https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages
if (index == 0) position = GetMousePosition();
return position;
}
// Register all input events
void PollInputEvents(void)
{
@ -1365,6 +1260,13 @@ void PollInputEvents(void)
// Reset touch positions
//for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 };
// Map touch position to mouse position for convenience
// WARNING: If the target desktop device supports touch screen, this behavious should be reviewed!
// TODO: GLFW does not support multi-touch input just yet
// https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch
// https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
// Check if gamepads are ready
// NOTE: We do it here in case of disconnection
for (int i = 0; i < MAX_GAMEPADS; i++)
@ -1454,25 +1356,9 @@ void PollInputEvents(void)
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Initialize display device and framebuffer
// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size
// If width or height are 0, default display size will be used for framebuffer size
// NOTE: returns false in case graphic device could not be created
static bool InitGraphicsDevice(int width, int height)
// Initialize platform: graphics, inputs and more
static int InitPlatform(void)
{
CORE.Window.screen.width = width; // User desired width
CORE.Window.screen.height = height; // User desired height
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
// Set the screen minimum and maximum default values to 0
CORE.Window.screenMin.width = 0;
CORE.Window.screenMin.height = 0;
CORE.Window.screenMax.width = 0;
CORE.Window.screenMax.height = 0;
// NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars...
// ...in top-down or left-right to match display aspect ratio (no weird scaling)
glfwSetErrorCallback(ErrorCallback);
/*
// TODO: Setup GLFW custom allocators to match raylib ones
@ -1485,15 +1371,13 @@ static bool InitGraphicsDevice(int width, int height)
glfwInitAllocator(&allocator);
*/
#if defined(__APPLE__)
glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE);
#endif
if (!glfwInit())
{
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize GLFW");
return false;
}
// Initialize GLFW internal global state
int result = glfwInit();
if (result == GLFW_FALSE) { TRACELOG(LOG_WARNING, "GLFW: Failed to initialize GLFW"); return -1; }
glfwDefaultWindowHints(); // Set default windows hints
//glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits
@ -1615,7 +1499,7 @@ static bool InitGraphicsDevice(int width, int height)
if (!monitor)
{
TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor");
return false;
return -1;
}
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
@ -1704,7 +1588,7 @@ static bool InitGraphicsDevice(int width, int height)
{
glfwTerminate();
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
return false;
return -1;
}
// Set window callback events
@ -1770,22 +1654,37 @@ static bool InitGraphicsDevice(int width, int height)
// Load OpenGL extensions
// NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(glfwGetProcAddress);
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
return true;
CORE.Window.ready = true; // TODO: Proper validation on windows/context creation
// If graphic device is no properly initialized, we end program
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
// Initialize hi-res timer
InitTimer();
// Initialize base path for storage
CORE.Storage.basePath = GetWorkingDirectory();
return 0;
}
// Close platform
static void ClosePlatform(void)
{
glfwDestroyWindow(platform.handle);
glfwTerminate();
#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
timeEndPeriod(1); // Restore time period
#endif
}
// GLFW3 Error Callback, runs on GLFW3 error
static void ErrorCallback(int error, const char *description)
{
@ -2053,7 +1952,7 @@ static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffs
// GLFW3 CursorEnter Callback, when cursor enters the window
static void CursorEnterCallback(GLFWwindow *window, int enter)
{
if (enter == true) CORE.Input.Mouse.cursorOnScreen = true;
if (enter) CORE.Input.Mouse.cursorOnScreen = true;
else CORE.Input.Mouse.cursorOnScreen = false;
}

View File

@ -155,12 +155,13 @@ static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
static bool InitGraphicsDevice(int width, int height); // Initialize graphics device
static int InitPlatform(void); // Initialize platform (graphics, inputs and more)
static void ClosePlatform(void); // Close platform
static void InitKeyboard(void); // Initialize raw keyboard system
static void RestoreKeyboard(void); // Restore keyboard system
static void InitKeyboard(void); // Initialize raw keyboard system
static void RestoreKeyboard(void); // Restore keyboard system
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
static void ProcessKeyboard(void); // Process keyboard events
static void ProcessKeyboard(void); // Process keyboard events
#endif
static void InitDrmInput(void); // Initialize inputs for DRM platform
@ -223,38 +224,31 @@ void InitWindow(int width, int height, const char *title)
TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
#endif
// NOTE: Keep internal pointer to input title string (no copy)
// Initialize window data
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
CORE.Window.eventWaiting = false;
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
// Initialize global input state
memset(&CORE.Input, 0, sizeof(CORE.Input));
memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
CORE.Input.Mouse.scale = (Vector2){1.0f, 1.0f};
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
CORE.Window.eventWaiting = false;
CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
for (int i = 0; i < MAX_GAMEPADS; i++)
{
CORE.Input.Gamepad.ready[i] = false;
}
// Initialize platform
//--------------------------------------------------------------
InitPlatform();
//--------------------------------------------------------------
// Initialize graphics device (display device and OpenGL context)
// NOTE: returns true if window and graphic device has been initialized successfully
CORE.Window.ready = InitGraphicsDevice(width, height);
// Initialize rlgl default data (buffers and shaders)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// If graphic device is no properly initialized, we end program
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return; }
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor()) / 2 - CORE.Window.screen.width / 2, GetMonitorHeight(GetCurrentMonitor()) / 2 - CORE.Window.screen.height / 2);
// Initialize hi-res timer
InitTimer();
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
// Initialize base path for storage
CORE.Storage.basePath = GetWorkingDirectory();
// Setup default viewport
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
// Load default font
@ -298,14 +292,8 @@ void InitWindow(int width, int height, const char *title)
CORE.Time.frameCounter = 0;
#endif
// Platform specific init window
//--------------------------------------------------------------
// Initialize raw input system
InitDrmInput(); // DRM platform input initialization
InitEvdevInput(); // Evdev inputs initialization
//InitGamepad(); // Gamepad init
InitKeyboard(); // Keyboard init (stdin)
//--------------------------------------------------------------
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
TRACELOG(LOG_INFO, "PLATFORM: DRM: Application initialized successfully");
}
@ -332,93 +320,9 @@ void CloseWindow(void)
timeEndPeriod(1); // Restore time period
#endif
// Platform specific close window
// De-initialize platform
//--------------------------------------------------------------
if (platform.prevFB)
{
drmModeRmFB(platform.fd, platform.prevFB);
platform.prevFB = 0;
}
if (platform.prevBO)
{
gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
platform.prevBO = NULL;
}
if (platform.gbmSurface)
{
gbm_surface_destroy(platform.gbmSurface);
platform.gbmSurface = NULL;
}
if (platform.gbmDevice)
{
gbm_device_destroy(platform.gbmDevice);
platform.gbmDevice = NULL;
}
if (platform.crtc)
{
if (platform.connector)
{
drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, platform.crtc->buffer_id,
platform.crtc->x, platform.crtc->y, &platform.connector->connector_id, 1, &platform.crtc->mode);
drmModeFreeConnector(platform.connector);
platform.connector = NULL;
}
drmModeFreeCrtc(platform.crtc);
platform.crtc = NULL;
}
if (platform.fd != -1)
{
close(platform.fd);
platform.fd = -1;
}
// Close surface, context and display
if (platform.device != EGL_NO_DISPLAY)
{
if (platform.surface != EGL_NO_SURFACE)
{
eglDestroySurface(platform.device, platform.surface);
platform.surface = EGL_NO_SURFACE;
}
if (platform.context != EGL_NO_CONTEXT)
{
eglDestroyContext(platform.device, platform.context);
platform.context = EGL_NO_CONTEXT;
}
eglTerminate(platform.device);
platform.device = EGL_NO_DISPLAY;
}
// Wait for mouse and gamepad threads to finish before closing
// NOTE: Those threads should already have finished at this point
// because they are controlled by CORE.Window.shouldClose variable
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called
// Close the evdev keyboard
if (platform.keyboardFd != -1)
{
close(platform.keyboardFd);
platform.keyboardFd = -1;
}
for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
{
if (platform.eventWorker[i].threadId)
{
pthread_join(platform.eventWorker[i].threadId, NULL);
}
}
if (platform.gamepadThreadId) pthread_join(platform.gamepadThreadId, NULL);
ClosePlatform();
//--------------------------------------------------------------
#if defined(SUPPORT_EVENTS_AUTOMATION)
@ -437,42 +341,18 @@ bool WindowShouldClose(void)
else return true;
}
// Check if window is currently hidden
bool IsWindowHidden(void)
{
return false;
}
// Check if window has been minimized
bool IsWindowMinimized(void)
{
return false;
}
// Check if window has been maximized
bool IsWindowMaximized(void)
{
return false;
}
// Check if window has the focus
bool IsWindowFocused(void)
{
return true;
}
// Check if window has been resizedLastFrame
bool IsWindowResized(void)
{
return false;
}
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform");
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
}
// Set window state: maximized, if resizable
void MaximizeWindow(void)
{
@ -491,12 +371,6 @@ void RestoreWindow(void)
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
}
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
@ -542,15 +416,15 @@ void SetWindowMonitor(int monitor)
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
void SetWindowMinSize(int width, int height)
{
CORE.Window.windowMin.width = width;
CORE.Window.windowMin.height = height;
CORE.Window.screenMin.width = width;
CORE.Window.screenMin.height = height;
}
// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
void SetWindowMaxSize(int width, int height)
{
CORE.Window.windowMax.width = width;
CORE.Window.windowMax.height = height;
CORE.Window.screenMax.width = width;
CORE.Window.screenMax.height = height;
}
// Set window dimensions
@ -764,18 +638,6 @@ void OpenURL(const char *url)
// Module Functions Definition: Inputs
//----------------------------------------------------------------------------------
// Get gamepad internal name id
const char *GetGamepadName(int gamepad)
{
return CORE.Input.Gamepad.name[gamepad];
}
// Get gamepad axis count
int GetGamepadAxisCount(int gamepad)
{
return CORE.Input.Gamepad.axisCount[gamepad];
}
// Set internal gamepad mappings
int SetGamepadMappings(const char *mappings)
{
@ -783,29 +645,6 @@ int SetGamepadMappings(const char *mappings)
return 0;
}
// Get mouse position X
int GetMouseX(void)
{
return (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x);
}
// Get mouse position Y
int GetMouseY(void)
{
return (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y);
}
// Get mouse position XY
Vector2 GetMousePosition(void)
{
Vector2 position = { 0 };
position.x = (CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x;
position.y = (CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y;
return position;
}
// Set mouse position XY
void SetMousePosition(int x, int y)
{
@ -813,46 +652,12 @@ void SetMousePosition(int x, int y)
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
// Get mouse wheel movement Y
float GetMouseWheelMove(void)
{
float result = 0.0f;
if (fabsf(CORE.Input.Mouse.currentWheelMove.x) > fabsf(CORE.Input.Mouse.currentWheelMove.y)) result = (float)CORE.Input.Mouse.currentWheelMove.x;
else result = (float)CORE.Input.Mouse.currentWheelMove.y;
return result;
}
// Set mouse cursor
void SetMouseCursor(int cursor)
{
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
}
// Get touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
return GetMouseX();
}
// Get touch position Y for touch point 0 (relative to screen size)
int GetTouchY(void)
{
return GetMouseY();
}
// Get touch position XY for a touch point index (relative to screen size)
Vector2 GetTouchPosition(int index)
{
Vector2 position = { -1.0f, -1.0f };
if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index];
else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS);
return position;
}
// Register all input events
void PollInputEvents(void)
{
@ -924,28 +729,9 @@ void PollInputEvents(void)
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Initialize display device and framebuffer
// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size
// If width or height are 0, default display size will be used for framebuffer size
// NOTE: returns false in case graphic device could not be created
static bool InitGraphicsDevice(int width, int height)
// Initialize platform: graphics, inputs and more
static int InitPlatform(void)
{
CORE.Window.screen.width = width; // User desired width
CORE.Window.screen.height = height; // User desired height
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
// Set the window minimum and maximum default values to 0
CORE.Window.windowMin.width = 0;
CORE.Window.windowMin.height = 0;
CORE.Window.windowMax.width = 0;
CORE.Window.windowMax.height = 0;
// NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars...
// ...in top-down or left-right to match display aspect ratio (no weird scaling)
CORE.Window.fullscreen = true;
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
platform.fd = -1;
platform.connector = NULL;
platform.modeIndex = -1;
@ -955,6 +741,9 @@ static bool InitGraphicsDevice(int width, int height)
platform.prevBO = NULL;
platform.prevFB = 0;
CORE.Window.fullscreen = true;
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
#else
@ -977,14 +766,14 @@ static bool InitGraphicsDevice(int width, int height)
if (platform.fd == -1)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card");
return false;
return -1;
}
drmModeRes *res = drmModeGetResources(platform.fd);
if (!res)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources");
return false;
return -1;
}
TRACELOG(LOG_TRACE, "DISPLAY: Connectors found: %i", res->count_connectors);
@ -1013,7 +802,7 @@ static bool InitGraphicsDevice(int width, int height)
{
TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found");
drmModeFreeResources(res);
return false;
return -1;
}
drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id);
@ -1021,7 +810,7 @@ static bool InitGraphicsDevice(int width, int height)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder");
drmModeFreeResources(res);
return false;
return -1;
}
platform.crtc = drmModeGetCrtc(platform.fd, enc->crtc_id);
@ -1030,7 +819,7 @@ static bool InitGraphicsDevice(int width, int height)
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc");
drmModeFreeEncoder(enc);
drmModeFreeResources(res);
return false;
return -1;
}
// If InitWindow should use the current mode find it in the connector's mode list
@ -1045,7 +834,7 @@ static bool InitGraphicsDevice(int width, int height)
TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found");
drmModeFreeEncoder(enc);
drmModeFreeResources(res);
return false;
return -1;
}
CORE.Window.screen.width = CORE.Window.display.width;
@ -1073,7 +862,7 @@ static bool InitGraphicsDevice(int width, int height)
TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode");
drmModeFreeEncoder(enc);
drmModeFreeResources(res);
return false;
return -1;
}
CORE.Window.display.width = platform.connector->modes[platform.modeIndex].hdisplay;
@ -1098,7 +887,7 @@ static bool InitGraphicsDevice(int width, int height)
if (!platform.gbmDevice)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM device");
return false;
return -1;
}
platform.gbmSurface = gbm_surface_create(platform.gbmDevice, platform.connector->modes[platform.modeIndex].hdisplay,
@ -1106,7 +895,7 @@ static bool InitGraphicsDevice(int width, int height)
if (!platform.gbmSurface)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM surface");
return false;
return -1;
}
EGLint samples = 0;
@ -1146,7 +935,7 @@ static bool InitGraphicsDevice(int width, int height)
if (platform.device == EGL_NO_DISPLAY)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
return false;
return -1;
}
// Initialize the EGL device connection
@ -1154,13 +943,13 @@ static bool InitGraphicsDevice(int width, int height)
{
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
return false;
return -1;
}
if (!eglChooseConfig(platform.device, NULL, NULL, 0, &numConfigs))
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError());
return false;
return -1;
}
TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs);
@ -1169,7 +958,7 @@ static bool InitGraphicsDevice(int width, int height)
if (!configs)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs");
return false;
return -1;
}
EGLint matchingNumConfigs = 0;
@ -1177,7 +966,7 @@ static bool InitGraphicsDevice(int width, int height)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose EGL config: 0x%x", eglGetError());
free(configs);
return false;
return -1;
}
TRACELOG(LOG_TRACE, "DISPLAY: EGL matching configs available: %d", matchingNumConfigs);
@ -1207,7 +996,7 @@ static bool InitGraphicsDevice(int width, int height)
if (!found)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable EGL config");
return false;
return -1;
}
// Set rendering API
@ -1218,7 +1007,7 @@ static bool InitGraphicsDevice(int width, int height)
if (platform.context == EGL_NO_CONTEXT)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context");
return false;
return -1;
}
// Create an EGL window surface
@ -1227,7 +1016,7 @@ static bool InitGraphicsDevice(int width, int height)
if (EGL_NO_SURFACE == platform.surface)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL window surface: 0x%04x", eglGetError());
return false;
return -1;
}
// At this point we need to manage render size vs screen size
@ -1243,7 +1032,7 @@ static bool InitGraphicsDevice(int width, int height)
if (eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context) == EGL_FALSE)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface");
return false;
return -1;
}
else
{
@ -1263,19 +1052,125 @@ static bool InitGraphicsDevice(int width, int height)
// NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(eglGetProcAddress);
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
return true;
CORE.Window.ready = true; // TODO: Proper validation on windows/context creation
// If graphic device is no properly initialized, we end program
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor()) / 2 - CORE.Window.screen.width / 2, GetMonitorHeight(GetCurrentMonitor()) / 2 - CORE.Window.screen.height / 2);
// Set some default window flags
CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // false
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
// Initialize hi-res timer
InitTimer();
// Initialize base path for storage
CORE.Storage.basePath = GetWorkingDirectory();
// Initialize raw input system
InitEvdevInput(); // Evdev inputs initialization
InitGamepad(); // Gamepad init
InitKeyboard(); // Keyboard init (stdin)
return 0;
}
// Close platform
static void ClosePlatform(void)
{
if (platform.prevFB)
{
drmModeRmFB(platform.fd, platform.prevFB);
platform.prevFB = 0;
}
if (platform.prevBO)
{
gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
platform.prevBO = NULL;
}
if (platform.gbmSurface)
{
gbm_surface_destroy(platform.gbmSurface);
platform.gbmSurface = NULL;
}
if (platform.gbmDevice)
{
gbm_device_destroy(platform.gbmDevice);
platform.gbmDevice = NULL;
}
if (platform.crtc)
{
if (platform.connector)
{
drmModeSetCrtc(platform.fd, platform.crtc->crtc_id, platform.crtc->buffer_id,
platform.crtc->x, platform.crtc->y, &platform.connector->connector_id, 1, &platform.crtc->mode);
drmModeFreeConnector(platform.connector);
platform.connector = NULL;
}
drmModeFreeCrtc(platform.crtc);
platform.crtc = NULL;
}
if (platform.fd != -1)
{
close(platform.fd);
platform.fd = -1;
}
// Close surface, context and display
if (platform.device != EGL_NO_DISPLAY)
{
if (platform.surface != EGL_NO_SURFACE)
{
eglDestroySurface(platform.device, platform.surface);
platform.surface = EGL_NO_SURFACE;
}
if (platform.context != EGL_NO_CONTEXT)
{
eglDestroyContext(platform.device, platform.context);
platform.context = EGL_NO_CONTEXT;
}
eglTerminate(platform.device);
platform.device = EGL_NO_DISPLAY;
}
// Wait for mouse and gamepad threads to finish before closing
// NOTE: Those threads should already have finished at this point
// because they are controlled by CORE.Window.shouldClose variable
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called
// Close the evdev keyboard
if (platform.keyboardFd != -1)
{
close(platform.keyboardFd);
platform.keyboardFd = -1;
}
for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
{
if (platform.eventWorker[i].threadId)
{
pthread_join(platform.eventWorker[i].threadId, NULL);
}
}
if (platform.gamepadThreadId) pthread_join(platform.gamepadThreadId, NULL);
}
// Initialize Keyboard system (using standard input)
static void InitKeyboard(void)
{

View File

@ -1,6 +1,6 @@
/**********************************************************************************************
*
* rcore_<platform> - Functions to manage window, graphics device and inputs
* rcore_<platform> template - Functions to manage window, graphics device and inputs
*
* PLATFORM: <PLATFORM>
* - TODO: Define the target platform for the core
@ -73,7 +73,8 @@ static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
static bool InitGraphicsDevice(int width, int height); // Initialize graphics device
static int InitPlatform(void); // Initialize platform (graphics, inputs and more)
static bool InitGraphicsDevice(void); // Initialize graphics device
//----------------------------------------------------------------------------------
// Module Functions Declaration
@ -128,8 +129,11 @@ void InitWindow(int width, int height, const char *title)
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
CORE.Window.eventWaiting = false;
// TODO: Platform specific init window
//--------------------------------------------------------------
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
CORE.Window.currentFbo.width = width;
@ -139,17 +143,15 @@ void InitWindow(int width, int height, const char *title)
// NOTE: returns true if window and graphic device has been initialized successfully
CORE.Window.ready = InitGraphicsDevice(width, height);
// If graphic device is no properly initialized, we end program
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return; }
// Initialize hi-res timer
InitTimer();
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Initialize base path for storage
CORE.Storage.basePath = GetWorkingDirectory();
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
// Load default font
@ -193,10 +195,8 @@ void InitWindow(int width, int height, const char *title)
CORE.Time.frameCounter = 0;
#endif
// TODO: Platform specific init window
//--------------------------------------------------------------
// ...
//--------------------------------------------------------------
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
TRACELOG(LOG_INFO, "PLATFORM: CUSTOM: Application initialized successfully");
}
@ -239,42 +239,18 @@ bool WindowShouldClose(void)
else return true;
}
// Check if window is currently hidden
bool IsWindowHidden(void)
{
return false;
}
// Check if window has been minimized
bool IsWindowMinimized(void)
{
return false;
}
// Check if window has been maximized
bool IsWindowMaximized(void)
{
return false;
}
// Check if window has the focus
bool IsWindowFocused(void)
{
return platform.appEnabled;
}
// Check if window has been resizedLastFrame
bool IsWindowResized(void)
{
return false;
}
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform");
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
}
// Set window state: maximized, if resizable
void MaximizeWindow(void)
{
@ -293,12 +269,6 @@ void RestoreWindow(void)
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
}
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
@ -344,15 +314,15 @@ void SetWindowMonitor(int monitor)
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
void SetWindowMinSize(int width, int height)
{
CORE.Window.windowMin.width = width;
CORE.Window.windowMin.height = height;
CORE.Window.screenMin.width = width;
CORE.Window.screenMin.height = height;
}
// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
void SetWindowMaxSize(int width, int height)
{
CORE.Window.windowMax.width = width;
CORE.Window.windowMax.height = height;
CORE.Window.screenMax.width = width;
CORE.Window.screenMax.height = height;
}
// Set window dimensions
@ -563,18 +533,6 @@ void OpenURL(const char *url)
// Module Functions Definition: Inputs
//----------------------------------------------------------------------------------
// Get gamepad internal name id
const char *GetGamepadName(int gamepad)
{
return CORE.Input.Gamepad.name[gamepad];
}
// Get gamepad axis count
int GetGamepadAxisCount(int gamepad)
{
return CORE.Input.Gamepad.axisCount;
}
// Set internal gamepad mappings
int SetGamepadMappings(const char *mappings)
{
@ -582,30 +540,6 @@ int SetGamepadMappings(const char *mappings)
return 0;
}
// Get mouse position X
int GetMouseX(void)
{
return (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x);
}
// Get mouse position Y
int GetMouseY(void)
{
return (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y);
}
// Get mouse position XY
Vector2 GetMousePosition(void)
{
Vector2 position = { 0 };
// NOTE: On canvas scaling, mouse position is proportionally returned
position.x = (CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x;
position.y = (CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y;
return position;
}
// Set mouse position XY
void SetMousePosition(int x, int y)
{
@ -613,43 +547,12 @@ void SetMousePosition(int x, int y)
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
// Get mouse wheel movement Y
float GetMouseWheelMove(void)
{
TRACELOG(LOG_WARNING, "GetMouseWheelMove() not implemented on target platform");
return 0.0f;
}
// Set mouse cursor
void SetMouseCursor(int cursor)
{
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
}
// Get touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
return (int)CORE.Input.Touch.position[0].x;
}
// Get touch position Y for touch point 0 (relative to screen size)
int GetTouchY(void)
{
return (int)CORE.Input.Touch.position[0].y;
}
// Get touch position XY for a touch point index (relative to screen size)
// TODO: Touch position should be scaled depending on display size and render size
Vector2 GetTouchPosition(int index)
{
Vector2 position = { -1.0f, -1.0f };
if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index];
else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS);
return position;
}
// Register all input events
void PollInputEvents(void)
{
@ -694,25 +597,9 @@ void PollInputEvents(void)
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Initialize display device and framebuffer
// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size
// If width or height are 0, default display size will be used for framebuffer size
// NOTE: returns false in case graphic device could not be created
static bool InitGraphicsDevice(int width, int height)
// Initialize platform: graphics, inputs and more
static int InitPlatform(void)
{
CORE.Window.screen.width = width; // User desired width
CORE.Window.screen.height = height; // User desired height
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
// Set the screen minimum and maximum default values to 0
CORE.Window.screenMin.width = 0;
CORE.Window.screenMin.height = 0;
CORE.Window.screenMax.width = 0;
CORE.Window.screenMax.height = 0;
// NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars...
// ...in top-down or left-right to match display aspect ratio (no weird scaling)
CORE.Window.fullscreen = true;
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
@ -774,7 +661,7 @@ static bool InitGraphicsDevice(int width, int height)
if (platform.context == EGL_NO_CONTEXT)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context");
return false;
return -1;
}
// Create an EGL window surface
@ -803,7 +690,7 @@ static bool InitGraphicsDevice(int width, int height)
if (eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context) == EGL_FALSE)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface");
return false;
return -1;
}
else
{
@ -823,19 +710,24 @@ static bool InitGraphicsDevice(int width, int height)
// NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(eglGetProcAddress);
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
CORE.Window.ready = true;
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
// If graphic device is no properly initialized, we end program
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
return true;
// Initialize hi-res timer
InitTimer();
// Initialize base path for storage
CORE.Storage.basePath = GetWorkingDirectory();
return 0;
}
// Close platform
static void ClosePlatform(void)
{
// TODO: De-initialize graphics, inputs and more
}
// EOF

View File

@ -87,17 +87,18 @@ static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
static bool InitGraphicsDevice(int width, int height); // Initialize graphics device
static int InitPlatform(void); // Initialize platform (graphics, inputs and more)
static void ClosePlatform(void); // Close platform
// Error callback event
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
// Window callbacks events
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
static void WindowMaximizeCallback(GLFWwindow *window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
static void WindowMaximizeCallback(GLFWwindow *window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window
// Input callbacks events
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
@ -107,11 +108,12 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y);
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel
static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
// Emscripten callback events
// Emscripten window callback events
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
// Emscripten input callback events
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
@ -160,33 +162,32 @@ void InitWindow(int width, int height, const char *title)
TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
#endif
// NOTE: Keep internal pointer to input title string (no copy)
// Initialize window data
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
CORE.Window.eventWaiting = false;
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
// Initialize global input state
memset(&CORE.Input, 0, sizeof(CORE.Input));
memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
CORE.Input.Mouse.scale = (Vector2){1.0f, 1.0f};
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
CORE.Window.eventWaiting = false;
CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
// Initialize graphics device (display device and OpenGL context)
// NOTE: returns true if window and graphic device has been initialized successfully
CORE.Window.ready = InitGraphicsDevice(width, height);
// Initialize platform
//--------------------------------------------------------------
InitPlatform();
//--------------------------------------------------------------
// If graphic device is no properly initialized, we end program
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return; }
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Initialize hi-res timer
InitTimer();
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
// Initialize base path for storage
CORE.Storage.basePath = GetWorkingDirectory();
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
// Load default font
@ -230,37 +231,8 @@ void InitWindow(int width, int height, const char *title)
CORE.Time.frameCounter = 0;
#endif
// Platform specific init window
//--------------------------------------------------------------
// Setup callback functions for the DOM events
emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
// Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
// emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
// Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
// Trigger this once to get initial window sizing
EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
// Support keyboard events -> Not used, GLFW.JS takes care of that
// emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
// emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
// Support mouse events
emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback);
// Support touch events
emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
// Support gamepad events (not provided by GLFW3 on emscripten)
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
//--------------------------------------------------------------
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
TRACELOG(LOG_INFO, "PLATFORM: WEB: Application initialized successfully");
}
@ -283,10 +255,9 @@ void CloseWindow(void)
rlglClose(); // De-init rlgl
// Platform specific close window
// De-initialize platform
//--------------------------------------------------------------
glfwDestroyWindow(platform.handle);
glfwTerminate();
ClosePlatform();
//--------------------------------------------------------------
#if defined(SUPPORT_EVENTS_AUTOMATION)
@ -309,36 +280,6 @@ bool WindowShouldClose(void)
return false;
}
// Check if window is currently hidden
bool IsWindowHidden(void)
{
return false;
}
// Check if window has been minimized
bool IsWindowMinimized(void)
{
return false;
}
// Check if window has been maximized
bool IsWindowMaximized(void)
{
return false;
}
// Check if window has the focus
bool IsWindowFocused(void)
{
return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0);
}
// Check if window has been resizedLastFrame
bool IsWindowResized(void)
{
return CORE.Window.resizedLastFrame;
}
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
@ -410,6 +351,12 @@ void ToggleFullscreen(void)
CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
}
// Set window state: maximized, if resizable
void MaximizeWindow(void)
{
@ -428,12 +375,6 @@ void RestoreWindow(void)
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
}
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
@ -697,18 +638,6 @@ void OpenURL(const char *url)
// Module Functions Definition: Inputs
//----------------------------------------------------------------------------------
// Get gamepad internal name id
const char *GetGamepadName(int gamepad)
{
return CORE.Input.Gamepad.name[gamepad];
}
// Get gamepad axis count
int GetGamepadAxisCount(int gamepad)
{
return CORE.Input.Gamepad.axisCount;
}
// Set internal gamepad mappings
int SetGamepadMappings(const char *mappings)
{
@ -717,30 +646,6 @@ int SetGamepadMappings(const char *mappings)
return 0;
}
// Get mouse position X
int GetMouseX(void)
{
return (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x);
}
// Get mouse position Y
int GetMouseY(void)
{
return (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y);
}
// Get mouse position XY
Vector2 GetMousePosition(void)
{
Vector2 position = { 0 };
// NOTE: On canvas scaling, mouse position is proportionally returned
position.x = (CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x;
position.y = (CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y;
return position;
}
// Set mouse position XY
void SetMousePosition(int x, int y)
{
@ -751,45 +656,37 @@ void SetMousePosition(int x, int y)
glfwSetCursorPos(platform.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y);
}
// Get mouse wheel movement Y
float GetMouseWheelMove(void)
{
float result = 0.0f;
if (fabsf(CORE.Input.Mouse.currentWheelMove.x) > fabsf(CORE.Input.Mouse.currentWheelMove.y)) result = (float)CORE.Input.Mouse.currentWheelMove.x;
else result = (float)CORE.Input.Mouse.currentWheelMove.y;
return result;
}
// Set mouse cursor
void SetMouseCursor(int cursor)
{
TRACELOG(LOG_INFO, "SetMouseCursor not implemented in rcore_web.c");
}
const char *cursorName;
switch (cursor)
{
case MOUSE_CURSOR_IBEAM: cursorName = "text"; break;
case MOUSE_CURSOR_CROSSHAIR: cursorName = "crosshair"; break;
case MOUSE_CURSOR_POINTING_HAND: cursorName = "pointer"; break;
case MOUSE_CURSOR_RESIZE_EW: cursorName = "ew-resize"; break;
case MOUSE_CURSOR_RESIZE_NS: cursorName = "ns-resize"; break;
case MOUSE_CURSOR_RESIZE_NWSE: cursorName = "nwse-resize"; break;
case MOUSE_CURSOR_RESIZE_NESW: cursorName = "nesw-resize"; break;
case MOUSE_CURSOR_RESIZE_ALL: cursorName = "move"; break;
case MOUSE_CURSOR_NOT_ALLOWED: cursorName = "not-allowed"; break;
// Get touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
return (int)CORE.Input.Touch.position[0].x;
}
case MOUSE_CURSOR_ARROW: // can't find a name specifically for arrow cursor
case MOUSE_CURSOR_DEFAULT:
{
cursorName = "default";
} break;
// Get touch position Y for touch point 0 (relative to screen size)
int GetTouchY(void)
{
return (int)CORE.Input.Touch.position[0].y;
}
default:
{
TRACELOG(LOG_WARNING, "Cursor value out of bound (%d). Setting to default", cursor);
cursorName = "default";
} break;
}
// Get touch position XY for a touch point index (relative to screen size)
// TODO: Touch position should be scaled depending on display size and render size
Vector2 GetTouchPosition(int index)
{
Vector2 position = { -1.0f, -1.0f };
if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index];
else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS);
return position;
// Set the cursor element on the CSS
EM_ASM({document.body.style.cursor = UTF8ToString($0);}, cursorName);
}
// Register all input events
@ -913,43 +810,14 @@ void PollInputEvents(void)
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Initialize display device and framebuffer
// NOTE: width and height represent the screen (framebuffer) desired size, not actual display size
// If width or height are 0, default display size will be used for framebuffer size
// NOTE: returns false in case graphic device could not be created
static bool InitGraphicsDevice(int width, int height)
// Initialize platform: graphics, inputs and more
static int InitPlatform(void)
{
CORE.Window.screen.width = width; // User desired width
CORE.Window.screen.height = height; // User desired height
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
// Set the screen minimum and maximum default values to 0
CORE.Window.screenMin.width = 0;
CORE.Window.screenMin.height = 0;
CORE.Window.screenMax.width = 0;
CORE.Window.screenMax.height = 0;
// NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars...
// ...in top-down or left-right to match display aspect ratio (no weird scaling)
glfwSetErrorCallback(ErrorCallback);
/*
// TODO: Setup GLFW custom allocators to match raylib ones
const GLFWallocator allocator = {
.allocate = MemAlloc,
.deallocate = MemFree,
.reallocate = MemRealloc,
.user = NULL
};
glfwInitAllocator(&allocator);
*/
if (!glfwInit())
{
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize GLFW");
return false;
}
// Initialize GLFW internal global state
int result = glfwInit();
if (result == GLFW_FALSE) { TRACELOG(LOG_WARNING, "GLFW: Failed to initialize GLFW"); return -1; }
glfwDefaultWindowHints(); // Set default windows hints
// glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits
@ -1115,7 +983,7 @@ static bool InitGraphicsDevice(int width, int height)
{
glfwTerminate();
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
return false;
return -1;
}
// WARNING: glfwCreateWindow() title doesn't work with emscripten
@ -1137,6 +1005,12 @@ static bool InitGraphicsDevice(int width, int height)
glfwMakeContextCurrent(platform.handle);
// Load OpenGL extensions
// NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(glfwGetProcAddress);
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
// NOTE: V-Sync can be enabled by graphic driver configuration, it doesn't need
// to be activated on web platforms since VSync is enforced there.
@ -1155,21 +1029,55 @@ static bool InitGraphicsDevice(int width, int height)
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
// Load OpenGL extensions
// NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(glfwGetProcAddress);
CORE.Window.ready = true; // TODO: Proper validation on windows/context creation
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// If graphic device is no properly initialized, we end program
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
// Initialize hi-res timer
InitTimer();
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
// Initialize base path for storage
CORE.Storage.basePath = GetWorkingDirectory();
return true;
// Setup callback functions for the DOM events
emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
// Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
// emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
// Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
// Trigger this once to get initial window sizing
EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
// Support keyboard events -> Not used, GLFW.JS takes care of that
// emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
// emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
// Support mouse events
emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback);
// Support touch events
emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenTouchCallback);
// Support gamepad events (not provided by GLFW3 on emscripten)
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
return 0;
}
// Close platform
static void ClosePlatform(void)
{
glfwDestroyWindow(platform.handle);
glfwTerminate();
}
// GLFW3 Error Callback, runs on GLFW3 error
@ -1218,7 +1126,7 @@ static void WindowIconifyCallback(GLFWwindow *window, int iconified)
// GLFW3 Window Maximize Callback, runs when window is maximized
static void WindowMaximizeCallback(GLFWwindow *window, int maximized)
{
// TODO.
}
// GLFW3 WindowFocus Callback, runs when window get/lose focus
@ -1256,7 +1164,6 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
}
}
// GLFW3 Keyboard Callback, runs on key pressed
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
@ -1435,11 +1342,10 @@ static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffs
// GLFW3 CursorEnter Callback, when cursor enters the window
static void CursorEnterCallback(GLFWwindow *window, int enter)
{
if (enter == true) CORE.Input.Mouse.cursorOnScreen = true;
if (enter) CORE.Input.Mouse.cursorOnScreen = true;
else CORE.Input.Mouse.cursorOnScreen = false;
}
// Register fullscreen change events
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
{

View File

@ -1371,15 +1371,24 @@ const char *TextFormat(const char *text, ...)
va_list args;
va_start(args, text);
vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
va_end(args);
// If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occured
if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH)
{
// Inserting "..." at the end of the string to mark as truncated
char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0"
sprintf(truncBuffer, "...");
}
index += 1; // Move to next buffer for next function call
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
return currentBuffer;
}
// Get integer value from text
// NOTE: This function replaces atoi() [stdlib.h]
int TextToInteger(const char *text)

View File

@ -213,7 +213,7 @@
#define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size))
#define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr))
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() [ImageResize()]
#include "external/stb_image_resize2.h" // Required for: stbir_resize_uint8_linear() [ImageResize()]
#if defined(SUPPORT_FILEFORMAT_SVG)
#define NANOSVG_IMPLEMENTATION // Expands implementation
@ -1624,10 +1624,10 @@ void ImageResize(Image *image, int newWidth, int newHeight)
switch (image->format)
{
case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 1); break;
case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 2); break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 3); break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, 4); break;
case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)1); break;
case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)2); break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)3); break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)4); break;
default: break;
}
@ -1643,7 +1643,7 @@ void ImageResize(Image *image, int newWidth, int newHeight)
Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
// NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem...
stbir_resize_uint8((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, 4);
stbir_resize_uint8_linear((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, (stbir_pixel_layout)4);
int format = image->format;