ruby2d 0.12.0 → 1.0.0

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 (619) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +7 -0
  3. data/README.md +141 -0
  4. data/USAGE.md +2435 -0
  5. data/assets/Rakefile +637 -0
  6. data/assets/build_support/CMakeLists.txt +94 -0
  7. data/assets/build_support/mruby/build_config.rb +34 -0
  8. data/assets/build_support/mruby/build_config_wasm.rb +30 -0
  9. data/assets/build_support/sdl_test.c +174 -0
  10. data/assets/deps.yaml +16 -0
  11. data/assets/platform/include/SDL3/SDL.h +91 -0
  12. data/assets/platform/include/SDL3/SDL_assert.h +705 -0
  13. data/assets/platform/include/SDL3/SDL_asyncio.h +550 -0
  14. data/assets/platform/include/SDL3/SDL_atomic.h +692 -0
  15. data/assets/platform/include/SDL3/SDL_audio.h +2370 -0
  16. data/assets/platform/include/SDL3/SDL_begin_code.h +553 -0
  17. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_bits.h +47 -27
  18. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_blendmode.h +59 -55
  19. data/assets/platform/include/SDL3/SDL_camera.h +535 -0
  20. data/assets/platform/include/SDL3/SDL_clipboard.h +331 -0
  21. data/assets/{include/SDL2/close_code.h → platform/include/SDL3/SDL_close_code.h} +9 -8
  22. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_copying.h +3 -1
  23. data/assets/platform/include/SDL3/SDL_cpuinfo.h +374 -0
  24. data/assets/platform/include/SDL3/SDL_dialog.h +343 -0
  25. data/assets/platform/include/SDL3/SDL_dlopennote.h +234 -0
  26. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_egl.h +11 -8
  27. data/assets/platform/include/SDL3/SDL_endian.h +645 -0
  28. data/assets/platform/include/SDL3/SDL_error.h +226 -0
  29. data/assets/platform/include/SDL3/SDL_events.h +1645 -0
  30. data/assets/platform/include/SDL3/SDL_filesystem.h +537 -0
  31. data/assets/platform/include/SDL3/SDL_gamepad.h +1656 -0
  32. data/assets/platform/include/SDL3/SDL_gpu.h +4608 -0
  33. data/assets/platform/include/SDL3/SDL_guid.h +106 -0
  34. data/assets/platform/include/SDL3/SDL_haptic.h +1461 -0
  35. data/assets/platform/include/SDL3/SDL_hidapi.h +571 -0
  36. data/assets/platform/include/SDL3/SDL_hints.h +5001 -0
  37. data/assets/platform/include/SDL3/SDL_init.h +507 -0
  38. data/assets/platform/include/SDL3/SDL_intrin.h +410 -0
  39. data/assets/platform/include/SDL3/SDL_iostream.h +1379 -0
  40. data/assets/platform/include/SDL3/SDL_joystick.h +1385 -0
  41. data/assets/platform/include/SDL3/SDL_keyboard.h +608 -0
  42. data/assets/platform/include/SDL3/SDL_keycode.h +347 -0
  43. data/assets/platform/include/SDL3/SDL_loadso.h +145 -0
  44. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_locale.h +40 -24
  45. data/assets/platform/include/SDL3/SDL_log.h +541 -0
  46. data/assets/platform/include/SDL3/SDL_main.h +704 -0
  47. data/assets/platform/include/SDL3/SDL_main_impl.h +151 -0
  48. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_messagebox.h +85 -48
  49. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_metal.h +29 -29
  50. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_misc.h +13 -12
  51. data/assets/platform/include/SDL3/SDL_mouse.h +813 -0
  52. data/assets/platform/include/SDL3/SDL_mutex.h +1117 -0
  53. data/assets/platform/include/SDL3/SDL_oldnames.h +1339 -0
  54. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengl.h +1247 -278
  55. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengl_glext.h +5 -1
  56. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles.h +6 -7
  57. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2.h +10 -11
  58. data/assets/platform/include/SDL3/SDL_pen.h +198 -0
  59. data/assets/platform/include/SDL3/SDL_pixels.h +1441 -0
  60. data/assets/{include/SDL2/SDL_test_log.h → platform/include/SDL3/SDL_platform.h} +25 -26
  61. data/assets/platform/include/SDL3/SDL_platform_defines.h +497 -0
  62. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_power.h +40 -20
  63. data/assets/platform/include/SDL3/SDL_process.h +441 -0
  64. data/assets/platform/include/SDL3/SDL_properties.h +572 -0
  65. data/assets/platform/include/SDL3/SDL_rect.h +528 -0
  66. data/assets/platform/include/SDL3/SDL_render.h +3028 -0
  67. data/assets/platform/include/SDL3/SDL_revision.h +59 -0
  68. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_scancode.h +59 -68
  69. data/assets/platform/include/SDL3/SDL_sensor.h +321 -0
  70. data/assets/platform/include/SDL3/SDL_stdinc.h +6186 -0
  71. data/assets/platform/include/SDL3/SDL_storage.h +686 -0
  72. data/assets/platform/include/SDL3/SDL_surface.h +1769 -0
  73. data/assets/platform/include/SDL3/SDL_system.h +840 -0
  74. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test.h +16 -22
  75. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_assert.h +27 -34
  76. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_common.h +109 -52
  77. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_compare.h +22 -14
  78. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_crc32.h +27 -30
  79. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_font.h +50 -49
  80. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_fuzzer.h +64 -79
  81. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_harness.h +47 -30
  82. data/assets/platform/include/SDL3/SDL_test_log.h +83 -0
  83. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_md5.h +21 -28
  84. data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_memory.h +19 -16
  85. data/assets/platform/include/SDL3/SDL_thread.h +602 -0
  86. data/assets/platform/include/SDL3/SDL_time.h +249 -0
  87. data/assets/platform/include/SDL3/SDL_timer.h +454 -0
  88. data/assets/platform/include/SDL3/SDL_touch.h +184 -0
  89. data/assets/platform/include/SDL3/SDL_tray.h +544 -0
  90. data/assets/platform/include/SDL3/SDL_version.h +198 -0
  91. data/assets/platform/include/SDL3/SDL_video.h +3497 -0
  92. data/assets/platform/include/SDL3/SDL_vulkan.h +287 -0
  93. data/assets/platform/include/SDL3_image/SDL_image.h +3328 -0
  94. data/assets/platform/include/SDL3_mixer/SDL_mixer.h +3369 -0
  95. data/assets/platform/include/SDL3_ttf/SDL_textengine.h +181 -0
  96. data/assets/platform/include/SDL3_ttf/SDL_ttf.h +2833 -0
  97. data/assets/{include → platform/include}/mrbconf.h +42 -31
  98. data/assets/{include → platform/include}/mruby/array.h +3 -4
  99. data/assets/{include → platform/include}/mruby/boxing_nan.h +10 -0
  100. data/assets/platform/include/mruby/boxing_no.h +59 -0
  101. data/assets/{include → platform/include}/mruby/boxing_word.h +72 -26
  102. data/assets/platform/include/mruby/class.h +157 -0
  103. data/assets/{include → platform/include}/mruby/common.h +30 -1
  104. data/assets/{include → platform/include}/mruby/compile.h +52 -74
  105. data/assets/{include → platform/include}/mruby/data.h +2 -2
  106. data/assets/{include → platform/include}/mruby/debug.h +12 -5
  107. data/assets/{include → platform/include}/mruby/dump.h +7 -9
  108. data/assets/{include → platform/include}/mruby/endian.h +1 -1
  109. data/assets/platform/include/mruby/error.h +173 -0
  110. data/assets/platform/include/mruby/gc.h +79 -0
  111. data/assets/{include → platform/include}/mruby/hash.h +1 -7
  112. data/assets/platform/include/mruby/internal.h +282 -0
  113. data/assets/platform/include/mruby/irep.h +143 -0
  114. data/assets/{include → platform/include}/mruby/istruct.h +1 -1
  115. data/assets/platform/include/mruby/khash.h +455 -0
  116. data/assets/platform/include/mruby/mempool.h +19 -0
  117. data/assets/{include → platform/include}/mruby/numeric.h +7 -10
  118. data/assets/platform/include/mruby/object.h +51 -0
  119. data/assets/{include → platform/include}/mruby/opcode.h +5 -5
  120. data/assets/{include → platform/include}/mruby/ops.h +19 -6
  121. data/assets/platform/include/mruby/presym/id.h +1447 -0
  122. data/assets/{include → platform/include}/mruby/presym/scanning.h +10 -7
  123. data/assets/platform/include/mruby/presym/table.h +2893 -0
  124. data/assets/platform/include/mruby/presym.h +65 -0
  125. data/assets/platform/include/mruby/proc.h +184 -0
  126. data/assets/{include → platform/include}/mruby/range.h +0 -2
  127. data/assets/{include → platform/include}/mruby/string.h +33 -53
  128. data/assets/platform/include/mruby/throw.h +81 -0
  129. data/assets/{include → platform/include}/mruby/value.h +64 -29
  130. data/assets/{include → platform/include}/mruby/variable.h +6 -23
  131. data/assets/{include → platform/include}/mruby/version.h +7 -7
  132. data/assets/{include → platform/include}/mruby.h +238 -116
  133. data/assets/platform/macos-arm64/bin/mrbc +0 -0
  134. data/assets/platform/macos-arm64/lib/libSDL3.a +0 -0
  135. data/assets/platform/macos-arm64/lib/libSDL3_image.a +0 -0
  136. data/assets/platform/macos-arm64/lib/libSDL3_mixer.a +0 -0
  137. data/assets/platform/macos-arm64/lib/libSDL3_ttf.a +0 -0
  138. data/assets/platform/macos-arm64/lib/libmruby.a +0 -0
  139. data/assets/platform/wasm/lib/libFLAC.a +0 -0
  140. data/assets/platform/wasm/lib/libSDL3.a +0 -0
  141. data/assets/platform/wasm/lib/libSDL3_image.a +0 -0
  142. data/assets/platform/wasm/lib/libSDL3_mixer.a +0 -0
  143. data/assets/platform/wasm/lib/libSDL3_ttf.a +0 -0
  144. data/assets/platform/wasm/lib/libfreetype.a +0 -0
  145. data/assets/platform/wasm/lib/libharfbuzz.a +0 -0
  146. data/assets/platform/wasm/lib/libmruby.a +0 -0
  147. data/assets/platform/wasm/lib/libogg.a +0 -0
  148. data/assets/platform/wasm/lib/libplutosvg.a +0 -0
  149. data/assets/platform/wasm/lib/libplutovg.a +0 -0
  150. data/assets/platform/wasm/lib/libpng.a +0 -0
  151. data/assets/platform/wasm/lib/libpng16.a +0 -0
  152. data/assets/platform/wasm/lib/libvorbis.a +0 -0
  153. data/assets/platform/wasm/lib/libvorbisfile.a +0 -0
  154. data/assets/platform/wasm/lib/libzlibstatic.a +0 -0
  155. data/assets/platform/windows-arm64-mingw-ucrt/bin/mrbc.exe +0 -0
  156. data/assets/platform/windows-arm64-mingw-ucrt/lib/libSDL3.a +0 -0
  157. data/assets/platform/windows-arm64-mingw-ucrt/lib/libSDL3_image.a +0 -0
  158. data/assets/platform/windows-arm64-mingw-ucrt/lib/libSDL3_mixer.a +0 -0
  159. data/assets/platform/windows-arm64-mingw-ucrt/lib/libSDL3_ttf.a +0 -0
  160. data/assets/platform/windows-arm64-mingw-ucrt/lib/libmruby.a +0 -0
  161. data/assets/platform/windows-x86_64-mingw-ucrt/bin/mrbc.exe +0 -0
  162. data/assets/platform/windows-x86_64-mingw-ucrt/lib/libSDL3.a +0 -0
  163. data/assets/platform/windows-x86_64-mingw-ucrt/lib/libSDL3_image.a +0 -0
  164. data/assets/platform/windows-x86_64-mingw-ucrt/lib/libSDL3_mixer.a +0 -0
  165. data/assets/platform/windows-x86_64-mingw-ucrt/lib/libSDL3_ttf.a +0 -0
  166. data/assets/platform/windows-x86_64-mingw-ucrt/lib/libmruby.a +0 -0
  167. data/assets/resources/fonts/outfit/OFL.txt +93 -0
  168. data/assets/resources/fonts/outfit/outfit.ttf +0 -0
  169. data/assets/resources/fonts/roboto_mono/OFL.txt +91 -0
  170. data/assets/resources/fonts/roboto_mono/roboto_mono.ttf +0 -0
  171. data/assets/resources/icons/icon.icns +0 -0
  172. data/assets/resources/icons/icon.png +0 -0
  173. data/assets/resources/spritesheets/License.txt +28 -0
  174. data/assets/resources/spritesheets/spritesheet-backgrounds.png +0 -0
  175. data/assets/resources/spritesheets/spritesheet-backgrounds.xml +16 -0
  176. data/assets/resources/spritesheets/spritesheet-characters.png +0 -0
  177. data/assets/resources/spritesheets/spritesheet-characters.xml +47 -0
  178. data/assets/resources/spritesheets/spritesheet-enemies.png +0 -0
  179. data/assets/resources/spritesheets/spritesheet-enemies.xml +62 -0
  180. data/assets/resources/spritesheets/spritesheet-tiles.png +0 -0
  181. data/assets/resources/spritesheets/spritesheet-tiles.xml +316 -0
  182. data/assets/{wasm → resources/web}/template.html +1 -1
  183. data/assets/target.rb +131 -0
  184. data/bin/ruby2d +281 -82
  185. data/examples/astar.rb +269 -0
  186. data/examples/asteroids.rb +403 -0
  187. data/examples/bezier_editor.rb +96 -0
  188. data/examples/boids.rb +191 -0
  189. data/examples/bouncing_balls.rb +119 -0
  190. data/examples/breakout.rb +186 -0
  191. data/examples/constellations.rb +100 -0
  192. data/examples/dashboard.rb +133 -0
  193. data/examples/double_pendulum.rb +254 -0
  194. data/examples/falling_sand.rb +291 -0
  195. data/examples/fireworks.rb +110 -0
  196. data/examples/fluid_dynamics.rb +340 -0
  197. data/examples/fourier_epicycles.rb +142 -0
  198. data/examples/fractal_tree.rb +326 -0
  199. data/examples/game_of_life.rb +148 -0
  200. data/examples/gamepads.rb +333 -0
  201. data/examples/hill_driver.rb +613 -0
  202. data/examples/logo_animation.rb +251 -0
  203. data/examples/lorenz_attractor.rb +115 -0
  204. data/examples/mandelbrot.rb +207 -0
  205. data/examples/marching_squares.rb +200 -0
  206. data/examples/maze.rb +323 -0
  207. data/examples/nbody.rb +338 -0
  208. data/examples/outrun.rb +391 -0
  209. data/examples/pixel_paint.rb +313 -0
  210. data/examples/platformer.rb +335 -0
  211. data/examples/ray_casting_maze.rb +175 -0
  212. data/examples/shadow_casting.rb +151 -0
  213. data/examples/shape_recognizer.rb +908 -0
  214. data/examples/snake.rb +144 -0
  215. data/examples/sprite_sheets.rb +246 -0
  216. data/examples/swarm.rb +206 -0
  217. data/examples/tsp_annealing.rb +104 -0
  218. data/examples/ui_controls.rb +163 -0
  219. data/examples/wireframe_3d.rb +139 -0
  220. data/ext/ruby2d/audio.c +324 -0
  221. data/ext/ruby2d/canvas.c +1715 -494
  222. data/ext/ruby2d/ext.c +541 -0
  223. data/ext/ruby2d/extconf.rb +122 -145
  224. data/ext/ruby2d/font.c +566 -20
  225. data/ext/ruby2d/fps.c +92 -0
  226. data/ext/ruby2d/image.c +466 -41
  227. data/ext/ruby2d/ruby2d.c +374 -1890
  228. data/ext/ruby2d/ruby2d.h +840 -460
  229. data/ext/ruby2d/shapes.c +931 -101
  230. data/ext/ruby2d/text.c +586 -21
  231. data/ext/ruby2d/window.c +1693 -283
  232. data/lib/ruby2d/atlas_parser.rb +194 -0
  233. data/lib/ruby2d/audio.rb +73 -0
  234. data/lib/ruby2d/benchmark.rb +259 -0
  235. data/lib/ruby2d/bitmap_text.rb +155 -0
  236. data/lib/ruby2d/button.rb +402 -0
  237. data/lib/ruby2d/canvas.rb +703 -279
  238. data/lib/ruby2d/circle.rb +206 -29
  239. data/lib/ruby2d/cli/browser.rb +314 -0
  240. data/lib/ruby2d/cli/build.rb +471 -257
  241. data/lib/ruby2d/cli/colorize.rb +7 -5
  242. data/lib/ruby2d/cli/examples.rb +127 -0
  243. data/lib/ruby2d/cli/launch.rb +24 -39
  244. data/lib/ruby2d/cli/lib_files.rb +48 -0
  245. data/lib/ruby2d/cli/messages.rb +40 -0
  246. data/lib/ruby2d/cli/setup.rb +273 -0
  247. data/lib/ruby2d/cli/static_server.rb +160 -0
  248. data/lib/ruby2d/cli/usage.rb +255 -0
  249. data/lib/ruby2d/color.rb +191 -69
  250. data/lib/ruby2d/core.rb +37 -19
  251. data/lib/ruby2d/deps_help.rb +89 -0
  252. data/lib/ruby2d/dsl.rb +51 -12
  253. data/lib/ruby2d/ellipse.rb +228 -0
  254. data/lib/ruby2d/exceptions.rb +0 -2
  255. data/lib/ruby2d/font.rb +34 -74
  256. data/lib/ruby2d/gamepad.rb +323 -0
  257. data/lib/ruby2d/gem_paths.rb +19 -0
  258. data/lib/ruby2d/image.rb +155 -52
  259. data/lib/ruby2d/interactive.rb +103 -0
  260. data/lib/ruby2d/json_parser.rb +268 -0
  261. data/lib/ruby2d/line.rb +194 -85
  262. data/lib/ruby2d/mruby_compat.rb +12 -0
  263. data/lib/ruby2d/polygon.rb +297 -0
  264. data/lib/ruby2d/polyline.rb +368 -0
  265. data/lib/ruby2d/quad.rb +358 -94
  266. data/lib/ruby2d/rectangle.rb +77 -19
  267. data/lib/ruby2d/renderable.rb +411 -11
  268. data/lib/ruby2d/sprite.rb +471 -180
  269. data/lib/ruby2d/sprite_sheet.rb +64 -0
  270. data/lib/ruby2d/square.rb +29 -17
  271. data/lib/ruby2d/text.rb +196 -65
  272. data/lib/ruby2d/tileset.rb +139 -81
  273. data/lib/ruby2d/triangle.rb +324 -89
  274. data/lib/ruby2d/version.rb +1 -3
  275. data/lib/ruby2d/vertices.rb +62 -85
  276. data/lib/ruby2d/warnings.rb +29 -0
  277. data/lib/ruby2d/window/class_methods.rb +218 -0
  278. data/lib/ruby2d/window/gamepad_events.rb +141 -0
  279. data/lib/ruby2d/window/key_events.rb +74 -0
  280. data/lib/ruby2d/window/mouse_events.rb +171 -0
  281. data/lib/ruby2d/window/object_events.rb +168 -0
  282. data/lib/ruby2d/window.rb +632 -585
  283. data/lib/ruby2d.rb +14 -19
  284. metadata +275 -428
  285. data/assets/app.icns +0 -0
  286. data/assets/include/GLES2/gl2.h +0 -656
  287. data/assets/include/GLES2/gl2ext.h +0 -3949
  288. data/assets/include/GLES2/gl2ext_angle.h +0 -701
  289. data/assets/include/GLES2/gl2platform.h +0 -27
  290. data/assets/include/GLES3/gl3.h +0 -1192
  291. data/assets/include/GLES3/gl31.h +0 -1507
  292. data/assets/include/GLES3/gl32.h +0 -1808
  293. data/assets/include/GLES3/gl3platform.h +0 -27
  294. data/assets/include/KHR/khrplatform.h +0 -290
  295. data/assets/include/SDL2/SDL.h +0 -233
  296. data/assets/include/SDL2/SDL_assert.h +0 -326
  297. data/assets/include/SDL2/SDL_atomic.h +0 -415
  298. data/assets/include/SDL2/SDL_audio.h +0 -1500
  299. data/assets/include/SDL2/SDL_clipboard.h +0 -141
  300. data/assets/include/SDL2/SDL_config.h +0 -61
  301. data/assets/include/SDL2/SDL_config_android.h +0 -194
  302. data/assets/include/SDL2/SDL_config_emscripten.h +0 -218
  303. data/assets/include/SDL2/SDL_config_iphoneos.h +0 -217
  304. data/assets/include/SDL2/SDL_config_macosx.h +0 -277
  305. data/assets/include/SDL2/SDL_config_minimal.h +0 -95
  306. data/assets/include/SDL2/SDL_config_ngage.h +0 -89
  307. data/assets/include/SDL2/SDL_config_os2.h +0 -207
  308. data/assets/include/SDL2/SDL_config_pandora.h +0 -141
  309. data/assets/include/SDL2/SDL_config_windows.h +0 -331
  310. data/assets/include/SDL2/SDL_config_wingdk.h +0 -253
  311. data/assets/include/SDL2/SDL_config_winrt.h +0 -220
  312. data/assets/include/SDL2/SDL_config_xbox.h +0 -235
  313. data/assets/include/SDL2/SDL_cpuinfo.h +0 -594
  314. data/assets/include/SDL2/SDL_endian.h +0 -348
  315. data/assets/include/SDL2/SDL_error.h +0 -163
  316. data/assets/include/SDL2/SDL_events.h +0 -1166
  317. data/assets/include/SDL2/SDL_filesystem.h +0 -149
  318. data/assets/include/SDL2/SDL_gamecontroller.h +0 -1074
  319. data/assets/include/SDL2/SDL_gesture.h +0 -117
  320. data/assets/include/SDL2/SDL_guid.h +0 -100
  321. data/assets/include/SDL2/SDL_haptic.h +0 -1341
  322. data/assets/include/SDL2/SDL_hidapi.h +0 -451
  323. data/assets/include/SDL2/SDL_hints.h +0 -2569
  324. data/assets/include/SDL2/SDL_image.h +0 -2173
  325. data/assets/include/SDL2/SDL_joystick.h +0 -1066
  326. data/assets/include/SDL2/SDL_keyboard.h +0 -353
  327. data/assets/include/SDL2/SDL_keycode.h +0 -358
  328. data/assets/include/SDL2/SDL_loadso.h +0 -115
  329. data/assets/include/SDL2/SDL_log.h +0 -404
  330. data/assets/include/SDL2/SDL_main.h +0 -275
  331. data/assets/include/SDL2/SDL_mixer.h +0 -2784
  332. data/assets/include/SDL2/SDL_mouse.h +0 -465
  333. data/assets/include/SDL2/SDL_mutex.h +0 -471
  334. data/assets/include/SDL2/SDL_name.h +0 -33
  335. data/assets/include/SDL2/SDL_pixels.h +0 -644
  336. data/assets/include/SDL2/SDL_platform.h +0 -261
  337. data/assets/include/SDL2/SDL_quit.h +0 -58
  338. data/assets/include/SDL2/SDL_rect.h +0 -376
  339. data/assets/include/SDL2/SDL_render.h +0 -1919
  340. data/assets/include/SDL2/SDL_revision.h +0 -6
  341. data/assets/include/SDL2/SDL_rwops.h +0 -841
  342. data/assets/include/SDL2/SDL_sensor.h +0 -322
  343. data/assets/include/SDL2/SDL_shape.h +0 -155
  344. data/assets/include/SDL2/SDL_stdinc.h +0 -830
  345. data/assets/include/SDL2/SDL_surface.h +0 -997
  346. data/assets/include/SDL2/SDL_system.h +0 -623
  347. data/assets/include/SDL2/SDL_syswm.h +0 -386
  348. data/assets/include/SDL2/SDL_test_images.h +0 -78
  349. data/assets/include/SDL2/SDL_test_random.h +0 -115
  350. data/assets/include/SDL2/SDL_thread.h +0 -464
  351. data/assets/include/SDL2/SDL_timer.h +0 -222
  352. data/assets/include/SDL2/SDL_touch.h +0 -150
  353. data/assets/include/SDL2/SDL_ttf.h +0 -2316
  354. data/assets/include/SDL2/SDL_types.h +0 -29
  355. data/assets/include/SDL2/SDL_version.h +0 -204
  356. data/assets/include/SDL2/SDL_video.h +0 -2150
  357. data/assets/include/SDL2/SDL_vulkan.h +0 -215
  358. data/assets/include/SDL2/begin_code.h +0 -187
  359. data/assets/include/mruby/boxing_no.h +0 -58
  360. data/assets/include/mruby/class.h +0 -108
  361. data/assets/include/mruby/error.h +0 -147
  362. data/assets/include/mruby/gc.h +0 -94
  363. data/assets/include/mruby/irep.h +0 -147
  364. data/assets/include/mruby/khash.h +0 -284
  365. data/assets/include/mruby/object.h +0 -43
  366. data/assets/include/mruby/presym/disable.h +0 -70
  367. data/assets/include/mruby/presym/enable.h +0 -37
  368. data/assets/include/mruby/presym.h +0 -40
  369. data/assets/include/mruby/proc.h +0 -211
  370. data/assets/include/mruby/throw.h +0 -66
  371. data/assets/macos/universal/bin/mrbc +0 -0
  372. data/assets/macos/universal/lib/libFLAC.a +0 -0
  373. data/assets/macos/universal/lib/libSDL2.a +0 -0
  374. data/assets/macos/universal/lib/libSDL2_image.a +0 -0
  375. data/assets/macos/universal/lib/libSDL2_mixer.a +0 -0
  376. data/assets/macos/universal/lib/libSDL2_ttf.a +0 -0
  377. data/assets/macos/universal/lib/libavif.a +0 -0
  378. data/assets/macos/universal/lib/libbrotlicommon-static.a +0 -0
  379. data/assets/macos/universal/lib/libbrotlidec-static.a +0 -0
  380. data/assets/macos/universal/lib/libfreetype.a +0 -0
  381. data/assets/macos/universal/lib/libgraphite2.a +0 -0
  382. data/assets/macos/universal/lib/libharfbuzz.a +0 -0
  383. data/assets/macos/universal/lib/libhwy.a +0 -0
  384. data/assets/macos/universal/lib/libjpeg.a +0 -0
  385. data/assets/macos/universal/lib/libjxl.a +0 -0
  386. data/assets/macos/universal/lib/libmodplug.a +0 -0
  387. data/assets/macos/universal/lib/libmpg123.a +0 -0
  388. data/assets/macos/universal/lib/libmruby.a +0 -0
  389. data/assets/macos/universal/lib/libogg.a +0 -0
  390. data/assets/macos/universal/lib/libpng.a +0 -0
  391. data/assets/macos/universal/lib/libtiff.a +0 -0
  392. data/assets/macos/universal/lib/libvorbis.a +0 -0
  393. data/assets/macos/universal/lib/libvorbisfile.a +0 -0
  394. data/assets/macos/universal/lib/libwebp.a +0 -0
  395. data/assets/macos/universal/lib/libzstd.a +0 -0
  396. data/assets/test_media/README.md +0 -3
  397. data/assets/test_media/bitstream_vera/COPYRIGHT.txt +0 -124
  398. data/assets/test_media/bitstream_vera/vera.ttf +0 -0
  399. data/assets/test_media/boom.png +0 -0
  400. data/assets/test_media/coin.png +0 -0
  401. data/assets/test_media/colors.png +0 -0
  402. data/assets/test_media/controller.png +0 -0
  403. data/assets/test_media/dial.wav +0 -0
  404. data/assets/test_media/hero.png +0 -0
  405. data/assets/test_media/image.bmp +0 -0
  406. data/assets/test_media/image.jpg +0 -0
  407. data/assets/test_media/image.png +0 -0
  408. data/assets/test_media/music.flac +0 -0
  409. data/assets/test_media/music.mp3 +0 -0
  410. data/assets/test_media/music.ogg +0 -0
  411. data/assets/test_media/music.wav +0 -0
  412. data/assets/test_media/originals/boom.pxm +0 -0
  413. data/assets/test_media/originals/coin.pxm +0 -0
  414. data/assets/test_media/originals/controller.sketch +0 -0
  415. data/assets/test_media/originals/hero.pxm +0 -0
  416. data/assets/test_media/originals/image.pxm +0 -0
  417. data/assets/test_media/originals/music.caf +0 -0
  418. data/assets/test_media/originals/texture_atlas.pxm +0 -0
  419. data/assets/test_media/rondo_alla_turka.ogg +0 -0
  420. data/assets/test_media/sound.flac +0 -0
  421. data/assets/test_media/sound.mp3 +0 -0
  422. data/assets/test_media/sound.ogg +0 -0
  423. data/assets/test_media/sound.wav +0 -0
  424. data/assets/test_media/sprite_sheet.png +0 -0
  425. data/assets/test_media/texture_atlas.png +0 -0
  426. data/assets/wasm/libmruby.a +0 -0
  427. data/assets/windows/mingw-w64-ucrt-x86_64/bin/mrbc.exe +0 -0
  428. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libFLAC.a +0 -0
  429. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libLerc.a +0 -0
  430. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libSDL2.a +0 -0
  431. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libSDL2_image.a +0 -0
  432. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libSDL2_mixer.a +0 -0
  433. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libSDL2_ttf.a +0 -0
  434. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libbrotlicommon.a +0 -0
  435. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libbrotlidec.a +0 -0
  436. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libbz2.a +0 -0
  437. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libdeflate.a +0 -0
  438. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libfreetype.a +0 -0
  439. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libglew32.a +0 -0
  440. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libgraphite2.a +0 -0
  441. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libharfbuzz.a +0 -0
  442. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libhwy.a +0 -0
  443. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libjbig.a +0 -0
  444. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libjpeg.a +0 -0
  445. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libjxl.a +0 -0
  446. data/assets/windows/mingw-w64-ucrt-x86_64/lib/liblzma.a +0 -0
  447. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libmodplug.a +0 -0
  448. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libmpg123.a +0 -0
  449. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libmruby.a +0 -0
  450. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libogg.a +0 -0
  451. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libopus.a +0 -0
  452. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libopusfile.a +0 -0
  453. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libpng.a +0 -0
  454. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libsndfile.a +0 -0
  455. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libssp.a +0 -1
  456. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libstdc++.a +0 -0
  457. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libtiff.a +0 -0
  458. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libvorbis.a +0 -0
  459. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libvorbisfile.a +0 -0
  460. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libwebp.a +0 -0
  461. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libz.a +0 -0
  462. data/assets/windows/mingw-w64-ucrt-x86_64/lib/libzstd.a +0 -0
  463. data/assets/windows/mingw-w64-x86_64/bin/mrbc.exe +0 -0
  464. data/assets/windows/mingw-w64-x86_64/lib/libFLAC.a +0 -0
  465. data/assets/windows/mingw-w64-x86_64/lib/libLerc.a +0 -0
  466. data/assets/windows/mingw-w64-x86_64/lib/libSDL2.a +0 -0
  467. data/assets/windows/mingw-w64-x86_64/lib/libSDL2_image.a +0 -0
  468. data/assets/windows/mingw-w64-x86_64/lib/libSDL2_mixer.a +0 -0
  469. data/assets/windows/mingw-w64-x86_64/lib/libSDL2_ttf.a +0 -0
  470. data/assets/windows/mingw-w64-x86_64/lib/libbrotlicommon.a +0 -0
  471. data/assets/windows/mingw-w64-x86_64/lib/libbrotlidec.a +0 -0
  472. data/assets/windows/mingw-w64-x86_64/lib/libbz2.a +0 -0
  473. data/assets/windows/mingw-w64-x86_64/lib/libdeflate.a +0 -0
  474. data/assets/windows/mingw-w64-x86_64/lib/libfreetype.a +0 -0
  475. data/assets/windows/mingw-w64-x86_64/lib/libglew32.a +0 -0
  476. data/assets/windows/mingw-w64-x86_64/lib/libgraphite2.a +0 -0
  477. data/assets/windows/mingw-w64-x86_64/lib/libharfbuzz.a +0 -0
  478. data/assets/windows/mingw-w64-x86_64/lib/libhwy.a +0 -0
  479. data/assets/windows/mingw-w64-x86_64/lib/libjbig.a +0 -0
  480. data/assets/windows/mingw-w64-x86_64/lib/libjpeg.a +0 -0
  481. data/assets/windows/mingw-w64-x86_64/lib/libjxl.a +0 -0
  482. data/assets/windows/mingw-w64-x86_64/lib/liblzma.a +0 -0
  483. data/assets/windows/mingw-w64-x86_64/lib/libmodplug.a +0 -0
  484. data/assets/windows/mingw-w64-x86_64/lib/libmpg123.a +0 -0
  485. data/assets/windows/mingw-w64-x86_64/lib/libmruby.a +0 -0
  486. data/assets/windows/mingw-w64-x86_64/lib/libogg.a +0 -0
  487. data/assets/windows/mingw-w64-x86_64/lib/libopus.a +0 -0
  488. data/assets/windows/mingw-w64-x86_64/lib/libopusfile.a +0 -0
  489. data/assets/windows/mingw-w64-x86_64/lib/libpng.a +0 -0
  490. data/assets/windows/mingw-w64-x86_64/lib/libsndfile.a +0 -0
  491. data/assets/windows/mingw-w64-x86_64/lib/libssp.a +0 -1
  492. data/assets/windows/mingw-w64-x86_64/lib/libstdc++.a +0 -0
  493. data/assets/windows/mingw-w64-x86_64/lib/libtiff.a +0 -0
  494. data/assets/windows/mingw-w64-x86_64/lib/libvorbis.a +0 -0
  495. data/assets/windows/mingw-w64-x86_64/lib/libvorbisfile.a +0 -0
  496. data/assets/windows/mingw-w64-x86_64/lib/libwebp.a +0 -0
  497. data/assets/windows/mingw-w64-x86_64/lib/libz.a +0 -0
  498. data/assets/windows/mingw-w64-x86_64/lib/libzstd.a +0 -0
  499. data/assets/xcode/ios/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -98
  500. data/assets/xcode/ios/Assets.xcassets/Contents.json +0 -6
  501. data/assets/xcode/ios/Base.lproj/LaunchScreen.storyboard +0 -27
  502. data/assets/xcode/ios/Info.plist +0 -43
  503. data/assets/xcode/ios/MRuby.framework/Headers/mrbconf.h +0 -143
  504. data/assets/xcode/ios/MRuby.framework/Headers/mruby/array.h +0 -280
  505. data/assets/xcode/ios/MRuby.framework/Headers/mruby/boxing_nan.h +0 -102
  506. data/assets/xcode/ios/MRuby.framework/Headers/mruby/boxing_no.h +0 -56
  507. data/assets/xcode/ios/MRuby.framework/Headers/mruby/boxing_word.h +0 -144
  508. data/assets/xcode/ios/MRuby.framework/Headers/mruby/class.h +0 -97
  509. data/assets/xcode/ios/MRuby.framework/Headers/mruby/common.h +0 -77
  510. data/assets/xcode/ios/MRuby.framework/Headers/mruby/compile.h +0 -195
  511. data/assets/xcode/ios/MRuby.framework/Headers/mruby/data.h +0 -75
  512. data/assets/xcode/ios/MRuby.framework/Headers/mruby/debug.h +0 -67
  513. data/assets/xcode/ios/MRuby.framework/Headers/mruby/dump.h +0 -196
  514. data/assets/xcode/ios/MRuby.framework/Headers/mruby/error.h +0 -75
  515. data/assets/xcode/ios/MRuby.framework/Headers/mruby/gc.h +0 -91
  516. data/assets/xcode/ios/MRuby.framework/Headers/mruby/hash.h +0 -215
  517. data/assets/xcode/ios/MRuby.framework/Headers/mruby/irep.h +0 -75
  518. data/assets/xcode/ios/MRuby.framework/Headers/mruby/istruct.h +0 -47
  519. data/assets/xcode/ios/MRuby.framework/Headers/mruby/khash.h +0 -274
  520. data/assets/xcode/ios/MRuby.framework/Headers/mruby/numeric.h +0 -161
  521. data/assets/xcode/ios/MRuby.framework/Headers/mruby/object.h +0 -44
  522. data/assets/xcode/ios/MRuby.framework/Headers/mruby/opcode.h +0 -69
  523. data/assets/xcode/ios/MRuby.framework/Headers/mruby/ops.h +0 -117
  524. data/assets/xcode/ios/MRuby.framework/Headers/mruby/proc.h +0 -131
  525. data/assets/xcode/ios/MRuby.framework/Headers/mruby/range.h +0 -49
  526. data/assets/xcode/ios/MRuby.framework/Headers/mruby/re.h +0 -16
  527. data/assets/xcode/ios/MRuby.framework/Headers/mruby/string.h +0 -444
  528. data/assets/xcode/ios/MRuby.framework/Headers/mruby/throw.h +0 -55
  529. data/assets/xcode/ios/MRuby.framework/Headers/mruby/value.h +0 -309
  530. data/assets/xcode/ios/MRuby.framework/Headers/mruby/variable.h +0 -136
  531. data/assets/xcode/ios/MRuby.framework/Headers/mruby/version.h +0 -110
  532. data/assets/xcode/ios/MRuby.framework/Headers/mruby.h +0 -1282
  533. data/assets/xcode/ios/MRuby.framework/Info.plist +0 -20
  534. data/assets/xcode/ios/MRuby.framework/MRuby +0 -0
  535. data/assets/xcode/ios/MyApp.xcodeproj/project.pbxproj +0 -368
  536. data/assets/xcode/ios/MyApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  537. data/assets/xcode/ios/MyApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  538. data/assets/xcode/ios/MyApp.xcodeproj/project.xcworkspace/xcshareddata/MyApp.xcscmblueprint +0 -30
  539. data/assets/xcode/ios/main.c +0 -1
  540. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json +0 -16
  541. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json +0 -6
  542. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json +0 -17
  543. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json +0 -16
  544. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json +0 -6
  545. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json +0 -16
  546. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json +0 -6
  547. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json +0 -16
  548. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json +0 -6
  549. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json +0 -17
  550. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json +0 -16
  551. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json +0 -6
  552. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json +0 -16
  553. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json +0 -6
  554. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json +0 -32
  555. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json +0 -16
  556. data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json +0 -16
  557. data/assets/xcode/tvos/Assets.xcassets/Contents.json +0 -6
  558. data/assets/xcode/tvos/Assets.xcassets/LaunchImage.launchimage/Contents.json +0 -22
  559. data/assets/xcode/tvos/Info.plist +0 -30
  560. data/assets/xcode/tvos/MRuby.framework/Headers/mrbconf.h +0 -143
  561. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/array.h +0 -280
  562. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/boxing_nan.h +0 -102
  563. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/boxing_no.h +0 -56
  564. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/boxing_word.h +0 -144
  565. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/class.h +0 -97
  566. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/common.h +0 -77
  567. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/compile.h +0 -195
  568. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/data.h +0 -75
  569. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/debug.h +0 -67
  570. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/dump.h +0 -196
  571. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/error.h +0 -75
  572. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/gc.h +0 -91
  573. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/hash.h +0 -215
  574. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/irep.h +0 -75
  575. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/istruct.h +0 -47
  576. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/khash.h +0 -274
  577. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/numeric.h +0 -161
  578. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/object.h +0 -44
  579. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/opcode.h +0 -69
  580. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/ops.h +0 -117
  581. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/proc.h +0 -131
  582. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/range.h +0 -49
  583. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/re.h +0 -16
  584. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/string.h +0 -444
  585. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/throw.h +0 -55
  586. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/value.h +0 -309
  587. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/variable.h +0 -136
  588. data/assets/xcode/tvos/MRuby.framework/Headers/mruby/version.h +0 -110
  589. data/assets/xcode/tvos/MRuby.framework/Headers/mruby.h +0 -1282
  590. data/assets/xcode/tvos/MRuby.framework/Info.plist +0 -20
  591. data/assets/xcode/tvos/MRuby.framework/MRuby +0 -0
  592. data/assets/xcode/tvos/MyApp.xcodeproj/project.pbxproj +0 -350
  593. data/assets/xcode/tvos/MyApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  594. data/assets/xcode/tvos/MyApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  595. data/assets/xcode/tvos/MyApp.xcodeproj/project.xcworkspace/xcshareddata/MyApp.xcscmblueprint +0 -30
  596. data/assets/xcode/tvos/main.c +0 -1
  597. data/ext/ruby2d/common.c +0 -185
  598. data/ext/ruby2d/controllers.c +0 -110
  599. data/ext/ruby2d/gl.c +0 -398
  600. data/ext/ruby2d/gl2.c +0 -86
  601. data/ext/ruby2d/gl3.c +0 -304
  602. data/ext/ruby2d/gles.c +0 -302
  603. data/ext/ruby2d/input.c +0 -48
  604. data/ext/ruby2d/music.c +0 -127
  605. data/ext/ruby2d/sound.c +0 -132
  606. data/lib/ruby2d/cli/console.rb +0 -65
  607. data/lib/ruby2d/cli/enable_console.rb +0 -7
  608. data/lib/ruby2d/cli/platform.rb +0 -17
  609. data/lib/ruby2d/music.rb +0 -77
  610. data/lib/ruby2d/pixel.rb +0 -18
  611. data/lib/ruby2d/pixmap.rb +0 -39
  612. data/lib/ruby2d/pixmap_atlas.rb +0 -56
  613. data/lib/ruby2d/sound.rb +0 -61
  614. data/lib/ruby2d/texture.rb +0 -38
  615. /data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2_gl2.h +0 -0
  616. /data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2_gl2ext.h +0 -0
  617. /data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2_gl2platform.h +0 -0
  618. /data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2_khrplatform.h +0 -0
  619. /data/assets/{include → platform/include}/mruby/re.h +0 -0
