45 Commits

Author SHA1 Message Date
7f9ded7642 [makefile] ANDROID_ARCH check (#5888) 2026-05-26 18:13:58 +02:00
34b06ca587 Update BINDINGS.md (#5887) 2026-05-25 16:05:20 +02:00
4d845608b8 Update listed Raylib version for zig bindings (#5886)
As per the README at https://github.com/raylib-zig/raylib-zig, raylib-zig now supports raylib 6.0
2026-05-25 08:32:52 +02:00
Ray
eaf32c83bf REXM: Latest w64devkit supports make directly, simplifying code to avoid mingw32-make 2026-05-25 00:26:26 +02:00
808e6b9b20 Raylib-lua version to 5.5 (#5884)
raylib-lua from 5.0 to 5.5 in bindings.
2026-05-24 17:36:12 +02:00
7dd72e7328 rlparser: update raylib_api.* by CI 2026-05-24 07:25:01 +00:00
Ray
f8270483e1 Merge branch 'master' of https://github.com/raysan5/raylib 2026-05-24 09:24:33 +02:00
Ray
f17babfe8a REVIEWED: #5879 2026-05-24 09:24:26 +02:00
f65d5ad7a9 rshapes: fix auto segment rounded-corner math and rounding (#5883) 2026-05-24 08:55:08 +02:00
Ray
0d78f10161 Reviewed comments formating 2026-05-20 09:16:16 +02:00
7d5b61ce01 [rlsw][SEGFAULT] Fix triangle and quad spans applying pixels out of bounds (#5849)
* fix triangle and quad spans applying pixels out of bounds

* remove off by one errors on x/y LoopMax

* apply the RASTER_QUAD offset at the loop start so it increments correctly

* fix missing endif

* remove include guard to allow dyMin usage

* early exit if nothing to draw on a span

* incorporate dxStart into xSubstep to make xOffset calculate a single time

* remove ghost comment

* early exit for quads, with a float cast on the left and top distance calculation

* remove duplicate xLoopEnd
2026-05-20 09:12:20 +02:00
Ray
b48933b096 Merge branch 'master' of https://github.com/raysan5/raylib 2026-05-19 18:59:30 +02:00
Ray
fd1dfd7d65 ADDED: rprand_get_value_raw() 2026-05-19 18:59:23 +02:00
be56f2c524 [rcore][GLFW] Fix GetClipboardImage() creating new connection under X11 (#5871)
* Improve GetClipboardImage implementation under X11

* Remove code for creating new connection, handle selection in GLFW connection instead.

* `GetClipboardImage()`: Small fix to remove unnecessary boolean
2026-05-19 18:57:42 +02:00
d31c10a01e Adjust segment calculation in DrawRectangleRounded to be consistent with DrawRectangleRoundedLinesEx (#5875) 2026-05-19 18:48:28 +02:00
c04e57399a Fix compilation for -DPLATFORM=RGFW (#5870)
When compiling with
cmake -S . -B build-desktop-rgfw -DPLATFORM=RGFW -DCMAKE_BUILD_TYPE=Release
cmake --build build-desktop-rgfw

these errors appeared:
raylib/examples/others/raylib_opengl_interop.c💯5: error: unknown type name ‘GLuint’
  100 |     GLuint vao = 0;
[etc]
2026-05-15 17:40:26 +02:00
6c090f6193 Fix build.zig building examples all the time (#5869) 2026-05-15 17:39:27 +02:00
Ray
5ca45bce37 Update rcore.c 2026-05-14 20:05:25 +02:00
Ray
729327a078 Update .gitignore 2026-05-14 20:05:21 +02:00
ea76845ecb [cmake]: remove GLFW_BUILD warnings for when platform is SDL (#5865) 2026-05-14 13:02:38 +02:00
5506aed190 BINDINGS.md: update golang binding to v6.0 (#5866) 2026-05-14 13:00:40 +02:00
Ray
43366d1c6a Some formatting tweaks 2026-05-13 09:28:08 +02:00
Ray
f35f4b9fad REVIEWED: GetTime(), small addition for RPI Pico 2 2026-05-13 09:17:04 +02:00
Ray
c4b4fcc17e Format review 2026-05-13 09:16:29 +02:00
Ray
fbf132d1d1 Use rlgl provided interface instead of rlsw direct access 2026-05-13 09:16:19 +02:00
Ray
e274c195af Update rcore.c 2026-05-13 09:15:50 +02:00
fd28dc5644 [rtext] add warning for loadfontex/loadfontfrommemory (#5864)
* add warning for loadfontex/loadfontfrommemory

* bump to re-run build tests
2026-05-13 08:56:13 +02:00
Ray
5aa3de194c Updated miniaudio warnings with emscripten 2026-05-12 20:33:20 +02:00
9400199b80 [rcore][RGFW] Add fullscreen behaviour on size 0 window creation (#5859)
* port glfw's behaviour on size 0 window creation to rgfw

* updates with change suggestions

* don't do the FLAG_FULLSCREEN_MODE check twice for no reason

---------

Co-authored-by: CrackedPixel <5776225+CrackedPixel@users.noreply.github.com>
2026-05-11 23:25:00 +02:00
Ray
200d344dee Merge branch 'master' of https://github.com/raysan5/raylib 2026-05-10 19:31:22 +02:00
Ray
094edcd32e Update Makefile 2026-05-10 19:31:19 +02:00
a005a044da [rcore_android] Restore face-button input on Android gamepads (#5824)
The KEYBOARD-source veto added in #5439 drops face-button key
events that arrive with both AINPUT_SOURCE_KEYBOARD and
AINPUT_SOURCE_GAMEPAD set on the source bitmask. Confirmed
reproducible on GameSir X2 Type-C and 8BitDo Ultimate Bluetooth,
both reporting source 0x501 on every face-button key event.

This source-bit pattern is general AOSP behaviour since Android
3.2 (commit 6f2fba4 in frameworks/base, Feb 2011): EventHub adds
InputDeviceClass::KEYBOARD to any device whose evdev keyBitmask
claims gamepad buttons (BTN_JOYSTICK..BTN_DIGI), and
KeyboardInputMapper::getEventSource stamps the resulting
KEYBOARD|GAMEPAD source on every outgoing key event.

Use AndroidTranslateGamepadButton(keycode) as the discriminator
instead. Recognised gamepad keycodes route to the gamepad path;
unknown keycodes fall through to the keyboard handler.

Assisted-by: Claude:claude-opus-4-7
2026-05-10 19:20:35 +02:00
ae315eecb9 added win32 to cmake + examples (#5855) 2026-05-10 19:09:24 +02:00
dcb0ca5d14 [raudio]: free converterResidual in UnloadSoundAlias to prevent leak (#5857)
The example audio_sound_multi was leaking memory every single time the spacebar was pressed.

```c
Direct leak of 576 byte(s) in 9 object(s) allocated from:
    #0 0x758a41019447 in calloc (/usr/lib/liblsan.so.0+0x19447) (BuildId: 8ee115309adc591d231c961c43d245cfa68d9aa7)
    #1 0x562dfbd2c4f3 in LoadAudioBuffer (/home/peter/raylib/examples/audio/audio_sound_multi+0xfa4f3) (BuildId: ea2a6f45d724abeccf904143a32012266f259f93)
```

This patch fixes that leak.
2026-05-10 15:01:38 +02:00
07b729d5d6 fix: check fread return value in jar_mod_load_file (#5840) 2026-05-09 18:55:02 +02:00
cd4599b447 Update BINDINGS.md (#5850) 2026-05-09 18:48:10 +02:00
Ray
b2ea5eae5e REVIEWED: long long usage in all raylib, minimize
REVIEWED: Using `long long` format instead of `long long int`, more consistent with the `short` alternative for smaller `int`, instead of `short int`
2026-05-08 22:59:55 +02:00
mjt
29ff1f02e9 Update Makefile comment (#5846) 2026-05-08 20:19:08 +02:00
d840a100a7 [CMake] Add configure-time test for libatomic requirement (#5847)
CMake now checks if -latomic is required for 64-bit atomics, and links
it if it's required. Miniaudio is the only thing in raylib that needs
it, so it's put behind SUPPORT_MODULE_RAUDIO.
2026-05-08 20:16:45 +02:00
95bfa196fd [cmake] Fix config.h parsing into cmake options (#5844)
Parse SUPPORT_ defines from src/config.h by their actual 0/1 values so CUSTOMIZE_BUILD exposes the correct defaults. Apply INCLUDE_EVERYTHING explicitly when registering dependent options.
2026-05-08 10:08:09 +02:00
Ray
aceb8ce3a8 Re-enable GLFW_LINUX_ENABLE_WAYLAND flag by default #5816
Wayland should be more stable at this point...
2026-05-07 15:24:08 +02:00
Ray
33e889907e ADDED: GL_SHADING_LANGUAGE_VERSION for swGetString() 2026-05-07 15:20:24 +02:00
Ray
61537200c0 Code cleaning 2026-05-07 15:18:42 +02:00
080f5c94bd [rlsw][rcore_drm] Silence warnings when using PLATFORM_DRM and GRAPHICS_API_OPENGL_SOFTWARE (#5839)
* fix warnings: goto label not used outside of SW_ENABLE_DEPTH_TEST

* comment out x coordinates that aren't used in SW_RASTER_TRIANGLE

* silence warnings: unused DrmModeConnector functions in rcore_drm.c when using GRAPHICS_API_OPENGL_SOFTWARE
2026-05-07 15:17:20 +02:00
7207c03c72 [rlsw] ESP32 optimizations (#5827)
* [rlsw] Add sw_rcp helper using Xtensa recip0.s for hot-path divisions

Adds a `sw_rcp(x)` inline reciprocal that on Xtensa (ESP32 / ESP32-S3
LX6/LX7) emits a `recip0.s` seed plus two Newton-Raphson refinement
steps -- 1-ULP accurate in ~7 instructions, all in FPU registers.
On every other target it expands to plain `1.0f/x`, so generated code
is byte-identical to before for non-Xtensa builds.

Replaces the hot-path `1.0f/x` calls that were previously compiling to
the `__divsf3` software helper on Xtensa:

  - perspective divide (1/w) in triangle clip-and-project (PCT and PC paths)
  - line and point clip-and-project NDC conversion
  - triangle span setup: dxRcp, blockLenRcp, wRcpA, wRcpB
  - triangle scanline setup: h02Rcp, h01Rcp, h12Rcp
  - axis-aligned quad: wRcp, hRcp
  - line rasterizer: stepRcp

Other `1.0f/x` uses (matrix translate/normalize, texture init `tx`/`ty`,
sw_matrix_rotate inverse-length) are not on the per-pixel hot path and
are left untouched.

Measured on ESP32-S3 @ 240 MHz, R5G6B5 240x240, textured 3D model:
contributes to a ~10-15% rasterization speedup.

Made-with: Cursor

* [rlsw] Use ESP-DSP for 4x4 matrix multiply and per-vertex MVP transform

Adds an opt-in ESP-DSP code path for ESP32 / ESP32-S3 builds. ESP-DSP is
ESP-IDF's official optimized math library and ships hand-vectorized
kernels that beat the scalar implementations on Xtensa.

Two integration points:

  1. `sw_matrix_mul_rst` -> `dspm_mult_4x4x4_f32` for any 4x4*4x4 multiply
     (used for MVP build, gluLookAt, push/multiply, etc.). rlsw stores
     matrices column-major and ESP-DSP reads row-major; the comment on the
     call site explains why the flat-buffer call still produces the
     correct column-major product (transpose-of-transposes equivalence).

  2. `sw_immediate_push_vertex` -> `dspm_mult_4x4x1_f32` for the per-vertex
     clip-space transform. Because ESP-DSP expects a row-major matrix in
     this case, a row-major copy `matMVP_rm[16]` is maintained alongside
     `matMVP` and refreshed once per `isDirtyMVP` rebuild in
     `sw_immediate_begin`. Cost is 16 scalar copies per matrix update,
     amortized over thousands of vertices per frame.

Detection is **opt-in** via `SW_USE_ESP_DSP` so existing ESP-IDF projects
that don't depend on the `esp-dsp` component keep building unchanged.
A user enables it from CMakeLists.txt (or anywhere before including
rlgl.h):

    target_compile_definitions(${COMPONENT_LIB} PRIVATE SW_USE_ESP_DSP=1)

and adds the dependency to `idf_component.yml`:

    espressif/esp-dsp: "^1.4.0"

Measured on ESP32-S3 @ 240 MHz, R5G6B5 240x240, textured 3D model:
contributes meaningfully to the overall frame-time improvement
(combined with sw_rcp).

Made-with: Cursor

* [rlsw] Add SW_TEXTURE_REPEAT_POT_FAST opt-in for POT bitmask wrap

Adds an opt-in compile-time flag that replaces the SW_REPEAT wrap chain
with a bitmask (`x & (size-1)`) for power-of-two textures. NPOT textures
keep using the original `sw_fract` / signed-modulo paths via a runtime
`(size & (size-1)) == 0` check, so SW_REPEAT remains correct for them.

Affects two samplers:

  - `sw_texture_sample_nearest`: drops the `floorf` + multiply + cast for
    POT textures in REPEAT mode (saves a software call on Xtensa).
  - `sw_texture_sample_linear`: replaces the `(x % w + w) % w` two-step
    modulo (a software divide on Xtensa) with a single bitwise AND for
    POT textures in REPEAT mode. Two's-complement int wrap covers
    negative coordinates correctly.

Off by default: for POT textures sampled with negative UVs, bitmask wrap
can differ from `sw_fract` wrap by one texel at the boundary. That is
imperceptible at typical resolutions but technically a behavior change,
so existing users get bit-for-bit identical output. Opt in if you
control your asset UVs and want the speedup:

    #define SW_TEXTURE_REPEAT_POT_FAST

This addresses the long-standing TODO comment "If the textures are POT,
avoid the division for SW_REPEAT" in `sw_texture_sample_linear`.

Made-with: Cursor
2026-05-06 12:38:52 +02:00
34 changed files with 568 additions and 298 deletions

2
.gitignore vendored
View File

@ -65,7 +65,7 @@ src/external/SDL3
# Emscripten # Emscripten
emsdk emsdk
# Ignore wasm data in examples/ # Ignore binaries generated in examples/
examples/**/* examples/**/*
!examples/**/*.* !examples/**/*.*
!examples/**/*/ !examples/**/*/

View File

@ -11,7 +11,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib-beef](https://github.com/Starpelly/raylib-beef) | **5.5** | [Beef](https://www.beeflang.org) | MIT | | [raylib-beef](https://github.com/Starpelly/raylib-beef) | **5.5** | [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-cs](https://github.com/raylib-cs/raylib-cs) | **5.5** | [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-CsLo](https://github.com/NotNotTech/Raylib-CsLo) | 4.2 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 | | [Raylib-CsLo](https://github.com/NotNotTech/Raylib-CsLo) | 4.2 | [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-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 |
@ -37,7 +37,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib-freebasic](https://github.com/WIITD/raylib-freebasic) | **5.0** | [FreeBASIC](https://www.freebasic.net) | MIT | | [raylib-freebasic](https://github.com/WIITD/raylib-freebasic) | **5.0** | [FreeBASIC](https://www.freebasic.net) | MIT |
| [raylib.f](https://github.com/cthulhuology/raylib.f) | **5.5** | [Forth](https://forth.com) | Zlib | | [raylib.f](https://github.com/cthulhuology/raylib.f) | **5.5** | [Forth](https://forth.com) | Zlib |
| [fortran-raylib](https://github.com/interkosmos/fortran-raylib) | **5.5** | [Fortran](https://fortran-lang.org) | ISC | | [fortran-raylib](https://github.com/interkosmos/fortran-raylib) | **5.5** | [Fortran](https://fortran-lang.org) | ISC |
| [raylib-go](https://github.com/gen2brain/raylib-go) | **5.5** | [Go](https://golang.org) | Zlib | | [raylib-go](https://github.com/gen2brain/raylib-go) | **6.0** | [Go](https://golang.org) | Zlib |
| [raylib-guile](https://github.com/petelliott/raylib-guile) | **auto** | [Guile](https://www.gnu.org/software/guile) | Zlib | | [raylib-guile](https://github.com/petelliott/raylib-guile) | **auto** | [Guile](https://www.gnu.org/software/guile) | Zlib |
| [gforth-raylib](https://github.com/ArnautDaniel/gforth-raylib) | 3.5 | [Gforth](https://gforth.org) | **???** | | [gforth-raylib](https://github.com/ArnautDaniel/gforth-raylib) | 3.5 | [Gforth](https://gforth.org) | **???** |
| [h-raylib](https://github.com/Anut-py/h-raylib) | **5.5-dev** | [Haskell](https://haskell.org) | Apache-2.0 | | [h-raylib](https://github.com/Anut-py/h-raylib) | **5.5-dev** | [Haskell](https://haskell.org) | Apache-2.0 |
@ -49,7 +49,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [Raylib.jl](https://github.com/chengchingwen/Raylib.jl) | 4.2 | [Julia](https://julialang.org) | Zlib | | [Raylib.jl](https://github.com/chengchingwen/Raylib.jl) | 4.2 | [Julia](https://julialang.org) | Zlib |
| [kaylib](https://github.com/electronstudio/kaylib) | 3.7 | [Kotlin/native](https://kotlinlang.org) | **???** | | [kaylib](https://github.com/electronstudio/kaylib) | 3.7 | [Kotlin/native](https://kotlinlang.org) | **???** |
| [KaylibKit](https://codeberg.org/Kenta/KaylibKit) | 4.5 | [Kotlin/native](https://kotlinlang.org) | Zlib | | [KaylibKit](https://codeberg.org/Kenta/KaylibKit) | 4.5 | [Kotlin/native](https://kotlinlang.org) | Zlib |
| [raylib-lua](https://github.com/TSnake41/raylib-lua) | 5.0 | [Lua](http://www.lua.org) | ISC | | [raylib-lua](https://github.com/TSnake41/raylib-lua) | 5.5 | [Lua](http://www.lua.org) | ISC |
| [raylib-lua-bindings (WIP)](https://github.com/legendaryredfox/raylib-lua-bindings) | 5.5 | [Lua](http://www.lua.org) | ISC | | [raylib-lua-bindings (WIP)](https://github.com/legendaryredfox/raylib-lua-bindings) | 5.5 | [Lua](http://www.lua.org) | ISC |
| [ReiLua](https://github.com/nullstare/ReiLua) | 5.5 | [Lua](http://www.lua.org) | MIT | | [ReiLua](https://github.com/nullstare/ReiLua) | 5.5 | [Lua](http://www.lua.org) | MIT |
| [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 |
@ -90,7 +90,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib-vapi](https://github.com/lxmcf/raylib-vapi) | **6.0** | [Vala](https://vala.dev) | Zlib | | [raylib-vapi](https://github.com/lxmcf/raylib-vapi) | **6.0** | [Vala](https://vala.dev) | Zlib |
| [raylib-wave](https://github.com/wavefnd/raylib-wave) | **auto** |[Wave](http://wave-lang.dev) | Zlib | | [raylib-wave](https://github.com/wavefnd/raylib-wave) | **auto** |[Wave](http://wave-lang.dev) | Zlib |
| [raylib-wren](https://github.com/TSnake41/raylib-wren) | 4.5 | [Wren](http://wren.io) | ISC | | [raylib-wren](https://github.com/TSnake41/raylib-wren) | 4.5 | [Wren](http://wren.io) | ISC |
| [raylib-zig](https://github.com/raylib-zig/raylib-zig) | **5.6-dev** | [Zig](https://ziglang.org) | MIT | | [raylib-zig](https://github.com/raylib-zig/raylib-zig) | **6.0** | [Zig](https://ziglang.org) | MIT |
| [raylib.zig](https://github.com/ryupold/raylib.zig) | **5.1-dev** | [Zig](https://ziglang.org) | MIT | | [raylib.zig](https://github.com/ryupold/raylib.zig) | **5.1-dev** | [Zig](https://ziglang.org) | MIT |
| [raylib-zig-bindings](https://github.com/L-Briand/raylib-zig-bindings) | **5.0** | [Zig](https://ziglang.org) | Zlib | | [raylib-zig-bindings](https://github.com/L-Briand/raylib-zig-bindings) | **5.0** | [Zig](https://ziglang.org) | Zlib |
| [hare-raylib](https://git.sr.ht/~evantj/hare-raylib) | **auto** | [Hare](https://harelang.org) | Zlib | | [hare-raylib](https://git.sr.ht/~evantj/hare-raylib) | **auto** | [Hare](https://harelang.org) | Zlib |
@ -106,6 +106,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [fnl-raylib](https://github.com/0riginaln0/fnl-raylib) | **5.5** | [Fennel](https://fennel-lang.org/) | MIT | | [fnl-raylib](https://github.com/0riginaln0/fnl-raylib) | **5.5** | [Fennel](https://fennel-lang.org/) | MIT |
| [Rayua](https://github.com/uiua-lang/rayua) | **5.5** | [Uiua](https://www.uiua.org/) | **???** | | [Rayua](https://github.com/uiua-lang/rayua) | **5.5** | [Uiua](https://www.uiua.org/) | **???** |
| [Target](https://github.com/FinnDemonCat/Target/tree/main/libs/raylib) | **5.5** | [Dart](https://dart.dev/) | Apache-2.0 license | | [Target](https://github.com/FinnDemonCat/Target/tree/main/libs/raylib) | **5.5** | [Dart](https://dart.dev/) | Apache-2.0 license |
| [gclang-raylib](https://github.com/gnuchanos/gcLang_Compiler/tree/main/windows_version/raylib_version)| **6.0** | [gclang](https://github.com/gnuchanos/gcLang_Compiler) | AGPL-3.0 |
### Utility Wrapers ### Utility Wrapers

View File

@ -29,7 +29,7 @@ include(CompilerFlags)
# Registers build options that are exposed to cmake # Registers build options that are exposed to cmake
include(CMakeOptions.txt) include(CMakeOptions.txt)
if (UNIX AND NOT APPLE AND NOT "${PLATFORM}" MATCHES "DRM" AND NOT "${PLATFORM}" MATCHES "Web") if (UNIX AND NOT APPLE AND NOT "${PLATFORM}" MATCHES "DRM" AND NOT "${PLATFORM}" MATCHES "Web" AND NOT "${PLATFORM}" MATCHES "SDL")
if (NOT GLFW_BUILD_WAYLAND AND NOT GLFW_BUILD_X11) if (NOT GLFW_BUILD_WAYLAND AND NOT GLFW_BUILD_X11)
message(FATAL_ERROR "Cannot disable both Wayland and X11") message(FATAL_ERROR "Cannot disable both Wayland and X11")
endif() endif()

View File

@ -6,7 +6,7 @@ if(EMSCRIPTEN)
# When configuring web builds with "emcmake cmake -B build -S .", set PLATFORM to Web by default # When configuring web builds with "emcmake cmake -B build -S .", set PLATFORM to Web by default
SET(PLATFORM Web CACHE STRING "Platform to build for.") SET(PLATFORM Web CACHE STRING "Platform to build for.")
endif() endif()
enum_option(PLATFORM "Desktop;Web;WebRGFW;Android;Raspberry Pi;DRM;SDL;RGFW;Memory" "Platform to build for.") enum_option(PLATFORM "Desktop;Win32;Web;WebRGFW;Android;Raspberry Pi;DRM;SDL;RGFW;Memory" "Platform to build for.")
enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0;Software" "Force a specific OpenGL Version?") enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0;Software" "Force a specific OpenGL Version?")
@ -29,11 +29,15 @@ option(GLFW_BUILD_WAYLAND "Build the bundled GLFW with Wayland support" OFF)
option(GLFW_BUILD_X11 "Build the bundled GLFW with X11 support" ON) option(GLFW_BUILD_X11 "Build the bundled GLFW with X11 support" ON)
option(INCLUDE_EVERYTHING "Include everything disabled by default (for CI usage)" OFF) option(INCLUDE_EVERYTHING "Include everything disabled by default (for CI usage)" OFF)
set(OFF ${INCLUDE_EVERYTHING} CACHE INTERNAL "Replace any OFF by default with \${OFF} to have it covered by this option")
include(ParseConfigHeader) include(ParseConfigHeader)
foreach(FLAG IN LISTS CONFIG_HEADER_FLAGS) foreach(FLAG IN LISTS CONFIG_HEADER_FLAGS)
string(REGEX MATCH "([^=]+)=(.+)" _ ${FLAG}) string(REGEX MATCH "([^=]+)=(.+)" _ ${FLAG})
cmake_dependent_option(${CMAKE_MATCH_1} "" ${CMAKE_MATCH_2} CUSTOMIZE_BUILD ${CMAKE_MATCH_2}) set(CONFIG_HEADER_FLAG_DEFAULT ${CMAKE_MATCH_2})
if (INCLUDE_EVERYTHING AND "${CONFIG_HEADER_FLAG_DEFAULT}" STREQUAL "OFF")
set(CONFIG_HEADER_FLAG_DEFAULT ON)
endif()
cmake_dependent_option(${CMAKE_MATCH_1} "" ${CONFIG_HEADER_FLAG_DEFAULT} CUSTOMIZE_BUILD ${CONFIG_HEADER_FLAG_DEFAULT})
endforeach() endforeach()

View File

@ -739,7 +739,6 @@ fn addExamples(
.root_module = exe_mod, .root_module = exe_mod,
.use_lld = target.result.os.tag == .windows, .use_lld = target.result.os.tag == .windows,
}); });
b.installArtifact(exe);
const install_cmd = b.addInstallArtifact(exe, .{ .dest_sub_path = b.fmt("{s}/{s}", .{ module, filename }) }); const install_cmd = b.addInstallArtifact(exe, .{ .dest_sub_path = b.fmt("{s}/{s}", .{ module, filename }) });

View File

@ -7,6 +7,30 @@ if(POLICY CMP0072)
cmake_policy(SET CMP0072 NEW) cmake_policy(SET CMP0072 NEW)
endif() endif()
include(CheckCSourceCompiles)
include(CMakePushCheckState)
function(raylib_check_libatomic_required result)
set(_atomic_test_source "
int main(void)
{
volatile long long value = 0;
return (int)__atomic_fetch_add(&value, 1, __ATOMIC_SEQ_CST);
}")
check_c_source_compiles("${_atomic_test_source}" RAYLIB_ATOMICS_WITHOUT_LIBATOMIC)
if (RAYLIB_ATOMICS_WITHOUT_LIBATOMIC)
set(${result} FALSE PARENT_SCOPE)
else ()
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_LIBRARIES atomic)
check_c_source_compiles("${_atomic_test_source}" RAYLIB_ATOMICS_WITH_LIBATOMIC)
cmake_pop_check_state()
set(${result} ${RAYLIB_ATOMICS_WITH_LIBATOMIC} PARENT_SCOPE)
endif ()
endfunction()
set(RAYLIB_DEPENDENCIES "include(CMakeFindDependencyMacro)") set(RAYLIB_DEPENDENCIES "include(CMakeFindDependencyMacro)")
if (${PLATFORM} STREQUAL "Desktop") if (${PLATFORM} STREQUAL "Desktop")
@ -67,6 +91,21 @@ if (${PLATFORM} STREQUAL "Desktop")
endif () endif ()
endif () endif ()
elseif (${PLATFORM} STREQUAL "Win32")
if ((NOT WIN32) AND (NOT CMAKE_C_COMPILER MATCHES "mingw|mingw32|mingw64"))
message(FATAL_ERROR "Win32 platform requires Windows or a cross compiler.")
endif ()
set(PLATFORM_CPP "PLATFORM_DESKTOP_WIN32")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
if (${OPENGL_VERSION} MATCHES "Software")
set(GRAPHICS "GRAPHICS_API_OPENGL_SOFTWARE")
endif ()
find_package(OpenGL QUIET)
set(LIBS_PRIVATE ${OPENGL_LIBRARIES} winmm)
elseif (${PLATFORM} STREQUAL "Web") elseif (${PLATFORM} STREQUAL "Web")
set(PLATFORM_CPP "PLATFORM_WEB") set(PLATFORM_CPP "PLATFORM_WEB")
if(NOT GRAPHICS) if(NOT GRAPHICS)
@ -222,6 +261,14 @@ endif ()
set(LIBS_PRIVATE ${LIBS_PRIVATE} ${OPENAL_LIBRARY}) set(LIBS_PRIVATE ${LIBS_PRIVATE} ${OPENAL_LIBRARY})
if (SUPPORT_MODULE_RAUDIO AND UNIX AND NOT APPLE)
raylib_check_libatomic_required(RAYLIB_LIBATOMIC_REQUIRED)
if (RAYLIB_LIBATOMIC_REQUIRED)
message(STATUS "64-bit atomics require libatomic")
list(APPEND LIBS_PRIVATE atomic)
endif ()
endif ()
if (${PLATFORM} MATCHES "Desktop") if (${PLATFORM} MATCHES "Desktop")
set(LIBS_PRIVATE ${LIBS_PRIVATE} glfw) set(LIBS_PRIVATE ${LIBS_PRIVATE} glfw)
endif () endif ()

View File

@ -10,7 +10,9 @@ string(REGEX MATCHALL ${MACRO_REGEX} MACRO_LIST ${CONFIG_HEADER_CONTENT})
set(CONFIG_HEADER_FLAGS ${MACRO_LIST}) set(CONFIG_HEADER_FLAGS ${MACRO_LIST})
list(FILTER CONFIG_HEADER_FLAGS INCLUDE REGEX "^.+SUPPORT_") list(FILTER CONFIG_HEADER_FLAGS INCLUDE REGEX "^.+SUPPORT_")
list(TRANSFORM CONFIG_HEADER_FLAGS REPLACE ${MACRO_REGEX} [[\2=OFF]] REGEX "^//") list(TRANSFORM CONFIG_HEADER_FLAGS REPLACE ${MACRO_REGEX} [[\2=OFF]] REGEX "^//")
list(TRANSFORM CONFIG_HEADER_FLAGS REPLACE ${MACRO_REGEX} [[\2=ON]]) list(TRANSFORM CONFIG_HEADER_FLAGS REPLACE ${MACRO_REGEX} [[\2=\3]] REGEX "^[^/]")
list(TRANSFORM CONFIG_HEADER_FLAGS REPLACE [[=0$]] [[=OFF]])
list(TRANSFORM CONFIG_HEADER_FLAGS REPLACE [[=1$]] [[=ON]])
set(CONFIG_HEADER_VALUES ${MACRO_LIST}) set(CONFIG_HEADER_VALUES ${MACRO_LIST})
list(FILTER CONFIG_HEADER_VALUES EXCLUDE REGEX "(^.+SUPPORT_)|(^//)") list(FILTER CONFIG_HEADER_VALUES EXCLUDE REGEX "(^.+SUPPORT_)|(^//)")

View File

@ -20,6 +20,8 @@
# - Linux (X11 desktop mode) # - Linux (X11 desktop mode)
# - macOS/OSX (x64, arm64 (not tested)) # - macOS/OSX (x64, arm64 (not tested))
# - Others (not tested) # - Others (not tested)
# > PLATFORM_DESKTOP_WIN32 (native Win32):
# - Windows (Win32, Win64)
# > PLATFORM_WEB_RGFW: # > PLATFORM_WEB_RGFW:
# - HTML5 (WebAssembly) # - HTML5 (WebAssembly)
# > PLATFORM_WEB: # > PLATFORM_WEB:
@ -794,6 +796,23 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
rm -f *.o rm -f *.o
endif endif
endif endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
ifeq ($(PLATFORM_OS),WINDOWS)
del *.o *.exe /s
endif
ifeq ($(PLATFORM_OS),BSD)
find . -type f -perm -ugo+x -delete
rm -fv *.o
endif
ifeq ($(PLATFORM_OS),LINUX)
find . -type f -executable -delete
rm -fv *.o
endif
ifeq ($(PLATFORM_OS),OSX)
find . -type f -perm +ugo+x -delete
rm -f *.o
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
find . -type f -executable -delete find . -type f -executable -delete
rm -fv *.o rm -fv *.o

View File

@ -28,7 +28,7 @@
#include "raylib.h" #include "raylib.h"
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_DESKTOP_SDL) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_DESKTOP_SDL) || defined(PLATFORM_DESKTOP_RGFW)
#if defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_ES2)
#include "glad_gles2.h" // Required for: OpenGL functionality #include "glad_gles2.h" // Required for: OpenGL functionality
#define glGenVertexArrays glGenVertexArraysOES #define glGenVertexArrays glGenVertexArraysOES

View File

@ -240,6 +240,9 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
ifeq ($(ANDROID_ARCH),x86_64) ifeq ($(ANDROID_ARCH),x86_64)
ANDROID_COMPILER_ARCH = x86_64 ANDROID_COMPILER_ARCH = x86_64
endif endif
ifndef ANDROID_COMPILER_ARCH
$(error ANDROID_COMPILER_ARCH: Unknown ANDROID_ARCH=$(ANDROID_ARCH))
endif
endif endif
# Define raylib graphics api depending on selected platform # Define raylib graphics api depending on selected platform

View File

@ -1538,10 +1538,10 @@ mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
modctx->modfile = (muchar *) JARMOD_MALLOC(fsize); modctx->modfile = (muchar *) JARMOD_MALLOC(fsize);
modctx->modfilesize = fsize; modctx->modfilesize = fsize;
memset(modctx->modfile, 0, fsize); memset(modctx->modfile, 0, fsize);
fread(modctx->modfile, fsize, 1, f); if(fread(modctx->modfile, fsize, 1, f) != 1) fsize = 0;
fclose(f); fclose(f);
if(!jar_mod_load(modctx, (void *)modctx->modfile, fsize)) fsize = 0; if(fsize && !jar_mod_load(modctx, (void *)modctx->modfile, fsize)) fsize = 0;
} else fsize = 0; } else fsize = 0;
} }
return fsize; return fsize;

View File

@ -41495,11 +41495,11 @@ Web Audio Backend
#ifdef MA_HAS_WEBAUDIO #ifdef MA_HAS_WEBAUDIO
#include <emscripten/emscripten.h> #include <emscripten/emscripten.h>
#if (__EMSCRIPTEN_major__ > 3) || (__EMSCRIPTEN_major__ == 3 && (__EMSCRIPTEN_minor__ > 1 || (__EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ >= 32))) #if (__EMSCRIPTEN_MAJOR__ > 3) || (__EMSCRIPTEN_MAJOR__ == 3 && (__EMSCRIPTEN_MINOR__ > 1 || (__EMSCRIPTEN_MINOR__ == 1 && __EMSCRIPTEN_TINY__ >= 32)))
#include <emscripten/webaudio.h> #include <emscripten/webaudio.h>
#define MA_SUPPORT_AUDIO_WORKLETS #define MA_SUPPORT_AUDIO_WORKLETS
#if (__EMSCRIPTEN_major__ > 3) || (__EMSCRIPTEN_major__ == 3 && (__EMSCRIPTEN_minor__ > 1 || (__EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ >= 70))) #if (__EMSCRIPTEN_MAJOR__ > 3) || (__EMSCRIPTEN_MAJOR__ == 3 && (__EMSCRIPTEN_MINOR__ > 1 || (__EMSCRIPTEN_MINOR__ == 1 && __EMSCRIPTEN_TINY__ >= 70)))
#define MA_SUPPORT_AUDIO_WORKLETS_VARIABLE_BUFFER_SIZE #define MA_SUPPORT_AUDIO_WORKLETS_VARIABLE_BUFFER_SIZE
#endif #endif
#endif #endif

262
src/external/rlsw.h vendored
View File

@ -164,6 +164,18 @@
#endif #endif
#endif #endif
// Fast power-of-two texture wrap (SW_REPEAT mode only)
// When defined, textures whose width/height are powers of two use a bitmask
// wrap (`x & (size-1)`) instead of `floorf`-based fractional wrap or the signed `%` chain in the linear sampler
// Saves a software divide on Xtensa and a few instructions everywhere
// NPOT textures keep using the original path via a runtime `(size & (size-1)) == 0` check,
// so SW_REPEAT remains correct for them
// The only observable behavior change is for POT textures sampled with negative UV coordinates:
// bitmask wrap (two's complement) can differ from `sw_fract` by one texel
// Off by default to keep bit-for-bit behavior; opt in if you control your asset UVs
//
//#define SW_TEXTURE_REPEAT_POT_FAST
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// OpenGL Compatibility Types // OpenGL Compatibility Types
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -200,6 +212,7 @@ typedef double GLclampd;
#define GL_RENDERER 0x1F01 #define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02 #define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03 #define GL_EXTENSIONS 0x1F03
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
//#define GL_ATTRIB_STACK_DEPTH 0x0BB0 //#define GL_ATTRIB_STACK_DEPTH 0x0BB0
//#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 //#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1
@ -507,6 +520,7 @@ typedef enum {
SW_RENDERER = GL_RENDERER, SW_RENDERER = GL_RENDERER,
SW_VERSION = GL_VERSION, SW_VERSION = GL_VERSION,
SW_EXTENSIONS = GL_EXTENSIONS, SW_EXTENSIONS = GL_EXTENSIONS,
SW_SHADING_LANGUAGE_VERSION = GL_SHADING_LANGUAGE_VERSION,
SW_COLOR_CLEAR_VALUE = GL_COLOR_CLEAR_VALUE, SW_COLOR_CLEAR_VALUE = GL_COLOR_CLEAR_VALUE,
SW_DEPTH_CLEAR_VALUE = GL_DEPTH_CLEAR_VALUE, SW_DEPTH_CLEAR_VALUE = GL_DEPTH_CLEAR_VALUE,
SW_CURRENT_COLOR = GL_CURRENT_COLOR, SW_CURRENT_COLOR = GL_CURRENT_COLOR,
@ -844,6 +858,15 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta
#endif #endif
#endif #endif
// ESP-DSP acceleration: ESP-IDF ships an optimized math library that includes
// `dspm_mult_4x4x4_f32` (4x4 matrix multiply) and `dspm_mult_4x4x1_f32` (matrix * vector)
// These are S3-tuned hand-vectorized kernels that beat the scalar versions for both throughput and code-size
// Detection is opt-in to keep the dependency optional: define SW_USE_ESP_DSP from your build system
#if defined(ESP_PLATFORM) && defined(SW_USE_ESP_DSP)
#define SW_HAS_ESP_DSP
#include "dspm_mult.h"
#endif
#ifdef __cplusplus #ifdef __cplusplus
#define SW_CURLY_INIT(name) name #define SW_CURLY_INIT(name) name
#else #else
@ -858,10 +881,10 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta
#define SW_DEG2RAD (SW_PI/180.0f) #define SW_DEG2RAD (SW_PI/180.0f)
#define SW_RAD2DEG (180.0f/SW_PI) #define SW_RAD2DEG (180.0f/SW_PI)
// When clipping a convex polygon against a plane, at most one vertex is added. // When clipping a convex polygon against a plane, at most one vertex is added
// Starting from a quadrilateral (4 vertices), clipped sequentially against // Starting from a quadrilateral (4 vertices), clipped sequentially against
// the frustum (6 planes) then the scissor rectangle (4 planes): // the frustum (6 planes) then the scissor rectangle (4 planes):
// 4 + 6 + 4 = 14 vertices maximum. // 4 + 6 + 4 = 14 vertices maximum
#define SW_MAX_CLIPPED_POLYGON_VERTICES 14 #define SW_MAX_CLIPPED_POLYGON_VERTICES 14
#define SW_CLIP_EPSILON 1e-4f #define SW_CLIP_EPSILON 1e-4f
@ -1038,6 +1061,9 @@ typedef struct {
SWmatrix currentMatrixMode; // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION) SWmatrix currentMatrixMode; // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION)
sw_matrix_t *currentMatrix; // Pointer to the currently used matrix according to the mode sw_matrix_t *currentMatrix; // Pointer to the currently used matrix according to the mode
sw_matrix_t matMVP; // Model view projection matrix, calculated and used internally sw_matrix_t matMVP; // Model view projection matrix, calculated and used internally
#ifdef SW_HAS_ESP_DSP
float matMVP_rm[16]; // Row-major MVP, kept in sync for esp-dsp dspm_mult_4x4x1_f32 vertex transform
#endif
bool isDirtyMVP; // Indicates if the MVP matrix should be rebuilt bool isDirtyMVP; // Indicates if the MVP matrix should be rebuilt
sw_handle_t boundFramebufferId; // Framebuffer currently bound sw_handle_t boundFramebufferId; // Framebuffer currently bound
@ -1141,6 +1167,14 @@ static inline void sw_matrix_id(sw_matrix_t dst)
static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RESTRICT left, const float *SW_RESTRICT right) static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RESTRICT left, const float *SW_RESTRICT right)
{ {
#ifdef SW_HAS_ESP_DSP
// dspm_mult_4x4x4_f32 treats its operands as row-major. rlsw stores matrices
// column-major, so passing them flat is equivalent to passing transposes:
// dspm_mult(L^T, R^T) computes (L^T)*(R^T) = (R*L)^T, written back into a
// flat array gives the same bit pattern as the column-major product (R*L)
// -- exactly the semantic the scalar fallback below has
dspm_mult_4x4x4_f32(left, right, dst);
#else
float l00 = left[0], l01 = left[1], l02 = left[2], l03 = left[3]; float l00 = left[0], l01 = left[1], l02 = left[2], l03 = left[3];
float l10 = left[4], l11 = left[5], l12 = left[6], l13 = left[7]; float l10 = left[4], l11 = left[5], l12 = left[6], l13 = left[7];
float l20 = left[8], l21 = left[9], l22 = left[10], l23 = left[11]; float l20 = left[8], l21 = left[9], l22 = left[10], l23 = left[11];
@ -1165,6 +1199,7 @@ static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RES
dst[7] = l10*right[3] + l11*right[7] + l12*right[11] + l13*right[15]; dst[7] = l10*right[3] + l11*right[7] + l12*right[11] + l13*right[15];
dst[11] = l20*right[3] + l21*right[7] + l22*right[11] + l23*right[15]; dst[11] = l20*right[3] + l21*right[7] + l22*right[11] + l23*right[15];
dst[15] = l30*right[3] + l31*right[7] + l32*right[11] + l33*right[15]; dst[15] = l30*right[3] + l31*right[7] + l32*right[11] + l33*right[15];
#endif
} }
static inline void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_t right) static inline void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_t right)
@ -1210,6 +1245,33 @@ static inline float sw_fract(float x)
return (x - floorf(x)); return (x - floorf(x));
} }
// Xtensa architecture optimization
// Fast reciprocal: 1-ULP accurate in ~7 instructions using the
// hardware `recip0.s` seed + two Newton-Raphson refinement steps
// All work stays in FPU registers — no `__divsf3` software call
// Hot-path divisions in the rasterizer (span/triangle setup, perspective divide, etc.) call this
// On non-Xtensa targets it transparently expands to `1.0f / x`, so generated code is identical to before
#if defined(__XTENSA__)
__attribute__((always_inline))
static inline float sw_rcp(float x)
{
float result, temp;
__asm__(
"recip0.s %0, %2\n"
"const.s %1, 1\n"
"msub.s %1, %2, %0\n"
"madd.s %0, %0, %1\n"
"const.s %1, 1\n"
"msub.s %1, %2, %0\n"
"maddn.s %0, %0, %1\n"
: "=&f"(result), "=&f"(temp) : "f"(x)
);
return result;
}
#else
static inline float sw_rcp(float x) { return 1.0f/x; }
#endif
static inline uint8_t sw_luminance8(const uint8_t *color) static inline uint8_t sw_luminance8(const uint8_t *color)
{ {
return (uint8_t)((color[0]*77 + color[1]*150 + color[2]*29) >> 8); return (uint8_t)((color[0]*77 + color[1]*150 + color[2]*29) >> 8);
@ -2406,11 +2468,31 @@ static inline void sw_texture_free(sw_texture_t *texture)
static inline void sw_texture_sample_nearest(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v) static inline void sw_texture_sample_nearest(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v)
{ {
u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u); int x, y;
v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v);
int x = u*tex->width; #ifdef SW_TEXTURE_REPEAT_POT_FAST
int y = v*tex->height; if ((tex->sWrap == SW_REPEAT) && ((tex->width & tex->wMinus1) == 0))
{
x = (int)(u*tex->width) & tex->wMinus1;
}
else
#endif
{
u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u);
x = (int)(u*tex->width);
}
#ifdef SW_TEXTURE_REPEAT_POT_FAST
if ((tex->tWrap == SW_REPEAT) && ((tex->height & tex->hMinus1) == 0))
{
y = (int)(v*tex->height) & tex->hMinus1;
}
else
#endif
{
v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v);
y = (int)(v*tex->height);
}
tex->readColor(color, tex->pixels, y*tex->width + x); tex->readColor(color, tex->pixels, y*tex->width + x);
} }
@ -2432,13 +2514,19 @@ static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_t
int x1 = x0 + 1; int x1 = x0 + 1;
int y1 = y0 + 1; int y1 = y0 + 1;
// NOTE: If the textures are POT, avoid the division for SW_REPEAT
if (tex->sWrap == SW_CLAMP) if (tex->sWrap == SW_CLAMP)
{ {
x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0; x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0;
x1 = (x1 > tex->wMinus1)? tex->wMinus1 : x1; x1 = (x1 > tex->wMinus1)? tex->wMinus1 : x1;
} }
#ifdef SW_TEXTURE_REPEAT_POT_FAST
else if ((tex->width & tex->wMinus1) == 0)
{
// POT fast path: bitmask wrap covers negative ints via two's complement
x0 = x0 & tex->wMinus1;
x1 = x1 & tex->wMinus1;
}
#endif
else else
{ {
x0 = (x0%tex->width + tex->width)%tex->width; x0 = (x0%tex->width + tex->width)%tex->width;
@ -2450,6 +2538,13 @@ static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_t
y0 = (y0 > tex->hMinus1)? tex->hMinus1 : y0; y0 = (y0 > tex->hMinus1)? tex->hMinus1 : y0;
y1 = (y1 > tex->hMinus1)? tex->hMinus1 : y1; y1 = (y1 > tex->hMinus1)? tex->hMinus1 : y1;
} }
#ifdef SW_TEXTURE_REPEAT_POT_FAST
else if ((tex->height & tex->hMinus1) == 0)
{
y0 = y0 & tex->hMinus1;
y1 = y1 & tex->hMinus1;
}
#endif
else else
{ {
y0 = (y0%tex->height + tex->height)%tex->height; y0 = (y0%tex->height + tex->height)%tex->height;
@ -3366,7 +3461,7 @@ static void sw_triangle_clip_and_project(void)
// Calculation of the reciprocal of W for normalization // Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes // as well as perspective-correct attributes
const float wRcp = 1.0f/v->position[3]; const float wRcp = sw_rcp(v->position[3]);
// Division of XYZ coordinates by weight // Division of XYZ coordinates by weight
v->position[0] *= wRcp; v->position[0] *= wRcp;
@ -3460,8 +3555,8 @@ static inline bool sw_quad_face_culling(void)
// winding in the projected space when all w > 0 // winding in the projected space when all w > 0
// A value of 0 for sgnArea means P0, P1, P2 are collinear in (x, y, w) // A value of 0 for sgnArea means P0, P1, P2 are collinear in (x, y, w)
// space, which corresponds to a degenerate triangle projection // space, which corresponds to a degenerate triangle projection
// Such quads might also be degenerate or non-planar. They are typically // Such quads might also be degenerate or non-planar
// not culled by this test (0 < 0 is false, 0 > 0 is false) // They are typically not culled by this test (0 < 0 is false, 0 > 0 is false)
// and should be handled by the clipper if necessary // and should be handled by the clipper if necessary
return (RLSW.cullFace == SW_FRONT)? (sgnArea < 0.0f) : (sgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise" return (RLSW.cullFace == SW_FRONT)? (sgnArea < 0.0f) : (sgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise"
@ -3481,7 +3576,7 @@ static void sw_quad_clip_and_project(void)
// Calculation of the reciprocal of W for normalization // Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes // as well as perspective-correct attributes
const float wRcp = 1.0f/v->position[3]; const float wRcp = sw_rcp(v->position[3]);
// Division of XYZ coordinates by weight // Division of XYZ coordinates by weight
v->position[0] *= wRcp; v->position[0] *= wRcp;
@ -3659,8 +3754,8 @@ static bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1)
if (!sw_line_clip(v0, v1)) return false; if (!sw_line_clip(v0, v1)) return false;
// Convert clip coordinates to NDC // Convert clip coordinates to NDC
v0->position[3] = 1.0f/v0->position[3]; v0->position[3] = sw_rcp(v0->position[3]);
v1->position[3] = 1.0f/v1->position[3]; v1->position[3] = sw_rcp(v1->position[3]);
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
v0->position[i] *= v0->position[3]; v0->position[i] *= v0->position[3];
@ -3709,7 +3804,7 @@ static bool sw_point_clip_and_project(sw_vertex_t *v)
if ((v->position[i] < -v->position[3]) || (v->position[i] > v->position[3])) return false; if ((v->position[i] < -v->position[3]) || (v->position[i] > v->position[3])) return false;
} }
v->position[3] = 1.0f/v->position[3]; v->position[3] = sw_rcp(v->position[3]);
v->position[0] *= v->position[3]; v->position[0] *= v->position[3];
v->position[1] *= v->position[3]; v->position[1] *= v->position[3];
v->position[2] *= v->position[3]; v->position[2] *= v->position[3];
@ -3781,8 +3876,7 @@ static inline void sw_poly_fill_render(uint32_t state)
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------
static void sw_immediate_begin(SWdraw mode) static void sw_immediate_begin(SWdraw mode)
{ {
// NOTE: Any checks to ensure command recording can start // NOTE: Any checks to ensure command recording can start must be performed before calling this function
// must be performed before calling this function.
// Recalculate the MVP if this is needed // Recalculate the MVP if this is needed
if (RLSW.isDirtyMVP) if (RLSW.isDirtyMVP)
@ -3791,6 +3885,19 @@ static void sw_immediate_begin(SWdraw mode)
RLSW.stackModelview[RLSW.stackModelviewCounter - 1], RLSW.stackModelview[RLSW.stackModelviewCounter - 1],
RLSW.stackProjection[RLSW.stackProjectionCounter - 1]); RLSW.stackProjection[RLSW.stackProjectionCounter - 1]);
#ifdef SW_HAS_ESP_DSP
// Pre-transpose to row-major so dspm_mult_4x4x1_f32(matMVP_rm, v, out)
// computes M*v directly in the per-vertex hot path; 16 scalar copies
// per MVP update vs saving ~20 cycles per vertex transform
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
RLSW.matMVP_rm[4*i + j] = RLSW.matMVP[4*j + i];
}
}
#endif
RLSW.isDirtyMVP = false; RLSW.isDirtyMVP = false;
} }
@ -3842,11 +3949,17 @@ static void sw_immediate_push_vertex(const float position[4])
sw_vertex_t *vertex = &RLSW.primitive.buffer[RLSW.primitive.vertexCount++]; sw_vertex_t *vertex = &RLSW.primitive.buffer[RLSW.primitive.vertexCount++];
// Calculate clip coordinates // Calculate clip coordinates
#ifdef SW_HAS_ESP_DSP
// dspm_mult_4x4x1_f32 declares its inputs non-const; rlsw treats them as
// read-only and the cast is safe (the kernel only loads from B)
dspm_mult_4x4x1_f32(RLSW.matMVP_rm, (float *)position, vertex->position);
#else
const float *m = RLSW.matMVP; const float *m = RLSW.matMVP;
vertex->position[0] = m[0]*position[0] + m[4]*position[1] + m[8]*position[2] + m[12]*position[3]; vertex->position[0] = m[0]*position[0] + m[4]*position[1] + m[8]*position[2] + m[12]*position[3];
vertex->position[1] = m[1]*position[0] + m[5]*position[1] + m[9]*position[2] + m[13]*position[3]; vertex->position[1] = m[1]*position[0] + m[5]*position[1] + m[9]*position[2] + m[13]*position[3];
vertex->position[2] = m[2]*position[0] + m[6]*position[1] + m[10]*position[2] + m[14]*position[3]; vertex->position[2] = m[2]*position[0] + m[6]*position[1] + m[10]*position[2] + m[14]*position[3];
vertex->position[3] = m[3]*position[0] + m[7]*position[1] + m[11]*position[2] + m[15]*position[3]; vertex->position[3] = m[3]*position[0] + m[7]*position[1] + m[11]*position[2] + m[15]*position[3];
#endif
// Copy the attributes in the current vertex // Copy the attributes in the current vertex
for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i]; for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i];
@ -4164,6 +4277,7 @@ const char *swGetString(SWget name)
case SW_RENDERER: result = "RLSW OpenGL Software Renderer"; break; case SW_RENDERER: result = "RLSW OpenGL Software Renderer"; break;
case SW_VERSION: result = RLSW_VERSION; break; case SW_VERSION: result = RLSW_VERSION; break;
case SW_EXTENSIONS: result = "None"; break; case SW_EXTENSIONS: result = "None"; break;
case SW_SHADING_LANGUAGE_VERSION: result = "Not supported"; break;
default: RLSW.errCode = SW_INVALID_ENUM; break; default: RLSW.errCode = SW_INVALID_ENUM; break;
} }
@ -5271,8 +5385,18 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
int xEnd = (int)end->position[0]; int xEnd = (int)end->position[0];
if (xStart == xEnd) return; if (xStart == xEnd) return;
// Intercept the span bounds to ensure to not write before the framebuffer
int xLoopStart = (xStart >= 0)? xStart : 0;
int xLoopEnd = (xEnd <= RLSW.colorBuffer->width)? xEnd : RLSW.colorBuffer->width;
if (xLoopStart >= xLoopEnd) return; // Nothing to draw
// Get the current row and skip if outside the framebuffer
// Maybe this check is better suited elsewhere?
int y = (int)start->position[1];
if (y < 0 || y >= RLSW.colorBuffer->height) return;
// Compute the inverse horizontal distance along the X axis // Compute the inverse horizontal distance along the X axis
float dxRcp = 1.0f/(end->position[0] - start->position[0]); float dxRcp = sw_rcp(end->position[0] - start->position[0]);
// Compute the interpolation steps along the X axis // Compute the interpolation steps along the X axis
float dWdx = (end->position[3] - start->position[3])*dxRcp; float dWdx = (end->position[3] - start->position[3])*dxRcp;
@ -5291,27 +5415,29 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
#endif #endif
// Compute the subpixel distance to traverse before the first pixel // Compute the subpixel distance to traverse before the first pixel
// Also step further into them to move away from the colorbuffer edge
float xSubstep = 1.0f - sw_fract(start->position[0]); float xSubstep = 1.0f - sw_fract(start->position[0]);
float dxStart = (float)(xLoopStart - xStart);
float xOffset = xSubstep + dxStart;
// Initializing the interpolation starting values // Initializing the interpolation starting values
float w = start->position[3] + dWdx*xSubstep; float w = start->position[3] + dWdx*xOffset;
float color[4] = { float color[4] = {
start->color[0] + dCdx[0]*xSubstep, start->color[0] + dCdx[0]*xOffset,
start->color[1] + dCdx[1]*xSubstep, start->color[1] + dCdx[1]*xOffset,
start->color[2] + dCdx[2]*xSubstep, start->color[2] + dCdx[2]*xOffset,
start->color[3] + dCdx[3]*xSubstep start->color[3] + dCdx[3]*xOffset
}; };
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
float z = start->position[2] + dZdx*xSubstep; float z = start->position[2] + dZdx*xOffset;
#endif #endif
#ifdef SW_ENABLE_TEXTURE #ifdef SW_ENABLE_TEXTURE
float u = start->texcoord[0] + dUdx*xSubstep; float u = start->texcoord[0] + dUdx*xOffset;
float v = start->texcoord[1] + dVdx*xSubstep; float v = start->texcoord[1] + dVdx*xOffset;
#endif #endif
// Pre-calculate the starting pointers for the framebuffer row // Pre-calculate the starting pointers for the framebuffer row
int y = (int)start->position[1]; int baseOffset = y*RLSW.colorBuffer->width + xLoopStart;
int baseOffset = y*RLSW.colorBuffer->width + xStart;
uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE;
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE; uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE;
@ -5319,19 +5445,19 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
#define SW_AFFINE_BLOCK 16 #define SW_AFFINE_BLOCK 16
int x = xStart; int x = xLoopStart;
while (x < xEnd) while (x < xLoopEnd)
{ {
// Clamp last block to remaining pixels // Clamp last block to remaining pixels
int blockEnd = x + SW_AFFINE_BLOCK; int blockEnd = x + SW_AFFINE_BLOCK;
if (blockEnd > xEnd) blockEnd = xEnd; if (blockEnd > xLoopEnd) blockEnd = xLoopEnd;
float blockLenF = (float)(blockEnd - x); float blockLenF = (float)(blockEnd - x);
float blockLenRcp = 1.0f/blockLenF; float blockLenRcp = sw_rcp(blockLenF);
// Only 2 '1/w' here; none inside the pixel loop // Only 2 '1/w' here; none inside the pixel loop
float wRcpA = 1.0f/w; float wRcpA = sw_rcp(w);
float wB = w + dWdx*blockLenF; float wB = w + dWdx*blockLenF;
float wRcpB = 1.0f/wB; float wRcpB = sw_rcp(wB);
// Perspective-correct color at both block endpoints, then affine gradient // Perspective-correct color at both block endpoints, then affine gradient
float srcColor[4] = { float srcColor[4] = {
@ -5402,7 +5528,9 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
} }
#endif #endif
#ifdef SW_ENABLE_DEPTH_TEST
discard: discard:
#endif
srcColor[0] += dSrcColordx[0]; srcColor[0] += dSrcColordx[0];
srcColor[1] += dSrcColordx[1]; srcColor[1] += dSrcColordx[1];
srcColor[2] += dSrcColordx[2]; srcColor[2] += dSrcColordx[2];
@ -5447,9 +5575,10 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con
if (v0->position[1] > v1->position[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } if (v0->position[1] > v1->position[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; }
// Extracting coordinates from the sorted vertices // Extracting coordinates from the sorted vertices
float x0 = v0->position[0], y0 = v0->position[1]; // Put x away for safe keeping; only y is used right now; silences warnings
float x1 = v1->position[0], y1 = v1->position[1]; float y0 = v0->position[1];
float x2 = v2->position[0], y2 = v2->position[1]; float y1 = v1->position[1];
float y2 = v2->position[1];
// Compute height differences // Compute height differences
float h02 = y2 - y0; float h02 = y2 - y0;
@ -5459,9 +5588,9 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con
if (h02 < 1e-6f) return; if (h02 < 1e-6f) return;
// Inverse edge dy for per-edge dV/dy (scanline interpolation) // Inverse edge dy for per-edge dV/dy (scanline interpolation)
float h02Rcp = 1.0f/h02; float h02Rcp = sw_rcp(h02);
float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; float h01Rcp = (h01 > 1e-6f)? sw_rcp(h01) : 0.0f;
float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; float h12Rcp = (h12 > 1e-6f)? sw_rcp(h12) : 0.0f;
// Compute gradients for each side of the triangle // Compute gradients for each side of the triangle
sw_vertex_t dVXdy02, dVXdy01, dVXdy12; sw_vertex_t dVXdy02, dVXdy01, dVXdy12;
@ -5556,12 +5685,20 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
int xMax = (int)br->position[0]; int xMax = (int)br->position[0];
int yMax = (int)br->position[1]; int yMax = (int)br->position[1];
// Exit early if no pixels to draw. Use these later for loop boundaries
int yLoopMin = (yMin >= 0)? yMin : 0;
int xLoopMin = (xMin >= 0)? xMin : 0;
int yLoopMax = (yMax <= RLSW.colorBuffer->height)? yMax : RLSW.colorBuffer->height;
int xLoopMax = (xMax <= RLSW.colorBuffer->width)? xMax : RLSW.colorBuffer->width;
if (yLoopMin >= yLoopMax || xLoopMin >= xLoopMax) return;
float w = (float)(xMax - xMin); float w = (float)(xMax - xMin);
float h = (float)(yMax - yMin); float h = (float)(yMax - yMin);
if ((w <= 0) || (h <= 0)) return; if ((w <= 0) || (h <= 0)) return;
float wRcp = 1.0f/w; float wRcp = sw_rcp(w);
float hRcp = 1.0f/h; float hRcp = sw_rcp(h);
// Subpixel corrections // Subpixel corrections
float xSubstep = 1.0f - sw_fract(tl->position[0]); float xSubstep = 1.0f - sw_fract(tl->position[0]);
@ -5609,21 +5746,44 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
uint8_t *dPixels = RLSW.depthBuffer->pixels; uint8_t *dPixels = RLSW.depthBuffer->pixels;
#endif #endif
for (int y = yMin; y < yMax; y++) // Calculate the distance the in-bounds boundary is from the quad's edges, only on the left and top
float dxMin = (float)(xLoopMin - xMin);
float dyMin = (float)(yLoopMin - yMin);
// Correct our start by how far it's clipped outside the framebuffer
cRow[0] += dCdx[0]*dxMin + dCdy[0]*dyMin;
cRow[1] += dCdx[1]*dxMin + dCdy[1]*dyMin;
cRow[2] += dCdx[2]*dxMin + dCdy[2]*dyMin;
cRow[3] += dCdx[3]*dxMin + dCdy[3]*dyMin;
#ifdef SW_ENABLE_DEPTH_TEST
zRow += dZdy*dyMin + dZdx*dxMin;
#endif
#ifdef SW_ENABLE_TEXTURE
uRow += dUdy*dyMin + dUdx*dxMin;
vRow += dVdy*dyMin + dVdx*dxMin;
#endif
for (int y = yLoopMin; y < yLoopMax; y++)
{ {
int baseOffset = y*stride + xMin; int baseOffset = y*stride + xLoopMin;
uint8_t *cPtr = cPixels + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; uint8_t *cPtr = cPixels + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE;
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE; uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE;
// Copy the cursors without destroying the offset maths
float z = zRow; float z = zRow;
#endif #endif
#ifdef SW_ENABLE_TEXTURE #ifdef SW_ENABLE_TEXTURE
float u = uRow; float u = uRow;
float v = vRow; float v = vRow;
#endif #endif
float color[4] = { cRow[0], cRow[1], cRow[2], cRow[3] }; float color[4] = {
cRow[0],
cRow[1],
cRow[2],
cRow[3]
};
for (int x = xMin; x < xMax; x++) for (int x = xLoopMin; x < xLoopMax; x++)
{ {
float srcColor[4] = { color[0], color[1], color[2], color[3] }; float srcColor[4] = { color[0], color[1], color[2], color[3] };
@ -5659,7 +5819,10 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
} }
#endif #endif
#ifdef SW_ENABLE_DEPTH_TEST
discard: discard:
#endif
// Move one pixel over without touching the original "start offset"
color[0] += dCdx[0]; color[0] += dCdx[0];
color[1] += dCdx[1]; color[1] += dCdx[1];
color[2] += dCdx[2]; color[2] += dCdx[2];
@ -5682,6 +5845,9 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
cPtr += SW_FRAMEBUFFER_COLOR_SIZE; cPtr += SW_FRAMEBUFFER_COLOR_SIZE;
} }
// The for loop is clamped to the right side of the screen
// However, these cursor start vars are still on the left
// That's fine, advancing to the next row
cRow[0] += dCdy[0]; cRow[0] += dCdy[0];
cRow[1] += dCdy[1]; cRow[1] += dCdy[1];
cRow[2] += dCdy[2]; cRow[2] += dCdy[2];
@ -5746,7 +5912,7 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1)
// Compute per pixel increments // Compute per pixel increments
float xInc = dx/steps; float xInc = dx/steps;
float yInc = dy/steps; float yInc = dy/steps;
float stepRcp = 1.0f/steps; float stepRcp = sw_rcp(steps);
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
float zInc = (v1->position[2] - v0->position[2])*stepRcp; float zInc = (v1->position[2] - v0->position[2])*stepRcp;
#endif #endif
@ -5812,7 +5978,9 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1)
} }
#endif #endif
#ifdef SW_ENABLE_DEPTH_TEST
discard: discard:
#endif
x += xInc; x += xInc;
y += yInc; y += yInc;
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST

10
src/external/rprand.h vendored
View File

@ -1,6 +1,6 @@
/********************************************************************************************** /**********************************************************************************************
* *
* rprand v1.0 - A simple and easy-to-use pseudo-random numbers generator (PRNG) * rprand v1.1 - A simple and easy-to-use pseudo-random numbers generator (PRNG)
* *
* FEATURES: * FEATURES:
* - Pseudo-random values generation, 32 bits: [0..4294967295] * - Pseudo-random values generation, 32 bits: [0..4294967295]
@ -118,6 +118,7 @@ extern "C" { // Prevents name mangling of functions
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
RPRANDAPI void rprand_set_seed(unsigned long long seed); // Set rprand_state for Xoshiro128**, seed is 64bit RPRANDAPI void rprand_set_seed(unsigned long long seed); // Set rprand_state for Xoshiro128**, seed is 64bit
RPRANDAPI int rprand_get_value(int min, int max); // Get random value within a range, min and max included RPRANDAPI int rprand_get_value(int min, int max); // Get random value within a range, min and max included
RPRANDAPI int rprand_get_value_raw(void); // Get random value, Xoshiro128** generator (uses global rprand_state)
RPRANDAPI int *rprand_load_sequence(unsigned int count, int min, int max); // Load pseudo-random numbers sequence with no duplicates RPRANDAPI int *rprand_load_sequence(unsigned int count, int min, int max); // Load pseudo-random numbers sequence with no duplicates
RPRANDAPI void rprand_unload_sequence(int *sequence); // Unload pseudo-random numbers sequence RPRANDAPI void rprand_unload_sequence(int *sequence); // Unload pseudo-random numbers sequence
@ -186,6 +187,13 @@ int rprand_get_value(int min, int max)
return value; return value;
} }
int rprand_get_value_raw(void)
{
int value = rprand_xoshiro();
return value;
}
// Load pseudo-random numbers sequence with no duplicates, min and max included // Load pseudo-random numbers sequence with no duplicates, min and max included
int *rprand_load_sequence(unsigned int count, int min, int max) int *rprand_load_sequence(unsigned int count, int min, int max)
{ {

View File

@ -4,14 +4,14 @@
#ifndef WIN32_CLIPBOARD_ #ifndef WIN32_CLIPBOARD_
#define WIN32_CLIPBOARD_ #define WIN32_CLIPBOARD_
unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long long int *dataSize); unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned int *dataSize);
#endif // WIN32_CLIPBOARD_ #endif // WIN32_CLIPBOARD_
#ifdef WIN32_CLIPBOARD_IMPLEMENTATION #ifdef WIN32_CLIPBOARD_IMPLEMENTATION
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <limits.h>
// NOTE: These search for architecture is taken from "windows.h", and it's necessary to avoid including windows.h // NOTE: These search for architecture is taken from "windows.h", and it's necessary to avoid including windows.h
// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. <minwindef.h>) can cause problems is these are not defined // and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. <minwindef.h>) can cause problems is these are not defined
@ -213,7 +213,7 @@ static int GetPixelDataOffset(BITMAPINFOHEADER bih); // Get pixel data offset fr
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition // Module Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long long int *dataSize) unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned int *dataSize)
{ {
unsigned char *bmpData = NULL; unsigned char *bmpData = NULL;
@ -228,7 +228,7 @@ unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long
*width = bmpInfoHeader->biWidth; *width = bmpInfoHeader->biWidth;
*height = bmpInfoHeader->biHeight; *height = bmpInfoHeader->biHeight;
SIZE_T clipDataSize = GlobalSize(clipHandle); SIZE_T clipDataSize = GlobalSize(clipHandle);
if (clipDataSize >= sizeof(BITMAPINFOHEADER)) if ((clipDataSize >= sizeof(BITMAPINFOHEADER)) && (clipDataSize < INT_MAX))
{ {
int pixelOffset = GetPixelDataOffset(*bmpInfoHeader); int pixelOffset = GetPixelDataOffset(*bmpInfoHeader);
@ -236,7 +236,7 @@ unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long
//------------------------------------------------------------------------ //------------------------------------------------------------------------
BITMAPFILEHEADER bmpFileHeader = { 0 }; BITMAPFILEHEADER bmpFileHeader = { 0 };
SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize; SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize;
*dataSize = bmpFileSize; *dataSize = (unsigned int)bmpFileSize;
bmpFileHeader.bfType = 0x4D42; // BMP fil type constant bmpFileHeader.bfType = 0x4D42; // BMP fil type constant
bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine
@ -254,7 +254,7 @@ unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long
} }
else else
{ {
TRACELOG(LOG_WARNING, "Clipboard data is malformed"); TRACELOG(LOG_WARNING, "Clipboard data is not supported (>2GB?)");
GlobalUnlock(clipHandle); GlobalUnlock(clipHandle);
CloseClipboard(); CloseClipboard();
} }

View File

@ -656,7 +656,7 @@ double GetTime(void)
double time = 0.0; double time = 0.0;
struct timespec ts = { 0 }; struct timespec ts = { 0 };
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
@ -1273,20 +1273,19 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
int32_t keycode = AKeyEvent_getKeyCode(event); int32_t keycode = AKeyEvent_getKeyCode(event);
//int32_t AKeyEvent_getMetaState(event); //int32_t AKeyEvent_getMetaState(event);
// Handle gamepad button presses and releases // Handle gamepad button presses and releases. AOSP stamps the
// NOTE: Skip gamepad handling if this is a keyboard event, as some devices // KEYBOARD source bit on every key event from a gamepad, so
// report both AINPUT_SOURCE_KEYBOARD and AINPUT_SOURCE_GAMEPAD flags // discriminate on the keycode rather than gating on source bits.
if ((FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) || if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD)) && FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD))
!FLAG_IS_SET(source, AINPUT_SOURCE_KEYBOARD)) {
GamepadButton button = AndroidTranslateGamepadButton(keycode);
if (button != GAMEPAD_BUTTON_UNKNOWN)
{ {
// Assuming a single gamepad, "detected" on its input event // Assuming a single gamepad, "detected" on its input event
CORE.Input.Gamepad.ready[0] = true; CORE.Input.Gamepad.ready[0] = true;
GamepadButton button = AndroidTranslateGamepadButton(keycode);
if (button == GAMEPAD_BUTTON_UNKNOWN) return 1;
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
{ {
CORE.Input.Gamepad.currentButtonState[0][button] = 1; CORE.Input.Gamepad.currentButtonState[0][button] = 1;
@ -1295,6 +1294,8 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
return 1; // Handled gamepad button return 1; // Handled gamepad button
} }
// Unknown keycode: fall through to the keyboard handler below.
}
KeyboardKey key = ((keycode > 0) && (keycode < KEYCODE_MAP_SIZE))? mapKeycode[keycode] : KEY_NULL; KeyboardKey key = ((keycode > 0) && (keycode < KEYCODE_MAP_SIZE))? mapKeycode[keycode] : KEY_NULL;
if (key != KEY_NULL) if (key != KEY_NULL)

View File

@ -1042,11 +1042,6 @@ const char *GetClipboardText(void)
return glfwGetClipboardString(platform.handle); return glfwGetClipboardString(platform.handle);
} }
#if SUPPORT_CLIPBOARD_IMAGE && defined(__linux__) && defined(_GLFW_X11)
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#endif
// Get clipboard image // Get clipboard image
Image GetClipboardImage(void) Image GetClipboardImage(void)
{ {
@ -1054,7 +1049,8 @@ Image GetClipboardImage(void)
#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES #if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
#if defined(_WIN32) #if defined(_WIN32)
unsigned long long int dataSize = 0;
unsigned int dataSize = 0;
void *bmpData = NULL; void *bmpData = NULL;
int width = 0; int width = 0;
int height = 0; int height = 0;
@ -1065,32 +1061,30 @@ Image GetClipboardImage(void)
else image = LoadImageFromMemory(".bmp", (const unsigned char *)bmpData, (int)dataSize); else image = LoadImageFromMemory(".bmp", (const unsigned char *)bmpData, (int)dataSize);
#elif defined(__linux__) && defined(_GLFW_X11) #elif defined(__linux__) && defined(_GLFW_X11)
// REF: https://github.com/ColleagueRiley/Clipboard-Copy-Paste/blob/main/x11.c // REF: https://github.com/ColleagueRiley/Clipboard-Copy-Paste/blob/main/x11.c
Display *dpy = XOpenDisplay(NULL);
if (!dpy) return image;
Window root = DefaultRootWindow(dpy); static Atom clipboard = 0;
Window win = XCreateSimpleWindow( static Atom targetType = 0;
dpy, // The connection to the X Server static Atom property = 0;
root, // The 'Parent' window (usually the desktop/root)
0, 0, // X and Y position on the screen
1, 1, // Width and Height (1x1 pixel)
0, // Border width
0, // Border color
0 // Background color
);
Atom clipboard = XInternAtom(dpy, "CLIPBOARD", False); Display *display = glfwGetX11Display();
Atom targetType = XInternAtom(dpy, "image/png", False); // Ask for PNG XID window = glfwGetX11Window(platform.handle);
Atom property = XInternAtom(dpy, "RAYLIB_CLIPBOARD_MANAGER", False);
// Request the data: "Convert whatever is in CLIPBOARD to image/png and put it in RAYLIB_CLIPBOARD_MANAGER" // Lazy-load X11 atoms
XConvertSelection(dpy, clipboard, targetType, property, win, CurrentTime); if(clipboard == 0)
{
clipboard = XInternAtom(display, "CLIPBOARD", False);
targetType = XInternAtom(display, "image/png", False);
property = XInternAtom(display, "RAYLIB_CLIPBOARD_MANAGER", False);
}
XConvertSelection(display, clipboard, targetType, property, window, CurrentTime);
XSync(display, 0);
// Wait for the SelectionNotify event
XEvent ev = { 0 }; XEvent ev = { 0 };
XNextEvent(dpy, &ev);
// Keep calling until we get SelectionNotify
while (XCheckTypedEvent(display, SelectionNotify, &ev) == False);
Atom actualType = { 0 }; Atom actualType = { 0 };
int actualFormat = 0; int actualFormat = 0;
@ -1098,8 +1092,7 @@ Image GetClipboardImage(void)
unsigned long bytesAfter = 0; unsigned long bytesAfter = 0;
unsigned char *data = NULL; unsigned char *data = NULL;
// Read the data from our ghost window's property XGetWindowProperty(display, window, property, 0, ~0L, False, AnyPropertyType,
XGetWindowProperty(dpy, win, property, 0, ~0L, False, AnyPropertyType,
&actualType, &actualFormat, &nitems, &bytesAfter, &data); &actualType, &actualFormat, &nitems, &bytesAfter, &data);
if (data != NULL) if (data != NULL)
@ -1108,11 +1101,9 @@ Image GetClipboardImage(void)
XFree(data); XFree(data);
} }
XDestroyWindow(dpy, win);
XCloseDisplay(dpy);
#else #else
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform"); TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
#endif // defined(_WIN32) #endif // _WIN32
#else #else
TRACELOG(LOG_WARNING, "Clipboard image: SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly"); TRACELOG(LOG_WARNING, "Clipboard image: SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly");
#endif // SUPPORT_CLIPBOARD_IMAGE #endif // SUPPORT_CLIPBOARD_IMAGE

91
src/platforms/rcore_desktop_rgfw.c Executable file → Normal file
View File

@ -1024,15 +1024,15 @@ Image GetClipboardImage(void)
#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES #if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
#if defined(_WIN32) #if defined(_WIN32)
unsigned long long int dataSize = 0; // moved into _WIN32 scope until other platforms gain support unsigned int dataSize = 0;
void *fileData = NULL; // moved into _WIN32 scope until other platforms gain support void *fileData = NULL;
int width = 0; int width = 0;
int height = 0; int height = 0;
fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize); fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data"); if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data");
else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, dataSize); else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, (int)dataSize);
#elif defined(__linux__) && defined(DRGFW_X11) #elif defined(__linux__) && defined(DRGFW_X11)
@ -1082,7 +1082,7 @@ Image GetClipboardImage(void)
XCloseDisplay(dpy); XCloseDisplay(dpy);
#else #else
TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_RGFW doesn't implement GetClipboardImage() for this OS"); TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_RGFW doesn't implement GetClipboardImage() for this OS");
#endif // defined(_WIN32) #endif // _WIN32
#else #else
TRACELOG(LOG_WARNING, "Clipboard image: SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly"); TRACELOG(LOG_WARNING, "Clipboard image: SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly");
#endif // SUPPORT_CLIPBOARD_IMAGE #endif // SUPPORT_CLIPBOARD_IMAGE
@ -1132,8 +1132,8 @@ void SwapScreenBuffer(void)
{ {
if (platform.surface) if (platform.surface)
{ {
// copy rlsw pixel data to the surface framebuffer // Copy rlsw pixel data to the surface framebuffer
swReadPixels(0, 0, platform.surfaceWidth, platform.surfaceHeight, SW_RGBA, SW_UNSIGNED_BYTE, platform.surfacePixels); rlCopyFramebuffer(0, 0, platform.surfaceWidth, platform.surfaceHeight, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.surfacePixels);
// Mac wants a different pixel order. I cant seem to get this to work any other way // Mac wants a different pixel order. I cant seem to get this to work any other way
#if defined(__APPLE__) #if defined(__APPLE__)
@ -1677,10 +1677,62 @@ int InitPlatform(void)
// Initialize RGFW internal global state, only required systems // Initialize RGFW internal global state, only required systems
unsigned int flags = RGFW_windowCenter | RGFW_windowAllowDND; unsigned int flags = RGFW_windowCenter | RGFW_windowAllowDND;
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, RGFW_windowNoBorder);
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, RGFW_windowNoResize);
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, RGFW_windowTransparent);
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, RGFW_windowHide);
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, RGFW_windowMaximize);
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(flags, RGFW_windowFocusOnShow | RGFW_windowFocus);
if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
{
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
// Check window creation flags // Check window creation flags
// Init window in fullscreen mode if requested
// NOTE: Keeping original screen size for toggle
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{ {
FLAG_SET(flags, RGFW_windowFullscreen); FLAG_SET(flags, RGFW_windowFullscreen);
int result = RGFW_init();
if (result != 0)
{
TRACELOG(LOG_WARNING, "RGFW: Failed to initialize RGFW");
return -1;
}
// NOTE: Fullscreen applications default to the primary monitor
RGFW_monitor *monitor = RGFW_getPrimaryMonitor();
if (!monitor)
{
TRACELOG(LOG_WARNING, "RGFW: Failed to get primary monitor");
return -1;
}
// Default display resolution to that of the current mode
CORE.Window.display.width = monitor->mode.w;
CORE.Window.display.height = monitor->mode.h;
// Check if user requested some screen size
if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
{
// Set some default screen size in case user decides to exit fullscreen mode
CORE.Window.previousScreen.width = 800;
CORE.Window.previousScreen.height = 450;
CORE.Window.previousPosition.x = (CORE.Window.display.width - CORE.Window.previousScreen.width)/2;
CORE.Window.previousPosition.y = (CORE.Window.display.height - CORE.Window.previousScreen.height)/2;
// Set screen width/height to the display width/height
if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
}
else
{
CORE.Window.previousScreen = CORE.Window.screen;
CORE.Window.screen = CORE.Window.display;
}
} }
if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
@ -1688,16 +1740,16 @@ int InitPlatform(void)
FLAG_SET(flags, RGFW_windowedFullscreen); FLAG_SET(flags, RGFW_windowedFullscreen);
} }
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, RGFW_windowNoBorder); if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, RGFW_windowNoResize); {
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, RGFW_windowTransparent); #if !defined(__APPLE__)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) FLAG_SET(flags, RGFW_windowFullscreen); CORE.Window.screen.width = CORE.Window.screen.width*GetWindowScaleDPI().x;
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, RGFW_windowHide); CORE.Window.screen.height = CORE.Window.screen.height*GetWindowScaleDPI().y;
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, RGFW_windowMaximize); #endif
}
// NOTE: Some OpenGL context attributes must be set before window creation // NOTE: Some OpenGL context attributes must be set before window creation
// Check selection OpenGL version // Check selection OpenGL version
RGFW_glHints* hints = RGFW_getGlobalHints_OpenGL(); RGFW_glHints* hints = RGFW_getGlobalHints_OpenGL();
if (rlGetVersion() == RL_OPENGL_21) if (rlGetVersion() == RL_OPENGL_21)
{ {
@ -1720,20 +1772,9 @@ int InitPlatform(void)
hints->minor = 1; hints->minor = 1;
hints->renderer = RGFW_glSoftware; hints->renderer = RGFW_glSoftware;
} }
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) hints->samples = 4; if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) hints->samples = 4;
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(flags, RGFW_windowFocusOnShow | RGFW_windowFocus);
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
#if !defined(__APPLE__)
CORE.Window.screen.width = CORE.Window.screen.width * GetWindowScaleDPI().x;
CORE.Window.screen.height = CORE.Window.screen.height * GetWindowScaleDPI().y;
#endif
}
RGFW_setGlobalHints_OpenGL(hints); RGFW_setGlobalHints_OpenGL(hints);
platform.window = RGFW_createWindow((CORE.Window.title != 0)? CORE.Window.title : " ", 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, flags | RGFW_windowOpenGL); platform.window = RGFW_createWindow((CORE.Window.title != 0)? CORE.Window.title : " ", 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, flags | RGFW_windowOpenGL);
#ifndef PLATFORM_WEB_RGFW #ifndef PLATFORM_WEB_RGFW

View File

@ -1526,7 +1526,6 @@ int InitPlatform(void)
if (hr < 0) TRACELOG(LOG_ERROR, "%s failed, hresult=0x%lx", "SetProcessDpiAwareness", (DWORD)hr); if (hr < 0) TRACELOG(LOG_ERROR, "%s failed, hresult=0x%lx", "SetProcessDpiAwareness", (DWORD)hr);
} }
*/ */
HINSTANCE hInstance = GetModuleHandleW(0); HINSTANCE hInstance = GetModuleHandleW(0);
// Define window class // Define window class

View File

@ -266,9 +266,12 @@ static void PollKeyboardEvents(void); // Process evdev keyboard events
static void PollGamepadEvents(void); // Process evdev gamepad events static void PollGamepadEvents(void); // Process evdev gamepad events
static void PollMouseEvents(void); // Process evdev mouse events static void PollMouseEvents(void); // Process evdev mouse events
// Not used by software rendering.
#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode); // Search matching DRM mode in connector's mode list static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode); // Search matching DRM mode in connector's mode list
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list
#endif
static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform()) static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
@ -1003,7 +1006,7 @@ double GetTime(void)
double time = 0.0; double time = 0.0;
struct timespec ts = { 0 }; struct timespec ts = { 0 };
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
@ -2560,6 +2563,7 @@ static void PollMouseEvents(void)
} }
} }
#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
// Search matching DRM mode in connector's mode list // Search matching DRM mode in connector's mode list
static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode) static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode)
{ {
@ -2648,6 +2652,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
return nearestIndex; return nearestIndex;
} }
#endif
// Compute framebuffer size relative to screen size and display size // Compute framebuffer size relative to screen size and display size
// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified // NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified

View File

@ -364,14 +364,18 @@ double GetTime(void)
{ {
double time = 0.0; double time = 0.0;
#if defined(_WIN32) #if defined(_WIN32)
LARGE_INTEGER now = { 0 }; LARGE_INTEGER currentTicks = { 0 };
QueryPerformanceCounter(&now); QueryPerformanceCounter(&currentTicks);
return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
time = (double)(currentTicks.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__) #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec ts = { 0 }; struct timespec ts = { 0 };
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
#elif defined(PICO_RP2350)
time = (double)to_ms_since_boot(get_absolute_time())/1000.0;
#endif #endif
return time; return time;
} }

View File

@ -341,9 +341,11 @@ void SwapScreenBuffer(void)
double GetTime(void) double GetTime(void)
{ {
double time = 0.0; double time = 0.0;
struct timespec ts = { 0 }; struct timespec ts = { 0 };
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
return time; return time;

View File

@ -858,7 +858,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0)) else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
{ {
drmp3_config config = { 0 }; drmp3_config config = { 0 };
unsigned long long int totalFrameCount = 0; unsigned long long totalFrameCount = 0;
// NOTE: Forcing conversion to 32bit float sample size on reading // NOTE: Forcing conversion to 32bit float sample size on reading
wave.data = drmp3_open_memory_and_read_pcm_frames_f32(fileData, dataSize, &config, &totalFrameCount, NULL); wave.data = drmp3_open_memory_and_read_pcm_frames_f32(fileData, dataSize, &config, &totalFrameCount, NULL);
@ -868,7 +868,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
{ {
wave.channels = config.channels; wave.channels = config.channels;
wave.sampleRate = config.sampleRate; wave.sampleRate = config.sampleRate;
wave.frameCount = (int)totalFrameCount; wave.frameCount = (unsigned int)totalFrameCount; // WARNING: Potential loss of data
} }
else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data"); else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data");
@ -896,13 +896,13 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
#if SUPPORT_FILEFORMAT_FLAC #if SUPPORT_FILEFORMAT_FLAC
else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0)) else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0))
{ {
unsigned long long int totalFrameCount = 0; unsigned long long totalFrameCount = 0;
// NOTE: Forcing conversion to 16bit sample size on reading // NOTE: Forcing conversion to 16bit sample size on reading
wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL); wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL);
wave.sampleSize = 16; wave.sampleSize = 16;
if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount; if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount; // WARNING: Potential loss of data
else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data"); else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data");
} }
#endif #endif
@ -1048,6 +1048,7 @@ void UnloadSoundAlias(Sound alias)
{ {
UntrackAudioBuffer(alias.stream.buffer); UntrackAudioBuffer(alias.stream.buffer);
ma_data_converter_uninit(&alias.stream.buffer->converter, NULL); ma_data_converter_uninit(&alias.stream.buffer->converter, NULL);
RL_FREE(alias.stream.buffer->converterResidual);
RL_FREE(alias.stream.buffer); RL_FREE(alias.stream.buffer);
} }
} }

View File

@ -1164,7 +1164,7 @@ RLAPI bool ChangeDirectory(const char *dirPath); // Change wo
RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory
RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan
RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: `*.*`,`FILES*`,`DIRS*` RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'
RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths

View File

@ -385,7 +385,7 @@ typedef struct CoreData {
double draw; // Time measure for frame draw (seconds) double draw; // Time measure for frame draw (seconds)
double frame; // Time measure for one frame (seconds) double frame; // Time measure for one frame (seconds)
double target; // Desired time for one frame, if 0 not applied (seconds) double target; // Desired time for one frame, if 0 not applied (seconds)
unsigned long long int base; // Base time measure for hi-res timer (ticks or nanoseconds) unsigned long long base; // Base time measure for hi-res timer (ticks or nanoseconds)
unsigned int frameCounter; // Frame counter (frames) unsigned int frameCounter; // Frame counter (frames)
} Time; } Time;
@ -442,18 +442,6 @@ typedef enum AutomationEventType {
ACTION_SETTARGETFPS // param[0]: fps ACTION_SETTARGETFPS // param[0]: fps
} AutomationEventType; } AutomationEventType;
// Event type to config events flags
// WARNING: Not used at the moment
typedef enum {
EVENT_INPUT_KEYBOARD = 0,
EVENT_INPUT_MOUSE = 1,
EVENT_INPUT_GAMEPAD = 2,
EVENT_INPUT_TOUCH = 4,
EVENT_INPUT_GESTURE = 8,
EVENT_WINDOW = 16,
EVENT_CUSTOM = 32
} EventType;
// Event type name strings, required for export // Event type name strings, required for export
static const char *autoEventTypeName[] = { static const char *autoEventTypeName[] = {
"EVENT_NONE", "EVENT_NONE",
@ -482,16 +470,6 @@ static const char *autoEventTypeName[] = {
"ACTION_SETTARGETFPS" "ACTION_SETTARGETFPS"
}; };
/*
// Automation event (24 bytes)
// NOTE: Opaque struct, internal to raylib
struct AutomationEvent {
unsigned int frame; // Event frame
unsigned int type; // Event type (AutomationEventType)
int params[4]; // Event parameters (if required)
};
*/
static AutomationEventList *currentEventList = NULL; // Current automation events list, set by user, keep internal pointer static AutomationEventList *currentEventList = NULL; // Current automation events list, set by user, keep internal pointer
static bool automationEventRecording = false; // Recording automation events flag static bool automationEventRecording = false; // Recording automation events flag
//static short automationEventEnabled = 0b0000001111111111; // TODO: Automation events enabled for recording/playing //static short automationEventEnabled = 0b0000001111111111; // TODO: Automation events enabled for recording/playing
@ -528,11 +506,11 @@ __declspec(dllimport) void __stdcall Sleep(unsigned long msTimeout); // Required
const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
#endif #endif
// NOTE: PLATFORM_DESKTOP defaults to GLFW backend
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
#define PLATFORM_DESKTOP_GLFW #define PLATFORM_DESKTOP_GLFW
#endif #endif
// Include platform-specific submodules // Include platform-specific submodules
#if defined(PLATFORM_DESKTOP_GLFW) #if defined(PLATFORM_DESKTOP_GLFW)
#include "platforms/rcore_desktop_glfw.c" #include "platforms/rcore_desktop_glfw.c"
@ -2340,7 +2318,7 @@ bool FileExists(const char *fileName)
{ {
bool result = false; bool result = false;
if (ACCESS(fileName) != -1) result = true; if ((fileName != NULL) && (ACCESS(fileName) != -1)) result = true;
// NOTE: Alternatively, stat() can be used instead of access() // NOTE: Alternatively, stat() can be used instead of access()
//#include <sys/stat.h> //#include <sys/stat.h>
@ -3475,8 +3453,8 @@ unsigned int *ComputeSHA256(const unsigned char *data, int dataSize)
hash[6] = 0x1f83d9ab; hash[6] = 0x1f83d9ab;
hash[7] = 0x5be0cd19; hash[7] = 0x5be0cd19;
const unsigned long long int bitLen = ((unsigned long long int)dataSize)*8; const unsigned long long bitLen = 8ULL*dataSize;
unsigned long long int paddedSize = dataSize + sizeof(dataSize); unsigned long long paddedSize = dataSize + sizeof(dataSize);
paddedSize += (64 - (paddedSize%64)); paddedSize += (64 - (paddedSize%64));
unsigned char *buffer = (unsigned char *)RL_CALLOC(paddedSize, sizeof(unsigned char)); unsigned char *buffer = (unsigned char *)RL_CALLOC(paddedSize, sizeof(unsigned char));
@ -3487,7 +3465,7 @@ unsigned int *ComputeSHA256(const unsigned char *data, int dataSize)
buffer[(paddedSize - sizeof(bitLen)) + (i - 1)] = (bitLen >> (8*(sizeof(bitLen) - i))) & 0xFF; buffer[(paddedSize - sizeof(bitLen)) + (i - 1)] = (bitLen >> (8*(sizeof(bitLen) - i))) & 0xFF;
} }
for (unsigned long long int blockN = 0; blockN < paddedSize/64; blockN++) for (unsigned long long blockN = 0; blockN < paddedSize/64; blockN++)
{ {
unsigned int a = hash[0]; unsigned int a = hash[0];
unsigned int b = hash[1]; unsigned int b = hash[1];
@ -3509,7 +3487,7 @@ unsigned int *ComputeSHA256(const unsigned char *data, int dataSize)
} }
for (int t = 16; t < 64; t++) w[t] = SHA256_A1(w[t - 2]) + w[t - 7] + SHA256_A0(w[t - 15]) + w[t - 16]; for (int t = 16; t < 64; t++) w[t] = SHA256_A1(w[t - 2]) + w[t - 7] + SHA256_A0(w[t - 15]) + w[t - 16];
for (unsigned long long int t = 0; t < 64; t++) for (int t = 0; t < 64; t++)
{ {
unsigned int e1 = (SHA256_ROTATE_RIGHT(e, 6) ^ SHA256_ROTATE_RIGHT(e, 11) ^ SHA256_ROTATE_RIGHT(e, 25)); unsigned int e1 = (SHA256_ROTATE_RIGHT(e, 6) ^ SHA256_ROTATE_RIGHT(e, 11) ^ SHA256_ROTATE_RIGHT(e, 25));
unsigned int ch = ((e & f) ^ (~e & g)); unsigned int ch = ((e & f) ^ (~e & g));
@ -4241,7 +4219,7 @@ void InitTimer(void)
if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
{ {
CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; CORE.Time.base = (unsigned long long)now.tv_sec*1000000000LLU + (unsigned long long)now.tv_nsec;
} }
else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available"); else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available");
#endif #endif

View File

@ -157,8 +157,8 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
#endif #endif
// Functions required to query time on Windows // Functions required to query time on Windows
int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); int __stdcall QueryPerformanceCounter(unsigned long long *lpPerformanceCount);
int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); int __stdcall QueryPerformanceFrequency(unsigned long long *lpFrequency);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif
@ -518,37 +518,36 @@ static double rgGetCurrentTime(void)
time = GetTime(); time = GetTime();
#else #else
#if defined(_WIN32) #if defined(_WIN32)
unsigned long long int clockFrequency, currentTime; unsigned long long clockFrequency = 0;
unsigned long long currentClockTicks = 0;
QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
QueryPerformanceCounter(&currentTime); QueryPerformanceCounter(&currentClockTicks);
time = (double)currentTime/clockFrequency; // Time in seconds time = (double)currentClockTicks/clockFrequency; // Time in seconds
#endif #endif
#if defined(__linux__) #if defined(__linux__)
// NOTE: Only for Linux-based systems // NOTE: Only for Linux-based systems
struct timespec now; struct timespec now = { 0 };
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds unsigned long long nanoSeconds = (unsigned long long)now.tv_sec*1000000000LLU + (unsigned long long)now.tv_nsec;
time = ((double)nowTime*1e-9); // Time in seconds time = ((double)nanoSeconds*1e-9); // Time in seconds
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
//#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01 //#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01
//#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time //#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time
clock_serv_t cclock; clock_serv_t cclock = { 0 };
mach_timespec_t now; mach_timespec_t now = { 0 };
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
// NOTE: OS X does not have clock_gettime(), using clock_get_time() // NOTE: OS X does not have clock_gettime(), using clock_get_time()
clock_get_time(cclock, &now); clock_get_time(cclock, &now);
mach_port_deallocate(mach_task_self(), cclock); mach_port_deallocate(mach_task_self(), cclock);
unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds unsigned long long nanoSeconds = (unsigned long long)now.tv_sec*1000000000LLU + (unsigned long long)now.tv_nsec;
time = ((double)nowTime*1e-9); // Time in seconds time = ((double)nanoSeconds*1e-9); // Time in seconds
#endif #endif
#endif #endif

View File

@ -3647,7 +3647,7 @@ void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned
case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_ARB; break; case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_ARB; break;
case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_ARB; break; case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_ARB; break;
case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_ARB; break; case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_ARB; break;
#else // defined(GRAPHICS_API_OPENGL_ES2) #else // GRAPHICS_API_OPENGL_ES2
case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float
case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float
case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float

View File

@ -361,7 +361,7 @@ void DrawCircleSector(Vector2 center, float radius, float startAngle, float endA
{ {
// Calculate the maximum angle between segments based on the error rate (usually 0.5f) // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
if (segments <= 0) segments = minSegments; if (segments <= 0) segments = minSegments;
} }
@ -453,7 +453,7 @@ void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float
{ {
// Calculate the maximum angle between segments based on the error rate (usually 0.5f) // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
if (segments <= 0) segments = minSegments; if (segments <= 0) segments = minSegments;
} }
@ -579,7 +579,7 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startA
{ {
// Calculate the maximum angle between segments based on the error rate (usually 0.5f) // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1); float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
if (segments <= 0) segments = minSegments; if (segments <= 0) segments = minSegments;
} }
@ -670,7 +670,7 @@ void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float s
{ {
// Calculate the maximum angle between segments based on the error rate (usually 0.5f) // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1); float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360); segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
if (segments <= 0) segments = minSegments; if (segments <= 0) segments = minSegments;
} }
@ -960,7 +960,7 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
{ {
// Calculate the maximum angle between segments based on the error rate (usually 0.5f) // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)(ceilf(2*PI/th)/4.0f); segments = (int)ceilf((2*PI/th)/4.0f);
if (segments <= 0) segments = 4; if (segments <= 0) segments = 4;
} }
@ -1195,7 +1195,7 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
{ {
// Calculate the maximum angle between segments based on the error rate (usually 0.5f) // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)(ceilf(2*PI/th)/2.0f); segments = (int)ceilf((2*PI/th)/4.0f);
if (segments <= 0) segments = 4; if (segments <= 0) segments = 4;
} }

View File

@ -580,8 +580,13 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount); TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
} }
else font = GetFontDefault(); else
{
TRACELOG(LOG_WARNING, "FONT: Font is not supported by LoadFontEx/LoadFontFromMemory or no glyphs found, reverted to default font");
font = GetFontDefault();
}
#else #else
TRACELOG(LOG_WARNING, "FONT: Font is not supported by LoadFontEx/LoadFontFromMemory or no glyphs found, reverted to default font");
font = GetFontDefault(); font = GetFontDefault();
#endif #endif

View File

@ -675,13 +675,12 @@ int main(int argc, char *argv[])
// WARNING 2: raylib.a and raylib.web.a must be available when compiling locally // WARNING 2: raylib.a and raylib.web.a must be available when compiling locally
#if defined(_WIN32) #if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", GetFileNameWithoutExt(inFileName)); LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", GetFileNameWithoutExt(inFileName));
//putenv("RAYLIB_DIR=C:\\GitHub\\raylib");
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
#else #else
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", GetFileNameWithoutExt(inFileName)); LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", GetFileNameWithoutExt(inFileName));
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
#endif #endif
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
// Update generated .html metadata // Update generated .html metadata
LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exName)); LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exName));
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
@ -778,10 +777,9 @@ int main(int argc, char *argv[])
// WARNING: EMSDK_PATH must be set to proper location when calling from GitHub Actions // WARNING: EMSDK_PATH must be set to proper location when calling from GitHub Actions
#if defined(_WIN32) #if defined(_WIN32)
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
#else
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
#endif #endif
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
// Update generated .html metadata // Update generated .html metadata
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exRename), UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exRename),
TextFormat("%s/%s/%s.c", exBasePath, exCategory, exRename)); TextFormat("%s/%s/%s.c", exBasePath, exCategory, exRename));
@ -917,7 +915,7 @@ int main(int argc, char *argv[])
// Set required environment variables // Set required environment variables
//putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath)); //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
//putenv("MAKE=mingw32-make"); //putenv("MAKE=make");
//ChangeDirectory(exBasePath); //ChangeDirectory(exBasePath);
#endif #endif
for (int i = 0; i < exBuildListCount; i++) for (int i = 0; i < exBuildListCount; i++)
@ -933,7 +931,7 @@ int main(int argc, char *argv[])
// Build example for PLATFORM_DESKTOP // Build example for PLATFORM_DESKTOP
#if defined(_WIN32) #if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName); LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName)); system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName));
#elif defined(PLATFORM_DRM) #elif defined(PLATFORM_DRM)
LOG("INFO: [%s] Building example for PLATFORM_DRM (Host: POSIX)\n", exName); LOG("INFO: [%s] Building example for PLATFORM_DRM (Host: POSIX)\n", exName);
system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DRM -B > %s/%s/logs/%s.build.log 2>&1", system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DRM -B > %s/%s/logs/%s.build.log 2>&1",
@ -949,13 +947,9 @@ int main(int argc, char *argv[])
// Build: raylib.com/examples/<category>/<category>_example_name.data // Build: raylib.com/examples/<category>/<category>_example_name.data
// Build: raylib.com/examples/<category>/<category>_example_name.wasm // Build: raylib.com/examples/<category>/<category>_example_name.wasm
// Build: raylib.com/examples/<category>/<category>_example_name.js // Build: raylib.com/examples/<category>/<category>_example_name.js
#if defined(_WIN32) LOG("INFO: [%s] Building example for PLATFORM_WEB\n", exName);
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
#else
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName)); system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
#endif
// Update generated .html metadata // Update generated .html metadata
LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exName)); LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exName));
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
@ -1312,11 +1306,10 @@ int main(int argc, char *argv[])
#if defined(_WIN32) #if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exInfo->name); LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exInfo->name);
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
#else #else
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->name); LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->name);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
#endif #endif
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
// Update generated .html metadata // Update generated .html metadata
LOG("INFO: [%s.html] Updating HTML Metadata...\n", exInfo->name); LOG("INFO: [%s.html] Updating HTML Metadata...\n", exInfo->name);
@ -1495,7 +1488,7 @@ int main(int argc, char *argv[])
// Set required environment variables // Set required environment variables
//putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath)); //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
//_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); //_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
//putenv("MAKE=mingw32-make"); //putenv("MAKE=make");
//ChangeDirectory(exBasePath); //ChangeDirectory(exBasePath);
//_putenv("MAKE_PATH=C:\\raylib\\w64devkit\\bin"); //_putenv("MAKE_PATH=C:\\raylib\\w64devkit\\bin");
//_putenv("EMSDK_PATH = C:\\raylib\\emsdk"); //_putenv("EMSDK_PATH = C:\\raylib\\emsdk");
@ -1592,7 +1585,7 @@ int main(int argc, char *argv[])
// Build: raylib.com/examples/<category>/<category>_example_name.js // Build: raylib.com/examples/<category>/<category>_example_name.js
#if defined(_WIN32) #if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName); LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B > %s/%s/logs/%s.build.log 2>&1", system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B > %s/%s/logs/%s.build.log 2>&1",
exBasePath, exCategory, exName, exBasePath, exCategory, exName)); exBasePath, exCategory, exName, exBasePath, exCategory, exName));
#else #else
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName); LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName);
@ -1641,13 +1634,13 @@ int main(int argc, char *argv[])
// Set required environment variables // Set required environment variables
//putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath)); //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
//putenv("MAKE=mingw32-make"); //putenv("MAKE=make");
//ChangeDirectory(exBasePath); //ChangeDirectory(exBasePath);
#endif #endif
// Build example for PLATFORM_DESKTOP // Build example for PLATFORM_DESKTOP
#if defined(_WIN32) #if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName); LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B > %s/%s/logs/%s.build.log 2>&1", system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B > %s/%s/logs/%s.build.log 2>&1",
exBasePath, exCategory, exName, exBasePath, exCategory, exName)); exBasePath, exCategory, exName, exBasePath, exCategory, exName));
#elif defined(PLATFORM_DRM) #elif defined(PLATFORM_DRM)
LOG("INFO: [%s] Building example for PLATFORM_DRM (Host: POSIX)\n", exName); LOG("INFO: [%s] Building example for PLATFORM_DRM (Host: POSIX)\n", exName);

