koffi 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/ChangeLog.md +6 -0
  2. package/build/qemu/2.1.2/koffi_darwin_arm64.tar.gz +0 -0
  3. package/build/qemu/2.1.2/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/2.1.2/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/2.1.2/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/2.1.2/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/2.1.2/koffi_linux_arm32hf.tar.gz +0 -0
  8. package/build/qemu/2.1.2/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/2.1.2/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/2.1.2/koffi_linux_riscv64hf64.tar.gz +0 -0
  11. package/build/qemu/2.1.2/koffi_linux_x64.tar.gz +0 -0
  12. package/build/qemu/2.1.2/koffi_openbsd_ia32.tar.gz +0 -0
  13. package/build/qemu/2.1.2/koffi_openbsd_x64.tar.gz +0 -0
  14. package/build/qemu/2.1.2/koffi_win32_arm64.tar.gz +0 -0
  15. package/build/qemu/2.1.2/koffi_win32_ia32.tar.gz +0 -0
  16. package/build/qemu/2.1.2/koffi_win32_x64.tar.gz +0 -0
  17. package/doc/templates/badges.html +3 -0
  18. package/package.json +2 -2
  19. package/src/abi_arm64.cc +35 -1
  20. package/src/abi_x64_win.cc +2 -8
  21. package/src/abi_x86.cc +1 -7
  22. package/src/ffi.hh +1 -1
  23. package/src/util.hh +6 -0
  24. package/test/raylib.js +37 -5
  25. package/vendor/libcc/libcc.cc +430 -196
  26. package/vendor/libcc/libcc.hh +1417 -1283
  27. package/vendor/raylib/BINDINGS.md +87 -70
  28. package/vendor/raylib/CHANGELOG +263 -50
  29. package/vendor/raylib/CMakeLists.txt +12 -0
  30. package/vendor/raylib/CMakeOptions.txt +8 -1
  31. package/vendor/raylib/CONVENTIONS.md +2 -3
  32. package/vendor/raylib/FAQ.md +137 -0
  33. package/vendor/raylib/HISTORY.md +62 -29
  34. package/vendor/raylib/LICENSE +1 -1
  35. package/vendor/raylib/README.md +22 -17
  36. package/vendor/raylib/ROADMAP.md +8 -7
  37. package/vendor/raylib/cmake/CompileDefinitions.cmake +19 -15
  38. package/vendor/raylib/cmake/GlfwImport.cmake +2 -0
  39. package/vendor/raylib/cmake/LibraryConfigurations.cmake +22 -16
  40. package/vendor/raylib/cmake/raylib-config.cmake +52 -49
  41. package/vendor/raylib/examples/CMakeLists.txt +14 -9
  42. package/vendor/raylib/examples/Makefile +112 -125
  43. package/vendor/raylib/examples/Makefile.Android +1 -1
  44. package/vendor/raylib/examples/Makefile.Web +145 -158
  45. package/vendor/raylib/examples/README.md +141 -141
  46. package/vendor/raylib/examples/audio/audio_module_playing.c +9 -4
  47. package/vendor/raylib/examples/audio/audio_multichannel_sound.c +8 -3
  48. package/vendor/raylib/examples/audio/audio_music_stream.c +16 -11
  49. package/vendor/raylib/examples/audio/audio_raw_stream.c +57 -9
  50. package/vendor/raylib/examples/audio/audio_sound_loading.c +8 -3
  51. package/vendor/raylib/examples/audio/audio_stream_effects.c +179 -0
  52. package/vendor/raylib/examples/audio/audio_stream_effects.png +0 -0
  53. package/vendor/raylib/examples/build.zig +17 -6
  54. package/vendor/raylib/examples/core/core_2d_camera.c +8 -4
  55. package/vendor/raylib/examples/core/core_2d_camera_mouse_zoom.c +105 -0
  56. package/vendor/raylib/examples/core/core_2d_camera_mouse_zoom.png +0 -0
  57. package/vendor/raylib/examples/core/core_2d_camera_platformer.c +11 -6
  58. package/vendor/raylib/examples/core/core_3d_camera_first_person.c +9 -4
  59. package/vendor/raylib/examples/core/core_3d_camera_free.c +9 -4
  60. package/vendor/raylib/examples/core/core_3d_camera_mode.c +8 -3
  61. package/vendor/raylib/examples/core/core_3d_picking.c +9 -4
  62. package/vendor/raylib/examples/core/core_basic_screen_manager.c +9 -7
  63. package/vendor/raylib/examples/core/core_basic_window.c +8 -3
  64. package/vendor/raylib/examples/core/core_basic_window_web.c +13 -11
  65. package/vendor/raylib/examples/core/core_custom_frame_control.c +9 -4
  66. package/vendor/raylib/examples/core/core_custom_logging.c +12 -8
  67. package/vendor/raylib/examples/core/core_drop_files.c +20 -12
  68. package/vendor/raylib/examples/core/core_input_gamepad.c +20 -15
  69. package/vendor/raylib/examples/core/core_input_gestures.c +19 -15
  70. package/vendor/raylib/examples/core/core_input_keys.c +8 -3
  71. package/vendor/raylib/examples/core/core_input_mouse.c +8 -3
  72. package/vendor/raylib/examples/core/core_input_mouse_wheel.c +8 -3
  73. package/vendor/raylib/examples/core/core_input_multitouch.c +8 -3
  74. package/vendor/raylib/examples/core/core_loading_thread.c +10 -6
  75. package/vendor/raylib/examples/core/core_random_values.c +8 -3
  76. package/vendor/raylib/examples/core/core_scissor_test.c +8 -3
  77. package/vendor/raylib/examples/core/core_smooth_pixelperfect.c +9 -4
  78. package/vendor/raylib/examples/core/core_split_screen.c +8 -3
  79. package/vendor/raylib/examples/core/core_storage_values.c +109 -3
  80. package/vendor/raylib/examples/core/core_vr_simulator.c +15 -7
  81. package/vendor/raylib/examples/core/core_window_flags.c +8 -3
  82. package/vendor/raylib/examples/core/core_window_letterbox.c +13 -18
  83. package/vendor/raylib/examples/core/core_window_should_close.c +77 -0
  84. package/vendor/raylib/examples/core/core_window_should_close.png +0 -0
  85. package/vendor/raylib/examples/core/core_world_screen.c +9 -4
  86. package/vendor/raylib/examples/examples_template.c +8 -3
  87. package/vendor/raylib/examples/models/models_animation.c +11 -7
  88. package/vendor/raylib/examples/models/models_billboard.c +9 -4
  89. package/vendor/raylib/examples/models/models_box_collisions.c +8 -3
  90. package/vendor/raylib/examples/models/models_cubicmap.c +9 -4
  91. package/vendor/raylib/examples/models/models_first_person_maze.c +9 -4
  92. package/vendor/raylib/examples/models/models_geometric_shapes.c +8 -3
  93. package/vendor/raylib/examples/models/models_heightmap.c +9 -4
  94. package/vendor/raylib/examples/models/models_loading.c +21 -17
  95. package/vendor/raylib/examples/models/models_loading_gltf.c +15 -41
  96. package/vendor/raylib/examples/models/models_loading_vox.c +9 -4
  97. package/vendor/raylib/examples/models/models_mesh_generation.c +71 -58
  98. package/vendor/raylib/examples/models/models_mesh_picking.c +25 -7
  99. package/vendor/raylib/examples/models/models_orthographic_projection.c +8 -5
  100. package/vendor/raylib/examples/models/models_rlgl_solar_system.c +6 -4
  101. package/vendor/raylib/examples/models/models_skybox.c +16 -12
  102. package/vendor/raylib/examples/models/models_waving_cubes.c +9 -4
  103. package/vendor/raylib/examples/models/models_yaw_pitch_roll.c +12 -7
  104. package/vendor/raylib/examples/models/resources/LICENSE.md +9 -10
  105. package/vendor/raylib/examples/models/resources/models/gltf/LICENSE +2 -23
  106. package/vendor/raylib/examples/models/resources/models/gltf/{raylib_32x32.glb → raylib_logo_3d.glb} +0 -0
  107. package/vendor/raylib/examples/models/resources/models/gltf/robot.blend +0 -0
  108. package/vendor/raylib/examples/models/resources/models/gltf/robot.glb +0 -0
  109. package/vendor/raylib/examples/others/easings_testbed.c +10 -8
  110. package/vendor/raylib/examples/others/easings_testbed.png +0 -0
  111. package/vendor/raylib/examples/others/embedded_files_loading.c +10 -5
  112. package/vendor/raylib/examples/others/embedded_files_loading.png +0 -0
  113. package/vendor/raylib/examples/others/raylib_opengl_interop.c +10 -6
  114. package/vendor/raylib/{src/extras/easings.h → examples/others/reasings.h} +38 -38
  115. package/vendor/raylib/examples/others/rlgl_compute_shader.c +21 -20
  116. package/vendor/raylib/examples/others/rlgl_compute_shader.png +0 -0
  117. package/vendor/raylib/examples/others/rlgl_standalone.c +4 -4
  118. package/vendor/raylib/examples/others/rlgl_standalone.png +0 -0
  119. package/vendor/raylib/examples/raylib_compile_execute.bat +2 -2
  120. package/vendor/raylib/examples/shaders/resources/shaders/glsl330/lighting.fs +1 -1
  121. package/vendor/raylib/examples/shaders/resources/shaders/glsl330/{base_lighting_instanced.vs → lighting_instancing.vs} +2 -2
  122. package/vendor/raylib/examples/shaders/rlights.h +14 -27
  123. package/vendor/raylib/examples/shaders/shaders_basic_lighting.c +24 -26
  124. package/vendor/raylib/examples/shaders/shaders_custom_uniform.c +10 -5
  125. package/vendor/raylib/examples/shaders/shaders_eratosthenes.c +13 -8
  126. package/vendor/raylib/examples/shaders/shaders_fog.c +8 -12
  127. package/vendor/raylib/examples/shaders/shaders_hot_reloading.c +10 -5
  128. package/vendor/raylib/examples/shaders/shaders_julia_set.c +9 -4
  129. package/vendor/raylib/examples/shaders/shaders_mesh_instancing.c +45 -119
  130. package/vendor/raylib/examples/shaders/shaders_model_shader.c +10 -5
  131. package/vendor/raylib/examples/shaders/shaders_multi_sample2d.c +8 -3
  132. package/vendor/raylib/examples/shaders/shaders_palette_switch.c +8 -3
  133. package/vendor/raylib/examples/shaders/shaders_postprocessing.c +9 -4
  134. package/vendor/raylib/examples/shaders/shaders_raymarching.c +14 -11
  135. package/vendor/raylib/examples/shaders/shaders_shapes_textures.c +8 -3
  136. package/vendor/raylib/examples/shaders/shaders_simple_mask.c +10 -5
  137. package/vendor/raylib/examples/shaders/shaders_spotlight.c +10 -6
  138. package/vendor/raylib/examples/shaders/shaders_texture_drawing.c +9 -4
  139. package/vendor/raylib/examples/shaders/shaders_texture_outline.c +8 -3
  140. package/vendor/raylib/examples/shaders/shaders_texture_waves.c +8 -3
  141. package/vendor/raylib/{src/extras → examples/shapes}/raygui.h +1290 -1141
  142. package/vendor/raylib/examples/{others/easings.h → shapes/reasings.h} +40 -40
  143. package/vendor/raylib/examples/shapes/shapes_basic_shapes.c +8 -3
  144. package/vendor/raylib/examples/shapes/shapes_bouncing_ball.c +8 -3
  145. package/vendor/raylib/examples/shapes/shapes_collision_area.c +10 -4
  146. package/vendor/raylib/examples/shapes/shapes_colors_palette.c +8 -3
  147. package/vendor/raylib/examples/shapes/shapes_draw_circle_sector.c +9 -4
  148. package/vendor/raylib/examples/shapes/shapes_draw_rectangle_rounded.c +9 -4
  149. package/vendor/raylib/examples/shapes/shapes_draw_ring.c +10 -6
  150. package/vendor/raylib/examples/shapes/shapes_easings_ball_anim.c +9 -4
  151. package/vendor/raylib/examples/shapes/shapes_easings_box_anim.c +9 -4
  152. package/vendor/raylib/examples/shapes/shapes_easings_rectangle_array.c +9 -4
  153. package/vendor/raylib/examples/shapes/shapes_following_eyes.c +8 -3
  154. package/vendor/raylib/examples/shapes/shapes_lines_bezier.c +8 -3
  155. package/vendor/raylib/examples/shapes/shapes_logo_raylib.c +8 -3
  156. package/vendor/raylib/examples/shapes/shapes_logo_raylib_anim.c +8 -3
  157. package/vendor/raylib/examples/shapes/shapes_rectangle_scaling.c +14 -5
  158. package/vendor/raylib/examples/shapes/shapes_top_down_lights.c +355 -0
  159. package/vendor/raylib/examples/shapes/shapes_top_down_lights.png +0 -0
  160. package/vendor/raylib/examples/text/resources/DotGothic16-Regular.ttf +0 -0
  161. package/vendor/raylib/examples/text/resources/DotGothic16-Regular_OFL.txt +93 -0
  162. package/vendor/raylib/examples/text/resources/LICENSE.md +1 -1
  163. package/vendor/raylib/examples/text/text_codepoints_loading.c +138 -0
  164. package/vendor/raylib/examples/text/text_codepoints_loading.png +0 -0
  165. package/vendor/raylib/examples/text/text_draw_3d.c +42 -33
  166. package/vendor/raylib/examples/text/text_font_filters.c +14 -11
  167. package/vendor/raylib/examples/text/text_font_loading.c +9 -4
  168. package/vendor/raylib/examples/text/text_font_sdf.c +9 -4
  169. package/vendor/raylib/examples/text/text_font_spritefont.c +12 -6
  170. package/vendor/raylib/examples/text/text_format_text.c +8 -3
  171. package/vendor/raylib/examples/text/text_input_box.c +8 -3
  172. package/vendor/raylib/examples/text/text_raylib_fonts.c +9 -4
  173. package/vendor/raylib/examples/text/text_rectangle_bounds.c +9 -5
  174. package/vendor/raylib/examples/text/text_unicode.c +9 -7
  175. package/vendor/raylib/examples/text/text_writing_anim.c +8 -3
  176. package/vendor/raylib/examples/textures/resources/scarfy_run.gif +0 -0
  177. package/vendor/raylib/examples/textures/textures_background_scrolling.c +8 -3
  178. package/vendor/raylib/examples/textures/textures_blend_modes.c +8 -3
  179. package/vendor/raylib/examples/textures/textures_bunnymark.c +8 -3
  180. package/vendor/raylib/examples/textures/textures_draw_tiled.c +14 -10
  181. package/vendor/raylib/examples/textures/textures_fog_of_war.c +154 -0
  182. package/vendor/raylib/examples/textures/textures_fog_of_war.png +0 -0
  183. package/vendor/raylib/examples/textures/textures_gif_player.c +121 -0
  184. package/vendor/raylib/examples/textures/textures_gif_player.png +0 -0
  185. package/vendor/raylib/examples/textures/textures_image_drawing.c +8 -3
  186. package/vendor/raylib/examples/textures/textures_image_generation.c +8 -3
  187. package/vendor/raylib/examples/textures/textures_image_loading.c +8 -3
  188. package/vendor/raylib/examples/textures/textures_image_processing.c +8 -3
  189. package/vendor/raylib/examples/textures/textures_image_text.c +8 -3
  190. package/vendor/raylib/examples/textures/textures_logo_raylib.c +8 -3
  191. package/vendor/raylib/examples/textures/textures_mouse_painting.c +9 -4
  192. package/vendor/raylib/examples/textures/textures_npatch_drawing.c +8 -3
  193. package/vendor/raylib/examples/textures/textures_particles_blending.c +8 -3
  194. package/vendor/raylib/examples/textures/textures_polygon.c +9 -5
  195. package/vendor/raylib/examples/textures/textures_raw_data.c +8 -3
  196. package/vendor/raylib/examples/textures/{textures_rectangle.c → textures_sprite_anim.c} +11 -5
  197. package/vendor/raylib/examples/textures/{textures_rectangle.png → textures_sprite_anim.png} +0 -0
  198. package/vendor/raylib/examples/textures/textures_sprite_button.c +8 -3
  199. package/vendor/raylib/examples/textures/textures_sprite_explosion.c +8 -3
  200. package/vendor/raylib/examples/textures/textures_srcrec_dstrec.c +8 -3
  201. package/vendor/raylib/examples/textures/textures_to_image.c +8 -3
  202. package/vendor/raylib/parser/LICENSE +1 -1
  203. package/vendor/raylib/parser/Makefile +28 -0
  204. package/vendor/raylib/parser/README.md +49 -5
  205. package/vendor/raylib/parser/output/raylib_api.json +10717 -0
  206. package/vendor/raylib/parser/output/raylib_api.lua +7435 -0
  207. package/vendor/raylib/parser/{raylib_api.txt → output/raylib_api.txt} +1371 -824
  208. package/vendor/raylib/parser/{raylib_api.xml → output/raylib_api.xml} +827 -595
  209. package/vendor/raylib/parser/raylib_parser.c +1174 -196
  210. package/vendor/raylib/projects/4coder/Makefile +2 -4
  211. package/vendor/raylib/projects/4coder/main.c +0 -1
  212. package/vendor/raylib/projects/CMake/CMakeLists.txt +13 -16
  213. package/vendor/raylib/projects/CMake/README.md +27 -0
  214. package/vendor/raylib/projects/CMake/core_basic_window.c +52 -31
  215. package/vendor/raylib/projects/CodeBlocks/README.md +4 -4
  216. package/vendor/raylib/projects/Geany/core_basic_window.c +1 -1
  217. package/vendor/raylib/projects/Notepad++/c_raylib.xml +168 -128
  218. package/vendor/raylib/projects/Notepad++/npes_saved_tcc.txt +0 -0
  219. package/vendor/raylib/projects/Notepad++/npes_saved_w64devkit.txt +0 -0
  220. package/vendor/raylib/projects/Notepad++/npes_saved_zig.txt +0 -0
  221. package/vendor/raylib/projects/Notepad++/raylib_npp_parser/raylib_npp.xml +168 -84
  222. package/vendor/raylib/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h +67 -51
  223. package/vendor/raylib/projects/README.md +1 -1
  224. package/vendor/raylib/projects/VSCode/.vscode/c_cpp_properties.json +1 -1
  225. package/vendor/raylib/projects/VSCode/Makefile +8 -11
  226. package/vendor/raylib/projects/VSCode/main.c +53 -26
  227. package/vendor/raylib/projects/VSCode/resources/LICENSE +1 -0
  228. package/vendor/raylib/projects/scripts/build-linux.sh +6 -6
  229. package/vendor/raylib/projects/scripts/build-osx.sh +6 -6
  230. package/vendor/raylib/projects/scripts/build-rpi.sh +6 -6
  231. package/vendor/raylib/projects/scripts/build-windows.bat +2 -2
  232. package/vendor/raylib/src/CMakeLists.txt +6 -7
  233. package/vendor/raylib/src/Makefile +209 -103
  234. package/vendor/raylib/src/build.zig +56 -20
  235. package/vendor/raylib/src/config.h +32 -27
  236. package/vendor/raylib/src/external/cgltf.h +342 -104
  237. package/vendor/raylib/src/external/dr_wav.h +487 -225
  238. package/vendor/raylib/src/external/glfw/src/posix_time.c +1 -3
  239. package/vendor/raylib/src/external/glfw/src/wl_init.c +1 -3
  240. package/vendor/raylib/src/external/jar_xm.h +2 -1
  241. package/vendor/raylib/src/external/miniaudio.h +62251 -42061
  242. package/vendor/raylib/src/external/qoi.h +671 -0
  243. package/vendor/raylib/src/external/stb_vorbis.h +1 -1
  244. package/vendor/raylib/src/external/vox_loader.h +30 -25
  245. package/vendor/raylib/src/minshell.html +82 -0
  246. package/vendor/raylib/src/raudio.c +359 -201
  247. package/vendor/raylib/src/raylib.dll.rc +5 -5
  248. package/vendor/raylib/src/raylib.dll.rc.data +0 -0
  249. package/vendor/raylib/src/raylib.h +95 -63
  250. package/vendor/raylib/src/raylib.rc +5 -5
  251. package/vendor/raylib/src/raylib.rc.data +0 -0
  252. package/vendor/raylib/src/raymath.h +391 -133
  253. package/vendor/raylib/src/rcamera.h +32 -41
  254. package/vendor/raylib/src/rcore.c +775 -471
  255. package/vendor/raylib/src/rgestures.h +5 -5
  256. package/vendor/raylib/src/rglfw.c +3 -3
  257. package/vendor/raylib/src/rlgl.h +184 -144
  258. package/vendor/raylib/src/rmodels.c +207 -144
  259. package/vendor/raylib/src/rshapes.c +105 -47
  260. package/vendor/raylib/src/rtext.c +255 -38
  261. package/vendor/raylib/src/rtextures.c +167 -71
  262. package/vendor/raylib/src/shell.html +63 -63
  263. package/vendor/raylib/src/utils.c +49 -3
  264. package/vendor/raylib/src/utils.h +3 -3
  265. package/build/qemu/2.1.1/koffi_darwin_arm64.tar.gz +0 -0
  266. package/build/qemu/2.1.1/koffi_darwin_x64.tar.gz +0 -0
  267. package/build/qemu/2.1.1/koffi_freebsd_arm64.tar.gz +0 -0
  268. package/build/qemu/2.1.1/koffi_freebsd_ia32.tar.gz +0 -0
  269. package/build/qemu/2.1.1/koffi_freebsd_x64.tar.gz +0 -0
  270. package/build/qemu/2.1.1/koffi_linux_arm32hf.tar.gz +0 -0
  271. package/build/qemu/2.1.1/koffi_linux_arm64.tar.gz +0 -0
  272. package/build/qemu/2.1.1/koffi_linux_ia32.tar.gz +0 -0
  273. package/build/qemu/2.1.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  274. package/build/qemu/2.1.1/koffi_linux_x64.tar.gz +0 -0
  275. package/build/qemu/2.1.1/koffi_openbsd_ia32.tar.gz +0 -0
  276. package/build/qemu/2.1.1/koffi_openbsd_x64.tar.gz +0 -0
  277. package/build/qemu/2.1.1/koffi_win32_arm64.tar.gz +0 -0
  278. package/build/qemu/2.1.1/koffi_win32_ia32.tar.gz +0 -0
  279. package/build/qemu/2.1.1/koffi_win32_x64.tar.gz +0 -0
  280. package/vendor/raylib/CONTRIBUTORS.md +0 -63
  281. package/vendor/raylib/SPONSORS.md +0 -68
  282. package/vendor/raylib/examples/core/core_quat_conversion.c +0 -132
  283. package/vendor/raylib/examples/core/core_quat_conversion.png +0 -0
  284. package/vendor/raylib/examples/models/resources/models/gltf/AnimatedMorphCube.glb +0 -0
  285. package/vendor/raylib/examples/models/resources/models/gltf/AnimatedTriangle.gltf +0 -118
  286. package/vendor/raylib/examples/models/resources/models/gltf/BoxAnimated.glb +0 -0
  287. package/vendor/raylib/examples/models/resources/models/gltf/girl.glb +0 -0
  288. package/vendor/raylib/examples/models/resources/models/gltf/rigged_figure.glb +0 -0
  289. package/vendor/raylib/examples/models/resources/models/gltf/vertex_colored_object.glb +0 -0
  290. package/vendor/raylib/examples/models/resources/models/iqm/vertex_colored_object.iqm +0 -0
  291. package/vendor/raylib/examples/models/rlights.h +0 -183
  292. package/vendor/raylib/examples/others/raudio_standalone.c +0 -152
  293. package/vendor/raylib/examples/others/resources/audio/country.mp3 +0 -0
  294. package/vendor/raylib/examples/others/resources/audio/target.ogg +0 -0
  295. package/vendor/raylib/examples/others/resources/audio/weird.wav +0 -0
  296. package/vendor/raylib/examples/physics/physics_demo.c +0 -128
  297. package/vendor/raylib/examples/physics/physics_demo.png +0 -0
  298. package/vendor/raylib/examples/physics/physics_friction.c +0 -142
  299. package/vendor/raylib/examples/physics/physics_friction.png +0 -0
  300. package/vendor/raylib/examples/physics/physics_movement.c +0 -128
  301. package/vendor/raylib/examples/physics/physics_movement.png +0 -0
  302. package/vendor/raylib/examples/physics/physics_restitution.c +0 -129
  303. package/vendor/raylib/examples/physics/physics_restitution.png +0 -0
  304. package/vendor/raylib/examples/physics/physics_shatter.c +0 -111
  305. package/vendor/raylib/examples/physics/physics_shatter.png +0 -0
  306. package/vendor/raylib/parser/raylib_api.json +0 -6668
  307. package/vendor/raylib/projects/VS2019/raylib/raylib.rc +0 -0
  308. package/vendor/raylib/projects/VS2019/raylib/resource.h +0 -14
  309. package/vendor/raylib/src/extras/physac.h +0 -1977
  310. package/vendor/raylib/src/extras/rmem.h +0 -751
  311. package/vendor/raylib/src/raudio.h +0 -198