data/ext/ruby2d/ruby2d.c CHANGED
@@ -1,1875 +1,493 @@
1
1
  // Native C extension for Ruby and MRuby
2
2
 
3
- #ifndef RUBY2D_IOS_TVOS
4
- #define RUBY2D_IOS_TVOS 0
5
- #endif
3
+ #include "ruby2d.h"
6
4
 
7
- // Ruby 2D includes
8
- #if RUBY2D_IOS_TVOS
9
- #else
10
- #include <ruby2d.h>
11
- #endif
12
5
 
13
- // Ruby includes
14
- #if MRUBY
15
- #include <mruby.h>
16
- #include <mruby/array.h>
17
- #include <mruby/string.h>
18
- #include <mruby/variable.h>
19
- #include <mruby/numeric.h>
20
- #include <mruby/data.h>
21
- #include <mruby/irep.h>
22
- #else
23
- #include <ruby.h>
24
- #endif
6
+ // =============================================================================
7
+ // Global Variables
8
+ // =============================================================================
25
9
 
26
- // Define Ruby type conversions in MRuby
27
- #if MRUBY
28
- // C to MRuby types
29
- #define INT2FIX(val) (mrb_fixnum_value(val))
30
- #define INT2NUM(val) (mrb_fixnum_value((mrb_int)(val)))
31
- #define UINT2NUM(val) (INT2NUM((unsigned mrb_int)(val)))
32
- #define LL2NUM(val) (INT2NUM(val))
33
- #define ULL2NUM(val) (INT2NUM((unsigned __int64)(val)))
34
- #define DBL2NUM(val) (mrb_float_value(mrb, (mrb_float)(val)))
35
- // MRuby to C types
36
- #define TO_PDT(val) ((mrb_type(val) == MRB_TT_FLOAT) ? mrb_float(val) : mrb_int(mrb, (val)))
37
- #define FIX2INT(val) (mrb_fixnum(val))
38
- #define NUM2INT(val) ((mrb_int)TO_PDT(val))
39
- #define NUM2UINT(val) ((unsigned mrb_int)TO_PDT(val))
40
- #define NUM2LONG(val) (mrb_int(mrb, (val)))
41
- #define NUM2LL(val) ((__int64)(TO_PDT(val)))
42
- #define NUM2ULL(val) ((unsigned __int64)(TO_PDT(val)))
43
- #define NUM2DBL(val) (mrb_to_flo(mrb, (val)))
44
- #define NUM2CHR(val) ((mrb_string_p(val) && (RSTRING_LEN(val)>=1)) ? RSTRING_PTR(val)[0] : (char)(NUM2INT(val) & 0xff))
45
- // Memory management
46
- #define ALLOC(type) ((type *)mrb_malloc(mrb, sizeof(type)))
47
- #define ALLOC_N(type, n) ((type *)mrb_malloc(mrb, sizeof(type) * (n)))
48
- #define ALLOCA_N(type, n) ((type *)alloca(sizeof(type) * (n)))
49
- #define MEMCMP(p1, p2, type, n) (memcmp((p1), (p2), sizeof(type)*(n)))
50
- #endif
10
+ // Initialize shared data
11
+ bool R2D_diagnostics = false;
51
12
 
