mirror of
https://github.com/raysan5/raylib.git
synced 2026-04-26 16:47:25 -04:00
Compare commits
7 Commits
f583674327
...
3bea7f518d
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bea7f518d | |||
| e1113c8833 | |||
| 2c5e7f8db6 | |||
| 8596c940ae | |||
| 0b9239eca2 | |||
| 70a58a6ec6 | |||
| 950c064448 |
110
examples/textures/textures_clipboard_image.c
Normal file
110
examples/textures/textures_clipboard_image.c
Normal file
@ -0,0 +1,110 @@
|
||||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [textures] example - clipboard image
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Maicon Santana (@maiconpintoabreu) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* 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) 2026 Maicon Santana (@maiconpintoabreu)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#define MAX_TEXTURE_COLLECTION 20
|
||||
|
||||
typedef struct TextureCollection {
|
||||
Texture2D texture;
|
||||
Vector2 position;
|
||||
} TextureCollection;
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [textures] example - clipboard_image");
|
||||
|
||||
TextureCollection collection[MAX_TEXTURE_COLLECTION] = { 0 };
|
||||
int currentCollectionIndex = 0;
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KEY_R)) // Reset image collection
|
||||
{
|
||||
// Unload textures to avoid memory leaks
|
||||
for (int i = 0; i < MAX_TEXTURE_COLLECTION; i++) UnloadTexture(collection[i].texture);
|
||||
|
||||
currentCollectionIndex = 0;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V) &&
|
||||
(currentCollectionIndex < MAX_TEXTURE_COLLECTION))
|
||||
{
|
||||
Image image = GetClipboardImage();
|
||||
|
||||
if (IsImageValid(image))
|
||||
{
|
||||
collection[currentCollectionIndex].texture = LoadTextureFromImage(image);
|
||||
collection[currentCollectionIndex].position = GetMousePosition();
|
||||
currentCollectionIndex++;
|
||||
UnloadImage(image);
|
||||
}
|
||||
else TraceLog(LOG_INFO, "IMAGE: Could not retrieve image from clipboard");
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
for (int i = 0; i < currentCollectionIndex; i++)
|
||||
{
|
||||
if (IsTextureValid(collection[i].texture))
|
||||
{
|
||||
DrawTexturePro(collection[i].texture,
|
||||
(Rectangle){0,0,collection[i].texture.width, collection[i].texture.height},
|
||||
(Rectangle){collection[i].position.x,collection[i].position.y,collection[i].texture.width, collection[i].texture.height},
|
||||
(Vector2){collection[i].texture.width*0.5f, collection[i].texture.height*0.5f},
|
||||
0.0f, WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
DrawRectangle(0, 0, screenWidth, 40, BLACK);
|
||||
DrawText("Clipboard Image - Ctrl+V to Paste and R to Reset ", 120, 10, 20, LIGHTGRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
for (int i = 0; i < MAX_TEXTURE_COLLECTION;i ++)
|
||||
{
|
||||
UnloadTexture(collection[i].texture);
|
||||
}
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
examples/textures/textures_clipboard_image.png
Normal file
BIN
examples/textures/textures_clipboard_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 196 KiB |
@ -75,6 +75,12 @@ if (${PLATFORM} MATCHES "Web")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (${PLATFORM} MATCHES "Android")
|
||||
# Wrap fopen at link time so all code (including third-party libs) goes
|
||||
# through __wrap_fopen, which handles Android APK asset loading
|
||||
target_link_options(raylib INTERFACE -Wl,--wrap=fopen)
|
||||
endif()
|
||||
|
||||
set_target_properties(raylib PROPERTIES
|
||||
PUBLIC_HEADER "${raylib_public_headers}"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
|
||||
@ -614,6 +614,9 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
|
||||
LDFLAGS += -Lsrc
|
||||
# Avoid unresolved symbol pointing to external main()
|
||||
LDFLAGS += -Wl,-undefined,dynamic_lookup
|
||||
# Wrap fopen at link time so all code (including third-party libs) goes
|
||||
# through __wrap_fopen, which handles Android APK asset loading
|
||||
LDFLAGS += -Wl,--wrap=fopen
|
||||
endif
|
||||
|
||||
# Define libraries required on linking: LDLIBS
|
||||
|
||||
@ -275,12 +275,12 @@ static int android_write(void *cookie, const char *buf, int size);
|
||||
static fpos_t android_seek(void *cookie, fpos_t offset, int whence);
|
||||
static int android_close(void *cookie);
|
||||
|
||||
FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only!
|
||||
FILE *__real_fopen(const char *fileName, const char *mode); // Real fopen, provided by the linker (--wrap=fopen)
|
||||
FILE *__wrap_fopen(const char *fileName, const char *mode); // Replacement for fopen()
|
||||
|
||||
FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int),
|
||||
fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *));
|
||||
|
||||
#define fopen(name, mode) android_fopen(name, mode)
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -1524,25 +1524,20 @@ static void SetupFramebuffer(int width, int height)
|
||||
}
|
||||
}
|
||||
|
||||
// Replacement for fopen()
|
||||
// Replacement for fopen(), used as linker wrap entry point (-Wl,--wrap=fopen)
|
||||
// REF: https://developer.android.com/ndk/reference/group/asset
|
||||
FILE *android_fopen(const char *fileName, const char *mode)
|
||||
FILE *__wrap_fopen(const char *fileName, const char *mode)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
|
||||
|
||||
// NOTE: AAsset provides access to read-only asset, write operations use regular fopen
|
||||
if (mode[0] == 'w')
|
||||
{
|
||||
// NOTE: fopen() is mapped to android_fopen() that only grants read access to
|
||||
// assets directory through AAssetManager but it could be required to write data
|
||||
// using the standard stdio FILE access functions
|
||||
// REF: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only
|
||||
#undef fopen
|
||||
file = fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
|
||||
#define fopen(name, mode) android_fopen(name, mode)
|
||||
file = __real_fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
|
||||
if (file == NULL) file = __real_fopen(fileName, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: AAsset provides access to read-only asset
|
||||
AAsset *asset = AAssetManager_open(platform.app->activity->assetManager, fileName, AASSET_MODE_UNKNOWN);
|
||||
|
||||
if (asset != NULL)
|
||||
@ -1552,14 +1547,12 @@ FILE *android_fopen(const char *fileName, const char *mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
#undef fopen
|
||||
// Just do a regular open if file is not found in the assets
|
||||
file = fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
|
||||
if (file == NULL) file = fopen(fileName, mode);
|
||||
#define fopen(name, mode) android_fopen(name, mode)
|
||||
file = __real_fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
|
||||
if (file == NULL) file = __real_fopen(fileName, mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
@ -1043,6 +1043,11 @@ const char *GetClipboardText(void)
|
||||
return glfwGetClipboardString(platform.handle);
|
||||
}
|
||||
|
||||
#if SUPPORT_CLIPBOARD_IMAGE && defined(__linux__) && defined(_GLFW_X11)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#endif
|
||||
|
||||
// Get clipboard image
|
||||
Image GetClipboardImage(void)
|
||||
{
|
||||
@ -1059,6 +1064,53 @@ Image GetClipboardImage(void)
|
||||
|
||||
if (bmpData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
|
||||
else image = LoadImageFromMemory(".bmp", (const unsigned char *)bmpData, (int)dataSize);
|
||||
|
||||
#elif defined(__linux__) && defined(_GLFW_X11)
|
||||
|
||||
// REF: https://github.com/ColleagueRiley/Clipboard-Copy-Paste/blob/main/x11.c
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
if (!dpy) return image;
|
||||
|
||||
Window root = DefaultRootWindow(dpy);
|
||||
Window win = XCreateSimpleWindow(
|
||||
dpy, // The connection to the X Server
|
||||
root, // The 'Parent' window (usually the desktop/root)
|
||||
0, 0, // X and Y position on the screen
|
||||
1, 1, // Width and Height (1x1 pixel)
|
||||
0, // Border width
|
||||
0, // Border color
|
||||
0 // Background color
|
||||
);
|
||||
|
||||
Atom clipboard = XInternAtom(dpy, "CLIPBOARD", False);
|
||||
Atom targetType = XInternAtom(dpy, "image/png", False); // Ask for PNG
|
||||
Atom property = XInternAtom(dpy, "RAYLIB_CLIPBOARD_MANAGER", False);
|
||||
|
||||
// Request the data: "Convert whatever is in CLIPBOARD to image/png and put it in RAYLIB_CLIPBOARD_MANAGER"
|
||||
XConvertSelection(dpy, clipboard, targetType, property, win, CurrentTime);
|
||||
|
||||
// Wait for the SelectionNotify event
|
||||
XEvent ev = { 0 };
|
||||
XNextEvent(dpy, &ev);
|
||||
|
||||
Atom actualType = { 0 };
|
||||
int actualFormat = 0;
|
||||
unsigned long nitems = 0;
|
||||
unsigned long bytesAfter = 0;
|
||||
unsigned char *data = NULL;
|
||||
|
||||
// Read the data from our ghost window's property
|
||||
XGetWindowProperty(dpy, win, property, 0, ~0L, False, AnyPropertyType,
|
||||
&actualType, &actualFormat, &nitems, &bytesAfter, &data);
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
image = LoadImageFromMemory(".png", data, (int)nitems);
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
XDestroyWindow(dpy, win);
|
||||
XCloseDisplay(dpy);
|
||||
#else
|
||||
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
@ -999,6 +999,9 @@ const char *GetClipboardText(void)
|
||||
#define WINBASE_ALREADY_INCLUDED
|
||||
#define WINGDI_ALREADY_INCLUDED
|
||||
#include "../external/win32_clipboard.h"
|
||||
#elif defined(__linux__) && defined(DRGFW_X11)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -1006,6 +1009,7 @@ const char *GetClipboardText(void)
|
||||
Image GetClipboardImage(void)
|
||||
{
|
||||
Image image = { 0 };
|
||||
|
||||
#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
|
||||
#if defined(_WIN32)
|
||||
|
||||
@ -1018,6 +1022,53 @@ Image GetClipboardImage(void)
|
||||
|
||||
if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data");
|
||||
else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, dataSize);
|
||||
|
||||
#elif defined(__linux__) && defined(DRGFW_X11)
|
||||
|
||||
// REF: https://github.com/ColleagueRiley/Clipboard-Copy-Paste/blob/main/x11.c
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
if (!dpy) return image;
|
||||
|
||||
Window root = DefaultRootWindow(dpy);
|
||||
Window win = XCreateSimpleWindow(
|
||||
dpy, // The connection to the X Server
|
||||
root, // The 'Parent' window (usually the desktop/root)
|
||||
0, 0, // X and Y position on the screen
|
||||
1, 1, // Width and Height (1x1 pixel)
|
||||
0, // Border width
|
||||
0, // Border color
|
||||
0 // Background color
|
||||
);
|
||||
|
||||
Atom clipboard = XInternAtom(dpy, "CLIPBOARD", False);
|
||||
Atom targetType = XInternAtom(dpy, "image/png", False); // Ask for PNG
|
||||
Atom property = XInternAtom(dpy, "RAYLIB_CLIPBOARD_MANAGER", False);
|
||||
|
||||
// Request the data: "Convert whatever is in CLIPBOARD to image/png and put it in RAYLIB_CLIPBOARD_MANAGER"
|
||||
XConvertSelection(dpy, clipboard, targetType, property, win, CurrentTime);
|
||||
|
||||
// Wait for the SelectionNotify event
|
||||
XEvent ev = { 0 };
|
||||
XNextEvent(dpy, &ev);
|
||||
|
||||
Atom actualType = { 0 };
|
||||
int actualFormat = 0;
|
||||
unsigned long nitems = 0;
|
||||
unsigned long bytesAfter = 0;
|
||||
unsigned char *data = NULL;
|
||||
|
||||
// Read the data from our ghost window's property
|
||||
XGetWindowProperty(dpy, win, property, 0, ~0L, False, AnyPropertyType,
|
||||
&actualType, &actualFormat, &nitems, &bytesAfter, &data);
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
image = LoadImageFromMemory(".png", data, (int)nitems);
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
XDestroyWindow(dpy, win);
|
||||
XCloseDisplay(dpy);
|
||||
#else
|
||||
TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_RGFW doesn't implement GetClipboardImage() for this OS");
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
@ -180,11 +180,6 @@ typedef struct tagBITMAPINFOHEADER {
|
||||
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fread()
|
||||
#include <string.h> // Required for: strcmp() [Used in IsFileExtension(), LoadWaveFromMemory(), LoadMusicStreamFromMemory()]
|
||||
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
FILE *android_fopen(const char *fileName, const char *mode);
|
||||
#define fopen(name, mode) android_fopen(name, mode)
|
||||
#endif
|
||||
|
||||
#if defined(RAUDIO_STANDALONE)
|
||||
#ifndef TRACELOG
|
||||
#define TRACELOG(level, ...) printf(__VA_ARGS__)
|
||||
|
||||
@ -1765,6 +1765,18 @@ RMAPI Matrix MatrixMultiply(Matrix left, Matrix right)
|
||||
return result;
|
||||
}
|
||||
|
||||
RMAPI Matrix MatrixMultiplyValue(Matrix left, float value)
|
||||
{
|
||||
Matrix result = {
|
||||
left.m0 * value, left.m4 * value, left.m8 * value, left.m12 * value,
|
||||
left.m1 * value, left.m5 * value, left.m9 * value, left.m13 * value,
|
||||
left.m2 * value, left.m6 * value, left.m10 * value, left.m14 * value,
|
||||
left.m3 * value, left.m7 * value, left.m11 * value, left.m15 * value
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get translation matrix
|
||||
RMAPI Matrix MatrixTranslate(float x, float y, float z)
|
||||
{
|
||||
@ -3079,6 +3091,11 @@ inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs)
|
||||
}
|
||||
|
||||
// Matrix operators
|
||||
static constexpr Matrix MatrixUnit = { 1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1 };
|
||||
|
||||
inline Matrix operator + (const Matrix& lhs, const Matrix& rhs)
|
||||
{
|
||||
return MatrixAdd(lhs, rhs);
|
||||
@ -3111,6 +3128,18 @@ inline const Matrix& operator *= (Matrix& lhs, const Matrix& rhs)
|
||||
lhs = MatrixMultiply(lhs, rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline Matrix operator * (const Matrix& lhs, const float value)
|
||||
{
|
||||
return MatrixMultiplyValue(lhs, value);
|
||||
}
|
||||
|
||||
inline const Matrix& operator *= (Matrix& lhs, const float value)
|
||||
{
|
||||
lhs = MatrixMultiplyValue(lhs, value);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
#endif // C++ operators
|
||||
|
||||
|
||||
@ -179,7 +179,7 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
|
||||
|
||||
<span id='controls'>
|
||||
<span><input type="button" value="📜 SOURCE CODE" onclick="location.href='https://github.com/raysan5/raylib';"/></span>
|
||||
<span><input type="button" value="🖵 FULLSCREEN" onclick="Module.canvas.requestFullscreen(false, false)"></span>
|
||||
<span><input type="button" value="🖵 FULLSCREEN" onclick="Module.canvas.requestFullscreen()"></span>
|
||||
<span><input type="button" id="btn-audio" value="🔇 MUTE" onclick="toggleAudio()"></span>
|
||||
</span>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user