@@ -22,9 +22,11 @@
22
22
  * Windowing and input system configured for Android device, app activity managed internally in this module.
23
23
  * NOTE: OpenGL ES 2.0 is required and graphic device is managed by EGL
24
24
  *
25
- * #define PLATFORM_RPI
25
+ * #define PLATFORM_RPI (deprecated - RPI OS Buster only)
26
26
  * Windowing and input system configured for Raspberry Pi in native mode (no XWindow required),
27
27
  * graphic device is managed by EGL and inputs are processed is raw mode, reading from /dev/input/
28
+ * WARNING: This platform is deprecated, since RPI OS Bullseye, the old Dispmanx libraries are not
29
+ * supported and you must be using PLATFORM_DRM
28
30
  *
29
31
  * #define PLATFORM_DRM
30
32
  * Windowing and input system configured for DRM native mode (RPI4 and other devices)
@@ -55,9 +57,6 @@
55
57
  * WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other running processes or
56
58
  * blocking the device if not restored properly. Use with care.
57
59
  *
58
- * #define SUPPORT_MOUSE_CURSOR_POINT
59
- * Draw a mouse pointer on screen
60
- *
61
60
  * #define SUPPORT_BUSY_WAIT_LOOP
62
61
  * Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
63
62
  *
@@ -78,9 +77,6 @@
78
77
  * provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module
79
78
  * for linkage
80
79
  *
81
- * #define SUPPORT_DATA_STORAGE
82
- * Support saving binary data automatically to a generated storage.data file. This file is managed internally
83
- *
84
80
  * #define SUPPORT_EVENTS_AUTOMATION
85
81
  * Support automatic generated events, loading and recording of those events when required
86
82
  *
@@ -93,7 +89,7 @@
93
89
  *
94
90
  * LICENSE: zlib/libpng
95
91
  *
96
- * Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
92
+ * Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
97
93
  *
98
94
  * This software is provided "as-is", without any express or implied warranty. In no event
99
95
  * will the authors be held liable for any damages arising from the use of this software.
@@ -160,21 +156,43 @@
160
156
  #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext.
161
157
  #endif
162
158
 
159
+ // Platform specific defines to handle GetApplicationDirectory()
160
+ #if defined (PLATFORM_DESKTOP)
161
+ #if defined(_WIN32)
162
+ #ifndef MAX_PATH
163
+ #define MAX_PATH 1025
164
+ #endif
165
+ __declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(void *hModule, void *lpFilename, unsigned long nSize);
166
+ __declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(void *hModule, void *lpFilename, unsigned long nSize);
167
+ __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, void *widestr, int cchwide, void *str, int cbmb, void *defchar, int *used_default);
168
+ #elif defined(__linux__)
169
+ #include <unistd.h>
170
+ #elif defined(__APPLE__)
171
+ #include <sys/syslimits.h>
172
+ #include <mach-o/dyld.h>
173
+ #endif // OSs
174
+ #endif // PLATFORM_DESKTOP
175
+
163
176
  #include <stdlib.h> // Required for: srand(), rand(), atexit()
164
177
  #include <stdio.h> // Required for: sprintf() [Used in OpenURL()]
165
- #include <string.h> // Required for: strrchr(), strcmp(), strlen()
178
+ #include <string.h> // Required for: strrchr(), strcmp(), strlen(), memset()
166
179
  #include <time.h> // Required for: time() [Used in InitTimer()]
167
180
  #include <math.h> // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
168
181
 
169
- #include <sys/stat.h> // Required for: stat() [Used in GetFileModTime()]
182
+ #define _CRT_INTERNAL_NONSTDC_NAMES 1
183
+ #include <sys/stat.h> // Required for: stat(), S_ISREG [Used in GetFileModTime(), IsFilePath()]
184
+
185
+ #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
186
+ #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
187
+ #endif
170
188
 
171
189
  #if defined(PLATFORM_DESKTOP) && defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__))
172
190
  #define DIRENT_MALLOC RL_MALLOC
173
191
  #define DIRENT_FREE RL_FREE
174
192
 
175
- #include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()]
193
+ #include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()]
176
194
  #else
177
- #include <dirent.h> // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()]
195
+ #include <dirent.h> // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()]
178
196
  #endif
179
197
 
180
198
  #if defined(_WIN32)
@@ -205,7 +223,7 @@
205
223
  unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
206
224
  #endif
207
225
  #endif
208
- #if defined(__linux__) || defined(__FreeBSD__)
226
+ #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
209
227
  #include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
210
228
 
211
229
  //#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type
@@ -225,6 +243,7 @@
225
243
  //#include <android/sensor.h> // Required for: Android sensors functions (accelerometer, gyroscope, light...)
226
244
  #include <android/window.h> // Required for: AWINDOW_FLAG_FULLSCREEN definition and others
227
245
  #include <android_native_app_glue.h> // Required for: android_app struct and activity management
246
+ #include <jni.h> // Required for: JNIEnv and JavaVM [Used in OpenURL()]
228
247
 
229
248
  #include <EGL/egl.h> // Native platform windowing system interface
230
249
  //#include <GLES2/gl2.h> // OpenGL ES 2.0 library (not required in this module, only in rlgl)
@@ -275,12 +294,11 @@
275
294
  #define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events
276
295
  #endif
277
296
 
297
+ #ifndef MAX_FILEPATH_CAPACITY
298
+ #define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
299
+ #endif
278
300
  #ifndef MAX_FILEPATH_LENGTH
279
- #if defined(__linux__)
280
- #define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
281
- #else
282
- #define MAX_FILEPATH_LENGTH 512 // Maximum length supported for filepaths
283
- #endif
301
+ #define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
284
302
  #endif
285
303
 
286
304
  #ifndef MAX_KEYBOARD_KEYS
@@ -308,12 +326,6 @@
308
326
  #define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
309
327
  #endif
310
328
 
311
- #if defined(SUPPORT_DATA_STORAGE)
312
- #ifndef STORAGE_DATA_FILE
313
- #define STORAGE_DATA_FILE "storage.data" // Automatic storage filename
314
- #endif
315
- #endif
316
-
317
329
  #ifndef MAX_DECOMPRESSION_SIZE
318
330
  #define MAX_DECOMPRESSION_SIZE 64 // Maximum size allocated for decompression in MB
319
331
  #endif
