Skip to content

Commit 1d85071

Browse files
committed
2 parents b474646 + 70a1a57 commit 1d85071

File tree

6 files changed

+168
-46
lines changed

6 files changed

+168
-46
lines changed

ROADMAP.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ _Current version of raylib is complete and functional but there is always room f
1616
**raylib 5.x**
1717
- [ ] `rcore`: Support additional platforms: iOS, consoles?
1818
- [x] `rcore_web`: Avoid GLFW dependency, functionality can be directly implemented using emscripten SDK
19-
- [ ] `rlgl`: Review GLSL shaders naming conventions for consistency
19+
- [x] `rlgl`: Review GLSL shaders naming conventions for consistency
2020
- [ ] `textures`: Improve compressed textures support, loading and saving
21-
- [ ] `rmodels`: Improve 3d objects loading, specially animations (obj, gltf)
22-
- [ ] `raudio`: Implement miniaudio high-level provided features
21+
- [x] `rmodels`: Improve 3d objects loading, specially animations (obj, gltf)
2322
- [x] `examples`: Review all examples, add more and better code explanations
2423
- [x] Software renderer backend? Maybe using `Image` provided API
2524

cmake/LibraryConfigurations.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ elseif ("${PLATFORM}" MATCHES "SDL")
143143
message(STATUS "Found SDL2 via find_package()")
144144
set(PLATFORM_CPP "PLATFORM_DESKTOP_SDL")
145145
set(LIBS_PUBLIC SDL2::SDL2)
146-
set(RAYLIB_DEPENDENCIES "${RAYLIB_DEPENDENCIES}\nfind_dependency(SDL3 REQUIRED)")
146+
set(RAYLIB_DEPENDENCIES "${RAYLIB_DEPENDENCIES}\nfind_dependency(SDL2 REQUIRED)")
147147
add_compile_definitions(USING_SDL2_PACKAGE)
148148
endif()
149149
endif()

examples/others/raylib_opengl_interop.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030

3131
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_DESKTOP_SDL)
3232
#if defined(GRAPHICS_API_OPENGL_ES2)
33-
#define GLAD_GLES2_IMPLEMENTATION
3433
#include "glad_gles2.h" // Required for: OpenGL functionality
3534
#define glGenVertexArrays glGenVertexArraysOES
3635
#define glBindVertexArray glBindVertexArrayOES

src/platforms/rcore_web.c

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -801,35 +801,98 @@ void SetClipboardText(const char *text)
801801
else EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
802802
}
803803