52
- // Define common types and API calls, mapping to both Ruby and MRuby APIs
53
- #if MRUBY
54
- // MRuby
55
- #define R_VAL mrb_value
56
- #define R_NIL (mrb_nil_value())
57
- #define R_TRUE (mrb_true_value())
58
- #define R_FALSE (mrb_false_value())
59
- #define R_CLASS struct RClass *
60
- #define r_iv_get(self, var) mrb_iv_get(mrb, self, mrb_intern_lit(mrb, var))
61
- #define r_iv_set(self, var, val) mrb_iv_set(mrb, self, mrb_intern_lit(mrb, var), val)
62
- #define r_funcall(self, method, num_args, ...) mrb_funcall(mrb, self, method, num_args, ##__VA_ARGS__)
63
- #define r_str_new(str) mrb_str_new(mrb, str, strlen(str))
64
- #define r_test(val) (mrb_test(val) == true)
65
- #define r_ary_entry(ary, pos) mrb_ary_entry(ary, pos)
66
- #define r_ary_new() mrb_ary_new(mrb)
67
- #define r_ary_push(self, val) mrb_ary_push(mrb, self, val)
68
- #define r_data_wrap_struct(name, data) mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &name##_data_type, data))
69
- #define r_data_get_struct(self, var, mrb_type, rb_type, data) Data_Get_Struct(mrb, r_iv_get(self, var), mrb_type, data)
70
- #define r_define_module(name) mrb_define_module(mrb, name)
71
- #define r_define_class(module, name) mrb_define_class_under(mrb, module, name, mrb->object_class)
72
- #define r_define_method(class, name, function, args) mrb_define_method(mrb, class, name, function, args)
73
- #define r_define_class_method(class, name, function, args) mrb_define_class_method(mrb, class, name, function, args)
74
- #define r_args_none (MRB_ARGS_NONE())
75
- #define r_args_req(n) MRB_ARGS_REQ(n)
76
- // Helpers
77
- #define r_char_to_sym(str) mrb_symbol_value(mrb_intern_cstr(mrb, str))
78
- #else
79
- // Ruby
80
- #define R_VAL VALUE
81
- #define R_NIL Qnil
82
- #define R_TRUE Qtrue
83
- #define R_FALSE Qfalse
84
- #define R_CLASS R_VAL
85
- #define r_iv_get(self, var) rb_iv_get(self, var)
86
- #define r_iv_set(self, var, val) rb_iv_set(self, var, val)
87
- #define r_funcall(self, method, num_args, ...) rb_funcall(self, rb_intern(method), num_args, ##__VA_ARGS__)
88
- #define r_str_new(str) rb_str_new2(str)
89
- #define r_test(val) (val != Qfalse && val != Qnil)
90
- #define r_ary_entry(ary, pos) rb_ary_entry(ary, pos)
91
- #define r_ary_new() rb_ary_new()
92
- #define r_ary_push(self, val) rb_ary_push(self, val)
93
- #define r_ary_len(self) rb_ary_len(self)
94
- #define r_data_wrap_struct(name, data) Data_Wrap_Struct(rb_cObject, NULL, (free_##name), data)
95
- #define r_data_get_struct(self, var, mrb_type, rb_type, data) Data_Get_Struct(r_iv_get(self, var), rb_type, data)
96
- #define r_define_module(name) rb_define_module(name)
97
- #define r_define_class(module, name) rb_define_class_under(module, name, rb_cObject)
98
- #define r_define_method(class, name, function, args) rb_define_method(class, name, function, args)
99
- #define r_define_class_method(class, name, function, args) rb_define_singleton_method(class, name, function, args)
100
- #define r_args_none 0
101
- #define r_args_req(n) n
102
- // Helpers
103
- #define r_char_to_sym(str) ID2SYM(rb_intern(str))
104
- #endif
13
+ // Initialization status
14
+ static bool initted = false;
105
15
 
106
- // Create the MRuby context
107
- #if MRUBY
16
+ // MRuby context
17
+ #ifdef MRUBY
108
18
  static mrb_state *mrb;
109
19
  #endif
110
20
 
111
- // Ruby 2D interpreter window
112
- static R_VAL ruby2d_window;
113
-
114
- // Ruby 2D native window
115
- static R2D_Window *ruby2d_c_window;
116
-
117
-
118
- // Method signatures and structures for Ruby 2D classes
119
- #if MRUBY
120
- static void free_sound(mrb_state *mrb, void *p_);
121
- static const struct mrb_data_type sound_data_type = {
122
- "sound", free_sound
123
- };
124
- static void free_music(mrb_state *mrb, void *p_);
125
- static const struct mrb_data_type music_data_type = {
126
- "music", free_music
127
- };
128
- static void free_font(mrb_state *mrb, void *p_);
129
- static const struct mrb_data_type font_data_type = {
130
- "font", free_font
131
- };
132
- static void free_surface(mrb_state *mrb, void *p_);
133
- static const struct mrb_data_type surface_data_type = {
134
- "surface", free_surface
135
- };
136
- static void free_sdl_texture(mrb_state *mrb, void *p_);
137
- static const struct mrb_data_type sdl_texture_data_type = {
138
- "sdl_texture", free_sdl_texture
139
- };
140
- static void free_renderer(mrb_state *mrb, void *p_);
141
- static const struct mrb_data_type renderer_data_type = {
142
- "renderer", free_renderer
143
- };
144
- #else
145
- static void free_sound(R2D_Sound *snd);
146
- static void free_music(R2D_Music *mus);
147
- static void free_font(TTF_Font *font);
148
- static void free_surface(SDL_Surface *surface);
149
- static void free_sdl_texture(SDL_Texture *surface);
150
- static void free_renderer(SDL_Renderer *renderer);
151
- #endif
152
-
153
-
154
- /*
155
- * Function pointer to free the Ruby 2D native window
156
- */
157
- static void free_window() {
158
- R2D_FreeWindow(ruby2d_c_window);
159
- }
160
21
 
22
+ // Pre-window display info — populated by R2D_Init, consumed by window_create
23
+ static float r2d_init_content_scale = 1.0f;
24
+ static float r2d_init_display_scale = 1.0f;
25
+ static float r2d_init_refresh_rate = 60.0f;
26
+ static int r2d_init_display_width = 0;
27
+ static int r2d_init_display_height = 0;
28
+ static int r2d_init_display_pixel_width = 0;
29
+ static int r2d_init_display_pixel_height = 0;
161
30
 
162
- /*
163
- * Normalize controller axis values to 0.0...1.0
164
- */
165
- double normalize_controller_axis(int val) {
166
- return val > 0 ? val / 32767.0 : val / 32768.0;
167
- }
31
+ float R2D_GetInitDisplayScale(void) { return r2d_init_display_scale; }
32
+ float R2D_GetInitContentScale(void) { return r2d_init_content_scale; }
33
+ float R2D_GetInitRefreshRate(void) { return r2d_init_refresh_rate; }
34
+ int R2D_GetInitDisplayWidth(void) { return r2d_init_display_width; }
35
+ int R2D_GetInitDisplayHeight(void) { return r2d_init_display_height; }
36
+ int R2D_GetInitDisplayPixelWidth(void) { return r2d_init_display_pixel_width; }
37
+ int R2D_GetInitDisplayPixelHeight(void) { return r2d_init_display_pixel_height; }
168
38
 
39
+ // Ruby 2D module
40
+ R_CLASS ruby2d_module;
169
41
 