@@ -376,6 +388,7 @@ typedef struct CoreData {
376
388
  bool fullscreen; // Check if fullscreen mode is enabled
377
389
  bool shouldClose; // Check if window set for closing
378
390
  bool resizedLastFrame; // Check if window has been resized last frame
391
+ bool eventWaiting; // Wait for events before ending frame
379
392
 
380
393
  Point position; // Window position on screen (required on fullscreen toggle)
381
394
  Size display; // Display width and height (monitor, device-screen, LCD, ...)
@@ -385,8 +398,8 @@ typedef struct CoreData {
385
398
  Point renderOffset; // Offset from render area (must be divided by 2)
386
399
  Matrix screenScale; // Matrix to scale screen (framebuffer rendering)
387
400
 
388
- char **dropFilesPath; // Store dropped files paths as strings
389
- int dropFileCount; // Count dropped files strings
401
+ char **dropFilepaths; // Store dropped files paths pointers (provided by GLFW)
402
+ unsigned int dropFileCount; // Count dropped files strings
390
403
 
391
404
  } Window;
392
405
  #if defined(PLATFORM_ANDROID)
@@ -437,8 +450,8 @@ typedef struct CoreData {
437
450
 
438
451
  char currentButtonState[MAX_MOUSE_BUTTONS]; // Registers current mouse button state
439
452
  char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state
440
- float currentWheelMove; // Registers current mouse wheel variation
441
- float previousWheelMove; // Registers previous mouse wheel variation
453
+ Vector2 currentWheelMove; // Registers current mouse wheel variation
454
+ Vector2 previousWheelMove; // Registers previous mouse wheel variation
442
455
  #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
443
456
  // NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update
444
457
  char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab
@@ -482,17 +495,16 @@ typedef struct CoreData {
482
495
  //----------------------------------------------------------------------------------
483
496
  // Global Variables Definition
484
497
  //----------------------------------------------------------------------------------
485
- static CoreData CORE = { 0 }; // Global CORE state context
498
+ const char *raylibVersion = RAYLIB_VERSION; // raylib version symbol, it could be required for some bindings
486
499
 
487
- static char **dirFilesPath = NULL; // Store directory files paths as strings
488
- static int dirFileCount = 0; // Count directory files strings
500
+ static CoreData CORE = { 0 }; // Global CORE state context
489
501
 
490
502
  #if defined(SUPPORT_SCREEN_CAPTURE)
491
503
  static int screenshotCounter = 0; // Screenshots counter
492
504
  #endif
493
505
 
494
506
  #if defined(SUPPORT_GIF_RECORDING)
495
- static int gifFrameCounter = 0; // GIF frames counter
507
+ static int gifFrameCounter = 0; // GIF frames counter
496
508
  static bool gifRecording = false; // GIF recording state
497
509
  static MsfGifState gifState = { 0 }; // MSGIF context state
498
510
  #endif
@@ -510,7 +522,7 @@ typedef enum AutomationEventType {
510
522
  INPUT_MOUSE_BUTTON_UP, // param[0]: button
511
523
  INPUT_MOUSE_BUTTON_DOWN, // param[0]: button
512
524
  INPUT_MOUSE_POSITION, // param[0]: x, param[1]: y
513
- INPUT_MOUSE_WHEEL_MOTION, // param[0]: delta
525
+ INPUT_MOUSE_WHEEL_MOTION, // param[0]: x delta, param[1]: y delta
514
526
  INPUT_GAMEPAD_CONNECT, // param[0]: gamepad
515
527
  INPUT_GAMEPAD_DISCONNECT, // param[0]: gamepad
516
528
  INPUT_GAMEPAD_BUTTON_UP, // param[0]: button
@@ -588,7 +600,7 @@ static bool eventsRecording = false; // Record events
588
600
  //----------------------------------------------------------------------------------
589
601
  // Other Modules Functions Declaration (required by core)
590
602
  //----------------------------------------------------------------------------------
591
- #if defined(SUPPORT_DEFAULT_FONT)
603
+ #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
592
604
  extern void LoadFontDefault(void); // [Module: text] Loads default font on InitWindow()
593
605
  extern void UnloadFontDefault(void); // [Module: text] Unloads default font from GPU memory
594
606
  #endif
@@ -601,6 +613,9 @@ static bool InitGraphicsDevice(int width, int height); // Initialize graphics d
601
613
  static void SetupFramebuffer(int width, int height); // Setup main framebuffer
602
614
  static void SetupViewport(int width, int height); // Set viewport for a provided width and height
603
615
 
616
+ static void ScanDirectoryFiles(const char *basePath, FilePathList *list, const char *filter); // Scan all files and directories in a base path
617
+ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *list, const char *filter); // Scan all files and directories recursively from a base path
618
+
604
619
  #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
605
620
  static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
606
621
  // Window callbacks events
@@ -626,11 +641,13 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
626
641
  #endif
627
642
 
628
643
  #if defined(PLATFORM_WEB)
644
+ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
645
+ static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
646
+ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
647
+
629
648
  static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
630
649
  static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
631
650
  static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
632
- static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *e, void *userData);
633
-
634
651
  #endif
635
652
 
636
653
  #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
@@ -668,6 +685,10 @@ static void PlayAutomationEvent(unsigned int frame); // Play frame events
668
685
  void __stdcall Sleep(unsigned long msTimeout); // Required for: WaitTime()
669
686
  #endif
670
687
 
688
+ #if !defined(SUPPORT_MODULE_RTEXT)
689
+ const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
690
+ #endif // !SUPPORT_MODULE_RTEXT
691
+
671
692
  //----------------------------------------------------------------------------------
672
693
  // Module Functions Definition - Window and OpenGL Context Functions
673
694
  //----------------------------------------------------------------------------------
@@ -698,13 +719,46 @@ void InitWindow(int width, int height, const char *title)
698
719
  {
699
720
  TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
700
721
 
722
+ TRACELOG(LOG_INFO, "Supported raylib modules:");
723
+ TRACELOG(LOG_INFO, " > rcore:..... loaded (mandatory)");
724
+ TRACELOG(LOG_INFO, " > rlgl:...... loaded (mandatory)");
725
+ #if defined(SUPPORT_MODULE_RSHAPES)
726
+ TRACELOG(LOG_INFO, " > rshapes:... loaded (optional)");
727
+ #else
728
+ TRACELOG(LOG_INFO, " > rshapes:... not loaded (optional)");
729
+ #endif
730
+ #if defined(SUPPORT_MODULE_RTEXTURES)
731
+ TRACELOG(LOG_INFO, " > rtextures:. loaded (optional)");
732
+ #else
733
+ TRACELOG(LOG_INFO, " > rtextures:. not loaded (optional)");
734
+ #endif
735
+ #if defined(SUPPORT_MODULE_RTEXT)
736
+ TRACELOG(LOG_INFO, " > rtext:..... loaded (optional)");
737
+ #else
738
+ TRACELOG(LOG_INFO, " > rtext:..... not loaded (optional)");
739
+ #endif
740
+ #if defined(SUPPORT_MODULE_RMODELS)
741
+ TRACELOG(LOG_INFO, " > rmodels:... loaded (optional)");
742
+ #else
743
+ TRACELOG(LOG_INFO, " > rmodels:... not loaded (optional)");
744
+ #endif
745
+ #if defined(SUPPORT_MODULE_RAUDIO)
746
+ TRACELOG(LOG_INFO, " > raudio:.... loaded (optional)");
747
+ #else
748
+ TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
749
+ #endif
750
+
701
751
  if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
702
752
 
703
- // Initialize required global values different than 0
753
+ // Initialize global input state
754
+ memset(&CORE.Input, 0, sizeof(CORE.Input));
704
755
  CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
705
756
  CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
706
757
  CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
707
758
  CORE.Input.Gamepad.lastButtonPressed = -1;
759
+ #if defined(SUPPORT_EVENTS_WAITING)
760
+ CORE.Window.eventWaiting = true;
761
+ #endif
708
762
 
709
763
  #if defined(PLATFORM_ANDROID)
710
764
  CORE.Window.screen.width = width;
@@ -791,24 +845,30 @@ void InitWindow(int width, int height, const char *title)
791
845
  // Initialize base path for storage
792
846
  CORE.Storage.basePath = GetWorkingDirectory();
793
847
 
794
- #if defined(SUPPORT_DEFAULT_FONT)
848
+ #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
795
849
  // Load default font
796
- // NOTE: External functions (defined in module: text)
850
+ // WARNING: External function: Module required: rtext
797
851
  LoadFontDefault();
852
+ #if defined(SUPPORT_MODULE_RSHAPES)
798
853
  Rectangle rec = GetFontDefault().recs[95];
799
854
  // NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
800
- SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
855
+ SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); // WARNING: Module required: rshapes
856
+ #endif
801
857
  #else
858
+ #if defined(SUPPORT_MODULE_RSHAPES)
802
859
  // Set default texture and rectangle to be used for shapes drawing
803
860
  // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
804
861
  Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
805
- SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f });
862
+ SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); // WARNING: Module required: rshapes
863
+ #endif
806
864
  #endif
807
- #if defined(PLATFORM_DESKTOP)
865
+ #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
808
866
  if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
809
867
  {
810
868
  // Set default font texture filter for HighDPI (blurry)
811
- SetTextureFilter(GetFontDefault().texture, TEXTURE_FILTER_BILINEAR);
869
+ // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
870
+ rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
871
+ rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
812
872
  }
813
873
  #endif
814
874
 
@@ -820,13 +880,18 @@ void InitWindow(int width, int height, const char *title)
820
880
  #endif
821
881
 
822
882
  #if defined(PLATFORM_WEB)
883
+ // Setup callback funtions for the DOM events
884
+ emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
885
+
886
+ // WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
823
887
  // Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
824
888
  //emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
825
889
  // Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
826
- emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
890
+ //emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
827
891
  // Trigger this once to get initial window sizing
828
- EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
829
- // Support keyboard events
892
+ //EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
893
+
894
+ // Support keyboard events -> Not used, GLFW.JS takes care of that
830
895
  //emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
831
896
  //emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
832
897
 
@@ -867,8 +932,8 @@ void CloseWindow(void)
867
932
  }
868
933
  #endif
869
934
 
870
- #if defined(SUPPORT_DEFAULT_FONT)
871
- UnloadFontDefault();
935
+ #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
936
+ UnloadFontDefault(); // WARNING: Module required: rtext
872
937
  #endif
873
938
 
874
939
  rlglClose(); // De-init rlgl
@@ -1109,39 +1174,38 @@ bool IsWindowState(unsigned int flag)
1109
1174
  void ToggleFullscreen(void)
1110
1175
  {
1111
1176
  #if defined(PLATFORM_DESKTOP)
1112
- // NOTE: glfwSetWindowMonitor() doesn't work properly (bugs)
1113
1177
  if (!CORE.Window.fullscreen)
1114
1178
  {
1115
1179
  // Store previous window position (in case we exit fullscreen)
1116
1180
  glfwGetWindowPos(CORE.Window.handle, &CORE.Window.position.x, &CORE.Window.position.y);
1117
1181
 
1118
1182
  int monitorCount = 0;
1119
- GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
1120
-
1121
1183
  int monitorIndex = GetCurrentMonitor();
1184
+ GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
1122
1185
 
1123
1186
  // Use current monitor, so we correctly get the display the window is on
1124
- GLFWmonitor* monitor = monitorIndex < monitorCount ? monitors[monitorIndex] : NULL;
1187
+ GLFWmonitor *monitor = (monitorIndex < monitorCount)? monitors[monitorIndex] : NULL;
1125
1188
 
1126
- if (!monitor)
1189
+ if (monitor == NULL)
1127
1190
  {
1128
1191
  TRACELOG(LOG_WARNING, "GLFW: Failed to get monitor");
1129
1192
 
1130
- CORE.Window.fullscreen = false; // Toggle fullscreen flag
1193
+ CORE.Window.fullscreen = false;
1131
1194
  CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
1132
1195
 
1133
1196
  glfwSetWindowMonitor(CORE.Window.handle, NULL, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
1134
- return;
1135
1197
  }
1198
+ else
1199
+ {
1200
+ CORE.Window.fullscreen = true;
1201
+ CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
1136
1202
 
1137
- CORE.Window.fullscreen = true; // Toggle fullscreen flag
1138
- CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
1139
-
1140
- glfwSetWindowMonitor(CORE.Window.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
1203
+ glfwSetWindowMonitor(CORE.Window.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
1204
+ }
1141
1205
  }
1142
1206
  else
1143
1207
  {
1144
- CORE.Window.fullscreen = false; // Toggle fullscreen flag
1208
+ CORE.Window.fullscreen = false;
1145
1209
  CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
1146
1210
 
1147
1211
  glfwSetWindowMonitor(CORE.Window.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
@@ -1152,6 +1216,7 @@ void ToggleFullscreen(void)
1152
1216
  if (CORE.Window.flags & FLAG_VSYNC_HINT) glfwSwapInterval(1);
1153
1217
  #endif
1154
1218
  #if defined(PLATFORM_WEB)
1219
+ /*
1155
1220
  EM_ASM
1156
1221
  (
1157
1222
  // This strategy works well while using raylib minimal web shell for emscripten,
@@ -1159,14 +1224,17 @@ void ToggleFullscreen(void)
1159
1224
  // is a good strategy but maybe games prefer to keep current canvas resolution and
1160
1225
  // display it in fullscreen, adjusting monitor resolution if possible
1161
1226
  if (document.fullscreenElement) document.exitFullscreen();
1162
- else Module.requestFullscreen(false, true);
1227
+ else Module.requestFullscreen(true, true); //false, true);
1163
1228
  );
1164
-
1229
+ */
1230
+ //EM_ASM(Module.requestFullscreen(false, false););
1165
1231
  /*
1166
1232
  if (!CORE.Window.fullscreen)
1167
1233
  {
1168
1234
  // Option 1: Request fullscreen for the canvas element
1169
- // This option does not seem to work at all
1235
+ // This option does not seem to work at all:
1236
+ // emscripten_request_pointerlock() and emscripten_request_fullscreen() are affected by web security,
1237
+ // the user must click once on the canvas to hide the pointer or transition to full screen
1170
1238
  //emscripten_request_fullscreen("#canvas", false);
1171
1239
 
1172
1240
  // Option 2: Request fullscreen for the canvas element with strategy
@@ -1195,20 +1263,25 @@ void ToggleFullscreen(void)
1195
1263
  int width, height;
1196
1264
  emscripten_get_canvas_element_size("#canvas", &width, &height);
1197
1265
  TRACELOG(LOG_WARNING, "Emscripten: Enter fullscreen: Canvas size: %i x %i", width, height);
1266
+
1267
+ CORE.Window.fullscreen = true; // Toggle fullscreen flag
1268
+ CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
1198
1269
  }
1199
1270
  else
1200
1271
  {
1201
1272
  //emscripten_exit_fullscreen();
1202
- emscripten_exit_soft_fullscreen();
1273
+ //emscripten_exit_soft_fullscreen();
1203
1274
 
1204
1275
  int width, height;
1205
1276
  emscripten_get_canvas_element_size("#canvas", &width, &height);
1206
1277
  TRACELOG(LOG_WARNING, "Emscripten: Exit fullscreen: Canvas size: %i x %i", width, height);
1278
+
1279
+ CORE.Window.fullscreen = false; // Toggle fullscreen flag
1280
+ CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
1207
1281
  }
1208
1282
  */
1209
1283
 
1210
1284
  CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag
1211
- CORE.Window.flags ^= FLAG_FULLSCREEN_MODE;
1212
1285
  #endif
1213
1286
  #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
1214
1287
  TRACELOG(LOG_WARNING, "SYSTEM: Failed to toggle to windowed mode");
@@ -1339,6 +1412,13 @@ void SetWindowState(unsigned int flags)
1339
1412
  TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization");
1340
1413
  }
1341
1414
 
1415
+ // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
1416
+ if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) != (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0))
1417
+ {
1418
+ glfwSetWindowAttrib(CORE.Window.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
1419
+ CORE.Window.flags |= FLAG_WINDOW_MOUSE_PASSTHROUGH;
1420
+ }
1421
+
1342
1422
  // State change: FLAG_MSAA_4X_HINT
1343
1423
  if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) != (flags & FLAG_MSAA_4X_HINT)) && ((flags & FLAG_MSAA_4X_HINT) > 0))
1344
1424
  {
@@ -1440,6 +1520,13 @@ void ClearWindowState(unsigned int flags)
1440
1520
  TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization");
1441
1521
  }
1442
1522
 
1523
+ // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
1524
+ if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0))
1525
+ {
1526
+ glfwSetWindowAttrib(CORE.Window.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE);
1527
+ CORE.Window.flags &= ~FLAG_WINDOW_MOUSE_PASSTHROUGH;
1528
+ }
1529
+
1443
1530
  // State change: FLAG_MSAA_4X_HINT
