18 Commits

Author SHA1 Message Date
fdc8b37391 [examples][shapes_rlgl_color_wheel] Remove cast from negative float to unsigned int (#6258) 2026-10-12 01:30:02 +02:00
Ray
795ec32880 REVIEWED: text_animations 2026-10-11 20:44:47 +02:00
Ray
76ddc33b02 Update rmodels.c 2026-10-11 20:40:19 +02:00
97bf3160dc [rmodels] Smarter use of GPU and CPU skinning (#5921)
* Enable GPU skinning in the default build.
Have the model animation update functions check the current shader to see if they are going to do GPU skinning or not.
Lazy load the CPU animation buffers so they don't get allocated if the user is doing GPU skinning.
This change allows both GPU and CPU skinning in the same program.

* rlparser: update raylib_api.* by CI

* Fix name conflict in custom example

* Update comment per PR#5921 feedback
Merge with master

* rlparser: update raylib_api.* by CI

* REVIEWED: Update model animations

* rlparser: update raylib_api.* by CI

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ray <raysan5@gmail.com>
2026-10-11 20:37:22 +02:00
2c620574ab Update gcl native raylib module link and version (#6256)
I moved the programming language to a separate repository to keep everything organized.

By the way, the Raylib module and additional Raylib modules, such as `#native <Raylib>` and `#native <Raygui>`, including their submodules and compiled binaries (`.dll`, `.so`, etc.), cannot be kept outside the repository because they are built directly by GCL.

This is not just a simple wrapper or binding system. It is a built-in module project. It would be a bit disappointing if this becomes an issue, because I'm working on something beyond basic Raylib bindings and simple wrappers.

Here are some examples of the built-in modules I'm working on:

* `#native <RaylibFPS>` — `.dll`, `.so`
* `#native <RaylibSimpleCollision>` — `.dll`, `.so`
* `#native <RaylibSimpleMesh>` — `.dll`, `.so`
* `#native <RaylibSimpleLight>` — `.dll`, `.so`
* `#native <RaylibShader>` — `.dll`, `.so`
* `#native <RaylibSkybox>` — `.dll`, `.so`
* `#native <RaylibFOG>` — `.dll`, `.so`
* `#native <RaylibSimpleWater>` — `.dll`, `.so`
2026-10-11 20:34:29 +02:00
Ray
02a65e3df6 REVIEWED: example: text_animations 2026-10-11 20:30:54 +02:00
a7cf7e74b9 [rcore][win32] Implement full scancode-based key mapping (#6255) 2026-10-11 19:57:09 +02:00
c284ea62de [rcore][GLFW] Fix window size not restored when leaving borderless-windowed mode (#6253) 2026-10-11 19:48:55 +02:00
1a615c9e64 [examples] Added text_animations (#6250)
* Added shapes drag puzzle example

* Aligned to raylib code conventions and moved the example to shapes

* Fixed Makefile.Web updates

* Implemented a waving text animation

* Added key bindings to change the paramaters in game

* Added a flashing animation

* Added shaking text animation

* Fixed code formating

* Added the example using the rexm tool

* Fixed warnings and moved animation logic out of drawing mode

* Fixed hard coded animations size

* Adjusted animationSize initialization
2026-10-11 19:47:25 +02:00
ae96b95c38 [rlsw] Coerce texture format to framebuffer format (#6235)
Fixes #5978
2026-10-11 19:45:38 +02:00
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
24 changed files with 1550 additions and 302 deletions

View File

@ -124,7 +124,7 @@ This is a set of recomendations and guidelines for binding authors, meant to hel
| [Rayua](https://github.com/uiua-lang/rayua) | **5.5** | [Uiua](https://www.uiua.org/) | **???** | | [Rayua](https://github.com/uiua-lang/rayua) | **5.5** | [Uiua](https://www.uiua.org/) | **???** |
| [Target](https://github.com/FinnDemonCat/Target/tree/main/lib/raylib) | **5.5** | [Dart](https://dart.dev/) | Apache-2.0 license | | [Target](https://github.com/FinnDemonCat/Target/tree/main/lib/raylib) | **5.5** | [Dart](https://dart.dev/) | Apache-2.0 license |
| [mach-raylib](https://github.com/angluca/mach-raylib) | **6.x-dev** | [Mach](https://machlang.org/) | MIT | | [mach-raylib](https://github.com/angluca/mach-raylib) | **6.x-dev** | [Mach](https://machlang.org/) | MIT |
| [gcl native raylib module](https://github.com/gnuchanos/GnuchanOS/tree/main/language) | **6.0** | [gclang](https://github.com/gnuchanos/GnuchanOS/tree/main/language) | GPLv3 | | [gcl native raylib module](https://github.com/gnuchanos/gcl/blob/main/src/Modules/gcl_raylib.c) | **6.x-dev** | [gcl](https://github.com/gnuchanos/gcl) | GPLv3 |
### Utility Wrappers ### Utility Wrappers

View File

@ -4,14 +4,14 @@ 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
@ -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

@ -672,6 +672,7 @@ TEXTURES = \
TEXT = \ TEXT = \
text/text_3d_drawing \ text/text_3d_drawing \
text/text_animations \
text/text_codepoints_loading \ text/text_codepoints_loading \
text/text_font_filters \ text/text_font_filters \
text/text_font_loading \ text/text_font_loading \

View File

@ -633,6 +633,7 @@ TEXTURES = \
TEXT = \ TEXT = \
text/text_3d_drawing \ text/text_3d_drawing \
text/text_animations \
text/text_codepoints_loading \ text/text_codepoints_loading \
text/text_font_filters \ text/text_font_filters \
text/text_font_loading \ text/text_font_loading \
@ -1172,6 +1173,9 @@ text/text_3d_drawing: text/text_3d_drawing.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file text/resources/shaders/glsl100/alpha_discard.fs@resources/shaders/glsl100/alpha_discard.fs --preload-file text/resources/shaders/glsl100/alpha_discard.fs@resources/shaders/glsl100/alpha_discard.fs
text/text_animations: text/text_animations.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
text/text_codepoints_loading: text/text_codepoints_loading.c text/text_codepoints_loading: text/text_codepoints_loading.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file text/resources/DotGothic16-Regular.ttf@resources/DotGothic16-Regular.ttf --preload-file text/resources/DotGothic16-Regular.ttf@resources/DotGothic16-Regular.ttf

View File

@ -19,7 +19,7 @@ Run the following commands from the repository root:
- `zig build [module]` to compile all examples for a module (e.g. `zig build core`) - `zig build [module]` to compile all examples for a module (e.g. `zig build core`)
- `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`) - `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`)
## EXAMPLES COLLECTION [TOTAL: 222] ## EXAMPLES COLLECTION [TOTAL: 223]
### category: core [49] ### category: core [49]
@ -169,7 +169,7 @@ Examples using raylib textures functionality, including image/textures loading/g
| [textures_framebuffer_rendering](textures/textures_framebuffer_rendering.c) | <img src="textures/textures_framebuffer_rendering.png" alt="textures_framebuffer_rendering" width="80"> | ⭐⭐☆☆ | 5.6 | 5.6 | [Jack Boakes](https://github.com/jackboakes) | | [textures_framebuffer_rendering](textures/textures_framebuffer_rendering.c) | <img src="textures/textures_framebuffer_rendering.png" alt="textures_framebuffer_rendering" width="80"> | ⭐⭐☆☆ | 5.6 | 5.6 | [Jack Boakes](https://github.com/jackboakes) |
| [textures_portal_window](textures/textures_portal_window.c) | <img src="textures/textures_portal_window.png" alt="textures_portal_window" width="80"> | ⭐⭐⭐⭐️ | 6.0 | 6.0 | [PanicTitan](https://github.com/PanicTitan) | | [textures_portal_window](textures/textures_portal_window.c) | <img src="textures/textures_portal_window.png" alt="textures_portal_window" width="80"> | ⭐⭐⭐⭐️ | 6.0 | 6.0 | [PanicTitan](https://github.com/PanicTitan) |
### category: text [16] ### category: text [17]
Examples using raylib text functionality, including sprite fonts loading/generation and text drawing, provided by raylib [text](../src/rtext.c) module. Examples using raylib text functionality, including sprite fonts loading/generation and text drawing, provided by raylib [text](../src/rtext.c) module.
@ -191,6 +191,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat
| [text_inline_styling](text/text_inline_styling.c) | <img src="text/text_inline_styling.png" alt="text_inline_styling" width="80"> | ⭐⭐⭐☆ | 6.0 | 6.0 | [Wagner Barongello](https://github.com/SultansOfCode) | | [text_inline_styling](text/text_inline_styling.c) | <img src="text/text_inline_styling.png" alt="text_inline_styling" width="80"> | ⭐⭐⭐☆ | 6.0 | 6.0 | [Wagner Barongello](https://github.com/SultansOfCode) |
| [text_words_alignment](text/text_words_alignment.c) | <img src="text/text_words_alignment.png" alt="text_words_alignment" width="80"> | ⭐☆☆☆ | 6.0 | 6.0 | [JP Mortiboys](https://github.com/themushroompirates) | | [text_words_alignment](text/text_words_alignment.c) | <img src="text/text_words_alignment.png" alt="text_words_alignment" width="80"> | ⭐☆☆☆ | 6.0 | 6.0 | [JP Mortiboys](https://github.com/themushroompirates) |
| [text_strings_management](text/text_strings_management.c) | <img src="text/text_strings_management.png" alt="text_strings_management" width="80"> | ⭐⭐⭐☆ | 6.0 | 6.0 | [David Buzatto](https://github.com/davidbuzatto) | | [text_strings_management](text/text_strings_management.c) | <img src="text/text_strings_management.png" alt="text_strings_management" width="80"> | ⭐⭐⭐☆ | 6.0 | 6.0 | [David Buzatto](https://github.com/davidbuzatto) |
| [text_animations](text/text_animations.c) | <img src="text/text_animations.png" alt="text_animations" width="80"> | ⭐☆☆☆ | 6.0 | 6.0 | [Gabriel Piangers](https://github.com/gabriel-piangers) |
### category: models [32] ### category: models [32]

View File

@ -152,6 +152,7 @@ text;text_codepoints_loading;★★★☆;4.2;4.2;2022;2025;"Ramon Santamaria";@
text;text_inline_styling;★★★☆;6.0;6.0;2025;2025;"Wagner Barongello";@SultansOfCode text;text_inline_styling;★★★☆;6.0;6.0;2025;2025;"Wagner Barongello";@SultansOfCode
text;text_words_alignment;★☆☆☆;6.0;6.0;2025;2025;"JP Mortiboys";@themushroompirates text;text_words_alignment;★☆☆☆;6.0;6.0;2025;2025;"JP Mortiboys";@themushroompirates
text;text_strings_management;★★★☆;6.0;6.0;2025;2025;"David Buzatto";@davidbuzatto text;text_strings_management;★★★☆;6.0;6.0;2025;2025;"David Buzatto";@davidbuzatto
text;text_animations;★☆☆☆;6.0;6.0;2026;2026;"Gabriel Piangers";@gabriel-piangers
models;models_loading_iqm;★★☆☆;2.5;3.5;2019;2025;"Culacant";@culacant models;models_loading_iqm;★★☆☆;2.5;3.5;2019;2025;"Culacant";@culacant
models;models_billboard_rendering;★★★☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5 models;models_billboard_rendering;★★★☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5
models;models_box_collisions;★☆☆☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5 models;models_box_collisions;★☆☆☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5

View File

@ -43,7 +43,7 @@
// Module Functions Declaration // Module Functions Declaration
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
static bool IsUpperBodyBone(const char *boneName); static bool IsUpperBodyBone(const char *boneName);
static void UpdateModelAnimationBones(Model *model, ModelAnimation *anim1, int frame1, static void UpdateModelAnimationBoneCustom(Model *model, ModelAnimation *anim1, int frame1,
ModelAnimation *anim2, int frame2, float blend, bool upperBodyBlend); ModelAnimation *anim2, int frame2, float blend, bool upperBodyBlend);
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -117,7 +117,7 @@ int main(void)
// When upperBodyBlend is ON: upper body = attack (1.0), lower body = walk (0.0) // When upperBodyBlend is ON: upper body = attack (1.0), lower body = walk (0.0)
// When upperBodyBlend is OFF: uniform blend at 0.5 (50% walk, 50% attack) // When upperBodyBlend is OFF: uniform blend at 0.5 (50% walk, 50% attack)
float blendFactor = (upperBodyBlend? 1.0f : 0.5f); float blendFactor = (upperBodyBlend? 1.0f : 0.5f);
UpdateModelAnimationBones(&model, &anim0, animCurrentFrame0, UpdateModelAnimationBoneCustom(&model, &anim0, animCurrentFrame0,
&anim1, animCurrentFrame1, blendFactor, upperBodyBlend); &anim1, animCurrentFrame1, blendFactor, upperBodyBlend);
// raylib provided animation blending function // raylib provided animation blending function
@ -194,7 +194,7 @@ static bool IsUpperBodyBone(const char *boneName)
} }
// Blend two animations per-bone with selective upper/lower body blending // Blend two animations per-bone with selective upper/lower body blending
static void UpdateModelAnimationBones(Model *model, ModelAnimation *anim0, int frame0, static void UpdateModelAnimationBoneCustom(Model *model, ModelAnimation *anim0, int frame0,
ModelAnimation *anim1, int frame1, float blend, bool upperBodyBlend) ModelAnimation *anim1, int frame1, float blend, bool upperBodyBlend)
{ {
// Validate inputs // Validate inputs

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

@ -1,4 +1,4 @@
/******************************************************************************************* /*******************************************************************************************
* *
* raylib [shapes] example - rlgl color wheel * raylib [shapes] example - rlgl color wheel
* *
@ -74,8 +74,8 @@ int main(void)
{ {
// Update // Update
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
triangleCount += (unsigned int)GetMouseWheelMove(); float wheel = roundf(GetMouseWheelMove());
triangleCount = (unsigned int)Clamp((float)triangleCount, (float)pointsMin, (float)pointsMax); triangleCount = (unsigned int)Clamp((float)triangleCount + wheel, (float)pointsMin, (float)pointsMax);
Rectangle sliderRectangle = { 42.0f, 16.0f + 64.0f + 45.0f, 64.0f, 16.0f }; Rectangle sliderRectangle = { 42.0f, 16.0f + 64.0f + 45.0f, 64.0f, 16.0f };
Vector2 mousePosition = GetMousePosition(); Vector2 mousePosition = GetMousePosition();

263
examples/text/reasings.h Normal file
View File

@ -0,0 +1,263 @@
/*******************************************************************************************
*
* reasings - raylib easings library, based on Robert Penner library
*
* Useful easing functions for values animation
*
* This header uses:
* #define REASINGS_STATIC_INLINE // Inlines all functions code, so it runs faster.
* // This requires lots of memory on system.
* How to use:
* The four inputs t,b,c,d are defined as follows:
* t = current time (in any unit measure, but same unit as duration)
* b = starting value to interpolate
* c = the total change in value of b that needs to occur
* d = total time it should take to complete (duration)
*
* Example:
*
* int currentTime = 0;
* int duration = 100;
* float startPositionX = 0.0f;
* float finalPositionX = 30.0f;
* float currentPositionX = startPositionX;
*
* while (currentPositionX < finalPositionX)
* {
* currentPositionX = EaseSineIn(currentTime, startPositionX, finalPositionX - startPositionX, duration);
* currentTime++;
* }
*
* A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/)
*
* Robert Penner License
* ---------------------------------------------------------------------------------
* Open source under the BSD License.
*
* Copyright (c) 2001 Robert Penner. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------------
*
* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef REASINGS_H
#define REASINGS_H
#define REASINGS_STATIC_INLINE // NOTE: By default, compile functions as static inline
#if defined(REASINGS_STATIC_INLINE)
#define EASEDEF static inline
#else
#define EASEDEF extern
#endif
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), powf()
#ifndef PI
#define PI 3.14159265358979323846f //Required as PI is not always defined in math.h
#endif
#if defined(__cplusplus)
extern "C" { // Prevents name mangling of functions
#endif
// Linear Easing functions
EASEDEF float EaseLinearNone(float t, float b, float c, float d) { return (c*t/d + b); } // Ease: Linear
EASEDEF float EaseLinearIn(float t, float b, float c, float d) { return (c*t/d + b); } // Ease: Linear In
EASEDEF float EaseLinearOut(float t, float b, float c, float d) { return (c*t/d + b); } // Ease: Linear Out
EASEDEF float EaseLinearInOut(float t, float b, float c, float d) { return (c*t/d + b); } // Ease: Linear In Out
// Sine Easing functions
EASEDEF float EaseSineIn(float t, float b, float c, float d) { return (-c*cosf(t/d*(PI/2.0f)) + c + b); } // Ease: Sine In
EASEDEF float EaseSineOut(float t, float b, float c, float d) { return (c*sinf(t/d*(PI/2.0f)) + b); } // Ease: Sine Out
EASEDEF float EaseSineInOut(float t, float b, float c, float d) { return (-c/2.0f*(cosf(PI*t/d) - 1.0f) + b); } // Ease: Sine In Out
// Circular Easing functions
EASEDEF float EaseCircIn(float t, float b, float c, float d) { t /= d; return (-c*(sqrtf(1.0f - t*t) - 1.0f) + b); } // Ease: Circular In
EASEDEF float EaseCircOut(float t, float b, float c, float d) { t = t/d - 1.0f; return (c*sqrtf(1.0f - t*t) + b); } // Ease: Circular Out
EASEDEF float EaseCircInOut(float t, float b, float c, float d) // Ease: Circular In Out
{
if ((t/=d/2.0f) < 1.0f) return (-c/2.0f*(sqrtf(1.0f - t*t) - 1.0f) + b);
t -= 2.0f; return (c/2.0f*(sqrtf(1.0f - t*t) + 1.0f) + b);
}
// Cubic Easing functions
EASEDEF float EaseCubicIn(float t, float b, float c, float d) { t /= d; return (c*t*t*t + b); } // Ease: Cubic In
EASEDEF float EaseCubicOut(float t, float b, float c, float d) { t = t/d - 1.0f; return (c*(t*t*t + 1.0f) + b); } // Ease: Cubic Out
EASEDEF float EaseCubicInOut(float t, float b, float c, float d) // Ease: Cubic In Out
{
if ((t/=d/2.0f) < 1.0f) return (c/2.0f*t*t*t + b);
t -= 2.0f; return (c/2.0f*(t*t*t + 2.0f) + b);
}
// Quadratic Easing functions
EASEDEF float EaseQuadIn(float t, float b, float c, float d) { t /= d; return (c*t*t + b); } // Ease: Quadratic In
EASEDEF float EaseQuadOut(float t, float b, float c, float d) { t /= d; return (-c*t*(t - 2.0f) + b); } // Ease: Quadratic Out
EASEDEF float EaseQuadInOut(float t, float b, float c, float d) // Ease: Quadratic In Out
{
if ((t/=d/2) < 1) return (((c/2)*(t*t)) + b);
return (-c/2.0f*(((t - 1.0f)*(t - 3.0f)) - 1.0f) + b);
}
// Exponential Easing functions
EASEDEF float EaseExpoIn(float t, float b, float c, float d) { return (t == 0.0f) ? b : (c*powf(2.0f, 10.0f*(t/d - 1.0f)) + b); } // Ease: Exponential In
EASEDEF float EaseExpoOut(float t, float b, float c, float d) { return (t == d) ? (b + c) : (c*(-powf(2.0f, -10.0f*t/d) + 1.0f) + b); } // Ease: Exponential Out
EASEDEF float EaseExpoInOut(float t, float b, float c, float d) // Ease: Exponential In Out
{
if (t == 0.0f) return b;
if (t == d) return (b + c);
if ((t/=d/2.0f) < 1.0f) return (c/2.0f*powf(2.0f, 10.0f*(t - 1.0f)) + b);
return (c/2.0f*(-powf(2.0f, -10.0f*(t - 1.0f)) + 2.0f) + b);
}
// Back Easing functions
EASEDEF float EaseBackIn(float t, float b, float c, float d) // Ease: Back In
{
float s = 1.70158f;
float postFix = t/=d;
return (c*(postFix)*t*((s + 1.0f)*t - s) + b);
}
EASEDEF float EaseBackOut(float t, float b, float c, float d) // Ease: Back Out
{
float s = 1.70158f;
t = t/d - 1.0f;
return (c*(t*t*((s + 1.0f)*t + s) + 1.0f) + b);
}
EASEDEF float EaseBackInOut(float t, float b, float c, float d) // Ease: Back In Out
{
float s = 1.70158f;
if ((t/=d/2.0f) < 1.0f)
{
s *= 1.525f;
return (c/2.0f*(t*t*((s + 1.0f)*t - s)) + b);
}
float postFix = t-=2.0f;
s *= 1.525f;
return (c/2.0f*((postFix)*t*((s + 1.0f)*t + s) + 2.0f) + b);
}
// Bounce Easing functions
EASEDEF float EaseBounceOut(float t, float b, float c, float d) // Ease: Bounce Out
{
if ((t/=d) < (1.0f/2.75f))
{
return (c*(7.5625f*t*t) + b);
}
else if (t < (2.0f/2.75f))
{
float postFix = t-=(1.5f/2.75f);
return (c*(7.5625f*(postFix)*t + 0.75f) + b);
}
else if (t < (2.5/2.75))
{
float postFix = t-=(2.25f/2.75f);
return (c*(7.5625f*(postFix)*t + 0.9375f) + b);
}
else
{
float postFix = t-=(2.625f/2.75f);
return (c*(7.5625f*(postFix)*t + 0.984375f) + b);
}
}
EASEDEF float EaseBounceIn(float t, float b, float c, float d) { return (c - EaseBounceOut(d - t, 0.0f, c, d) + b); } // Ease: Bounce In
EASEDEF float EaseBounceInOut(float t, float b, float c, float d) // Ease: Bounce In Out
{
if (t < d/2.0f) return (EaseBounceIn(t*2.0f, 0.0f, c, d)*0.5f + b);
else return (EaseBounceOut(t*2.0f - d, 0.0f, c, d)*0.5f + c*0.5f + b);
}
// Elastic Easing functions
EASEDEF float EaseElasticIn(float t, float b, float c, float d) // Ease: Elastic In
{
if (t == 0.0f) return b;
if ((t/=d) == 1.0f) return (b + c);
float p = d*0.3f;
float a = c;
float s = p/4.0f;
float postFix = a*powf(2.0f, 10.0f*(t-=1.0f));
return (-(postFix*sinf((t*d-s)*(2.0f*PI)/p )) + b);
}
EASEDEF float EaseElasticOut(float t, float b, float c, float d) // Ease: Elastic Out
{
if (t == 0.0f) return b;
if ((t/=d) == 1.0f) return (b + c);
float p = d*0.3f;
float a = c;
float s = p/4.0f;
return (a*powf(2.0f,-10.0f*t)*sinf((t*d-s)*(2.0f*PI)/p) + c + b);
}
EASEDEF float EaseElasticInOut(float t, float b, float c, float d) // Ease: Elastic In Out
{
if (t == 0.0f) return b;
if ((t/=d/2.0f) == 2.0f) return (b + c);
float p = d*(0.3f*1.5f);
float a = c;
float s = p/4.0f;
if (t < 1.0f)
{
float postFix = a*powf(2.0f, 10.0f*(t-=1.0f));
return -0.5f*(postFix*sinf((t*d-s)*(2.0f*PI)/p)) + b;
}
float postFix = a*powf(2.0f, -10.0f*(t-=1.0f));
return (postFix*sinf((t*d-s)*(2.0f*PI)/p)*0.5f + c + b);
}
#if defined(__cplusplus)
}
#endif
#endif // REASINGS_H

View File

@ -0,0 +1,158 @@
/*******************************************************************************************
*
* raylib [text] example - animations
*
* Example complexity rating: [★☆☆☆] 1/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by Gabriel Piangers (@gabriel-piangers) 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 Gabriel Piangers (@gabriel-piangers)
*
********************************************************************************************/
#include "raylib.h"
#include "reasings.h" // Required for: Easing functions
#include "raymath.h" // Required for: Clamp()
#define MAX_TEXT_LENGTH 64
#define TEXT_SPACING 4
// Animated text type
typedef struct {
char str[MAX_TEXT_LENGTH]; // Text to animate
Vector2 position; // Text position on screen
float delta; // Intensity of the effect (does not apply for flashing)
float offset; // Time offset (in frames) between each char
float duration; // Time duration (in frames) of the animation
} AnimatedText;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [text] example - animations");
char animations[3][MAX_TEXT_LENGTH] = { "Waving", "Flashing", "Shaking" };
int animationsSize = sizeof(animations)/sizeof(animations[0]);
int currentAnimation = 0;
AnimatedText text = { "This is an animated text!", { 200, 250 }, 24.0f, 6, 60 };
int frameCount = 0;
Vector2 glyphPosition[MAX_TEXT_LENGTH] = { 0 };
unsigned char glyphAlpha[MAX_TEXT_LENGTH] = { 0 };
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
frameCount++;
if (IsKeyPressed(KEY_S)) text.delta = Clamp(text.delta - 2.0f, 10.0f, 60.0f);
else if (IsKeyPressed(KEY_W)) text.delta = Clamp(text.delta + 2.0f, 10.0f, 60.0f);
if (IsKeyPressed(KEY_A)) text.duration = (int) Clamp((float) text.duration - 5.0f, 20.0f, 120.0f);
else if (IsKeyPressed(KEY_D)) text.duration = (int) Clamp((float) text.duration + 5.0f, 20.0f, 120.0f);
if (IsKeyPressed(KEY_Z)) text.offset = Clamp(text.offset - 1.0f, 0.0f, 15.0f);
else if (IsKeyPressed(KEY_X)) text.offset = Clamp(text.offset + 1.0f, 0.0f, 15.0f);
if (IsKeyPressed(KEY_Q)) currentAnimation = currentAnimation? currentAnimation - 1 : animationsSize - 1;
else if (IsKeyPressed(KEY_E)) currentAnimation = (currentAnimation + 1)%animationsSize;
for (unsigned int i = 0, offsetX = 0; i < TextLength(text.str); i++)
{
// NOTE: Calculating every glyph position by its width
glyphPosition[i] = (Vector2) { text.position.x + offsetX, text.position.y };
glyphAlpha[i] = 255U;
offsetX += (MeasureText(TextSubtext(text.str, i, 1), 30) + TEXT_SPACING);
}
switch (currentAnimation)
{
case 0: // Waving animation
{
for (unsigned int i = 0; i < TextLength(text.str); i++)
{
float time = (int) (frameCount + i*text.offset)%(int)text.duration;
if (time < text.duration/2) glyphPosition[i].y = EaseSineIn(time, text.position.y, text.delta, text.duration);
else glyphPosition[i].y = EaseSineOut(time, text.position.y + text.delta, -text.delta, text.duration);
}
} break;
case 1: // Flashing animation
{
for (unsigned int i = 0; i < TextLength(text.str); i++)
{
float time = (int) (frameCount + i*text.offset)%(int)text.duration;
glyphAlpha[i] = (unsigned char) EaseSineInOut(time, 255.0f, -255.0f, text.duration);
}
} break;
case 2: // Shaking animation
{
for (unsigned int i = 0; i < TextLength(text.str); i++)
{
float time = (int) (frameCount + i*text.offset)%(int)text.duration;
float deltaX = (float) GetRandomValue(-text.delta/10, text.delta/10);
float deltaY = (float) GetRandomValue(-text.delta/10, text.delta/10);
if (time < (text.duration/2))
{
glyphPosition[i].x = EaseLinearNone(time, glyphPosition[i].x, deltaX, text.duration/2);
glyphPosition[i].y = EaseLinearNone(time, text.position.y, deltaY, text.duration/2);
}
else
{
glyphPosition[i].x = EaseLinearNone(time - text.duration/2, glyphPosition[i].x + deltaX, -deltaX, text.duration/2);
glyphPosition[i].y = EaseLinearNone(time - text.duration/2, text.position.y + deltaY, -deltaY, text.duration/2);
}
}
} break;
default: break;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
DrawText(TextFormat("Duration (A | D): %d", text.duration), 20, 20, 20, GRAY);
DrawText(TextFormat("Delta (W | S): %.1f", text.delta), 20, 50, 20, GRAY);
DrawText(TextFormat("Offset (Z | X): %.1f", text.offset), 20, 80, 20, GRAY);
DrawText(TextFormat("Curent Animation (Q | E): %s", animations[currentAnimation]), 20, 110, 20, GRAY);
for (unsigned int i = 0; i < TextLength(text.str); i++)
{
// NOTE: Drawing text glyph by glyph, so, spacing is actually not used
DrawTextEx(GetFontDefault(), TextSubtext(text.str, i, 1), glyphPosition[i],
GetFontDefault().baseSize*3.0f, 0, (Color) { 200U, 122U, 255U, glyphAlpha[i] });
}
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

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

@ -0,0 +1,569 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug.DLL|ARM64">
<Configuration>Debug.DLL</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug.DLL|Win32">
<Configuration>Debug.DLL</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug.DLL|x64">
<Configuration>Debug.DLL</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release.DLL|ARM64">
<Configuration>Release.DLL</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release.DLL|Win32">
<Configuration>Release.DLL</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release.DLL|x64">
<Configuration>Release.DLL</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F42CD94A-7008-42AB-BABF-B2053B6E6D77}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>text_animations</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>text_animations</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|ARM64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|ARM64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|ARM64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|ARM64'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)..\..\examples\text</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/FS %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/FS %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
<Message>Copy Debug DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
<Message>Copy Debug DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug.DLL|ARM64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
<Message>Copy Debug DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy Release DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy Release DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release.DLL|ARM64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CompileAs>CompileAsC</CompileAs>
<RemoveUnreferencedCodeData>true</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy Release DLL to output directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\examples\text\text_animations.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\examples\examples.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\raylib\raylib.vcxproj">
<Project>{e89d61ac-55de-4482-afd4-df7242ebc859}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -465,6 +465,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_lights_bloom", "exa
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_amp_envelope", "examples\audio_amp_envelope.vcxproj", "{B767C0BE-CE22-4683-B671-0EF4E73676A5}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_amp_envelope", "examples\audio_amp_envelope.vcxproj", "{B767C0BE-CE22-4683-B671-0EF4E73676A5}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "text_animations", "examples\text_animations.vcxproj", "{F42CD94A-7008-42AB-BABF-B2053B6E6D77}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug.DLL|ARM64 = Debug.DLL|ARM64 Debug.DLL|ARM64 = Debug.DLL|ARM64
@ -5833,6 +5835,30 @@ Global
{B767C0BE-CE22-4683-B671-0EF4E73676A5}.Release|x64.Build.0 = Release|x64 {B767C0BE-CE22-4683-B671-0EF4E73676A5}.Release|x64.Build.0 = Release|x64
{B767C0BE-CE22-4683-B671-0EF4E73676A5}.Release|x86.ActiveCfg = Release|Win32 {B767C0BE-CE22-4683-B671-0EF4E73676A5}.Release|x86.ActiveCfg = Release|Win32
{B767C0BE-CE22-4683-B671-0EF4E73676A5}.Release|x86.Build.0 = Release|Win32 {B767C0BE-CE22-4683-B671-0EF4E73676A5}.Release|x86.Build.0 = Release|Win32
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug|ARM64.Build.0 = Debug|ARM64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug|x64.ActiveCfg = Debug|x64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug|x64.Build.0 = Debug|x64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug|x86.ActiveCfg = Debug|Win32
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Debug|x86.Build.0 = Debug|Win32
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release.DLL|x64.Build.0 = Release.DLL|x64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release.DLL|x86.Build.0 = Release.DLL|Win32
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release|ARM64.ActiveCfg = Release|ARM64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release|ARM64.Build.0 = Release|ARM64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release|x64.ActiveCfg = Release|x64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release|x64.Build.0 = Release|x64
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release|x86.ActiveCfg = Release|Win32
{F42CD94A-7008-42AB-BABF-B2053B6E6D77}.Release|x86.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -5995,7 +6021,7 @@ Global
{C54703BF-D68A-480D-BE27-49B62E45D582} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {C54703BF-D68A-480D-BE27-49B62E45D582} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
{9CD8BCAD-F212-4BCC-BA98-899743CE3279} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {9CD8BCAD-F212-4BCC-BA98-899743CE3279} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}
{0981CA28-E4A5-4DF1-987F-A41D09131EFC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {0981CA28-E4A5-4DF1-987F-A41D09131EFC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}
{6BFF72EA-7362-4A3B-B6E5-9A3655BBBDA3} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {6BFF72EA-7362-4A3B-B6E5-9A3655BBBDA3} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
{6777EC3C-077C-42FC-B4AD-B799CE55CCE4} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {6777EC3C-077C-42FC-B4AD-B799CE55CCE4} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}
{A61DAD9C-271C-4E95-81AA-DB4CD58564D4} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {A61DAD9C-271C-4E95-81AA-DB4CD58564D4} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
@ -6067,6 +6093,7 @@ Global
{69717464-8311-4E93-8787-E9046472F120} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} {69717464-8311-4E93-8787-E9046472F120} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
{C9B012F6-95F3-4DD5-ACCF-98283EA01D0E} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {C9B012F6-95F3-4DD5-ACCF-98283EA01D0E} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
{B767C0BE-CE22-4683-B671-0EF4E73676A5} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {B767C0BE-CE22-4683-B671-0EF4E73676A5} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}
{F42CD94A-7008-42AB-BABF-B2053B6E6D77} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29}

View File

@ -328,8 +328,9 @@
#define SUPPORT_MESH_GENERATION 1 #define SUPPORT_MESH_GENERATION 1
#endif #endif
#ifndef SUPPORT_GPU_SKINNING #ifndef SUPPORT_GPU_SKINNING
// GPU skinning disabled by default, some GPUs do not support more than 8 VBOs // GPU skinning enabled by default for GL3.3+,
#define SUPPORT_GPU_SKINNING 0 // Some GPUs do not support more than 8 VBOs so you may need to disable it if you have issues loading animated models
#define SUPPORT_GPU_SKINNING 1
#endif #endif
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------

14
src/external/rlsw.h vendored
View File

@ -4931,10 +4931,16 @@ void swTexStorage2D(int width, int height, SWinternalformat format)
case SW_R32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32; break; case SW_R32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32; break;
case SW_RGB32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32G32B32; break; case SW_RGB32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32G32B32; break;
case SW_RGBA32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32G32B32A32; break; case SW_RGBA32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32G32B32A32; break;
case SW_DEPTH_COMPONENT16: pixelFormat = SW_PIXELFORMAT_DEPTH_D16; break; case SW_DEPTH_COMPONENT16:
case SW_DEPTH_COMPONENT24: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break; case SW_DEPTH_COMPONENT24:
case SW_DEPTH_COMPONENT32: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break; case SW_DEPTH_COMPONENT32:
case SW_DEPTH_COMPONENT32F: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break; case SW_DEPTH_COMPONENT32F:
{
pixelFormat = SW_FRAMEBUFFER_DEPTH_FORMAT;
int requestedFormat = (format == SW_DEPTH_COMPONENT16)? SW_PIXELFORMAT_DEPTH_D16 : SW_PIXELFORMAT_DEPTH_D32;
if (requestedFormat != pixelFormat) SW_LOG("WARNING: RLSW: Coercing depth internalformat %d to framebuffer depth format\n", format);
break;
}
default: RLSW.errCode = SW_INVALID_ENUM; return; default: RLSW.errCode = SW_INVALID_ENUM; return;
} }

View File

@ -303,14 +303,16 @@ void ToggleBorderlessWindowed(void)
} }
else else
{ {
// Remove undecorated flag
// WARNING: Decorating the window resizes it, launching FramebufferSizeCallback() that
// overwrites screen size and position, so it must be done before restoring previous values
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
// Restore previous screen values // Restore previous screen values
CORE.Window.position = CORE.Window.previousPosition; CORE.Window.position = CORE.Window.previousPosition;
CORE.Window.screen = CORE.Window.previousScreen; CORE.Window.screen = CORE.Window.previousScreen;
// Remove undecorated flag
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
#if !defined(__APPLE__) && !defined(_GLFW_WAYLAND) #if !defined(__APPLE__) && !defined(_GLFW_WAYLAND)
// Make sure to restore size considering HighDPI scaling // Make sure to restore size considering HighDPI scaling
// NOTE: On Wayland, GLFW_SCALE_FRAMEBUFFER handles scaling, skip manual resize // NOTE: On Wayland, GLFW_SCALE_FRAMEBUFFER handles scaling, skip manual resize

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)
@ -156,6 +158,9 @@ static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL;
// Flags that have no operations to perform during an update // Flags that have no operations to perform during an update
#define FLAG_MASK_NO_UPDATE (FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT) #define FLAG_MASK_NO_UPDATE (FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT)
// Lowest extended-key scancode, start of keyboardKeyFromExtendedScancode[]
#define EXTENDED_KEY_OFFSET 0x1C
#define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_ACCELERATION_ARB 0x2003 #define WGL_ACCELERATION_ARB 0x2003
#define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_SUPPORT_OPENGL_ARB 0x2010
@ -480,190 +485,6 @@ static void *WglGetProcAddress(const char *procname)
return proc; return proc;
} }
// Get key from wparam (mapping)
static KeyboardKey GetKeyFromWparam(WPARAM wparam)
{
switch (wparam)
{
/* case VK_LBUTTON: return KEY_; */
/* case VK_RBUTTON: return KEY_; */
/* case VK_CANCEL: return KEY_; */
/* case VK_MBUTTON: return KEY_; */
/* case VK_XBUTTON1: return KEY_; */
/* case VK_XBUTTON2: return KEY_; */
/* case VK_BACK: return KEY_; */
/* case VK_TAB: return KEY_; */
/* case VK_CLEAR: return KEY_; */
case VK_RETURN: return KEY_ENTER;
/* case VK_SHIFT: return KEY_; */
/* case VK_CONTROL: return KEY_; */
/* case VK_MENU: return KEY_; */
/* case VK_PAUSE: return KEY_; */
/* case VK_CAPITAL: return KEY_; */
/* case VK_KANA: return KEY_; */
/* case VK_HANGUL: return KEY_; */
/* case VK_IME_ON: return KEY_; */
/* case VK_JUNJA: return KEY_; */
/* case VK_FINAL: return KEY_; */
/* case VK_HANJA: return KEY_; */
/* case VK_KANJI: return KEY_; */
/* case VK_IME_OFF: return KEY_; */
case VK_ESCAPE: return KEY_ESCAPE;
/* case VK_CONVERT: return KEY_; */
/* case VK_NONCONVERT: return KEY_; */
/* case VK_ACCEPT: return KEY_; */
/* case VK_MODECHANGE: return KEY_; */
case VK_SPACE: return KEY_SPACE;
/* case VK_PRIOR: return KEY_; */
/* case VK_NEXT: return KEY_; */
/* case VK_END: return KEY_; */
/* case VK_HOME: return KEY_; */
case VK_LEFT: return KEY_LEFT;
case VK_UP: return KEY_UP;
case VK_RIGHT: return KEY_RIGHT;
case VK_DOWN: return KEY_DOWN;
/* case VK_SELECT: return KEY_; */
/* case VK_PRINT: return KEY_; */
/* case VK_EXECUTE: return KEY_; */
/* case VK_SNAPSHOT: return KEY_; */
/* case VK_INSERT: return KEY_; */
/* case VK_DELETE: return KEY_; */
/* case VK_HELP: return KEY_; */
case '0': return KEY_ZERO;
case '1': return KEY_ONE;
case '2': return KEY_TWO;
case '3': return KEY_THREE;
case '4': return KEY_FOUR;
case '5': return KEY_FIVE;
case '6': return KEY_SIX;
case '7': return KEY_SEVEN;
case '8': return KEY_EIGHT;
case '9': return KEY_NINE;
/* case 0x3A-40: return KEY_; */
case 'A': return KEY_A;
case 'B': return KEY_B;
case 'C': return KEY_C;
case 'D': return KEY_D;
case 'E': return KEY_E;
case 'F': return KEY_F;
case 'G': return KEY_G;
case 'H': return KEY_H;
case 'I': return KEY_I;
case 'J': return KEY_J;
case 'K': return KEY_K;
case 'L': return KEY_L;
case 'M': return KEY_M;
case 'N': return KEY_N;
case 'O': return KEY_O;
case 'P': return KEY_P;
case 'Q': return KEY_Q;
case 'R': return KEY_R;
case 'S': return KEY_S;
case 'T': return KEY_T;
case 'U': return KEY_U;
case 'V': return KEY_V;
case 'W': return KEY_W;
case 'X': return KEY_X;
case 'Y': return KEY_Y;
case 'Z': return KEY_Z;
//case VK_LWIN: return KEY_;
//case VK_RWIN: return KEY_;
//case VK_APPS: return KEY_;
//case VK_SLEEP: return KEY_;
//case VK_NUMPAD0: return KEY_;
//case VK_NUMPAD1: return KEY_;
//case VK_NUMPAD2: return KEY_;
//case VK_NUMPAD3: return KEY_;
//case VK_NUMPAD4: return KEY_;
//case VK_NUMPAD5: return KEY_;
//case VK_NUMPAD6: return KEY_;
//case VK_NUMPAD7: return KEY_;
//case VK_NUMPAD8: return KEY_;
//case VK_NUMPAD9: return KEY_;
//case VK_MULTIPLY: return KEY_;
//case VK_ADD: return KEY_;
//case VK_SEPARATOR: return KEY_;
//case VK_SUBTRACT: return KEY_;
//case VK_DECIMAL: return KEY_;
//case VK_DIVIDE: return KEY_;
//case VK_F1: return KEY_;
//case VK_F2: return KEY_;
//case VK_F3: return KEY_;
//case VK_F4: return KEY_;
//case VK_F5: return KEY_;
//case VK_F6: return KEY_;
//case VK_F7: return KEY_;
//case VK_F8: return KEY_;
//case VK_F9: return KEY_;
//case VK_F10: return KEY_;
//case VK_F11: return KEY_;
//case VK_F12: return KEY_;
//case VK_F13: return KEY_;
//case VK_F14: return KEY_;
//case VK_F15: return KEY_;
//case VK_F16: return KEY_;
//case VK_F17: return KEY_;
//case VK_F18: return KEY_;
//case VK_F19: return KEY_;
//case VK_F20: return KEY_;
//case VK_F21: return KEY_;
//case VK_F22: return KEY_;
//case VK_F23: return KEY_;
//case VK_F24: return KEY_;
//case VK_NUMLOCK: return KEY_;
//case VK_SCROLL: return KEY_;
//case VK_LSHIFT: return KEY_;
//case VK_RSHIFT: return KEY_;
//case VK_LCONTROL: return KEY_;
//case VK_RCONTROL: return KEY_;
//case VK_LMENU: return KEY_;
//case VK_RMENU: return KEY_;
//case VK_BROWSER_BACK: return KEY_;
//case VK_BROWSER_FORWARD: return KEY_;
//case VK_BROWSER_REFRESH: return KEY_;
//case VK_BROWSER_STOP: return KEY_;
//case VK_BROWSER_SEARCH: return KEY_;
//case VK_BROWSER_FAVORITES: return KEY_;
//case VK_BROWSER_HOME: return KEY_;
//case VK_VOLUME_MUTE: return KEY_;
//case VK_VOLUME_DOWN: return KEY_;
//case VK_VOLUME_UP: return KEY_;
//case VK_MEDIA_NEXT_TRACK: return KEY_;
//case VK_MEDIA_PREV_TRACK: return KEY_;
//case VK_MEDIA_STOP: return KEY_;
//case VK_MEDIA_PLAY_PAUSE: return KEY_;
//case VK_LAUNCH_MAIL: return KEY_;
//case VK_LAUNCH_MEDIA_SELECT: return KEY_;
//case VK_LAUNCH_APP1: return KEY_;
//case VK_LAUNCH_APP2: return KEY_;
//case VK_OEM_1: return KEY_;
//case VK_OEM_PLUS: return KEY_;
//case VK_OEM_COMMA: return KEY_;
//case VK_OEM_MINUS: return KEY_;
//case VK_OEM_PERIOD: return KEY_;
//case VK_OEM_2: return KEY_;
//case VK_OEM_3: return KEY_;
//case VK_OEM_4: return KEY_;
//case VK_OEM_5: return KEY_;
//case VK_OEM_6: return KEY_;
//case VK_OEM_7: return KEY_;
//case VK_OEM_8: return KEY_;
//case VK_OEM_102: return KEY_;
//case VK_PROCESSKEY: return KEY_;
//case VK_PACKET: return KEY_;
//case VK_ATTN: return KEY_;
//case VK_CRSEL: return KEY_;
//case VK_EXSEL: return KEY_;
//case VK_EREOF: return KEY_;
//case VK_PLAY: return KEY_;
//case VK_ZOOM: return KEY_;
//case VK_NONAME: return KEY_;
//case VK_PA1: return KEY_;
//case VK_OEM_CLEAR: return KEY_;
default: return KEY_NULL;
}
}
// Get cursor name // Get cursor name
static LPCWSTR GetCursorName(int cursor) static LPCWSTR GetCursorName(int cursor)
{ {
@ -925,7 +746,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 +941,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
@ -1391,6 +1300,29 @@ void PollInputEvents(void)
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessageW(&msg); DispatchMessageW(&msg);
} }
// Windows will miss key up events for specific keys; check them manually
if ((GetKeyState(VK_LSHIFT) & 0x8000) == 0)
{
CORE.Input.Keyboard.currentKeyState[KEY_LEFT_SHIFT] = 0;
}
if ((GetKeyState(VK_RSHIFT) & 0x8000) == 0)
{
CORE.Input.Keyboard.currentKeyState[KEY_RIGHT_SHIFT] = 0;
}
if ((GetKeyState(VK_LWIN) & 0x8000) == 0)
{
CORE.Input.Keyboard.currentKeyState[KEY_LEFT_SUPER] = 0;
}
if ((GetKeyState(VK_RWIN) & 0x8000) == 0)
{
CORE.Input.Keyboard.currentKeyState[KEY_RIGHT_SUPER] = 0;
}
// Windows won't send a WM_KEYDOWN event for print screen; check it manually
bool isPrintScreenDown = ((GetAsyncKeyState(VK_SNAPSHOT) & 0x8000) != 0) && (GetForegroundWindow() == platform.hwnd);
CORE.Input.Keyboard.currentKeyState[KEY_PRINT_SCREEN] = isPrintScreenDown;
if (isPrintScreenDown && (CORE.Input.Keyboard.exitKey == KEY_PRINT_SCREEN)) CORE.Window.shouldClose = true;
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -1777,6 +1709,10 @@ void ClosePlatform(void)
if (platform.hwnd) if (platform.hwnd)
{ {
// SetWindowIcon uses the same resource for both ICON_BIG and ICON_SMALL
// 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); BOOL result = DestroyWindow(platform.hwnd);
if (!result) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed on window destroy [ERROR: %u]", GetLastError()); if (!result) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed on window destroy [ERROR: %u]", GetLastError());
@ -1784,9 +1720,17 @@ void ClosePlatform(void)
result = UnregisterClassW(CLASS_NAME, hInstance); result = UnregisterClassW(CLASS_NAME, hInstance);
if (!result) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed to unregister window class [ERROR: %u]", GetLastError()); 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; CORE.Window.flags = savedFlags;
#if SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP #if SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP
@ -2078,8 +2022,31 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
} }
} break; } break;
case WM_SYSKEYDOWN:
{
HandleKey(wparam, lparam, 1);
// WM_SYSKEYDOWN events should still call DefWindowProc to allow things like alt+F4 to work
result = DefWindowProcW(hwnd, msg, wparam, lparam);
} break;
case WM_SYSKEYUP:
{
HandleKey(wparam, lparam, 0);
result = DefWindowProcW(hwnd, msg, wparam, lparam);
} break;
case WM_KEYDOWN: HandleKey(wparam, lparam, 1); break; case WM_KEYDOWN: HandleKey(wparam, lparam, 1); break;
case WM_KEYUP: HandleKey(wparam, lparam, 0); break; case WM_KEYUP: HandleKey(wparam, lparam, 0); break;
case WM_SYSCOMMAND:
{
if ((wparam & 0xFFF0) == SC_KEYMENU)
{
// Prevent the window from freezing when pressing Alt or F10
result = 0;
}
else
{
result = DefWindowProcW(hwnd, msg, wparam, lparam);
}
} break;
case WM_LBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_LEFT, 1); break; case WM_LBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_LEFT, 1); break;
case WM_LBUTTONUP : HandleMouseButton(MOUSE_BUTTON_LEFT, 0); break; case WM_LBUTTONUP : HandleMouseButton(MOUSE_BUTTON_LEFT, 0); break;
case WM_RBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_RIGHT, 1); break; case WM_RBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_RIGHT, 1); break;
@ -2125,23 +2092,194 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
return result; return result;
} }
// Maps scancodes to Raylib keys
static const unsigned short keyboardKeyFromScancode[] =
{
[0x01] = KEY_ESCAPE,
[0x02] = KEY_ONE,
[0x03] = KEY_TWO,
[0x04] = KEY_THREE,
[0x05] = KEY_FOUR,
[0x06] = KEY_FIVE,
[0x07] = KEY_SIX,
[0x08] = KEY_SEVEN,
[0x09] = KEY_EIGHT,
[0x0A] = KEY_NINE,
[0x0B] = KEY_ZERO,
[0x0C] = KEY_MINUS,
[0x0D] = KEY_EQUAL,
[0x0E] = KEY_BACKSPACE,
[0x0F] = KEY_TAB,
[0x10] = KEY_Q,
[0x11] = KEY_W,
[0x12] = KEY_E,
[0x13] = KEY_R,
[0x14] = KEY_T,
[0x15] = KEY_Y,
[0x16] = KEY_U,
[0x17] = KEY_I,
[0x18] = KEY_O,
[0x19] = KEY_P,
[0x1A] = KEY_LEFT_BRACKET,
[0x1B] = KEY_RIGHT_BRACKET,
[0x1C] = KEY_ENTER,
[0x1D] = KEY_LEFT_CONTROL,
[0x1E] = KEY_A,
[0x1F] = KEY_S,
[0x20] = KEY_D,
[0x21] = KEY_F,
[0x22] = KEY_G,
[0x23] = KEY_H,
[0x24] = KEY_J,
[0x25] = KEY_K,
[0x26] = KEY_L,
[0x27] = KEY_SEMICOLON,
[0x28] = KEY_APOSTROPHE,
[0x29] = KEY_GRAVE,
[0x2A] = KEY_LEFT_SHIFT,
[0x2B] = KEY_BACKSLASH,
[0x2C] = KEY_Z,
[0x2D] = KEY_X,
[0x2E] = KEY_C,
[0x2F] = KEY_V,
[0x30] = KEY_B,
[0x31] = KEY_N,
[0x32] = KEY_M,
[0x33] = KEY_COMMA,
[0x34] = KEY_PERIOD,
[0x35] = KEY_SLASH,
[0x36] = KEY_RIGHT_SHIFT,
[0x37] = KEY_KP_MULTIPLY,
[0x38] = KEY_LEFT_ALT,
[0x39] = KEY_SPACE,
[0x3A] = KEY_CAPS_LOCK,
[0x3B] = KEY_F1,
[0x3C] = KEY_F2,
[0x3D] = KEY_F3,
[0x3E] = KEY_F4,
[0x3F] = KEY_F5,
[0x40] = KEY_F6,
[0x41] = KEY_F7,
[0x42] = KEY_F8,
[0x43] = KEY_F9,
[0x44] = KEY_F10,
[0x45] = KEY_PAUSE,
[0x46] = KEY_SCROLL_LOCK,
[0x47] = KEY_KP_7,
[0x48] = KEY_KP_8,
[0x49] = KEY_KP_9,
[0x4A] = KEY_KP_SUBTRACT,
[0x4B] = KEY_KP_4,
[0x4C] = KEY_KP_5,
[0x4D] = KEY_KP_6,
[0x4E] = KEY_KP_ADD,
[0x4F] = KEY_KP_1,
[0x50] = KEY_KP_2,
[0x51] = KEY_KP_3,
[0x52] = KEY_KP_0,
[0x53] = KEY_KP_DECIMAL,
[0x57] = KEY_F11,
[0x58] = KEY_F12,
[0x59] = KEY_KP_EQUAL,
// Duplicate scancodes
[0x54] = KEY_PRINT_SCREEN, // Alt+PrtSc sends the SysRq scancode
};
// Maps scancodes with extended-flag set to Raylib keys; lowest key is 0x1C
static const unsigned short keyboardKeyFromExtendedScancode[] =
{
[0x1C - EXTENDED_KEY_OFFSET] = KEY_KP_ENTER,
[0x1D - EXTENDED_KEY_OFFSET] = KEY_RIGHT_CONTROL,
[0x35 - EXTENDED_KEY_OFFSET] = KEY_KP_DIVIDE,
[0x37 - EXTENDED_KEY_OFFSET] = KEY_PRINT_SCREEN,
[0x38 - EXTENDED_KEY_OFFSET] = KEY_RIGHT_ALT,
[0x45 - EXTENDED_KEY_OFFSET] = KEY_NUM_LOCK,
[0x47 - EXTENDED_KEY_OFFSET] = KEY_HOME,
[0x48 - EXTENDED_KEY_OFFSET] = KEY_UP,
[0x49 - EXTENDED_KEY_OFFSET] = KEY_PAGE_UP,
[0x4B - EXTENDED_KEY_OFFSET] = KEY_LEFT,
[0x4D - EXTENDED_KEY_OFFSET] = KEY_RIGHT,
[0x4F - EXTENDED_KEY_OFFSET] = KEY_END,
[0x50 - EXTENDED_KEY_OFFSET] = KEY_DOWN,
[0x51 - EXTENDED_KEY_OFFSET] = KEY_PAGE_DOWN,
[0x52 - EXTENDED_KEY_OFFSET] = KEY_INSERT,
[0x53 - EXTENDED_KEY_OFFSET] = KEY_DELETE,
[0x5B - EXTENDED_KEY_OFFSET] = KEY_LEFT_SUPER,
[0x5C - EXTENDED_KEY_OFFSET] = KEY_RIGHT_SUPER,
[0x5D - EXTENDED_KEY_OFFSET] = KEY_KB_MENU,
// Duplicate scancodes
[0x46 - EXTENDED_KEY_OFFSET] = KEY_PAUSE, // Ctrl+Pause sends the Break scancode
[0x36 - EXTENDED_KEY_OFFSET] = KEY_RIGHT_SHIFT, // Some keyboards set the extended bit on Right Shift
};
// Handle keyboard input event // Handle keyboard input event
static void HandleKey(WPARAM wparam, LPARAM lparam, char state) static void HandleKey(WPARAM wparam, LPARAM lparam, char state)
{ {
KeyboardKey key = GetKeyFromWparam(wparam); bool isExtendedKey = ((HIWORD(lparam) & KF_EXTENDED) != 0);
// TODO: Use scancode? WORD scancode = LOBYTE(HIWORD(lparam));
//BYTE scancode = lparam >> 16; if (scancode == 0)
//TRACELOG(LOG_INFO, "KEY key=%d vk=%lu scan=%u = %u", key, wparam, scancode, state);
if (key != KEY_NULL)
{ {
CORE.Input.Keyboard.currentKeyState[key] = state; // Certain keys don't arrive with a scancode; fall back to virtual key mapping
scancode = MapVirtualKeyW((UINT)wparam, MAPVK_VK_TO_VSC);
if (((HIWORD(lparam) & KF_REPEAT) != 0) && (state == 1)) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; }
if ((key == CORE.Input.Keyboard.exitKey) && (state == 1)) CORE.Window.shouldClose = true;
KeyboardKey key = KEY_NULL;
if (isExtendedKey)
{
unsigned int index = scancode - EXTENDED_KEY_OFFSET;
unsigned int arrayLength = sizeof(keyboardKeyFromExtendedScancode)/sizeof(keyboardKeyFromExtendedScancode[0]);
if (index < arrayLength)
{
key = keyboardKeyFromExtendedScancode[index];
}
}
else
{
unsigned int arrayLength = sizeof(keyboardKeyFromScancode)/sizeof(keyboardKeyFromScancode[0]);
if (scancode < arrayLength)
{
key = keyboardKeyFromScancode[scancode];
}
}
bool ignoreKey = false;
if ((wparam == VK_CONTROL) && !isExtendedKey)
{
// Pressing AltGr causes Windows to send a fake Left Ctrl message
// GLFW does something similar in win32_window.c
MSG next = { 0 };
LONG time = GetMessageTime();
if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
{
// If the current message is Left Ctrl (VK_CONTROL) and the next message is AltGr (VK_MENU) with the exact same timestamp,
// silently drop the fake control key event
bool isNextExtendedKey = ((HIWORD(next.lParam) & KF_EXTENDED) != 0);
if ((next.wParam == VK_MENU) && ((LONG)next.time == time) && isNextExtendedKey)
{
if ((next.message == WM_KEYDOWN) || (next.message == WM_SYSKEYDOWN) || (next.message == WM_KEYUP) || (next.message == WM_SYSKEYUP))
{
ignoreKey = true;
}
}
}
}
if (!ignoreKey)
{
if (key != KEY_NULL)
{
CORE.Input.Keyboard.currentKeyState[key] = state;
if (((HIWORD(lparam) & KF_REPEAT) != 0) && (state == 1)) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
if ((key == CORE.Input.Keyboard.exitKey) && (state == 1)) CORE.Window.shouldClose = true;
}
else TRACELOG(LOG_WARNING, "INPUT: Unknown (or currently unhandled) virtual keycode %d (0x%x)", wparam, wparam);
} }
else TRACELOG(LOG_WARNING, "INPUT: Unknown (or currently unhandled) virtual keycode %d (0x%x)", wparam, wparam);
// TODO: Add key to the queue as well? // TODO: Add key to the queue as well?
} }