View File

@ -4696,7 +4696,7 @@
}, },
{ {
"name": "LoadDirectoryFilesEx", "name": "LoadDirectoryFilesEx",
"description": "Load directory filepaths with extension filtering and subdir scan; some filters available: `*.*`,`FILES*`,`DIRS*`", "description": "Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'",
"returnType": "FilePathList", "returnType": "FilePathList",
"params": [ "params": [
{ {

View File

@ -4207,7 +4207,7 @@ return {
}, },
{ {
name = "LoadDirectoryFilesEx", name = "LoadDirectoryFilesEx",
description = "Load directory filepaths with extension filtering and subdir scan; some filters available: `*.*`,`FILES*`,`DIRS*`", description = "Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'",
returnType = "FilePathList", returnType = "FilePathList",
params = { params = {
{type = "const char *", name = "basePath"}, {type = "const char *", name = "basePath"},

View File

@ -1789,7 +1789,7 @@ Function 146: LoadDirectoryFiles() (1 input parameters)
Function 147: LoadDirectoryFilesEx() (3 input parameters) Function 147: LoadDirectoryFilesEx() (3 input parameters)
Name: LoadDirectoryFilesEx Name: LoadDirectoryFilesEx
Return type: FilePathList Return type: FilePathList
Description: Load directory filepaths with extension filtering and subdir scan; some filters available: `*.*`,`FILES*`,`DIRS*` Description: Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'
Param[1]: basePath (type: const char *) Param[1]: basePath (type: const char *)
Param[2]: filter (type: const char *) Param[2]: filter (type: const char *)
Param[3]: scanSubdirs (type: bool) Param[3]: scanSubdirs (type: bool)

View File

@ -1125,7 +1125,7 @@
<Function name="LoadDirectoryFiles" retType="FilePathList" paramCount="1" desc="Load directory filepaths, files and directories, no subdirs scan"> <Function name="LoadDirectoryFiles" retType="FilePathList" paramCount="1" desc="Load directory filepaths, files and directories, no subdirs scan">
<Param type="const char *" name="dirPath" desc="" /> <Param type="const char *" name="dirPath" desc="" />
</Function> </Function>
<Function name="LoadDirectoryFilesEx" retType="FilePathList" paramCount="3" desc="Load directory filepaths with extension filtering and subdir scan; some filters available: `*.*`,`FILES*`,`DIRS*`"> <Function name="LoadDirectoryFilesEx" retType="FilePathList" paramCount="3" desc="Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'">
<Param type="const char *" name="basePath" desc="" /> <Param type="const char *" name="basePath" desc="" />
<Param type="const char *" name="filter" desc="" /> <Param type="const char *" name="filter" desc="" />
<Param type="bool" name="scanSubdirs" desc="" /> <Param type="bool" name="scanSubdirs" desc="" />