1444
1531
  if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) > 0) && ((flags & FLAG_MSAA_4X_HINT) > 0))
1445
1532
  {
@@ -1525,12 +1612,15 @@ void SetWindowSize(int width, int height)
1525
1612
  #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
1526
1613
  glfwSetWindowSize(CORE.Window.handle, width, height);
1527
1614
  #endif
1528
- #if defined(PLATFORM_WEB)
1529
- //emscripten_set_canvas_size(width, height); // DEPRECATED!
1615
+ }
1530
1616
 
1531
- // TODO: Below functions should be used to replace previous one but they do not seem to work properly
1532
- //emscripten_set_canvas_element_size("canvas", width, height);
1533
- //emscripten_set_element_css_size("canvas", width, height);
1617
+ // Set window opacity, value opacity is between 0.0 and 1.0
1618
+ void SetWindowOpacity(float opacity)
1619
+ {
1620
+ #if defined(PLATFORM_DESKTOP)
1621
+ if (opacity >= 1.0f) opacity = 1.0f;
1622
+ else if (opacity <= 0.0f) opacity = 0.0f;
1623
+ glfwSetWindowOpacity(CORE.Window.handle, opacity);
1534
1624
  #endif
1535
1625
  }
1536
1626
 
@@ -1640,7 +1730,7 @@ int GetCurrentMonitor(void)
1640
1730
  #endif
1641
1731
  }
1642
1732
 
1643
- // Get selected monitor width
1733
+ // Get selected monitor position
1644
1734
  Vector2 GetMonitorPosition(int monitor)
1645
1735
  {
1646
1736
  #if defined(PLATFORM_DESKTOP)
@@ -1659,7 +1749,7 @@ Vector2 GetMonitorPosition(int monitor)
1659
1749
  return (Vector2){ 0, 0 };
1660
1750
  }
1661
1751
 
1662
- // Get selected monitor width (max available by monitor)
1752
+ // Get selected monitor width (currently used by monitor)
1663
1753
  int GetMonitorWidth(int monitor)
1664
1754
  {
1665
1755
  #if defined(PLATFORM_DESKTOP)
@@ -1668,11 +1758,9 @@ int GetMonitorWidth(int monitor)
1668
1758
 
1669
1759
  if ((monitor >= 0) && (monitor < monitorCount))
1670
1760
  {
1671
- int count = 0;
1672
- const GLFWvidmode *modes = glfwGetVideoModes(monitors[monitor], &count);
1761
+ const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
1673
1762
 
1674
- // We return the maximum resolution available, the last one in the modes array
1675
- if (count > 0) return modes[count - 1].width;
1763
+ if (mode) return mode->width;
1676
1764
  else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
1677
1765
  }
1678
1766
  else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
@@ -1680,7 +1768,7 @@ int GetMonitorWidth(int monitor)
1680
1768
  return 0;
1681
1769
  }
1682
1770
 
1683
- // Get selected monitor width (max available by monitor)
1771
+ // Get selected monitor height (currently used by monitor)
1684
1772
  int GetMonitorHeight(int monitor)
1685
1773
  {
1686
1774
  #if defined(PLATFORM_DESKTOP)
@@ -1689,11 +1777,9 @@ int GetMonitorHeight(int monitor)
1689
1777
 
1690
1778
  if ((monitor >= 0) && (monitor < monitorCount))
1691
1779
  {
1692
- int count = 0;
1693
- const GLFWvidmode *modes = glfwGetVideoModes(monitors[monitor], &count);
1780
+ const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
1694
1781
 
1695
- // We return the maximum resolution available, the last one in the modes array
1696
- if (count > 0) return modes[count - 1].height;
1782
+ if (mode) return mode->height;
1697
1783
  else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
1698
1784
  }
1699
1785
  else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
@@ -1820,25 +1906,44 @@ const char *GetMonitorName(int monitor)
1820
1906
  return "";
1821
1907
  }
1822
1908
 
1823
- // Get clipboard text content
1824
- // NOTE: returned string is allocated and freed by GLFW
1825
- const char *GetClipboardText(void)
1909
+ // Set clipboard text content
1910
+ void SetClipboardText(const char *text)
1826
1911
  {
1827
1912
  #if defined(PLATFORM_DESKTOP)
1828
- return glfwGetClipboardString(CORE.Window.handle);
1829
- #else
1830
- return NULL;
1913
+ glfwSetClipboardString(CORE.Window.handle, text);
1914
+ #endif
1915
+ #if defined(PLATFORM_WEB)
1916
+ emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text));
1831
1917
  #endif
1832
1918
  }
1833
1919
 
1834
- // Set clipboard text content
1835
- void SetClipboardText(const char *text)
1920
+ // Enable waiting for events on EndDrawing(), no automatic event polling
1921
+ void EnableEventWaiting(void)
1922
+ {
1923
+ CORE.Window.eventWaiting = true;
1924
+ }
1925
+
1926
+ // Disable waiting for events on EndDrawing(), automatic events polling
1927
+ RLAPI void DisableEventWaiting(void)
1928
+ {
1929
+ CORE.Window.eventWaiting = false;
1930
+ }
1931
+
1932
+ // Get clipboard text content
1933
+ // NOTE: returned string is allocated and freed by GLFW
1934
+ const char *GetClipboardText(void)
1836
1935
  {
1837
1936
  #if defined(PLATFORM_DESKTOP)
1838
- glfwSetClipboardString(CORE.Window.handle, text);
1937
+ return glfwGetClipboardString(CORE.Window.handle);
1938
+ #endif
1939
+ #if defined(PLATFORM_WEB)
1940
+ return emscripten_run_script_string("navigator.clipboard.readText()");
1839
1941
  #endif
1942
+ return NULL;
1840
1943
  }
1841
1944
 
1945
+
1946
+
1842
1947
  // Show mouse cursor
1843
1948
  void ShowCursor(void)
1844
1949
  {
@@ -1926,15 +2031,6 @@ void EndDrawing(void)
1926
2031
  {
1927
2032
  rlDrawRenderBatchActive(); // Update and draw internal render batch
1928
2033
 
1929
- #if defined(SUPPORT_MOUSE_CURSOR_POINT)
1930
- // Draw a small rectangle on mouse position for user reference
1931
- if (!CORE.Input.Mouse.cursorHidden)
1932
- {
1933
- DrawRectangle(CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y, 3, 3, MAROON);
1934
- rlDrawRenderBatchActive(); // Update and draw internal render batch
1935
- }
1936
- #endif
1937
-
1938
2034
  #if defined(SUPPORT_GIF_RECORDING)
1939
2035
  // Draw record indicator
1940
2036
  if (gifRecording)
@@ -1947,17 +2043,20 @@ void EndDrawing(void)
1947
2043
  {
1948
2044
  // Get image data for the current frame (from backbuffer)
1949
2045
  // NOTE: This process is quite slow... :(
1950
- unsigned char *screenData = rlReadScreenPixels(CORE.Window.screen.width, CORE.Window.screen.height);
1951
- msf_gif_frame(&gifState, screenData, 10, 16, CORE.Window.screen.width*4);
2046
+ Vector2 scale = GetWindowScaleDPI();
2047
+ unsigned char *screenData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
2048
+ msf_gif_frame(&gifState, screenData, 10, 16, (int)((float)CORE.Window.render.width*scale.x)*4);
1952
2049
 
1953
2050
  RL_FREE(screenData); // Free image data
1954
2051
  }
1955
2052
 
2053
+ #if defined(SUPPORT_MODULE_RSHAPES) && defined(SUPPORT_MODULE_RTEXT)
1956
2054
  if (((gifFrameCounter/15)%2) == 1)
1957
2055
  {
1958
- DrawCircle(30, CORE.Window.screen.height - 20, 10, MAROON);
1959
- DrawText("GIF RECORDING", 50, CORE.Window.screen.height - 25, 10, RED);
2056
+ DrawCircle(30, CORE.Window.screen.height - 20, 10, MAROON); // WARNING: Module required: rshapes
2057
+ DrawText("GIF RECORDING", 50, CORE.Window.screen.height - 25, 10, RED); // WARNING: Module required: rtext
1960
2058
  }
2059
+ #endif
1961
2060
 
1962
2061
  rlDrawRenderBatchActive(); // Update and draw internal render batch
1963
2062
  }
@@ -2004,7 +2103,7 @@ void EndDrawing(void)
2004
2103
  // Wait for some milliseconds...
2005
2104
  if (CORE.Time.frame < CORE.Time.target)
2006
2105
  {
2007
- WaitTime((float)(CORE.Time.target - CORE.Time.frame)*1000.0f);
2106
+ WaitTime(CORE.Time.target - CORE.Time.frame);
2008
2107
 
2009
2108
  CORE.Time.current = GetTime();
2010
2109
  double waitTime = CORE.Time.current - CORE.Time.previous;
@@ -2115,8 +2214,10 @@ void BeginTextureMode(RenderTexture2D target)
2115
2214
 
2116
2215
  rlEnableFramebuffer(target.id); // Enable render target
2117
2216
 
2118
- // Set viewport to framebuffer size
2217
+ // Set viewport and RLGL internal framebuffer size
2119
2218
  rlViewport(0, 0, target.texture.width, target.texture.height);
2219
+ rlSetFramebufferWidth(target.texture.width);
2220
+ rlSetFramebufferHeight(target.texture.height);
2120
2221
 
2121
2222
  rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
2122
2223
  rlLoadIdentity(); // Reset current matrix (projection)
@@ -2184,16 +2285,20 @@ void BeginScissorMode(int x, int y, int width, int height)
2184
2285
 
2185
2286
  rlEnableScissorTest();
2186
2287
 
2288
+ #if defined(__APPLE__)
2289
+ Vector2 scale = GetWindowScaleDPI();
2290
+ rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y));
2291
+ #else
2187
2292
  if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
2188
2293
  {
2189
2294
  Vector2 scale = GetWindowScaleDPI();
2190
-
2191
2295
  rlScissor((int)(x*scale.x), (int)(CORE.Window.currentFbo.height - (y + height)*scale.y), (int)(width*scale.x), (int)(height*scale.y));
2192
2296
  }
2193
2297
  else
2194
2298
  {
2195
2299
  rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height);
2196
2300
  }
2301
+ #endif
2197
2302
  }
2198
2303
 
2199
2304
  // End scissor mode
@@ -2258,8 +2363,8 @@ VrStereoConfig LoadVrStereoConfig(VrDeviceInfo device)
2258
2363
 
2259
2364
  // Fovy is normally computed with: 2*atan2f(device.vScreenSize, 2*device.eyeToScreenDistance)
2260
2365
  // ...but with lens distortion it is increased (see Oculus SDK Documentation)
2261
- //float fovy = 2.0f*atan2f(device.vScreenSize*0.5f*distortionScale, device.eyeToScreenDistance); // Really need distortionScale?
2262
- float fovy = 2.0f*(float)atan2f(device.vScreenSize*0.5f, device.eyeToScreenDistance);
2366
+ float fovy = 2.0f*atan2f(device.vScreenSize*0.5f*distortionScale, device.eyeToScreenDistance); // Really need distortionScale?
2367
+ // float fovy = 2.0f*(float)atan2f(device.vScreenSize*0.5f, device.eyeToScreenDistance);
2263
2368
 
2264
2369
  // Compute camera projection matrices
2265
2370
  float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1]
@@ -2585,7 +2690,7 @@ void SetTargetFPS(int fps)
2585
2690
  if (fps < 1) CORE.Time.target = 0.0;
2586
2691
  else CORE.Time.target = 1.0/(double)fps;
2587
2692
 
2588
- TRACELOG(LOG_INFO, "TIMER: Target time per frame: %02.03f milliseconds", (float)CORE.Time.target*1000);
2693
+ TRACELOG(LOG_INFO, "TIMER: Target time per frame: %02.03f milliseconds", (float)CORE.Time.target*1000.0f);
2589
2694
  }
2590
2695
 
2591
2696
  // Get current FPS
@@ -2661,13 +2766,15 @@ void SetConfigFlags(unsigned int flags)
2661
2766
  // Takes a screenshot of current screen (saved a .png)
2662
2767
  void TakeScreenshot(const char *fileName)
2663
2768
  {
2664
- unsigned char *imgData = rlReadScreenPixels(CORE.Window.render.width, CORE.Window.render.height);
2665
- Image image = { imgData, CORE.Window.render.width, CORE.Window.render.height, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
2769
+ #if defined(SUPPORT_MODULE_RTEXTURES)
2770
+ Vector2 scale = GetWindowScaleDPI();
2771
+ unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
2772
+ Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
2666
2773
 
2667
- char path[512] = { 0 };
2774
+ char path[2048] = { 0 };
2668
2775
  strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName));
2669
2776
 
2670
- ExportImage(image, path);
2777
+ ExportImage(image, path); // WARNING: Module required: rtextures
2671
2778
  RL_FREE(imgData);
2672
2779
 
2673
2780
  #if defined(PLATFORM_WEB)
@@ -2677,6 +2784,9 @@ void TakeScreenshot(const char *fileName)
2677
2784
  #endif
2678
2785
 
2679
2786
  TRACELOG(LOG_INFO, "SYSTEM: [%s] Screenshot taken successfully", path);
2787
+ #else
2788
+ TRACELOG(LOG_WARNING,"IMAGE: ExportImage() requires module: rtextures");
2789
+ #endif
2680
2790
  }
2681
2791
 
2682
2792
  // Get a random value between min and max (both included)
@@ -2709,6 +2819,11 @@ bool FileExists(const char *fileName)
2709
2819
  if (access(fileName, F_OK) != -1) result = true;
2710
2820
  #endif
2711
2821
 
2822
+ // NOTE: Alternatively, stat() can be used instead of access()
2823
+ //#include <sys/stat.h>
2824
+ //struct stat statbuf;
2825
+ //if (stat(filename, &statbuf) == 0) result = true;
2826
+
2712
2827
  return result;
2713
2828
  }
2714
2829
 
@@ -2716,21 +2831,23 @@ bool FileExists(const char *fileName)
2716
2831
  // NOTE: Extensions checking is not case-sensitive
2717
2832
  bool IsFileExtension(const char *fileName, const char *ext)