View File

@ -2304,11 +2304,9 @@ ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount)
return animations; return animations;
} }
// Update model animation data (vertex buffers / bone matrices) for a specific pose // Update model animation data (bone matrices) for a specific pose
// NOTE 1: Request frame could be fractional, using a lerp interpolation between two frames // NOTE 1: Request frame could be fractional, using a lerp interpolation between two frames
// NOTE 2: Updated vertex animation data is uploaded to GPU in case of CPU skinning, void UpdateModelAnimationBones(Model model, ModelAnimation anim, float frame)
// for GPU skinning, bone matrices are uploaded to shader on DrawModelEx()
void UpdateModelAnimation(Model model, ModelAnimation anim, float frame)
{ {
if (model.boneMatrices == NULL) return; if (model.boneMatrices == NULL) return;
@ -2360,6 +2358,18 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, float frame)
model.boneMatrices[boneIndex] = MatrixMultiply(MatrixInvert(bindPoseMatrix), currentPoseMatrix); model.boneMatrices[boneIndex] = MatrixMultiply(MatrixInvert(bindPoseMatrix), currentPoseMatrix);
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
} }
}
}
// Update model animation data (vertex buffers / bone matrices) for a specific pose
// NOTE 1: Request frame could be fractional, using a lerp interpolation between two frames
// NOTE 2: Updated vertex animation data is uploaded to GPU in case of CPU skinning,
// for GPU skinning, bone matrices are uploaded to shader on DrawModelEx()
void UpdateModelAnimation(Model model, ModelAnimation anim, float frame)
{
if ((anim.keyframeCount > 0) && (model.skeleton.bones != NULL) && (anim.keyframePoses != NULL))
{
UpdateModelAnimationBones(model, anim, frame);
// CPU skinning, updates CPU buffers and uploads them to GPU // CPU skinning, updates CPU buffers and uploads them to GPU
// NOTE: On GPU skinning not supported, use CPU skinning // NOTE: On GPU skinning not supported, use CPU skinning
@ -2367,12 +2377,10 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, float frame)
} }
} }
// Update model animation data (vertex buffers / bone matrices) for a specific pose, // Update model animation data (bone matrices) for a specific pose,
// defined by two different animations at specific frames blended together // defined by two different animations at specific frames blended together
// NOTE 1: Request frames could be fractional, using a lerp interpolation between two frames // NOTE 1: Request frames could be fractional, using a lerp interpolation between two frames
// NOTE 2: Updated vertex animation data is uploaded to GPU in case of CPU skinning, void UpdateModelAnimationBonesEx(Model model, ModelAnimation animA, float frameA, ModelAnimation animB, float frameB, float blend)
// for GPU skinning, bone matrices are uploaded to shader on DrawModelEx()
void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, ModelAnimation animB, float frameB, float blend)
{ {
if (model.boneMatrices == NULL) return; if (model.boneMatrices == NULL) return;
@ -2475,6 +2483,23 @@ void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, Mod
MatrixScale(boneScale.x, boneScale.y, boneScale.z)); MatrixScale(boneScale.x, boneScale.y, boneScale.z));
*/ */
} }
}
}
// Update model animation data (vertex buffers / bone matrices) for a specific pose,
// defined by two different animations at specific frames blended together
// NOTE 1: Request frames could be fractional, using a lerp interpolation between two frames
// NOTE 2: Updated vertex animation data is uploaded to GPU in case of CPU skinning,
// for GPU skinning, bone matrices are uploaded to shader on DrawModelEx()
void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, ModelAnimation animB, float frameB, float blend)
{
if (model.boneMatrices == NULL) return;
if ((animA.keyframeCount > 0) && (animA.keyframePoses != NULL) &&
(animB.keyframeCount > 0) && (animB.keyframePoses != NULL) &&
(blend >= 0.0f) && (blend <= 1.0f))
{
UpdateModelAnimationBonesEx(model, animA, frameA, animB, frameB, blend);
// CPU skinning, updates CPU buffers and uploads them to GPU (if available) // CPU skinning, updates CPU buffers and uploads them to GPU (if available)
// NOTE: Fallback in case GPU skinning is not supported or enabled // NOTE: Fallback in case GPU skinning is not supported or enabled
@ -2491,10 +2516,10 @@ static void UpdateModelAnimationVertexBuffers(Model model)
for (int m = 0; m < model.meshCount; m++) for (int m = 0; m < model.meshCount; m++)
{ {
Mesh mesh = model.meshes[m]; Mesh *mesh = model.meshes + m; // don't copy the mesh, we may need to allocate buffers
Vector3 animVertex = { 0 }; Vector3 animVertex = { 0 };
Vector3 animNormal = { 0 }; Vector3 animNormal = { 0 };
const int vertexValuesCount = mesh.vertexCount*3; const int vertexValuesCount = mesh->vertexCount*3;
int boneIndex = 0; int boneIndex = 0;
int boneCounter = 0; int boneCounter = 0;
@ -2502,11 +2527,28 @@ static void UpdateModelAnimationVertexBuffers(Model model)
bool bufferUpdateRequired = false; // Flag to check when anim vertex information is updated bool bufferUpdateRequired = false; // Flag to check when anim vertex information is updated
// Skip if missing bone data or missing anim buffers initialization // Skip if missing bone data or missing anim buffers initialization
if ((mesh.boneWeights == NULL) || (mesh.boneIndices == NULL) || if ((mesh->boneWeights == NULL) || (mesh->boneIndices == NULL)) continue;
(mesh.animVertices == NULL) || (mesh.animNormals == NULL)) continue;
// Skip if the shader is using the bones directly
#if defined (SUPPORT_GPU_SKINNING)
Material material = model.materials[model.meshMaterial[m]];
if ((material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1) ) continue;
#endif
// Lazy allocation of CPU animation buffers for vertex positions and normals,
// to be used on CPU software skinning
if (mesh->animVertices == NULL)
{
mesh->animVertices = (float *)RL_CALLOC(mesh->vertexCount*3, sizeof(float));
memcpy(mesh->animVertices, mesh->vertices, mesh->vertexCount*3*sizeof(float));
}
if ((mesh->normals != NULL) && (mesh->animNormals == NULL))
{
mesh->animNormals = (float *)RL_CALLOC(mesh->vertexCount*3, sizeof(float));
memcpy(mesh->animNormals, mesh->normals, mesh->vertexCount*3*sizeof(float));
}
// Normal matrix only depends on the bone, compute it once per bone instead of per vertex // Normal matrix only depends on the bone, compute it once per bone instead of per vertex
if ((mesh.normals != NULL) && !boneNormalsReady) if ((mesh->normals != NULL) && !boneNormalsReady)
{ {
memset(boneNormalMatrices, 0, 256*sizeof(Matrix)); memset(boneNormalMatrices, 0, 256*sizeof(Matrix));
for (unsigned int b = 0; (b < model.skeleton.boneCount) && (b < 256); b++) boneNormalMatrices[b] = MatrixTranspose(MatrixInvert(model.boneMatrices[b])); for (unsigned int b = 0; (b < model.skeleton.boneCount) && (b < 256); b++) boneNormalMatrices[b] = MatrixTranspose(MatrixInvert(model.boneMatrices[b]));
@ -2515,40 +2557,40 @@ static void UpdateModelAnimationVertexBuffers(Model model)
for (int vCounter = 0; vCounter < vertexValuesCount; vCounter += 3) for (int vCounter = 0; vCounter < vertexValuesCount; vCounter += 3)
{ {
mesh.animVertices[vCounter] = 0; mesh->animVertices[vCounter] = 0;
mesh.animVertices[vCounter + 1] = 0; mesh->animVertices[vCounter + 1] = 0;
mesh.animVertices[vCounter + 2] = 0; mesh->animVertices[vCounter + 2] = 0;
if (mesh.animNormals != NULL) if (mesh->animNormals != NULL)
{ {
mesh.animNormals[vCounter] = 0; mesh->animNormals[vCounter] = 0;
mesh.animNormals[vCounter + 1] = 0; mesh->animNormals[vCounter + 1] = 0;
mesh.animNormals[vCounter + 2] = 0; mesh->animNormals[vCounter + 2] = 0;
} }
// Iterates over 4 bones per vertex // Iterates over 4 bones per vertex
for (int j = 0; j < 4; j++, boneCounter++) for (int j = 0; j < 4; j++, boneCounter++)
{ {
boneWeight = mesh.boneWeights[boneCounter]; boneWeight = mesh->boneWeights[boneCounter];
boneIndex = mesh.boneIndices[boneCounter]; boneIndex = mesh->boneIndices[boneCounter];
// Early stop when no transformation will be applied // Early stop when no transformation will be applied
if (boneWeight == 0.0f) continue; if (boneWeight == 0.0f) continue;
animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] }; animVertex = (Vector3){ mesh->vertices[vCounter], mesh->vertices[vCounter + 1], mesh->vertices[vCounter + 2] };
animVertex = Vector3Transform(animVertex, model.boneMatrices[boneIndex]); animVertex = Vector3Transform(animVertex, model.boneMatrices[boneIndex]);
mesh.animVertices[vCounter] += animVertex.x*boneWeight; mesh->animVertices[vCounter] += animVertex.x*boneWeight;
mesh.animVertices[vCounter + 1] += animVertex.y*boneWeight; mesh->animVertices[vCounter + 1] += animVertex.y*boneWeight;
mesh.animVertices[vCounter + 2] += animVertex.z*boneWeight; mesh->animVertices[vCounter + 2] += animVertex.z*boneWeight;
bufferUpdateRequired = true; bufferUpdateRequired = true;
// Normals processing // Normals processing
// NOTE: Using meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) // NOTE: Using meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
if ((mesh.normals != NULL) && (mesh.animNormals != NULL )) if ((mesh->normals != NULL) && (mesh->animNormals != NULL ))
{ {
animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] }; animNormal = (Vector3){ mesh->normals[vCounter], mesh->normals[vCounter + 1], mesh->normals[vCounter + 2] };
animNormal = Vector3Transform(animNormal, boneNormalMatrices[boneIndex]); animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model.boneMatrices[boneIndex])));
mesh.animNormals[vCounter] += animNormal.x*boneWeight; mesh->animNormals[vCounter] += animNormal.x*boneWeight;
mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight; mesh->animNormals[vCounter + 1] += animNormal.y*boneWeight;
mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight; mesh->animNormals[vCounter + 2] += animNormal.z*boneWeight;
} }
} }
} }
@ -2556,8 +2598,8 @@ static void UpdateModelAnimationVertexBuffers(Model model)
if (bufferUpdateRequired) if (bufferUpdateRequired)
{ {
// Update GPU vertex buffers with updated data (position + normals) // Update GPU vertex buffers with updated data (position + normals)
rlUpdateVertexBuffer(mesh.vboId[SHADER_LOC_VERTEX_POSITION], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_POSITION], mesh->animVertices, mesh->vertexCount*3*sizeof(float), 0);
if (mesh.normals != NULL) rlUpdateVertexBuffer(mesh.vboId[SHADER_LOC_VERTEX_NORMAL], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0); if (mesh->normals != NULL) rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_NORMAL], mesh->animNormals, mesh->vertexCount*3*sizeof(float), 0);
} }
} }
} }
@ -4863,13 +4905,6 @@ static Model LoadIQM(const char *fileName)
model.meshes[i].triangleCount = imesh[i].num_triangles; model.meshes[i].triangleCount = imesh[i].num_triangles;
model.meshes[i].indices = (unsigned short *)RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short)); model.meshes[i].indices = (unsigned short *)RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
#if !SUPPORT_GPU_SKINNING
// Animated vertex data, processed for rendering
// NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
model.meshes[i].animVertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
model.meshes[i].animNormals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
#endif
} }
// Triangles data processing // Triangles data processing
@ -6369,13 +6404,6 @@ static Model LoadGLTF(const char *fileName)
} }
} }
#if !SUPPORT_GPU_SKINNING
// Animated vertex data (CPU skinning)
model.meshes[meshIndex].animVertices = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
model.meshes[meshIndex].animNormals = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
if (model.meshes[meshIndex].normals != NULL) memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
#endif
model.meshes[meshIndex].boneCount = model.skeleton.boneCount; model.meshes[meshIndex].boneCount = model.skeleton.boneCount;
meshIndex++; // Move to next mesh meshIndex++; // Move to next mesh
@ -7039,10 +7067,6 @@ static Model LoadM3D(const char *fileName)
{ {
model.meshes[k].boneIndices = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char)); model.meshes[k].boneIndices = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
model.meshes[k].boneWeights = (float *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(float)); model.meshes[k].boneWeights = (float *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(float));
#if !SUPPORT_GPU_SKINNING
model.meshes[k].animVertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
model.meshes[k].animNormals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
#endif
} }
model.meshMaterial[k] = mi + 1; model.meshMaterial[k] = mi + 1;
@ -7245,12 +7269,6 @@ static Model LoadM3D(const char *fileName)
for (i = 0; i < model.meshCount; i++) for (i = 0; i < model.meshCount; i++)
{ {
model.meshes[i].boneCount = model.skeleton.boneCount; model.meshes[i].boneCount = model.skeleton.boneCount;
#if !SUPPORT_GPU_SKINNING
// Initialize vertex buffers for CPU skinning
memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float));
memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));
#endif
} }
// Initialize runtime animation data: current pose and bone matrices // Initialize runtime animation data: current pose and bone matrices

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);