804+
// Async EM_JS to be able to await clickboard read asynchronous function
805+
EM_ASYNC_JS(void, RequestClipboardData, (void), {
806+
if (navigator.clipboard && window.isSecureContext) {
807+
let items = await navigator.clipboard.read();
808+
for (const item of items) {
809+
810+
// Check if this item contains plain text or image
811+
if (item.types.includes("text/plain")) {
812+
const blob = await item.getType("text/plain");
813+
const text = await blob.text();
814+
window._lastClipboardString = text;
815+
}
816+
else if (item.types.find(t => t.startsWith("image/"))) {
817+
const blob = await item.getType(item.types.find(t => t.startsWith("image/")));
818+
const bitmap = await createImageBitmap(blob);
819+
820+
const canvas = document.createElement('canvas');
821+
canvas.width = bitmap.width;
822+
canvas.height = bitmap.height;
823+
const ctx = canvas.getContext('2d');
824+
ctx.drawImage(bitmap, 0, 0);
825+
826+
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
827+
828+
// Store image and data for the Fetch function
829+
window._lastImgWidth = canvas.width;
830+
window._lastImgHeight = canvas.height;
831+
window._lastImgData = imgData;
832+
}
833+
}
834+
} else {
835+
console.warn("Clipboard read() requires HTTPS/Localhost");
836+
}
837+
});
838+
839+
// Returns the string created by RequestClipboardData from JS memory to Emscripten C memory
840+
EM_JS(char*, GetLastPastedText, (void), {
841+
var str = window._lastClipboardString || "";
842+
var length = lengthBytesUTF8(str) + 1;
843+
if (length > 1) {
844+
var ptr = _malloc(length);
845+
stringToUTF8(str, ptr, length);
846+
return ptr;
847+
}
848+
return 0;
849+
});
850+
851+
// Returns the image created by RequestClipboardData from JS memory to Emscripten C memory
852+
EM_JS(unsigned char*, GetLastPastedImage, (int* width, int* height), {
853+
if (window._lastImgData) {
854+
const data = window._lastImgData;
855+
if (data.length > 0) {
856+
const ptr = _malloc(data.length);
857+
HEAPU8.set(data, ptr);
858+
859+
// Set the width and height via the pointers passed from C
860+
// HEAP32 handles the 4-byte integers
861+
if (width) setValue(width, window._lastImgWidth, 'i32');
862+
if (height) setValue(height, window._lastImgHeight, 'i32');
863+
864+
// Clear the JS buffer so we don't fetch the same image twice
865+
window._lastImgData = null;
866+
867+
return ptr;
868+
}
869+
}
870+
return 0;
871+
});
872+
804873
// Get clipboard text content
805874
// NOTE: returned string is allocated and freed by GLFW
806875
const char *GetClipboardText(void)
807876
{
808-
/*
809-
// Accessing clipboard data from browser is tricky due to security reasons
810-
// The method to use is navigator.clipboard.readText() but this is an asynchronous method
811-
// that will return at some moment after the function is called with the required data
812-
emscripten_run_script_string("navigator.clipboard.readText() \
813-
.then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \
814-
.catch(err => { console.error('Failed to read clipboard contents: ', err); });"
815-
);
816-
817-
// The main issue is getting that data, one approach could be using ASYNCIFY and wait
818-
// for the data but it requires adding Asyncify emscripten library on compilation
819-
820-
// Another approach could be just copy the data in a HTML text field and try to retrieve it
821-
// later on if available... and clean it for future accesses
822-
*/
823-
return NULL;
877+
RequestClipboardData();
878+
return GetLastPastedText();
824879
}
825880

826881
// Get clipboard image
827882
Image GetClipboardImage(void)
828883
{
829884
Image image = { 0 };
830-
831-
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
832-
885+
int w = 0, h = 0;
886+
RequestClipboardData();
887+
unsigned char* data = GetLastPastedImage(&w, &h);
888+
if (data != NULL) {
889+
image.data = data;
890+
image.width = w;
891+
image.height = h;
892+
image.mipmaps = 1;
893+
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
894+
}
895+
833896
return image;
834897
}
835898

src/platforms/rcore_web_emscripten.c

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -779,37 +779,98 @@ void SetClipboardText(const char *text)
779779
else EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
780780
}
781781