2718
2833
  {
2834
+ #define MAX_FILE_EXTENSION_SIZE 16
2835
+
2719
2836
  bool result = false;
2720
2837
  const char *fileExt = GetFileExtension(fileName);
2721
2838
 
2722
2839
  if (fileExt != NULL)
2723
2840
  {
2724
- #if defined(SUPPORT_TEXT_MANIPULATION)
2841
+ #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_TEXT_MANIPULATION)
2725
2842
  int extCount = 0;
2726
- const char **checkExts = TextSplit(ext, ';', &extCount);
2843
+ const char **checkExts = TextSplit(ext, ';', &extCount); // WARNING: Module required: rtext
2727
2844
 
2728
- char fileExtLower[16] = { 0 };
2729
- strcpy(fileExtLower, TextToLower(fileExt));
2845
+ char fileExtLower[MAX_FILE_EXTENSION_SIZE] = { 0 };
2846
+ strncpy(fileExtLower, TextToLower(fileExt),MAX_FILE_EXTENSION_SIZE); // WARNING: Module required: rtext
2730
2847
 
2731
2848
  for (int i = 0; i < extCount; i++)
2732
2849
  {
2733
- if (TextIsEqual(fileExtLower, TextToLower(checkExts[i])))
2850
+ if (strcmp(fileExtLower, TextToLower(checkExts[i])) == 0)
2734
2851
  {
2735
2852
  result = true;
2736
2853
  break;
@@ -2759,6 +2876,24 @@ bool DirectoryExists(const char *dirPath)
2759
2876
  return result;
2760
2877
  }
2761
2878
 
2879
+ // Get file length in bytes
2880
+ // NOTE: GetFileSize() conflicts with windows.h
2881
+ int GetFileLength(const char *fileName)
2882
+ {
2883
+ int size = 0;
2884
+
2885
+ FILE *file = fopen(fileName, "rb");
2886
+
2887
+ if (file != NULL)
2888
+ {
2889
+ fseek(file, 0L, SEEK_END);
2890
+ size = (int)ftell(file);
2891
+ fclose(file);
2892
+ }
2893
+
2894
+ return size;
2895
+ }
2896
+
2762
2897
  // Get pointer to extension for a filename string (includes the dot: .png)
2763
2898
  const char *GetFileExtension(const char *fileName)
2764
2899
  {
@@ -2791,7 +2926,7 @@ const char *GetFileName(const char *filePath)
2791
2926
  // Get filename string without extension (uses static string)
2792
2927
  const char *GetFileNameWithoutExt(const char *filePath)
2793
2928
  {
2794
- #define MAX_FILENAMEWITHOUTEXT_LENGTH 128
2929
+ #define MAX_FILENAMEWITHOUTEXT_LENGTH 256
2795
2930
 
2796
2931
  static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH] = { 0 };
2797
2932
  memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH);
@@ -2894,55 +3029,148 @@ const char *GetWorkingDirectory(void)
2894
3029
  return path;
2895
3030
  }
2896
3031
 
2897
- // Get filenames in a directory path (max 512 files)
2898
- // NOTE: Files count is returned by parameters pointer
2899
- char **GetDirectoryFiles(const char *dirPath, int *fileCount)
3032
+ const char *GetApplicationDirectory(void)
2900
3033
  {
2901
- #define MAX_DIRECTORY_FILES 512
3034
+ static char appDir[MAX_FILEPATH_LENGTH] = { 0 };
3035
+ memset(appDir, 0, MAX_FILEPATH_LENGTH);
3036
+
3037
+ #if defined(_WIN32)
3038
+ int len = 0;
3039
+ #if defined (UNICODE)
3040
+ unsigned short widePath[MAX_PATH];
3041
+ len = GetModuleFileNameW(NULL, widePath, MAX_PATH);
3042
+ len = WideCharToMultiByte(0, 0, widePath, len, appDir, MAX_PATH, NULL, NULL);
3043
+ #else
3044
+ len = GetModuleFileNameA(NULL, appDir, MAX_PATH);
3045
+ #endif
3046
+ if (len > 0)
3047
+ {
3048
+ for (int i = len; i >= 0; --i)
3049
+ {
3050
+ if (appDir[i] == '\\')
3051
+ {
3052
+ appDir[i + 1] = '\0';
3053
+ break;
3054
+ }
3055
+ }
3056
+ }
3057
+ else
3058
+ {
3059
+ appDir[0] = '.';
3060
+ appDir[1] = '\\';
3061
+ }
3062
+
3063
+ #elif defined(__linux__)
3064
+ unsigned int size = sizeof(appDir);
3065
+ ssize_t len = readlink("/proc/self/exe", appDir, size);
3066
+
3067
+ if (len > 0)
3068
+ {
3069
+ for (int i = len; i >= 0; --i)
3070
+ {
3071
+ if (appDir[i] == '/')
3072
+ {
3073
+ appDir[i + 1] = '\0';
3074
+ break;
3075
+ }
3076
+ }
3077
+ }
3078
+ else
3079
+ {
3080
+ appDir[0] = '.';
3081
+ appDir[1] = '/';
3082
+ }
3083
+ #elif defined(__APPLE__)
3084
+ uint32_t size = sizeof(appDir);
3085
+
3086
+ if (_NSGetExecutablePath(appDir, &size) == 0)
3087
+ {
3088
+ int len = strlen(appDir);
3089
+ for (int i = len; i >= 0; --i)
3090
+ {
3091
+ if (appDir[i] == '/')
3092
+ {
3093
+ appDir[i + 1] = '\0';
3094
+ break;
3095
+ }
3096
+ }
3097
+ }
3098
+ else
3099
+ {
3100
+ appDir[0] = '.';
3101
+ appDir[1] = '/';
3102
+ }
3103
+ #endif
2902
3104
 
2903
- ClearDirectoryFiles();
3105
+ return appDir;
3106
+ }
2904
3107
 
2905
- // Memory allocation for MAX_DIRECTORY_FILES
2906
- dirFilesPath = (char **)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(char *));
2907
- for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)RL_MALLOC(MAX_FILEPATH_LENGTH*sizeof(char));
3108
+ // Load directory filepaths
3109
+ // NOTE: Base path is prepended to the scanned filepaths
3110
+ // WARNING: Directory is scanned twice, first time to get files count
3111
+ // No recursive scanning is done!
3112
+ FilePathList LoadDirectoryFiles(const char *dirPath)
3113
+ {
3114
+ FilePathList files = { 0 };
3115
+ unsigned int fileCounter = 0;
2908
3116
 
2909
- int counter = 0;
2910
3117
  struct dirent *entity;
2911
3118
  DIR *dir = opendir(dirPath);
2912
3119
 
2913
- if (dir != NULL) // It's a directory
3120
+ if (dir != NULL) // It's a directory
2914
3121
  {
2915
- // TODO: Reading could be done in two passes,
2916
- // first one to count files and second one to read names
2917
- // That way we can allocate required memory, instead of a limited pool
2918
-
3122
+ // SCAN 1: Count files
2919
3123
  while ((entity = readdir(dir)) != NULL)
2920
3124
  {
2921
- strcpy(dirFilesPath[counter], entity->d_name);
2922
- counter++;
3125
+ // NOTE: We skip '.' (current dir) and '..' (parent dir) filepaths
3126
+ if ((strcmp(entity->d_name, ".") != 0) && (strcmp(entity->d_name, "..") != 0)) fileCounter++;
2923
3127
  }
2924
3128
 
3129
+ // Memory allocation for dirFileCount
3130
+ files.capacity = fileCounter;
3131
+ files.paths = (char **)RL_MALLOC(files.capacity*sizeof(char *));
3132
+ for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_MALLOC(MAX_FILEPATH_LENGTH*sizeof(char));
3133
+
2925
3134
  closedir(dir);
3135
+
3136
+ // SCAN 2: Read filepaths
3137
+ // NOTE: Directory paths are also registered
3138
+ ScanDirectoryFiles(dirPath, &files, NULL);
3139
+
3140
+ // Security check: read files.count should match fileCounter
3141
+ if (files.count != files.capacity) TRACELOG(LOG_WARNING, "FILEIO: Read files count do not match capacity allocated");
2926
3142
  }
2927
3143
  else TRACELOG(LOG_WARNING, "FILEIO: Failed to open requested directory"); // Maybe it's a file...
2928
3144
 
2929
- dirFileCount = counter;
2930
- *fileCount = dirFileCount;
3145
+ return files;
3146
+ }
3147
+
3148
+ // Load directory filepaths with extension filtering and recursive directory scan
3149
+ // NOTE: On recursive loading we do not pre-scan for file count, we use MAX_FILEPATH_CAPACITY
3150
+ FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs)
3151
+ {
3152
+ FilePathList files = { 0 };
3153
+
3154
+ files.capacity = MAX_FILEPATH_CAPACITY;
3155
+ files.paths = (char **)RL_CALLOC(files.capacity, sizeof(char *));
3156
+ for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
2931
3157
 
2932
- return dirFilesPath;
3158
+ // WARNING: basePath is always prepended to scanned paths
3159
+ if (scanSubdirs) ScanDirectoryFilesRecursively(basePath, &files, filter);
3160
+ else ScanDirectoryFiles(basePath, &files, filter);
3161
+
3162
+ return files;
2933
3163
  }
2934
3164
 
2935
- // Clear directory files paths buffers
2936
- void ClearDirectoryFiles(void)
3165
+ // Unload directory filepaths
3166
+ void UnloadDirectoryFiles(FilePathList files)
2937
3167
  {
2938
- if (dirFileCount > 0)
3168
+ if (files.capacity > 0)
2939
3169
  {
2940
- for (int i = 0; i < MAX_DIRECTORY_FILES; i++) RL_FREE(dirFilesPath[i]);
3170
+ for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
2941
3171
 
2942
- RL_FREE(dirFilesPath);
3172
+ RL_FREE(files.paths);
2943
3173
  }
2944
-
2945
- dirFileCount = 0;
2946
3174
  }
2947
3175
 
2948
3176
  // Change working directory, returns true on success
@@ -2955,6 +3183,15 @@ bool ChangeDirectory(const char *dir)
2955
3183
  return (result == 0);
2956
3184
  }
2957
3185
 
3186
+ // Check if a given path point to a file
3187
+ bool IsPathFile(const char *path)
3188
+ {
3189
+ struct stat pathStat = { 0 };
3190
+ stat(path, &pathStat);
3191
+
3192
+ return S_ISREG(pathStat.st_mode);
3193
+ }
3194
+
2958
3195
  // Check if a file has been dropped into window
2959
3196
  bool IsFileDropped(void)
2960
3197
  {
@@ -2962,23 +3199,30 @@ bool IsFileDropped(void)
2962
3199
  else return false;
2963
3200
  }
2964
3201
 
2965
- // Get dropped files names
2966
- char **GetDroppedFiles(int *count)
3202
+ // Load dropped filepaths
3203
+ FilePathList LoadDroppedFiles(void)
2967
3204
  {
2968
- *count = CORE.Window.dropFileCount;
2969
- return CORE.Window.dropFilesPath;
3205
+ FilePathList files = { 0 };
3206
+
3207
+ files.count = CORE.Window.dropFileCount;
3208
+ files.paths = CORE.Window.dropFilepaths;
3209
+
3210
+ return files;
2970
3211
  }
2971
3212
 
2972
- // Clear dropped files paths buffer
2973
- void ClearDroppedFiles(void)
3213
+ // Unload dropped filepaths
3214
+ void UnloadDroppedFiles(FilePathList files)
2974
3215
  {
2975
- if (CORE.Window.dropFileCount > 0)
3216
+ // WARNING: files pointers are the same as internal ones
3217
+
3218
+ if (files.count > 0)
2976
3219
  {
2977
- for (int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilesPath[i]);
3220
+ for (unsigned int i = 0; i < files.count; i++) RL_FREE(files.paths[i]);
2978
3221
 
2979
- RL_FREE(CORE.Window.dropFilesPath);
3222
+ RL_FREE(files.paths);
2980
3223
 
2981
3224
  CORE.Window.dropFileCount = 0;
3225
+ CORE.Window.dropFilepaths = NULL;
2982
3226
  }
2983
3227
  }
2984
3228
 
@@ -2997,8 +3241,8 @@ long GetFileModTime(const char *fileName)
2997
3241
  return 0;
2998
3242
  }
2999
3243
 
3000
- // Compress data (DEFLATE algorythm)
3001
- unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength)
3244
+ // Compress data (DEFLATE algorithm)
3245
+ unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize)
3002
3246
  {
3003
3247
  #define COMPRESSION_QUALITY_DEFLATE 8
3004
3248
 
@@ -3007,40 +3251,40 @@ unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLe
3007
3251
  #if defined(SUPPORT_COMPRESSION_API)
3008
3252
  // Compress data and generate a valid DEFLATE stream
3009
3253
  struct sdefl sdefl = { 0 };
3010
- int bounds = sdefl_bound(dataLength);
3254
+ int bounds = sdefl_bound(dataSize);
3011
3255
  compData = (unsigned char *)RL_CALLOC(bounds, 1);
3012
- *compDataLength = sdeflate(&sdefl, compData, data, dataLength, COMPRESSION_QUALITY_DEFLATE); // Compression level 8, same as stbwi
3256
+ *compDataSize = sdeflate(&sdefl, compData, data, dataSize, COMPRESSION_QUALITY_DEFLATE); // Compression level 8, same as stbwi
3013
3257
 
3014
- TraceLog(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataLength, *compDataLength);
3258
+ TraceLog(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataSize, *compDataSize);
3015
3259
  #endif
3016
3260
 
3017
3261
  return compData;
3018
3262
  }
3019
3263
 
3020
- // Decompress data (DEFLATE algorythm)
3021
- unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength)
3264
+ // Decompress data (DEFLATE algorithm)
3265
+ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize)
3022
3266
  {
3023
3267
  unsigned char *data = NULL;
3024
3268
 
3025
3269
  #if defined(SUPPORT_COMPRESSION_API)
3026
3270
  // Decompress data from a valid DEFLATE stream
3027
3271
  data = RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1);
3028
- int length = sinflate(data, MAX_DECOMPRESSION_SIZE, compData, compDataLength);
3272
+ int length = sinflate(data, MAX_DECOMPRESSION_SIZE*1024*1024, compData, compDataSize);
3029
3273
  unsigned char *temp = RL_REALLOC(data, length);
3030
3274
 
3031
3275
  if (temp != NULL) data = temp;
3032
3276
  else TRACELOG(LOG_WARNING, "SYSTEM: Failed to re-allocate required decompression memory");
3033
3277
 
3034
- *dataLength = length;
3278
+ *dataSize = length;
3035
3279
 
3036
- TraceLog(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataLength, *dataLength);
3280
+ TraceLog(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, *dataSize);
3037
3281
  #endif
3038
3282
 
3039
3283
  return data;
3040
3284
  }
3041
3285
 
3042
3286
  // Encode data to Base64 string