170
- /*
171
- * Ruby2D#self.ext_base_path
172
- */
173
- #if MRUBY
174
- static R_VAL ruby2d_ext_base_path(mrb_state* mrb, R_VAL self) {
175
- #else
176
- static R_VAL ruby2d_ext_base_path(R_VAL self) {
177
- #endif
178
- return r_str_new(SDL_GetBasePath());
179
- }
180
42
 
43
+ // =============================================================================
44
+ // Platform-Specific Code
45
+ // =============================================================================
181
46
 
182
47
  /*
183
- * Ruby2D::Pixel#self.ext_draw
48
+ * Provide a `vasprintf()` implementation for Windows
184
49
  */
185
- #if MRUBY
186
- static R_VAL ruby2d_pixel_ext_draw(mrb_state* mrb, R_VAL self) {
187
- mrb_value a;
188
- mrb_get_args(mrb, "o", &a);
189
- #else
190
- static R_VAL ruby2d_pixel_ext_draw(R_VAL self, R_VAL a) {
191
- #endif
192
- // `a` is the array representing the pixel
193
-
194
- R2D_DrawQuad(
195
- NUM2DBL(r_ary_entry(a, 0)), // x1
196
- NUM2DBL(r_ary_entry(a, 1)), // y1
197
- NUM2DBL(r_ary_entry(a, 8)), // color
198
- NUM2DBL(r_ary_entry(a, 9)), // color
199
- NUM2DBL(r_ary_entry(a, 10)), // color
200
- NUM2DBL(r_ary_entry(a, 11)), // color
201
-
202
- NUM2DBL(r_ary_entry(a, 2)), // x2
203
- NUM2DBL(r_ary_entry(a, 3)), // y2
204
- NUM2DBL(r_ary_entry(a, 8)), // color
205
- NUM2DBL(r_ary_entry(a, 9)), // color
206
- NUM2DBL(r_ary_entry(a, 10)), // color
207
- NUM2DBL(r_ary_entry(a, 11)), // color
208
-
209
- NUM2DBL(r_ary_entry(a, 4)), // x3
210
- NUM2DBL(r_ary_entry(a, 5)), // y3
211
- NUM2DBL(r_ary_entry(a, 8)), // color
212
- NUM2DBL(r_ary_entry(a, 9)), // color
213
- NUM2DBL(r_ary_entry(a, 10)), // color
214
- NUM2DBL(r_ary_entry(a, 11)), // color
215
-
216
- NUM2DBL(r_ary_entry(a, 6)), // x4
217
- NUM2DBL(r_ary_entry(a, 7)), // y4
218
- NUM2DBL(r_ary_entry(a, 8)), // color
219
- NUM2DBL(r_ary_entry(a, 9)), // color
220
- NUM2DBL(r_ary_entry(a, 10)), // color
221
- NUM2DBL(r_ary_entry(a, 11)) // color
222
- );
223
-
224
- return R_NIL;
225
- }
226
-
227
-
228
- /*
229
- * Ruby2D::Triangle#self.ext_draw
230
- */
231
- #if MRUBY
232
- static R_VAL ruby2d_triangle_ext_draw(mrb_state* mrb, R_VAL self) {
233
- mrb_value a;
234
- mrb_get_args(mrb, "o", &a);
235
- #else
236
- static R_VAL ruby2d_triangle_ext_draw(R_VAL self, R_VAL a) {
237
- #endif
238
- // `a` is the array representing the triangle
239
-
240
- R2D_DrawTriangle(
241
- NUM2DBL(r_ary_entry(a, 0)), // x1
242
- NUM2DBL(r_ary_entry(a, 1)), // y1
243
- NUM2DBL(r_ary_entry(a, 2)), // c1 red
244
- NUM2DBL(r_ary_entry(a, 3)), // c1 green
245
- NUM2DBL(r_ary_entry(a, 4)), // c1 blue
246
- NUM2DBL(r_ary_entry(a, 5)), // c1 alpha
247
-
248
- NUM2DBL(r_ary_entry(a, 6)), // x2
249
- NUM2DBL(r_ary_entry(a, 7)), // y2
250
- NUM2DBL(r_ary_entry(a, 8)), // c2 red
251
- NUM2DBL(r_ary_entry(a, 9)), // c2 green
252
- NUM2DBL(r_ary_entry(a, 10)), // c2 blue
253
- NUM2DBL(r_ary_entry(a, 11)), // c2 alpha
254
-
255
- NUM2DBL(r_ary_entry(a, 12)), // x3
256
- NUM2DBL(r_ary_entry(a, 13)), // y3
257
- NUM2DBL(r_ary_entry(a, 14)), // c3 red
258
- NUM2DBL(r_ary_entry(a, 15)), // c3 green
259
- NUM2DBL(r_ary_entry(a, 16)), // c3 blue
260
- NUM2DBL(r_ary_entry(a, 17)) // c3 alpha
261
- );
262
-
263
- return R_NIL;
50
+ #ifdef _WIN32
51
+ int vasprintf(char **strp, const char *fmt, va_list ap) {
52
+ int r = -1, size = _vscprintf(fmt, ap);
53
+ if ((size >= 0) && (size < INT_MAX)) {
54
+ *strp = (char *)malloc(size + 1);
55
+ if (*strp) {
56
+ r = vsnprintf(*strp, size + 1, fmt, ap);
57
+ if (r == -1) { free(*strp); *strp = 0; }
58
+ }
59
+ } else { *strp = 0; }
60
+ return(r);
264
61
  }
265
-
266
-
267
- /*
268
- * Ruby2D::Quad#self.ext_draw
269
- */
270
- #if MRUBY
271
- static R_VAL ruby2d_quad_ext_draw(mrb_state* mrb, R_VAL self) {
272
- mrb_value a;
273
- mrb_get_args(mrb, "o", &a);
274
- #else
275
- static R_VAL ruby2d_quad_ext_draw(R_VAL self, R_VAL a) {
276
62
  #endif
277
- // `a` is the array representing the quad
278
-
279
- R2D_DrawQuad(
280
- NUM2DBL(r_ary_entry(a, 0)), // x1
281
- NUM2DBL(r_ary_entry(a, 1)), // y1
282
- NUM2DBL(r_ary_entry(a, 2)), // c1 red
283
- NUM2DBL(r_ary_entry(a, 3)), // c1 green
284
- NUM2DBL(r_ary_entry(a, 4)), // c1 blue
285
- NUM2DBL(r_ary_entry(a, 5)), // c1 alpha
286
-
287
- NUM2DBL(r_ary_entry(a, 6)), // x2
288
- NUM2DBL(r_ary_entry(a, 7)), // y2
289
- NUM2DBL(r_ary_entry(a, 8)), // c2 red
290
- NUM2DBL(r_ary_entry(a, 9)), // c2 green
291
- NUM2DBL(r_ary_entry(a, 10)), // c2 blue
292
- NUM2DBL(r_ary_entry(a, 11)), // c2 alpha
293
-
294
- NUM2DBL(r_ary_entry(a, 12)), // x3
295
- NUM2DBL(r_ary_entry(a, 13)), // y3
296
- NUM2DBL(r_ary_entry(a, 14)), // c3 red
297
- NUM2DBL(r_ary_entry(a, 15)), // c3 green
298
- NUM2DBL(r_ary_entry(a, 16)), // c3 blue
299
- NUM2DBL(r_ary_entry(a, 17)), // c3 alpha
300
-
301
- NUM2DBL(r_ary_entry(a, 18)), // x4
302
- NUM2DBL(r_ary_entry(a, 19)), // y4
303
- NUM2DBL(r_ary_entry(a, 20)), // c4 red
304
- NUM2DBL(r_ary_entry(a, 21)), // c4 green
305
- NUM2DBL(r_ary_entry(a, 22)), // c4 blue
306
- NUM2DBL(r_ary_entry(a, 23)) // c4 alpha
307
- );
308
-
309
- return R_NIL;
310
- }
311
63
 
312
64
 
313
- /*
314
- * Ruby2D::Line#self.ext_draw
315
- */
316
- #if MRUBY
317
- static R_VAL ruby2d_line_ext_draw(mrb_state* mrb, R_VAL self) {
318
- mrb_value a;
319
- mrb_get_args(mrb, "o", &a);
320
- #else
321
- static R_VAL ruby2d_line_ext_draw(R_VAL self, R_VAL a) {
322
- #endif
323
- // `a` is the array representing the line
324
-
325
- R2D_DrawLine(
326
- NUM2DBL(r_ary_entry(a, 0)), // x1
327
- NUM2DBL(r_ary_entry(a, 1)), // y1
328
- NUM2DBL(r_ary_entry(a, 2)), // x2
329
- NUM2DBL(r_ary_entry(a, 3)), // y2
330
- NUM2DBL(r_ary_entry(a, 4)), // width
331
-
332
- NUM2DBL(r_ary_entry(a, 5)), // c1 red
333
- NUM2DBL(r_ary_entry(a, 6)), // c1 green
334
- NUM2DBL(r_ary_entry(a, 7)), // c1 blue
335
- NUM2DBL(r_ary_entry(a, 8)), // c1 alpha
336
-
337
- NUM2DBL(r_ary_entry(a, 9)), // c2 red
338
- NUM2DBL(r_ary_entry(a, 10)), // c2 green
339
- NUM2DBL(r_ary_entry(a, 11)), // c2 blue
340
- NUM2DBL(r_ary_entry(a, 12)), // c2 alpha
341
-
342
- NUM2DBL(r_ary_entry(a, 13)), // c3 red
343
- NUM2DBL(r_ary_entry(a, 14)), // c3 green
344
- NUM2DBL(r_ary_entry(a, 15)), // c3 blue
345
- NUM2DBL(r_ary_entry(a, 16)), // c3 alpha
346
-
347
- NUM2DBL(r_ary_entry(a, 17)), // c4 red
348
- NUM2DBL(r_ary_entry(a, 18)), // c4 green
349
- NUM2DBL(r_ary_entry(a, 19)), // c4 blue
350
- NUM2DBL(r_ary_entry(a, 20)) // c4 alpha
351
- );
352
-
353
- return R_NIL;
354
- }
355
-
65
+ // =============================================================================
66
+ // Utility Functions
67
+ // =============================================================================
356
68
 
357
69
  /*
358
- * Ruby2D::Circle#self.ext_draw
70
+ * Checks if a file exists and can be accessed
359
71
  */
360
- #if MRUBY
361
- static R_VAL ruby2d_circle_ext_draw(mrb_state* mrb, R_VAL self) {
362
- mrb_value a;
363
- mrb_get_args(mrb, "o", &a);
364
- #else
365
- static R_VAL ruby2d_circle_ext_draw(R_VAL self, R_VAL a) {
366
- #endif
367
- // `a` is the array representing the circle
368
-
369
- R2D_DrawCircle(
370
- NUM2DBL(r_ary_entry(a, 0)), // x
371
- NUM2DBL(r_ary_entry(a, 1)), // y
372
- NUM2DBL(r_ary_entry(a, 2)), // radius
373
- NUM2DBL(r_ary_entry(a, 3)), // sectors
374
- NUM2DBL(r_ary_entry(a, 4)), // red
375
- NUM2DBL(r_ary_entry(a, 5)), // green
376
- NUM2DBL(r_ary_entry(a, 6)), // blue
377
- NUM2DBL(r_ary_entry(a, 7)) // alpha
378
- );
379
-
380
- return R_NIL;
381
- }
382
-
383
-
384
- /*
385
- * Ruby2D::Pixmap#ext_load_pixmap
386
- * Create an SDL surface from an image path, and ...
387
- * TODO: store the surface, width, and height in the object
388
- */
389
- #if MRUBY
390
- static R_VAL ruby2d_pixmap_ext_load_pixmap(mrb_state* mrb, R_VAL self) {
391
- mrb_value path;
392
- mrb_get_args(mrb, "o", &path);
393
- #else
394
- static R_VAL ruby2d_pixmap_ext_load_pixmap(R_VAL self, R_VAL path) {
395
- #endif
396
- R2D_Init();
72
+ bool R2D_FileExists(const char *path) {
73
+ if (!path) return false;
397
74
 
398
- SDL_Surface *surface = R2D_CreateImageSurface(RSTRING_PTR(path));
399
- // initialize for later use
400
- r_iv_set(self, "@ext_sdl_texture", R_NIL);
401
-
402
- if (surface != NULL) {
403
- #if GLES
404
- // OpenGL ES doesn't support BGR color order, so applying the
405
- // conversion to the pixels. This will however render incorrect colours
406
- // for BGR images when using Canvas.
407
- // TODO: A better solution one day?
408
- R2D_ImageConvertToRGB(surface);
409
- #endif
410
-
411
- r_iv_set(self, "@ext_pixel_data", r_data_wrap_struct(surface, surface));
412
- r_iv_set(self, "@width", INT2NUM(surface->w));
413
- r_iv_set(self, "@height", INT2NUM(surface->h));
414
- }
415
- else {
416
- // TODO: consider raising an exception?
417
- // for docs: https://silverhammermba.github.io/emberb/c/#raise
418
- r_iv_set(self, "@ext_pixel_data", R_NIL);
419
- r_iv_set(self, "@width", INT2NUM(0));
420
- r_iv_set(self, "@height", INT2NUM(0));
421
- }
422
- return R_NIL;
75
+ return access(path, F_OK) != -1;
423
76
  }
424
77
 
425
- /*
426
- * Ruby2D::Text#ext_load_text
427
- */
428
- #if MRUBY
429
- static R_VAL ruby2d_text_ext_load_text(mrb_state* mrb, R_VAL self) {
430
- mrb_value font, message;
431
- mrb_get_args(mrb, "oo", &font, &message);
432
- #else
433
- static R_VAL ruby2d_text_ext_load_text(R_VAL self, R_VAL font, R_VAL message) {
434
- #endif
435
- R2D_Init();
436
-
437
- R_VAL result = r_ary_new();
438
-
439
- TTF_Font *ttf_font;
440
-
441
- #if MRUBY
442
- Data_Get_Struct(mrb, font, &font_data_type, ttf_font);
443
- #else
444
- Data_Get_Struct(font, TTF_Font, ttf_font);
445
- #endif
446
-
447
- SDL_Surface *surface = R2D_TextCreateSurface(ttf_font, RSTRING_PTR(message));
448
- if (!surface) {
449
- return result;
450
- }
451
-
452
- r_ary_push(result, r_data_wrap_struct(surface, surface));
453
- r_ary_push(result, INT2NUM(surface->w));
454
- r_ary_push(result, INT2NUM(surface->h));
455
-
456
- return result;
457
- }
458
78
 
459
79
  /*
460
- * Ruby2D::Canvas#ext_draw_pixmap
80
+ * Logs standard messages to the console
461
81
  */
462
- #if MRUBY
463
- static R_VAL ruby2d_canvas_ext_draw_pixmap(mrb_state* mrb, R_VAL self) {
464
- mrb_value pixmap, src_rect, x, y, w, h;
465
- mrb_get_args(mrb, "oooooo", &pixmap, &src_rect, &x, &y, &w, &h);
466
- #else
467
- static R_VAL ruby2d_canvas_ext_draw_pixmap(R_VAL self, R_VAL pixmap, R_VAL src_rect, R_VAL x, R_VAL y, R_VAL w, R_VAL h) {
468
- #endif
469
-
470
- if (r_test(pixmap)) {
471
- // Retrieve pixmap's external pixel data (SDL_Surface)
472
- SDL_Surface *pix_surface;
473
- r_data_get_struct(pixmap, "@ext_pixel_data", &surface_data_type, SDL_Surface, pix_surface);
82
+ void R2D_Log(int type, const char *msg, ...) {
474
83
 
475
- SDL_Texture *pix_sdl_tex = NULL;
476
- R_VAL pix_ext_sdl_tex = r_iv_get(pixmap, "@ext_sdl_texture");
477
- if (r_test(pix_ext_sdl_tex)) {
478
- r_data_get_struct(pixmap, "@ext_sdl_texture", &sdl_texture_data_type, SDL_Texture, pix_sdl_tex);
479
- }
84
+ // Always log if diagnostics set, or if a warning or error message
85
+ if (R2D_diagnostics || type != R2D_INFO) {
480
86
 
481
- SDL_Renderer *render;
482
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
87
+ va_list args;
88
+ va_start(args, msg);
483
89
 
484
- if (pix_sdl_tex == NULL) {
485
- // create and cache an SDL_Texture for this Pixmap
486
- pix_sdl_tex = SDL_CreateTextureFromSurface(render, pix_surface);
487
- if (pix_sdl_tex != NULL) {
488
- r_iv_set(pixmap, "@ext_sdl_texture", r_data_wrap_struct(sdl_texture, pix_sdl_tex));
489
- }
490
- else printf("*** Unable to create SDL_Texture: %s\n", SDL_GetError());
90
+ switch (type) {
91
+ case R2D_INFO:
92
+ fprintf(stderr, "\033[1;34m[INFO]\033[0m ");
93
+ break;
94
+ case R2D_WARN:
95
+ fprintf(stderr, "\033[1;33m[WARN]\033[0m ");
96
+ break;
97
+ case R2D_ERROR:
98
+ fprintf(stderr, "\033[1;31m[ERROR]\033[0m ");
99
+ break;
491
100
  }
492
101
 
493
- // Draw if we have an SDL_Texture
494
- if (pix_sdl_tex != NULL) {
495
- SDL_bool src_set = SDL_FALSE;
496
- SDL_Rect src;
497
- if (r_test(src_rect)) {
498
- src_set = SDL_TRUE;
499
- // portion of pixmap
500
- src = (SDL_Rect) {
501
- .x = NUM2INT(r_ary_entry(src_rect, 0)),
502
- .y = NUM2INT(r_ary_entry(src_rect, 1)),
503
- .w = NUM2INT(r_ary_entry(src_rect, 2)),
504
- .h = NUM2INT(r_ary_entry(src_rect, 3))
505
- };
506
- }
507
- else {
508
- // whole pixmap
509
- src = (SDL_Rect){ .x = 0, .y = 0, .w = pix_surface->w, .h = pix_surface->h };
510
- }
511
- // use incoming size or source size or fallback to pixmap size
512
- int pix_w = r_test(w) ? NUM2INT(w) : (src_set ? src.w : NUM2INT(r_iv_get(pixmap, "@width")));
513
- int pix_h = r_test(h) ? NUM2INT(h) : (src_set ? src.h : NUM2INT(r_iv_get(pixmap, "@height")));
514
-
515
- SDL_Rect dst = { .x = NUM2INT(x), .y = NUM2INT(y), .w = pix_w, .h = pix_h };
516
- SDL_RenderCopy (render, pix_sdl_tex, &src, &dst);
517
- }
102
+ vfprintf(stderr, msg, args);
103
+ fprintf(stderr, "\n");
104
+ va_end(args);
518
105
  }
519
- return R_NIL;
520
106
  }
521
107
 
522
108
 
523
109
  /*
524
- * Ruby2D::Texture#ext_create
110
+ * Warn once per process if an SDL render call reported failure. The draw path
111
+ * calls these every frame, so a persistent GPU/driver fault would flood the
112
+ * console — this emits a single diagnostic instead of silently rendering
113
+ * nothing. `what` names the SDL function; the SDL error string is appended.
525
114
  */
526
- #if MRUBY
527
- static R_VAL ruby2d_texture_ext_create(mrb_state* mrb, R_VAL self) {
528
- mrb_value rubySurface, width, height;
529
- mrb_get_args(mrb, "ooo", &rubySurface, &width, &height);
530
- #else
531
- static R_VAL ruby2d_texture_ext_create(R_VAL self, R_VAL rubySurface, R_VAL width, R_VAL height) {
532
- #endif
533
- GLuint texture_id = 0;
534
- SDL_Surface *surface;
535
-
536
- #if MRUBY
537
- Data_Get_Struct(mrb, rubySurface, &surface_data_type, surface);
538
- #else
539
- Data_Get_Struct(rubySurface, SDL_Surface, surface);
540
- #endif
541
-
542
- // Detect image mode
543
- GLint gl_internal_format, gl_format;
544
- GLenum gl_type;
545
-
546
- switch (surface->format->BytesPerPixel) {
547
- case 4:
548
- #if GLES
549
- gl_internal_format = gl_format = GL_RGBA;
550
- #else
551
- gl_internal_format = GL_RGBA;
552
- gl_format = (surface->format->Rmask == 0xff0000) ? GL_BGRA : GL_RGBA;
553
- #endif
554
- gl_type = GL_UNSIGNED_BYTE;
555
- break;
556
- case 3:
557
- #if GLES
558
- gl_internal_format = gl_format = GL_RGB;
559
- #else
560
- gl_internal_format = GL_RGB;
561
- gl_format = (surface->format->Rmask == 0xff0000) ? GL_BGR : GL_RGB;
562
- #endif
563
- gl_type = GL_UNSIGNED_BYTE;
564
- break;
565
- case 2:
566
- gl_internal_format = gl_format = GL_RGB;
567
- gl_type = GL_UNSIGNED_SHORT_5_6_5;
568
- break;
569
- case 1:
570
- default:
571
- // this would be ideal for font glyphs which use luminance + alpha and colour
572
- // is set when drawing
573
- gl_internal_format = gl_format = GL_LUMINANCE_ALPHA;
574
- gl_type = GL_UNSIGNED_BYTE;
575
- break;
115
+ void R2D_CheckSDL(bool ok, const char *what) {
116
+ static bool warned = false;
117
+ if (!ok && !warned) {
118
+ R2D_Log(R2D_WARN, "%s failed: %s", what, SDL_GetError());
119
+ warned = true;
576
120
  }
577
- R2D_GL_CreateTexture(&texture_id, gl_internal_format, gl_format, gl_type,
578
- NUM2INT(width), NUM2INT(height),
579
- surface->pixels, GL_NEAREST);
580
-
581
- return INT2NUM(texture_id);
582
121
  }
583
122
 
123
+
584
124
  /*
585
- * Ruby2D::Texture#ext_delete
125
+ * Logs Ruby 2D errors to the console, with caller and message body
586
126
  */
587
- #if MRUBY
588
- static R_VAL ruby2d_texture_ext_delete(mrb_state* mrb, R_VAL self) {
589
- mrb_value rubyTexture_id;
590
- mrb_get_args(mrb, "o", &rubyTexture_id);
591
- #else
592
- static R_VAL ruby2d_texture_ext_delete(R_VAL self, R_VAL rubyTexture_id) {
593
- #endif
594
- GLuint texture_id = NUM2INT(rubyTexture_id);
127
+ void R2D_Error(const char *caller, const char *msg, ...) {
128
+ va_list args;
129
+ va_start(args, msg);
130
+ char *fmsg = NULL;
131
+ int len = vasprintf(&fmsg, msg, args);
132
+ va_end(args);
595
133
 
596
- R2D_GL_FreeTexture(&texture_id);
597
-
598
- return R_NIL;
134
+ // On failure vasprintf leaves fmsg undefined; fall back to the raw format
135
+ // string rather than log/free a garbage pointer while reporting an error.
136
+ if (len >= 0 && fmsg) {
137
+ R2D_Log(R2D_ERROR, "(%s) %s", caller, fmsg);
138
+ free(fmsg);
139
+ } else {
140
+ R2D_Log(R2D_ERROR, "(%s) %s", caller, msg);
141
+ }
599
142
  }
600
143
 
601
144
 
602
145
  /*
603
- * Ruby2D::Canvas#ext_create
146
+ * Enable/disable logging of diagnostics
604
147
  */
605
- #if MRUBY
606
- static R_VAL ruby2d_canvas_ext_create(mrb_state* mrb, R_VAL self) {
607
- mrb_value a;
608
- mrb_get_args(mrb, "o", &a);
609
- #else
610
- static R_VAL ruby2d_canvas_ext_create(R_VAL self, R_VAL a) {
611
- #endif
612
- SDL_Surface *surf = SDL_CreateRGBSurface(
613
- 0, NUM2INT(r_ary_entry(a, 0)), NUM2INT(r_ary_entry(a, 1)),
614
- 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
615
- );
616
-
617
- SDL_Renderer *render = SDL_CreateSoftwareRenderer(surf);
618
-
619
- SDL_SetRenderDrawColor(render,
620
- NUM2DBL(r_ary_entry(a, 2)) * 255, // r
621
- NUM2DBL(r_ary_entry(a, 3)) * 255, // g
622
- NUM2DBL(r_ary_entry(a, 4)) * 255, // b
623
- NUM2DBL(r_ary_entry(a, 5)) * 255 // a
624
- );
625
- SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE);
626
- SDL_RenderClear(render);
627
-
628
- SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND);
629
- SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND);
630
-
631
- r_iv_set(self, "@ext_pixel_data", r_data_wrap_struct(surface, surf));
632
- r_iv_set(self, "@ext_renderer", r_data_wrap_struct(renderer, render));
633
- return R_NIL;
148
+ void R2D_Diagnostics(bool status) {
149
+ R2D_diagnostics = status;
150
+ R2D_Window *w = R2D_GetWindow();
151
+ if (w) w->diagnostics = status;
634
152
  }
635
153
 
636
- /*
637
- * Ruby2D::Canvas#ext_clear
638
- */
639
- #if MRUBY
640
- static R_VAL ruby2d_canvas_ext_clear(mrb_state* mrb, R_VAL self) {
641
- mrb_value a;
642
- mrb_get_args(mrb, "o", &a);
643
- #else
644
- static R_VAL ruby2d_canvas_ext_clear(R_VAL self, R_VAL a) {
645
- #endif
646
- // `a` is the array representing the colour values
647
-
648
- SDL_Renderer *render;
649
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
650
-
651
- SDL_SetRenderDrawColor(render,
652
- NUM2DBL(r_ary_entry(a, 0)) * 255, // r
653
- NUM2DBL(r_ary_entry(a, 1)) * 255, // g
654
- NUM2DBL(r_ary_entry(a, 2)) * 255, // b
655
- NUM2DBL(r_ary_entry(a, 3)) * 255 // a
656
- );
657
- SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE);
658
- SDL_RenderClear(render);
659
- SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND);
660
-
661
- return R_NIL;
662
- }
663
-
664
- /*
665
- * Ruby2D::Canvas#ext_fill_rectangle
666
- */
667
- #if MRUBY
668
- static R_VAL ruby2d_canvas_ext_fill_rectangle(mrb_state* mrb, R_VAL self) {
669
- mrb_value a;
670
- mrb_get_args(mrb, "o", &a);
671
- #else
672
- static R_VAL ruby2d_canvas_ext_fill_rectangle(R_VAL self, R_VAL a) {
673
- #endif
674
- // `a` is the array representing the rectangle
675
-
676
- SDL_Renderer *render;
677
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
678
-
679
- SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND);
680
-
681
- SDL_Rect rect = { .x = NUM2INT(r_ary_entry(a, 0)),
682
- .y = NUM2INT(r_ary_entry(a, 1)),
683
- .w = NUM2INT(r_ary_entry(a, 2)),
684
- .h = NUM2INT(r_ary_entry(a, 3))
685
- };
686
-
687
- SDL_SetRenderDrawColor(render,
688
- NUM2DBL(r_ary_entry(a, 4)) * 255, // r
689
- NUM2DBL(r_ary_entry(a, 5)) * 255, // g
690
- NUM2DBL(r_ary_entry(a, 6)) * 255, // b
691
- NUM2DBL(r_ary_entry(a, 7)) * 255 // a
692
- );
693
- SDL_RenderFillRect(render, &rect);
694
-
695
- return R_NIL;
696
- }
697
154
 
698
155
  /*
699
- * Ruby2D::Canvas#ext_draw_rectangle
156
+ * Enable/disable FPS display
700
157
  */
701
- #if MRUBY
702
- static R_VAL ruby2d_canvas_ext_draw_rectangle(mrb_state* mrb, R_VAL self) {
703
- mrb_value a;
704
- mrb_get_args(mrb, "o", &a);
705
- #else
706
- static R_VAL ruby2d_canvas_ext_draw_rectangle(R_VAL self, R_VAL a) {
707
- #endif
708
- // `a` is the array representing the rectangle
709
- // 0, 1, 2, 3, 4, 5, 6, 7, 8
710
- // [ x, y, width, height, thickness, r, g, b, a]
711
-
712
- SDL_Renderer *render;
713
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
714
-
715
- int thickness = NUM2INT(r_ary_entry(a, 4));
716
- if (thickness == 1) {
717
- SDL_Rect rect = { .x = NUM2INT(r_ary_entry(a, 0)),
718
- .y = NUM2INT(r_ary_entry(a, 1)),
719
- .w = NUM2INT(r_ary_entry(a, 2)),
720
- .h = NUM2INT(r_ary_entry(a, 3))
721
- };
722
-
723
- SDL_SetRenderDrawColor(render,
724
- NUM2DBL(r_ary_entry(a, 5)) * 255, // r
725
- NUM2DBL(r_ary_entry(a, 6)) * 255, // g
726
- NUM2DBL(r_ary_entry(a, 7)) * 255, // b
727
- NUM2DBL(r_ary_entry(a, 8)) * 255 // a
728
- );
729
- SDL_RenderDrawRect(render, &rect);
730
- }
731
- else if (thickness > 1) {
732
- R2D_Canvas_DrawThickRect(render,
733
- NUM2INT(r_ary_entry(a, 0)), // x
734
- NUM2INT(r_ary_entry(a, 1)), // y
735
- NUM2INT(r_ary_entry(a, 2)), // width
736
- NUM2INT(r_ary_entry(a, 3)), // height
737
- thickness,
738
- NUM2DBL(r_ary_entry(a, 5)) * 255, // r
739
- NUM2DBL(r_ary_entry(a, 6)) * 255, // g
740
- NUM2DBL(r_ary_entry(a, 7)) * 255, // b
741
- NUM2DBL(r_ary_entry(a, 8)) * 255 // a
742
- );
743
- }
744
- return R_NIL;
158
+ void R2D_ShowFPS(bool status) {
159
+ if (R2D_GetWindow()) R2D_GetWindow()->show_fps = status;
745
160
  }
746
161
 
747
- /*
748
- * Ruby2D::Canvas#ext_draw_line
749
- */
750
- #if MRUBY
751
- static R_VAL ruby2d_canvas_ext_draw_line(mrb_state* mrb, R_VAL self) {
752
- mrb_value a;
753
- mrb_get_args(mrb, "o", &a);
754
- #else
755
- static R_VAL ruby2d_canvas_ext_draw_line(R_VAL self, R_VAL a) {
756
- #endif
757
- // `a` is the array representing the line
758
-
759
- SDL_Renderer *render;
760
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
761
-
762
- int thickness = NUM2INT(r_ary_entry(a, 4));
763
- if (thickness == 1) {
764
- // use the SDL_Renderer's draw line for single pixel lines
765
- SDL_SetRenderDrawColor(render,
766
- NUM2DBL(r_ary_entry(a, 5)) * 255, // r
767
- NUM2DBL(r_ary_entry(a, 6)) * 255, // g
768
- NUM2DBL(r_ary_entry(a, 7)) * 255, // b
769
- NUM2DBL(r_ary_entry(a, 8)) * 255 // a
770
- );
771
- SDL_RenderDrawLine(render,
772
- NUM2INT(r_ary_entry(a, 0)), // x1
773
- NUM2INT(r_ary_entry(a, 1)), // y1
774
- NUM2INT(r_ary_entry(a, 2)), // x2
775
- NUM2INT(r_ary_entry(a, 3)) // y2
776
- );
777
- }
778
- else if (thickness > 1) {
779
- // use a custom handler to convert a thick line into a
780
- // quad and draw using SDL_Renderer's geometry renderer
781
- R2D_Canvas_DrawThickLine(render,
782
- NUM2INT(r_ary_entry(a, 0)), // x1
783
- NUM2INT(r_ary_entry(a, 1)), // y1
784
- NUM2INT(r_ary_entry(a, 2)), // x2
785
- NUM2INT(r_ary_entry(a, 3)), // y2
786
- thickness,
787
- NUM2DBL(r_ary_entry(a, 5)) * 255, // r
788
- NUM2DBL(r_ary_entry(a, 6)) * 255, // g
789
- NUM2DBL(r_ary_entry(a, 7)) * 255, // b
790
- NUM2DBL(r_ary_entry(a, 8)) * 255 // a
791
- );
792
- }
793
-
794
- return R_NIL;
795
- }
796
162
 
797
- #define MAX_POLY_POINTS 64
163
+ // =============================================================================
164
+ // Initialization and Cleanup
165
+ // =============================================================================
798
166
 
799
167
  /*
800
- * Ruby2D::Canvas#ext_draw_polyline
168
+ * Initialize Ruby 2D subsystems
801
169
  */
802
- #if MRUBY
803
- static R_VAL ruby2d_canvas_ext_draw_polyline(mrb_state* mrb, R_VAL self) {
804
- mrb_value config, coords;
805
- mrb_get_args(mrb, "oo", &config, &coords);
806
- #else
807
- static R_VAL ruby2d_canvas_ext_draw_polyline(R_VAL self, R_VAL config, R_VAL coords) {
808
- #endif
809
- // `config` is an array
810
- // 0, 1, 2, 3, 4
811
- // [ thickness, r, g, b, a ]
812
- //
813
- // `coords` is an array of x, y values
814
- // 0, 1, 2, 3, ...
815
- // [ x1, y1, x2, y2, ... ]
816
-
817
- SDL_Renderer *render;
818
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
819
-
820
- long coord_count = RARRAY_LEN(coords);
821
- int thickness = NUM2INT(r_ary_entry(config, 0));
822
- if (thickness == 1) {
823
- // use the SDL_Renderer's draw line for single pixel lines
824
- SDL_SetRenderDrawColor(render,
825
- NUM2DBL(r_ary_entry(config, 1)) * 255, // r
826
- NUM2DBL(r_ary_entry(config, 2)) * 255, // g
827
- NUM2DBL(r_ary_entry(config, 3)) * 255, // b
828
- NUM2DBL(r_ary_entry(config, 4)) * 255 // a
829
- );
830
- int x1 = NUM2INT(r_ary_entry(coords, 0));
831
- int y1 = NUM2INT(r_ary_entry(coords, 1));
832
- for (int i = 2; i < coord_count; i+= 2) {
833
- int x2 = NUM2INT(r_ary_entry(coords, i));
834
- int y2 = NUM2INT(r_ary_entry(coords, i+1));
835
- SDL_RenderDrawLine(render, x1, y1, x2, y2);
836
- x1 = x2;
837
- y1 = y2;
838
- }
839
- }
840
- else if (thickness > 1) {
841
- // use a custom handler to convert a thick line into a
842
- // quad and draw using SDL_Renderer's geometry renderer
843
-
844
- SDL_FPoint points[MAX_POLY_POINTS];
845
- int num_points = 0;
846
-
847
- points[num_points++] = (SDL_FPoint) {
848
- .x = NUM2INT(r_ary_entry(coords, 0)),
849
- .y = NUM2INT(r_ary_entry(coords, 1))
850
- };
851
- for (int i = 2; i < coord_count && num_points < MAX_POLY_POINTS; i+= 2) {
852
- points[num_points++] = (SDL_FPoint) {
853
- .x = NUM2INT(r_ary_entry(coords, i)),
854
- .y = NUM2INT(r_ary_entry(coords, i+1)) };
855
- }
856
- R2D_Canvas_DrawThickPolyline(render,
857
- points, num_points,
858
- thickness,
859
- NUM2DBL(r_ary_entry(config, 1)) * 255, // r
860
- NUM2DBL(r_ary_entry(config, 2)) * 255, // g
861
- NUM2DBL(r_ary_entry(config, 3)) * 255, // b
862
- NUM2DBL(r_ary_entry(config, 4)) * 255, // a
863
- false // don't skip first/last
864
- );
865
- }
170
+ bool R2D_Init() {
171
+ if (initted) return true;
866
172
 
867
- return R_NIL;
868
- }
173
+ R2D_Log(R2D_INFO, "Initializing Ruby 2D");
869
174
 
870
- /*
871
- * Ruby2D::Canvas#ext_draw_polygon
872
- */
873
- #if MRUBY
874
- static R_VAL ruby2d_canvas_ext_draw_polygon(mrb_state* mrb, R_VAL self) {
875
- mrb_value config, coords;
876
- mrb_get_args(mrb, "oo", &config, &coords);
877
- #else
878
- static R_VAL ruby2d_canvas_ext_draw_polygon(R_VAL self, R_VAL config, R_VAL coords) {
879
- #endif
880
- // `config` is an array
881
- // 0, 1, 2, 3, 4
882
- // [ thickness, r, g, b, a ]
883
- //
884
- // `coords` is an array of x, y values
885
- // 0, 1, 2, 3, ...
886
- // [ x1, y1, x2, y2, ... ]
887
-
888
- SDL_Renderer *render;
889
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
890
-
891
- long coord_count = RARRAY_LEN(coords);
892
- int thickness = NUM2INT(r_ary_entry(config, 0));
893
- if (thickness == 1) {
894
- // use the SDL_Renderer's draw line for single pixel lines
895
- SDL_SetRenderDrawColor(render,
896
- NUM2DBL(r_ary_entry(config, 1)) * 255, // r
897
- NUM2DBL(r_ary_entry(config, 2)) * 255, // g
898
- NUM2DBL(r_ary_entry(config, 3)) * 255, // b
899
- NUM2DBL(r_ary_entry(config, 4)) * 255 // a
900
- );
901
- int x1 = NUM2INT(r_ary_entry(coords, 0));
902
- int y1 = NUM2INT(r_ary_entry(coords, 1));
903
- for (int i = 2; i < coord_count; i+= 2) {
904
- int x2 = NUM2INT(r_ary_entry(coords, i));
905
- int y2 = NUM2INT(r_ary_entry(coords, i+1));
906
- SDL_RenderDrawLine(render, x1, y1, x2, y2);
907
- x1 = x2;
908
- y1 = y2;
909
- }
910
- // connect back to first point to close the shape
911
- int x2 = NUM2INT(r_ary_entry(coords, 0));
912
- int y2 = NUM2INT(r_ary_entry(coords, 1));
913
- SDL_RenderDrawLine(render, x1, y1, x2, y2);
914
- }
915
- else if (thickness > 1) {
916
- // use a custom handler to convert a thick line into a
917
- // quad and draw using SDL_Renderer's geometry renderer
918
-
919
- SDL_FPoint points[MAX_POLY_POINTS+3]; // three extra slots to points 0, 1, 2
920
- int num_points = 0;
921
-
922
- points[num_points++] = (SDL_FPoint) {
923
- .x = NUM2INT(r_ary_entry(coords, 0)),
924
- .y = NUM2INT(r_ary_entry(coords, 1))
925
- };
926
- for (int i = 2; i < coord_count && num_points < MAX_POLY_POINTS; i+= 2) {
927
- points[num_points++] = (SDL_FPoint) {
928
- .x = NUM2INT(r_ary_entry(coords, i)),
929
- .y = NUM2INT(r_ary_entry(coords, i+1)) };
930
- }
931
- // repeat first three coordinates at the end
932
- points[num_points++] = points[0];
933
- points[num_points++] = points[1];
934
- points[num_points++] = points[2];
935
- // use polyline draw but ask it to skip first and last segments
936
- // since we added three more points at the end, these produce the
937
- // missing segments with proper joins
938
- R2D_Canvas_DrawThickPolyline(render,
939
- points, num_points,
940
- thickness,
941
- NUM2DBL(r_ary_entry(config, 1)) * 255, // r
942
- NUM2DBL(r_ary_entry(config, 2)) * 255, // g
943
- NUM2DBL(r_ary_entry(config, 3)) * 255, // b
944
- NUM2DBL(r_ary_entry(config, 4)) * 255, // a
945
- true // skip first/last segments when drawing the polyline
946
- );
175
+ // Initialize SDL (only needed subsystems)
176
+ if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD)) {
177
+ R2D_Error("SDL_Init", "%s", SDL_GetError());
178
+ return false;
947
179
  }
948
180
 
949
- return R_NIL;
950
- }
181
+ // Initialize SDL_ttf (SDL3 style: returns true on success)
182
+ if (!TTF_Init()) {
183
+ R2D_Error("TTF_Init", "%s", SDL_GetError());
184
+ return false;
185
+ }
951
186
 
952
- /*
953
- * Ruby2D::Canvas#ext_fill_polygon
954
- */
955
- #if MRUBY
956
- static R_VAL ruby2d_canvas_ext_fill_polygon(mrb_state* mrb, R_VAL self) {
957
- mrb_value coords, rgbas;
958
- mrb_get_args(mrb, "oo", &coords, &rgbas);
959
- #else
960
- static R_VAL ruby2d_canvas_ext_fill_polygon(R_VAL self, R_VAL coords, R_VAL rgbas) {
961
- #endif
962
- // `coords` is an array of x, y values
963
- // 0, 1, 2, 3, ...
964
- // [ x1, y1, x2, y2, ... ]
965
- //
966
- // `rgbas` is an array of r, g, b, a values
967
- // 0, 1, 2, 3, 4, 5, 6, 7 ...
968
- // [ r1, g1, b1, a1, r2, g2, b2, a2, ... ]
969
-
970
- SDL_Renderer *render;
971
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
972
-
973
- long coord_len = RARRAY_LEN(coords);
974
- long rgbas_len = RARRAY_LEN(rgbas);
975
-
976
- if (coord_len >= 6 && rgbas_len > 0) {
977
- SDL_FPoint points[MAX_POLY_POINTS];
978
- int num_points = 0;
979
-
980
- SDL_Color colors[MAX_POLY_POINTS];
981
- int num_colors = 0;
982
-
983
- for (int i = 0; i < coord_len && num_points < MAX_POLY_POINTS; i+= 2) {
984
- points[num_points++] = (SDL_FPoint) {
985
- .x = NUM2INT(r_ary_entry(coords, i)),
986
- .y = NUM2INT(r_ary_entry(coords, i+1)) };
187
+ // The audio mixer device is intentionally NOT opened here. Opening the default
188
+ // playback device fails on a headless/audio-blocked machine, and graphics must
189
+ // not depend on that. Audio entry points call R2D_InitAudio() lazily instead.
190
+
191
+ // Get display information (content scale, dimensions). Done early so Text and
192
+ // Image can use it before a window is created. The r2d_init_* statics keep
193
+ // their file-scope defaults until a display is found below.
194
+ int display_count = 0;
195
+ SDL_DisplayID *display_ids = SDL_GetDisplays(&display_count);
196
+ if (display_ids && display_count > 0) {
197
+ const SDL_DisplayMode *mode = SDL_GetCurrentDisplayMode(display_ids[0]);
198
+ if (mode) {
199
+ r2d_init_content_scale = SDL_GetDisplayContentScale(display_ids[0]);
200
+ // SDL returns 0.0f if this query fails; clamp so it can't zero out
201
+ // display_scale or become a divide-by-zero in the resize handler.
202
+ if (r2d_init_content_scale <= 0.0f) r2d_init_content_scale = 1.0f;
203
+ r2d_init_display_scale = mode->pixel_density * r2d_init_content_scale;
204
+ r2d_init_refresh_rate = mode->refresh_rate;
205
+ r2d_init_display_width = mode->w;
206
+ r2d_init_display_height = mode->h;
207
+ r2d_init_display_pixel_width = (int)(mode->w * mode->pixel_density);
208
+ r2d_init_display_pixel_height = (int)(mode->h * mode->pixel_density);
209
+
210
+ R2D_Log(R2D_INFO, "Display (%u of %d)", display_ids[0], display_count);
211
+ R2D_Log(R2D_INFO, " width: %d", mode->w);
212
+ R2D_Log(R2D_INFO, " height: %d", mode->h);
213
+ R2D_Log(R2D_INFO, " pixel_width: %d", r2d_init_display_pixel_width);
214
+ R2D_Log(R2D_INFO, " pixel_height: %d", r2d_init_display_pixel_height);
215
+ R2D_Log(R2D_INFO, " pixel_density: %.2f", mode->pixel_density);
216
+ R2D_Log(R2D_INFO, " content_scale: %.2f", r2d_init_content_scale);
217
+ R2D_Log(R2D_INFO, " display_scale: %.2f", r2d_init_display_scale);
218
+ R2D_Log(R2D_INFO, " refresh_rate: %.2f", mode->refresh_rate);
987
219
  }
988
- for (int i = 0; i < rgbas_len && num_colors < MAX_POLY_POINTS; i+= 4) {
989
- colors[num_colors++] = (SDL_Color) {
990
- .r = NUM2DBL(r_ary_entry(rgbas, i)) * 255, // r
991
- .g = NUM2DBL(r_ary_entry(rgbas, i+1)) * 255, // g
992
- .b = NUM2DBL(r_ary_entry(rgbas, i+2)) * 255, // b
993
- .a = NUM2DBL(r_ary_entry(rgbas, i+3)) * 255 // a
994
- };
995
- }
996
-
997
- R2D_Canvas_FillPolygon(render, points, num_points, colors, num_colors);
220
+ SDL_free(display_ids);
998
221
  }
999
222
 
1000
- return R_NIL;
223
+ // All subsystems initted
224
+ initted = true;
225
+ return true;
1001
226
  }
1002
227
 
1003
- /*
1004
- * Ruby2D::Canvas#self.ext_fill_ellipse
1005
- */
1006
- #if MRUBY
1007
- static R_VAL ruby2d_canvas_ext_fill_ellipse(mrb_state* mrb, R_VAL self) {
1008
- mrb_value a;
1009
- mrb_get_args(mrb, "o", &a);
1010
- #else
1011
- static R_VAL ruby2d_canvas_ext_fill_ellipse(R_VAL self, R_VAL a) {
1012
- #endif
1013
- // `a` is the array representing the filled circle
1014
- // 0 1 2 3 4 5 6 7 8
1015
- // [ x, y, xradius, yradius, sectors, r, g, b, a ]
1016
- SDL_Renderer *render;
1017
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
1018
-
1019
- SDL_Vertex verts[3];
1020
- // center
1021
- float x, y;
1022
- verts[0].position = (SDL_FPoint) {
1023
- .x = x = NUM2INT(r_ary_entry(a, 0)),
1024
- .y = y = NUM2INT(r_ary_entry(a, 1))
1025
- };
1026
- // dimensions
1027
- float xradius = NUM2INT(r_ary_entry(a, 2));
1028
- float yradius = NUM2INT(r_ary_entry(a, 3));
1029
- float sectors = NUM2INT(r_ary_entry(a, 4));
1030
- float unit_angle = 2 * M_PI / sectors;
1031
-
1032
- // colour all vertices
1033
- verts[1].color = verts[2].color = verts[0].color = (SDL_Color) {
1034
- .r = NUM2DBL(r_ary_entry(a, 5)) * 255,
1035
- .g = NUM2DBL(r_ary_entry(a, 6)) * 255,
1036
- .b = NUM2DBL(r_ary_entry(a, 7)) * 255,
1037
- .a = NUM2DBL(r_ary_entry(a, 8)) * 255,
1038
- };
1039
-
1040
- // point at 0 radians
1041
- verts[1].position = (SDL_FPoint) {
1042
- .x = x + xradius * cosf(0),
1043
- .y = y + yradius * sinf(0)
1044
- };
1045
- for (float i = 1; i <= sectors; i++) {
1046
- float angle = i * unit_angle;
1047
- // re-use from previous calculation
1048
- verts[2].position = verts[1].position;
1049
- // calculate new point
1050
- verts[1].position = (SDL_FPoint) {
1051
- .x = x + xradius * cosf(angle),
1052
- .y = y + yradius * sinf(angle)
1053
- };
1054
- SDL_RenderGeometry(render, NULL, verts, 3, NULL, 0);
1055
- }
1056
-
1057
- return R_NIL;
1058
- }
1059
228
 
1060
229
  /*
1061
- * Ruby2D::Canvas#self.ext_draw_ellipse
230
+ * Gets the primary display's dimensions
1062
231
  */
1063
- #if MRUBY
1064
- static R_VAL ruby2d_canvas_ext_draw_ellipse(mrb_state* mrb, R_VAL self) {
1065
- mrb_value a;
1066
- mrb_get_args(mrb, "o", &a);
1067
- #else
1068
- static R_VAL ruby2d_canvas_ext_draw_ellipse(R_VAL self, R_VAL a) {
1069
- #endif
1070
- // `a` is the array representing the ellipse to draw
1071
- // 0 1 2 3 4 5 6 7 8 9
1072
- // [ x, y, xradius, yradius, sectors, thickness, r, g, b, a ]
1073
-
1074
- // thickness
1075
- int thickness = NUM2INT(r_ary_entry(a, 5));
1076
- if (thickness <= 0) return R_NIL;
1077
-
1078
- SDL_Renderer *render;
1079
- r_data_get_struct(self, "@ext_renderer", &renderer_data_type, SDL_Renderer, render);
1080
-
1081
- // center
1082
- float x = NUM2INT(r_ary_entry(a, 0));
1083
- float y = NUM2INT(r_ary_entry(a, 1)) ;
1084
- // dimensions
1085
- float xradius = NUM2INT(r_ary_entry(a, 2));
1086
- float yradius = NUM2INT(r_ary_entry(a, 3));
1087
- float sectors = NUM2INT(r_ary_entry(a, 4));
1088
- // colors
1089
- int clr_r = NUM2DBL(r_ary_entry(a, 6)) * 255;
1090
- int clr_g = NUM2DBL(r_ary_entry(a, 7)) * 255;
1091
- int clr_b = NUM2DBL(r_ary_entry(a, 8)) * 255;
1092
- int clr_a = NUM2DBL(r_ary_entry(a, 9)) * 255;
1093
-
1094
- if (thickness > 1) {
1095
- R2D_Canvas_DrawThickEllipse(render,
1096
- x, y, xradius, yradius, sectors, thickness,
1097
- clr_r, clr_g, clr_b, clr_a);
232
+ void R2D_GetDisplayDimensions(int *w, int *h) {
233
+ R2D_Init();
234
+ int display_count = 0;
235
+ SDL_DisplayID *display_ids = SDL_GetDisplays(&display_count);
236
+ if (!display_ids || display_count < 1) {
237
+ R2D_Error("SDL_GetDisplays", "%s", SDL_GetError());
238
+ *w = 0;
239
+ *h = 0;
240
+ return;
1098
241
  }
1099
- else {
1100
- R2D_Canvas_DrawThinEllipse(render,
1101
- x, y, xradius, yradius, sectors,
1102
- clr_r, clr_g, clr_b, clr_a);
242
+ const SDL_DisplayMode *mode = SDL_GetCurrentDisplayMode(display_ids[0]);
243
+ if (!mode) {
244
+ R2D_Error("SDL_GetCurrentDisplayMode", "%s", SDL_GetError());
245
+ SDL_free(display_ids);
246
+ *w = 0;
247
+ *h = 0;
248
+ return;
1103
249
  }
1104
-
1105
- return R_NIL;
1106
- }
1107
-
1108
- /*
1109
- * Calculate the cross product of the two lines
1110
- * connecting the three points clock-wise. A negative value
1111
- * means the angle "to the right" is > 180.
1112
- */
1113
- /* Unused
1114
- static inline int cross_product_corner(x1, y1, x2, y2, x3, y3) {
1115
- register int vec1_x = x1 - x2;
1116
- register int vec1_y = y1 - y2;
1117
- register int vec2_x = x2 - x3;
1118
- register int vec2_y = y2 - y3;
1119
-
1120
- return (vec1_x * vec2_y) - (vec1_y * vec2_x);
1121
- }
1122
- */
1123
-
1124
- /*
1125
- * Ruby2D::Sound#ext_init
1126
- * Initialize sound structure data
1127
- */
1128
- #if MRUBY
1129
- static R_VAL ruby2d_sound_ext_init(mrb_state* mrb, R_VAL self) {
1130
- mrb_value path;
1131
- mrb_get_args(mrb, "o", &path);
1132
- #else
1133
- static R_VAL ruby2d_sound_ext_init(R_VAL self, R_VAL path) {
1134
- #endif
1135
- R2D_Sound *snd = R2D_CreateSound(RSTRING_PTR(path));
1136
- if (!snd) return R_FALSE;
1137
- r_iv_set(self, "@data", r_data_wrap_struct(sound, snd));
1138
- return R_TRUE;
1139
- }
1140
-
1141
-
1142
- /*
1143
- * Ruby2D::Sound#ext_play
1144
- */
1145
- #if MRUBY
1146
- static R_VAL ruby2d_sound_ext_play(mrb_state* mrb, R_VAL self) {
1147
- #else
1148
- static R_VAL ruby2d_sound_ext_play(R_VAL self) {
1149
- #endif
1150
- R2D_Sound *snd;
1151
- r_data_get_struct(self, "@data", &sound_data_type, R2D_Sound, snd);
1152
- R2D_PlaySound(snd, r_test(r_iv_get(self, "@loop")));
1153
- return R_NIL;
1154
- }
1155
-
1156
-
1157
- /*
1158
- * Ruby2D::Sound#ext_stop
1159
- */
1160
- #if MRUBY
1161
- static R_VAL ruby2d_sound_ext_stop(mrb_state* mrb, R_VAL self) {
1162
- #else
1163
- static R_VAL ruby2d_sound_ext_stop(R_VAL self) {
1164
- #endif
1165
- R2D_Sound *snd;
1166
- r_data_get_struct(self, "@data", &sound_data_type, R2D_Sound, snd);
1167
- R2D_StopSound(snd);
1168
- return R_NIL;
1169
- }
1170
-
1171
-
1172
- /*
1173
- * Ruby2D::Sound#ext_length
1174
- */
1175
- #if MRUBY
1176
- static R_VAL ruby2d_sound_ext_length(mrb_state* mrb, R_VAL self) {
1177
- #else
1178
- static R_VAL ruby2d_sound_ext_length(R_VAL self) {
1179
- #endif
1180
- R2D_Sound *snd;
1181
- r_data_get_struct(self, "@data", &sound_data_type, R2D_Sound, snd);
1182
- return INT2NUM(R2D_GetSoundLength(snd));
1183
- }
1184
-
1185
-
1186
- /*
1187
- * Free sound structure attached to Ruby 2D `Sound` class
1188
- */
1189
- #if MRUBY
1190
- static void free_sound(mrb_state *mrb, void *p_) {
1191
- R2D_Sound *snd = (R2D_Sound *)p_;
1192
- #else
1193
- static void free_sound(R2D_Sound *snd) {
1194
- #endif
1195
- R2D_FreeSound(snd);
1196
- }
1197
-
1198
-
1199
- /*
1200
- * Ruby2D::Sound#ext_get_volume
1201
- */
1202
- #if MRUBY
1203
- static R_VAL ruby2d_sound_ext_get_volume(mrb_state* mrb, R_VAL self) {
1204
- #else
1205
- static R_VAL ruby2d_sound_ext_get_volume(R_VAL self) {
1206
- #endif
1207
- R2D_Sound *snd;
1208
- r_data_get_struct(self, "@data", &sound_data_type, R2D_Sound, snd);
1209
- return INT2NUM(ceil(Mix_VolumeChunk(snd->data, -1) * (100.0 / MIX_MAX_VOLUME)));
1210
- }
1211
-
1212
-
1213
- /*
1214
- * Ruby2D::Music#ext_set_volume
1215
- */
1216
- #if MRUBY
1217
- static R_VAL ruby2d_sound_ext_set_volume(mrb_state* mrb, R_VAL self) {
1218
- mrb_value volume;
1219
- mrb_get_args(mrb, "o", &volume);
1220
- #else
1221
- static R_VAL ruby2d_sound_ext_set_volume(R_VAL self, R_VAL volume) {
1222
- #endif
1223
- R2D_Sound *snd;
1224
- r_data_get_struct(self, "@data", &sound_data_type, R2D_Sound, snd);
1225
- Mix_VolumeChunk(snd->data, (NUM2INT(volume) / 100.0) * MIX_MAX_VOLUME);
1226
- return R_NIL;
1227
- }
1228
-
1229
-
1230
- /*
1231
- * Ruby2D::Sound#ext_get_mix_volume
1232
- */
1233
- #if MRUBY
1234
- static R_VAL ruby2d_sound_ext_get_mix_volume(mrb_state* mrb, R_VAL self) {
1235
- #else
1236
- static R_VAL ruby2d_sound_ext_get_mix_volume(R_VAL self) {
1237
- #endif
1238
- return INT2NUM(ceil(Mix_Volume(-1, -1) * (100.0 / MIX_MAX_VOLUME)));
250
+ *w = mode->w;
251
+ *h = mode->h;
252
+ SDL_free(display_ids);
1239
253
  }
1240
254
 
1241
255
 
1242
256
  /*
1243
- * Ruby2D::Music#ext_set_mix_volume
257
+ * Add gamepad mappings from a file. Returns the number of mappings added,
258
+ * or -1 on error.
1244
259
  */
1245
- #if MRUBY
1246
- static R_VAL ruby2d_sound_ext_set_mix_volume(mrb_state* mrb, R_VAL self) {
1247
- mrb_value volume;
1248
- mrb_get_args(mrb, "o", &volume);
1249
- #else
1250
- static R_VAL ruby2d_sound_ext_set_mix_volume(R_VAL self, R_VAL volume) {
1251
- #endif
1252
- Mix_Volume(-1, (NUM2INT(volume) / 100.0) * MIX_MAX_VOLUME);
1253
- return R_NIL;
1254
- }
1255
-
1256
-
1257
- /*
1258
- * Ruby2D::Music#ext_init
1259
- * Initialize music structure data
1260
- */
1261
- #if MRUBY
1262
- static R_VAL ruby2d_music_ext_init(mrb_state* mrb, R_VAL self) {
1263
- mrb_value path;
1264
- mrb_get_args(mrb, "o", &path);
1265
- #else
1266
- static R_VAL ruby2d_music_ext_init(R_VAL self, R_VAL path) {
1267
- #endif
1268
- R2D_Music *mus = R2D_CreateMusic(RSTRING_PTR(path));
1269
- if (!mus) return R_FALSE;
1270
- r_iv_set(self, "@data", r_data_wrap_struct(music, mus));
1271
- return R_TRUE;
1272
- }
1273
-
1274
-
1275
- /*
1276
- * Ruby2D::Music#ext_play
1277
- */
1278
- #if MRUBY
1279
- static R_VAL ruby2d_music_ext_play(mrb_state* mrb, R_VAL self) {
1280
- #else
1281
- static R_VAL ruby2d_music_ext_play(R_VAL self) {
1282
- #endif
1283
- R2D_Music *mus;
1284
- r_data_get_struct(self, "@data", &music_data_type, R2D_Music, mus);
1285
- R2D_PlayMusic(mus, r_test(r_iv_get(self, "@loop")));
1286
- return R_NIL;
1287
- }
1288
-
1289
-
1290
- /*
1291
- * Ruby2D::Music#ext_pause
1292
- */
1293
- #if MRUBY
1294
- static R_VAL ruby2d_music_ext_pause(mrb_state* mrb, R_VAL self) {
1295
- #else
1296
- static R_VAL ruby2d_music_ext_pause(R_VAL self) {
1297
- #endif
1298
- R2D_PauseMusic();
1299
- return R_NIL;
1300
- }
1301
-
1302
-
1303
- /*
1304
- * Ruby2D::Music#ext_resume
1305
- */
1306
- #if MRUBY
1307
- static R_VAL ruby2d_music_ext_resume(mrb_state* mrb, R_VAL self) {
1308
- #else
1309
- static R_VAL ruby2d_music_ext_resume(R_VAL self) {
1310
- #endif
1311
- R2D_ResumeMusic();
1312
- return R_NIL;
1313
- }
1314
-
1315
-
1316
- /*
1317
- * Ruby2D::Music#ext_stop
1318
- */
1319
- #if MRUBY
1320
- static R_VAL ruby2d_music_ext_stop(mrb_state* mrb, R_VAL self) {
1321
- #else
1322
- static R_VAL ruby2d_music_ext_stop(R_VAL self) {
1323
- #endif
1324
- R2D_StopMusic();
1325
- return R_NIL;
260
+ int R2D_AddGamepadMappingsFromFile(const char *path) {
261
+ if (!path) return -1;
262
+ int result = SDL_AddGamepadMappingsFromFile(path);
263
+ if (result < 0) {
264
+ R2D_Error("R2D_AddGamepadMappingsFromFile", "%s", SDL_GetError());
265
+ } else {
266
+ R2D_Log(R2D_INFO, "Added %d gamepad mappings", result);
267
+ }
268
+ return result;
1326
269
  }
1327
270
 
1328
271
 
1329
272
  /*
1330
- * Ruby2D::Music#ext_get_volume
273
+ * Add a single gamepad mapping from a string. Returns 1 if the mapping was
274
+ * added, 0 if it updated an existing one, or -1 on error.
1331
275
  */
1332
- #if MRUBY
1333
- static R_VAL ruby2d_music_ext_get_volume(mrb_state* mrb, R_VAL self) {
1334
- #else
1335
- static R_VAL ruby2d_music_ext_get_volume(R_VAL self) {
1336
- #endif
1337
- return INT2NUM(R2D_GetMusicVolume());
276
+ int R2D_AddGamepadMapping(const char *mapping) {
277
+ if (!mapping) return -1;
278
+ int result = SDL_AddGamepadMapping(mapping);
279
+ if (result < 0) {
280
+ R2D_Error("R2D_AddGamepadMapping", "%s", SDL_GetError());
281
+ }
282
+ return result;
1338
283
  }
1339
284
 
1340
285
 
1341
286
  /*
1342
- * Ruby2D::Music#ext_set_volume
287
+ * Trigger whole-gamepad rumble.
1343
288
  */
1344
- #if MRUBY
1345
- static R_VAL ruby2d_music_ext_set_volume(mrb_state* mrb, R_VAL self) {
1346
- mrb_value volume;
1347
- mrb_get_args(mrb, "o", &volume);
1348
- #else
1349
- static R_VAL ruby2d_music_ext_set_volume(R_VAL self, R_VAL volume) {
1350
- #endif
1351
- R2D_SetMusicVolume(NUM2INT(volume));
1352
- return R_NIL;
289
+ bool R2D_RumbleGamepad(SDL_JoystickID id, double low, double high, double duration) {
290
+ SDL_Gamepad *pad = SDL_GetGamepadFromID(id);
291
+ if (!pad) return false;
292
+ if (low < 0.0) low = 0.0; if (low > 1.0) low = 1.0;
293
+ if (high < 0.0) high = 0.0; if (high > 1.0) high = 1.0;
294
+ if (duration < 0.0) duration = 0.0;
295
+ Uint16 lo = (Uint16)(low * 0xFFFF);
296
+ Uint16 hi = (Uint16)(high * 0xFFFF);
297
+ Uint32 ms = (Uint32)(duration * 1000.0);
298
+ return SDL_RumbleGamepad(pad, lo, hi, ms);
1353
299
  }
1354
300
 
1355
301
 
1356
302
  /*
1357
- * Ruby2D::Music#ext_fadeout
303
+ * Trigger trigger-only rumble.
1358
304
  */
1359
- #if MRUBY
1360
- static R_VAL ruby2d_music_ext_fadeout(mrb_state* mrb, R_VAL self) {
1361
- mrb_value ms;
1362
- mrb_get_args(mrb, "o", &ms);
1363
- #else
1364
- static R_VAL ruby2d_music_ext_fadeout(R_VAL self, R_VAL ms) {
1365
- #endif
1366
- R2D_FadeOutMusic(NUM2INT(ms));
1367
- return R_NIL;
305
+ bool R2D_RumbleGamepadTriggers(SDL_JoystickID id, double left, double right, double duration) {
306
+ SDL_Gamepad *pad = SDL_GetGamepadFromID(id);
307
+ if (!pad) return false;
308
+ if (left < 0.0) left = 0.0; if (left > 1.0) left = 1.0;
309
+ if (right < 0.0) right = 0.0; if (right > 1.0) right = 1.0;
310
+ if (duration < 0.0) duration = 0.0;
311
+ Uint16 l = (Uint16)(left * 0xFFFF);
312
+ Uint16 r = (Uint16)(right * 0xFFFF);
313
+ Uint32 ms = (Uint32)(duration * 1000.0);
314
+ return SDL_RumbleGamepadTriggers(pad, l, r, ms);
1368
315
  }
1369
316
 
1370
317
 
1371
318
  /*
1372
- * Ruby2D::Music#ext_length
319
+ * Set the gamepad's LED color (PS4/PS5).
1373
320
  */
1374
- #if MRUBY
1375
- static R_VAL ruby2d_music_ext_length(mrb_state* mrb, R_VAL self) {
1376
- #else
1377
- static R_VAL ruby2d_music_ext_length(R_VAL self) {
1378
- #endif
1379
- R2D_Music *ms;
1380
- r_data_get_struct(self, "@data", &music_data_type, R2D_Music, ms);
1381
- return INT2NUM(R2D_GetMusicLength(ms));
321
+ bool R2D_SetGamepadLED(SDL_JoystickID id, int r, int g, int b) {
322
+ SDL_Gamepad *pad = SDL_GetGamepadFromID(id);
323
+ if (!pad) return false;
324
+ if (r < 0) r = 0; if (r > 255) r = 255;
325
+ if (g < 0) g = 0; if (g > 255) g = 255;
326
+ if (b < 0) b = 0; if (b > 255) b = 255;
327
+ return SDL_SetGamepadLED(pad, (Uint8)r, (Uint8)g, (Uint8)b);
1382
328
  }
1383
329
 
1384
330
 
1385
331
  /*
1386
- * Ruby2D::Font#ext_load
332
+ * Look up the gamepad's battery status. The high-level state and percent
333
+ * are returned separately so the Ruby side can map them into the
334
+ * documented :wired/:full/:medium/:low/:empty/nil vocabulary.
1387
335
  */
1388
- #if MRUBY
1389
- static R_VAL ruby2d_font_ext_load(mrb_state* mrb, R_VAL self) {
1390
- mrb_value path, size, style;
1391
- mrb_get_args(mrb, "ooo", &path, &size, &style);
1392
- #else
1393
- static R_VAL ruby2d_font_ext_load(R_VAL self, R_VAL path, R_VAL size, R_VAL style) {
1394
- #endif
1395
- R2D_Init();
1396
-
1397
- TTF_Font *font = R2D_FontCreateTTFFont(RSTRING_PTR(path), NUM2INT(size), RSTRING_PTR(style));
1398
- if (!font) {
1399
- return R_NIL;
336
+ int R2D_GetGamepadBattery(SDL_JoystickID id, int *out_percent) {
337
+ if (out_percent) *out_percent = -1;
338
+ SDL_Gamepad *pad = SDL_GetGamepadFromID(id);
339
+ if (!pad) return R2D_GAMEPAD_BATTERY_UNKNOWN;
340
+ int percent = -1;
341
+ SDL_PowerState ps = SDL_GetGamepadPowerInfo(pad, &percent);
342
+ if (out_percent) *out_percent = percent;
343
+ switch (ps) {
344
+ case SDL_POWERSTATE_NO_BATTERY:
345
+ case SDL_POWERSTATE_CHARGING:
346
+ case SDL_POWERSTATE_CHARGED:
347
+ return R2D_GAMEPAD_BATTERY_WIRED;
348
+ case SDL_POWERSTATE_ON_BATTERY:
349
+ return R2D_GAMEPAD_BATTERY_ON_BATTERY;
350
+ default:
351
+ return R2D_GAMEPAD_BATTERY_UNKNOWN;
1400
352
  }
1401
-
1402
- return r_data_wrap_struct(font, font);
1403
353
  }
1404
354
 
1405
355
 
1406
356
  /*
1407
- * Ruby2D::Texture#ext_draw
357
+ * Capability checks for buttons / axes on a connected gamepad.
1408
358
  */
1409
- #if MRUBY
1410
- static R_VAL ruby2d_texture_ext_draw(mrb_state* mrb, R_VAL self) {
1411
- mrb_value ruby_coordinates, ruby_texture_coordinates, ruby_color, texture_id;
1412
- mrb_get_args(mrb, "oooo", &ruby_coordinates, &ruby_texture_coordinates, &ruby_color, &texture_id);
1413
- #else
1414
- static R_VAL ruby2d_texture_ext_draw(R_VAL self, R_VAL ruby_coordinates, R_VAL ruby_texture_coordinates, R_VAL ruby_color, R_VAL texture_id) {
1415
- #endif
1416
- GLfloat coordinates[8];
1417
- GLfloat texture_coordinates[8];
1418
- GLfloat color[4];
1419
-
1420
- for(int i = 0; i < 8; i++) { coordinates[i] = NUM2DBL(r_ary_entry(ruby_coordinates, i)); }
1421
- for(int i = 0; i < 8; i++) { texture_coordinates[i] = NUM2DBL(r_ary_entry(ruby_texture_coordinates, i)); }
1422
- for(int i = 0; i < 4; i++) { color[i] = NUM2DBL(r_ary_entry(ruby_color, i)); }
1423
-
1424
- R2D_GL_DrawTexture(coordinates, texture_coordinates, color, NUM2INT(texture_id));
1425
-
1426
- return R_NIL;
359
+ bool R2D_GamepadHasButton(SDL_JoystickID id, int button) {
360
+ SDL_Gamepad *pad = SDL_GetGamepadFromID(id);
361
+ if (!pad) return false;
362
+ return SDL_GamepadHasButton(pad, (SDL_GamepadButton)button);
1427
363
  }
1428
364
 
1429
365
 
1430
- /*
1431
- * Free font structure stored in the Ruby 2D `Font` class
1432
- */
1433
- #if MRUBY
1434
- static void free_font(mrb_state *mrb, void *p_) {
1435
- TTF_Font *font = (TTF_Font *)p_;
1436
- #else
1437
- static void free_font(TTF_Font *font) {
1438
- #endif
1439
- TTF_CloseFont(font);
366
+ bool R2D_GamepadHasAxis(SDL_JoystickID id, int axis) {
367
+ SDL_Gamepad *pad = SDL_GetGamepadFromID(id);
368
+ if (!pad) return false;
369
+ return SDL_GamepadHasAxis(pad, (SDL_GamepadAxis)axis);
1440
370
  }
1441
371
 
1442
372
 
1443
373
  /*
1444
- * Free surface structure used within the Ruby 2D `Texture` class
1445
- */
1446
- #if MRUBY
1447
- static void free_surface(mrb_state *mrb, void *p_) {
1448
- SDL_Surface *surface = (SDL_Surface *)p_;
1449
- #else
1450
- static void free_surface(SDL_Surface *surface) {
1451
- #endif
1452
- SDL_FreeSurface(surface);
1453
- }
1454
-
1455
- /*
1456
- * Free SDL texture structure used within the Ruby 2D `Pixmap` class
374
+ * Returns a bitfield of feedback capabilities for the gamepad.
1457
375
  */
1458
- #if MRUBY
1459
- static void free_sdl_texture(mrb_state *mrb, void *p_) {
1460
- SDL_Texture *sdl_texure = (SDL_Texture *)p_;
1461
- #else
1462
- static void free_sdl_texture(SDL_Texture *sdl_texure) {
1463
- #endif
1464
- SDL_DestroyTexture(sdl_texure);
376
+ int R2D_GetGamepadCaps(SDL_JoystickID id) {
377
+ SDL_Gamepad *pad = SDL_GetGamepadFromID(id);
378
+ if (!pad) return 0;
379
+ SDL_PropertiesID props = SDL_GetGamepadProperties(pad);
380
+ if (!props) return 0;
381
+ int caps = 0;
382
+ if (SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false))
383
+ caps |= R2D_GAMEPAD_CAP_RUMBLE;
384
+ if (SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_TRIGGER_RUMBLE_BOOLEAN, false))
385
+ caps |= R2D_GAMEPAD_CAP_RUMBLE_TRIGGERS;
386
+ if (SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_RGB_LED_BOOLEAN, false))
387
+ caps |= R2D_GAMEPAD_CAP_RGB_LED;
388
+ return caps;
1465
389
  }
1466
390
 
1467
- /*
1468
- * Free renderer structure used within the Ruby 2D `Canvas` class
1469
- */
1470
- #if MRUBY
1471
- static void free_renderer(mrb_state *mrb, void *p_) {
1472
- SDL_Renderer *renderer = (SDL_Renderer *)p_;
1473
- #else
1474
- static void free_renderer(SDL_Renderer *renderer) {
1475
- #endif
1476
- SDL_DestroyRenderer(renderer);
1477
- }
1478
391
 
392
+ // =============================================================================
393
+ // Module Methods
394
+ // =============================================================================
1479
395
 
1480
396
  /*
1481
- * Free music structure attached to Ruby 2D `Music` class
397
+ * Ruby2D.web?
398
+ * Whether this build targets the web. Emscripten defines `__EMSCRIPTEN__` for
399
+ * the WASM build and nothing else does, so the answer is settled at compile
400
+ * time: a native build reports false, as does the gem running under CRuby.
401
+ * Apps use it to size work to the target, which the web needs less of.
1482
402
  */
1483
- #if MRUBY
1484
- static void free_music(mrb_state *mrb, void *p_) {
1485
- R2D_Music *mus = (R2D_Music *)p_;
403
+ static R_VAL ruby2d_web_p(RUBY2D_METHOD_ARGS_VARIADIC) {
404
+ #ifdef __EMSCRIPTEN__
405
+ return R_TRUE;
1486
406
  #else
1487
- static void free_music(R2D_Music *mus) {
407
+ return R_FALSE;
1488
408
  #endif
1489
- R2D_FreeMusic(mus);
1490
409
  }
1491
410
 
1492
411
 
1493
- /*
1494
- * Ruby 2D native `on_key` input callback function
1495
- */
1496
- static void on_key(R2D_Event e) {
1497
-
1498
- R_VAL type;
1499
-
1500
- switch (e.type) {
1501
- case R2D_KEY_DOWN:
1502
- type = r_char_to_sym("down");
1503
- break;
1504
- case R2D_KEY_HELD:
1505
- type = r_char_to_sym("held");
1506
- break;
1507
- case R2D_KEY_UP:
1508
- type = r_char_to_sym("up");
1509
- break;
1510
- }
1511
-
1512
- r_funcall(ruby2d_window, "key_callback", 2, type, r_str_new(e.key));
1513
- }
1514
-
1515
-
1516
- /*
1517
- * Ruby 2D native `on_mouse` input callback function
1518
- */
1519
- void on_mouse(R2D_Event e) {
1520
-
1521
- R_VAL type = R_NIL; R_VAL button = R_NIL; R_VAL direction = R_NIL;
1522
-
1523
- switch (e.type) {
1524
- case R2D_MOUSE_DOWN:
1525
- // type, button, x, y
1526
- type = r_char_to_sym("down");
1527
- break;
1528
- case R2D_MOUSE_UP:
1529
- // type, button, x, y
1530
- type = r_char_to_sym("up");
1531
- break;
1532
- case R2D_MOUSE_SCROLL:
1533
- // type, direction, delta_x, delta_y
1534
- type = r_char_to_sym("scroll");
1535
- direction = e.direction == R2D_MOUSE_SCROLL_NORMAL ?
1536
- r_char_to_sym("normal") : r_char_to_sym("inverted");
1537
- break;
1538
- case R2D_MOUSE_MOVE:
1539
- // type, x, y, delta_x, delta_y
1540
- type = r_char_to_sym("move");
1541
- break;
1542
- }
1543
-
1544
- if (e.type == R2D_MOUSE_DOWN || e.type == R2D_MOUSE_UP) {
1545
- switch (e.button) {
1546
- case R2D_MOUSE_LEFT:
1547
- button = r_char_to_sym("left");
1548
- break;
1549
- case R2D_MOUSE_MIDDLE:
1550
- button = r_char_to_sym("middle");
1551
- break;
1552
- case R2D_MOUSE_RIGHT:
1553
- button = r_char_to_sym("right");
1554
- break;
1555
- case R2D_MOUSE_X1:
1556
- button = r_char_to_sym("x1");
1557
- break;
1558
- case R2D_MOUSE_X2:
1559
- button = r_char_to_sym("x2");
1560
- break;
1561
- }
1562
- }
1563
-
1564
- r_funcall(
1565
- ruby2d_window, "mouse_callback", 7, type, button, direction,
1566
- INT2NUM(e.x), INT2NUM(e.y), INT2NUM(e.delta_x), INT2NUM(e.delta_y)
1567
- );
1568
- }
1569
-
1570
-
1571
- /*
1572
- * Ruby 2D native `on_controller` input callback function
1573
- */
1574
- static void on_controller(R2D_Event e) {
1575
-
1576
- R_VAL type = R_NIL; R_VAL axis = R_NIL; R_VAL button = R_NIL;
1577
-
1578
- switch (e.type) {
1579
- case R2D_AXIS:
1580
- type = r_char_to_sym("axis");
1581
- switch (e.axis) {
1582
- case R2D_AXIS_LEFTX:
1583
- axis = r_char_to_sym("left_x");
1584
- break;
1585
- case R2D_AXIS_LEFTY:
1586
- axis = r_char_to_sym("left_y");
1587
- break;
1588
- case R2D_AXIS_RIGHTX:
1589
- axis = r_char_to_sym("right_x");
1590
- break;
1591
- case R2D_AXIS_RIGHTY:
1592
- axis = r_char_to_sym("right_y");
1593
- break;
1594
- case R2D_AXIS_TRIGGERLEFT:
1595
- axis = r_char_to_sym("trigger_left");
1596
- break;
1597
- case R2D_AXIS_TRIGGERRIGHT:
1598
- axis = r_char_to_sym("trigger_right");
1599
- break;
1600
- case R2D_AXIS_INVALID:
1601
- axis = r_char_to_sym("invalid");
1602
- break;
1603
- }
1604
- break;
1605
- case R2D_BUTTON_DOWN: case R2D_BUTTON_UP:
1606
- type = e.type == R2D_BUTTON_DOWN ? r_char_to_sym("button_down") : r_char_to_sym("button_up");
1607
- switch (e.button) {
1608
- case R2D_BUTTON_A:
1609
- button = r_char_to_sym("a");
1610
- break;
1611
- case R2D_BUTTON_B:
1612
- button = r_char_to_sym("b");
1613
- break;
1614
- case R2D_BUTTON_X:
1615
- button = r_char_to_sym("x");
1616
- break;
1617
- case R2D_BUTTON_Y:
1618
- button = r_char_to_sym("y");
1619
- break;
1620
- case R2D_BUTTON_BACK:
1621
- button = r_char_to_sym("back");
1622
- break;
1623
- case R2D_BUTTON_GUIDE:
1624
- button = r_char_to_sym("guide");
1625
- break;
1626
- case R2D_BUTTON_START:
1627
- button = r_char_to_sym("start");
1628
- break;
1629
- case R2D_BUTTON_LEFTSTICK:
1630
- button = r_char_to_sym("left_stick");
1631
- break;
1632
- case R2D_BUTTON_RIGHTSTICK:
1633
- button = r_char_to_sym("right_stick");
1634
- break;
1635
- case R2D_BUTTON_LEFTSHOULDER:
1636
- button = r_char_to_sym("left_shoulder");
1637
- break;
1638
- case R2D_BUTTON_RIGHTSHOULDER:
1639
- button = r_char_to_sym("right_shoulder");
1640
- break;
1641
- case R2D_BUTTON_DPAD_UP:
1642
- button = r_char_to_sym("up");
1643
- break;
1644
- case R2D_BUTTON_DPAD_DOWN:
1645
- button = r_char_to_sym("down");
1646
- break;
1647
- case R2D_BUTTON_DPAD_LEFT:
1648
- button = r_char_to_sym("left");
1649
- break;
1650
- case R2D_BUTTON_DPAD_RIGHT:
1651
- button = r_char_to_sym("right");
1652
- break;
1653
- case R2D_BUTTON_INVALID:
1654
- button = r_char_to_sym("invalid");
1655
- break;
1656
- }
1657
- break;
1658
- }
1659
-
1660
- r_funcall(
1661
- ruby2d_window, "controller_callback", 5, INT2NUM(e.which),
1662
- type, axis, DBL2NUM(normalize_controller_axis(e.value)), button
1663
- );
1664
- }
1665
-
1666
-
1667
- /*
1668
- * Ruby 2D native `update` callback function
1669
- */
1670
- static void update() {
412
+ // =============================================================================
413
+ // Extension Initialization
414
+ // =============================================================================
1671
415
 
1672
- // Set the cursor
1673
- r_iv_set(ruby2d_window, "@mouse_x", INT2NUM(ruby2d_c_window->mouse.x));
1674
- r_iv_set(ruby2d_window, "@mouse_y", INT2NUM(ruby2d_c_window->mouse.y));
1675
416
 
1676
- // Store frames
1677
- r_iv_set(ruby2d_window, "@frames", DBL2NUM(ruby2d_c_window->frames));
417
+ #if defined(MRUBY) && !defined(__EMSCRIPTEN__)
1678
418
 
1679
- // Store frame rate
1680
- r_iv_set(ruby2d_window, "@fps", DBL2NUM(ruby2d_c_window->fps));
1681
-
1682
- // Call update proc, `window.update`
1683
- r_funcall(ruby2d_window, "update_callback", 0);
1684
- }
1685
-
1686
-
1687
- /*
1688
- * Ruby 2D native `render` callback function
1689
- */
1690
- static void render() {
1691
-
1692
- // Set background color
1693
- R_VAL bc = r_iv_get(ruby2d_window, "@background");
1694
- ruby2d_c_window->background.r = NUM2DBL(r_iv_get(bc, "@r"));
1695
- ruby2d_c_window->background.g = NUM2DBL(r_iv_get(bc, "@g"));
1696
- ruby2d_c_window->background.b = NUM2DBL(r_iv_get(bc, "@b"));
1697
- ruby2d_c_window->background.a = NUM2DBL(r_iv_get(bc, "@a"));
1698
-
1699
- // Read window objects
1700
- R_VAL objects = r_iv_get(ruby2d_window, "@objects");
1701
- int num_objects = NUM2INT(r_funcall(objects, "length", 0));
1702
-
1703
- // Switch on each object type
1704
- for (int i = 0; i < num_objects; ++i) {
1705
- R_VAL el = r_ary_entry(objects, i);
1706
- r_funcall(el, "render", 0); // call the object's `render` function
1707
- }
1708
-
1709
- // Call render proc, `window.render`
1710
- r_funcall(ruby2d_window, "render_callback", 0);
1711
- }
1712
-
1713
-
1714
- /*
1715
- * Ruby2D::Window#ext_diagnostics
1716
- */
1717
- #if MRUBY
1718
- static R_VAL ruby2d_ext_diagnostics(mrb_state* mrb, R_VAL self) {
1719
- mrb_value enable;
1720
- mrb_get_args(mrb, "o", &enable);
1721
- #else
1722
- static R_VAL ruby2d_ext_diagnostics(R_VAL self, R_VAL enable) {
419
+ #include <string.h>
420
+ #if defined(__APPLE__)
421
+ #include <mach-o/dyld.h>
422
+ #elif defined(_WIN32)
423
+ #include <windows.h>
424
+ #include <direct.h>
425
+ #define chdir _chdir
1723
426
  #endif
1724
- // Set Ruby 2D native diagnostics
1725
- R2D_Diagnostics(r_test(enable));
1726
- return R_TRUE;
1727
- }
1728
-
1729
427
 
1730
428
  /*
1731
- * Ruby2D::Window#ext_get_display_dimensions
429
+ * Change the working directory to the one containing this executable, so
430
+ * relative resource paths (notably the bundled default font `ruby2d/fonts/…`)
431
+ * resolve no matter how the app was launched. A Finder-launched macOS .app
432
+ * starts with the working directory set to `/`, which would otherwise break
433
+ * the bundled-font lookup. Native builds only — the WASM build keeps its
434
+ * Emscripten-preloaded filesystem rooted at the working directory.
1732
435
  */
1733
- #if MRUBY
1734
- static R_VAL ruby2d_window_ext_get_display_dimensions(mrb_state* mrb, R_VAL self) {
1735
- #else
1736
- static R_VAL ruby2d_window_ext_get_display_dimensions(R_VAL self) {
1737
- #endif
1738
- int w; int h;
1739
- R2D_GetDisplayDimensions(&w, &h);
1740
- r_iv_set(self, "@display_width" , INT2NUM(w));
1741
- r_iv_set(self, "@display_height", INT2NUM(h));
1742
- return R_NIL;
1743
- }
1744
-
436
+ static void R2D_ChdirToExeDir(void) {
437
+ char path[4096];
1745
438
 
1746
- /*
1747
- * Ruby2D::Window#ext_add_controller_mappings
1748
- */
1749
- #if MRUBY
1750
- static R_VAL ruby2d_window_ext_add_controller_mappings(mrb_state* mrb, R_VAL self) {
1751
- mrb_value path;
1752
- mrb_get_args(mrb, "o", &path);
439
+ #if defined(__APPLE__)
440
+ uint32_t size = sizeof(path);
441
+ if (_NSGetExecutablePath(path, &size) != 0) return;
442
+ #elif defined(_WIN32)
443
+ DWORD len = GetModuleFileNameA(NULL, path, sizeof(path));
444
+ if (len == 0 || len >= sizeof(path)) return;
1753
445
  #else
1754
- static R_VAL ruby2d_window_ext_add_controller_mappings(R_VAL self, R_VAL path) {
446
+ ssize_t len = readlink("/proc/self/exe", path, sizeof(path) - 1);
447
+ if (len <= 0) return;
448
+ path[len] = '\0';
1755
449
  #endif
1756
- R2D_Log(R2D_INFO, "Adding controller mappings from `%s`", RSTRING_PTR(path));
1757
- R2D_AddControllerMappingsFromFile(RSTRING_PTR(path));
1758
- return R_NIL;
1759
- }
1760
-
1761
450
 
1762
- /*
1763
- * Ruby2D::Window#ext_show
1764
- */
1765
- #if MRUBY
1766
- static R_VAL ruby2d_window_ext_show(mrb_state* mrb, R_VAL self) {
1767
- #else
1768
- static R_VAL ruby2d_window_ext_show(R_VAL self) {
451
+ // Trim the trailing path component to get the containing directory
452
+ char *sep = strrchr(path, '/');
453
+ #if defined(_WIN32)
454
+ char *backslash = strrchr(path, '\\');
455
+ if (backslash > sep) sep = backslash;
1769
456
  #endif
1770
- ruby2d_window = self;
1771
-
1772
- // Add controller mappings from file
1773
- r_funcall(self, "add_controller_mappings", 0);
1774
-
1775
- // Get window attributes
1776
- char *title = RSTRING_PTR(r_iv_get(self, "@title"));
1777
- int width = NUM2INT(r_iv_get(self, "@width"));
1778
- int height = NUM2INT(r_iv_get(self, "@height"));
1779
- int fps_cap = NUM2INT(r_iv_get(self, "@fps_cap"));
1780
-
1781
- // Get the window icon
1782
- char *icon = NULL;
1783
- R_VAL iv_icon = r_iv_get(self, "@icon");
1784
- if (r_test(iv_icon)) icon = RSTRING_PTR(iv_icon);
1785
-
1786
- // Get window flags
1787
- int flags = 0;
1788
- if (r_test(r_iv_get(self, "@resizable"))) {
1789
- flags = flags | R2D_RESIZABLE;
1790
- }
1791
- if (r_test(r_iv_get(self, "@borderless"))) {
1792
- flags = flags | R2D_BORDERLESS;
1793
- }
1794
- if (r_test(r_iv_get(self, "@fullscreen"))) {
1795
- flags = flags | R2D_FULLSCREEN;
1796
- }
1797
- if (r_test(r_iv_get(self, "@highdpi"))) {
1798
- flags = flags | R2D_HIGHDPI;
1799
- }
1800
-
1801
- // Check viewport size and set
1802
-
1803
- R_VAL vp_w = r_iv_get(self, "@viewport_width");
1804
- int viewport_width = r_test(vp_w) ? NUM2INT(vp_w) : width;
1805
-
1806
- R_VAL vp_h = r_iv_get(self, "@viewport_height");
1807
- int viewport_height = r_test(vp_h) ? NUM2INT(vp_h) : height;
457
+ if (!sep) return;
458
+ *sep = '\0';
1808
459
 
1809
- // Create and show window
1810
-
1811
- ruby2d_c_window = R2D_CreateWindow(
1812
- title, width, height, update, render, flags
1813
- );
1814
-
1815
- ruby2d_c_window->viewport.width = viewport_width;
1816
- ruby2d_c_window->viewport.height = viewport_height;
1817
- ruby2d_c_window->fps_cap = fps_cap;
1818
- ruby2d_c_window->icon = icon;
1819
- ruby2d_c_window->on_key = on_key;
1820
- ruby2d_c_window->on_mouse = on_mouse;
1821
- ruby2d_c_window->on_controller = on_controller;
1822
-
1823
- R2D_Show(ruby2d_c_window);
1824
-
1825
- atexit(free_window);
1826
- return R_NIL;
460
+ if (chdir(path) != 0) R2D_Log(R2D_WARN, "Could not change directory to `%s`", path);
1827
461
  }
1828
462
 
1829
-
1830
- /*
1831
- * Ruby2D::Window#ext_screenshot
1832
- */
1833
- #if MRUBY
1834
- static R_VAL ruby2d_ext_screenshot(mrb_state* mrb, R_VAL self) {
1835
- mrb_value path;
1836
- mrb_get_args(mrb, "o", &path);
1837
- #else
1838
- static R_VAL ruby2d_ext_screenshot(R_VAL self, R_VAL path) {
1839
463
  #endif
1840
- if (ruby2d_c_window) {
1841
- R2D_Screenshot(ruby2d_c_window, RSTRING_PTR(path));
1842
- return path;
1843
- } else {
1844
- return R_FALSE;
1845
- }
1846
- }
1847
464
 
1848
465
 
466
+ #ifdef MRUBY
1849
467
  /*
1850
- * Ruby2D::Window#ext_close
1851
- */
1852
- #if MRUBY
1853
- static R_VAL ruby2d_window_ext_close(mrb_state* mrb, R_VAL self) {
1854
- #else
1855
- static R_VAL ruby2d_window_ext_close() {
1856
- #endif
1857
- R2D_Close(ruby2d_c_window);
1858
- return R_NIL;
1859
- }
1860
-
1861
-
1862
- #if MRUBY
1863
- /*
1864
- * MRuby entry point
468
+ * MRuby entry point. This is the one sanctioned exception to the "never call
469
+ * `mrb_*` directly, use the `r_*` macros" rule (see AGENTS.md): it bootstraps,
470
+ * runs, and tears down the very interpreter the `r_*` layer runs inside, so the
471
+ * raw `mrb_open`/`mrb_load_irep`/`mrb_close` calls here have no abstraction to
472
+ * route through (CRuby has no equivalent — its VM calls `Init_ruby2d` instead).
473
+ *
474
+ * Raw calls only, though: never exchange a compile-time symbol id (`MRB_SYM`
475
+ * and friends, or vendored macros expanding to them) with `libmruby` here.
476
+ * Presym ids are assigned per build, so these vendored headers' numbering can
477
+ * be wrong for a cross-compiled target — intern at runtime with
478
+ * `mrb_intern_lit` instead. The `SystemExit` status read below is a live case.
1865
479
  */
1866
480
  int main() {
1867
481
  // Open the MRuby environment
1868
482
  mrb = mrb_open();
1869
- if (!mrb) { /* handle error */ }
483
+ if (!mrb) {
484
+ R2D_Error("mrb_open", "Could not initialize the mruby interpreter");
485
+ return EXIT_FAILURE;
486
+ }
1870
487
 
1871
- // Load the Ruby 2D library
1872
- mrb_load_irep(mrb, ruby2d_lib);
488
+ #ifndef __EMSCRIPTEN__
489
+ R2D_ChdirToExeDir();
490
+ #endif
1873
491
 
1874
492
  #else
1875
493
  /*
@@ -1879,195 +497,61 @@ void Init_ruby2d() {
1879
497
  #endif
1880
498
 
1881
499
  // Ruby2D
1882
- R_CLASS ruby2d_module = r_define_module("Ruby2D");
1883
-
1884
- // Ruby2D#self.ext_base_path
1885
- r_define_class_method(ruby2d_module, "ext_base_path", ruby2d_ext_base_path, r_args_none);
1886
-
1887
- // Ruby2D::Pixel
1888
- R_CLASS ruby2d_pixel_class = r_define_class(ruby2d_module, "Pixel");
1889
-
1890
- // Ruby2D::Pixel#self.ext_draw
1891
- r_define_class_method(ruby2d_pixel_class, "ext_draw", ruby2d_pixel_ext_draw, r_args_req(1));
1892
-
1893
- // Ruby2D::Triangle
1894
- R_CLASS ruby2d_triangle_class = r_define_class(ruby2d_module, "Triangle");
1895
-
1896
- // Ruby2D::Triangle#self.ext_draw
1897
- r_define_class_method(ruby2d_triangle_class, "ext_draw", ruby2d_triangle_ext_draw, r_args_req(1));
1898
-
1899
- // Ruby2D::Quad
1900
- R_CLASS ruby2d_quad_class = r_define_class(ruby2d_module, "Quad");
1901
-
1902
- // Ruby2D::Quad#self.ext_draw
1903
- r_define_class_method(ruby2d_quad_class, "ext_draw", ruby2d_quad_ext_draw, r_args_req(1));
1904
-
1905
- // Ruby2D::Line
1906
- R_CLASS ruby2d_line_class = r_define_class(ruby2d_module, "Line");
1907
-
1908
- // Ruby2D::Line#self.ext_draw
1909
- r_define_class_method(ruby2d_line_class, "ext_draw", ruby2d_line_ext_draw, r_args_req(1));
1910
-
1911
- // Ruby2D::Circle
1912
- R_CLASS ruby2d_circle_class = r_define_class(ruby2d_module, "Circle");
1913
-
1914
- // Ruby2D::Circle#self.ext_draw
1915
- r_define_class_method(ruby2d_circle_class, "ext_draw", ruby2d_circle_ext_draw, r_args_req(1));
1916
-
1917
- // Ruby2D::Pixmap
1918
- R_CLASS ruby2d_pixmap_class = r_define_class(ruby2d_module, "Pixmap");
1919
-
1920
- // Ruby2D::Pixmap#ext_load_pixmap
1921
- r_define_method(ruby2d_pixmap_class, "ext_load_pixmap", ruby2d_pixmap_ext_load_pixmap, r_args_req(1));
1922
-
1923
- // Ruby2D::Text
1924
- R_CLASS ruby2d_text_class = r_define_class(ruby2d_module, "Text");
1925
-
1926
- // Ruby2D::Text#ext_load_text
1927
- r_define_class_method(ruby2d_text_class, "ext_load_text", ruby2d_text_ext_load_text, r_args_req(2));
1928
-
1929
- // Ruby2D::Sound
1930
- R_CLASS ruby2d_sound_class = r_define_class(ruby2d_module, "Sound");
1931
-
1932
- // Ruby2D::Sound#ext_init
1933
- r_define_method(ruby2d_sound_class, "ext_init", ruby2d_sound_ext_init, r_args_req(1));
1934
-
1935
- // Ruby2D::Sound#ext_play
1936
- r_define_method(ruby2d_sound_class, "ext_play", ruby2d_sound_ext_play, r_args_none);
1937
-
1938
- // Ruby2D::Sound#ext_stop
1939
- r_define_method(ruby2d_sound_class, "ext_stop", ruby2d_sound_ext_stop, r_args_none);
1940
-
1941
- // Ruby2D::Sound#ext_get_volume
1942
- r_define_method(ruby2d_sound_class, "ext_get_volume", ruby2d_sound_ext_get_volume, r_args_none);
1943
-
1944
- // Ruby2D::Sound#ext_set_volume
1945
- r_define_method(ruby2d_sound_class, "ext_set_volume", ruby2d_sound_ext_set_volume, r_args_req(1));
1946
-
1947
- // Ruby2D::Sound#self.ext_get_mix_volume
1948
- r_define_class_method(ruby2d_sound_class, "ext_get_mix_volume", ruby2d_sound_ext_get_mix_volume, r_args_none);
1949
-
1950
- // Ruby2D::Sound#self.ext_set_mix_volume
1951
- r_define_class_method(ruby2d_sound_class, "ext_set_mix_volume", ruby2d_sound_ext_set_mix_volume, r_args_req(1));
1952
-
1953
- // Ruby2D::Sound#ext_length
1954
- r_define_method(ruby2d_sound_class, "ext_length", ruby2d_sound_ext_length, r_args_none);
1955
-
1956
- // Ruby2D::Music
1957
- R_CLASS ruby2d_music_class = r_define_class(ruby2d_module, "Music");
1958
-
1959
- // Ruby2D::Music#ext_init
1960
- r_define_method(ruby2d_music_class, "ext_init", ruby2d_music_ext_init, r_args_req(1));
1961
-
1962
- // Ruby2D::Music#ext_play
1963
- r_define_method(ruby2d_music_class, "ext_play", ruby2d_music_ext_play, r_args_none);
1964
-
1965
- // Ruby2D::Music#ext_pause
1966
- r_define_method(ruby2d_music_class, "ext_pause", ruby2d_music_ext_pause, r_args_none);
1967
-
1968
- // Ruby2D::Music#ext_resume
1969
- r_define_method(ruby2d_music_class, "ext_resume", ruby2d_music_ext_resume, r_args_none);
500
+ ruby2d_module = r_define_module("Ruby2D");
501
+ r_define_class_method(ruby2d_module, "web?", ruby2d_web_p, r_args_variadic);
1970
502
 
1971
- // Ruby2D::Music#ext_stop
1972
- r_define_method(ruby2d_music_class, "ext_stop", ruby2d_music_ext_stop, r_args_none);
503
+ // Initialize Ruby2D::Ext bindings (must come before any module that uses them)
504
+ R2D_Ext_Init();
1973
505
 
1974
- // Ruby2D::Music#self.ext_get_volume
1975
- r_define_class_method(ruby2d_music_class, "ext_get_volume", ruby2d_music_ext_get_volume, r_args_none);
506
+ // Initialize Ruby2D::Image native parts
507
+ R2D_Image_Init();
1976
508
 
1977
- // Ruby2D::Music#self.ext_set_volume
1978
- r_define_class_method(ruby2d_music_class, "ext_set_volume", ruby2d_music_ext_set_volume, r_args_req(1));
509
+ // Initialize Ruby2D::Text native parts
510
+ R2D_Text_Init();
1979
511
 
1980
- // Ruby2D::Music#ext_fadeout
1981
- r_define_method(ruby2d_music_class, "ext_fadeout", ruby2d_music_ext_fadeout, r_args_req(1));
512
+ // Initialize Ruby2D::BitmapText native parts
513
+ R2D_BitmapText_Init();
1982
514
 
1983
- // Ruby2D::Music#ext_length
1984
- r_define_method(ruby2d_music_class, "ext_length", ruby2d_music_ext_length, r_args_none);
515
+ // Initialize Ruby2D::Canvas native parts
516
+ R2D_Canvas_Init();
1985
517
 
1986
- // Ruby2D::Font
1987
- R_CLASS ruby2d_font_class = r_define_class(ruby2d_module, "Font");
518
+ // Initialize Ruby2D::Audio native parts
519
+ R2D_Audio_Init();
1988
520
 
1989
- // Ruby2D::Font#ext_load
1990
- r_define_class_method(ruby2d_font_class, "ext_load", ruby2d_font_ext_load, r_args_req(3));
521
+ // Initialize Ruby2D::Window native parts
522
+ R2D_Window_Init();
1991
523
 
1992
- // Ruby2D::Texture
1993
- R_CLASS ruby2d_texture_class = r_define_class(ruby2d_module, "Texture");
1994
-
1995
- // Ruby2D::Texture#ext_draw
1996
- r_define_method(ruby2d_texture_class, "ext_draw", ruby2d_texture_ext_draw, r_args_req(4));
1997
-
1998
- // Ruby2D::Texture#ext_create
1999
- r_define_method(ruby2d_texture_class, "ext_create", ruby2d_texture_ext_create, r_args_req(3));
2000
-
2001
- // Ruby2D::Texture#ext_delete
2002
- r_define_method(ruby2d_texture_class, "ext_delete", ruby2d_texture_ext_delete, r_args_req(1));
2003
-
2004
- // Ruby2D::Canvas
2005
- R_CLASS ruby2d_canvas_class = r_define_class(ruby2d_module, "Canvas");
2006
-
2007
- // Ruby2D::Canvas#ext_create
2008
- r_define_method(ruby2d_canvas_class, "ext_create", ruby2d_canvas_ext_create, r_args_req(1));
2009
-
2010
- // Ruby2D::Canvas#ext_clear
2011
- r_define_method(ruby2d_canvas_class, "ext_clear", ruby2d_canvas_ext_clear, r_args_req(1));
2012
-
2013
- // Ruby2D::Canvas#ext_fill_rectangle
2014
- r_define_method(ruby2d_canvas_class, "ext_fill_rectangle", ruby2d_canvas_ext_fill_rectangle, r_args_req(1));
2015
-
2016
- // Ruby2D::Canvas#ext_draw_rectangle
2017
- r_define_method(ruby2d_canvas_class, "ext_draw_rectangle", ruby2d_canvas_ext_draw_rectangle, r_args_req(1));
2018
-
2019
- // Ruby2D::Canvas#ext_draw_line
2020
- r_define_method(ruby2d_canvas_class, "ext_draw_line", ruby2d_canvas_ext_draw_line, r_args_req(1));
2021
-
2022
- // Ruby2D::Canvas#ext_draw_polyline
2023
- r_define_method(ruby2d_canvas_class, "ext_draw_polyline", ruby2d_canvas_ext_draw_polyline, r_args_req(2));
2024
-
2025
- // Ruby2D::Canvas#ext_draw_polygon
2026
- r_define_method(ruby2d_canvas_class, "ext_draw_polygon", ruby2d_canvas_ext_draw_polygon, r_args_req(2));
2027
-
2028
- // Ruby2D::Canvas#ext_fill_polygon
2029
- r_define_method(ruby2d_canvas_class, "ext_fill_polygon", ruby2d_canvas_ext_fill_polygon, r_args_req(2));
2030
-
2031
- // Ruby2D::Canvas#ext_fill_ellipse
2032
- r_define_method(ruby2d_canvas_class, "ext_fill_ellipse", ruby2d_canvas_ext_fill_ellipse, r_args_req(1));
2033
-
2034
- // Ruby2D::Canvas#ext_draw_ellipse
2035
- r_define_method(ruby2d_canvas_class, "ext_draw_ellipse", ruby2d_canvas_ext_draw_ellipse, r_args_req(1));
2036
-
2037
- // Ruby2D::Canvas#ext_draw_pixmap
2038
- r_define_method(ruby2d_canvas_class, "ext_draw_pixmap", ruby2d_canvas_ext_draw_pixmap, r_args_req(6));
2039
-
2040
- // Ruby2D::Window
2041
- R_CLASS ruby2d_window_class = r_define_class(ruby2d_module, "Window");
2042
-
2043
- // Ruby2D::Window#ext_diagnostics
2044
- r_define_method(ruby2d_window_class, "ext_diagnostics", ruby2d_ext_diagnostics, r_args_req(1));
2045
-
2046
- // Ruby2D::Window#ext_get_display_dimensions
2047
- r_define_method(ruby2d_window_class, "ext_get_display_dimensions", ruby2d_window_ext_get_display_dimensions, r_args_none);
2048
-
2049
- // Ruby2D::Window#ext_add_controller_mappings
2050
- r_define_method(ruby2d_window_class, "ext_add_controller_mappings", ruby2d_window_ext_add_controller_mappings, r_args_req(1));
2051
-
2052
- // Ruby2D::Window#ext_show
2053
- r_define_method(ruby2d_window_class, "ext_show", ruby2d_window_ext_show, r_args_none);
2054
-
2055
- // Ruby2D::Window#ext_screenshot
2056
- r_define_method(ruby2d_window_class, "ext_screenshot", ruby2d_ext_screenshot, r_args_req(1));
2057
-
2058
- // Ruby2D::Window#ext_close
2059
- r_define_method(ruby2d_window_class, "ext_close", ruby2d_window_ext_close, r_args_none);
524
+ #ifdef MRUBY
525
+ // Load the Ruby 2D library
526
+ mrb_load_irep(mrb, ruby2d_lib);
527
+ if (mrb->exc) { mrb_print_error(mrb); mrb->exc = 0; }
2060
528
 
2061
- #if MRUBY
2062
- // Load the Ruby 2D app
529
+ // Load the Ruby 2D app. A clean run returns success; a `Kernel#exit`
530
+ // terminates with its own status; any other uncaught exception prints a
531
+ // backtrace and returns failure — so a crashing app reports non-zero to the
532
+ // shell/CI, matching CRuby and mruby's own `mruby` binary.
533
+ int exit_code = EXIT_SUCCESS;
2063
534
  mrb_load_irep(mrb, ruby2d_app);
2064
-
2065
- // If an exception, print error
2066
- if (mrb->exc) mrb_print_error(mrb);
535
+ if (mrb->exc) {
536
+ struct RException *e = (struct RException *)mrb->exc;
537
+ // `Kernel#exit` raises SystemExit with the exit flag set. Honor its status
538
+ // and terminate quietly, rather than printing a backtrace for what is an
539
+ // ordinary, deliberate exit. Read the status by interning "status" in the
540
+ // live interpreter instead of MRB_EXC_EXIT_STATUS's MRB_SYM(status): that
541
+ // presym id, baked into these vendored headers, matches the native libmruby
542
+ // but not the cross-compiled wasm one, where it reads back as nil and
543
+ // aborts. Default to success.
544
+ if (MRB_EXC_EXIT_P(e)) {
545
+ mrb_value status = mrb_iv_get(mrb, mrb_obj_value(e), mrb_intern_lit(mrb, "status"));
546
+ exit(mrb_integer_p(status) ? (int)mrb_integer(status) : EXIT_SUCCESS);
547
+ }
548
+ mrb_print_error(mrb);
549
+ exit_code = EXIT_FAILURE;
550
+ }
2067
551
 
2068
552
  // Close the MRuby environment
2069
553
  mrb_close(mrb);
2070
554
 
2071
- return 0;
555
+ return exit_code;
2072
556
  #endif
2073
557
  }