782+
// Async EM_JS to be able to await clickboard read asynchronous function
783+
EM_ASYNC_JS(void, RequestClipboardData, (void), {
784+
if (navigator.clipboard && window.isSecureContext) {
785+
let items = await navigator.clipboard.read();
786+
for (const item of items) {
787+
788+
// Check if this item contains plain text or image
789+
if (item.types.includes("text/plain")) {
790+
const blob = await item.getType("text/plain");
791+
const text = await blob.text();
792+
window._lastClipboardString = text;
793+
}
794+
else if (item.types.find(t => t.startsWith("image/"))) {
795+
const blob = await item.getType(item.types.find(t => t.startsWith("image/")));
796+
const bitmap = await createImageBitmap(blob);
797+
798+
const canvas = document.createElement('canvas');
799+
canvas.width = bitmap.width;
800+
canvas.height = bitmap.height;
801+
const ctx = canvas.getContext('2d');
802+
ctx.drawImage(bitmap, 0, 0);
803+
804+
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
805+
806+
// Store image and data for the Fetch function
807+
window._lastImgWidth = canvas.width;
808+
window._lastImgHeight = canvas.height;
809+
window._lastImgData = imgData;
810+
}
811+
}
812+
} else {
813+
console.warn("Clipboard read() requires HTTPS/Localhost");
814+
}
815+
});
816+
817+
// Returns the string created by RequestClipboardData from JS memory to Emscripten C memory
818+
EM_JS(char*, GetLastPastedText, (void), {
819+
var str = window._lastClipboardString || "";
820+
var length = lengthBytesUTF8(str) + 1;
821+
if (length > 1) {
822+
var ptr = _malloc(length);
823+
stringToUTF8(str, ptr, length);
824+
return ptr;
825+
}
826+
return 0;
827+
});
828+
829+
// Returns the image created by RequestClipboardData from JS memory to Emscripten C memory
830+
EM_JS(unsigned char*, GetLastPastedImage, (int* width, int* height), {
831+
if (window._lastImgData) {
832+
const data = window._lastImgData;
833+
if (data.length > 0) {
834+
const ptr = _malloc(data.length);
835+
HEAPU8.set(data, ptr);
836+
837+
// Set the width and height via the pointers passed from C
838+
// HEAP32 handles the 4-byte integers
839+
if (width) setValue(width, window._lastImgWidth, 'i32');
840+
if (height) setValue(height, window._lastImgHeight, 'i32');
841+
842+
// Clear the JS buffer so we don't fetch the same image twice
843+
window._lastImgData = null;
844+
845+
return ptr;
846+
}
847+
}
848+
return 0;
849+
});
850+
782851
// Get clipboard text content
783852
// NOTE: returned string is allocated and freed by GLFW
784853
const char *GetClipboardText(void)
785854
{
786-
/*
787-
// Accessing clipboard data from browser is tricky due to security reasons
788-
// The method to use is navigator.clipboard.readText() but this is an asynchronous method
789-
// that will return at some moment after the function is called with the required data
790-
emscripten_run_script_string("navigator.clipboard.readText() \
791-
.then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \
792-
.catch(err => { console.error('Failed to read clipboard contents: ', err); });"
793-
);
794-
795-
// The main issue is getting that data, one approach could be using ASYNCIFY and wait
796-
// for the data but it requires adding Asyncify emscripten library on compilation
797-
798-
// Another approach could be just copy the data in a HTML text field and try to retrieve it
799-
// later on if available... and clean it for future accesses
800-
*/
801-
return NULL;
855+
RequestClipboardData();
856+
return GetLastPastedText();
802857
}
803858

804859
// Get clipboard image
805860
Image GetClipboardImage(void)
806861
{
807862
Image image = { 0 };
808-
809-
// NOTE: In theory, the new navigator.clipboard.read() can be used to return arbitrary data from clipboard (2024)
810-
// REF: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/read
811-
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
812-
863+
int w = 0, h = 0;
864+
RequestClipboardData();
865+
unsigned char* data = GetLastPastedImage(&w, &h);
866+
if (data != NULL) {
867+
image.data = data;
868+
image.width = w;
869+
image.height = h;
870+
image.mipmaps = 1;
871+
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
872+
}
873+
813874
return image;
814875
}
815876

tools/rexm/rexm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,7 @@ int main(int argc, char *argv[])
10401040
// Find position to add new example on list, just before the following category
10411041
// Category order: core, shapes, textures, text, models, shaders, audio
10421042
int exListNextCatIndex = -1;
1043-
if (nextCatIndex != -1) exListNextCatIndex = TextFindIndex(exList, exCategories[nextCatIndex]);
1043+
if (nextCatIndex != -1) exListNextCatIndex = TextFindIndex(exList, TextFormat("\n%s", exCategories[nextCatIndex])) + 1;
10441044
else exListNextCatIndex = exListLen; // EOF
10451045

10461046
strncpy(exListUpdated, exList, exListNextCatIndex);

0 commit comments

Comments
 (0)