3043
- char *EncodeDataBase64(const unsigned char *data, int dataLength, int *outputLength)
3287
+ char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
3044
3288
  {
3045
3289
  static const unsigned char base64encodeTable[] = {
3046
3290
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
@@ -3050,17 +3294,17 @@ char *EncodeDataBase64(const unsigned char *data, int dataLength, int *outputLen
3050
3294
 
3051
3295
  static const int modTable[] = { 0, 2, 1 };
3052
3296
 
3053
- *outputLength = 4*((dataLength + 2)/3);
3297
+ *outputSize = 4*((dataSize + 2)/3);
3054
3298
 
3055
- char *encodedData = RL_MALLOC(*outputLength);
3299
+ char *encodedData = RL_MALLOC(*outputSize);
3056
3300
 
3057
3301
  if (encodedData == NULL) return NULL;
3058
3302
 
3059
- for (int i = 0, j = 0; i < dataLength;)
3303
+ for (int i = 0, j = 0; i < dataSize;)
3060
3304
  {
3061
- unsigned int octetA = (i < dataLength)? (unsigned char)data[i++] : 0;
3062
- unsigned int octetB = (i < dataLength)? (unsigned char)data[i++] : 0;
3063
- unsigned int octetC = (i < dataLength)? (unsigned char)data[i++] : 0;
3305
+ unsigned int octetA = (i < dataSize)? (unsigned char)data[i++] : 0;
3306
+ unsigned int octetB = (i < dataSize)? (unsigned char)data[i++] : 0;
3307
+ unsigned int octetC = (i < dataSize)? (unsigned char)data[i++] : 0;
3064
3308
 
3065
3309
  unsigned int triple = (octetA << 0x10) + (octetB << 0x08) + octetC;
3066
3310
 
@@ -3070,13 +3314,13 @@ char *EncodeDataBase64(const unsigned char *data, int dataLength, int *outputLen
3070
3314
  encodedData[j++] = base64encodeTable[(triple >> 0*6) & 0x3F];
3071
3315
  }
3072
3316
 
3073
- for (int i = 0; i < modTable[dataLength%3]; i++) encodedData[*outputLength - 1 - i] = '=';
3317
+ for (int i = 0; i < modTable[dataSize%3]; i++) encodedData[*outputSize - 1 - i] = '='; // Padding character
3074
3318
 
3075
3319
  return encodedData;
3076
3320
  }
3077
3321
 
3078
3322
  // Decode Base64 string data
3079
- unsigned char *DecodeDataBase64(unsigned char *data, int *outputLength)
3323
+ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
3080
3324
  {
3081
3325
  static const unsigned char base64decodeTable[] = {
3082
3326
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -3086,21 +3330,21 @@ unsigned char *DecodeDataBase64(unsigned char *data, int *outputLength)
3086
3330
  };
3087
3331
 
3088
3332
  // Get output size of Base64 input data
3089
- int outLength = 0;
3333
+ int outSize = 0;
3090
3334
  for (int i = 0; data[4*i] != 0; i++)
3091
3335
  {
3092
3336
  if (data[4*i + 3] == '=')
3093
3337
  {
3094
- if (data[4*i + 2] == '=') outLength += 1;
3095
- else outLength += 2;
3338
+ if (data[4*i + 2] == '=') outSize += 1;
3339
+ else outSize += 2;
3096
3340
  }
3097
- else outLength += 3;
3341
+ else outSize += 3;
3098
3342
  }
3099
3343
 
3100
3344
  // Allocate memory to store decoded Base64 data
3101
- unsigned char *decodedData = (unsigned char *)RL_MALLOC(outLength);
3345
+ unsigned char *decodedData = (unsigned char *)RL_MALLOC(outSize);
3102
3346
 
3103
- for (int i = 0; i < outLength/3; i++)
3347
+ for (int i = 0; i < outSize/3; i++)
3104
3348
  {
3105
3349
  unsigned char a = base64decodeTable[(int)data[4*i]];
3106
3350
  unsigned char b = base64decodeTable[(int)data[4*i + 1]];
@@ -3112,131 +3356,27 @@ unsigned char *DecodeDataBase64(unsigned char *data, int *outputLength)
3112
3356
  decodedData[3*i + 2] = (c << 6) | d;
3113
3357
  }
3114
3358
 
3115
- if (outLength%3 == 1)
3359
+ if (outSize%3 == 1)
3116
3360
  {
3117
- int n = outLength/3;
3361
+ int n = outSize/3;
3118
3362
  unsigned char a = base64decodeTable[(int)data[4*n]];
3119
3363
  unsigned char b = base64decodeTable[(int)data[4*n + 1]];
3120
- decodedData[outLength - 1] = (a << 2) | (b >> 4);
3364
+ decodedData[outSize - 1] = (a << 2) | (b >> 4);
3121
3365
  }
3122
- else if (outLength%3 == 2)
3366
+ else if (outSize%3 == 2)
3123
3367
  {
3124
- int n = outLength/3;
3368
+ int n = outSize/3;
3125
3369
  unsigned char a = base64decodeTable[(int)data[4*n]];
3126
3370
  unsigned char b = base64decodeTable[(int)data[4*n + 1]];
3127
3371
  unsigned char c = base64decodeTable[(int)data[4*n + 2]];
3128
- decodedData[outLength - 2] = (a << 2) | (b >> 4);
3129
- decodedData[outLength - 1] = (b << 4) | (c >> 2);
3372
+ decodedData[outSize - 2] = (a << 2) | (b >> 4);
3373
+ decodedData[outSize - 1] = (b << 4) | (c >> 2);
3130
3374
  }
3131
3375
 
3132
- *outputLength = outLength;
3376
+ *outputSize = outSize;
3133
3377
  return decodedData;
3134
3378
  }
3135
3379
 
3136
- // Save integer value to storage file (to defined position)
3137
- // NOTE: Storage positions is directly related to file memory layout (4 bytes each integer)
3138
- bool SaveStorageValue(unsigned int position, int value)
3139
- {
3140
- bool success = false;
3141
-
3142
- #if defined(SUPPORT_DATA_STORAGE)
3143
- char path[512] = { 0 };
3144
- strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, STORAGE_DATA_FILE));
3145
-
3146
- unsigned int dataSize = 0;
3147
- unsigned int newDataSize = 0;
3148
- unsigned char *fileData = LoadFileData(path, &dataSize);
3149
- unsigned char *newFileData = NULL;
3150
-
3151
- if (fileData != NULL)
3152
- {
3153
- if (dataSize <= (position*sizeof(int)))
3154
- {
3155
- // Increase data size up to position and store value
3156
- newDataSize = (position + 1)*sizeof(int);
3157
- newFileData = (unsigned char *)RL_REALLOC(fileData, newDataSize);
3158
-
3159
- if (newFileData != NULL)
3160
- {
3161
- // RL_REALLOC succeded
3162
- int *dataPtr = (int *)newFileData;
3163
- dataPtr[position] = value;
3164
- }
3165
- else
3166
- {
3167
- // RL_REALLOC failed
3168
- TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to realloc data (%u), position in bytes (%u) bigger than actual file size", path, dataSize, position*sizeof(int));
3169
-
3170
- // We store the old size of the file
3171
- newFileData = fileData;
3172
- newDataSize = dataSize;
3173
- }
3174
- }
3175
- else
3176
- {
3177
- // Store the old size of the file
3178
- newFileData = fileData;
3179
- newDataSize = dataSize;
3180
-
3181
- // Replace value on selected position
3182
- int *dataPtr = (int *)newFileData;
3183
- dataPtr[position] = value;
3184
- }
3185
-
3186
- success = SaveFileData(path, newFileData, newDataSize);
3187
- RL_FREE(newFileData);
3188
-
3189
- TRACELOG(LOG_INFO, "FILEIO: [%s] Saved storage value: %i", path, value);
3190
- }
3191
- else
3192
- {
3193
- TRACELOG(LOG_INFO, "FILEIO: [%s] File created successfully", path);
3194
-
3195
- dataSize = (position + 1)*sizeof(int);
3196
- fileData = (unsigned char *)RL_MALLOC(dataSize);
3197
- int *dataPtr = (int *)fileData;
3198
- dataPtr[position] = value;
3199
-
3200
- success = SaveFileData(path, fileData, dataSize);
3201
- UnloadFileData(fileData);
3202
-
3203
- TRACELOG(LOG_INFO, "FILEIO: [%s] Saved storage value: %i", path, value);
3204
- }
3205
- #endif
3206
-
3207
- return success;
3208
- }
3209
-
3210
- // Load integer value from storage file (from defined position)
3211
- // NOTE: If requested position could not be found, value 0 is returned
3212
- int LoadStorageValue(unsigned int position)
3213
- {
3214
- int value = 0;
3215
-
3216
- #if defined(SUPPORT_DATA_STORAGE)
3217
- char path[512] = { 0 };
3218
- strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, STORAGE_DATA_FILE));
3219
-
3220
- unsigned int dataSize = 0;
3221
- unsigned char *fileData = LoadFileData(path, &dataSize);
3222
-
3223
- if (fileData != NULL)
3224
- {
3225
- if (dataSize < (position*4)) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to find storage position: %i", path, position);
3226
- else
3227
- {
3228
- int *dataPtr = (int *)fileData;
3229
- value = dataPtr[position];
3230
- }
3231
-
3232
- UnloadFileData(fileData);
3233
-
3234
- TRACELOG(LOG_INFO, "FILEIO: [%s] Loaded storage value: %i", path, value);
3235
- }
3236
- #endif
3237
- return value;
3238
- }
3239
-
3240
3380
  // Open URL with default system browser (if available)
3241
3381
  // NOTE: This function is only safe to use if you control the URL given.
3242
3382
  // A user could craft a malicious string performing another action.
@@ -3255,19 +3395,43 @@ void OpenURL(const char *url)
3255
3395
  #if defined(PLATFORM_DESKTOP)
3256
3396
  char *cmd = (char *)RL_CALLOC(strlen(url) + 10, sizeof(char));
3257
3397
  #if defined(_WIN32)
3258
- sprintf(cmd, "explorer %s", url);
3398
+ sprintf(cmd, "explorer \"%s\"", url);
3259
3399
  #endif
3260
- #if defined(__linux__) || defined(__FreeBSD__)
3400
+ #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
3261
3401
  sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser
3262
3402
  #endif
3263
3403
  #if defined(__APPLE__)
3264
3404
  sprintf(cmd, "open '%s'", url);
3265
3405
  #endif
3266
- system(cmd);
3406
+ int result = system(cmd);
3407
+ if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
3267
3408
  RL_FREE(cmd);
3268
3409
  #endif
3269
3410
  #if defined(PLATFORM_WEB)
3270
3411
  emscripten_run_script(TextFormat("window.open('%s', '_blank')", url));
3412
+ #endif
3413
+ #if defined(PLATFORM_ANDROID)
3414
+ JNIEnv *env = NULL;
3415
+ JavaVM *vm = CORE.Android.app->activity->vm;
3416
+ (*vm)->AttachCurrentThread(vm, &env, NULL);
3417
+
3418
+ jstring urlString = (*env)->NewStringUTF(env, url);
3419
+ jclass uriClass = (*env)->FindClass(env, "android/net/Uri");
3420
+ jmethodID uriParse = (*env)->GetStaticMethodID(env, uriClass, "parse", "(Ljava/lang/String;)Landroid/net/Uri;");
3421
+ jobject uri = (*env)->CallStaticObjectMethod(env, uriClass, uriParse, urlString);
3422
+
3423
+ jclass intentClass = (*env)->FindClass(env, "android/content/Intent");
3424
+ jfieldID actionViewId = (*env)->GetStaticFieldID(env, intentClass, "ACTION_VIEW", "Ljava/lang/String;");
3425
+ jobject actionView = (*env)->GetStaticObjectField(env, intentClass, actionViewId);
3426
+ jmethodID newIntent = (*env)->GetMethodID(env, intentClass, "<init>", "(Ljava/lang/String;Landroid/net/Uri;)V");
3427
+ jobject intent = (*env)->AllocObject(env, intentClass);
3428
+
3429
+ (*env)->CallVoidMethod(env, intent, newIntent, actionView, uri);
3430
+ jclass activityClass = (*env)->FindClass(env, "android/app/Activity");
3431
+ jmethodID startActivity = (*env)->GetMethodID(env, activityClass, "startActivity", "(Landroid/content/Intent;)V");
3432
+ (*env)->CallVoidMethod(env, CORE.Android.app->activity->clazz, startActivity, intent);
3433
+
3434
+ (*vm)->DetachCurrentThread(vm);
3271
3435
  #endif
3272
3436
  }
3273
3437
  }
@@ -3594,14 +3758,24 @@ void SetMouseScale(float scaleX, float scaleY)
3594
3758
  // Get mouse wheel movement Y
3595
3759
  float GetMouseWheelMove(void)
3596
3760
  {
3597
- #if defined(PLATFORM_ANDROID)
3598
- return 0.0f;
3599
- #endif
3600
- #if defined(PLATFORM_WEB)
3601
- return CORE.Input.Mouse.previousWheelMove/100.0f;
3761
+ float result = 0.0f;
3762
+
3763
+ #if !defined(PLATFORM_ANDROID)
3764
+ if (fabsf(CORE.Input.Mouse.currentWheelMove.x) > fabsf(CORE.Input.Mouse.currentWheelMove.y)) result = (float)CORE.Input.Mouse.currentWheelMove.x;
3765
+ else result = (float)CORE.Input.Mouse.currentWheelMove.y;
3602
3766
  #endif
3603
3767
 
3604
- return CORE.Input.Mouse.previousWheelMove;
3768
+ return result;
3769
+ }
3770
+
3771
+ // Get mouse wheel movement X/Y as a vector
3772
+ Vector2 GetMouseWheelMoveV(void)
3773
+ {
3774
+ Vector2 result = { 0 };
3775
+
3776
+ result = CORE.Input.Mouse.currentWheelMove;
3777
+
3778
+ return result;
3605
3779
  }
3606
3780
 
3607
3781
  // Set mouse cursor
@@ -3804,6 +3978,10 @@ static bool InitGraphicsDevice(int width, int height)
3804
3978
  #endif
3805
3979
  }
3806
3980
  else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
3981
+
3982
+ // Mouse passthrough
3983
+ if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
3984
+ else glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE);
3807
3985
  #endif
3808
3986
 
3809
3987
  if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
@@ -3892,14 +4070,6 @@ static bool InitGraphicsDevice(int width, int height)
3892
4070
  }
3893
4071
  }
3894
4072
  }
3895
-
3896
- #if defined(PLATFORM_DESKTOP)
3897
- // If we are windowed fullscreen, ensures that window does not minimize when focus is lost
3898
- if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
3899
- {
3900
- glfwWindowHint(GLFW_AUTO_ICONIFY, 0);
3901
- }
3902
- #endif
3903
4073
  TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
3904
4074
 
3905
4075
  // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example,
@@ -3921,6 +4091,13 @@ static bool InitGraphicsDevice(int width, int height)
3921
4091
  }
3922
4092
  else
3923
4093
  {
4094
+ #if defined(PLATFORM_DESKTOP)
4095
+ // If we are windowed fullscreen, ensures that window does not minimize when focus is lost
4096
+ if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
4097
+ {
4098
+ glfwWindowHint(GLFW_AUTO_ICONIFY, 0);
4099
+ }
4100
+ #endif
3924
4101
  // No-fullscreen window creation
3925
4102
  CORE.Window.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL);
3926
4103
 
@@ -3978,7 +4155,7 @@ static bool InitGraphicsDevice(int width, int height)
3978
4155
  glfwSwapInterval(1);
3979
4156
  TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC");
3980
4157
  }
3981
-
4158
+
3982
4159
  int fbWidth = CORE.Window.screen.width;
3983
4160
  int fbHeight = CORE.Window.screen.height;
3984
4161
 
@@ -4003,7 +4180,7 @@ static bool InitGraphicsDevice(int width, int height)
4003
4180
  CORE.Window.render.height = fbHeight;
4004
4181
  CORE.Window.currentFbo.width = fbWidth;
4005
4182
  CORE.Window.currentFbo.height = fbHeight;
4006
-
4183
+
4007
4184
  TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
4008
4185
  TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
4009
4186
  TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
@@ -4042,11 +4219,13 @@ static bool InitGraphicsDevice(int width, int height)
4042
4219
  #else
4043
4220
  TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying platform-gpu-card");
4044
4221
  CORE.Window.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
4222
+
4045
4223
  if ((-1 == CORE.Window.fd) || (drmModeGetResources(CORE.Window.fd) == NULL))
4046
4224
  {
4047
4225
  TRACELOG(LOG_INFO, "DISPLAY: Failed to open platform-gpu-card, trying card1");
4048
4226
  CORE.Window.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
4049
4227
  }
4228
+
4050
4229
  if ((-1 == CORE.Window.fd) || (drmModeGetResources(CORE.Window.fd) == NULL))
4051
4230
  {
4052
4231
  TRACELOG(LOG_INFO, "DISPLAY: Failed to open graphic card1, trying card0");
@@ -4415,7 +4594,7 @@ static bool InitGraphicsDevice(int width, int height)
4415
4594
  CORE.Window.render.height = CORE.Window.screen.height;
4416
4595
  CORE.Window.currentFbo.width = CORE.Window.render.width;
4417
4596
  CORE.Window.currentFbo.height = CORE.Window.render.height;
4418
-
4597
+
4419
4598
  TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
4420
4599
  TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
4421
4600
  TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
@@ -4440,8 +4619,6 @@ static bool InitGraphicsDevice(int width, int height)
4440
4619
  // NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
4441
4620
  SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
4442
4621
 
4443
- ClearBackground(RAYWHITE); // Default background color for raylib games :P
4444
-
4445
4622
  #if defined(PLATFORM_ANDROID)
4446
4623
  CORE.Window.ready = true;
4447
4624
  #endif
@@ -4581,49 +4758,46 @@ static void InitTimer(void)
4581
4758
  CORE.Time.previous = GetTime(); // Get time as double
4582
4759
  }
4583
4760
 
4584
- // Wait for some milliseconds (stop program execution)
4761
+ // Wait for some time (stop program execution)
4585
4762
  // NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
4586
4763
  // take longer than expected... for that reason we use the busy wait loop
4587
4764
  // Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
4588
4765
  // Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timming on Win32!
