24 Commits

Author SHA1 Message Date
Ray
453cc35f27 Update CHANGELOG 2026-10-10 21:35:57 +02:00
Ray
bc77441de0 Update CHANGELOG 2026-10-10 21:35:39 +02:00
89650b5b9e [examples] Update all examples to use explicit NULL pointer checks (#6251) 2026-10-10 21:27:59 +02:00
0b5fab1123 [rcore][win32] Implement SetClipboardText() and GetClipboardText() (#6248)
* [rcore][win32] Implement `SetClipboardText()` and `GetClipboardText()`

* Use explicit NULL pointer checks
2026-10-10 20:24:15 +02:00
Ray
e453e80bed Update CONVENTIONS.md 2026-10-10 20:22:42 +02:00
c5958f5832 [rexm] Validate screenshot size before comparing with template image (#6249) 2026-10-10 20:20:03 +02:00
fd0f4c185b [examples] Avoid unloading stale clipboard textures (#6244)
Co-authored-by: Hugohong258 <282228220+Hugohong258@users.noreply.github.com>
2026-10-10 09:20:02 +02:00
84e4a2a257 [rcore][win32] Stop SetWindowIcon() from leaking the previous icon (#6239)
* [rcore][win32] Stop SetWindowIcon() from leaking the previous icon

* Use WM_SETICON instead of WM_GETICON in ClosePlatform icon cleanup

* Delete icon after window is destroyed
2026-10-09 09:50:28 +02:00
9056ea3299 [examples] core_input_gestures_testbed: fix out-of-bounds log read (#6238)
gestureLogIndex started at GESTURE_LOG_SIZE, and the log drawing loop
starts reading at that index, so gestureLog[GESTURE_LOG_SIZE] (one past
the end) was read every frame until the first gesture was logged.
Start the index at 0 instead. Logging is unchanged: the first logged
gesture still wraps to GESTURE_LOG_SIZE - 1.
2026-10-09 00:57:48 +02:00
806d68a9bc [examples] audio_stream_callback: fix out-of-bounds read in waveform drawing (#6237)
The waveform loop draws a line from sample i to sample i + 1 for every
x in [0, screenWidth). For the last x, the end point index works out to
SAMPLE_RATE, one past the end of buffer[SAMPLE_RATE]. Stop the loop one
pixel earlier so the last segment ends on the final sample.
2026-10-09 00:56:35 +02:00
3825bbf2d4 [raudio] LoadSoundAlias(): check source buffer before use (#6236)
If the source sound failed to load (for example when no audio
playback device could be initialized), its stream.buffer is NULL and
LoadSoundAlias() dereferenced it. Check the buffer first, like
UnloadSoundAlias() and IsSoundValid() already do, so an empty Sound
is returned instead of crashing.

Seen with examples/audio/audio_sound_multi (reported in #5664).
2026-10-09 00:55:47 +02:00
c8b19b297b [rmodels] Fix GetRayCollisionSphere() hitting spheres behind the ray (#6231)
* [rmodels] Fix GetRayCollisionSphere() hitting spheres behind the ray

* Return zeroed struct on failure cases
2026-10-09 00:53:32 +02:00
a043255aa7 [examples] models_animation_blending: avoid crash when animations fail to load (#6234)
If resources/models/gltf/robot.glb can't be found (e.g. the example is
run from another working directory), LoadModelAnimations() returns NULL
with animCount = 0 and the example indexed anims[] in the update loop
and in the timeline drawing, crashing. Skip both when no animations
were loaded, so it just logs the usual load warnings.

Reported in #5664.
2026-10-08 15:33:10 +02:00
8c23ce44a0 [rcore][win32] Clean up window state in CloseWindow() (#6233) 2026-10-08 15:32:37 +02:00
48aaf6e2df [rcore][win32] Allow SetWindowSize() to change only the width or height (#6232) 2026-10-08 15:30:41 +02:00
0ed3570469 [raymath] Fix QuaternionFromVector3ToVector3() returning a zero quaternion for opposite vectors (#6230) 2026-10-08 15:26:36 +02:00
2dee47282a [raymath] Fix MatrixDecompose() reading rows instead of columns (#6225) 2026-10-07 13:13:42 +02:00
607a659363 [rcore][win32] Support MSAA (#6227) 2026-10-07 07:46:34 +02:00
040a4bafa9 [CHANGELOG] Fix typos in 6.2 release notes (#6228) 2026-10-07 07:44:20 +02:00
8571d445e9 [rtextures] Fix ImageDrawImageEx() blending on transparent destinations (#6224) 2026-10-06 20:55:35 +02:00
Ray
4722c9fa58 Minor tweaks 2026-10-06 18:35:06 +02:00
91d50e2938 [rcore][win32] Fix WGL pixel format not being applied (#6219)
* [rcore][win32] Fix WGL pixel format not being applied

* Specify Stencil Bits In Fallback Pixel Format
2026-10-06 08:22:59 +02:00
92f1f3d5d5 [rcore][web] Avoid glfwGetProcAddress() to reduce code size (#6220)
* [rcore][web] Avoid glfwGetProcAddress() to reduce code size

* [build][cmake] Remove unneeded GL_ENABLE_GET_PROC_ADDRESS flag
2026-10-06 08:20:40 +02:00
Ray
f0736f6fb5 GLFW: Boundaries check #6222 2026-10-06 07:49:07 +02:00
20 changed files with 404 additions and 115 deletions

View File

@ -4,20 +4,20 @@ changelog
Current Release: raylib 6.0 (23 April 2026) Current Release: raylib 6.0 (23 April 2026)
------------------------------------------------------------------------- -------------------------------------------------------------------------
Release: raylib 6.2 (xx Sep 2026) Release: raylib 6.2 (xx Oct 2026)
------------------------------------------------------------------------- -------------------------------------------------------------------------
KEY CHANGES: KEY CHANGES:
- REDESIGNED: Image API for more alignment with Texture API - REDESIGNED: Image API for more alignment with Texture API
- REDESIGNED: File API for more standard return result values - REDESIGNED: File API for more standard return result values
- REVIEWED: Shapes lines drawing functions, added new ones and unify behaviour - REVIEWED: Shapes lines drawing functions, added new ones and unify behaviour
Detailed changes (until 12-Sept-2026): Detailed changes (until 08-Oct-2026):
[rcore] ADDED: `IsPathDirectory()`, for convenience and more readability at user code by @raysan5 [rcore] ADDED: `IsPathDirectory()`, for convenience and more readability at user code by @raysan5
[rcore] ADDED: `IsPathAbsolute()`, check absolute paths by @raysan5 [rcore] ADDED: `IsPathAbsolute()`, check absolute paths by @raysan5
[rcore] ADDED: `IsFileHidden()`, check file hidden (OS-dependant) by @raysan5 [rcore] ADDED: `IsFileHidden()`, check file hidden (OS-dependant) by @raysan5
[rcore] REVIEWED: `File*()` functions for consistent return result value by @raysan5 -WARNING- [rcore] REVIEWED: `File*()` functions for consistent return result value by @raysan5 -WARNING-
[rcore] REVIEWED: Not updating mouse.previousPosition when `SeMousePosition()` #5962 by @raysan5 -WARNING- [rcore] REVIEWED: Not updating mouse.previousPosition when `SetMousePosition()` #5962 by @raysan5 -WARNING-
[rcore] REVIEWED: Use `rlgl` provided interface instead of `rlsw` direct access by @raysan5 [rcore] REVIEWED: Use `rlgl` provided interface instead of `rlsw` direct access by @raysan5
[rcore] REVIEWED: Set mouse position to (0,0) when mouse leaves window area #5945 by @raysan5 [rcore] REVIEWED: Set mouse position to (0,0) when mouse leaves window area #5945 by @raysan5
[rcore] REVIEWED: Multiple string boundary handling (#5812) by @zhaob1n [rcore] REVIEWED: Multiple string boundary handling (#5812) by @zhaob1n
@ -26,7 +26,7 @@ Detailed changes (until 12-Sept-2026):
[rcore] REVIEWED: Fix initial macOS window size (#5967) by @loukamb [rcore] REVIEWED: Fix initial macOS window size (#5967) by @loukamb
[rcore] REVIEWED: Fix clipboard image memory leak (#5968) by @LuisR385 [rcore] REVIEWED: Fix clipboard image memory leak (#5968) by @LuisR385
[rcore] REVIEWED: `TakeScreenshot()`, support absolute paths by @raysan5 [rcore] REVIEWED: `TakeScreenshot()`, support absolute paths by @raysan5
[rcore] REVIEWED: `OpenURL()`, added some safety checks to mitigate malicious url inputs - ROS: `CLN-002 by @raysan5 -WARNING- [rcore] REVIEWED: `OpenURL()`, added some safety checks to mitigate malicious url inputs - ROS: `CLN-002` by @raysan5 -WARNING-
[rcore] REVIEWED: `LoadAutomationEventList()` - ROS: `CLN-005`, `CLN-006` by @raysan5 [rcore] REVIEWED: `LoadAutomationEventList()` - ROS: `CLN-005`, `CLN-006` by @raysan5
[rcore] REVIEWED: `GetWindowHandle()`, to be consistent between backends, fix #5885 by @raysan5 [rcore] REVIEWED: `GetWindowHandle()`, to be consistent between backends, fix #5885 by @raysan5
[rcore] REVIEWED: `GetWindowPosition()` #5932 by @raysan5 [rcore] REVIEWED: `GetWindowPosition()` #5932 by @raysan5
@ -40,6 +40,8 @@ Detailed changes (until 12-Sept-2026):
[rcore] REVIEWED: `ComputeSHA256()`, wrong hash when message length mod 64 is 56..59 (#6144) by @killerdevildog -WARNING- [rcore] REVIEWED: `ComputeSHA256()`, wrong hash when message length mod 64 is 56..59 (#6144) by @killerdevildog -WARNING-
[rcore] REVIEWED: `GetPrevDirectoryPath()` behavior to better support side cases (#6073) by @luphi [rcore] REVIEWED: `GetPrevDirectoryPath()` behavior to better support side cases (#6073) by @luphi
[rcore] REVIEWED: `GetGamepadAxisCount()`, `GetGamepadName()`, bounds-check gamepad index (#5937) by @szarta [rcore] REVIEWED: `GetGamepadAxisCount()`, `GetGamepadName()`, bounds-check gamepad index (#5937) by @szarta
[rcore] REVIEWED: `FileText*()`, make error handling consistent with `Text*()` helpers (#6210) by @Ne0nWinds
[rcore] REVIEWED: `MAX_FILEPATH_LENGTH` to match `MAX_PATH` (#6164) by @randomnumbersandletters
[rcore][GLFW] REVIEWED: `GetClipboardImage()`, fix creating new connection under X11 (#5871) by @steampuker [rcore][GLFW] REVIEWED: `GetClipboardImage()`, fix creating new connection under X11 (#5871) by @steampuker
[rcore][GLFW] REVIEWED: Borderless-windowed mode being always on top (#5868) by @auwsmit [rcore][GLFW] REVIEWED: Borderless-windowed mode being always on top (#5868) by @auwsmit
[rcore][GLFW] REVIEWED: Clipboard image memory leak (GLFW, RGFW) (#6103) by @omaribrahimsaad [rcore][GLFW] REVIEWED: Clipboard image memory leak (GLFW, RGFW) (#6103) by @omaribrahimsaad
@ -47,19 +49,35 @@ Detailed changes (until 12-Sept-2026):
[rcore][GLFW] REVIEWED: `Font` symbol conflict (#6094) by @M374LX [rcore][GLFW] REVIEWED: `Font` symbol conflict (#6094) by @M374LX
[rcore][RGFW] REVIEWED: Add fullscreen behaviour on size 0 window creation (#5859) by @keks137 [rcore][RGFW] REVIEWED: Add fullscreen behaviour on size 0 window creation (#5859) by @keks137
[rcore][RGFW] REVIEWED: Fix window Y position reading X in RGFW move callback (#6044) by @latent-9 [rcore][RGFW] REVIEWED: Fix window Y position reading X in RGFW move callback (#6044) by @latent-9
[rcore][GLFW] REVIEWED: Window centering overflow with unsigned screen size (#6119) by @nfvelten
[rcore][GLFW] REVIEWED: Allow non-fullscreen window being able to be larger than a workable area (#6137) by @JamesMillsDev
[rcore][SDL] REVIEWED: Use precise mouse wheel values (#5830) by @Menduist [rcore][SDL] REVIEWED: Use precise mouse wheel values (#5830) by @Menduist
[rcore][SDL] REVIEWED: Fix SDL3 wrong joystick functions usage (#5948) by @0xFishbyte [rcore][SDL] REVIEWED: Fix SDL3 wrong joystick functions usage (#5948) by @0xFishbyte
[rcore][SDL] REVIEWED: Accumulate relative mouse motion per frame (#6215) by @snowyukitty
[rcore][SDL] REVIEWED: Fix only the first dropped file being registered (#6190) by @SulimanAbdulrazzaq
[rcore][SDL] REVIEWED: `DROP_EVENT_DATA` definition (#6185) by @Yonokid
[rcore][SDL] REVIEWED: Grow dropFilePaths dynamically when file is dragged ontop of window (#6178) by @jestarray
[rcore][SDL] REVIEWED: Refactor dragdrop file onto window handling and grow dropFilepaths dynamically like glfw (#6178) by @jestarray
[rcore][DRM] REVIEWED: Silence warnings when using GRAPHICS_API_OPENGL_SOFTWARE (#5839) by @NighthowlerStudios [rcore][DRM] REVIEWED: Silence warnings when using GRAPHICS_API_OPENGL_SOFTWARE (#5839) by @NighthowlerStudios
[rcore][DRM] REVIEWED: Segfault on some NVIDIA proprietary drivers (#5960) by @girvel [rcore][DRM] REVIEWED: Segfault on some NVIDIA proprietary drivers (#5960) by @girvel
[rcore][DRM] REVIEWED: Raise MAX_DRM_CACHED_BUFFERS to 4 and warn when the cache fills (#6107) by @jtakakura [rcore][DRM] REVIEWED: Raise MAX_DRM_CACHED_BUFFERS to 4 and warn when the cache fills (#6107) by @jtakakura
[rcore][Web] REVIEWED: Fix for stale mouse position (#5981) by @largenumberhere [rcore][Web] REVIEWED: Fix for stale mouse position (#5981) by @largenumberhere
[rcore][Win32] ADDED: GetClipboardImage() (#6091) by @omaribrahimsaad [rcore][Web] REVIEWED: Avoid `glfwGetProcAddress()` to reduce code size (#6220) by @vdemcak -WARNING-
[rcore][Win32] ADDED: Support MSAA (#6227) by @Ne0nWinds
[rcore][Win32] ADDED: `IsKeyPressedRepeat()` implementation (#6218) by @Ne0nWinds
[rcore][Win32] ADDED: `GetClipboardImage()` (#6091) by @omaribrahimsaad
[rcore][Win32] REVIEWED: Use `CORE.Input.Keyboard.exitKey` when handling window closing (#5911) by @aceinetx [rcore][Win32] REVIEWED: Use `CORE.Input.Keyboard.exitKey` when handling window closing (#5911) by @aceinetx
[rcore][Win32] REVIEWED: Security fixes (#5899) by @M374LX [rcore][Win32] REVIEWED: Security fixes (#5899) by @M374LX
[rcore][Win32] REVIEWED: Handle conflict with `PlaySoundW()` for wide string builds (#6140) by @JeffM2501 [rcore][Win32] REVIEWED: Handle conflict with `PlaySoundW()` for wide string builds (#6140) by @JeffM2501
[rcore][Win32] REVIEWED: `SetWindowState()`, prevent infinite loop (#6194) by @Ne0nWinds
[rcore][Win32] REVIEWED: Missing break in WndProc switch statement (#6209) by @Ne0nWinds
[rcore][Win32] REVIEWED: `SetWindowSize()`, allow to change only the width or height (#6232) by @Ne0nWinds
[rcore][Win32] REVIEWED: `CloseWindow()`, clean up window state (#6233) by @Ne0nWinds
[rcore][Win32] REVIEWED: `IsWindowResized()`, return true only when needed (#6186) by @Ne0nWinds
[rcore][Win32] REVIEWED: WGL pixel format not being applied (#6219) by @Ne0nWinds
[rcore][Android] REVIEWED: Restore face-button input on Android gamepads (#5824) by @Tubbles [rcore][Android] REVIEWED: Restore face-button input on Android gamepads (#5824) by @Tubbles
[rcore][Android] REVIEWED: Relaunch hang after destroy while paused (#6040) by @get-charlie [rcore][Android] REVIEWED: Relaunch hang after destroy while paused (#6040) by @get-charlie
[rcore][Emscripten] REVIEWED: GetTime(), fix time calculation (#6061) by @andzdroid [rcore][Emscripten] REVIEWED: `GetTime()`, fix time calculation (#6061) by @andzdroid
[rcore][Emscripten] REVIEWED: Handle emscripten keyboard events (#6067) by @andzdroid [rcore][Emscripten] REVIEWED: Handle emscripten keyboard events (#6067) by @andzdroid
[rcore][Emscripten] REVIEWED: Invert emscripten scroll wheel direction (#6104) by @andzdroid [rcore][Emscripten] REVIEWED: Invert emscripten scroll wheel direction (#6104) by @andzdroid
[rcore][Emscripten] REVIEWED: Update emscripten mouse handling (#6070) by @andzdroid [rcore][Emscripten] REVIEWED: Update emscripten mouse handling (#6070) by @andzdroid
@ -97,12 +115,16 @@ Detailed changes (until 12-Sept-2026):
[rshapes] REVIEWED: `DrawPolyLinesEx()` line thickness (#6014) by @MatthewRoush [rshapes] REVIEWED: `DrawPolyLinesEx()` line thickness (#6014) by @MatthewRoush
[rshapes] REVIEWED: `DrawRectangleLinesEx()` (#6027) by @MatthewRoush [rshapes] REVIEWED: `DrawRectangleLinesEx()` (#6027) by @MatthewRoush
[rshapes] REVIEWED: `DrawRectangleRoundedLines()` (#5992) by @MatthewRoush [rshapes] REVIEWED: `DrawRectangleRoundedLines()` (#5992) by @MatthewRoush
[rshapes] REVIEWED: `DrawRectangleRounded*()`, segment auto-calculation threshold (#6159) by @MatthewRoush
[rtextures] ADDED: Support for .pep image fileformat, useful for pixel-art by @raysan5
[rtextures] ADDED: `LoadRenderTextureEx()` with user defined pixel format (#6114) by @JeffM2501 [rtextures] ADDED: `LoadRenderTextureEx()` with user defined pixel format (#6114) by @JeffM2501
[rtextures] ADDED: `ImageDrawLineStrip()` by @raysan5 [rtextures] ADDED: `ImageDrawLineStrip()` by @raysan5
[rtextures] ADDED: `DrawTriangleGradient()` by @raysan5 [rtextures] ADDED: `DrawTriangleGradient()` by @raysan5
[rtextures] ADDED: `DrawCircleLinesEx()`, simpler naming than `DrawRing()` by @raysan5 [rtextures] ADDED: `DrawCircleLinesEx()`, simpler naming than `DrawRing()` by @raysan5
[rtextures] ADDED: `ImageDrawCircleGradient()` by @raysan5 [rtextures] ADDED: `ImageDrawCircleGradient()` by @raysan5
[rtextures] ADDED: Support for .pep image fileformat, useful for pixel-art by @raysan5 [rtextures] ADDED: `ImageDrawImageEx()` by @raysan5
[rtextures] ADDED: `ImageDrawRectanglePro()` by @raysan5
[rtextures] ADDED: `ImageDrawRectangleGradientEx()` by @raysan5
[rtextures] RENAMED: `ImageDrawTriangleEx()` to `ImageDrawTriangleGradient()` by @raysan5 -WARNING- [rtextures] RENAMED: `ImageDrawTriangleEx()` to `ImageDrawTriangleGradient()` by @raysan5 -WARNING-
[rtextures] REDESIGNED: `ImageDraw()`, align with `DrawTexture()` by @raysan5 -WARNING- [rtextures] REDESIGNED: `ImageDraw()`, align with `DrawTexture()` by @raysan5 -WARNING-
[rtextures] REDESIGNED: `ImageDrawRectangleLines()`, consistency with `DrawRectangleLines()` by @raysan5 -WARNING- [rtextures] REDESIGNED: `ImageDrawRectangleLines()`, consistency with `DrawRectangleLines()` by @raysan5 -WARNING-
@ -118,6 +140,9 @@ Detailed changes (until 12-Sept-2026):
[rtextures] REVIEWED: `ImageColorContrast()` parameter type, consistent with other `Image*()` functions by @raysan5 -WARNING- [rtextures] REVIEWED: `ImageColorContrast()` parameter type, consistent with other `Image*()` functions by @raysan5 -WARNING-
[rtextures] REVIEWED: `GetPixelDataSize()`, avoid allocations >2GB - ROS: `CLN-013` by @raysan5 [rtextures] REVIEWED: `GetPixelDataSize()`, avoid allocations >2GB - ROS: `CLN-013` by @raysan5
[rtextures] REVIEWED: `GetPixelColor()` const by @raysan5 [rtextures] REVIEWED: `GetPixelColor()` const by @raysan5
[rtextures] REVIEWED: `ImageDrawImageEx()`, blending on transparent destinations (#6224) by @Kartikey-cs
[rtextures] REVIEWED: `ImageKernelConvolution()`, sampling across rows at image edges and unclamped alpha (#6192) by @4RH1T3CT0R7
[rtext] REVIEWED: BDF loading writing glyphs through a NULL-based pointer (#6198) by @antonsoo
[rtext] REVIEWED: `LoadFontEx()`, `LoadFontFromMemory()`, additional warnings (#5864) by @CrackedPixel [rtext] REVIEWED: `LoadFontEx()`, `LoadFontFromMemory()`, additional warnings (#5864) by @CrackedPixel
[rtext] REVIEWED: `TextToSnake()`, not considering spaces properly by @raysan5 [rtext] REVIEWED: `TextToSnake()`, not considering spaces properly by @raysan5
[rtext] REVIEWED: `TextSubtext()`, fix returning empty string when position is 0 (#5975) by @thiagomucci [rtext] REVIEWED: `TextSubtext()`, fix returning empty string when position is 0 (#5975) by @thiagomucci
@ -127,10 +152,14 @@ Detailed changes (until 12-Sept-2026):
[rtext] REVIEWED: `LoadFontFromImage()`, memory leak (#6100) by @ApexNadir [rtext] REVIEWED: `LoadFontFromImage()`, memory leak (#6100) by @ApexNadir
[rtext] REVIEWED: `TextInsert()`/`TextInsertAlloc()` (#6021) by @SewerynKaminski [rtext] REVIEWED: `TextInsert()`/`TextInsertAlloc()` (#6021) by @SewerynKaminski
[rtext] REVIEWED: `TextSplit()` reading past its buffer on text of 1024 bytes (#6136) by @MaxFreedomPollard [rtext] REVIEWED: `TextSplit()` reading past its buffer on text of 1024 bytes (#6136) by @MaxFreedomPollard
[rtext] REVIEWED: `TextToPascal()`/`TextToCamel()` truncating text after a separator (#6132) by @MaxFreedomPollard [rtext] REVIEWED: `TextToPascal()`/`TextToCamel()`, truncating text after a separator (#6132) by @MaxFreedomPollard
[rtext] REVIEWED: `TextToPascal()`/`TextToCamel()`, empty strings checks (#6213) by @Ne0nWinds
[rmodels] REDESIGNED: `DrawCapsule()`, `DrawCapsuleWires()`, parameter order by @raysan5 -WARNING- [rmodels] REDESIGNED: `DrawCapsule()`, `DrawCapsuleWires()`, parameter order by @raysan5 -WARNING-
[rmodels] REVIEWED: Fix glTF skinning when joints have non-joint parent nodes (#5876) by @cseelhoff [rmodels] REVIEWED: Fix glTF skinning when joints have non-joint parent nodes (#5876) by @cseelhoff
[rmodels] REVIEWED: Change `boneCount` field type to `unsigned int` (#5955) by @lauchimoon [rmodels] REVIEWED: Change `boneCount` field type to `unsigned int` (#5955) by @lauchimoon
[rmodels] REVIEWED: GLTF animation interpolation (#6007) by @lassade
[rmodels] REVIEWED: glTF pose sampled at the end of an animation returning a pose from the start (#6048) by @LeFede
[rmodels] REVIEWED: `LoadOBJ()`, avoid reading past vertex data on out-of-range face indices (#6199) by @antonsoo
[rmodels] REVIEWED: `LoadGLTF()`, use inverse bind matrices for bind pose (#5832) by @fyl2xp1 [rmodels] REVIEWED: `LoadGLTF()`, use inverse bind matrices for bind pose (#5832) by @fyl2xp1
[rmodels] REVIEWED: `IsModelValid()` #5780 by @raysan5 [rmodels] REVIEWED: `IsModelValid()` #5780 by @raysan5
[rmodels] REVIEWED: `GenMeshTorus()`, improved comments (#5934) by @EugenioBarbieriViale [rmodels] REVIEWED: `GenMeshTorus()`, improved comments (#5934) by @EugenioBarbieriViale
@ -138,8 +167,7 @@ Detailed changes (until 12-Sept-2026):
[rmodels] REVIEWED: `DrawSphereWires()`, code optimization (#6000) by @oscujic [rmodels] REVIEWED: `DrawSphereWires()`, code optimization (#6000) by @oscujic
[rmodels] REVIEWED: `DrawCapsule()`, `DrawCapsuleWires()`, validate minimum rings (#5909) by @LuisR385 [rmodels] REVIEWED: `DrawCapsule()`, `DrawCapsuleWires()`, validate minimum rings (#5909) by @LuisR385
[rmodels] REVIEWED: `UnloadModel()`, fix memory leak (#5907) by @LuisR385 [rmodels] REVIEWED: `UnloadModel()`, fix memory leak (#5907) by @LuisR385
[rmodels] REVIEWED: GLTF animation interpolation (#6007) by @lassade [rmodels] REVIEWED: `UpdateModelAnimation()`, compute bone normal matrices once per bone instead of per vertex (#6191) by @4RH1T3CT0R7 -WARNING-
[rmodels] REVIEWED: glTF pose sampled at the end of an animation returning a pose from the start (#6048) by @LeFede
[raudio] REVIEWED: `UpdateSound()`, missleading parameter name by @raysan5 [raudio] REVIEWED: `UpdateSound()`, missleading parameter name by @raysan5
[raudio] REVIEWED: `UnloadSoundAlias()`, prevent leak (#5857) by @Peter0x44 [raudio] REVIEWED: `UnloadSoundAlias()`, prevent leak (#5857) by @Peter0x44
[raudio] REVIEWED: Remove extra `drflac_free()` call (#5916) by @CrackedPixel [raudio] REVIEWED: Remove extra `drflac_free()` call (#5916) by @CrackedPixel
@ -149,6 +177,9 @@ Detailed changes (until 12-Sept-2026):
[raudio] REVIEWED: `CloseAudioDevice()`, crash when uninit device before mutex (#6039) by @get-charlie [raudio] REVIEWED: `CloseAudioDevice()`, crash when uninit device before mutex (#6039) by @get-charlie
[raymath] ADDED: Operator overload for (float * Vector) (#5815) by @alphahex99 [raymath] ADDED: Operator overload for (float * Vector) (#5815) by @alphahex99
[raymath] REVIEWED: `MatrixCompose()` to follow raymath conventions (#6133) by @carlost0 [raymath] REVIEWED: `MatrixCompose()` to follow raymath conventions (#6133) by @carlost0
[raymath] REVIEWED: `MatrixCompose()`, rotating vectors with already overwritten components (#6187) by @ethanstoner
[raymath] REVIEWED: `MatrixDecompose()`, reading rows instead of columns (#6225) by @ewraj
[raymath] REVIEWED: `QuaternionFromVector3ToVector3()`, returning a zero quaternion for opposite vectors (#6230) by @ewraj
[build] REMOVED: Unmaintained project: 4coder by @raysan5 [build] REMOVED: Unmaintained project: 4coder by @raysan5
[build] REMOVED: Unmaintained project: VS2019-Android by @raysan5 [build] REMOVED: Unmaintained project: VS2019-Android by @raysan5
@ -156,6 +187,7 @@ Detailed changes (until 12-Sept-2026):
[build][Make] REVIEWED: Re-enable `GLFW_LINUX_ENABLE_WAYLAND` flag by default #5816 by @raysan5 [build][Make] REVIEWED: Re-enable `GLFW_LINUX_ENABLE_WAYLAND` flag by default #5816 by @raysan5
[build][Make] REVIEWED: examples/Makefile after testing on OSX (#6077) by @WilliamIsMe1 [build][Make] REVIEWED: examples/Makefile after testing on OSX (#6077) by @WilliamIsMe1
[build][Make] REVIEWED: Detect the recipe shell for proper clean (#6146) by @Peter0x44 [build][Make] REVIEWED: Detect the recipe shell for proper clean (#6146) by @Peter0x44
[build][Make] REVIEWED: Avoid _GNU_SOURCE on Linux to keep the library linkable with older glibc (#6214) by @Peter0x44 -WARNING-
[build][VS2022] REVIEWED: x64 build compatibility support (#6052) (#6053) by @yoobezxc [build][VS2022] REVIEWED: x64 build compatibility support (#6052) (#6053) by @yoobezxc
[build][CMake] ADDED: Support for Win32 platform + examples (#5855) by @CrackedPixel [build][CMake] ADDED: Support for Win32 platform + examples (#5855) by @CrackedPixel
[build][CMake] REVIEWED: Fix config.h parsing into cmake options (#5844) by @Peter0x44 [build][CMake] REVIEWED: Fix config.h parsing into cmake options (#5844) by @Peter0x44
@ -166,16 +198,20 @@ Detailed changes (until 12-Sept-2026):
[build][CMake] REVIEWED: Fix static link dependencies (#5990) by @meta-legend [build][CMake] REVIEWED: Fix static link dependencies (#5990) by @meta-legend
[build][CMake] REVIEWED: Fix standalone configuration of examples project (#6079) by @zaveshaa [build][CMake] REVIEWED: Fix standalone configuration of examples project (#6079) by @zaveshaa
[build][CMake] REVIEWED: Propagate Cocoa backend frameworks to consumers of static raylib on macOS (#6086) by @zaveshaa [build][CMake] REVIEWED: Propagate Cocoa backend frameworks to consumers of static raylib on macOS (#6086) by @zaveshaa
[build][CMake] REVIEWED: Fix install export with vendored SDL (#6173) by @RobLoach
[build][Zig] REVIEWED: Support wasm examples building (#5811) by @shadeops [build][Zig] REVIEWED: Support wasm examples building (#5811) by @shadeops
[build][Zig] REVIEWED: Avoid building examples all the time (#5869) by @jn-jairo [build][Zig] REVIEWED: Avoid building examples all the time (#5869) by @jn-jairo
[build][Zig] REVIEWED: Avoid building web examples all the time (#6006) by @jn-jairo [build][Zig] REVIEWED: Avoid building web examples all the time (#6006) by @jn-jairo
[build][Zig] REVIEWED: Update to raygui 5.0 (#6005) by @jn-jairo [build][Zig] REVIEWED: Update to raygui 5.0 (#6005) by @jn-jairo
[build][Zig] REVIEWED: Migration to latest 0.17 release (#5951) by @miker2049 -WARNING-
[build][CI] ADDED: Clang tidy linting (disabled by default) (#6163) by @jestarray -WARNING-
[build][CI] REVIEWED: GitHub Actions update to latest actions versions by @raysan5 [build][CI] REVIEWED: GitHub Actions update to latest actions versions by @raysan5
[build][CI] REVIEWED: `build_examples_windows.yml`, use latest actions versions by @raysan5 [build][CI] REVIEWED: `build_examples_windows.yml`, use latest actions versions by @raysan5
[build][CI] REVIEWED: `analyze_codeql.yml`, use latest actions versions by @raysan5 [build][CI] REVIEWED: `analyze_codeql.yml`, use latest actions versions by @raysan5
[build][CI] REVIEWED: `setup-emsdk`, use latest actions version by @raysan5 [build][CI] REVIEWED: `setup-emsdk`, use latest actions version by @raysan5
[bindings] ADDED: Recomendations for binding authors (#6141) by @JeffM2501 [bindings] ADDED: Recomendations for binding authors (#6141) by @JeffM2501
[bindings] ADDED: gcl native raylib module (#6152) by @gnuchanos
[bindings] ADDED: sola-raylib (6.0) (#5790, #5795) by @brettchalupa [bindings] ADDED: sola-raylib (6.0) (#5790, #5795) by @brettchalupa
[bindings] ADDED: gclang-raylib (6.0) (#5850) by @gnuchanos [bindings] ADDED: gclang-raylib (6.0) (#5850) by @gnuchanos
[bindings] ADDED: mach-raylib (#6059) by @Angluca [bindings] ADDED: mach-raylib (#6059) by @Angluca
@ -208,26 +244,39 @@ Detailed changes (until 12-Sept-2026):
[bindings] UPDATED: fortran-raylib to raylib 6.0 (#6060) by @interkosmos [bindings] UPDATED: fortran-raylib to raylib 6.0 (#6060) by @interkosmos
[bindings] UPDATED: raylib-py to raylib 6.0 (#6095) by @overdev [bindings] UPDATED: raylib-py to raylib 6.0 (#6095) by @overdev
[bindings] UPDATED: h-raylib to raylib 6.0 (#6142) by @Anut-py [bindings] UPDATED: h-raylib to raylib 6.0 (#6142) by @Anut-py
[bindings] UPDATED: Raylib.nelua (#6183) by @AuzFox
[bindings] UPDATED: mach-raylib to raylib 6.x-dev (#6153) by @Angluca
[examples] ADDED: `core_scissor_shape` (#6032) by @davidbuzatto [examples] ADDED: `core_scissor_shape` (#6032) by @davidbuzatto
[examples] ADDED: `models_mesh_uv_painting` (#6084) by @PanicTitan
[examples] ADDED: `models_procedural_decals` (#6083) by @PanicTitan
[examples] ADDED: `shaders_lights_bloom` (#6081) by @PanicTitan
[examples] ADDED: `shapes_outlines_testbed` (#6072) by @MatthewRoush [examples] ADDED: `shapes_outlines_testbed` (#6072) by @MatthewRoush
[examples] ADDED: `shapes_outlines_thickness` (#6037) by @MatthewRoush [examples] ADDED: `shapes_outlines_thickness` (#6037) by @MatthewRoush
[examples] ADDED: `shapes_polygon_lines` (#6023) by @MatthewRoush [examples] ADDED: `shapes_polygon_lines` (#6023) by @MatthewRoush
[examples] ADDED: `shapes_drag_puzzle` (#6165) by @gabriel-piangers
[examples] ADDED: `textures_portal_window` (#6082) by @PanicTitan [examples] ADDED: `textures_portal_window` (#6082) by @PanicTitan
[examples] REVIEWED: `shaders_shadowmap_rendering` by @raysan5 [examples] ADDED: `models_mesh_uv_painting` (#6084) by @PanicTitan
[examples] REVIEWED: `models_mesh_uv_painting` by @raysan5 [examples] ADDED: `models_procedural_decals` (#6083) by @PanicTitan
[examples] REVIEWED: `shaders_lights_bloom` by @raysan5 [examples] ADDED: `shaders_lights_bloom` (#6081) by @PanicTitan
[examples] REVIEWED: `textures_portal_window` by @raysan5 [examples] REVIEWED: Clarify Camera2d.offset and how it works with High DPI scale mode (#6203) by @JeffM2501
[examples] REVIEWED: Inconsistent version metadata (#6171) by @Ne0nWinds
[examples] REVIEWED: Multiple examples, adding missing `Unload*()` (#6151) by @emecdelam
[examples] REVIEWED: `core_smooth_pixelperfect` (#5803) by @rose-mtz [examples] REVIEWED: `core_smooth_pixelperfect` (#5803) by @rose-mtz
[examples] REVIEWED: `core_directory_files` (#5823) by @MAXDVVV [examples] REVIEWED: `core_directory_files` (#5823) by @MAXDVVV
[examples] REVIEWED: `core_delta_time`, convert frametime to milliseconds before printing (#6201) by @Ne0nWinds
[examples] REVIEWED: `shapes_ball_physics`, move window for ball shake (#5791) by @Sebbl0508 [examples] REVIEWED: `shapes_ball_physics`, move window for ball shake (#5791) by @Sebbl0508
[examples] REVIEWED: `textures_image_drawing` by @raysan5 [examples] REVIEWED: `textures_image_drawing` by @raysan5
[examples] REVIEWED: `textures_portal_window` by @raysan5
[examples] REVIEWED: `textures_image_rotate`, unload source image (#6145) by @Hugohong258
[examples] REVIEWED: `textures_image_processing`, fix up arrow wraparound logic (#6217) by @Ne0nWinds
[examples] REVIEWED: `text_codepoints_loading`, out of bounds error in `CodepointRemoveDuplicates()` (#6206) by @Ne0nWinds
[examples] REVIEWED: `models_basic_voxel` by @raysan5 [examples] REVIEWED: `models_basic_voxel` by @raysan5
[examples] REVIEWED: `models_animation_blending` by @raysan5 [examples] REVIEWED: `models_animation_blending` by @raysan5
[examples] REVIEWED: `models_mesh_uv_painting` by @raysan5
[examples] REVIEWED: `models_animation_blending`, avoid crash when animations fail to load (#6234) by @akashdeshmukh-git
[examples] REVIEWED: `shaders_*`, `pbr.fs`, using wrong uniform value (#5965) by @raysan5 [examples] REVIEWED: `shaders_*`, `pbr.fs`, using wrong uniform value (#5965) by @raysan5
[examples] REVIEWED: `shaders_lights_bloom` by @raysan5
[examples] REVIEWED: `shaders_shadowmap_rendering` by @raysan5
[examples] REVIEWED: `shaders_mesh_instancing`, release mesh instancing resources on exit (#6207) by @Hugohong258
[examples] REVIEWED: `shaders_lightmap_rendering`, unload lightmap render texture (#6188) by @Hugohong258
[rlparser] ADDED: S-Expression output type (#5943) by @VisenDev [rlparser] ADDED: S-Expression output type (#5943) by @VisenDev
[rlparser] REVIEWED: Path fixes (#5794) by @gigamonster256 [rlparser] REVIEWED: Path fixes (#5794) by @gigamonster256
@ -249,11 +298,12 @@ Detailed changes (until 12-Sept-2026):
[external] UPDATED: GLFW to 3.5.1 (#6051) by @M374LX [external] UPDATED: GLFW to 3.5.1 (#6051) by @M374LX
[external] UPDATED: miniaudio to 0.11.25 (#6050) by @M374LX [external] UPDATED: miniaudio to 0.11.25 (#6050) by @M374LX
[external] UPDATED: `raygui` to latest master (raygui 5.0) by @raysan5 [external] UPDATED: `raygui` to latest master (raygui 5.0) by @raysan5
[external] UPDATED: `qoa` with upstream out-of-bounds fixes (#6162) by @thaidn
[external] REVIEWED: `jar_mod_load_file()`, check fread return value (#5840) by @fffaraz [external] REVIEWED: `jar_mod_load_file()`, check fread return value (#5840) by @fffaraz
[external] REVIEWED: `tiny_obj_loader` Replace `assert()` by runtime checks - ROS: `CLN-012` by @raysan5 [external] REVIEWED: `tiny_obj_loader` Replace `assert()` by runtime checks - ROS: `CLN-012` by @raysan5
[external] REVIEWED: `fix_win32_compatibility.h`, fix for newer windows SDK versions (#6088) by @JeffM2501 [external] REVIEWED: `fix_win32_compatibility.h`, fix for newer windows SDK versions (#6088) by @JeffM2501
[external] REVIEWED: `vox_loader`, added bounds checks to `Vox_SetVoxel()` and chunk parsing (#6175) by @AvAl4nch
[external] REVIEWED: `vox_loader`, Prevent memory leak when loading voxel models (#6208) by @Ne0nWinds
------------------------------------------------------------------------- -------------------------------------------------------------------------
Release: raylib 6.0 (23 April 2026) Release: raylib 6.0 (23 April 2026)

View File

@ -68,6 +68,14 @@ void SomeFunction()
{ {
// TODO: Do something here! // TODO: Do something here!
} }
```
- When checking pointers, use full verbose check against `NULL`
```c
if (dataPtr != NULL)
{
RL_FREE(dataPtr);
dataPtr = NULL;
}
``` ```
**If proposing new functions, please try to use a clear naming for function-name and functions-parameters, in case of doubt, open an issue for discussion.** **If proposing new functions, please try to use a clear naming for function-name and functions-parameters, in case of doubt, open an issue for discussion.**

View File

@ -131,7 +131,7 @@ int main(void)
DrawText("Left/right to change wave type", 10, 30, 20, DARKGRAY); DrawText("Left/right to change wave type", 10, 30, 20, DARKGRAY);
// Draw the last 10 ms of uploaded audio // Draw the last 10 ms of uploaded audio
for (int i = 0; i < screenWidth; i++) for (int i = 0; i < screenWidth - 1; i++)
{ {
Vector2 startPos = {(float)i, 250 - 50*buffer[SAMPLE_RATE - SAMPLE_RATE/100 + i*SAMPLE_RATE/100/screenWidth] }; Vector2 startPos = {(float)i, 250 - 50*buffer[SAMPLE_RATE - SAMPLE_RATE/100 + i*SAMPLE_RATE/100/screenWidth] };
Vector2 endPos = { (float)(i + 1), 250 - 50*buffer[SAMPLE_RATE - SAMPLE_RATE/100 + (i + 1)*SAMPLE_RATE/100/screenWidth] }; Vector2 endPos = { (float)(i + 1), 250 - 50*buffer[SAMPLE_RATE - SAMPLE_RATE/100 + (i + 1)*SAMPLE_RATE/100/screenWidth] };

View File

@ -50,7 +50,7 @@ int main(void)
// NOTE: The gesture log uses an array (as an inverted circular queue) to store the performed gestures // NOTE: The gesture log uses an array (as an inverted circular queue) to store the performed gestures
char gestureLog[GESTURE_LOG_SIZE][12] = { "" }; char gestureLog[GESTURE_LOG_SIZE][12] = { "" };
// NOTE: The index for the inverted circular queue (moving from last to first direction, then looping around) // NOTE: The index for the inverted circular queue (moving from last to first direction, then looping around)
int gestureLogIndex = GESTURE_LOG_SIZE; int gestureLogIndex = 0;
int previousGesture = 0; int previousGesture = 0;
// Log mode values: // Log mode values:

View File

@ -114,7 +114,7 @@ int main(void)
if (IsKeyPressed(KEY_P)) animPause = !animPause; if (IsKeyPressed(KEY_P)) animPause = !animPause;
if (!animPause) if (!animPause && (animCount > 0)) // Animations could fail to load
{ {
// Start transition from anim0[] to anim1[] // Start transition from anim0[] to anim1[]
if (IsKeyPressed(KEY_SPACE) && !animTransition) if (IsKeyPressed(KEY_SPACE) && !animTransition)
@ -256,6 +256,8 @@ int main(void)
GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetFont().baseSize); GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetFont().baseSize);
GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
if (animCount > 0)
{
// Draw playing timeline with keyframes for anim0[] // Draw playing timeline with keyframes for anim0[]
GuiProgressBar((Rectangle){ 60, GetScreenHeight() - 60.0f, GetScreenWidth() - 180.0f, 20 }, "ANIM 0", GuiProgressBar((Rectangle){ 60, GetScreenHeight() - 60.0f, GetScreenWidth() - 180.0f, 20 }, "ANIM 0",
TextFormat("FRAME: %.2f / %i", animFrameProgress0, anims[animIndex0].keyframeCount), TextFormat("FRAME: %.2f / %i", animFrameProgress0, anims[animIndex0].keyframeCount),
@ -271,6 +273,7 @@ int main(void)
for (int i = 0; i < anims[animIndex1].keyframeCount; i++) for (int i = 0; i < anims[animIndex1].keyframeCount; i++)
DrawRectangle(60 + (int)(((float)(GetScreenWidth() - 180)/(float)anims[animIndex1].keyframeCount)*(float)i), DrawRectangle(60 + (int)(((float)(GetScreenWidth() - 180)/(float)anims[animIndex1].keyframeCount)*(float)i),
GetScreenHeight() - 30, 1, 20, BLUE); GetScreenHeight() - 30, 1, 20, BLUE);
}
//--------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------
EndDrawing(); EndDrawing();

View File

@ -316,7 +316,7 @@ static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3])
static void FreeMeshBuilder(MeshBuilder *mb) static void FreeMeshBuilder(MeshBuilder *mb)
{ {
MemFree(mb->vertices); MemFree(mb->vertices);
if (mb->uvs) MemFree(mb->uvs); if (mb->uvs != NULL) MemFree(mb->uvs);
*mb = (MeshBuilder){ 0 }; *mb = (MeshBuilder){ 0 };
} }
@ -328,7 +328,7 @@ static Mesh BuildMesh(MeshBuilder *mb)
outMesh.vertexCount = mb->vertexCount; outMesh.vertexCount = mb->vertexCount;
outMesh.triangleCount = mb->vertexCount/3; outMesh.triangleCount = mb->vertexCount/3;
outMesh.vertices = MemAlloc(outMesh.vertexCount*3*sizeof(float)); outMesh.vertices = MemAlloc(outMesh.vertexCount*3*sizeof(float));
if (mb->uvs) outMesh.texcoords = MemAlloc(outMesh.vertexCount*2*sizeof(float)); if (mb->uvs != NULL) outMesh.texcoords = MemAlloc(outMesh.vertexCount*2*sizeof(float));
for (int i = 0; i < mb->vertexCount; i++) for (int i = 0; i < mb->vertexCount; i++)
{ {
@ -336,7 +336,7 @@ static Mesh BuildMesh(MeshBuilder *mb)
outMesh.vertices[3*i+1] = mb->vertices[i].y; outMesh.vertices[3*i+1] = mb->vertices[i].y;
outMesh.vertices[3*i+2] = mb->vertices[i].z; outMesh.vertices[3*i+2] = mb->vertices[i].z;
if (mb->uvs) if (mb->uvs != NULL)
{ {
outMesh.texcoords[2*i+0] = mb->uvs[i].x; outMesh.texcoords[2*i+0] = mb->uvs[i].x;
outMesh.texcoords[2*i+1] = mb->uvs[i].y; outMesh.texcoords[2*i+1] = mb->uvs[i].y;

View File

@ -149,7 +149,7 @@ int main(void)
GLFWwindow *window = glfwCreateWindow(screenWidth, screenHeight, "raylib [others] example - rlgl standalone", NULL, NULL); GLFWwindow *window = glfwCreateWindow(screenWidth, screenHeight, "raylib [others] example - rlgl standalone", NULL, NULL);
if (!window) if (window == NULL)
{ {
glfwTerminate(); glfwTerminate();
return 2; return 2;

View File

@ -50,7 +50,7 @@ int main(void)
if (IsKeyPressed(KEY_R)) // Reset image collection if (IsKeyPressed(KEY_R)) // Reset image collection
{ {
// Unload textures to avoid memory leaks // Unload textures to avoid memory leaks
for (int i = 0; i < MAX_TEXTURE_COLLECTION; i++) UnloadTexture(collection[i].texture); for (int i = 0; i < currentCollectionIndex; i++) UnloadTexture(collection[i].texture);
currentCollectionIndex = 0; currentCollectionIndex = 0;
} }
@ -98,7 +98,7 @@ int main(void)
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
for (int i = 0; i < MAX_TEXTURE_COLLECTION;i ++) for (int i = 0; i < currentCollectionIndex; i++)
{ {
UnloadTexture(collection[i].texture); UnloadTexture(collection[i].texture);
} }

View File

@ -95,7 +95,7 @@ int main(void)
if (!IsMouseButtonDown(MOUSE_LEFT_BUTTON)) curveSelectedPoint = NULL; if (!IsMouseButtonDown(MOUSE_LEFT_BUTTON)) curveSelectedPoint = NULL;
// If a point was selected, move it // If a point was selected, move it
if (curveSelectedPoint) *curveSelectedPoint = Vector2Add(*curveSelectedPoint, GetMouseDelta()); if (curveSelectedPoint != NULL) *curveSelectedPoint = Vector2Add(*curveSelectedPoint, GetMouseDelta());
// The mouse is down, and nothing was selected, so see if anything was picked // The mouse is down, and nothing was selected, so see if anything was picked
Vector2 mouse = GetMousePosition(); Vector2 mouse = GetMousePosition();

View File

@ -30,7 +30,7 @@ target_link_libraries(${PROJECT_NAME} raylib)
# Web Configurations # Web Configurations
if (${PLATFORM} STREQUAL "Web") if (${PLATFORM} STREQUAL "Web")
set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") # Tell Emscripten to build an example.html file. set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") # Tell Emscripten to build an example.html file.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -s GL_ENABLE_GET_PROC_ADDRESS=1") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY")
endif() endif()
# Checks if OSX and links appropriate frameworks (Only required on MacOS) # Checks if OSX and links appropriate frameworks (Only required on MacOS)

View File

@ -285,7 +285,6 @@ static int android_close(void *cookie);
// CMake: handled automatically — the PUBLIC flag propagates as INTERFACE_LINK_OPTIONS // CMake: handled automatically — the PUBLIC flag propagates as INTERFACE_LINK_OPTIONS
// to the consumer's final link via target_link_libraries // to the consumer's final link via target_link_libraries
// Make: pass -Wl,--wrap=fopen to the linker command producing the final artifact // Make: pass -Wl,--wrap=fopen to the linker command producing the final artifact
// build.zig: pass -Wl,--wrap=fopen to the linker command producing the final artifact
// custom: pass -Wl,--wrap=fopen to the linker command producing the final artifact // custom: pass -Wl,--wrap=fopen to the linker command producing the final artifact
// //
// SHARED library (.so) — wrapping is self-contained: // SHARED library (.so) — wrapping is self-contained:
@ -296,8 +295,6 @@ static int android_close(void *cookie);
// only raylib internals are wrapped, app code requires a separate flag // only raylib internals are wrapped, app code requires a separate flag
// Make: handled automatically — src/Makefile sets LDFLAGS += -Wl,--wrap=fopen; // Make: handled automatically — src/Makefile sets LDFLAGS += -Wl,--wrap=fopen;
// only raylib internals are wrapped, app code requires a separate flag // only raylib internals are wrapped, app code requires a separate flag
// build.zig: NOT supported — std.Build has no dedicated linker wrap helper, the flag
// is not correctly applied at the .so link step
// custom: apply -Wl,--wrap=fopen to the linker command producing the .so // custom: apply -Wl,--wrap=fopen to the linker command producing the .so
FILE *__real_fopen(const char *fileName, const char *mode); // Real fopen, provided by the linker (--wrap=fopen) 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 *__wrap_fopen(const char *fileName, const char *mode); // Replacement for fopen()

View File

@ -2093,7 +2093,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
// GLFW3: Keyboard callback, runs on key pressed // GLFW3: Keyboard callback, runs on key pressed
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
{ {
if (key < 0) return; // Security check, macOS fn key generates -1 if ((key < 0) || (key >= MAX_KEYBOARD_KEYS)) return; // Security check, macOS fn key generates -1
// WARNING: GLFW could return GLFW_REPEAT, it needs to be considered as 1 // WARNING: GLFW could return GLFW_REPEAT, it needs to be considered as 1
// to work properly with our implementation (IsKeyDown/IsKeyUp checks) // to work properly with our implementation (IsKeyDown/IsKeyUp checks)

View File

@ -97,6 +97,8 @@ typedef struct {
unsigned int desiredFlags; unsigned int desiredFlags;
LARGE_INTEGER timerFrequency; LARGE_INTEGER timerFrequency;
char *clipboardText;
} PlatformData; } PlatformData;
// Define WGL function pointer types (no wglext.h needed) // Define WGL function pointer types (no wglext.h needed)
@ -393,7 +395,7 @@ static bool UpdateWindowSize(int mode, HWND hwnd, int width, int height, unsigne
SIZE clientSize = { rect.right, rect.bottom }; SIZE clientSize = { rect.right, rect.bottom };
// If client size is alread desired size, no need to update // If client size is alread desired size, no need to update
if ((clientSize.cx == desiredSize.cx) || (clientSize.cy == desiredSize.cy)) return false; if ((clientSize.cx == desiredSize.cx) && (clientSize.cy == desiredSize.cy)) return false;
TRACELOG(LOG_INFO, "WIN32: Restoring client size from [%dx%d] to [%dx%d] (dpi:%lu dpiScaling:%d app:%ix%i)", TRACELOG(LOG_INFO, "WIN32: Restoring client size from [%dx%d] to [%dx%d] (dpi:%lu dpiScaling:%d app:%ix%i)",
clientSize.cx, clientSize.cy, desiredSize.cx, desiredSize.cy, dpi, dpiScaling, width, height); clientSize.cx, clientSize.cy, desiredSize.cx, desiredSize.cy, dpi, dpiScaling, width, height);
@ -925,7 +927,8 @@ void SetWindowIcon(Image image)
{ {
// Set both large and small icons // Set both large and small icons
SendMessage(platform.hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); SendMessage(platform.hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
SendMessage(platform.hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); HICON previousIcon = (HICON)SendMessage(platform.hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
if (previousIcon) DestroyIcon(previousIcon);
} }
} }
@ -1119,14 +1122,101 @@ Vector2 GetWindowScaleDPI(void)
// Set clipboard text content // Set clipboard text content
void SetClipboardText(const char *text) void SetClipboardText(const char *text)
{ {
TRACELOG(LOG_WARNING, "SetClipboardText not implemented"); if (OpenClipboard(platform.hwnd))
{
if (text == NULL)
{
EmptyClipboard();
}
else
{
size_t length = strlen(text);
int clipboardTextLength = MultiByteToWideChar(CP_UTF8, 0, text, (int)(length + 1), NULL, 0);
if (clipboardTextLength != 0)
{
HGLOBAL globalHandle = GlobalAlloc(GMEM_MOVEABLE, clipboardTextLength*sizeof(wchar_t));
if (globalHandle)
{
LPVOID clipboardText = GlobalLock(globalHandle);
int charactersCopied = 0;
if (clipboardText != NULL)
{
// Directly copies text to clipboardText and converts from UTF-8 to UTF-16
charactersCopied = MultiByteToWideChar(CP_UTF8, 0, text, (int)(length + 1), clipboardText, clipboardTextLength);
GlobalUnlock(globalHandle);
}
if (charactersCopied != 0)
{
EmptyClipboard();
// We don't need to call GlobalFree when SetClipboardData succeeds; Windows takes control of the memory
HANDLE clipboardData = SetClipboardData(CF_UNICODETEXT, globalHandle);
if (!clipboardData)
{
TRACELOG(LOG_WARNING, "Clipboard: Failed to set clipboard text.");
GlobalFree(globalHandle);
}
}
else
{
GlobalFree(globalHandle);
}
}
}
}
CloseClipboard();
}
else
{
TRACELOG(LOG_WARNING, "Clipboard: Failed to write to clipboard. It may be locked by another program.");
}
} }
// Get clipboard text content // Get clipboard text content
const char *GetClipboardText(void) const char *GetClipboardText(void)
{ {
TRACELOG(LOG_WARNING, "GetClipboardText not implemented"); if (platform.clipboardText != NULL)
return NULL; {
RL_FREE(platform.clipboardText);
platform.clipboardText = NULL;
}
if (OpenClipboard(platform.hwnd))
{
HANDLE clipboardDataHandle = GetClipboardData(CF_UNICODETEXT);
if (clipboardDataHandle)
{
wchar_t *clipboardText = GlobalLock(clipboardDataHandle);
if (clipboardText != NULL)
{
// The clipboard data can't be trusted. It may or may not be null-terminated!
size_t maxLength = GlobalSize(clipboardDataHandle)/sizeof(wchar_t);
int length = (int)wcsnlen(clipboardText, maxLength);
int size = WideCharToMultiByte(CP_UTF8, 0, clipboardText, length, NULL, 0, NULL, NULL);
char *utf8Text = (char *)RL_MALLOC(size + 1);
if ((size > 0) && (WideCharToMultiByte(CP_UTF8, 0, clipboardText, length, utf8Text, size, NULL, NULL) == 0)) size = 0;
utf8Text[size] = '\0';
platform.clipboardText = utf8Text;
GlobalUnlock(clipboardDataHandle);
}
}
CloseClipboard();
}
else
{
TRACELOG(LOG_WARNING, "Clipboard: Failed to read clipboard. It may be locked by another program.");
}
return platform.clipboardText;
} }
#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES #if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
@ -1401,7 +1491,23 @@ void PollInputEvents(void)
// NOTE: Creating a dummy context first to query required extensions // NOTE: Creating a dummy context first to query required extensions
HGLRC InitOpenGL(HWND hwnd, HDC hdc) HGLRC InitOpenGL(HWND hwnd, HDC hdc)
{ {
// First, create a dummy context to get WGL extensions // Create an invisible window for initial dummy OpenGL context
WNDCLASSEXW dummyWindowClass = {
.cbSize = sizeof(WNDCLASSEXW),
.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
.lpfnWndProc = DefWindowProcW,
.hInstance = GetModuleHandleW(NULL),
.lpszClassName = L"wglDummy"
};
RegisterClassExW(&dummyWindowClass);
HWND dummyWindow = CreateWindowExW(
0, dummyWindowClass.lpszClassName, L"dummyWindow",
0, 0, 0, 1, 1, NULL, NULL, NULL, NULL);
HDC dummyHDC = GetDC(dummyWindow);
// Create a dummy OpenGL context to get WGL extensions
PIXELFORMATDESCRIPTOR pixelFormatDesc = { PIXELFORMATDESCRIPTOR pixelFormatDesc = {
.nSize = sizeof(PIXELFORMATDESCRIPTOR), .nSize = sizeof(PIXELFORMATDESCRIPTOR),
.nVersion = 1, .nVersion = 1,
@ -1410,18 +1516,19 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
.cColorBits = 32, .cColorBits = 32,
.cAlphaBits = 8, .cAlphaBits = 8,
.cDepthBits = 24, .cDepthBits = 24,
.cStencilBits = 8,
.iLayerType = PFD_MAIN_PLANE .iLayerType = PFD_MAIN_PLANE
}; };
int pixelFormat = ChoosePixelFormat(hdc, &pixelFormatDesc); int dummyPixelFormat = ChoosePixelFormat(dummyHDC, &pixelFormatDesc);
SetPixelFormat(hdc, pixelFormat, &pixelFormatDesc); SetPixelFormat(dummyHDC, dummyPixelFormat, &pixelFormatDesc);
//int pixelFormat = ChoosePixelFormat(platform.hdc, &pixelFormatDesc); //int pixelFormat = ChoosePixelFormat(platform.hdc, &pixelFormatDesc);
//if (!pixelFormat) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ChoosePixelFormat", GetLastError()); return -1; } //if (!pixelFormat) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ChoosePixelFormat", GetLastError()); return -1; }
//if (!SetPixelFormat(platform.hdc, pixelFormat, &pixelFormatDesc)) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetPixelFormat", GetLastError()); return -1; } //if (!SetPixelFormat(platform.hdc, pixelFormat, &pixelFormatDesc)) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetPixelFormat", GetLastError()); return -1; }
HGLRC tempContext = wglCreateContext(hdc); HGLRC tempContext = wglCreateContext(dummyHDC);
//if (!tempContext) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "wglCreateContext", GetLastError()); return -1; } //if (!tempContext) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "wglCreateContext", GetLastError()); return -1; }
BOOL result = wglMakeCurrent(hdc, tempContext); BOOL result = wglMakeCurrent(dummyHDC, tempContext);
//if (!result) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "wglMakeCurrent", GetLastError()); return -1; } //if (!result) { TRACELOG(LOG_ERROR, "%s failed, error=%lu", "wglMakeCurrent", GetLastError()); return -1; }
// Load WGL extension entry points // Load WGL extension entry points
@ -1431,8 +1538,11 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
// Setup modern pixel format if extension is available // Setup modern pixel format if extension is available
BOOL setPixelFormatSucceeded = FALSE;
if (wglChoosePixelFormatARB) if (wglChoosePixelFormatARB)
{ {
bool useMSAA = FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT);
int pixelFormatAttribs[] = { int pixelFormatAttribs[] = {
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
@ -1440,12 +1550,14 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
WGL_DOUBLE_BUFFER_ARB, GL_TRUE, WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32, WGL_COLOR_BITS_ARB, 32,
//WGL_RED_BITS_ARB, 8, WGL_RED_BITS_ARB, 8,
//WGL_GREEN_BITS_ARB, 8, WGL_GREEN_BITS_ARB, 8,
//WGL_BLUE_BITS_ARB, 8, WGL_BLUE_BITS_ARB, 8,
//WGL_ALPHA_BITS_ARB, 8, WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 24, WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8, WGL_STENCIL_BITS_ARB, 8,
WGL_SAMPLES_ARB, (useMSAA)? 4 : 0,
WGL_SAMPLE_BUFFERS_ARB, (int)useMSAA,
0 // Terminator 0 // Terminator
}; };
@ -1455,7 +1567,23 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
{ {
PIXELFORMATDESCRIPTOR newPixelFormatDescriptor = { 0 }; PIXELFORMATDESCRIPTOR newPixelFormatDescriptor = { 0 };
DescribePixelFormat(hdc, format, sizeof(newPixelFormatDescriptor), &newPixelFormatDescriptor); DescribePixelFormat(hdc, format, sizeof(newPixelFormatDescriptor), &newPixelFormatDescriptor);
SetPixelFormat(hdc, format, &newPixelFormatDescriptor); setPixelFormatSucceeded = SetPixelFormat(hdc, format, &newPixelFormatDescriptor);
}
}
if (!setPixelFormatSucceeded)
{
// If modern pixel format selection failed, fall back to old SetPixelFormat
int pixelFormat = ChoosePixelFormat(hdc, &pixelFormatDesc);
setPixelFormatSucceeded = SetPixelFormat(hdc, pixelFormat, &pixelFormatDesc);
if (setPixelFormatSucceeded)
{
TRACELOG(LOG_WARNING, "WGL: Using legacy pixel format, MSAA not available");
}
else
{
TRACELOG(LOG_ERROR, "WGL: Unable to find a suitable pixel format with this graphics driver");
} }
} }
@ -1521,10 +1649,18 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
// ERROR_INVALID_PROFILE_ARB (0x2096) // ERROR_INVALID_PROFILE_ARB (0x2096)
if (realContext == NULL) TRACELOG(LOG_ERROR, "GL: Error creating requested context: %lu", GetLastError()); if (realContext == NULL) TRACELOG(LOG_ERROR, "GL: Error creating requested context: %lu", GetLastError());
} }
else
{
// If modern context extension isn't available, fall back to classic context creation
realContext = wglCreateContext(hdc);
}
// Cleanup dummy temp context // Cleanup dummy temp context and window
wglMakeCurrent(NULL, NULL); wglMakeCurrent(NULL, NULL);
wglDeleteContext(tempContext); wglDeleteContext(tempContext);
ReleaseDC(dummyWindow, dummyHDC);
DestroyWindow(dummyWindow);
UnregisterClassW(dummyWindowClass.lpszClassName, dummyWindowClass.hInstance);
// Activate real context // Activate real context
if (realContext) wglMakeCurrent(hdc, realContext); if (realContext) wglMakeCurrent(hdc, realContext);
@ -1721,12 +1857,43 @@ int InitPlatform(void)
// Close platform // Close platform
void ClosePlatform(void) void ClosePlatform(void)
{ {
// Undo disable cursor if it's locked and unregister raw input devices
EnableCursor();
// Calling DestroyWindow invokes a WindowProc event that sets the FLAG_WINDOW_HIDDEN flag to true
// If InitWindow is called again, the hidden flag will be interpreted as something the user requested
// Save the current flags and restore them after
unsigned int savedFlags = CORE.Window.flags;
if (platform.hwnd) if (platform.hwnd)
{ {
int result = DestroyWindow(platform.hwnd); // SetWindowIcon uses the same resource for both ICON_BIG and ICON_SMALL
if (result == 0) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed on window destroy [ERROR: %u]", GetLastError()); // If this ever changes, this code may have to be updated
HICON icon = (HICON)SendMessage(platform.hwnd, WM_GETICON, ICON_BIG, (LPARAM)0);
BOOL result = DestroyWindow(platform.hwnd);
if (!result) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed on window destroy [ERROR: %u]", GetLastError());
HINSTANCE hInstance = GetModuleHandleW(0);
result = UnregisterClassW(CLASS_NAME, hInstance);
if (!result) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed to unregister window class [ERROR: %u]", GetLastError());
if (icon != NULL) DestroyIcon(icon);
platform.hwnd = NULL; platform.hwnd = NULL;
} }
if (platform.clipboardText != NULL)
{
RL_FREE(platform.clipboardText);
platform.clipboardText = NULL;
}
CORE.Window.flags = savedFlags;
#if SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP
timeEndPeriod(1); // Restore time period
#endif
} }
// Window procedure, message processing callback // Window procedure, message processing callback

View File

@ -111,6 +111,9 @@ static const char cursorLUT[11][12] = {
int InitPlatform(void); // Initialize platform (graphics, inputs and more) int InitPlatform(void); // Initialize platform (graphics, inputs and more)
void ClosePlatform(void); // Close platform void ClosePlatform(void); // Close platform
// OpenGL extensions loader
static void *WebGLGetProcAddress(const char *procName); // Get WebGL extension procedure address, used by rlLoadExtensions()
// Error callback event // 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
@ -1442,7 +1445,7 @@ int InitPlatform(void)
// Load OpenGL extensions // Load OpenGL extensions
// NOTE: GL procedures address loader is required to load extensions // NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(glfwGetProcAddress); rlLoadExtensions(WebGLGetProcAddress);
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Initialize events callbacks // Initialize events callbacks
@ -1499,6 +1502,24 @@ void ClosePlatform(void)
glfwTerminate(); glfwTerminate();
} }
// Get WebGL extension procedure address
// WARNING: rlGetProcAddress() uses this loader, so it only returns the functions listed below
static void *WebGLGetProcAddress(const char *procName)
{
void *proc = NULL;
#if defined(GRAPHICS_API_OPENGL_ES2)
if (strcmp(procName, "glGenVertexArraysOES") == 0) proc = (void *)glGenVertexArraysOES;
else if (strcmp(procName, "glBindVertexArrayOES") == 0) proc = (void *)glBindVertexArrayOES;
else if (strcmp(procName, "glDeleteVertexArraysOES") == 0) proc = (void *)glDeleteVertexArraysOES;
else if (strcmp(procName, "glDrawArraysInstancedANGLE") == 0) proc = (void *)glDrawArraysInstancedANGLE;
else if (strcmp(procName, "glDrawElementsInstancedANGLE") == 0) proc = (void *)glDrawElementsInstancedANGLE;
else if (strcmp(procName, "glVertexAttribDivisorANGLE") == 0) proc = (void *)glVertexAttribDivisorANGLE;
#endif
return proc;
}
// GLFW3 callback functions, called on GLFW registered events // GLFW3 callback functions, called on GLFW registered events
//------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------
// GLFW3: Called on errors // GLFW3: Called on errors

View File

@ -209,6 +209,9 @@ static const char cursorLUT[11][12] = {
int InitPlatform(void); // Initialize platform (graphics, inputs and more) int InitPlatform(void); // Initialize platform (graphics, inputs and more)
void ClosePlatform(void); // Close platform void ClosePlatform(void); // Close platform
// OpenGL extensions loader
static void *WebGLGetProcAddress(const char *procName); // Get WebGL extension procedure address, used by rlLoadExtensions()
// Emscripten window callback events // Emscripten window callback events
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData); static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData); static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData);
@ -1387,7 +1390,7 @@ int InitPlatform(void)
// Load OpenGL extensions // Load OpenGL extensions
// NOTE: GL procedures address loader is required to load extensions // NOTE: GL procedures address loader is required to load extensions
if (platform.glContext != 0) rlLoadExtensions(emscripten_webgl_get_proc_address); if (platform.glContext != 0) rlLoadExtensions(WebGLGetProcAddress);
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Initialize events callbacks // Initialize events callbacks
@ -1450,6 +1453,24 @@ void ClosePlatform(void)
if (platform.glContext != 0) emscripten_webgl_destroy_context(platform.glContext); if (platform.glContext != 0) emscripten_webgl_destroy_context(platform.glContext);
} }
// Get WebGL extension procedure address
// WARNING: rlGetProcAddress() uses this loader, so it only returns the functions listed below
static void *WebGLGetProcAddress(const char *procName)
{
void *proc = NULL;
#if defined(GRAPHICS_API_OPENGL_ES2)
if (strcmp(procName, "glGenVertexArraysOES") == 0) proc = (void *)glGenVertexArraysOES;
else if (strcmp(procName, "glBindVertexArrayOES") == 0) proc = (void *)glBindVertexArrayOES;
else if (strcmp(procName, "glDeleteVertexArraysOES") == 0) proc = (void *)glDeleteVertexArraysOES;
else if (strcmp(procName, "glDrawArraysInstancedANGLE") == 0) proc = (void *)glDrawArraysInstancedANGLE;
else if (strcmp(procName, "glDrawElementsInstancedANGLE") == 0) proc = (void *)glDrawElementsInstancedANGLE;
else if (strcmp(procName, "glVertexAttribDivisorANGLE") == 0) proc = (void *)glVertexAttribDivisorANGLE;
#endif
return proc;
}
// Emscripten callback functions, called on specific browser events // Emscripten callback functions, called on specific browser events
//------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------
// Emscripten: Called on resize event // Emscripten: Called on resize event

View File

@ -988,7 +988,7 @@ Sound LoadSoundAlias(Sound source)
{ {
Sound sound = { 0 }; Sound sound = { 0 };
if (source.stream.buffer->data != NULL) if ((source.stream.buffer != NULL) && (source.stream.buffer->data != NULL))
{ {
AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC); AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC);

View File

@ -2381,10 +2381,31 @@ RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to) float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to)
Vector3 cross = { from.y*to.z - from.z*to.y, from.z*to.x - from.x*to.z, from.x*to.y - from.y*to.x }; // Vector3CrossProduct(from, to) Vector3 cross = { from.y*to.z - from.z*to.y, from.z*to.x - from.x*to.z, from.x*to.y - from.y*to.x }; // Vector3CrossProduct(from, to)
float lengths = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z + cos2Theta*cos2Theta); // |from|*|to|
result.x = cross.x; result.x = cross.x;
result.y = cross.y; result.y = cross.y;
result.z = cross.z; result.z = cross.z;
result.w = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z + cos2Theta*cos2Theta) + cos2Theta; result.w = lengths + cos2Theta;
// Opposite vectors: cross product is zero, rotate 180 degrees around any axis perpendicular to 'from'
if ((lengths > 0.0f) && (result.w <= lengths*EPSILON))
{
if (fabsf(from.x) > fabsf(from.z))
{
result.x = -from.y;
result.y = from.x;
result.z = 0.0f;
}
else
{
result.x = 0.0f;
result.y = -from.z;
result.z = from.y;
}
result.w = 0.0f;
}
// QuaternionNormalize(q); // QuaternionNormalize(q);
// NOTE: Normalize to essentially nlerp the original and identity to 0.5 // NOTE: Normalize to essentially nlerp the original and identity to 0.5
@ -2717,9 +2738,9 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio
translation->z = mat.m14; translation->z = mat.m14;
// Matrix Columns - Rotation will be extracted into here // Matrix Columns - Rotation will be extracted into here
Vector3 matColumns[3] = {{ mat.m0, mat.m4, mat.m8 }, Vector3 matColumns[3] = {{ mat.m0, mat.m1, mat.m2 },
{ mat.m1, mat.m5, mat.m9 }, { mat.m4, mat.m5, mat.m6 },
{ mat.m2, mat.m6, mat.m10 }}; { mat.m8, mat.m9, mat.m10 }};
// Shear Parameters XY, XZ, and YZ (extract and ignored) // Shear Parameters XY, XZ, and YZ (extract and ignored)
float shear[3] = { 0 }; float shear[3] = { 0 };
@ -2783,9 +2804,9 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio
*scale = Vector3Scale(scl, stabilizer); *scale = Vector3Scale(scl, stabilizer);
// Extract Rotation // Extract Rotation
Matrix rotationMatrix = { matColumns[0].x, matColumns[0].y, matColumns[0].z, 0, Matrix rotationMatrix = { matColumns[0].x, matColumns[1].x, matColumns[2].x, 0,
matColumns[1].x, matColumns[1].y, matColumns[1].z, 0, matColumns[0].y, matColumns[1].y, matColumns[2].y, 0,
matColumns[2].x, matColumns[2].y, matColumns[2].z, 0, matColumns[0].z, matColumns[1].z, matColumns[2].z, 0,
0, 0, 0, 1 }; 0, 0, 0, 1 };
*rotation = QuaternionFromMatrix(rotationMatrix); *rotation = QuaternionFromMatrix(rotationMatrix);
} }

View File

@ -4174,31 +4174,45 @@ RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius)
Vector3 raySpherePos = Vector3Subtract(center, ray.position); Vector3 raySpherePos = Vector3Subtract(center, ray.position);
float vector = Vector3DotProduct(raySpherePos, ray.direction); float vector = Vector3DotProduct(raySpherePos, ray.direction);
float distance = Vector3Length(raySpherePos); float distanceToCenter = Vector3Length(raySpherePos);
float d = radius*radius - (distance*distance - vector*vector); float d = radius*radius - (distanceToCenter*distanceToCenter - vector*vector);
collision.hit = d >= 0.0f; // Check if the ray's line intersects with the sphere
if (d >= 0.0f)
{
Vector3 point = { 0 };
Vector3 normal = { 0 };
float hitDistance = 0.0f;
// Check if ray origin is inside the sphere to calculate the correct collision point // Check if ray origin is inside the sphere to calculate the correct collision point
if (distance < radius) if (distanceToCenter < radius)
{ {
collision.distance = vector + sqrtf(d); hitDistance = vector + sqrtf(d);
// Calculate collision point // Calculate collision point
collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance)); point = Vector3Add(ray.position, Vector3Scale(ray.direction, hitDistance));
// Calculate collision normal (pointing outwards) // Calculate collision normal (pointing outwards)
collision.normal = Vector3Negate(Vector3Normalize(Vector3Subtract(collision.point, center))); normal = Vector3Negate(Vector3Normalize(Vector3Subtract(point, center)));
} }
else else
{ {
collision.distance = vector - sqrtf(d); hitDistance = vector - sqrtf(d);
// Calculate collision point // Calculate collision point
collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance)); point = Vector3Add(ray.position, Vector3Scale(ray.direction, hitDistance));
// Calculate collision normal (pointing inwards) // Calculate collision normal (pointing inwards)
collision.normal = Vector3Normalize(Vector3Subtract(collision.point, center)); normal = Vector3Normalize(Vector3Subtract(point, center));
}
if (hitDistance >= 0.0f)
{
collision.hit = true;
collision.point = point;
collision.normal = normal;
collision.distance = hitDistance;
}
} }
return collision; return collision;

View File

@ -4242,29 +4242,15 @@ void ImageDrawImageEx(Image *dst, Image src, Vector2 position, float rotation, f
Color srcColor = GetImageColor(src, srcX, srcY); Color srcColor = GetImageColor(src, srcX, srcY);
// Apply tint
srcColor.r = (unsigned char)(srcColor.r*tint.r/255.0f);
srcColor.g = (unsigned char)(srcColor.g*tint.g/255.0f);
srcColor.b = (unsigned char)(srcColor.b*tint.b/255.0f);
srcColor.a = (unsigned char)(srcColor.a*tint.a/255.0f);
// Skip fully transparent pixels // Skip fully transparent pixels
if (srcColor.a == 0) continue; if (srcColor.a == 0) continue;
// Read destination pixel for alpha blending // Read destination pixel and blend source over it, applying tint
// NOTE: ColorAlphaBlend() takes destination alpha into account,
// same as ImageDrawImagePro(), required to draw on transparent images
Color dstColor = GetImageColor(*dst, x, y); Color dstColor = GetImageColor(*dst, x, y);
unsigned int alpha = srcColor.a; ImageDrawPixel(dst, x, y, ColorAlphaBlend(dstColor, srcColor, tint));
unsigned int invA = 255 - alpha;
Color out = {
(unsigned char)((srcColor.r*alpha + dstColor.r*invA)/255), // red
(unsigned char)((srcColor.g*alpha + dstColor.g*invA)/255), // green
(unsigned char)((srcColor.b*alpha + dstColor.b*invA)/255), // blue
(unsigned char)(alpha + (dstColor.a*invA)/255) // alpha
};
ImageDrawPixel(dst, x, y, out);
} }
} }
} }

View File

@ -1161,7 +1161,8 @@ int main(int argc, char *argv[])
// Validate: example screenshot is not the template default one // Validate: example screenshot is not the template default one
Image imScreenshot = LoadImage(TextFormat("%s/%s/%s.png", exBasePath, exInfo->category, exInfo->name)); Image imScreenshot = LoadImage(TextFormat("%s/%s/%s.png", exBasePath, exInfo->category, exInfo->name));
Image imTemplate = LoadImage(TextFormat("%s/examples_template.png", exBasePath)); Image imTemplate = LoadImage(TextFormat("%s/examples_template.png", exBasePath));
if (memcmp(imScreenshot.data, imTemplate.data, GetPixelDataSize(imScreenshot.width, imScreenshot.height, imScreenshot.format)) == 0) bool imSameSize = (imScreenshot.width == imTemplate.width) && (imScreenshot.height == imTemplate.height);
if (imSameSize && (memcmp(imScreenshot.data, imTemplate.data, GetPixelDataSize(imScreenshot.width, imScreenshot.height, imScreenshot.format)) == 0))
exInfo->status |= VALID_INVALID_PNG; exInfo->status |= VALID_INVALID_PNG;
UnloadImage(imTemplate); UnloadImage(imTemplate);
UnloadImage(imScreenshot); UnloadImage(imScreenshot);