37 Commits
6.2 ... master

Author SHA1 Message Date
48f352c966 [rtextures] LoadImageColors(), GetImageColor(): fix 16-bit color conversion precision (#6322) 2026-10-23 09:25:31 +02:00
63d01d6237 [rtextures] ImageColorBrightness(): clamp negative values to 0 (#6320) 2026-10-23 08:59:12 +02:00
ad124dd7f5 [raymath] Fix QuaternionNlerp() taking the long path when quaternions have opposite signs (#6317) 2026-10-22 11:54:08 +02:00
7b677dd847 [rtextures] ImageTextEx(): use MeasureTextEx() line spacing, fix multiline scaling (#6311)
* [rtextures] ImageTextEx(): use MeasureTextEx() line spacing, fix multiline scaling

* Keep ImageTextEx offsets as integers
2026-10-22 11:50:41 +02:00
6095f71e54 [rlparser] Fix Makefile raygui.h dependency (#6316) 2026-10-22 00:28:49 +02:00
4383fe1c22 Add new raylib binding for c3 and update license for raylib-matte (MIT) (#6314)
* docs: add new raylib binding for c3

* docs: update license for raylib-matte (MIT)
2026-10-22 00:27:13 +02:00
Ray
1026cb9645 REVIEWED: Limit all math to float
Most double data ends-up being cut to float, the unique real reason to keep double on rlgl functions is to mimic legacy OpenGL 1.1.

Using float everywhere will slightly improve performance at a really negligible cost, and it will more consistent through all the raylib library.
2026-10-21 10:13:36 +02:00
c9fca4c15a [rcore] Fix GetFileExtension() returning a dot from a directory name (#6312) 2026-10-21 09:37:07 +02:00
5e63cf99a3 [rcore][win32] Implement SetWindowIcons() (#6304)
* [rcore][win32] Reject non-RGBA images in SetWindowIcon()

* Implement SetWindowIcons

* Inline UpdateIcons()
2026-10-20 22:49:50 +02:00
114a857bde [examples] text_3d_drawing: remove stale line spacing NOTE/TODO comments (#6310) 2026-10-20 22:48:07 +02:00
a40a167804 [examples] Fix typos in text examples (#6309) 2026-10-20 14:53:22 +02:00
57c0764853 [examples] shapes_penrose_tile: remove resolved TODO (#6307) 2026-10-19 23:24:40 +02:00
bbdc73e324 [examples] shapes_penrose_tile: use Load/Unload naming convention (#6306) 2026-10-19 20:59:22 +02:00
dcdbdde89b [examples] shapes_penrose_tile: fix memory leak on exit (#6301) 2026-10-19 10:11:00 +02:00
9c5d9f2856 chore(bindings): update raylib-d to 6.2 (#6302) 2026-10-19 10:09:51 +02:00
a750741cf8 [rcore][win32] Implement IsWindowFocused() and SetWindowFocused() (#6300)
* [rcore][win32] Implement IsWindowFocused()

* FLAG_WINDOW_UNFOCUSED and SetWindowFocused

* Minor formatting changes
2026-10-18 23:33:47 +02:00
2e66d4080c [rtextures] Fix ImageCrop() float precision issues (#6295) 2026-10-18 15:36:22 +02:00
ab1dde8fbb [rcore][GLFW] Skip workarea clamp when the reported workarea size is invalid (#6296)
Some window managers on X11 multi-monitor setups report a _NET_WORKAREA that does not overlap the primary monitor, so glfwGetMonitorWorkarea() returns a zero width or height. The window size was then clamped to 0 and window creation failed with "Invalid window size 0x450".

Fixes #6292
2026-10-18 15:33:43 +02:00
f400535eb6 [examples] shapes_pie_chart: use DrawRing() for donut mode, fix related bugs (#6293) 2026-10-18 15:28:55 +02:00
d9ff09c3c9 [rcore][win32] Re-add EnableCursor() to ClosePlatform() (#6294) 2026-10-18 15:28:06 +02:00
9b6d185ef0 rlparser: update raylib_api.* by CI 2026-10-17 18:20:52 +00:00
Ray
28789122ce Update version to avoid confusions with latest release 2026-10-17 20:20:35 +02:00
Ray
5dc3674c00 Update rcore.c 2026-10-17 20:15:03 +02:00
Ray
bf08870034 REVIEWED: CloseWindow(), clear CORE data
NOTE: Win32, flags are not kept between windows initializations
2026-10-17 19:43:11 +02:00
3061e73f0e [rcore][win32] Support legacy versions of Windows (#6284) 2026-10-17 18:25:26 +02:00
986e8b0f1a [rtextures] Fix heap-buffer-overflow when saving KTX images (#6290)
rl_save_ktx allocated only header + pixel bytes, but each mipmap level
is written as UInt32 imageSize followed by the pixels. Include those
4 bytes per level in the allocation size.

Fixes #6289
2026-10-17 18:23:35 +02:00
777e17f9d4 [rcore] Normalize mouse wheel behavior across backends (#6291) 2026-10-17 18:10:12 +02:00
c4a49fd24f [rcore][win32] Allow close requests to be cancelled (#6285) 2026-10-17 15:03:33 +02:00
dec2fdfbf8 [examples] shapes_pie_chart: fix slice list not scrolling (#6282) 2026-10-17 14:59:19 +02:00
3d5d33bc51 [examples] shapes_pie_chart: fix slice labels not editable (#6281) 2026-10-17 14:58:28 +02:00
430439e63b [rmodels] Fix heap overflow and dropped faces for OBJ n-gons (#6283)
parseLine() set command->type = COMMAND_F before the face-size checks.
A face with 6+ vertices then returned 0 early, but the command was left
looking like a valid COMMAND_F while its num_f/f[] fields were
uninitialized (commands[] is malloc'd, not zeroed). The
attribute-construction pass then looped over garbage num_f values,
writing out of bounds into attrib->faces. This caused intermittent
SIGSEGV / "malloc(): invalid size" crashes in LoadModel() and silently
dropped n-gon faces (e.g. a mesh missing its floor).

Changes:
- Set command->type = COMMAND_F only after the face is fully validated
  and filled.
- Bound the f[num_f] collection loop against the fixed-size buffer.
- Reject faces with fewer than 3 vertices.
- Validate the triangulated output size as 3*(num_f-2) rather than
  3*num_f.
- Raise TINYOBJ_MAX_FACES_PER_F_LINE from 16 to 64 so triangulated n-gons
  fit.

Verified with ASan (reported heap-buffer-overflow at
tinyobj_loader_c.h:1432) and Valgrind (uninitialized reads at
:1427/1432-1434/1437). After the fix a 6-gon loads as 4 triangles and
an 8-gon bathtub floor loads (248 vs 204 triangles).
2026-10-17 14:56:34 +02:00
226b281e55 [rtextures] Fix use-after-free in LoadImageFromMemory for PEP format (#6288) 2026-10-17 14:54:37 +02:00
c757c7435a fix_app_freeze_SDL (#6279) 2026-10-16 10:43:21 +02:00
b9758a6403 [rtextures] Fix QOI loading reading past the end of short file data (#6245)
LoadImageFromMemory() passed fileData[12] (the channels byte of the QOI
header) to qoi_decode() as the requested channel count, reading it before
qoi_decode() checks the data size. Data shorter than 13 bytes made it read
past the end of the buffer.

Pass 0 instead, so qoi_decode() uses the channel count from the header after
checking the size. For valid files this gives the same result, since the
value passed was that same header byte.
2026-10-16 10:09:45 +02:00
426d656185 Fix typo in HISTORY.md (#6278) 2026-10-16 09:41:11 +02:00
c0921587c3 Update Ray4Laz version to 6.2 in BINDINGS.md (#6277) 2026-10-16 00:05:05 +02:00
Ray
8658e4e551 Update README.md 2026-10-15 18:27:36 +02:00
29 changed files with 541 additions and 312 deletions

View File

@ -28,6 +28,7 @@ This is a set of recomendations and guidelines for binding authors, meant to hel
| [raylib-beef](https://github.com/Starpelly/raylib-beef) | **auto** | [Beef](https://www.beeflang.org) | MIT | | [raylib-beef](https://github.com/Starpelly/raylib-beef) | **auto** | [Beef](https://www.beeflang.org) | MIT |
| [raybit](https://github.com/Alex-Velez/raybit) | **5.0** | [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) | MIT | | [raybit](https://github.com/Alex-Velez/raybit) | **5.0** | [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) | MIT |
| [raylib-c3](https://github.com/c3lang/vendor/tree/main/libraries/raylib6.c3l) | **6** | [C3](https://c3-lang.org) | MIT | | [raylib-c3](https://github.com/c3lang/vendor/tree/main/libraries/raylib6.c3l) | **6** | [C3](https://c3-lang.org) | MIT |
| [raylib.c3l](https://github.com/NexushasTaken/raylib.c3l) | **6.2** | [C3](https://c3-lang.org) | MIT |
| [raylib-cs](https://github.com/raylib-cs/raylib-cs) | **6.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | Zlib | | [raylib-cs](https://github.com/raylib-cs/raylib-cs) | **6.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | Zlib |
| [Raylib-CSharp-Vinculum](https://github.com/ZeroElectric/Raylib-CSharp-Vinculum) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 | | [Raylib-CSharp-Vinculum](https://github.com/ZeroElectric/Raylib-CSharp-Vinculum) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 |
| [Raylib-CSharp](https://github.com/MrScautHD/Raylib-CSharp) | **5.5** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MIT | | [Raylib-CSharp](https://github.com/MrScautHD/Raylib-CSharp) | **5.5** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MIT |
@ -44,7 +45,7 @@ This is a set of recomendations and guidelines for binding authors, meant to hel
| [dart-raylib](https://gitlab.com/wolfenrain/dart-raylib) | 4.0 | [Dart](https://dart.dev) | MIT | | [dart-raylib](https://gitlab.com/wolfenrain/dart-raylib) | 4.0 | [Dart](https://dart.dev) | MIT |
| [raylib_dart](https://pub.dev/packages/raylib_dart) | 6.0 | [Dart](https://dart.dev) | MIT | | [raylib_dart](https://pub.dev/packages/raylib_dart) | 6.0 | [Dart](https://dart.dev) | MIT |
| [bindbc-raylib3](https://github.com/o3o/bindbc-raylib3) | **5.0** | [D](https://dlang.org) | BSL-1.0 | | [bindbc-raylib3](https://github.com/o3o/bindbc-raylib3) | **5.0** | [D](https://dlang.org) | BSL-1.0 |
| [raylib-d](https://github.com/schveiguy/raylib-d) | **6.0** | [D](https://dlang.org) | Zlib | | [raylib-d](https://github.com/schveiguy/raylib-d) | **6.2** | [D](https://dlang.org) | Zlib |
| [Deno-Raylib](https://github.com/JJLDonley/Deno-Raylib) | **6.0** | [Deno / TS](https://deno.land) | MIT | | [Deno-Raylib](https://github.com/JJLDonley/Deno-Raylib) | **6.0** | [Deno / TS](https://deno.land) | MIT |
| [rayex](https://github.com/shiryel/rayex) | 5.5 | [elixir](https://elixir-lang.org) | Apache-2.0 | | [rayex](https://github.com/shiryel/rayex) | 5.5 | [elixir](https://elixir-lang.org) | Apache-2.0 |
| [raylib-elfscript](https://github.com/ohmtal/raylib-elfscript) | 6.0 | [ElfScript](https://github.com/ohmtal/ElfScript) | MIT | | [raylib-elfscript](https://github.com/ohmtal/raylib-elfscript) | 6.0 | [ElfScript](https://github.com/ohmtal/ElfScript) | MIT |
@ -70,7 +71,7 @@ This is a set of recomendations and guidelines for binding authors, meant to hel
| [raylib-lua-sol](https://github.com/RobLoach/raylib-lua-sol) | 5.5 | [Lua](http://www.lua.org) | Zlib | | [raylib-lua-sol](https://github.com/RobLoach/raylib-lua-sol) | 5.5 | [Lua](http://www.lua.org) | Zlib |
| [raylib-luajit](https://github.com/homma/raylib-luajit) | 5.5 | [Lua](http://www.lua.org) | MIT | | [raylib-luajit](https://github.com/homma/raylib-luajit) | 5.5 | [Lua](http://www.lua.org) | MIT |
| [raylib-luajit-generated](https://github.com/james2doyle/raylib-luajit-generated) | 5.5 | [Lua](http://www.lua.org) | MIT | | [raylib-luajit-generated](https://github.com/james2doyle/raylib-luajit-generated) | 5.5 | [Lua](http://www.lua.org) | MIT |
| [raylib-matte](https://github.com/jcorks/raylib-matte) | 4.6-dev | [Matte](https://github.com/jcorks/matte) | **???** | | [raylib-matte](https://github.com/jcorks/raylib-matte) | 4.6-dev | [Matte](https://github.com/jcorks/matte) | MIT |
| [raylib_mojo](https://github.com/willGuimont/raylib_mojo) | **6.0** | [Mojo](https://www.modular.com/mojo) | ZLib | | [raylib_mojo](https://github.com/willGuimont/raylib_mojo) | **6.0** | [Mojo](https://www.modular.com/mojo) | ZLib |
| [raymojo](https://github.com/RobertFlexx/raymojo) | **6.0** | [Mojo](https://www.modular.com/mojo) | GPLv3 | | [raymojo](https://github.com/RobertFlexx/raymojo) | **6.0** | [Mojo](https://www.modular.com/mojo) | GPLv3 |
| [raymod](https://github.com/RobertFlexx/raymod) | **6.0** | [Modula-2](https://en.wikipedia.org/wiki/Modula-2) / [Modula-3](https://en.wikipedia.org/wiki/Modula-3) | Apache-2.0 | | [raymod](https://github.com/RobertFlexx/raymod) | **6.0** | [Modula-2](https://en.wikipedia.org/wiki/Modula-2) / [Modula-3](https://en.wikipedia.org/wiki/Modula-3) | Apache-2.0 |
@ -83,7 +84,7 @@ This is a set of recomendations and guidelines for binding authors, meant to hel
| [TurboRaylib](https://github.com/turborium/TurboRaylib) | 4.5 | [Object Pascal](https://en.wikipedia.org/wiki/Object_Pascal) | MIT | | [TurboRaylib](https://github.com/turborium/TurboRaylib) | 4.5 | [Object Pascal](https://en.wikipedia.org/wiki/Object_Pascal) | MIT |
| [Rayberon](https://github.com/RobertFlexx/Rayberon) | **6.0** | [Oberon-2](https://en.wikipedia.org/wiki/Oberon-2) | MIT | | [Rayberon](https://github.com/RobertFlexx/Rayberon) | **6.0** | [Oberon-2](https://en.wikipedia.org/wiki/Oberon-2) | MIT |
| [EuRaylib](https://github.com/gAndy50/EuRaylib6) | **6.0** | [openEuphoria](https://openeuphoria.org/) | Zlib | | [EuRaylib](https://github.com/gAndy50/EuRaylib6) | **6.0** | [openEuphoria](https://openeuphoria.org/) | Zlib |
| [Ray4Laz](https://github.com/GuvaCode/Ray4Laz) | **6.0** | [Free Pascal](https://en.wikipedia.org/wiki/Free_Pascal) | Zlib | | [Ray4Laz](https://github.com/GuvaCode/Ray4Laz) | **6.2** | [Free Pascal](https://en.wikipedia.org/wiki/Free_Pascal) | Zlib |
| [Raylib.4.0.Pascal](https://github.com/sysrpl/Raylib.4.0.Pascal) | 4.0 | [Free Pascal](https://en.wikipedia.org/wiki/Free_Pascal) | Zlib | | [Raylib.4.0.Pascal](https://github.com/sysrpl/Raylib.4.0.Pascal) | 4.0 | [Free Pascal](https://en.wikipedia.org/wiki/Free_Pascal) | Zlib |
| [raylib-python-cffi](https://github.com/electronstudio/raylib-python-cffi) | **6.0** | [Python](https://www.python.org) | EPL-2.0 | | [raylib-python-cffi](https://github.com/electronstudio/raylib-python-cffi) | **6.0** | [Python](https://www.python.org) | EPL-2.0 |
| [raylibpyctbg](https://github.com/overdev/raylibpyctbg) | 5.5 | [Python](https://www.python.org) | MIT | | [raylibpyctbg](https://github.com/overdev/raylibpyctbg) | 5.5 | [Python](https://www.python.org) | MIT |

View File

@ -689,6 +689,6 @@ Make sure to check raylib [CHANGELOG](https://github.com/raysan5/raylib/blob/mas
Again, I want to **thank all the contributors (+950!**) that helped improving raylib, this time there have been **more than 100 new contributors** sending fixes and improvements! Again, I want to **thank all the contributors (+950!**) that helped improving raylib, this time there have been **more than 100 new contributors** sending fixes and improvements!
After 13 years of development, `raylib 6.2` is today probably one of the bests libraries to enjoy **games/tools/graphics/AI programming!** After 13 years of development, `raylib 6.2` is today probably one of the best libraries to enjoy **games/tools/graphics/AI programming!**
**Hope you keep enjoying programming with raylib!** :) **Hope you keep enjoying programming with raylib!** :)

View File

@ -14,7 +14,7 @@ Ready to learn? Jump to [code examples!](https://www.raylib.com/examples.html)
[![GitHub Releases Downloads](https://img.shields.io/github/downloads/raysan5/raylib/total)](https://github.com/raysan5/raylib/releases) [![GitHub Releases Downloads](https://img.shields.io/github/downloads/raysan5/raylib/total)](https://github.com/raysan5/raylib/releases)
[![GitHub Stars](https://img.shields.io/github/stars/raysan5/raylib?style=flat&label=stars)](https://github.com/raysan5/raylib/stargazers) [![GitHub Stars](https://img.shields.io/github/stars/raysan5/raylib?style=flat&label=stars)](https://github.com/raysan5/raylib/stargazers)
[![GitHub commits since tagged version](https://img.shields.io/github/commits-since/raysan5/raylib/6.0)](https://github.com/raysan5/raylib/commits/master) [![GitHub commits since tagged version](https://img.shields.io/github/commits-since/raysan5/raylib/6.2)](https://github.com/raysan5/raylib/commits/master)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/raysan5?label=sponsors)](https://github.com/sponsors/raysan5) [![GitHub Sponsors](https://img.shields.io/github/sponsors/raysan5?label=sponsors)](https://github.com/sponsors/raysan5)
[![License](https://img.shields.io/badge/license-zlib%2Flibpng-blue.svg)](LICENSE) [![License](https://img.shields.io/badge/license-zlib%2Flibpng-blue.svg)](LICENSE)

View File

@ -55,7 +55,8 @@ static int turtleTop = -1;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static void PushTurtleState(TurtleState state); static void PushTurtleState(TurtleState state);
static TurtleState PopTurtleState(void); static TurtleState PopTurtleState(void);
static PenroseLSystem CreatePenroseLSystem(float drawLength); static PenroseLSystem LoadPenroseLSystem(float drawLength);
static void UnloadPenroseLSystem(PenroseLSystem ls);
static void BuildProductionStep(PenroseLSystem *ls); static void BuildProductionStep(PenroseLSystem *ls);
static void DrawPenroseLSystem(PenroseLSystem *ls); static void DrawPenroseLSystem(PenroseLSystem *ls);
@ -77,8 +78,8 @@ int main(void)
int maxGenerations = 4; int maxGenerations = 4;
int generations = 0; int generations = 0;
// Initializee new penrose tile // Initialize new penrose tile
PenroseLSystem ls = CreatePenroseLSystem(drawLength*(generations/(float)maxGenerations)); PenroseLSystem ls = LoadPenroseLSystem(drawLength*(generations/(float)maxGenerations));
for (int i = 0; i < generations; i++) BuildProductionStep(&ls); for (int i = 0; i < generations; i++) BuildProductionStep(&ls);
SetTargetFPS(120); // Set our game to run at 120 frames-per-second SetTargetFPS(120); // Set our game to run at 120 frames-per-second
@ -109,8 +110,8 @@ int main(void)
if (rebuild) if (rebuild)
{ {
RL_FREE(ls.production); // Free previous production for re-creation UnloadPenroseLSystem(ls); // Free previous production for re-creation
ls = CreatePenroseLSystem(drawLength*(generations/(float)maxGenerations)); ls = LoadPenroseLSystem(drawLength*(generations/(float)maxGenerations));
for (int i = 0; i < generations; i++) BuildProductionStep(&ls); for (int i = 0; i < generations; i++) BuildProductionStep(&ls);
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -119,7 +120,7 @@ int main(void)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing(); BeginDrawing();
ClearBackground( RAYWHITE ); ClearBackground(RAYWHITE);
if (generations > 0) DrawPenroseLSystem(&ls); if (generations > 0) DrawPenroseLSystem(&ls);
@ -133,6 +134,8 @@ int main(void)
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
UnloadPenroseLSystem(ls); // Free production string
CloseWindow(); // Close window and OpenGL context CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
@ -158,10 +161,9 @@ static TurtleState PopTurtleState(void)
return (TurtleState){ 0 }; return (TurtleState){ 0 };
} }
// Create a new penrose tile structure // Load a new penrose tile structure
static PenroseLSystem CreatePenroseLSystem(float drawLength) static PenroseLSystem LoadPenroseLSystem(float drawLength)
{ {
// TODO: Review constant values assignment on recreation?
PenroseLSystem ls = { PenroseLSystem ls = {
.steps = 0, .steps = 0,
.ruleW = "YF++ZF4-XF[-YF4-WF]++", .ruleW = "YF++ZF4-XF[-YF4-WF]++",
@ -179,6 +181,12 @@ static PenroseLSystem CreatePenroseLSystem(float drawLength)
return ls; return ls;
} }
// Unload penrose tile structure
static void UnloadPenroseLSystem(PenroseLSystem ls)
{
RL_FREE(ls.production);
}
// Build next penrose step // Build next penrose step
static void BuildProductionStep(PenroseLSystem *ls) static void BuildProductionStep(PenroseLSystem *ls)
{ {

View File

@ -41,6 +41,7 @@ int main(void)
float donutInnerRadius = 25.0f; float donutInnerRadius = 25.0f;
float values[MAX_PIE_SLICES] = { 300.0f, 100.0f, 450.0f, 350.0f, 600.0f, 380.0f, 750.0f }; // Initial slice values float values[MAX_PIE_SLICES] = { 300.0f, 100.0f, 450.0f, 350.0f, 600.0f, 380.0f, 750.0f }; // Initial slice values
bool editingLabel[MAX_PIE_SLICES] = { 0 }; bool editingLabel[MAX_PIE_SLICES] = { 0 };
char labels[MAX_PIE_SLICES][32] = { 0 }; // Slice label texts, editable
bool showValues = true; bool showValues = true;
bool showPercentages = false; bool showPercentages = false;
@ -75,6 +76,9 @@ int main(void)
// Total value for percentage calculations // Total value for percentage calculations
float totalValue = 0.0f; float totalValue = 0.0f;
// Initialize slice labels
for (int i = 0; i < MAX_PIE_SLICES; i++) snprintf(labels[i], 32, "Slice %02i", i + 1);
SetTargetFPS(60); SetTargetFPS(60);
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
@ -97,7 +101,7 @@ int main(void)
float dy = mousePos.y - center.y; float dy = mousePos.y - center.y;
float distance = sqrtf(dx*dx + dy*dy); float distance = sqrtf(dx*dx + dy*dy);
if (distance <= radius) // Inside the pie radius if ((distance <= radius) && (!showDonut || distance >= donutInnerRadius)) // Inside the pie, outside the donut hole
{ {
float angle = atan2f(dy, dx)*RAD2DEG; float angle = atan2f(dy, dx)*RAD2DEG;
if (angle < 0) angle += 360; if (angle < 0) angle += 360;
@ -134,11 +138,12 @@ int main(void)
Color color = ColorFromHSV((float)i/sliceCount*360.0f, 0.75f, 0.9f); Color color = ColorFromHSV((float)i/sliceCount*360.0f, 0.75f, 0.9f);
float currentRadius = radius; float currentRadius = radius;
// Make the hovered slice pop out by adding 5 pixels to its radius // Make the hovered slice pop out by adding 20 pixels to its radius
if (i == hoveredSlice) currentRadius += 20.0f; if (i == hoveredSlice) currentRadius += 20.0f;
// Draw the pie slice using raylib's DrawCircleSector function // Draw the pie slice (DrawRing() for donut mode)
DrawCircleSector(center, currentRadius, startAngle, startAngle + sweepAngle, 120, color); if (showDonut) DrawRing(center, donutInnerRadius, currentRadius, startAngle, startAngle + sweepAngle, 120, color);
else DrawCircleSector(center, currentRadius, startAngle, startAngle + sweepAngle, 120, color);
// Draw the label for the current slice // Draw the label for the current slice
if (values[i] > 0) if (values[i] > 0)
@ -150,16 +155,12 @@ int main(void)
else labelText[0] = '\0'; else labelText[0] = '\0';
Vector2 textSize = MeasureTextEx(GetFontDefault(), labelText, 20, 1); Vector2 textSize = MeasureTextEx(GetFontDefault(), labelText, 20, 1);
float labelRadius = radius*0.7f; float labelRadius = showDonut? (donutInnerRadius + radius)/2.0f : radius*0.7f;
Vector2 labelPos = { center.x + cosf(midAngle*DEG2RAD)*labelRadius - textSize.x/2.0f, Vector2 labelPos = { center.x + cosf(midAngle*DEG2RAD)*labelRadius - textSize.x/2.0f,
center.y + sinf(midAngle*DEG2RAD)*labelRadius - textSize.y/2.0f }; center.y + sinf(midAngle*DEG2RAD)*labelRadius - textSize.y/2.0f };
DrawText(labelText, (int)labelPos.x, (int)labelPos.y, 20, WHITE); DrawText(labelText, (int)labelPos.x, (int)labelPos.y, 20, WHITE);
} }
// Draw inner circle to create donut effect
// TODO: This is a hacky solution, better use DrawRing()
if (showDonut) DrawCircleV(center, donutInnerRadius, RAYWHITE);
startAngle += sweepAngle; startAngle += sweepAngle;
} }
@ -172,7 +173,7 @@ int main(void)
GuiCheckBox((Rectangle){ panelPos.x + 20, (float)panelPos.y + 12 + 70, 20, 20 }, "Show Percentages", &showPercentages); GuiCheckBox((Rectangle){ panelPos.x + 20, (float)panelPos.y + 12 + 70, 20, 20 }, "Show Percentages", &showPercentages);
GuiCheckBox((Rectangle){ panelPos.x + 20, (float)panelPos.y + 12 + 100, 20, 20 }, "Make Donut", &showDonut); GuiCheckBox((Rectangle){ panelPos.x + 20, (float)panelPos.y + 12 + 100, 20, 20 }, "Make Donut", &showDonut);
if (showDonut) GuiDisable(); if (!showDonut) GuiDisable();
GuiSliderBar((Rectangle){ panelPos.x + 80, (float)panelPos.y + 12 + 130, panelRect.width - 100, 30 }, GuiSliderBar((Rectangle){ panelPos.x + 80, (float)panelPos.y + 12 + 130, panelRect.width - 100, 30 },
"Inner Radius", NULL, & donutInnerRadius, 5.0f, radius - 10.0f); "Inner Radius", NULL, & donutInnerRadius, 5.0f, radius - 10.0f);
GuiEnable(); GuiEnable();
@ -184,7 +185,7 @@ int main(void)
panelPos.x + panelMargin, panelPos.x + panelMargin,
(float)panelPos.y + 12 + 190, (float)panelPos.y + 12 + 190,
panelRect.width - panelMargin*2, panelRect.width - panelMargin*2,
panelRect.y + panelRect.height - panelPos.y + 12 + 190 - panelMargin panelRect.y + panelRect.height - (panelPos.y + 12 + 190) - panelMargin
}; };
int contentHeight = sliceCount*35; int contentHeight = sliceCount*35;
@ -205,7 +206,7 @@ int main(void)
DrawRectangle((int)(contentX + 15), rowY + 5, 20, 20, color); DrawRectangle((int)(contentX + 15), rowY + 5, 20, 20, color);
// Label textbox // Label textbox
if (GuiTextBox((Rectangle){ contentX + 45, (float)rowY, 75, 30 }, TextFormat("Slice %02i", i + 1), 32, editingLabel[i])) if (GuiTextBox((Rectangle){ contentX + 45, (float)rowY, 75, 30 }, labels[i], 32, editingLabel[i]))
editingLabel[i] = !editingLabel[i]; editingLabel[i] = !editingLabel[i];
GuiSliderBar((Rectangle){ contentX + 130, (float)rowY, 110, 30 }, NULL, NULL, &values[i], 0.0f, 1000.0f); GuiSliderBar((Rectangle){ contentX + 130, (float)rowY, 110, 30 }, NULL, NULL, &values[i], 0.0f, 1000.0f);

View File

@ -5,7 +5,7 @@
* Example complexity rating: [★★★★] 4/4 * Example complexity rating: [★★★★] 4/4
* *
* NOTE: Draw a 2D text in 3D space, each letter is drawn in a quad (or 2 quads if backface is set) * NOTE: Draw a 2D text in 3D space, each letter is drawn in a quad (or 2 quads if backface is set)
* where the texture coodinates of each quad map to the texture coordinates of the glyphs * where the texture coordinates of each quad map to the texture coordinates of the glyphs
* inside the font texture * inside the font texture
* *
* A more efficient approach, i believe, would be to render the text in a render texture and * A more efficient approach, i believe, would be to render the text in a render texture and
@ -303,11 +303,11 @@ int main(void)
DrawTextWave3D(font, text, (Vector3){ -tbox.x/2.0f, layerDistance*i, -4.5f }, fontSize, fontSpacing, lineSpacing, true, &wcfg, time, clr); DrawTextWave3D(font, text, (Vector3){ -tbox.x/2.0f, layerDistance*i, -4.5f }, fontSize, fontSpacing, lineSpacing, true, &wcfg, time, clr);
} }
// Draw the text boundry if set // Draw the text boundary if set
if (SHOW_TEXT_BOUNDRY) DrawCubeWiresV((Vector3){ 0.0f, 0.0f, -4.5f + tbox.z/2 }, tbox, dark); if (SHOW_TEXT_BOUNDRY) DrawCubeWiresV((Vector3){ 0.0f, 0.0f, -4.5f + tbox.z/2 }, tbox, dark);
rlPopMatrix(); rlPopMatrix();
// Don't draw the letter boundries for the 3D text below // Don't draw the letter boundaries for the 3D text below
bool slb = SHOW_LETTER_BOUNDRY; bool slb = SHOW_LETTER_BOUNDRY;
SHOW_LETTER_BOUNDRY = false; SHOW_LETTER_BOUNDRY = false;
@ -388,14 +388,14 @@ int main(void)
DrawText3D(GetFontDefault(), opt, pos, 0.6f, 0.05f, 0.0f, false, DARKBLUE); DrawText3D(GetFontDefault(), opt, pos, 0.6f, 0.05f, 0.0f, false, DARKBLUE);
pos.z += 0.5f + m.y; pos.z += 0.5f + m.y;
opt = "press [F1] to toggle the letter boundry"; opt = "press [F1] to toggle the letter boundary";
quads += 39; quads += 39;
m = MeasureTextEx(GetFontDefault(), opt, 0.6f, 0.05f); m = MeasureTextEx(GetFontDefault(), opt, 0.6f, 0.05f);
pos.x = -m.x/2.0f; pos.x = -m.x/2.0f;
DrawText3D(GetFontDefault(), opt, pos, 0.6f, 0.05f, 0.0f, false, DARKBLUE); DrawText3D(GetFontDefault(), opt, pos, 0.6f, 0.05f, 0.0f, false, DARKBLUE);
pos.z += 0.5f + m.y; pos.z += 0.5f + m.y;
opt = "press [F2] to toggle the text boundry"; opt = "press [F2] to toggle the text boundary";
quads += 37; quads += 37;
m = MeasureTextEx(GetFontDefault(), opt, 0.6f, 0.05f); m = MeasureTextEx(GetFontDefault(), opt, 0.6f, 0.05f);
pos.x = -m.x/2.0f; pos.x = -m.x/2.0f;
@ -543,8 +543,6 @@ static void DrawText3D(Font font, const char *text, Vector3 position, float font
if (codepoint == '\n') if (codepoint == '\n')
{ {
// NOTE: Fixed line spacing of 1.5 line-height
// TODO: Support custom line spacing defined by user
textOffsetY += fontSize + lineSpacing; textOffsetY += fontSize + lineSpacing;
textOffsetX = 0.0f; textOffsetX = 0.0f;
} }
@ -589,8 +587,6 @@ static void DrawTextWave3D(Font font, const char *text, Vector3 position, float
if (codepoint == '\n') if (codepoint == '\n')
{ {
// NOTE: Fixed line spacing of 1.5 line-height
// TODO: Support custom line spacing defined by user
textOffsetY += fontSize + lineSpacing; textOffsetY += fontSize + lineSpacing;
textOffsetX = 0.0f; textOffsetX = 0.0f;
k = 0; k = 0;

View File

@ -136,7 +136,7 @@ int main(void)
DrawText(TextFormat("Duration (A | D): %d", (int)text.duration), 20, 20, 20, GRAY); DrawText(TextFormat("Duration (A | D): %d", (int)text.duration), 20, 20, 20, GRAY);
DrawText(TextFormat("Delta (W | S): %.1f", text.delta), 20, 50, 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("Offset (Z | X): %.1f", text.offset), 20, 80, 20, GRAY);
DrawText(TextFormat("Curent Animation (Q | E): %s", animations[currentAnimation]), 20, 110, 20, GRAY); DrawText(TextFormat("Current Animation (Q | E): %s", animations[currentAnimation]), 20, 110, 20, GRAY);
for (unsigned int i = 0; i < TextLength(text.str); i++) for (unsigned int i = 0; i < TextLength(text.str); i++)
{ {

View File

@ -605,8 +605,10 @@ int rl_save_ktx(const char *file_name, void *data, int width, int height, int fo
// Calculate file data_size required // Calculate file data_size required
int data_size = sizeof(ktx_header); int data_size = sizeof(ktx_header);
// NOTE: Each mipmap level is stored as: UInt32 imageSize + pixel data
for (int i = 0, w = width, h = height; i < mipmaps; i++) for (int i = 0, w = width, h = height; i < mipmaps; i++)
{ {
data_size += (int)sizeof(unsigned int);
data_size += get_pixel_data_size(w, h, format); data_size += get_pixel_data_size(w, h, format);
w /= 2; h /= 2; w /= 2; h /= 2;
} }

View File

@ -128,7 +128,7 @@ extern void tinyobj_materials_free(tinyobj_material_t *materials,
#define TINYOBJ_FREE free #define TINYOBJ_FREE free
#endif #endif
#define TINYOBJ_MAX_FACES_PER_F_LINE (16) #define TINYOBJ_MAX_FACES_PER_F_LINE (64)
#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) #define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
#define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10)) #define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10))
@ -1093,11 +1093,20 @@ static int parseLine(Command *command, const char *p, unsigned int p_len,
tinyobj_vertex_index_t vi = parseRawTriple(&token); tinyobj_vertex_index_t vi = parseRawTriple(&token);
skip_space_and_cr(&token); skip_space_and_cr(&token);
// Guard the fixed-size f[] buffer against overrun.
if (num_f >= TINYOBJ_MAX_FACES_PER_F_LINE) return 0;
f[num_f] = vi; f[num_f] = vi;
num_f++; num_f++;
} }
command->type = COMMAND_F; // A face needs at least 3 vertices, otherwise the triangulation
// below reads uninitialized f[] entries.
if (num_f < 3) return 0;
// NOTE: command->type is deliberately not set here. A face rejected by
// the size checks below must not look like COMMAND_F to the later
// attribute-construction pass, which would otherwise consume
// uninitialized command->num_f/f[] fields (heap buffer overflow).
if (triangulate) { if (triangulate) {
unsigned int k; unsigned int k;
@ -1111,7 +1120,7 @@ static int parseLine(Command *command, const char *p, unsigned int p_len,
// WARNING: If -DNDEBUG is set when compiling, assertions will not // WARNING: If -DNDEBUG is set when compiling, assertions will not
// be present in the compiled binary, replacing by a runtime check // be present in the compiled binary, replacing by a runtime check
//assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE); //assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
if (3*num_f > TINYOBJ_MAX_FACES_PER_F_LINE) return 0; if ((num_f - 2) * 3 > TINYOBJ_MAX_FACES_PER_F_LINE) return 0;
for (k = 2; k < num_f; k++) { for (k = 2; k < num_f; k++) {
i1 = i2; i1 = i2;
@ -1144,6 +1153,9 @@ static int parseLine(Command *command, const char *p, unsigned int p_len,
command->num_f_num_verts = 1; command->num_f_num_verts = 1;
} }
// Mark COMMAND_F only after full validation/fill so a rejected face
// stays COMMAND_EMPTY for the attribute pass below.
command->type = COMMAND_F;
return 1; return 1;
} }

View File

@ -1677,8 +1677,10 @@ int InitPlatform(void)
// If the area requested by the user exceeds the maximum workable area, clamp it to that // If the area requested by the user exceeds the maximum workable area, clamp it to that
// GLFW has a problem where if the window is greater than the workable area (this means // GLFW has a problem where if the window is greater than the workable area (this means
// the taskbar / dockable areas) it won't show up if the window isn't fullscreen // the taskbar / dockable areas) it won't show up if the window isn't fullscreen
if (CORE.Window.screen.width > (unsigned int)workWidth) CORE.Window.screen.width = workWidth; // NOTE: Some window managers report a workarea that does not overlap the primary monitor
if (CORE.Window.screen.height > (unsigned int)workHeight) CORE.Window.screen.height = workHeight; // (i.e. multi-monitor setups on X11), resulting in a zero/negative size, skip clamping then
if ((workWidth > 0) && (CORE.Window.screen.width > (unsigned int)workWidth)) CORE.Window.screen.width = workWidth;
if ((workHeight > 0) && (CORE.Window.screen.height > (unsigned int)workHeight)) CORE.Window.screen.height = workHeight;
platform.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL); platform.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL);
if (!platform.handle) if (!platform.handle)
@ -2206,7 +2208,8 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
// GLFW3: Mouse wheel scroll callback, runs on mouse wheel changes // GLFW3: Mouse wheel scroll callback, runs on mouse wheel changes
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset) static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset)
{ {
CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset }; CORE.Input.Mouse.currentWheelMove.x += (float)xoffset;
CORE.Input.Mouse.currentWheelMove.y += (float)yoffset;
} }
// GLFW3: Cursor ennter callback, when cursor enters the window // GLFW3: Cursor ennter callback, when cursor enters the window

View File

@ -2020,20 +2020,13 @@ int InitPlatform(void)
// Close platform // Close platform
void ClosePlatform(void) void ClosePlatform(void)
{ {
mg_gamepads_free(&platform.minigamepad); mg_gamepads_free(&platform.minigamepad); // Clear gamepad data
RGFW_window_close(platform.window); RGFW_window_close(platform.window);
#if defined(GRAPHICS_API_OPENGL_SOFTWARE) #if defined(GRAPHICS_API_OPENGL_SOFTWARE)
if (platform.surfacePixels != NULL) if (platform.surfacePixels != NULL) RL_FREE(platform.surfacePixels);
{ if (platform.surface != NULL) RGFW_surface_free(platform.surface);
RL_FREE(platform.surfacePixels); #endif
}
if (platform.surface != NULL)
{
RGFW_surface_free(platform.surface);
}
#endif
} }
// Keycode mapping // Keycode mapping

View File

@ -1720,11 +1720,11 @@ void PollInputEvents(void)
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
{ {
#if defined(USING_VERSION_SDL3) #if defined(USING_VERSION_SDL3)
CORE.Input.Mouse.currentWheelMove.x = event.wheel.x; CORE.Input.Mouse.currentWheelMove.x -= event.wheel.x;
CORE.Input.Mouse.currentWheelMove.y = event.wheel.y; CORE.Input.Mouse.currentWheelMove.y += event.wheel.y;
#else #else
CORE.Input.Mouse.currentWheelMove.x = event.wheel.preciseX; CORE.Input.Mouse.currentWheelMove.x -= event.wheel.preciseX;
CORE.Input.Mouse.currentWheelMove.y = event.wheel.preciseY; CORE.Input.Mouse.currentWheelMove.y += event.wheel.preciseY;
#endif #endif
} break; } break;
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
@ -2198,6 +2198,7 @@ int InitPlatform(void)
// NOTE: No need to call InitTimer(), let SDL manage it internally // NOTE: No need to call InitTimer(), let SDL manage it internally
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
CORE.Time.previous = 0.0;
// Initialize storage system // Initialize storage system
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -2218,8 +2219,10 @@ int InitPlatform(void)
void ClosePlatform(void) void ClosePlatform(void)
{ {
SDL_FreeCursor(platform.cursor); // Free cursor SDL_FreeCursor(platform.cursor); // Free cursor
if (platform.glContext != NULL) SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context if (platform.glContext != NULL) SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context
SDL_DestroyWindow(platform.window); SDL_DestroyWindow(platform.window);
SDL_Quit(); // Deinitialize SDL internal global state SDL_Quit(); // Deinitialize SDL internal global state
} }

View File

@ -87,6 +87,9 @@ typedef struct {
HDC hdc; // Graphic context handler HDC hdc; // Graphic context handler
HGLRC glContext; // OpenGL context handler HGLRC glContext; // OpenGL context handler
HICON largeIcon; // Large icon typically used for the taskbar
HICON smallIcon; // Small icon typically used for the window's title bar
// Software renderer variables // Software renderer variables
HDC hdcmem; // Memory graphic context handler HDC hdcmem; // Memory graphic context handler
HBITMAP hbitmap; // GDI bitmap handler HBITMAP hbitmap; // GDI bitmap handler
@ -107,6 +110,10 @@ typedef BOOL (WINAPI *PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC, const int *, const FL
typedef BOOL (WINAPI *PFNWGLSWAPINTERVALEXTPROC)(int); typedef BOOL (WINAPI *PFNWGLSWAPINTERVALEXTPROC)(int);
typedef const char *(WINAPI *PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc); typedef const char *(WINAPI *PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc);
// Define Win32 function pointer types
typedef UINT (WINAPI *GetDpiForWindowProc)(HWND hwnd);
typedef BOOL (WINAPI *AdjustWindowRectExForDpiProc)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global Variables Definition // Global Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -120,6 +127,10 @@ static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL; static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL;
// Win32 functions that need to be dynamically loaded to support older versions of Windows
static GetDpiForWindowProc pGetDpiForWindow = NULL;
static AdjustWindowRectExForDpiProc pAdjustWindowRectExForDpi = NULL;
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
// This part of the file contains pure functions that never access global state // This part of the file contains pure functions that never access global state
// This distinction helps keep the backend maintainable as the inputs and outputs // This distinction helps keep the backend maintainable as the inputs and outputs
@ -152,7 +163,7 @@ static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL;
#define CLASS_NAME L"raylibWindow" #define CLASS_NAME L"raylibWindow"
#define FLAG_MASK_OPTIONAL (FLAG_VSYNC_HINT) #define FLAG_MASK_OPTIONAL (FLAG_VSYNC_HINT | FLAG_WINDOW_UNFOCUSED)
#define FLAG_MASK_REQUIRED ~(FLAG_MASK_OPTIONAL) #define FLAG_MASK_REQUIRED ~(FLAG_MASK_OPTIONAL)
// Flags that have no operations to perform during an update // Flags that have no operations to perform during an update
@ -200,6 +211,20 @@ static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL;
#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 #define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 #define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
// Older versions of Windows don't support these events
// These events won't be triggered, but this allows them to compile
#ifndef WM_DPICHANGED
#define WM_DPICHANGED 0x02E0
#endif
#ifndef WM_GETDPISCALEDSIZE
#define WM_GETDPISCALEDSIZE 0x02E4
#endif
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -368,6 +393,51 @@ static void AToWCopy(const char *ascii, wchar_t *outPtr, size_t outLen)
if (size != outLen) TRACELOG(LOG_WARNING, "WIN32: Failed to convert %i UTF-8 chars to WCHAR, converted %i chars", outLen, size); if (size != outLen) TRACELOG(LOG_WARNING, "WIN32: Failed to convert %i UTF-8 chars to WCHAR, converted %i chars", outLen, size);
} }
// Dynamically load Windows functions that may not be available on older versions
static void LoadWin32FunctionPointers(void)
{
HMODULE user32 = GetModuleHandleW(L"user32.dll");
pGetDpiForWindow = (GetDpiForWindowProc)GetProcAddress(user32, "GetDpiForWindow");
pAdjustWindowRectExForDpi = (AdjustWindowRectExForDpiProc)GetProcAddress(user32, "AdjustWindowRectExForDpi");
}
// GetDpiForWindow with a fallback for older versions of Windows
static UINT GetDpiForWindowCompat(HWND hwnd)
{
UINT result = 0;
if (pGetDpiForWindow != NULL)
{
// This API requires Windows 10 v1607 or newer
result = pGetDpiForWindow(hwnd);
}
else
{
// Window uses CS_OWNDC, so we don't need to call ReleaseDC
HDC dc = GetDC(hwnd);
// Before Windows 10 v1607: fallback to system-wide DPI (96 for DPI-unaware processes)
result = GetDeviceCaps(dc, LOGPIXELSX);
}
return result;
}
// AdjustWindowRectExForDpi with a fallback for older versions of Windows
static BOOL AdjustWindowRectExForDpiCompat(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi)
{
BOOL result = FALSE;
if (pAdjustWindowRectExForDpi != NULL)
{
result = pAdjustWindowRectExForDpi(lpRect, dwStyle, bMenu, dwExStyle, dpi);
}
else
{
result = AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
}
return result;
}
static bool DecoratedFromStyle(DWORD style) static bool DecoratedFromStyle(DWORD style)
{ {
if (style & STYLE_FLAGS_UNDECORATED_ON) if (style & STYLE_FLAGS_UNDECORATED_ON)
@ -464,7 +534,7 @@ static SIZE CalcWindowSize(UINT dpi, SIZE clientSize, DWORD style)
{ {
RECT rect = { 0, 0, clientSize.cx, clientSize.cy }; RECT rect = { 0, 0, clientSize.cx, clientSize.cy };
int result = AdjustWindowRectExForDpi(&rect, style, 0, WINDOW_STYLE_EX, dpi); int result = AdjustWindowRectExForDpiCompat(&rect, style, 0, WINDOW_STYLE_EX, dpi);
if (result == 0) TRACELOG(LOG_ERROR, "WIN32: Failed to adjust window rect [ERROR: %lu]", GetLastError()); if (result == 0) TRACELOG(LOG_ERROR, "WIN32: Failed to adjust window rect [ERROR: %lu]", GetLastError());
return (SIZE){ rect.right - rect.left, rect.bottom - rect.top }; return (SIZE){ rect.right - rect.left, rect.bottom - rect.top };
@ -510,7 +580,7 @@ static bool UpdateWindowSize(int mode, HWND hwnd, int width, int height, unsigne
} }
// Get size in pixels from points, considering high-dpi // Get size in pixels from points, considering high-dpi
UINT dpi = GetDpiForWindow(hwnd); UINT dpi = GetDpiForWindowCompat(hwnd);
float dpiScale = ((float)dpi)/96.0f; float dpiScale = ((float)dpi)/96.0f;
bool dpiScaling = flags & FLAG_WINDOW_HIGHDPI; bool dpiScaling = flags & FLAG_WINDOW_HIGHDPI;
SIZE desiredSize = { SIZE desiredSize = {
@ -635,6 +705,101 @@ static LPCWSTR GetCursorName(int cursor)
return name; return name;
} }
// Delete platform.smallIcon and platform.largeIcon
static void DeletePlatformIconHandles(void)
{
HICON smallIcon = platform.smallIcon;
HICON largeIcon = platform.largeIcon;
if (smallIcon != NULL) DestroyIcon(smallIcon);
// Only delete largeIcon if it's not pointing to the same underlying resource as smallIcon
if ((largeIcon != NULL) && (largeIcon != smallIcon)) DestroyIcon(largeIcon);
platform.smallIcon = NULL;
platform.largeIcon = NULL;
}
// Delete existing icons and replace them with the standard window/taskbar icons
static void ResetToDefaultWindowsIcons(void)
{
HICON smallIcon = (HICON)GetClassLongPtrW(platform.hwnd, GCLP_HICONSM);
HICON largeIcon = (HICON)GetClassLongPtrW(platform.hwnd, GCLP_HICON);
SendMessage(platform.hwnd, WM_SETICON, ICON_SMALL, (LPARAM)smallIcon);
SendMessage(platform.hwnd, WM_SETICON, ICON_BIG, (LPARAM)largeIcon);
// The built-in Windows icons shouldn't be deleted, so there's no need to store a reference to them
// Just delete the previous icons and exit
DeletePlatformIconHandles();
}
// Convert Image to Win32 HICON (must be RGBA)
static HICON ConvertImageToWindowsIcon(Image image)
{
if (image.format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
{
TRACELOG(LOG_WARNING, "WIN32: Window icon image must be in R8G8B8A8 pixel format");
return NULL;
}
HDC hdc = GetDC(platform.hwnd);
// Create 32-bit BGRA DIB for color
BITMAPV5HEADER bi = { 0 };
ZeroMemory(&bi, sizeof(bi));
bi.bV5Size = sizeof(bi);
bi.bV5Width = image.width;
bi.bV5Height = -image.height; // Negative = top-down bitmap
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
unsigned char *targetBits = NULL;
HBITMAP hColorBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&targetBits, NULL, 0);
if (!hColorBitmap)
{
ReleaseDC(platform.hwnd, hdc);
return NULL;
}
// Copy RGBA > BGRA (Win32 expects BGRA)
for (int y = 0; y < image.height; y++)
{
for (int x = 0; x < image.width; x++)
{
int i = (y*image.width + x)*4;
targetBits[i + 0] = ((unsigned char *)image.data)[i + 2]; // B
targetBits[i + 1] = ((unsigned char *)image.data)[i + 1]; // G
targetBits[i + 2] = ((unsigned char *)image.data)[i + 0]; // R
targetBits[i + 3] = ((unsigned char *)image.data)[i + 3]; // A
}
}
// Create mask bitmap (1-bit, all opaque)
HBITMAP hMaskBitmap = CreateBitmap(image.width, image.height, 1, 1, NULL);
// Build icon info
ICONINFO ii = { 0 };
ZeroMemory(&ii, sizeof(ii));
ii.fIcon = TRUE;
ii.hbmMask = hMaskBitmap;
ii.hbmColor = hColorBitmap;
HICON result = CreateIconIndirect(&ii);
// Clean up GDI bitmaps (icon keeps copies internally)
DeleteObject(hColorBitmap);
DeleteObject(hMaskBitmap);
ReleaseDC(platform.hwnd, hdc);
return result;
}
// Count monitors process // Count monitors process
// NOTE: Required by GetMonitorCount() // NOTE: Required by GetMonitorCount()
static BOOL CALLBACK CountMonitorsProc(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM lparam) static BOOL CALLBACK CountMonitorsProc(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM lparam)
@ -812,75 +977,82 @@ void ClearWindowState(unsigned int flags)
// Set icon for window // Set icon for window
void SetWindowIcon(Image image) void SetWindowIcon(Image image)
{ {
if (!platform.hwnd || (image.data == NULL) || (image.width <= 0) || (image.height <= 0)) return; if (!platform.hwnd) return;
HDC hdc = GetDC(platform.hwnd); if ((image.data == NULL) || (image.width <= 0) || (image.height <= 0))
// Create 32-bit BGRA DIB for color
BITMAPV5HEADER bi = { 0 };
ZeroMemory(&bi, sizeof(bi));
bi.bV5Size = sizeof(bi);
bi.bV5Width = image.width;
bi.bV5Height = -image.height; // Negative = top-down bitmap
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
unsigned char *targetBits = NULL;
HBITMAP hColorBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&targetBits, NULL, 0);
if (!hColorBitmap)
{ {
ReleaseDC(platform.hwnd, hdc); ResetToDefaultWindowsIcons();
return; return;
} }
// Copy RGBA > BGRA (Win32 expects BGRA) HICON hIcon = ConvertImageToWindowsIcon(image);
for (int y = 0; y < image.height; y++)
{
for (int x = 0; x < image.width; x++)
{
int i = (y*image.width + x)*4;
targetBits[i + 0] = ((unsigned char *)image.data)[i + 2]; // B
targetBits[i + 1] = ((unsigned char *)image.data)[i + 1]; // G
targetBits[i + 2] = ((unsigned char *)image.data)[i + 0]; // R
targetBits[i + 3] = ((unsigned char *)image.data)[i + 3]; // A
}
}
// Create mask bitmap (1-bit, all opaque)
HBITMAP hMaskBitmap = CreateBitmap(image.width, image.height, 1, 1, NULL);
// Build icon info
ICONINFO ii = { 0 };
ZeroMemory(&ii, sizeof(ii));
ii.fIcon = TRUE;
ii.hbmMask = hMaskBitmap;
ii.hbmColor = hColorBitmap;
HICON hIcon = CreateIconIndirect(&ii);
// Clean up GDI bitmaps (icon keeps copies internally)
DeleteObject(hColorBitmap);
DeleteObject(hMaskBitmap);
ReleaseDC(platform.hwnd, hdc);
if (hIcon) if (hIcon)
{ {
// Set both large and small icons SendMessage(platform.hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
SendMessage(platform.hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); SendMessage(platform.hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
HICON previousIcon = (HICON)SendMessage(platform.hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); DeletePlatformIconHandles();
if (previousIcon) DestroyIcon(previousIcon); platform.smallIcon = hIcon;
platform.largeIcon = hIcon;
} }
} }
// Set icon for window (multiple sizes) // Set icon for window (multiple sizes)
void SetWindowIcons(Image *images, int count) void SetWindowIcons(Image *images, int count)
{ {
// TODO: Implement SetWindowIcons() if ((images == NULL) || (count <= 0))
{
ResetToDefaultWindowsIcons();
return;
}
// Large icon has a resolution of (SM_CXICON*SM_CXICON) pixels
int largeIconRenderSize = GetSystemMetrics(SM_CXICON);
// Attempt to find a best match for the large icon based on each image's width
int bestLargeIconIndex = -1;
int bestLargeIconSizeDifference = INT_MAX;
for (int i = 0; i < count; i++)
{
Image img = images[i];
int difference = abs(img.width - largeIconRenderSize);
if ((img.data != NULL) && (img.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) && (difference < bestLargeIconSizeDifference))
{
bestLargeIconIndex = i;
bestLargeIconSizeDifference = difference;
}
}
// Small icon has a resolution of (SM_CYSMICON*SM_CYSMICON) pixels
int smallIconRenderSize = GetSystemMetrics(SM_CYSMICON);
// Attempt to find a best match for the small icon based on each image's width
int bestSmallIconIndex = -1;
int bestSmallIconSizeDifference = INT_MAX;
for (int i = 0; i < count; i++)
{
Image img = images[i];
int difference = abs(img.width - smallIconRenderSize);
if ((img.data != NULL) && (img.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) && (difference < bestSmallIconSizeDifference))
{
bestSmallIconIndex = i;
bestSmallIconSizeDifference = difference;
}
}
if ((bestSmallIconIndex != -1) && (bestLargeIconIndex != -1))
{
HICON smallIcon = ConvertImageToWindowsIcon(images[bestSmallIconIndex]);
HICON largeIcon = ConvertImageToWindowsIcon(images[bestLargeIconIndex]);
SendMessage(platform.hwnd, WM_SETICON, ICON_SMALL, (LPARAM)smallIcon);
SendMessage(platform.hwnd, WM_SETICON, ICON_BIG, (LPARAM)largeIcon);
DeletePlatformIconHandles();
platform.smallIcon = smallIcon;
platform.largeIcon = largeIcon;
}
else TRACELOG(LOG_WARNING, "WIN32: All icons passed to SetWindowIcons were invalid");
} }
void SetWindowTitle(const char *title) void SetWindowTitle(const char *title)
@ -965,7 +1137,11 @@ void SetWindowOpacity(float opacity)
// Set window focused // Set window focused
void SetWindowFocused(void) void SetWindowFocused(void)
{ {
TRACELOG(LOG_WARNING, "SetWindowFocused not implemented"); BringWindowToTop(platform.hwnd);
SetForegroundWindow(platform.hwnd);
SetFocus(platform.hwnd);
if (GetForegroundWindow() != platform.hwnd) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed to set window focus");
} }
// Get native window handle // Get native window handle
@ -1060,7 +1236,7 @@ Vector2 GetWindowPosition(void)
// Get window scale DPI factor for current monitor // Get window scale DPI factor for current monitor
Vector2 GetWindowScaleDPI(void) Vector2 GetWindowScaleDPI(void)
{ {
float scale = ((float)GetDpiForWindow(platform.hwnd))/96.0f; float scale = ((float)GetDpiForWindowCompat(platform.hwnd))/96.0f;
return (Vector2){ scale, scale }; return (Vector2){ scale, scale };
} }
@ -1069,10 +1245,7 @@ void SetClipboardText(const char *text)
{ {
if (OpenClipboard(platform.hwnd)) if (OpenClipboard(platform.hwnd))
{ {
if (text == NULL) if (text == NULL) EmptyClipboard();
{
EmptyClipboard();
}
else else
{ {
size_t length = strlen(text); size_t length = strlen(text);
@ -1105,20 +1278,14 @@ void SetClipboardText(const char *text)
GlobalFree(globalHandle); GlobalFree(globalHandle);
} }
} }
else else GlobalFree(globalHandle);
{
GlobalFree(globalHandle);
}
} }
} }
} }
CloseClipboard(); CloseClipboard();
} }
else else TRACELOG(LOG_WARNING, "Clipboard: Failed to write to clipboard. It may be locked by another program.");
{
TRACELOG(LOG_WARNING, "Clipboard: Failed to write to clipboard. It may be locked by another program.");
}
} }
// Get clipboard text content // Get clipboard text content
@ -1189,7 +1356,6 @@ Image GetClipboardImage(void)
else else
{ {
image = LoadImageFromMemory(".bmp", (const unsigned char*)fileData, (int)dataSize); image = LoadImageFromMemory(".bmp", (const unsigned char*)fileData, (int)dataSize);
RL_FREE(fileData); RL_FREE(fileData);
} }
#else #else
@ -1426,6 +1592,7 @@ void PollInputEvents(void)
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
CORE.Window.resizedLastFrame = false; CORE.Window.resizedLastFrame = false;
CORE.Window.shouldClose = false;
// Process windows messages // Process windows messages
MSG msg = { 0 }; MSG msg = { 0 };
@ -1444,7 +1611,7 @@ void PollInputEvents(void)
// Windows won't send a WM_KEYDOWN event for print screen; check it manually // Windows won't send a WM_KEYDOWN event for print screen; check it manually
bool isPrintScreenDown = ((GetAsyncKeyState(VK_SNAPSHOT) & 0x8000) != 0) && (GetForegroundWindow() == platform.hwnd); bool isPrintScreenDown = ((GetAsyncKeyState(VK_SNAPSHOT) & 0x8000) != 0) && (GetForegroundWindow() == platform.hwnd);
CORE.Input.Keyboard.currentKeyState[KEY_PRINT_SCREEN] = isPrintScreenDown; CORE.Input.Keyboard.currentKeyState[KEY_PRINT_SCREEN] = isPrintScreenDown;
if (isPrintScreenDown && (CORE.Input.Keyboard.exitKey == KEY_PRINT_SCREEN)) CORE.Window.shouldClose = true; if (IsKeyPressed(KEY_PRINT_SCREEN) && (CORE.Input.Keyboard.exitKey == KEY_PRINT_SCREEN)) CORE.Window.shouldClose = true;
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -1642,6 +1809,8 @@ int InitPlatform(void)
CORE.Window.flags = FLAG_WINDOW_HIDDEN | (platform.desiredFlags & FLAG_MASK_NO_UPDATE); CORE.Window.flags = FLAG_WINDOW_HIDDEN | (platform.desiredFlags & FLAG_MASK_NO_UPDATE);
CORE.Window.screenMax.width = 9999; CORE.Window.screenMax.width = 9999;
CORE.Window.screenMax.height = 9999; CORE.Window.screenMax.height = 9999;
LoadWin32FunctionPointers();
/* /*
// TODO: Review SetProcessDpiAwarenessContext() // TODO: Review SetProcessDpiAwarenessContext()
// NOTE: SetProcessDpiAwarenessContext() requires Windows 10, version 1703 and shcore.lib linkage // NOTE: SetProcessDpiAwarenessContext() requires Windows 10, version 1703 and shcore.lib linkage
@ -1764,8 +1933,14 @@ int InitPlatform(void)
CORE.Window.ready = true; CORE.Window.ready = true;
// Activate window to set focus and show taskbar icon if ((platform.desiredFlags & FLAG_WINDOW_HIDDEN) == 0)
ShowWindow(platform.hwnd, SW_SHOWDEFAULT); {
// Show window and taskbar icon, activate unless FLAG_WINDOW_UNFOCUSED is set
bool isUnfocused = ((platform.desiredFlags & FLAG_WINDOW_UNFOCUSED) != 0);
if (isUnfocused) CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
int nCmdShow = (isUnfocused)? SW_SHOWNA : SW_SHOWDEFAULT;
ShowWindow(platform.hwnd, nCmdShow);
}
// Update flags (in case of deferred state change required) // Update flags (in case of deferred state change required)
UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight); UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight);
@ -1814,19 +1989,11 @@ int InitPlatform(void)
// Close platform // Close platform
void ClosePlatform(void) void ClosePlatform(void)
{ {
// Undo disable cursor if it's locked and unregister raw input devices // Clear required platform data
EnableCursor();
// Calling DestroyWindow invokes a WindowProc event that sets the FLAG_WINDOW_HIDDEN flag to true
// If InitWindow is called again, the hidden flag will be interpreted as something the user requested
// Save the current flags and restore them after
unsigned int savedFlags = CORE.Window.flags;
if (platform.hwnd) if (platform.hwnd)
{ {
// SetWindowIcon uses the same resource for both ICON_BIG and ICON_SMALL // Disable cursor lock (if enabled) and unregister raw input devices
// If this ever changes, this code may have to be updated EnableCursor();
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());
@ -1835,19 +2002,18 @@ 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); DeletePlatformIconHandles();
platform.hwnd = NULL; platform.hwnd = NULL;
} }
// Clear clipboard
if (platform.clipboardText != NULL) if (platform.clipboardText != NULL)
{ {
RL_FREE(platform.clipboardText); RL_FREE(platform.clipboardText);
platform.clipboardText = NULL; platform.clipboardText = NULL;
} }
CORE.Window.flags = savedFlags;
#if SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP #if SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP
timeEndPeriod(1); // Restore time period timeEndPeriod(1); // Restore time period
#endif #endif
@ -1921,10 +2087,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
//case WM_QUIT: // Application closing, not related to window //case WM_QUIT: // Application closing, not related to window
case WM_KILLFOCUS: case WM_KILLFOCUS:
{ {
CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
memset(CORE.Input.Keyboard.currentKeyState, 0, sizeof(CORE.Input.Keyboard.currentKeyState)); memset(CORE.Input.Keyboard.currentKeyState, 0, sizeof(CORE.Input.Keyboard.currentKeyState));
memset(CORE.Input.Mouse.currentButtonState, 0, sizeof(CORE.Input.Mouse.currentButtonState)); memset(CORE.Input.Mouse.currentButtonState, 0, sizeof(CORE.Input.Mouse.currentButtonState));
memset(CORE.Input.Touch.currentTouchState, 0, sizeof(CORE.Input.Touch.currentTouchState)); memset(CORE.Input.Touch.currentTouchState, 0, sizeof(CORE.Input.Touch.currentTouchState));
} break; } break;
case WM_SETFOCUS: CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; break;
case WM_SIZING: // Sent to a window that the user is resizing case WM_SIZING: // Sent to a window that the user is resizing
{ {
if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE) if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE)
@ -1973,7 +2141,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
STYLESTRUCT *ss = (STYLESTRUCT *)lparam; STYLESTRUCT *ss = (STYLESTRUCT *)lparam;
GetStyleChangeFlagOps(CORE.Window.flags, ss, deferredFlags); GetStyleChangeFlagOps(CORE.Window.flags, ss, deferredFlags);
UINT dpi = GetDpiForWindow(hwnd); UINT dpi = GetDpiForWindowCompat(hwnd);
// Get client size (framebuffer inside the window) // Get client size (framebuffer inside the window)
RECT rect = { 0 }; RECT rect = { 0 };
GetClientRect(hwnd, &rect); GetClientRect(hwnd, &rect);
@ -2187,8 +2355,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
default: TRACELOG(LOG_WARNING, "TODO: Handle ex mouse button UP [wparam=%u]", HIWORD(wparam)); break; default: TRACELOG(LOG_WARNING, "TODO: Handle ex mouse button UP [wparam=%u]", HIWORD(wparam)); break;
} }
} break; } break;
case WM_MOUSEWHEEL: CORE.Input.Mouse.currentWheelMove.y = ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; break; case WM_MOUSEWHEEL: CORE.Input.Mouse.currentWheelMove.y += ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; break;
case WM_MOUSEHWHEEL: CORE.Input.Mouse.currentWheelMove.x = ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; break; // Horizontal wheel movement is inverted to match GLFW
case WM_MOUSEHWHEEL: CORE.Input.Mouse.currentWheelMove.x -= ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; break;
default: result = DefWindowProcW(hwnd, msg, wparam, lparam); // Message passed directly for execution (default behaviour) default: result = DefWindowProcW(hwnd, msg, wparam, lparam); // Message passed directly for execution (default behaviour)
} }
@ -2260,8 +2429,9 @@ static void HandleKey(WPARAM wparam, LPARAM lparam, char state)
{ {
CORE.Input.Keyboard.currentKeyState[key] = state; CORE.Input.Keyboard.currentKeyState[key] = state;
if (((HIWORD(lparam) & KF_REPEAT) != 0) && (state == 1)) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; bool isKeyRepeatEvent = ((HIWORD(lparam) & KF_REPEAT) != 0);
if ((key == CORE.Input.Keyboard.exitKey) && (state == 1)) CORE.Window.shouldClose = true; if (isKeyRepeatEvent && (state == 1)) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
if (!isKeyRepeatEvent && (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);
} }
@ -2351,7 +2521,7 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height)
SetupViewport(clientSize.cx, clientSize.cy); SetupViewport(clientSize.cx, clientSize.cy);
CORE.Window.resizedLastFrame = true; CORE.Window.resizedLastFrame = true;
float dpiScale = ((float)GetDpiForWindow(hwnd))/96.0f; float dpiScale = ((float)GetDpiForWindowCompat(hwnd))/96.0f;
bool highdpi = !!(CORE.Window.flags & FLAG_WINDOW_HIGHDPI); bool highdpi = !!(CORE.Window.flags & FLAG_WINDOW_HIGHDPI);
unsigned int screenWidth = highdpi? (unsigned int)(((float)clientSize.cx)/dpiScale) : clientSize.cx; unsigned int screenWidth = highdpi? (unsigned int)(((float)clientSize.cx)/dpiScale) : clientSize.cx;
unsigned int screenHeight = highdpi? (unsigned int)(((float)clientSize.cy)/dpiScale) : clientSize.cy; unsigned int screenHeight = highdpi? (unsigned int)(((float)clientSize.cy)/dpiScale) : clientSize.cy;

View File

@ -1735,7 +1735,6 @@ void ClosePlatform(void)
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called
// Close the evdev devices // Close the evdev devices
if (platform.mouseFd != -1) if (platform.mouseFd != -1)
{ {
close(platform.mouseFd); close(platform.mouseFd);

View File

@ -554,7 +554,7 @@ int InitPlatform(void)
// Close platform // Close platform
void ClosePlatform(void) void ClosePlatform(void)
{ {
RL_FREE(platform.pixels); RL_FREE(platform.pixels); // Free pixels buffer
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------

View File

@ -1450,6 +1450,7 @@ int InitPlatform(void)
void ClosePlatform(void) void ClosePlatform(void)
{ {
if (platform.pixels != NULL) RL_FREE(platform.pixels); if (platform.pixels != NULL) RL_FREE(platform.pixels);
if (platform.glContext != 0) emscripten_webgl_destroy_context(platform.glContext); if (platform.glContext != 0) emscripten_webgl_destroy_context(platform.glContext);
} }

View File

@ -810,6 +810,12 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
{ {
Wave wave = { 0 }; Wave wave = { 0 };
if (fileType == NULL)
{
TRACELOG(LOG_WARNING, "WAVE: Missing file extension");
return wave;
}
if (false) { } if (false) { }
#if SUPPORT_FILEFORMAT_WAV #if SUPPORT_FILEFORMAT_WAV
else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0)) else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
@ -2781,7 +2787,7 @@ static bool IsFileExtension(const char *fileName, const char *ext)
bool result = false; bool result = false;
const char *fileExt; const char *fileExt;
if ((fileExt = strrchr(fileName, '.')) != NULL) if ((fileExt = GetFileExtension(fileName)) != NULL)
{ {
if (strcmp(fileExt, ext) == 0) result = true; if (strcmp(fileExt, ext) == 0) result = true;
} }
@ -2792,7 +2798,9 @@ static bool IsFileExtension(const char *fileName, const char *ext)
// Get pointer to extension for a filename string (includes the dot: .png) // Get pointer to extension for a filename string (includes the dot: .png)
static const char *GetFileExtension(const char *fileName) static const char *GetFileExtension(const char *fileName)
{ {
const char *dot = strrchr(fileName, '.'); // Only the file name part can contain the extension, not a directory name
const char *name = GetFileName(fileName);
const char *dot = strrchr(name, '.');
if (!dot || dot == fileName) return NULL; if (!dot || dot == fileName) return NULL;

View File

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylib v6.2 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) * raylib v6.5-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
* *
* FEATURES: * FEATURES:
* - NO external dependencies, all required libraries included with raylib * - NO external dependencies, all required libraries included with raylib
@ -87,9 +87,9 @@
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback #include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
#define RAYLIB_VERSION_MAJOR 6 #define RAYLIB_VERSION_MAJOR 6
#define RAYLIB_VERSION_MINOR 2 #define RAYLIB_VERSION_MINOR 5
#define RAYLIB_VERSION_PATCH 0 #define RAYLIB_VERSION_PATCH 0
#define RAYLIB_VERSION "6.2" #define RAYLIB_VERSION "6.5-dev"
// Function specifiers in case library is build/used as a shared library // Function specifiers in case library is build/used as a shared library
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll

View File

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raymath v2.0 - Math functions to work with Vector2, Vector3, Vector4, Matrix and Quaternions * raymath v2.1 - Math functions to work with Vector2, Vector3, Vector4, Matrix and Quaternions
* *
* CONVENTIONS: * CONVENTIONS:
* - Matrix structure is defined as row-major (memory layout) but parameters naming AND all * - Matrix structure is defined as row-major (memory layout) but parameters naming AND all
@ -9,6 +9,7 @@
* It benefits some functions making them cache-friendly and also avoids matrix * It benefits some functions making them cache-friendly and also avoids matrix
* transpositions sometimes required by OpenGL * transpositions sometimes required by OpenGL
* Example: In memory order, row0 is [m0 m4 m8 m12] but in semantic math row0 is [m0 m1 m2 m3] * Example: In memory order, row0 is [m0 m4 m8 m12] but in semantic math row0 is [m0 m1 m2 m3]
* - All math is float only, no doubles usage
* - Functions are always self-contained, no function use another raymath function inside, * - Functions are always self-contained, no function use another raymath function inside,
* required code is directly re-implemented inside * required code is directly re-implemented inside
* - Functions input parameters are always received by value (2 unavoidable exceptions) * - Functions input parameters are always received by value (2 unavoidable exceptions)
@ -1970,32 +1971,32 @@ RMAPI Matrix MatrixScale(float x, float y, float z)
} }
// Get perspective projection matrix // Get perspective projection matrix
RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top, double nearPlane, double farPlane) RMAPI Matrix MatrixFrustum(float left, float right, float bottom, float top, float nearPlane, float farPlane)
{ {
Matrix result = { 0 }; Matrix result = { 0 };
float rl = (float)(right - left); float rl = right - left;
float tb = (float)(top - bottom); float tb = top - bottom;
float fn = (float)(farPlane - nearPlane); float fn = farPlane - nearPlane;
result.m0 = ((float)nearPlane*2.0f)/rl; result.m0 = (nearPlane*2.0f)/rl;
result.m1 = 0.0f; result.m1 = 0.0f;
result.m2 = 0.0f; result.m2 = 0.0f;
result.m3 = 0.0f; result.m3 = 0.0f;
result.m4 = 0.0f; result.m4 = 0.0f;
result.m5 = ((float)nearPlane*2.0f)/tb; result.m5 = (nearPlane*2.0f)/tb;
result.m6 = 0.0f; result.m6 = 0.0f;
result.m7 = 0.0f; result.m7 = 0.0f;
result.m8 = ((float)right + (float)left)/rl; result.m8 = (right + left)/rl;
result.m9 = ((float)top + (float)bottom)/tb; result.m9 = (top + bottom)/tb;
result.m10 = -((float)farPlane + (float)nearPlane)/fn; result.m10 = -(farPlane + nearPlane)/fn;
result.m11 = -1.0f; result.m11 = -1.0f;
result.m12 = 0.0f; result.m12 = 0.0f;
result.m13 = 0.0f; result.m13 = 0.0f;
result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn; result.m14 = -(farPlane*nearPlane*2.0f)/fn;
result.m15 = 0.0f; result.m15 = 0.0f;
return result; return result;
@ -2003,39 +2004,39 @@ RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top,
// Get perspective projection matrix // Get perspective projection matrix
// NOTE: Fovy angle must be provided in radians // NOTE: Fovy angle must be provided in radians
RMAPI Matrix MatrixPerspective(double fovY, double aspect, double nearPlane, double farPlane) RMAPI Matrix MatrixPerspective(float fovY, float aspect, float nearPlane, float farPlane)
{ {
Matrix result = { 0 }; Matrix result = { 0 };
double top = nearPlane*tan(fovY*0.5); float top = nearPlane*tanf(fovY*0.5f);
double bottom = -top; float bottom = -top;
double right = top*aspect; float right = top*aspect;
double left = -right; float left = -right;
// MatrixFrustum(-right, right, -top, top, near, far); // MatrixFrustum(-right, right, -top, top, near, far);
float rl = (float)(right - left); float rl = right - left;
float tb = (float)(top - bottom); float tb = top - bottom;
float fn = (float)(farPlane - nearPlane); float fn = farPlane - nearPlane;
result.m0 = ((float)nearPlane*2.0f)/rl; result.m0 = (nearPlane*2.0f)/rl;
result.m5 = ((float)nearPlane*2.0f)/tb; result.m5 = (nearPlane*2.0f)/tb;
result.m8 = ((float)right + (float)left)/rl; result.m8 = (right + left)/rl;
result.m9 = ((float)top + (float)bottom)/tb; result.m9 = (top + bottom)/tb;
result.m10 = -((float)farPlane + (float)nearPlane)/fn; result.m10 = -(farPlane + nearPlane)/fn;
result.m11 = -1.0f; result.m11 = -1.0f;
result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn; result.m14 = -(farPlane*nearPlane*2.0f)/fn;
return result; return result;
} }
// Get orthographic projection matrix // Get orthographic projection matrix
RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane) RMAPI Matrix MatrixOrtho(float left, float right, float bottom, float top, float nearPlane, float farPlane)
{ {
Matrix result = { 0 }; Matrix result = { 0 };
float rl = (float)(right - left); float rl = right - left;
float tb = (float)(top - bottom); float tb = top - bottom;
float fn = (float)(farPlane - nearPlane); float fn = farPlane - nearPlane;
result.m0 = 2.0f/rl; result.m0 = 2.0f/rl;
result.m1 = 0.0f; result.m1 = 0.0f;
@ -2049,9 +2050,9 @@ RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, d
result.m9 = 0.0f; result.m9 = 0.0f;
result.m10 = -2.0f/fn; result.m10 = -2.0f/fn;
result.m11 = 0.0f; result.m11 = 0.0f;
result.m12 = -((float)left + (float)right)/rl; result.m12 = -(left + right)/rl;
result.m13 = -((float)top + (float)bottom)/tb; result.m13 = -(top + bottom)/tb;
result.m14 = -((float)farPlane + (float)nearPlane)/fn; result.m14 = -(farPlane + nearPlane)/fn;
result.m15 = 1.0f; result.m15 = 1.0f;
return result; return result;
@ -2281,6 +2282,12 @@ RMAPI Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount)
{ {
Quaternion result = { 0 }; Quaternion result = { 0 };
// q2 and -q2 are the same rotation, take the shorter path like QuaternionSlerp()
if ((q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w) < 0.0f)
{
q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w;
}
// QuaternionLerp(q1, q2, amount) // QuaternionLerp(q1, q2, amount)
result.x = q1.x + amount*(q2.x - q1.x); result.x = q1.x + amount*(q2.x - q1.x);
result.y = q1.y + amount*(q2.y - q1.y); result.y = q1.y + amount*(q2.y - q1.y);

View File

@ -65,8 +65,8 @@
#endif #endif
#if defined(RCAMERA_STANDALONE) #if defined(RCAMERA_STANDALONE)
#define CAMERA_CULL_DISTANCE_NEAR 0.05 #define CAMERA_CULL_DISTANCE_NEAR 0.05f
#define CAMERA_CULL_DISTANCE_FAR 4000.0 #define CAMERA_CULL_DISTANCE_FAR 4000.0f
#else #else
#define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR #define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR
#define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR #define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR
@ -430,8 +430,8 @@ Matrix GetCameraProjectionMatrix(Camera *camera, float aspect)
} }
else if (camera->projection == CAMERA_ORTHOGRAPHIC) else if (camera->projection == CAMERA_ORTHOGRAPHIC)
{ {
double top = camera->fovy/2.0; float top = camera->fovy/2.0f;
double right = top*aspect; float right = top*aspect;
return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
} }

View File

@ -379,6 +379,7 @@ typedef struct CoreData {
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXES]; // Gamepad axes state float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXES]; // Gamepad axes state
} Gamepad; } Gamepad;
} Input; } Input;
struct { struct {
double current; // Current time measure (seconds) double current; // Current time measure (seconds)
@ -646,7 +647,6 @@ void InitWindow(int width, int height, const char *title)
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title; if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
// Initialize global input state // Initialize global input state
memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
CORE.Input.Keyboard.exitKey = KEY_ESCAPE; CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f }; CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW; CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
@ -708,15 +708,16 @@ void InitWindow(int width, int height, const char *title)
#endif #endif
#endif #endif
// NOTE: Should be already initialized to 0 but just in case
CORE.Time.frameCounter = 0; CORE.Time.frameCounter = 0;
CORE.Window.shouldClose = false; CORE.Window.shouldClose = false;
// Initialize random seed using available timer source instead of standard time() on embedded platforms // Initialize random seed using available timer source instead of standard time() on embedded platforms
#ifndef PICO_RP2350 #ifndef PICO_RP2350
SetRandomSeed((unsigned int)time(NULL)); SetRandomSeed((unsigned int)time(NULL));
#else #else
SetRandomSeed(get_rand_32()); SetRandomSeed(get_rand_32());
#endif #endif
TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory()); TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory());
} }
@ -735,7 +736,9 @@ void CloseWindow(void)
ClosePlatform(); ClosePlatform();
//-------------------------------------------------------------- //--------------------------------------------------------------
CORE.Window.ready = false; // Clear CORE data, in case new window is initialized
CORE = (CoreData){ 0 };
TRACELOG(LOG_INFO, "Window closed successfully"); TRACELOG(LOG_INFO, "Window closed successfully");
} }
@ -954,16 +957,16 @@ void BeginMode3D(Camera camera)
if (camera.projection == CAMERA_PERSPECTIVE) if (camera.projection == CAMERA_PERSPECTIVE)
{ {
// Setup perspective projection // Setup perspective projection
double top = rlGetCullDistanceNear()*tan(camera.fovy*0.5*DEG2RAD); float top = rlGetCullDistanceNear()*tanf(camera.fovy*0.5f*DEG2RAD);
double right = top*aspect; float right = top*aspect;
rlFrustum(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar()); rlFrustum(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
} }
else if (camera.projection == CAMERA_ORTHOGRAPHIC) else if (camera.projection == CAMERA_ORTHOGRAPHIC)
{ {
// Setup orthographic projection // Setup orthographic projection
double top = camera.fovy/2.0; float top = camera.fovy/2.0f;
double right = top*aspect; float right = top*aspect;
rlOrtho(-right, right, -top,top, rlGetCullDistanceNear(), rlGetCullDistanceFar()); rlOrtho(-right, right, -top,top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
} }
@ -1011,7 +1014,7 @@ void BeginTextureMode(RenderTexture2D target)
// Set orthographic projection to current framebuffer size // Set orthographic projection to current framebuffer size
// NOTE: Configured top-left corner as (0, 0) // NOTE: Configured top-left corner as (0, 0)
rlOrtho(0, target.texture.width, target.texture.height, 0, 0.0f, 1.0f); rlOrtho(0.0f, (float)target.texture.width, (float)target.texture.height, 0.0f, 0.0f, 1.0f);
rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix
rlLoadIdentity(); // Reset current matrix (modelview) rlLoadIdentity(); // Reset current matrix (modelview)
@ -1424,13 +1427,13 @@ Ray GetScreenToWorldRayEx(Vector2 position, Camera camera, int width, int height
if (camera.projection == CAMERA_PERSPECTIVE) if (camera.projection == CAMERA_PERSPECTIVE)
{ {
// Calculate projection matrix from perspective // Calculate projection matrix from perspective
matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)width/(double)height), rlGetCullDistanceNear(), rlGetCullDistanceFar()); matProj = MatrixPerspective(camera.fovy*DEG2RAD, (float)width/(float)height, rlGetCullDistanceNear(), rlGetCullDistanceFar());
} }
else if (camera.projection == CAMERA_ORTHOGRAPHIC) else if (camera.projection == CAMERA_ORTHOGRAPHIC)
{ {
double aspect = (double)width/(double)height; float aspect = (float)width/(float)height;
double top = camera.fovy/2.0; float top = camera.fovy/2.0f;
double right = top*aspect; float right = top*aspect;
// Calculate projection matrix from orthographic // Calculate projection matrix from orthographic
matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar()); matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
@ -1511,13 +1514,13 @@ Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int heigh
if (camera.projection == CAMERA_PERSPECTIVE) if (camera.projection == CAMERA_PERSPECTIVE)
{ {
// Calculate projection matrix from perspective // Calculate projection matrix from perspective
matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)width/(double)height), rlGetCullDistanceNear(), rlGetCullDistanceFar()); matProj = MatrixPerspective(camera.fovy*DEG2RAD, (float)width/(float)height, rlGetCullDistanceNear(), rlGetCullDistanceFar());
} }
else if (camera.projection == CAMERA_ORTHOGRAPHIC) else if (camera.projection == CAMERA_ORTHOGRAPHIC)
{ {
double aspect = (double)width/(double)height; float aspect = (float)width/(float)height;
double top = camera.fovy/2.0; float top = camera.fovy/2.0f;
double right = top*aspect; float right = top*aspect;
// Calculate projection matrix from orthographic // Calculate projection matrix from orthographic
matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar()); matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
@ -2496,7 +2499,9 @@ long GetFileModTime(const char *fileName)
// WARNING: Getting the pointer to the input string extension position (not a string copy) // WARNING: Getting the pointer to the input string extension position (not a string copy)
const char *GetFileExtension(const char *fileName) const char *GetFileExtension(const char *fileName)
{ {
const char *dot = strrchr(fileName, '.'); // Only the file name part can contain the extension, not a directory name
const char *name = GetFileName(fileName);
const char *dot = strrchr(name, '.');
if ((dot == NULL) || (dot == fileName)) return NULL; if ((dot == NULL) || (dot == fileName)) return NULL;
@ -4336,7 +4341,7 @@ void SetupViewport(int width, int height)
// Set orthographic projection to current framebuffer size // Set orthographic projection to current framebuffer size
// NOTE: Configured top-left corner as (0, 0) // NOTE: Configured top-left corner as (0, 0)
rlOrtho(0, CORE.Window.render.width, CORE.Window.render.height, 0, 0.0f, 1.0f); rlOrtho(0.0f, (float)CORE.Window.render.width, (float)CORE.Window.render.height, 0.0f, 0.0f, 1.0f);
rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix
rlLoadIdentity(); // Reset current matrix (modelview) rlLoadIdentity(); // Reset current matrix (modelview)

View File

@ -53,8 +53,8 @@
* *
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack * #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported * #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
* #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance * #define RL_CULL_DISTANCE_NEAR 0.05f // Default projection matrix near cull distance
* #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance * #define RL_CULL_DISTANCE_FAR 4000.0f // Default projection matrix far cull distance
* *
* When loading a shader, the following vertex attributes and uniform location names are tried to be set automatically: * When loading a shader, the following vertex attributes and uniform location names are tried to be set automatically:
* WARNING: Pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference * WARNING: Pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference
@ -235,10 +235,10 @@
// Projection matrix culling // Projection matrix culling
#ifndef RL_CULL_DISTANCE_NEAR #ifndef RL_CULL_DISTANCE_NEAR
#define RL_CULL_DISTANCE_NEAR 0.05 // Default near cull distance #define RL_CULL_DISTANCE_NEAR 0.05f // Default near cull distance
#endif #endif
#ifndef RL_CULL_DISTANCE_FAR #ifndef RL_CULL_DISTANCE_FAR
#define RL_CULL_DISTANCE_FAR 4000.0 // Default far cull distance #define RL_CULL_DISTANCE_FAR 4000.0f // Default far cull distance
#endif #endif
// Texture parameters (equivalent to OpenGL defines) // Texture parameters (equivalent to OpenGL defines)
@ -611,12 +611,12 @@ RLAPI void rlTranslatef(float x, float y, float z); // Multiply the current
RLAPI void rlRotatef(float angle, float x, float y, float z); // Multiply the current matrix by a rotation matrix RLAPI void rlRotatef(float angle, float x, float y, float z); // Multiply the current matrix by a rotation matrix
RLAPI void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix RLAPI void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix
RLAPI void rlMultMatrixf(const float *matf); // Multiply the current matrix by another matrix RLAPI void rlMultMatrixf(const float *matf); // Multiply the current matrix by another matrix
RLAPI void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar); RLAPI void rlFrustum(float left, float right, float bottom, float top, float znear, float zfar);
RLAPI void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar); RLAPI void rlOrtho(float left, float right, float bottom, float top, float znear, float zfar);
RLAPI void rlViewport(int x, int y, int width, int height); // Set the viewport area RLAPI void rlViewport(int x, int y, int width, int height); // Set the viewport area
RLAPI void rlSetClipPlanes(double nearPlane, double farPlane); // Set clip planes distances RLAPI void rlSetClipPlanes(float nearPlane, float farPlane); // Set clip planes distances
RLAPI double rlGetCullDistanceNear(void); // Get cull plane distance near RLAPI float rlGetCullDistanceNear(void); // Get cull plane distance near
RLAPI double rlGetCullDistanceFar(void); // Get cull plane distance far RLAPI float rlGetCullDistanceFar(void); // Get cull plane distance far
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Functions Declaration - Vertex level operations // Functions Declaration - Vertex level operations
@ -1111,8 +1111,8 @@ typedef struct rlglData {
// Global Variables Definition // Global Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static bool isGpuReady = false; static bool isGpuReady = false;
static double rlCullDistanceNear = RL_CULL_DISTANCE_NEAR; static float rlCullDistanceNear = RL_CULL_DISTANCE_NEAR;
static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR; static float rlCullDistanceFar = RL_CULL_DISTANCE_FAR;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
static rlglData RLGL = { 0 }; static rlglData RLGL = { 0 };
@ -1174,12 +1174,12 @@ void rlMatrixMode(int mode)
} }
} }
void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar) void rlFrustum(float left, float right, float bottom, float top, float znear, float zfar)
{ {
glFrustum(left, right, bottom, top, znear, zfar); glFrustum(left, right, bottom, top, znear, zfar);
} }
void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar) void rlOrtho(float left, float right, float bottom, float top, float znear, float zfar)
{ {
glOrtho(left, right, bottom, top, znear, zfar); glOrtho(left, right, bottom, top, znear, zfar);
} }
@ -1332,47 +1332,47 @@ void rlMultMatrixf(const float *matf)
} }
// Multiply the current matrix by a perspective matrix generated by parameters // Multiply the current matrix by a perspective matrix generated by parameters
void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar) void rlFrustum(float left, float right, float bottom, float top, float znear, float zfar)
{ {
Matrix matFrustum = { 0 }; Matrix matFrustum = { 0 };
float rl = (float)(right - left); float rl = right - left;
float tb = (float)(top - bottom); float tb = top - bottom;
float fn = (float)(zfar - znear); float fn = zfar - znear;
matFrustum.m0 = ((float) znear*2.0f)/rl; matFrustum.m0 = (znear*2.0f)/rl;
matFrustum.m1 = 0.0f; matFrustum.m1 = 0.0f;
matFrustum.m2 = 0.0f; matFrustum.m2 = 0.0f;
matFrustum.m3 = 0.0f; matFrustum.m3 = 0.0f;
matFrustum.m4 = 0.0f; matFrustum.m4 = 0.0f;
matFrustum.m5 = ((float) znear*2.0f)/tb; matFrustum.m5 = (znear*2.0f)/tb;
matFrustum.m6 = 0.0f; matFrustum.m6 = 0.0f;
matFrustum.m7 = 0.0f; matFrustum.m7 = 0.0f;
matFrustum.m8 = ((float)right + (float)left)/rl; matFrustum.m8 = (right + left)/rl;
matFrustum.m9 = ((float)top + (float)bottom)/tb; matFrustum.m9 = (top + bottom)/tb;
matFrustum.m10 = -((float)zfar + (float)znear)/fn; matFrustum.m10 = -(zfar + znear)/fn;
matFrustum.m11 = -1.0f; matFrustum.m11 = -1.0f;
matFrustum.m12 = 0.0f; matFrustum.m12 = 0.0f;
matFrustum.m13 = 0.0f; matFrustum.m13 = 0.0f;
matFrustum.m14 = -((float)zfar*(float)znear*2.0f)/fn; matFrustum.m14 = -(zfar*znear*2.0f)/fn;
matFrustum.m15 = 0.0f; matFrustum.m15 = 0.0f;
*RLGL.State.currentMatrix = rlMatrixMultiply(*RLGL.State.currentMatrix, matFrustum); *RLGL.State.currentMatrix = rlMatrixMultiply(*RLGL.State.currentMatrix, matFrustum);
} }
// Multiply the current matrix by an orthographic matrix generated by parameters // Multiply the current matrix by an orthographic matrix generated by parameters
void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar) void rlOrtho(float left, float right, float bottom, float top, float znear, float zfar)
{ {
// NOTE: If left-right and top-botton values are equal it could create a division by zero, // NOTE: If left-right and top-botton values are equal it could create a division by zero,
// response to it is platform/compiler dependent // response to it is platform/compiler dependent
Matrix matOrtho = { 0 }; Matrix matOrtho = { 0 };
float rl = (float)(right - left); float rl = right - left;
float tb = (float)(top - bottom); float tb = top - bottom;
float fn = (float)(zfar - znear); float fn = zfar - znear;
matOrtho.m0 = 2.0f/rl; matOrtho.m0 = 2.0f/rl;
matOrtho.m1 = 0.0f; matOrtho.m1 = 0.0f;
@ -1386,9 +1386,9 @@ void rlOrtho(double left, double right, double bottom, double top, double znear,
matOrtho.m9 = 0.0f; matOrtho.m9 = 0.0f;
matOrtho.m10 = -2.0f/fn; matOrtho.m10 = -2.0f/fn;
matOrtho.m11 = 0.0f; matOrtho.m11 = 0.0f;
matOrtho.m12 = -((float)left + (float)right)/rl; matOrtho.m12 = -(left + right)/rl;
matOrtho.m13 = -((float)top + (float)bottom)/tb; matOrtho.m13 = -(top + bottom)/tb;
matOrtho.m14 = -((float)zfar + (float)znear)/fn; matOrtho.m14 = -(zfar + znear)/fn;
matOrtho.m15 = 1.0f; matOrtho.m15 = 1.0f;
*RLGL.State.currentMatrix = rlMatrixMultiply(*RLGL.State.currentMatrix, matOrtho); *RLGL.State.currentMatrix = rlMatrixMultiply(*RLGL.State.currentMatrix, matOrtho);
@ -1402,20 +1402,20 @@ void rlViewport(int x, int y, int width, int height)
} }
// Set clip planes distances // Set clip planes distances
void rlSetClipPlanes(double nearPlane, double farPlane) void rlSetClipPlanes(float nearPlane, float farPlane)
{ {
rlCullDistanceNear = nearPlane; rlCullDistanceNear = nearPlane;
rlCullDistanceFar = farPlane; rlCullDistanceFar = farPlane;
} }
// Get cull plane distance near // Get cull plane distance near
double rlGetCullDistanceNear(void) float rlGetCullDistanceNear(void)
{ {
return rlCullDistanceNear; return rlCullDistanceNear;
} }
// Get cull plane distance far // Get cull plane distance far
double rlGetCullDistanceFar(void) float rlGetCullDistanceFar(void)
{ {
return rlCullDistanceFar; return rlCullDistanceFar;
} }

View File

@ -512,7 +512,7 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i
if (fileData != NULL) if (fileData != NULL)
{ {
qoi_desc desc = { 0 }; qoi_desc desc = { 0 };
image.data = qoi_decode(fileData, dataSize, &desc, (int) fileData[12]); image.data = qoi_decode(fileData, dataSize, &desc, 0); // NOTE: Using channels from file data
image.width = desc.width; image.width = desc.width;
image.height = desc.height; image.height = desc.height;
image.format = (desc.channels == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : PIXELFORMAT_UNCOMPRESSED_R8G8B8; image.format = (desc.channels == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : PIXELFORMAT_UNCOMPRESSED_R8G8B8;
@ -540,7 +540,6 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
image.mipmaps = 1; image.mipmaps = 1;
PEP_FREE(pepData);
pep_free(&p); pep_free(&p);
} }
} }
@ -1269,48 +1268,58 @@ void ImageCrop(Image *image, Rectangle crop)
// Security check to avoid program crash // Security check to avoid program crash
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
crop.x = floorf(crop.x);
crop.y = floorf(crop.y);
crop.width = floorf(crop.width);
crop.height = floorf(crop.height);
// Security checks to validate crop rectangle // Security checks to validate crop rectangle
if (crop.x < 0) { crop.width += crop.x; crop.x = 0; } if (crop.x < 0) { crop.width += crop.x; crop.x = 0; }
if (crop.y < 0) { crop.height += crop.y; crop.y = 0; } if (crop.y < 0) { crop.height += crop.y; crop.y = 0; }
if ((crop.x + crop.width) > image->width) crop.width = image->width - crop.x; if ((crop.x + crop.width) > image->width) crop.width = image->width - crop.x;
if ((crop.y + crop.height) > image->height) crop.height = image->height - crop.y; if ((crop.y + crop.height) > image->height) crop.height = image->height - crop.y;
if ((crop.x > image->width) || (crop.y > image->height)) if ((crop.x > image->width) || (crop.y > image->height) || (crop.width < 1) || (crop.height < 1))
{ {
TRACELOG(LOG_WARNING, "IMAGE: Failed to crop, rectangle out of bounds"); TRACELOG(LOG_WARNING, "IMAGE: Failed to crop, rectangle out of bounds");
return; return;
} }
int cropX = (int)crop.x;
int cropY = (int)crop.y;
int cropWidth = (int)crop.width;
int cropHeight = (int)crop.height;
if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level"); if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats"); if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
else else
{ {
int bytesPerPixel = GetPixelDataSize(1, 1, image->format); int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
unsigned char *croppedData = (unsigned char *)RL_MALLOC((int)(crop.width*crop.height)*bytesPerPixel); unsigned char *croppedData = (unsigned char *)RL_MALLOC(cropWidth*cropHeight*bytesPerPixel);
// OPTION 1: Move cropped data line-by-line // OPTION 1: Move cropped data line-by-line
for (int y = (int)crop.y, offsetSize = 0; y < (int)(crop.y + crop.height); y++) for (int y = cropY, offsetSize = 0; y < cropY + cropHeight; y++)
{ {
memcpy(croppedData + offsetSize, ((unsigned char *)image->data) + (y*image->width + (int)crop.x)*bytesPerPixel, (int)crop.width*bytesPerPixel); memcpy(croppedData + offsetSize, ((unsigned char *)image->data) + (y*image->width + cropX)*bytesPerPixel, cropWidth*bytesPerPixel);
offsetSize += ((int)crop.width*bytesPerPixel); offsetSize += (cropWidth*bytesPerPixel);
} }
/* /*
// OPTION 2: Move cropped data pixel-by-pixel or byte-by-byte // OPTION 2: Move cropped data pixel-by-pixel or byte-by-byte
for (int y = (int)crop.y; y < (int)(crop.y + crop.height); y++) for (int y = cropY; y < cropY + cropHeight; y++)
{ {
for (int x = (int)crop.x; x < (int)(crop.x + crop.width); x++) for (int x = cropX; x < cropX + cropWidth; x++)
{ {
//memcpy(croppedData + ((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel); //memcpy(croppedData + ((y - cropY)*cropWidth + (x - cropX))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel);
for (int i = 0; i < bytesPerPixel; i++) croppedData[((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i]; for (int i = 0; i < bytesPerPixel; i++) croppedData[((y - cropY)*cropWidth + (x - cropX))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i];
} }
} }
*/ */
RL_FREE(image->data); RL_FREE(image->data);
image->data = croppedData; image->data = croppedData;
image->width = (int)crop.width; image->width = cropWidth;
image->height = (int)crop.height; image->height = cropHeight;
} }
} }
@ -1547,13 +1556,25 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
int textLength = (int)strlen(text); // Get length of text in bytes int textLength = (int)strlen(text); // Get length of text in bytes
int textOffsetX = 0; // Image drawing position X int textOffsetX = 0; // Image drawing position X
int textOffsetY = 0; // Offset between lines (on linebreak '\n') int textOffsetY = 0; // Offset between lines (on linebreak '\n')
int lineIndex = 0; // Current line index (on linebreak '\n')
// NOTE: Text image is generated at font base size, later scaled to desired font size // NOTE: Text image is generated at font base size, later scaled to desired font size
Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing); // WARNING: Module required: rtext Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing); // WARNING: Module required: rtext
Vector2 textSize = MeasureTextEx(font, text, fontSize, spacing); Vector2 textSize = MeasureTextEx(font, text, fontSize, spacing);
int lineBreakCount = 0; // Number of line breaks ('\n') in text
for (int i = 0; i < textLength; i++)
{
if (text[i] == '\n') lineBreakCount++;
}
float lineSpacing = 0.0f; // Line spacing, as used by MeasureTextEx()
if (lineBreakCount > 0) lineSpacing = (textSize.y - fontSize)/lineBreakCount - fontSize;
float lineStep = (float)font.baseSize + lineSpacing*(float)font.baseSize/fontSize; // Line advance at base size
// Create image to store text // Create image to store text
imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK); imText = GenImageColor((int)imSize.x, font.baseSize + (int)(lineBreakCount*lineStep), BLANK);
for (int i = 0; i < textLength;) for (int i = 0; i < textLength;)
{ {
@ -1564,9 +1585,8 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
if (codepoint == '\n') if (codepoint == '\n')
{ {
// NOTE: Fixed line spacing of 1.5 line-height lineIndex++;
// TODO: Support custom line spacing defined by user textOffsetY = (int)(lineIndex*lineStep);
textOffsetY += (font.baseSize + font.baseSize/2);
textOffsetX = 0; textOffsetX = 0;
} }
else else
@ -1586,15 +1606,15 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
} }
// Scale image depending on text size // Scale image depending on text size
if (textSize.y != imSize.y) if (fontSize != (float)font.baseSize)
{ {
float scaleFactor = textSize.y/imSize.y; float scaleFactor = fontSize/(float)font.baseSize;
TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor); TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor);
// Using nearest-neighbor scaling algorithm for default font // Using nearest-neighbor scaling algorithm for default font
// TODO: Support other scaling mechanism, use flag? // TODO: Support other scaling mechanism, use flag?
if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imText.width*scaleFactor), (int)(imText.height*scaleFactor));
else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); else ImageResize(&imText, (int)(imText.width*scaleFactor), (int)(imText.height*scaleFactor));
} }
#else #else
imText = GenImageColor(200, 60, BLACK); // Generating placeholder black image rectangle imText = GenImageColor(200, 60, BLACK); // Generating placeholder black image rectangle
@ -2904,13 +2924,13 @@ void ImageColorBrightness(Image *image, int brightness)
int cG = pixels[i].g + brightness; int cG = pixels[i].g + brightness;
int cB = pixels[i].b + brightness; int cB = pixels[i].b + brightness;
if (cR < 0) cR = 1; if (cR < 0) cR = 0;
if (cR > 255) cR = 255; if (cR > 255) cR = 255;
if (cG < 0) cG = 1; if (cG < 0) cG = 0;
if (cG > 255) cG = 255; if (cG > 255) cG = 255;
if (cB < 0) cB = 1; if (cB < 0) cB = 0;
if (cB > 255) cB = 255; if (cB > 255) cB = 255;
pixels[i].r = (unsigned char)cR; pixels[i].r = (unsigned char)cR;
@ -3011,9 +3031,9 @@ Color *LoadImageColors(Image image)
{ {
unsigned short pixel = ((unsigned short *)image.data)[i]; unsigned short pixel = ((unsigned short *)image.data)[i];
pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*255.0f/31);
pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31)); pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*255.0f/31);
pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31)); pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*255.0f/31);
pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255); pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255);
} break; } break;
@ -3021,9 +3041,9 @@ Color *LoadImageColors(Image image)
{ {
unsigned short pixel = ((unsigned short *)image.data)[i]; unsigned short pixel = ((unsigned short *)image.data)[i];
pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*255.0f/31);
pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63)); pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*255.0f/63);
pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31)); pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*255.0f/31);
pixels[i].a = 255; pixels[i].a = 255;
} break; } break;
@ -3255,9 +3275,9 @@ Color GetImageColor(Image image, int x, int y)
{ {
unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x]; unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x];
color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*255.0f/31);
color.g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31)); color.g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*255.0f/31);
color.b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31)); color.b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*255.0f/31);
color.a = (unsigned char)((pixel & 0b0000000000000001)*255); color.a = (unsigned char)((pixel & 0b0000000000000001)*255);
} break; } break;
@ -3265,9 +3285,9 @@ Color GetImageColor(Image image, int x, int y)
{ {
unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x]; unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x];
color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*255.0f/31);
color.g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63)); color.g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*255.0f/63);
color.b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31)); color.b = (unsigned char)((float)(pixel & 0b0000000000011111)*255.0f/31);
color.a = 255; color.a = 255;
} break; } break;

View File

@ -106,8 +106,8 @@ reasings_api.$(EXTENSION): ../../examples/others/reasings.h rlparser
./rlparser -i ../../examples/others/reasings.h -o reasings_api.$(EXTENSION) -f $(FORMAT) -d EASEDEF ./rlparser -i ../../examples/others/reasings.h -o reasings_api.$(EXTENSION) -f $(FORMAT) -d EASEDEF
# rlparser execution: [raygui.h] parse, generating some output files # rlparser execution: [raygui.h] parse, generating some output files
raygui_api.$(EXTENSION): ../raygui.h rlparser raygui_api.$(EXTENSION): ../../examples/core/raygui.h rlparser
./rlparser -i ../raygui.h -o raygui_api.$(EXTENSION) -f $(FORMAT) -d RAYGUIAPI -t "RAYGUI IMPLEMENTATION" ./rlparser -i ../../examples/core/raygui.h -o raygui_api.$(EXTENSION) -f $(FORMAT) -d RAYGUIAPI -t "RAYGUI IMPLEMENTATION"
# Target to generate required APIs output files # Target to generate required APIs output files
parse: raylib_api.$(EXTENSION) raymath_api.$(EXTENSION) rlgl_api.$(EXTENSION) raygui_api.$(EXTENSION) parse: raylib_api.$(EXTENSION) raymath_api.$(EXTENSION) rlgl_api.$(EXTENSION) raygui_api.$(EXTENSION)

View File

@ -15,7 +15,7 @@
{ {
"name": "RAYLIB_VERSION_MINOR", "name": "RAYLIB_VERSION_MINOR",
"type": "INT", "type": "INT",
"value": 2, "value": 5,
"description": "" "description": ""
}, },
{ {
@ -27,7 +27,7 @@
{ {
"name": "RAYLIB_VERSION", "name": "RAYLIB_VERSION",
"type": "STRING", "type": "STRING",
"value": "6.2", "value": "6.5-dev",
"description": "" "description": ""
}, },
{ {

View File

@ -15,7 +15,7 @@ return {
{ {
name = "RAYLIB_VERSION_MINOR", name = "RAYLIB_VERSION_MINOR",
type = "INT", type = "INT",
value = 2, value = 5,
description = "" description = ""
}, },
{ {
@ -27,7 +27,7 @@ return {
{ {
name = "RAYLIB_VERSION", name = "RAYLIB_VERSION",
type = "STRING", type = "STRING",
value = "6.2", value = "6.5-dev",
description = "" description = ""
}, },
{ {

View File

@ -9,7 +9,7 @@
(description "")) (description ""))
((name "RAYLIB_VERSION_MINOR") ((name "RAYLIB_VERSION_MINOR")
(type "INT") (type "INT")
(value 2) (value 5)
(description "")) (description ""))
((name "RAYLIB_VERSION_PATCH") ((name "RAYLIB_VERSION_PATCH")
(type "INT") (type "INT")
@ -17,7 +17,7 @@
(description "")) (description ""))
((name "RAYLIB_VERSION") ((name "RAYLIB_VERSION")
(type "STRING") (type "STRING")
(value "6.2") (value "6.5-dev")
(description "")) (description ""))
((name "__declspec(x)") ((name "__declspec(x)")
(type "MACRO") (type "MACRO")

View File

@ -14,7 +14,7 @@ Define 002: RAYLIB_VERSION_MAJOR
Define 003: RAYLIB_VERSION_MINOR Define 003: RAYLIB_VERSION_MINOR
Name: RAYLIB_VERSION_MINOR Name: RAYLIB_VERSION_MINOR
Type: INT Type: INT
Value: 2 Value: 5
Description: Description:
Define 004: RAYLIB_VERSION_PATCH Define 004: RAYLIB_VERSION_PATCH
Name: RAYLIB_VERSION_PATCH Name: RAYLIB_VERSION_PATCH
@ -24,7 +24,7 @@ Define 004: RAYLIB_VERSION_PATCH
Define 005: RAYLIB_VERSION Define 005: RAYLIB_VERSION
Name: RAYLIB_VERSION Name: RAYLIB_VERSION
Type: STRING Type: STRING
Value: "6.2" Value: "6.5-dev"
Description: Description:
Define 006: __declspec(x) Define 006: __declspec(x)
Name: __declspec(x) Name: __declspec(x)

View File

@ -3,9 +3,9 @@
<Defines count="56"> <Defines count="56">
<Define name="RAYLIB_H" type="GUARD" value="" desc="" /> <Define name="RAYLIB_H" type="GUARD" value="" desc="" />
<Define name="RAYLIB_VERSION_MAJOR" type="INT" value="6" desc="" /> <Define name="RAYLIB_VERSION_MAJOR" type="INT" value="6" desc="" />
<Define name="RAYLIB_VERSION_MINOR" type="INT" value="2" desc="" /> <Define name="RAYLIB_VERSION_MINOR" type="INT" value="5" desc="" />
<Define name="RAYLIB_VERSION_PATCH" type="INT" value="0" desc="" /> <Define name="RAYLIB_VERSION_PATCH" type="INT" value="0" desc="" />
<Define name="RAYLIB_VERSION" type="STRING" value="6.2" desc="" /> <Define name="RAYLIB_VERSION" type="STRING" value="6.5-dev" desc="" />
<Define name="__declspec(x)" type="MACRO" value="__attribute__((x))" desc="" /> <Define name="__declspec(x)" type="MACRO" value="__attribute__((x))" desc="" />
<Define name="RLAPI" type="UNKNOWN" value="__declspec(dllexport)" desc="Building the library as a Win32 shared library (.dll)" /> <Define name="RLAPI" type="UNKNOWN" value="__declspec(dllexport)" desc="Building the library as a Win32 shared library (.dll)" />
<Define name="PI" type="FLOAT" value="3.14159265358979323846" desc="" /> <Define name="PI" type="FLOAT" value="3.14159265358979323846" desc="" />