4589
- void WaitTime(float ms)
4766
+ void WaitTime(double seconds)
4590
4767
  {
4591
- #if defined(SUPPORT_BUSY_WAIT_LOOP)
4592
- double previousTime = GetTime();
4593
- double currentTime = 0.0;
4768
+ #if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
4769
+ double destinationTime = GetTime() + seconds;
4770
+ #endif
4594
4771
 
4595
- // Busy wait loop
4596
- while ((currentTime - previousTime) < ms/1000.0f) currentTime = GetTime();
4772
+ #if defined(SUPPORT_BUSY_WAIT_LOOP)
4773
+ while (GetTime() < destinationTime) { }
4597
4774
  #else
4598
4775
  #if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
4599
- double busyWait = ms*0.05; // NOTE: We are using a busy wait of 5% of the time
4600
- ms -= (float)busyWait;
4776
+ double sleepSeconds = seconds - seconds*0.05; // NOTE: We reserve a percentage of the time for busy waiting
4777
+ #else
4778
+ double sleepSeconds = seconds;
4601
4779
  #endif
4602
4780
 
4603
4781
  // System halt functions
4604
4782
  #if defined(_WIN32)
4605
- Sleep((unsigned int)ms);
4783
+ Sleep((unsigned long)(sleepSeconds*1000.0));
4606
4784
  #endif
4607
- #if defined(__linux__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__)
4785
+ #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
4608
4786
  struct timespec req = { 0 };
4609
- time_t sec = (int)(ms/1000.0f);
4610
- ms -= (sec*1000);
4787
+ time_t sec = sleepSeconds;
4788
+ long nsec = (sleepSeconds - sec)*1000000000L;
4611
4789
  req.tv_sec = sec;
4612
- req.tv_nsec = ms*1000000L;
4790
+ req.tv_nsec = nsec;
4613
4791
 
4614
4792
  // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated.
4615
4793
  while (nanosleep(&req, &req) == -1) continue;
4616
4794
  #endif
4617
4795
  #if defined(__APPLE__)
4618
- usleep(ms*1000.0f);
4796
+ usleep(sleepSeconds*1000000.0);
4619
4797
  #endif
4620
4798
 
4621
4799
  #if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
4622
- double previousTime = GetTime();
4623
- double currentTime = 0.0;
4624
-
4625
- // Partial busy wait loop (only a fraction of the total wait time)
4626
- while ((currentTime - previousTime) < busyWait/1000.0f) currentTime = GetTime();
4800
+ while (GetTime() < destinationTime) { }
4627
4801
  #endif
4628
4802
  #endif
4629
4803
  }
@@ -4639,53 +4813,31 @@ void SwapScreenBuffer(void)
4639
4813
  eglSwapBuffers(CORE.Window.device, CORE.Window.surface);
4640
4814
 
4641
4815
  #if defined(PLATFORM_DRM)
4642
- if (!CORE.Window.gbmSurface || (-1 == CORE.Window.fd) || !CORE.Window.connector || !CORE.Window.crtc)
4643
- {
4644
- TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap");
4645
- abort();
4646
- }
4816
+
4817
+ if (!CORE.Window.gbmSurface || (-1 == CORE.Window.fd) || !CORE.Window.connector || !CORE.Window.crtc) TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap");
4647
4818
 
4648
4819
  struct gbm_bo *bo = gbm_surface_lock_front_buffer(CORE.Window.gbmSurface);
4649
- if (!bo)
4650
- {
4651
- TRACELOG(LOG_ERROR, "DISPLAY: Failed GBM to lock front buffer");
4652
- abort();
4653
- }
4820
+ if (!bo) TRACELOG(LOG_ERROR, "DISPLAY: Failed GBM to lock front buffer");
4654
4821
 
4655
4822
  uint32_t fb = 0;
4656
- int result = drmModeAddFB(CORE.Window.fd, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay,
4657
- CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb);
4658
- if (0 != result)
4659
- {
4660
- TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d", result);
4661
- abort();
4662
- }
4823
+ int result = drmModeAddFB(CORE.Window.fd, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb);
4824
+ if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d", result);
4663
4825
 
4664
- result = drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, fb, 0, 0,
4665
- &CORE.Window.connector->connector_id, 1, &CORE.Window.connector->modes[CORE.Window.modeIndex]);
4666
- if (0 != result)
4667
- {
4668
- TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d", result);
4669
- abort();
4670
- }
4826
+ result = drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, fb, 0, 0, &CORE.Window.connector->connector_id, 1, &CORE.Window.connector->modes[CORE.Window.modeIndex]);
4827
+ if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d", result);
4671
4828
 
4672
4829
  if (CORE.Window.prevFB)
4673
4830
  {
4674
4831
  result = drmModeRmFB(CORE.Window.fd, CORE.Window.prevFB);
4675
- if (0 != result)
4676
- {
4677
- TRACELOG(LOG_ERROR, "DISPLAY: drmModeRmFB() failed with result: %d", result);
4678
- abort();
4679
- }
4832
+ if (result != 0) TRACELOG(LOG_ERROR, "DISPLAY: drmModeRmFB() failed with result: %d", result);
4680
4833
  }
4834
+
4681
4835
  CORE.Window.prevFB = fb;
4682
4836
 
4683
- if (CORE.Window.prevBO)
4684
- {
4685
- gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO);
4686
- }
4837
+ if (CORE.Window.prevBO) gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO);
4687
4838
 
4688
4839
  CORE.Window.prevBO = bo;
4840
+
4689
4841
  #endif // PLATFORM_DRM
4690
4842
  #endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM
4691
4843
  }
@@ -4717,7 +4869,7 @@ void PollInputEvents(void)
4717
4869
 
4718
4870
  // Register previous mouse states
4719
4871
  CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
4720
- CORE.Input.Mouse.currentWheelMove = 0.0f;
4872
+ CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f };
4721
4873
  for (int i = 0; i < MAX_MOUSE_BUTTONS; i++)
4722
4874
  {
4723
4875
  CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
@@ -4746,7 +4898,7 @@ void PollInputEvents(void)
4746
4898
 
4747
4899
  // Register previous mouse wheel state
4748
4900
  CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
4749
- CORE.Input.Mouse.currentWheelMove = 0.0f;
4901
+ CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f };
4750
4902
 
4751
4903
  // Register previous mouse position
4752
4904
  CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
@@ -4754,7 +4906,7 @@ void PollInputEvents(void)
4754
4906
 
4755
4907
  // Register previous touch states
4756
4908
  for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
4757
-
4909
+
4758
4910
  // Reset touch positions
4759
4911
  // TODO: It resets on PLATFORM_WEB the mouse position and not filled again until a move-event,
4760
4912
  // so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed!
@@ -4833,8 +4985,8 @@ void PollInputEvents(void)
4833
4985
  }
4834
4986
 
4835
4987
  // Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis)
4836
- CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = (char)(CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1);
4837
- CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = (char)(CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] > 0.1);
4988
+ CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = (char)(CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f);
4989
+ CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_RIGHT_TRIGGER_2] = (char)(CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] > 0.1f);
4838
4990
 
4839
4991
  CORE.Input.Gamepad.axisCount = GLFW_GAMEPAD_AXIS_LAST + 1;
4840
4992
  }
@@ -4842,11 +4994,8 @@ void PollInputEvents(void)
4842
4994
 
4843
4995
  CORE.Window.resizedLastFrame = false;
4844
4996
 
4845
- #if defined(SUPPORT_EVENTS_WAITING)
4846
- glfwWaitEvents();
4847
- #else
4848
- glfwPollEvents(); // Register keyboard/mouse events (callbacks)... and window events!
4849
- #endif
4997
+ if (CORE.Window.eventWaiting) glfwWaitEvents(); // Wait for in input events before continue (drawing is paused)
4998
+ else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks)
4850
4999
  #endif // PLATFORM_DESKTOP
4851
5000
 
4852
5001
  #if defined(PLATFORM_WEB)
@@ -4958,45 +5107,102 @@ void PollInputEvents(void)
4958
5107
  #endif
4959
5108
  }
4960
5109
 
4961
- #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
4962
- // GLFW3 Error Callback, runs on GLFW3 error
4963
- static void ErrorCallback(int error, const char *description)
5110
+ // Scan all files and directories in a base path
5111
+ // WARNING: files.paths[] must be previously allocated and
5112
+ // contain enough space to store all required paths
5113
+ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const char *filter)
4964
5114
  {
4965
- TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description);
4966
- }
5115
+ static char path[MAX_FILEPATH_LENGTH] = { 0 };
5116
+ memset(path, 0, MAX_FILEPATH_LENGTH);
4967
5117
 
4968
- #if defined(PLATFORM_WEB)
4969
- EM_JS(int, GetCanvasWidth, (), { return canvas.clientWidth; });
4970
- EM_JS(int, GetCanvasHeight, (), { return canvas.clientHeight; });
5118
+ struct dirent *dp = NULL;
5119
+ DIR *dir = opendir(basePath);
4971
5120
 
4972
- static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *e, void *userData)
4973
- {
4974
- // Don't resize non-resizeable windows
4975
- if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
5121
+ if (dir != NULL)
5122
+ {
5123
+ while ((dp = readdir(dir)) != NULL)
5124
+ {
5125
+ if ((strcmp(dp->d_name, ".") != 0) &&
5126
+ (strcmp(dp->d_name, "..") != 0))
5127
+ {
5128
+ sprintf(path, "%s/%s", basePath, dp->d_name);
4976
5129
 
4977
- // This event is called whenever the window changes sizes,
4978
- // so the size of the canvas object is explicitly retrieved below
4979
- int width = GetCanvasWidth();
4980
- int height = GetCanvasHeight();
4981
- emscripten_set_canvas_element_size("#canvas",width,height);
5130
+ if (filter != NULL)
5131
+ {
5132
+ if (IsFileExtension(path, filter))
5133
+ {
5134
+ strcpy(files->paths[files->count], path);
5135
+ files->count++;
5136
+ }
5137
+ }
5138
+ else
5139
+ {
5140
+ strcpy(files->paths[files->count], path);
5141
+ files->count++;
5142
+ }
5143
+ }
5144
+ }
4982
5145
 
4983
- SetupViewport(width, height); // Reset viewport and projection matrix for new size
5146
+ closedir(dir);
5147
+ }
5148
+ else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath);
5149
+ }
4984
5150
 
4985
- CORE.Window.currentFbo.width = width;
4986
- CORE.Window.currentFbo.height = height;
4987
- CORE.Window.resizedLastFrame = true;
5151
+ // Scan all files and directories recursively from a base path
5152
+ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
5153
+ {
5154
+ static char path[MAX_FILEPATH_LENGTH] = { 0 };
5155
+ memset(path, 0, MAX_FILEPATH_LENGTH);
4988
5156
 
4989
- if (IsWindowFullscreen()) return 1;
5157
+ struct dirent *dp = NULL;
5158
+ DIR *dir = opendir(basePath);
4990
5159
 
4991
- // Set current screen size
4992
- CORE.Window.screen.width = width;
4993
- CORE.Window.screen.height = height;
5160
+ if (dir != NULL)
5161
+ {
5162
+ while (((dp = readdir(dir)) != NULL) && (files->count < files->capacity))
5163
+ {
5164
+ if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0))
5165
+ {
5166
+ // Construct new path from our base path
5167
+ sprintf(path, "%s/%s", basePath, dp->d_name);
4994
5168
 
4995
- // NOTE: Postprocessing texture is not scaled to new size
5169
+ if (IsPathFile(path))
5170
+ {
5171
+ if (filter != NULL)
5172
+ {
5173
+ if (IsFileExtension(path, filter))
5174
+ {
5175
+ strcpy(files->paths[files->count], path);
5176
+ files->count++;
5177
+ }
5178
+ }
5179
+ else
5180
+ {
5181
+ strcpy(files->paths[files->count], path);
5182
+ files->count++;
5183
+ }
4996
5184
 
4997
- return 0;
5185
+ if (files->count >= files->capacity)
5186
+ {
5187
+ TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity);
5188
+ break;
5189
+ }
5190
+ }
5191
+ else ScanDirectoryFilesRecursively(path, files, filter);
5192
+ }
5193
+ }
5194
+
5195
+ closedir(dir);
5196
+ }
5197
+ else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath);
5198
+ }
5199
+
5200
+ #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
5201
+ // GLFW3 Error Callback, runs on GLFW3 error
5202
+ static void ErrorCallback(int error, const char *description)
5203
+ {
5204
+ TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description);
4998
5205
  }
4999
- #endif
5000
5206
 
5001
5207
  // GLFW3 WindowSize Callback, runs when window is resizedLastFrame
5002
5208
  // NOTE: Window resizing not allowed by default
@@ -5059,6 +5265,8 @@ static void WindowFocusCallback(GLFWwindow *window, int focused)
5059
5265
  // GLFW3 Keyboard Callback, runs on key pressed
5060
5266
  static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
5061
5267
  {
5268
+ if (key < 0) return; // Security check, macOS fn key generates -1
5269
+
5062
5270
  // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1
5063
5271
  // to work properly with our implementation (IsKeyDown/IsKeyUp checks)
5064
5272
  if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0;
@@ -5071,7 +5279,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
5071
5279
  CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
5072
5280
  CORE.Input.Keyboard.keyPressedQueueCount++;
5073
5281
  }
5074
-
5282
+
5075
5283
  // Check the exit key to set close window
5076
5284
  if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(CORE.Window.handle, GLFW_TRUE);
5077
5285
 
@@ -5103,7 +5311,8 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
5103
5311
  gifRecording = true;
5104
5312
  gifFrameCounter = 0;
5105
5313
 
5106
- msf_gif_begin(&gifState, CORE.Window.screen.width, CORE.Window.screen.height);
5314
+ Vector2 scale = GetWindowScaleDPI();
5315
+ msf_gif_begin(&gifState, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
5107
5316
  screenshotCounter++;
5108
5317
 
5109
5318
  TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter));
@@ -5221,11 +5430,10 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
5221
5430
  #endif
5222
5431
  }
5223
5432
 
5224
- // GLFW3 Srolling Callback, runs on mouse wheel
5433
+ // GLFW3 Scrolling Callback, runs on mouse wheel
5225
5434
  static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset)
5226
5435
  {
5227
- if (xoffset != 0.0) CORE.Input.Mouse.currentWheelMove = (float)xoffset;
5228
- else CORE.Input.Mouse.currentWheelMove = (float)yoffset;
5436
+ CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset };
5229
5437
  }
5230
5438
 
5231
5439
  // GLFW3 CursorEnter Callback, when cursor enters the window
@@ -5236,21 +5444,28 @@ static void CursorEnterCallback(GLFWwindow *window, int enter)
5236
5444
  }
5237
5445
 
5238
5446
  // GLFW3 Window Drop Callback, runs when drop files into window
5239
- // NOTE: Paths are stored in dynamic memory for further retrieval
5240
- // Everytime new files are dropped, old ones are discarded
5241
5447
  static void WindowDropCallback(GLFWwindow *window, int count, const char **paths)
5242
5448
  {
5243
- ClearDroppedFiles();
5449
+ // In case previous dropped filepaths have not been freed, we free them
5450
+ if (CORE.Window.dropFileCount > 0)
5451
+ {
5452
+ for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]);
5244
5453
 
5245
- CORE.Window.dropFilesPath = (char **)RL_MALLOC(count*sizeof(char *));
5454
+ RL_FREE(CORE.Window.dropFilepaths);
5246
5455
 
5247
- for (int i = 0; i < count; i++)
5248
- {
5249
- CORE.Window.dropFilesPath[i] = (char *)RL_MALLOC(MAX_FILEPATH_LENGTH*sizeof(char));
5250
- strcpy(CORE.Window.dropFilesPath[i], paths[i]);
5456
+ CORE.Window.dropFileCount = 0;
5457
+ CORE.Window.dropFilepaths = NULL;
5251
5458
  }
5252
5459
 
5460
+ // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy
5253
5461
  CORE.Window.dropFileCount = count;
5462
+ CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *));
5463
+
5464
+ for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++)
5465
+ {
5466
+ CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
5467
+ strcpy(CORE.Window.dropFilepaths[i], paths[i]);
5468
+ }
5254
5469
  }
5255
5470
  #endif
5256
5471
 
@@ -5296,13 +5511,15 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
5296
5511
  // Initialize random seed
5297
5512
  srand((unsigned int)time(NULL));
5298
5513
 
5299
- #if defined(SUPPORT_DEFAULT_FONT)
5514
+ #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
5300
5515
  // Load default font
5301
- // NOTE: External function (defined in module: text)
5516
+ // WARNING: External function: Module required: rtext
5302
5517
  LoadFontDefault();
