Merge branch 'raysan5:master' into master

This commit is contained in:
fmixolydian 2026-02-09 22:33:28 +01:00 committed by GitHub
commit 619ee0b557
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 57 additions and 62 deletions

View File

@ -148,6 +148,7 @@ int main(void)
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
UnloadRenderTexture(observerTarget); UnloadRenderTexture(observerTarget);
UnloadRenderTexture(subjectTarget); UnloadRenderTexture(subjectTarget);
CloseWindow(); // Close window and OpenGL context CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

View File

@ -4,7 +4,7 @@
#ifndef WIN32_CLIPBOARD_ #ifndef WIN32_CLIPBOARD_
#define WIN32_CLIPBOARD_ #define WIN32_CLIPBOARD_
unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize); unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long long int *dataSize);
#endif // WIN32_CLIPBOARD_ #endif // WIN32_CLIPBOARD_
#ifdef WIN32_CLIPBOARD_IMPLEMENTATION #ifdef WIN32_CLIPBOARD_IMPLEMENTATION
@ -92,7 +92,6 @@ unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long
typedef int WINBOOL; typedef int WINBOOL;
#if !defined(_WINUSER_) || !defined(WINUSER_ALREADY_INCLUDED) #if !defined(_WINUSER_) || !defined(WINUSER_ALREADY_INCLUDED)
WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner);
WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID);
@ -170,8 +169,7 @@ typedef struct tagRGBQUAD {
} RGBQUAD, *LPRGBQUAD; } RGBQUAD, *LPRGBQUAD;
#endif #endif
// REF: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57
#define BI_RGB 0x0000 #define BI_RGB 0x0000
#define BI_RLE8 0x0001 #define BI_RLE8 0x0001
#define BI_RLE4 0x0002 #define BI_RLE4 0x0002
@ -184,10 +182,10 @@ typedef struct tagRGBQUAD {
#endif #endif
// https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats // REF: https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats
#define CF_DIB 8 #define CF_DIB 8
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setsystemcursor // REF: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setsystemcursor
// #define OCR_NORMAL 32512 // Normal select // #define OCR_NORMAL 32512 // Normal select
// #define OCR_IBEAM 32513 // Text select // #define OCR_IBEAM 32513 // Text select
// #define OCR_WAIT 32514 // Busy // #define OCR_WAIT 32514 // Busy
@ -202,36 +200,37 @@ typedef struct tagRGBQUAD {
// #define OCR_HAND 32649 // Link select // #define OCR_HAND 32649 // Link select
// #define OCR_APPSTARTING 32650 // // #define OCR_APPSTARTING 32650 //
static BOOL OpenClipboardRetrying(HWND handle); // Open clipboard with a number of retries
static int GetPixelDataOffset(BITMAPINFOHEADER bih);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Internal Functions Declaration // Module Internal Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long long int *dataSize)
static BOOL OpenClipboardRetrying(HWND handle); // Open clipboard with a number of retries
static int GetPixelDataOffset(BITMAPINFOHEADER bih);
unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize)
{ {
HWND win = NULL; // Get from somewhere but is doesnt seem to matter HWND win = NULL; // Get from somewhere but is doesnt seem to matter
const char* msgString = ""; const char *msgString = "";
int severity = LOG_INFO; int severity = LOG_INFO;
BYTE* bmpData = NULL; BYTE *bmpData = NULL;
if (!OpenClipboardRetrying(win)) {
if (!OpenClipboardRetrying(win))
{
severity = LOG_ERROR; severity = LOG_ERROR;
msgString = "Couldn't open clipboard"; msgString = "Couldn't open clipboard";
goto end; goto end;
} }
HGLOBAL clipHandle = (HGLOBAL)GetClipboardData(CF_DIB); HGLOBAL clipHandle = (HGLOBAL)GetClipboardData(CF_DIB);
if (!clipHandle) { if (!clipHandle)
{
severity = LOG_ERROR; severity = LOG_ERROR;
msgString = "Clipboard data is not an Image"; msgString = "Clipboard data is not an Image";
goto close; goto close;
} }
BITMAPINFOHEADER *bmpInfoHeader = (BITMAPINFOHEADER *)GlobalLock(clipHandle); BITMAPINFOHEADER *bmpInfoHeader = (BITMAPINFOHEADER *)GlobalLock(clipHandle);
if (!bmpInfoHeader) { if (!bmpInfoHeader)
{
// Mapping from HGLOBAL to our local *address space* failed // Mapping from HGLOBAL to our local *address space* failed
severity = LOG_ERROR; severity = LOG_ERROR;
msgString = "Clipboard data failed to be locked"; msgString = "Clipboard data failed to be locked";
@ -242,7 +241,8 @@ unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long
*height = bmpInfoHeader->biHeight; *height = bmpInfoHeader->biHeight;
SIZE_T clipDataSize = GlobalSize(clipHandle); SIZE_T clipDataSize = GlobalSize(clipHandle);
if (clipDataSize < sizeof(BITMAPINFOHEADER)) { if (clipDataSize < sizeof(BITMAPINFOHEADER))
{
// Format CF_DIB needs space for BITMAPINFOHEADER struct. // Format CF_DIB needs space for BITMAPINFOHEADER struct.
msgString = "Clipboard has Malformed data"; msgString = "Clipboard has Malformed data";
severity = LOG_ERROR; severity = LOG_ERROR;
@ -259,30 +259,28 @@ unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long
// //
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
BITMAPFILEHEADER bmpFileHeader = {0}; BITMAPFILEHEADER bmpFileHeader = { 0 };
SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize; SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize;
*dataSize = bmpFileSize; *dataSize = bmpFileSize;
bmpFileHeader.bfType = 0x4D42; //https://stackoverflow.com/questions/601430/multibyte-character-constants-and-bitmap-file-header-type-constants#601536 bmpFileHeader.bfType = 0x4D42; // REF: https://stackoverflow.com/questions/601430/multibyte-character-constants-and-bitmap-file-header-type-constants#601536
bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine
bmpFileHeader.bfOffBits = sizeof(bmpFileHeader) + pixelOffset; bmpFileHeader.bfOffBits = sizeof(bmpFileHeader) + pixelOffset;
// // WARNING: Each process has a default heap provided by the system
// Each process has a default heap provided by the system
// Memory objects allocated by GlobalAlloc and LocalAlloc are in private, // Memory objects allocated by GlobalAlloc and LocalAlloc are in private,
// committed pages with read/write access that cannot be accessed by other processes. // committed pages with read/write access that cannot be accessed by other processes
// //
// This may be wrong since we might be allocating in a DLL and freeing from another module, the main application // This may be wrong since we might be allocating in a DLL and freeing from another module, the main application
// that may cause heap corruption. We could create a FreeImage function // that may cause heap corruption. We could create a FreeImage function
// bmpData = (BYTE *)RL_MALLOC(sizeof(bmpFileHeader) + clipDataSize);
bmpData = (BYTE *)malloc(sizeof(bmpFileHeader) + clipDataSize);
// First we add the header for a bmp file // First we add the header for a bmp file
memcpy(bmpData, &bmpFileHeader, sizeof(bmpFileHeader)); memcpy(bmpData, &bmpFileHeader, sizeof(bmpFileHeader)); // Add BMP file header data
// Then we add the header for the bmp itself + the pixel data // Then we add the header for the bmp itself + the pixel data
memcpy(bmpData + sizeof(bmpFileHeader), bmpInfoHeader, clipDataSize); memcpy(bmpData + sizeof(bmpFileHeader), bmpInfoHeader, clipDataSize); // Add BMP info header data
msgString = "Clipboad image acquired successfully";
msgString = "Clipboad image acquired successfully";
unlock: unlock:
GlobalUnlock(clipHandle); GlobalUnlock(clipHandle);
@ -291,6 +289,7 @@ close:
end: end:
TRACELOG(severity, msgString); TRACELOG(severity, msgString);
return bmpData; return bmpData;
} }
@ -298,65 +297,57 @@ static BOOL OpenClipboardRetrying(HWND hWnd)
{ {
static const int maxTries = 20; static const int maxTries = 20;
static const int sleepTimeMS = 60; static const int sleepTimeMS = 60;
for (int _ = 0; _ < maxTries; ++_)
for (int i = 0; i < maxTries; i++)
{ {
// Might be being hold by another process // Might be being hold by another process
// Or yourself forgot to CloseClipboard // Or yourself forgot to CloseClipboard
if (OpenClipboard(hWnd)) { if (OpenClipboard(hWnd)) return true;
return true;
}
Sleep(sleepTimeMS); Sleep(sleepTimeMS);
} }
return false; return false;
} }
// Based off of researching microsoft docs and reponses from this question https://stackoverflow.com/questions/30552255/how-to-read-a-bitmap-from-the-windows-clipboard#30552856
// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
// Get the byte offset where does the pixels data start (from a packed DIB) // Get the byte offset where does the pixels data start (from a packed DIB)
// REF: https://stackoverflow.com/questions/30552255/how-to-read-a-bitmap-from-the-windows-clipboard#30552856
// REF: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
static int GetPixelDataOffset(BITMAPINFOHEADER bih) static int GetPixelDataOffset(BITMAPINFOHEADER bih)
{ {
int offset = 0; int offset = 0;
const unsigned int rgbaSize = sizeof(RGBQUAD); const unsigned int rgbaSize = sizeof(RGBQUAD);
// biSize Specifies the number of bytes required by the structure // NOTE: biSize specifies the number of bytes required by the structure
// We expect to always be 40 because it should be packed // We expect to always be 40 because it should be packed
if (40 == bih.biSize && 40 == sizeof(BITMAPINFOHEADER)) if ((40 == bih.biSize) && (40 == sizeof(BITMAPINFOHEADER)))
{ {
// // NOTE: biBitCount specifies the number of bits per pixel.
// biBitCount Specifies the number of bits per pixel.
// Might exist some bit masks *after* the header and *before* the pixel offset // Might exist some bit masks *after* the header and *before* the pixel offset
// we're looking, but only if we have more than // we're looking, but only if we have more than
// 8 bits per pixel, so we need to ajust for that // 8 bits per pixel, so we need to ajust for that
//
if (bih.biBitCount > 8) if (bih.biBitCount > 8)
{ {
// if bih.biCompression is RBG we should NOT offset more // if bih.biCompression is RBG we should NOT offset more
if (bih.biCompression == BI_BITFIELDS) if (bih.biCompression == BI_BITFIELDS) offset += 3*rgbaSize;
else if (bih.biCompression == 6) // BI_ALPHABITFIELDS
{ {
offset += 3 * rgbaSize; // Not widely supported, but valid
} else if (bih.biCompression == 6 /* BI_ALPHABITFIELDS */) offset += 4*rgbaSize;
{
// Not widely supported, but valid.
offset += 4 * rgbaSize;
} }
} }
} }
// // NOTE: biClrUsed specifies the number of color indices in the color table that are actually used by the bitmap
// biClrUsed Specifies the number of color indices in the color table that are actually used by the bitmap.
// If this value is zero, the bitmap uses the maximum number of colors // If this value is zero, the bitmap uses the maximum number of colors
// corresponding to the value of the biBitCount member for the compression mode specified by biCompression. // corresponding to the value of the biBitCount member for the compression mode specified by biCompression
// If biClrUsed is nonzero and the biBitCount member is less than 16 // If biClrUsed is nonzero and the biBitCount member is less than 16
// the biClrUsed member specifies the actual number of colors // the biClrUsed member specifies the actual number of colors
// if (bih.biClrUsed > 0) offset += bih.biClrUsed*rgbaSize;
if (bih.biClrUsed > 0) { else
offset += bih.biClrUsed * rgbaSize; {
} else { if (bih.biBitCount < 16) offset = offset + (rgbaSize << bih.biBitCount);
if (bih.biBitCount < 16)
{
offset = offset + (rgbaSize << bih.biBitCount);
}
} }
return bih.biSize + offset; return bih.biSize + offset;

View File

@ -1049,14 +1049,14 @@ Image GetClipboardImage(void)
#if defined(SUPPORT_CLIPBOARD_IMAGE) #if defined(SUPPORT_CLIPBOARD_IMAGE)
#if defined(_WIN32) #if defined(_WIN32)
unsigned long long int dataSize = 0; unsigned long long int dataSize = 0;
void *fileData = NULL; void *bmpData = NULL;
int width = 0; int width = 0;
int height = 0; int height = 0;
fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize); bmpData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data."); if (bmpData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, (int)dataSize); else image = LoadImageFromMemory(".bmp", (const unsigned char *)bmpData, (int)dataSize);
#else #else
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform"); TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
#endif #endif

View File

@ -1469,7 +1469,7 @@ int InitPlatform(void)
if (!eglChooseConfig(platform.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs)) if (!eglChooseConfig(platform.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs))
{ {
TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose EGL config: 0x%x", eglGetError()); TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose EGL config: 0x%x", eglGetError());
free(configs); RL_FREE(configs);
return -1; return -1;
} }

View File

@ -17,11 +17,14 @@
* - Linux (X11/Wayland desktop mode) * - Linux (X11/Wayland desktop mode)
* - macOS/OSX (x64, arm64) * - macOS/OSX (x64, arm64)
* - Others (not tested) * - Others (not tested)
* > PLATFORM_WEB_RGFW: * > PLATFORM_DESKTOP_WIN32 (native Win32):
* - Windows (Win32, Win64)
* > PLATFORM_WEB (GLFW + Emscripten): * > PLATFORM_WEB (GLFW + Emscripten):
* - HTML5 (WebAssembly) * - HTML5 (WebAssembly)
* > PLATFORM_WEB_EMSCRIPTEN (Emscripten): * > PLATFORM_WEB_EMSCRIPTEN (Emscripten):
* - HTML5 (WebAssembly) * - HTML5 (WebAssembly)
* > PLATFORM_WEB_RGFW (Emscripten):
* - HTML5 (WebAssembly)
* > PLATFORM_DRM (native DRM): * > PLATFORM_DRM (native DRM):
* - Raspberry Pi 0-5 (DRM/KMS) * - Raspberry Pi 0-5 (DRM/KMS)
* - Linux DRM subsystem (KMS mode) * - Linux DRM subsystem (KMS mode)