5303
5518
  Rectangle rec = GetFontDefault().recs[95];
5304
5519
  // NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
5305
- SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
5520
+ #if defined(SUPPORT_MODULE_RSHAPES)
5521
+ SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); // WARNING: Module required: rshapes
5522
+ #endif
5306
5523
  #endif
5307
5524
 
5308
5525
  // TODO: GPU assets reload in case of lost focus (lost context)
@@ -5485,11 +5702,82 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
5485
5702
  #endif
5486
5703
 
5487
5704
  #if defined(PLATFORM_WEB)
5705
+ // Register fullscreen change events
5706
+ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
5707
+ {
5708
+ // TODO: Implement EmscriptenFullscreenChangeCallback()?
5709
+
5710
+ return 1; // The event was consumed by the callback handler
5711
+ }
5712
+
5713
+ // Register window resize event
5714
+ static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
5715
+ {
5716
+ // TODO: Implement EmscriptenWindowResizedCallback()?
5717
+
5718
+ return 1; // The event was consumed by the callback handler
5719
+ }
5720
+
5721
+ EM_JS(int, GetCanvasWidth, (), { return canvas.clientWidth; });
5722
+ EM_JS(int, GetCanvasHeight, (), { return canvas.clientHeight; });
5723
+
5724
+ // Register DOM element resize event
5725
+ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
5726
+ {
5727
+ // Don't resize non-resizeable windows
5728
+ if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
5729
+
5730
+ // This event is called whenever the window changes sizes,
5731
+ // so the size of the canvas object is explicitly retrieved below
5732
+ int width = GetCanvasWidth();
5733
+ int height = GetCanvasHeight();
5734
+ emscripten_set_canvas_element_size("#canvas",width,height);
5735
+
5736
+ SetupViewport(width, height); // Reset viewport and projection matrix for new size
5737
+
5738
+ CORE.Window.currentFbo.width = width;
5739
+ CORE.Window.currentFbo.height = height;
5740
+ CORE.Window.resizedLastFrame = true;
5741
+
5742
+ if (IsWindowFullscreen()) return 1;
5743
+
5744
+ // Set current screen size
5745
+ CORE.Window.screen.width = width;
5746
+ CORE.Window.screen.height = height;
5747
+
5748
+ // NOTE: Postprocessing texture is not scaled to new size
5749
+
5750
+ return 0;
5751
+ }
5752
+
5488
5753
  // Register mouse input events
5489
5754
  static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
5490
5755
  {
5491
5756
  // This is only for registering mouse click events with emscripten and doesn't need to do anything
5492
- return 0;
5757
+
5758
+ return 1; // The event was consumed by the callback handler
5759
+ }
5760
+
5761
+ // Register connected/disconnected gamepads events
5762
+ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
5763
+ {
5764
+ /*
5765
+ TRACELOGD("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"",
5766
+ eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
5767
+ gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
5768
+
5769
+ for (int i = 0; i < gamepadEvent->numAxes; ++i) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]);
5770
+ for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
5771
+ */
5772
+
5773
+ if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS))
5774
+ {
5775
+ CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
5776
+ sprintf(CORE.Input.Gamepad.name[gamepadEvent->index],"%s",gamepadEvent->id);
5777
+ }
5778
+ else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
5779
+
5780
+ return 1; // The event was consumed by the callback handler
5493
5781
  }
5494
5782
 
5495
5783
  // Register touch input events
@@ -5542,29 +5830,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
5542
5830
  ProcessGestureEvent(gestureEvent);
5543
5831
  #endif
5544
5832
 
5545
- return 1;
5546
- }
5547
-
5548
- // Register connected/disconnected gamepads events
5549
- static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
5550
- {
5551
- /*
5552
- TRACELOGD("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"",
5553
- eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
5554
- gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
5555
-
5556
- for (int i = 0; i < gamepadEvent->numAxes; ++i) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]);
5557
- for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
5558
- */
5559
-
5560
- if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS))
5561
- {
5562
- CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
5563
- sprintf(CORE.Input.Gamepad.name[gamepadEvent->index],"%s",gamepadEvent->id);
5564
- }
5565
- else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
5566
-
5567
- return 0;
5833
+ return 1; // The event was consumed by the callback handler
5568
5834
  }
5569
5835
  #endif
5570
5836
 
@@ -5633,8 +5899,8 @@ static void ProcessKeyboard(void)
5633
5899
  #define MAX_KEYBUFFER_SIZE 32 // Max size in bytes to read
5634
5900
 
5635
5901
  // Keyboard input polling (fill keys[256] array with status)
5636
- int bufferByteCount = 0; // Bytes available on the buffer
5637
- char keysBuffer[MAX_KEYBUFFER_SIZE]; // Max keys to be read at a time
5902
+ int bufferByteCount = 0; // Bytes available on the buffer
5903
+ char keysBuffer[MAX_KEYBUFFER_SIZE] = { 0 }; // Max keys to be read at a time
5638
5904
 
5639
5905
  // Read availables keycodes from stdin
5640
5906
  bufferByteCount = read(STDIN_FILENO, keysBuffer, MAX_KEYBUFFER_SIZE); // POSIX system call
@@ -5765,7 +6031,8 @@ static void InitEvdevInput(void)
5765
6031
  {
5766
6032
  while ((entity = readdir(directory)) != NULL)
5767
6033
  {
5768
- if (strncmp("event", entity->d_name, strlen("event")) == 0) // Search for devices named "event*"
6034
+ if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*"
6035
+ (strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*"
5769
6036
  {
5770
6037
  sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
5771
6038
  ConfigureEvdevDevice(path); // Configure the device if appropriate
@@ -5828,7 +6095,7 @@ static void ConfigureEvdevDevice(char *device)
5828
6095
  fd = open(device, O_RDONLY | O_NONBLOCK);
5829
6096
  if (fd < 0)
5830
6097
  {
5831
- TRACELOG(LOG_WARNING, "RPI: Failed to open input device %s", device);
6098
+ TRACELOG(LOG_WARNING, "RPI: Failed to open input device: %s", device);
5832
6099
  return;
5833
6100
  }
5834
6101
  worker->fd = fd;
@@ -5842,6 +6109,7 @@ static void ConfigureEvdevDevice(char *device)
5842
6109
  {
5843
6110
  if (sscanf(ptrDevName, "t%d", &devNum) == 1) worker->eventNum = devNum;
5844
6111
  }
6112
+ else worker->eventNum = 0; // TODO: HACK: Grab number for mouse0 device!
5845
6113
 
5846
6114
  // At this point we have a connection to the device, but we don't yet know what the device is.
5847
6115
  // It could be many things, even as simple as a power button...
@@ -5925,7 +6193,7 @@ static void ConfigureEvdevDevice(char *device)
5925
6193
 
5926
6194
  // Decide what to do with the device
5927
6195
  //-------------------------------------------------------------------------------------------------------
5928
- if (worker->isKeyboard && CORE.Input.Keyboard.fd == -1)
6196
+ if (worker->isKeyboard && (CORE.Input.Keyboard.fd == -1))
5929
6197
  {
5930
6198
  // Use the first keyboard encountered. This assumes that a device that says it's a keyboard is just a
5931
6199
  // keyboard. The keyboard is polled synchronously, whereas other input devices are polled in separate
@@ -6089,7 +6357,7 @@ static void *EventThread(void *arg)
6089
6357
  gestureUpdate = true;
6090
6358
  }
6091
6359
 
6092
- if (event.code == REL_WHEEL) CORE.Input.Mouse.currentWheelMove += event.value;
6360
+ if (event.code == REL_WHEEL) CORE.Input.Mouse.currentWheelMove.y += event.value;
6093
6361
  }
6094
6362
 
6095
6363
  // Absolute movement parsing
@@ -6220,7 +6488,7 @@ static void *EventThread(void *arg)
6220
6488
  #endif
6221
6489
  }
6222
6490
 
6223
- WaitTime(5); // Sleep for 5ms to avoid hogging CPU time
6491
+ WaitTime(0.005); // Sleep for 5ms to avoid hogging CPU time
6224
6492
  }
6225
6493
 
6226
6494
  close(worker->fd);
@@ -6237,7 +6505,7 @@ static void InitGamepad(void)
6237
6505
  {
6238
6506
  sprintf(gamepadDev, "%s%i", DEFAULT_GAMEPAD_DEV, i);
6239
6507
 
6240
- if ((CORE.Input.Gamepad.streamId[i] = open(gamepadDev, O_RDONLY|O_NONBLOCK)) < 0)
6508
+ if ((CORE.Input.Gamepad.streamId[i] = open(gamepadDev, O_RDONLY | O_NONBLOCK)) < 0)
6241
6509
  {
6242
6510
  // NOTE: Only show message for first gamepad
6243
6511
  if (i == 0) TRACELOG(LOG_WARNING, "RPI: Failed to open Gamepad device, no gamepad available");
@@ -6308,7 +6576,7 @@ static void *GamepadThread(void *arg)
6308
6576
  }
6309
6577
  }
6310
6578
  }
6311
- else WaitTime(1); // Sleep for 1 ms to avoid hogging CPU time
6579
+ else WaitTime(0.001); // Sleep for 1 ms to avoid hogging CPU time
6312
6580
  }
6313
6581
  }
6314
6582
 
@@ -6376,7 +6644,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
6376
6644
  TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh,
6377
6645
  (mode->flags & DRM_MODE_FLAG_INTERLACE) ? "interlaced" : "progressive");
6378
6646
 
6379
- if ((mode->hdisplay < width) || (mode->vdisplay < height) | (mode->vrefresh < fps))
6647
+ if ((mode->hdisplay < width) || (mode->vdisplay < height))
6380
6648
  {
6381
6649
  TRACELOG(LOG_TRACE, "DISPLAY: DRM mode is too small");
6382
6650
  continue;
@@ -6388,23 +6656,22 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
6388
6656
  continue;
6389
6657
  }
6390
6658
 
6391
- if ((mode->hdisplay >= width) && (mode->vdisplay >= height) && (mode->vrefresh >= fps))
6659
+ if (nearestIndex < 0)
6392
6660
  {
6393
- const int widthDiff = mode->hdisplay - width;
6394
- const int heightDiff = mode->vdisplay - height;
6395
- const int fpsDiff = mode->vrefresh - fps;
6661
+ nearestIndex = i;
6662
+ continue;
6663
+ }
6396
6664
 
6397
- if (nearestIndex < 0)
6398
- {
6399
- nearestIndex = i;
6400
- continue;
6401
- }
6665
+ const int widthDiff = abs(mode->hdisplay - width);
6666
+ const int heightDiff = abs(mode->vdisplay - height);
6667
+ const int fpsDiff = abs(mode->vrefresh - fps);
6402
6668
 
6403
- const int nearestWidthDiff = CORE.Window.connector->modes[nearestIndex].hdisplay - width;
6404
- const int nearestHeightDiff = CORE.Window.connector->modes[nearestIndex].vdisplay - height;
6405
- const int nearestFpsDiff = CORE.Window.connector->modes[nearestIndex].vrefresh - fps;
6669
+ const int nearestWidthDiff = abs(CORE.Window.connector->modes[nearestIndex].hdisplay - width);
6670
+ const int nearestHeightDiff = abs(CORE.Window.connector->modes[nearestIndex].vdisplay - height);
6671
+ const int nearestFpsDiff = abs(CORE.Window.connector->modes[nearestIndex].vrefresh - fps);
6406
6672
 
6407
- if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff)) nearestIndex = i;
6673
+ if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff)) {
6674
+ nearestIndex = i;
6408
6675
  }
6409
6676
  }
6410
6677
 
@@ -6414,6 +6681,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
6414
6681
 
6415
6682
  #if defined(SUPPORT_EVENTS_AUTOMATION)
6416
6683
  // NOTE: Loading happens over AutomationEvent *events
6684
+ // TODO: This system should probably be redesigned
6417
6685
  static void LoadAutomationEvents(const char *fileName)
6418
6686
  {
6419
6687
  //unsigned char fileId[4] = { 0 };
@@ -6576,12 +6844,13 @@ static void RecordAutomationEvent(unsigned int frame)
6576
6844
  }
6577
6845
 
6578
6846
  // INPUT_MOUSE_WHEEL_MOTION
6579
- if ((int)CORE.Input.Mouse.currentWheelMove != (int)CORE.Input.Mouse.previousWheelMove)
6847
+ if (((int)CORE.Input.Mouse.currentWheelMove.x != (int)CORE.Input.Mouse.previousWheelMove.x) ||
6848
+ ((int)CORE.Input.Mouse.currentWheelMove.y != (int)CORE.Input.Mouse.previousWheelMove.y))
6580
6849
  {
6581
6850
  events[eventCount].frame = frame;
6582
6851
  events[eventCount].type = INPUT_MOUSE_WHEEL_MOTION;
6583
- events[eventCount].params[0] = (int)CORE.Input.Mouse.currentWheelMove;
6584
- events[eventCount].params[1] = 0;
6852
+ events[eventCount].params[0] = (int)CORE.Input.Mouse.currentWheelMove.x;
6853
+ events[eventCount].params[1] = (int)CORE.Input.Mouse.currentWheelMove.y;;
6585
6854
  events[eventCount].params[2] = 0;
6586
6855
 
6587
6856
  TRACELOG(LOG_INFO, "[%i] INPUT_MOUSE_WHEEL_MOTION: %i, %i, %i", events[eventCount].frame, events[eventCount].params[0], events[eventCount].params[1], events[eventCount].params[2]);
@@ -6733,7 +7002,11 @@ static void PlayAutomationEvent(unsigned int frame)
6733
7002
  CORE.Input.Mouse.currentPosition.x = (float)events[i].params[0];
6734
7003
  CORE.Input.Mouse.currentPosition.y = (float)events[i].params[1];
6735
7004
  } break;
6736
- case INPUT_MOUSE_WHEEL_MOTION: CORE.Input.Mouse.currentWheelMove = (float)events[i].params[0]; break; // param[0]: delta
7005
+ case INPUT_MOUSE_WHEEL_MOTION: // param[0]: x delta, param[1]: y delta
7006
+ {
7007
+ CORE.Input.Mouse.currentWheelMove.x = (float)events[i].params[0]; break;
7008
+ CORE.Input.Mouse.currentWheelMove.y = (float)events[i].params[1]; break;
7009
+ } break;
6737
7010
  case INPUT_TOUCH_UP: CORE.Input.Touch.currentTouchState[events[i].params[0]] = false; break; // param[0]: id
6738
7011
  case INPUT_TOUCH_DOWN: CORE.Input.Touch.currentTouchState[events[i].params[0]] = true; break; // param[0]: id
6739
7012
  case INPUT_TOUCH_POSITION: // param[0]: id, param[1]: x, param[2]: y
@@ -6770,3 +7043,34 @@ static void PlayAutomationEvent(unsigned int frame)
6770
7043
  }
6771
7044
  }
6772
7045
  #endif
7046
+
7047
+ #if !defined(SUPPORT_MODULE_RTEXT)
7048
+ // Formatting of text with variables to 'embed'
7049
+ // WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
7050
+ const char *TextFormat(const char *text, ...)
7051
+ {
7052
+ #ifndef MAX_TEXTFORMAT_BUFFERS
7053
+ #define MAX_TEXTFORMAT_BUFFERS 4 // Maximum number of static buffers for text formatting
7054
+ #endif
7055
+ #ifndef MAX_TEXT_BUFFER_LENGTH
7056
+ #define MAX_TEXT_BUFFER_LENGTH 1024 // Maximum size of static text buffer
7057
+ #endif
7058
+
7059
+ // We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
7060
+ static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
7061
+ static int index = 0;
7062
+
7063
+ char *currentBuffer = buffers[index];
7064
+ memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
7065
+
7066
+ va_list args;
7067
+ va_start(args, text);
7068
+ vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
7069
+ va_end(args);
7070
+
7071
+ index += 1; // Move to next buffer for next function call
7072
+ if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
7073
+
7074
+ return currentBuffer;
7075
+ }
7076
+ #endif // !SUPPORT_MODULE_RTEXT