ruby2d 0.12.1 → 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.
- checksums.yaml +4 -4
- data/LICENSE.md +7 -0
- data/README.md +141 -0
- data/USAGE.md +2435 -0
- data/assets/Rakefile +637 -0
- data/assets/build_support/CMakeLists.txt +94 -0
- data/assets/build_support/mruby/build_config.rb +34 -0
- data/assets/build_support/mruby/build_config_wasm.rb +30 -0
- data/assets/build_support/sdl_test.c +174 -0
- data/assets/deps.yaml +16 -0
- data/assets/platform/include/SDL3/SDL.h +91 -0
- data/assets/platform/include/SDL3/SDL_assert.h +705 -0
- data/assets/platform/include/SDL3/SDL_asyncio.h +550 -0
- data/assets/platform/include/SDL3/SDL_atomic.h +692 -0
- data/assets/platform/include/SDL3/SDL_audio.h +2370 -0
- data/assets/platform/include/SDL3/SDL_begin_code.h +553 -0
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_bits.h +47 -27
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_blendmode.h +59 -55
- data/assets/platform/include/SDL3/SDL_camera.h +535 -0
- data/assets/platform/include/SDL3/SDL_clipboard.h +331 -0
- data/assets/{include/SDL2/close_code.h → platform/include/SDL3/SDL_close_code.h} +9 -8
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_copying.h +3 -1
- data/assets/platform/include/SDL3/SDL_cpuinfo.h +374 -0
- data/assets/platform/include/SDL3/SDL_dialog.h +343 -0
- data/assets/platform/include/SDL3/SDL_dlopennote.h +234 -0
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_egl.h +11 -8
- data/assets/platform/include/SDL3/SDL_endian.h +645 -0
- data/assets/platform/include/SDL3/SDL_error.h +226 -0
- data/assets/platform/include/SDL3/SDL_events.h +1645 -0
- data/assets/platform/include/SDL3/SDL_filesystem.h +537 -0
- data/assets/platform/include/SDL3/SDL_gamepad.h +1656 -0
- data/assets/platform/include/SDL3/SDL_gpu.h +4608 -0
- data/assets/platform/include/SDL3/SDL_guid.h +106 -0
- data/assets/platform/include/SDL3/SDL_haptic.h +1461 -0
- data/assets/platform/include/SDL3/SDL_hidapi.h +571 -0
- data/assets/platform/include/SDL3/SDL_hints.h +5001 -0
- data/assets/platform/include/SDL3/SDL_init.h +507 -0
- data/assets/platform/include/SDL3/SDL_intrin.h +410 -0
- data/assets/platform/include/SDL3/SDL_iostream.h +1379 -0
- data/assets/platform/include/SDL3/SDL_joystick.h +1385 -0
- data/assets/platform/include/SDL3/SDL_keyboard.h +608 -0
- data/assets/platform/include/SDL3/SDL_keycode.h +347 -0
- data/assets/platform/include/SDL3/SDL_loadso.h +145 -0
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_locale.h +40 -24
- data/assets/platform/include/SDL3/SDL_log.h +541 -0
- data/assets/platform/include/SDL3/SDL_main.h +704 -0
- data/assets/platform/include/SDL3/SDL_main_impl.h +151 -0
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_messagebox.h +85 -48
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_metal.h +29 -29
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_misc.h +13 -12
- data/assets/platform/include/SDL3/SDL_mouse.h +813 -0
- data/assets/platform/include/SDL3/SDL_mutex.h +1117 -0
- data/assets/platform/include/SDL3/SDL_oldnames.h +1339 -0
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengl.h +1247 -278
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengl_glext.h +5 -1
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles.h +6 -7
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2.h +10 -11
- data/assets/platform/include/SDL3/SDL_pen.h +198 -0
- data/assets/platform/include/SDL3/SDL_pixels.h +1441 -0
- data/assets/{include/SDL2/SDL_test_log.h → platform/include/SDL3/SDL_platform.h} +25 -26
- data/assets/platform/include/SDL3/SDL_platform_defines.h +497 -0
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_power.h +40 -20
- data/assets/platform/include/SDL3/SDL_process.h +441 -0
- data/assets/platform/include/SDL3/SDL_properties.h +572 -0
- data/assets/platform/include/SDL3/SDL_rect.h +528 -0
- data/assets/platform/include/SDL3/SDL_render.h +3028 -0
- data/assets/platform/include/SDL3/SDL_revision.h +59 -0
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_scancode.h +59 -68
- data/assets/platform/include/SDL3/SDL_sensor.h +321 -0
- data/assets/platform/include/SDL3/SDL_stdinc.h +6186 -0
- data/assets/platform/include/SDL3/SDL_storage.h +686 -0
- data/assets/platform/include/SDL3/SDL_surface.h +1769 -0
- data/assets/platform/include/SDL3/SDL_system.h +840 -0
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test.h +16 -22
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_assert.h +27 -34
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_common.h +109 -52
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_compare.h +22 -14
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_crc32.h +27 -30
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_font.h +50 -49
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_fuzzer.h +64 -79
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_harness.h +47 -30
- data/assets/platform/include/SDL3/SDL_test_log.h +83 -0
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_md5.h +21 -28
- data/assets/{include/SDL2 → platform/include/SDL3}/SDL_test_memory.h +19 -16
- data/assets/platform/include/SDL3/SDL_thread.h +602 -0
- data/assets/platform/include/SDL3/SDL_time.h +249 -0
- data/assets/platform/include/SDL3/SDL_timer.h +454 -0
- data/assets/platform/include/SDL3/SDL_touch.h +184 -0
- data/assets/platform/include/SDL3/SDL_tray.h +544 -0
- data/assets/platform/include/SDL3/SDL_version.h +198 -0
- data/assets/platform/include/SDL3/SDL_video.h +3497 -0
- data/assets/platform/include/SDL3/SDL_vulkan.h +287 -0
- data/assets/platform/include/SDL3_image/SDL_image.h +3328 -0
- data/assets/platform/include/SDL3_mixer/SDL_mixer.h +3369 -0
- data/assets/platform/include/SDL3_ttf/SDL_textengine.h +181 -0
- data/assets/platform/include/SDL3_ttf/SDL_ttf.h +2833 -0
- data/assets/{include → platform/include}/mrbconf.h +42 -31
- data/assets/{include → platform/include}/mruby/array.h +3 -4
- data/assets/{include → platform/include}/mruby/boxing_nan.h +10 -0
- data/assets/platform/include/mruby/boxing_no.h +59 -0
- data/assets/{include → platform/include}/mruby/boxing_word.h +72 -26
- data/assets/platform/include/mruby/class.h +157 -0
- data/assets/{include → platform/include}/mruby/common.h +30 -1
- data/assets/{include → platform/include}/mruby/compile.h +52 -74
- data/assets/{include → platform/include}/mruby/data.h +2 -2
- data/assets/{include → platform/include}/mruby/debug.h +12 -5
- data/assets/{include → platform/include}/mruby/dump.h +7 -9
- data/assets/{include → platform/include}/mruby/endian.h +1 -1
- data/assets/platform/include/mruby/error.h +173 -0
- data/assets/platform/include/mruby/gc.h +79 -0
- data/assets/{include → platform/include}/mruby/hash.h +1 -7
- data/assets/platform/include/mruby/internal.h +282 -0
- data/assets/platform/include/mruby/irep.h +143 -0
- data/assets/{include → platform/include}/mruby/istruct.h +1 -1
- data/assets/platform/include/mruby/khash.h +455 -0
- data/assets/platform/include/mruby/mempool.h +19 -0
- data/assets/{include → platform/include}/mruby/numeric.h +7 -10
- data/assets/platform/include/mruby/object.h +51 -0
- data/assets/{include → platform/include}/mruby/opcode.h +5 -5
- data/assets/{include → platform/include}/mruby/ops.h +19 -6
- data/assets/platform/include/mruby/presym/id.h +1447 -0
- data/assets/{include → platform/include}/mruby/presym/scanning.h +10 -7
- data/assets/platform/include/mruby/presym/table.h +2893 -0
- data/assets/platform/include/mruby/presym.h +65 -0
- data/assets/platform/include/mruby/proc.h +184 -0
- data/assets/{include → platform/include}/mruby/range.h +0 -2
- data/assets/{include → platform/include}/mruby/string.h +33 -53
- data/assets/platform/include/mruby/throw.h +81 -0
- data/assets/{include → platform/include}/mruby/value.h +64 -29
- data/assets/{include → platform/include}/mruby/variable.h +6 -23
- data/assets/{include → platform/include}/mruby/version.h +7 -7
- data/assets/{include → platform/include}/mruby.h +238 -116
- data/assets/platform/macos-arm64/bin/mrbc +0 -0
- data/assets/platform/macos-arm64/lib/libSDL3.a +0 -0
- data/assets/platform/macos-arm64/lib/libSDL3_image.a +0 -0
- data/assets/platform/macos-arm64/lib/libSDL3_mixer.a +0 -0
- data/assets/platform/macos-arm64/lib/libSDL3_ttf.a +0 -0
- data/assets/platform/macos-arm64/lib/libmruby.a +0 -0
- data/assets/platform/wasm/lib/libFLAC.a +0 -0
- data/assets/platform/wasm/lib/libSDL3.a +0 -0
- data/assets/platform/wasm/lib/libSDL3_image.a +0 -0
- data/assets/platform/wasm/lib/libSDL3_mixer.a +0 -0
- data/assets/platform/wasm/lib/libSDL3_ttf.a +0 -0
- data/assets/platform/wasm/lib/libfreetype.a +0 -0
- data/assets/platform/wasm/lib/libharfbuzz.a +0 -0
- data/assets/platform/wasm/lib/libmruby.a +0 -0
- data/assets/platform/wasm/lib/libogg.a +0 -0
- data/assets/platform/wasm/lib/libplutosvg.a +0 -0
- data/assets/platform/wasm/lib/libplutovg.a +0 -0
- data/assets/platform/wasm/lib/libpng.a +0 -0
- data/assets/platform/wasm/lib/libpng16.a +0 -0
- data/assets/platform/wasm/lib/libvorbis.a +0 -0
- data/assets/platform/wasm/lib/libvorbisfile.a +0 -0
- data/assets/platform/wasm/lib/libzlibstatic.a +0 -0
- data/assets/platform/windows-arm64-mingw-ucrt/bin/mrbc.exe +0 -0
- data/assets/platform/windows-arm64-mingw-ucrt/lib/libSDL3.a +0 -0
- data/assets/platform/windows-arm64-mingw-ucrt/lib/libSDL3_image.a +0 -0
- data/assets/platform/windows-arm64-mingw-ucrt/lib/libSDL3_mixer.a +0 -0
- data/assets/platform/windows-arm64-mingw-ucrt/lib/libSDL3_ttf.a +0 -0
- data/assets/platform/windows-arm64-mingw-ucrt/lib/libmruby.a +0 -0
- data/assets/platform/windows-x86_64-mingw-ucrt/bin/mrbc.exe +0 -0
- data/assets/platform/windows-x86_64-mingw-ucrt/lib/libSDL3.a +0 -0
- data/assets/platform/windows-x86_64-mingw-ucrt/lib/libSDL3_image.a +0 -0
- data/assets/platform/windows-x86_64-mingw-ucrt/lib/libSDL3_mixer.a +0 -0
- data/assets/platform/windows-x86_64-mingw-ucrt/lib/libSDL3_ttf.a +0 -0
- data/assets/platform/windows-x86_64-mingw-ucrt/lib/libmruby.a +0 -0
- data/assets/resources/fonts/outfit/OFL.txt +93 -0
- data/assets/resources/fonts/outfit/outfit.ttf +0 -0
- data/assets/resources/fonts/roboto_mono/OFL.txt +91 -0
- data/assets/resources/fonts/roboto_mono/roboto_mono.ttf +0 -0
- data/assets/resources/icons/icon.icns +0 -0
- data/assets/resources/icons/icon.png +0 -0
- data/assets/resources/spritesheets/License.txt +28 -0
- data/assets/resources/spritesheets/spritesheet-backgrounds.png +0 -0
- data/assets/resources/spritesheets/spritesheet-backgrounds.xml +16 -0
- data/assets/resources/spritesheets/spritesheet-characters.png +0 -0
- data/assets/resources/spritesheets/spritesheet-characters.xml +47 -0
- data/assets/resources/spritesheets/spritesheet-enemies.png +0 -0
- data/assets/resources/spritesheets/spritesheet-enemies.xml +62 -0
- data/assets/resources/spritesheets/spritesheet-tiles.png +0 -0
- data/assets/resources/spritesheets/spritesheet-tiles.xml +316 -0
- data/assets/{wasm → resources/web}/template.html +1 -1
- data/assets/target.rb +131 -0
- data/bin/ruby2d +281 -82
- data/examples/astar.rb +269 -0
- data/examples/asteroids.rb +403 -0
- data/examples/bezier_editor.rb +96 -0
- data/examples/boids.rb +191 -0
- data/examples/bouncing_balls.rb +119 -0
- data/examples/breakout.rb +186 -0
- data/examples/constellations.rb +100 -0
- data/examples/dashboard.rb +133 -0
- data/examples/double_pendulum.rb +254 -0
- data/examples/falling_sand.rb +291 -0
- data/examples/fireworks.rb +110 -0
- data/examples/fluid_dynamics.rb +340 -0
- data/examples/fourier_epicycles.rb +142 -0
- data/examples/fractal_tree.rb +326 -0
- data/examples/game_of_life.rb +148 -0
- data/examples/gamepads.rb +333 -0
- data/examples/hill_driver.rb +613 -0
- data/examples/logo_animation.rb +251 -0
- data/examples/lorenz_attractor.rb +115 -0
- data/examples/mandelbrot.rb +207 -0
- data/examples/marching_squares.rb +200 -0
- data/examples/maze.rb +323 -0
- data/examples/nbody.rb +338 -0
- data/examples/outrun.rb +391 -0
- data/examples/pixel_paint.rb +313 -0
- data/examples/platformer.rb +335 -0
- data/examples/ray_casting_maze.rb +175 -0
- data/examples/shadow_casting.rb +151 -0
- data/examples/shape_recognizer.rb +908 -0
- data/examples/snake.rb +144 -0
- data/examples/sprite_sheets.rb +246 -0
- data/examples/swarm.rb +206 -0
- data/examples/tsp_annealing.rb +104 -0
- data/examples/ui_controls.rb +163 -0
- data/examples/wireframe_3d.rb +139 -0
- data/ext/ruby2d/audio.c +324 -0
- data/ext/ruby2d/canvas.c +1715 -494
- data/ext/ruby2d/ext.c +541 -0
- data/ext/ruby2d/extconf.rb +122 -145
- data/ext/ruby2d/font.c +566 -20
- data/ext/ruby2d/fps.c +92 -0
- data/ext/ruby2d/image.c +466 -41
- data/ext/ruby2d/ruby2d.c +374 -1890
- data/ext/ruby2d/ruby2d.h +840 -460
- data/ext/ruby2d/shapes.c +931 -101
- data/ext/ruby2d/text.c +586 -21
- data/ext/ruby2d/window.c +1693 -283
- data/lib/ruby2d/atlas_parser.rb +194 -0
- data/lib/ruby2d/audio.rb +73 -0
- data/lib/ruby2d/benchmark.rb +259 -0
- data/lib/ruby2d/bitmap_text.rb +155 -0
- data/lib/ruby2d/button.rb +402 -0
- data/lib/ruby2d/canvas.rb +703 -279
- data/lib/ruby2d/circle.rb +206 -29
- data/lib/ruby2d/cli/browser.rb +314 -0
- data/lib/ruby2d/cli/build.rb +471 -257
- data/lib/ruby2d/cli/colorize.rb +7 -5
- data/lib/ruby2d/cli/examples.rb +127 -0
- data/lib/ruby2d/cli/launch.rb +24 -39
- data/lib/ruby2d/cli/lib_files.rb +48 -0
- data/lib/ruby2d/cli/messages.rb +40 -0
- data/lib/ruby2d/cli/setup.rb +273 -0
- data/lib/ruby2d/cli/static_server.rb +160 -0
- data/lib/ruby2d/cli/usage.rb +255 -0
- data/lib/ruby2d/color.rb +191 -69
- data/lib/ruby2d/core.rb +37 -19
- data/lib/ruby2d/deps_help.rb +89 -0
- data/lib/ruby2d/dsl.rb +51 -12
- data/lib/ruby2d/ellipse.rb +228 -0
- data/lib/ruby2d/exceptions.rb +0 -2
- data/lib/ruby2d/font.rb +34 -74
- data/lib/ruby2d/gamepad.rb +323 -0
- data/lib/ruby2d/gem_paths.rb +19 -0
- data/lib/ruby2d/image.rb +155 -52
- data/lib/ruby2d/interactive.rb +103 -0
- data/lib/ruby2d/json_parser.rb +268 -0
- data/lib/ruby2d/line.rb +194 -85
- data/lib/ruby2d/mruby_compat.rb +12 -0
- data/lib/ruby2d/polygon.rb +297 -0
- data/lib/ruby2d/polyline.rb +368 -0
- data/lib/ruby2d/quad.rb +358 -94
- data/lib/ruby2d/rectangle.rb +77 -19
- data/lib/ruby2d/renderable.rb +411 -11
- data/lib/ruby2d/sprite.rb +471 -180
- data/lib/ruby2d/sprite_sheet.rb +64 -0
- data/lib/ruby2d/square.rb +29 -17
- data/lib/ruby2d/text.rb +196 -65
- data/lib/ruby2d/tileset.rb +139 -81
- data/lib/ruby2d/triangle.rb +324 -89
- data/lib/ruby2d/version.rb +1 -3
- data/lib/ruby2d/vertices.rb +62 -85
- data/lib/ruby2d/warnings.rb +29 -0
- data/lib/ruby2d/window/class_methods.rb +218 -0
- data/lib/ruby2d/window/gamepad_events.rb +141 -0
- data/lib/ruby2d/window/key_events.rb +74 -0
- data/lib/ruby2d/window/mouse_events.rb +171 -0
- data/lib/ruby2d/window/object_events.rb +168 -0
- data/lib/ruby2d/window.rb +632 -585
- data/lib/ruby2d.rb +14 -19
- metadata +275 -443
- data/assets/app.icns +0 -0
- data/assets/include/GL/glew.h +0 -26427
- data/assets/include/GLES2/gl2.h +0 -656
- data/assets/include/GLES2/gl2ext.h +0 -3949
- data/assets/include/GLES2/gl2ext_angle.h +0 -701
- data/assets/include/GLES2/gl2platform.h +0 -27
- data/assets/include/GLES3/gl3.h +0 -1192
- data/assets/include/GLES3/gl31.h +0 -1507
- data/assets/include/GLES3/gl32.h +0 -1808
- data/assets/include/GLES3/gl3platform.h +0 -27
- data/assets/include/KHR/khrplatform.h +0 -290
- data/assets/include/SDL2/SDL.h +0 -233
- data/assets/include/SDL2/SDL_assert.h +0 -326
- data/assets/include/SDL2/SDL_atomic.h +0 -415
- data/assets/include/SDL2/SDL_audio.h +0 -1500
- data/assets/include/SDL2/SDL_clipboard.h +0 -141
- data/assets/include/SDL2/SDL_config.h +0 -61
- data/assets/include/SDL2/SDL_config_android.h +0 -194
- data/assets/include/SDL2/SDL_config_emscripten.h +0 -218
- data/assets/include/SDL2/SDL_config_iphoneos.h +0 -217
- data/assets/include/SDL2/SDL_config_macosx.h +0 -277
- data/assets/include/SDL2/SDL_config_minimal.h +0 -95
- data/assets/include/SDL2/SDL_config_ngage.h +0 -89
- data/assets/include/SDL2/SDL_config_os2.h +0 -207
- data/assets/include/SDL2/SDL_config_pandora.h +0 -141
- data/assets/include/SDL2/SDL_config_windows.h +0 -331
- data/assets/include/SDL2/SDL_config_wingdk.h +0 -253
- data/assets/include/SDL2/SDL_config_winrt.h +0 -220
- data/assets/include/SDL2/SDL_config_xbox.h +0 -235
- data/assets/include/SDL2/SDL_cpuinfo.h +0 -594
- data/assets/include/SDL2/SDL_endian.h +0 -348
- data/assets/include/SDL2/SDL_error.h +0 -163
- data/assets/include/SDL2/SDL_events.h +0 -1166
- data/assets/include/SDL2/SDL_filesystem.h +0 -149
- data/assets/include/SDL2/SDL_gamecontroller.h +0 -1074
- data/assets/include/SDL2/SDL_gesture.h +0 -117
- data/assets/include/SDL2/SDL_guid.h +0 -100
- data/assets/include/SDL2/SDL_haptic.h +0 -1341
- data/assets/include/SDL2/SDL_hidapi.h +0 -451
- data/assets/include/SDL2/SDL_hints.h +0 -2569
- data/assets/include/SDL2/SDL_image.h +0 -2173
- data/assets/include/SDL2/SDL_joystick.h +0 -1066
- data/assets/include/SDL2/SDL_keyboard.h +0 -353
- data/assets/include/SDL2/SDL_keycode.h +0 -358
- data/assets/include/SDL2/SDL_loadso.h +0 -115
- data/assets/include/SDL2/SDL_log.h +0 -404
- data/assets/include/SDL2/SDL_main.h +0 -275
- data/assets/include/SDL2/SDL_mixer.h +0 -2784
- data/assets/include/SDL2/SDL_mouse.h +0 -465
- data/assets/include/SDL2/SDL_mutex.h +0 -471
- data/assets/include/SDL2/SDL_name.h +0 -33
- data/assets/include/SDL2/SDL_pixels.h +0 -644
- data/assets/include/SDL2/SDL_platform.h +0 -261
- data/assets/include/SDL2/SDL_quit.h +0 -58
- data/assets/include/SDL2/SDL_rect.h +0 -376
- data/assets/include/SDL2/SDL_render.h +0 -1919
- data/assets/include/SDL2/SDL_revision.h +0 -6
- data/assets/include/SDL2/SDL_rwops.h +0 -841
- data/assets/include/SDL2/SDL_sensor.h +0 -322
- data/assets/include/SDL2/SDL_shape.h +0 -155
- data/assets/include/SDL2/SDL_stdinc.h +0 -830
- data/assets/include/SDL2/SDL_surface.h +0 -997
- data/assets/include/SDL2/SDL_system.h +0 -623
- data/assets/include/SDL2/SDL_syswm.h +0 -386
- data/assets/include/SDL2/SDL_test_images.h +0 -78
- data/assets/include/SDL2/SDL_test_random.h +0 -115
- data/assets/include/SDL2/SDL_thread.h +0 -464
- data/assets/include/SDL2/SDL_timer.h +0 -222
- data/assets/include/SDL2/SDL_touch.h +0 -150
- data/assets/include/SDL2/SDL_ttf.h +0 -2316
- data/assets/include/SDL2/SDL_types.h +0 -29
- data/assets/include/SDL2/SDL_version.h +0 -204
- data/assets/include/SDL2/SDL_video.h +0 -2150
- data/assets/include/SDL2/SDL_vulkan.h +0 -215
- data/assets/include/SDL2/begin_code.h +0 -187
- data/assets/include/mruby/boxing_no.h +0 -58
- data/assets/include/mruby/class.h +0 -108
- data/assets/include/mruby/error.h +0 -147
- data/assets/include/mruby/gc.h +0 -94
- data/assets/include/mruby/irep.h +0 -147
- data/assets/include/mruby/khash.h +0 -284
- data/assets/include/mruby/object.h +0 -43
- data/assets/include/mruby/presym/disable.h +0 -70
- data/assets/include/mruby/presym/enable.h +0 -37
- data/assets/include/mruby/presym.h +0 -40
- data/assets/include/mruby/proc.h +0 -211
- data/assets/include/mruby/throw.h +0 -66
- data/assets/macos/universal/bin/mrbc +0 -0
- data/assets/macos/universal/lib/libFLAC.a +0 -0
- data/assets/macos/universal/lib/libSDL2.a +0 -0
- data/assets/macos/universal/lib/libSDL2_image.a +0 -0
- data/assets/macos/universal/lib/libSDL2_mixer.a +0 -0
- data/assets/macos/universal/lib/libSDL2_ttf.a +0 -0
- data/assets/macos/universal/lib/libavif.a +0 -0
- data/assets/macos/universal/lib/libbrotlicommon-static.a +0 -0
- data/assets/macos/universal/lib/libbrotlidec-static.a +0 -0
- data/assets/macos/universal/lib/libfreetype.a +0 -0
- data/assets/macos/universal/lib/libgraphite2.a +0 -0
- data/assets/macos/universal/lib/libharfbuzz.a +0 -0
- data/assets/macos/universal/lib/libhwy.a +0 -0
- data/assets/macos/universal/lib/libjpeg.a +0 -0
- data/assets/macos/universal/lib/libjxl.a +0 -0
- data/assets/macos/universal/lib/libmodplug.a +0 -0
- data/assets/macos/universal/lib/libmpg123.a +0 -0
- data/assets/macos/universal/lib/libmruby.a +0 -0
- data/assets/macos/universal/lib/libogg.a +0 -0
- data/assets/macos/universal/lib/libpng.a +0 -0
- data/assets/macos/universal/lib/libtiff.a +0 -0
- data/assets/macos/universal/lib/libvorbis.a +0 -0
- data/assets/macos/universal/lib/libvorbisfile.a +0 -0
- data/assets/macos/universal/lib/libwebp.a +0 -0
- data/assets/macos/universal/lib/libzstd.a +0 -0
- data/assets/test_media/README.md +0 -3
- data/assets/test_media/bitstream_vera/COPYRIGHT.txt +0 -124
- data/assets/test_media/bitstream_vera/vera.ttf +0 -0
- data/assets/test_media/boom.png +0 -0
- data/assets/test_media/coin.png +0 -0
- data/assets/test_media/colors.png +0 -0
- data/assets/test_media/controller.png +0 -0
- data/assets/test_media/dial.wav +0 -0
- data/assets/test_media/hero.png +0 -0
- data/assets/test_media/image.bmp +0 -0
- data/assets/test_media/image.jpg +0 -0
- data/assets/test_media/image.png +0 -0
- data/assets/test_media/music.flac +0 -0
- data/assets/test_media/music.mp3 +0 -0
- data/assets/test_media/music.ogg +0 -0
- data/assets/test_media/music.wav +0 -0
- data/assets/test_media/originals/boom.pxm +0 -0
- data/assets/test_media/originals/coin.pxm +0 -0
- data/assets/test_media/originals/controller.sketch +0 -0
- data/assets/test_media/originals/hero.pxm +0 -0
- data/assets/test_media/originals/image.pxm +0 -0
- data/assets/test_media/originals/music.caf +0 -0
- data/assets/test_media/originals/texture_atlas.pxm +0 -0
- data/assets/test_media/rondo_alla_turka.ogg +0 -0
- data/assets/test_media/sound.flac +0 -0
- data/assets/test_media/sound.mp3 +0 -0
- data/assets/test_media/sound.ogg +0 -0
- data/assets/test_media/sound.wav +0 -0
- data/assets/test_media/sprite_sheet.png +0 -0
- data/assets/test_media/texture_atlas.png +0 -0
- data/assets/wasm/libmruby.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/bin/mrbc.exe +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libFLAC.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libLerc.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libSDL2.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libSDL2_image.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libSDL2_mixer.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libSDL2_ttf.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libbrotlicommon.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libbrotlidec.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libbz2.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libdeflate.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libfreetype.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libglew32.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libgraphite2.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libharfbuzz.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libhwy.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libjbig.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libjpeg.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libjxl.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/liblzma.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libmodplug.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libmpg123.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libmruby.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libogg.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libopus.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libopusfile.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libpng.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libsndfile.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libssp.a +0 -1
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libstdc++.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libtiff.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libvorbis.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libvorbisfile.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libwebp.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libz.a +0 -0
- data/assets/windows/mingw-w64-ucrt-x86_64/lib/libzstd.a +0 -0
- data/assets/windows/mingw-w64-x86_64/bin/mrbc.exe +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libFLAC.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libLerc.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libSDL2.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libSDL2_image.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libSDL2_mixer.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libSDL2_ttf.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libbrotlicommon.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libbrotlidec.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libbz2.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libdeflate.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libfreetype.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libglew32.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libgraphite2.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libharfbuzz.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libhwy.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libjbig.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libjpeg.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libjxl.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/liblzma.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libmodplug.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libmpg123.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libmruby.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libogg.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libopus.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libopusfile.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libpng.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libsndfile.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libssp.a +0 -1
- data/assets/windows/mingw-w64-x86_64/lib/libstdc++.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libtiff.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libvorbis.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libvorbisfile.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libwebp.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libz.a +0 -0
- data/assets/windows/mingw-w64-x86_64/lib/libzstd.a +0 -0
- data/assets/xcode/ios/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -98
- data/assets/xcode/ios/Assets.xcassets/Contents.json +0 -6
- data/assets/xcode/ios/Base.lproj/LaunchScreen.storyboard +0 -27
- data/assets/xcode/ios/Info.plist +0 -43
- data/assets/xcode/ios/MRuby.framework/Headers/mrbconf.h +0 -143
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/array.h +0 -280
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/boxing_nan.h +0 -102
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/boxing_no.h +0 -56
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/boxing_word.h +0 -144
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/class.h +0 -97
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/common.h +0 -77
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/compile.h +0 -195
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/data.h +0 -75
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/debug.h +0 -67
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/dump.h +0 -196
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/error.h +0 -75
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/gc.h +0 -91
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/hash.h +0 -215
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/irep.h +0 -75
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/istruct.h +0 -47
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/khash.h +0 -274
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/numeric.h +0 -161
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/object.h +0 -44
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/opcode.h +0 -69
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/ops.h +0 -117
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/proc.h +0 -131
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/range.h +0 -49
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/re.h +0 -16
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/string.h +0 -444
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/throw.h +0 -55
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/value.h +0 -309
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/variable.h +0 -136
- data/assets/xcode/ios/MRuby.framework/Headers/mruby/version.h +0 -110
- data/assets/xcode/ios/MRuby.framework/Headers/mruby.h +0 -1282
- data/assets/xcode/ios/MRuby.framework/Info.plist +0 -20
- data/assets/xcode/ios/MRuby.framework/MRuby +0 -0
- data/assets/xcode/ios/MyApp.xcodeproj/project.pbxproj +0 -368
- data/assets/xcode/ios/MyApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- data/assets/xcode/ios/MyApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- data/assets/xcode/ios/MyApp.xcodeproj/project.xcworkspace/xcshareddata/MyApp.xcscmblueprint +0 -30
- data/assets/xcode/ios/main.c +0 -1
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json +0 -16
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json +0 -6
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json +0 -17
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json +0 -16
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json +0 -6
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json +0 -16
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json +0 -6
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json +0 -16
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json +0 -6
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json +0 -17
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json +0 -16
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json +0 -6
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json +0 -16
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json +0 -6
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json +0 -32
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json +0 -16
- data/assets/xcode/tvos/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json +0 -16
- data/assets/xcode/tvos/Assets.xcassets/Contents.json +0 -6
- data/assets/xcode/tvos/Assets.xcassets/LaunchImage.launchimage/Contents.json +0 -22
- data/assets/xcode/tvos/Info.plist +0 -30
- data/assets/xcode/tvos/MRuby.framework/Headers/mrbconf.h +0 -143
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/array.h +0 -280
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/boxing_nan.h +0 -102
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/boxing_no.h +0 -56
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/boxing_word.h +0 -144
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/class.h +0 -97
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/common.h +0 -77
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/compile.h +0 -195
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/data.h +0 -75
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/debug.h +0 -67
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/dump.h +0 -196
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/error.h +0 -75
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/gc.h +0 -91
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/hash.h +0 -215
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/irep.h +0 -75
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/istruct.h +0 -47
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/khash.h +0 -274
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/numeric.h +0 -161
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/object.h +0 -44
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/opcode.h +0 -69
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/ops.h +0 -117
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/proc.h +0 -131
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/range.h +0 -49
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/re.h +0 -16
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/string.h +0 -444
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/throw.h +0 -55
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/value.h +0 -309
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/variable.h +0 -136
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby/version.h +0 -110
- data/assets/xcode/tvos/MRuby.framework/Headers/mruby.h +0 -1282
- data/assets/xcode/tvos/MRuby.framework/Info.plist +0 -20
- data/assets/xcode/tvos/MRuby.framework/MRuby +0 -0
- data/assets/xcode/tvos/MyApp.xcodeproj/project.pbxproj +0 -350
- data/assets/xcode/tvos/MyApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- data/assets/xcode/tvos/MyApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- data/assets/xcode/tvos/MyApp.xcodeproj/project.xcworkspace/xcshareddata/MyApp.xcscmblueprint +0 -30
- data/assets/xcode/tvos/main.c +0 -1
- data/ext/ruby2d/common.c +0 -185
- data/ext/ruby2d/controllers.c +0 -110
- data/ext/ruby2d/gl.c +0 -398
- data/ext/ruby2d/gl2.c +0 -86
- data/ext/ruby2d/gl3.c +0 -304
- data/ext/ruby2d/gles.c +0 -302
- data/ext/ruby2d/input.c +0 -48
- data/ext/ruby2d/music.c +0 -127
- data/ext/ruby2d/sound.c +0 -132
- data/lib/ruby2d/cli/console.rb +0 -65
- data/lib/ruby2d/cli/enable_console.rb +0 -7
- data/lib/ruby2d/cli/platform.rb +0 -17
- data/lib/ruby2d/music.rb +0 -77
- data/lib/ruby2d/pixel.rb +0 -18
- data/lib/ruby2d/pixmap.rb +0 -39
- data/lib/ruby2d/pixmap_atlas.rb +0 -56
- data/lib/ruby2d/sound.rb +0 -61
- data/lib/ruby2d/texture.rb +0 -38
- /data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2_gl2.h +0 -0
- /data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2_gl2ext.h +0 -0
- /data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2_gl2platform.h +0 -0
- /data/assets/{include/SDL2 → platform/include/SDL3}/SDL_opengles2_khrplatform.h +0 -0
- /data/assets/{include → platform/include}/mruby/re.h +0 -0
data/lib/ruby2d/window.rb
CHANGED
|
@@ -1,30 +1,56 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
1
|
# Ruby2D::Window
|
|
4
2
|
|
|
5
3
|
module Ruby2D
|
|
6
|
-
#
|
|
7
|
-
# event handlers, the update loop, showing and closing the window.
|
|
8
|
-
|
|
9
|
-
attr_reader :width, :height
|
|
10
|
-
|
|
4
|
+
# The application window
|
|
11
5
|
class Window
|
|
12
6
|
# Event structures
|
|
13
7
|
EventDescriptor = Struct.new(:type, :id)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
ObjectEventDescriptor = Struct.new(:object, :type, :id)
|
|
9
|
+
MouseEvent = Struct.new(:type, :button, :direction, :x, :y, :delta_x, :delta_y) do
|
|
10
|
+
def button?(name) = button == name
|
|
11
|
+
def position = [x, y]
|
|
12
|
+
def delta = [delta_x, delta_y]
|
|
13
|
+
end
|
|
14
|
+
KeyEvent = Struct.new(:type, :key) do
|
|
15
|
+
def key?(name) = key == name.to_s.downcase
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
include KeyEvents
|
|
19
|
+
include MouseEvents
|
|
20
|
+
include GamepadEvents
|
|
21
|
+
include ObjectEventDispatch
|
|
22
|
+
extend ClassMethods
|
|
23
|
+
|
|
24
|
+
attr_reader :title, :width, :height, :fps_cap, :fps, :frames, :delta_time,
|
|
25
|
+
:background, :icon, :resizable,
|
|
26
|
+
:highdpi, :pixel_scale,
|
|
27
|
+
:viewport_width, :viewport_height, :viewport_mode,
|
|
28
|
+
:render_mode,
|
|
29
|
+
:mouse_x, :mouse_y, :diagnostics, :show_fps, :close_on_esc
|
|
30
|
+
|
|
31
|
+
# Accepted `fps_cap` values, shared by the strict constructor check and the
|
|
32
|
+
# lenient runtime setter so the two messages can't drift apart.
|
|
33
|
+
FPS_CAP_VALUES = 'nil, a positive number, :infinity, or Float::INFINITY'
|
|
34
|
+
|
|
35
|
+
# Recognized `viewport:` modes. The native parser silently falls back to
|
|
36
|
+
# letterbox for anything else, so validate here to surface typos rather than
|
|
37
|
+
# let `viewport_mode` report a value the renderer never applied. Must match
|
|
38
|
+
# R2D_ParseViewportMode in ext/ruby2d/window.c.
|
|
39
|
+
VIEWPORT_MODES = %i[letterbox stretch integer overscan expand fixed].freeze
|
|
40
|
+
|
|
41
|
+
# Create a window
|
|
42
|
+
def initialize(title: 'Ruby 2D', width: 640, height: 480, fps_cap: nil)
|
|
43
|
+
# Ruby 2D is single-window by design: per-object events and the top-level
|
|
44
|
+
# DSL all route through one shared `DSL.window`. A second window would
|
|
45
|
+
# silently steal that pointer and strand the first window's objects and
|
|
46
|
+
# event handlers, so refuse to create one.
|
|
47
|
+
if Ruby2D::DSL.window?
|
|
48
|
+
raise Error,
|
|
49
|
+
'A window already exists. Ruby 2D supports a single window per ' \
|
|
50
|
+
'process (it may have been created automatically on first use of ' \
|
|
51
|
+
'a Window class method or the top-level DSL).'
|
|
52
|
+
end
|
|
19
53
|
|
|
20
|
-
#
|
|
21
|
-
# Create a Window
|
|
22
|
-
# @param title [String] Title for the window
|
|
23
|
-
# @param width [Numeric] In pixels
|
|
24
|
-
# @param height [Numeric] in pixels
|
|
25
|
-
# @param fps_cap [Numeric] Over-ride the default (60fps) frames-per-second
|
|
26
|
-
# @param vsync [Boolean] Enabled by default, use this to override it (Not recommended)
|
|
27
|
-
def initialize(title: 'Ruby 2D', width: 640, height: 480, fps_cap: 60, vsync: true)
|
|
28
54
|
# Title of the window
|
|
29
55
|
@title = title
|
|
30
56
|
|
|
@@ -32,246 +58,128 @@ module Ruby2D
|
|
|
32
58
|
@width = width
|
|
33
59
|
@height = height
|
|
34
60
|
|
|
35
|
-
# Frames per second upper limit, and the actual FPS
|
|
61
|
+
# Frames per second upper limit, and the actual FPS. Valid: nil (no cap),
|
|
62
|
+
# a positive number, or Float::INFINITY (uncapped). The constructor is
|
|
63
|
+
# strict; the runtime setter (#set) warns and falls back instead.
|
|
64
|
+
fps_cap = normalize_fps_cap(fps_cap)
|
|
65
|
+
unless fps_cap_valid?(fps_cap)
|
|
66
|
+
raise Error, "fps_cap must be #{FPS_CAP_VALUES}, got #{fps_cap.inspect}"
|
|
67
|
+
end
|
|
36
68
|
@fps_cap = fps_cap
|
|
37
|
-
@fps =
|
|
38
|
-
|
|
39
|
-
# Vertical synchronization, set to prevent screen tearing (recommended)
|
|
40
|
-
@vsync = vsync
|
|
69
|
+
@fps = 0
|
|
41
70
|
|
|
42
71
|
# Total number of frames that have been rendered
|
|
43
72
|
@frames = 0
|
|
44
73
|
|
|
74
|
+
# Whether the frame loop is running, i.e. between `show` and the window
|
|
75
|
+
# closing. Frame-scoped work like `screenshot` needs an end-of-frame to
|
|
76
|
+
# land on, so it consults this rather than doing nothing at all.
|
|
77
|
+
@running = false
|
|
78
|
+
|
|
45
79
|
# Renderable objects currently in the window, like a linear scene graph
|
|
46
80
|
@objects = []
|
|
81
|
+
@object_set = {}
|
|
47
82
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Track open window state in a class instance variable
|
|
55
|
-
@open_window = false
|
|
56
|
-
|
|
57
|
-
# Class methods for convenient access to properties
|
|
58
|
-
class << self
|
|
59
|
-
def current
|
|
60
|
-
get(:window)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def title
|
|
64
|
-
get(:title)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def background
|
|
68
|
-
get(:background)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def width
|
|
72
|
-
get(:width)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def height
|
|
76
|
-
get(:height)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def viewport_width
|
|
80
|
-
get(:viewport_width)
|
|
81
|
-
end
|
|
83
|
+
init_window_defaults
|
|
84
|
+
init_event_stores
|
|
85
|
+
init_event_registrations
|
|
86
|
+
init_procs_and_dsl
|
|
82
87
|
|
|
83
|
-
|
|
84
|
-
get(:viewport_height)
|
|
85
|
-
end
|
|
88
|
+
Ext.window_create(self)
|
|
86
89
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def display_height
|
|
92
|
-
get(:display_height)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def resizable
|
|
96
|
-
get(:resizable)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def borderless
|
|
100
|
-
get(:borderless)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def fullscreen
|
|
104
|
-
get(:fullscreen)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def highdpi
|
|
108
|
-
get(:highdpi)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def frames
|
|
112
|
-
get(:frames)
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def fps
|
|
116
|
-
get(:fps)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def fps_cap
|
|
120
|
-
get(:fps_cap)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def mouse_x
|
|
124
|
-
get(:mouse_x)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def mouse_y
|
|
128
|
-
get(:mouse_y)
|
|
129
|
-
end
|
|
90
|
+
Ruby2D::DSL.window = self
|
|
91
|
+
end
|
|
130
92
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
end
|
|
93
|
+
# Track window shown state in a class instance variable
|
|
94
|
+
@shown = false
|
|
134
95
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def get(sym, opts = nil)
|
|
140
|
-
DSL.window.get(sym, opts)
|
|
141
|
-
end
|
|
96
|
+
class << self
|
|
97
|
+
attr_reader :shown
|
|
98
|
+
alias_method :shown?, :shown
|
|
142
99
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
end
|
|
100
|
+
attr_writer :shown
|
|
101
|
+
end
|
|
146
102
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
103
|
+
def display_width
|
|
104
|
+
Ext.window_get_display_dimensions(self)
|
|
105
|
+
@display_width
|
|
106
|
+
end
|
|
150
107
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
108
|
+
def display_height
|
|
109
|
+
Ext.window_get_display_dimensions(self)
|
|
110
|
+
@display_height
|
|
111
|
+
end
|
|
154
112
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
113
|
+
def display_pixel_width
|
|
114
|
+
Ext.window_get_display_dimensions(self)
|
|
115
|
+
@display_pixel_width
|
|
116
|
+
end
|
|
158
117
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
118
|
+
def display_pixel_height
|
|
119
|
+
Ext.window_get_display_dimensions(self)
|
|
120
|
+
@display_pixel_height
|
|
121
|
+
end
|
|
162
122
|
|
|
163
|
-
|
|
164
|
-
|
|
123
|
+
# Get a window attribute by name. `:window` returns the Window itself (the
|
|
124
|
+
# DSL escape hatch to the full API); any other symbol reads that attribute.
|
|
125
|
+
def get(sym)
|
|
126
|
+
case sym
|
|
127
|
+
when :window then self
|
|
128
|
+
else public_send(sym)
|
|
165
129
|
end
|
|
130
|
+
end
|
|
166
131
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
132
|
+
# Set window attributes
|
|
133
|
+
def set(opts)
|
|
134
|
+
# Store new window attributes, or ignore if nil
|
|
135
|
+
set_any_window_properties opts
|
|
136
|
+
set_any_window_dimensions opts
|
|
170
137
|
|
|
171
|
-
|
|
172
|
-
DSL.window.render(&proc)
|
|
173
|
-
end
|
|
138
|
+
Ext.window_set_size(self) if Window.shown? && (opts[:width] || opts[:height])
|
|
174
139
|
|
|
175
|
-
|
|
176
|
-
|
|
140
|
+
if Window.shown? && (opts[:viewport] || opts[:viewport_width] || opts[:viewport_height] || !opts[:pixel_scale].nil?)
|
|
141
|
+
Ext.window_set_viewport_mode(self)
|
|
177
142
|
end
|
|
178
143
|
|
|
179
|
-
|
|
180
|
-
|
|
144
|
+
if opts.key?(:fps_cap)
|
|
145
|
+
cap = normalize_fps_cap(opts[:fps_cap])
|
|
146
|
+
if fps_cap_valid?(cap)
|
|
147
|
+
@fps_cap = cap
|
|
148
|
+
else
|
|
149
|
+
Ruby2D.warn "fps_cap must be #{FPS_CAP_VALUES}, got #{opts[:fps_cap].inspect}; ignoring (no cap)."
|
|
150
|
+
@fps_cap = nil
|
|
151
|
+
end
|
|
152
|
+
Ext.window_set_fps_cap(self, @fps_cap) if Window.shown?
|
|
181
153
|
end
|
|
182
154
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
155
|
+
unless opts[:render_mode].nil?
|
|
156
|
+
unless %i[continuous on_demand].include?(opts[:render_mode])
|
|
157
|
+
raise Error, "`render_mode` must be :continuous or :on_demand, got #{opts[:render_mode].inspect}"
|
|
158
|
+
end
|
|
159
|
+
@render_mode = opts[:render_mode]
|
|
160
|
+
Ext.window_set_render_mode(self) if Window.shown?
|
|
188
161
|
end
|
|
189
162
|
|
|
190
|
-
|
|
191
|
-
@open_window
|
|
192
|
-
end
|
|
163
|
+
@close_on_esc = opts[:close_on_esc] unless opts[:close_on_esc].nil?
|
|
193
164
|
|
|
194
|
-
|
|
165
|
+
self.cursor = opts[:cursor] unless opts[:cursor].nil?
|
|
195
166
|
|
|
196
|
-
|
|
197
|
-
@
|
|
167
|
+
unless opts[:show_fps].nil?
|
|
168
|
+
@show_fps = opts[:show_fps]
|
|
169
|
+
Ext.window_show_fps(self, @show_fps)
|
|
198
170
|
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
# Public instance methods
|
|
202
171
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
207
|
-
# rubocop:disable Metrics/AbcSize
|
|
208
|
-
|
|
209
|
-
# Retrieve an attribute of the window
|
|
210
|
-
# @param sym [Symbol] The name of an attribute to retrieve.
|
|
211
|
-
def get(sym, opts = nil)
|
|
212
|
-
case sym
|
|
213
|
-
when :window then self
|
|
214
|
-
when :title then @title
|
|
215
|
-
when :background then @background
|
|
216
|
-
when :width then @width
|
|
217
|
-
when :height then @height
|
|
218
|
-
when :viewport_width then @viewport_width
|
|
219
|
-
when :viewport_height then @viewport_height
|
|
220
|
-
when :display_width, :display_height
|
|
221
|
-
ext_get_display_dimensions
|
|
222
|
-
if sym == :display_width
|
|
223
|
-
@display_width
|
|
224
|
-
else
|
|
225
|
-
@display_height
|
|
226
|
-
end
|
|
227
|
-
when :resizable then @resizable
|
|
228
|
-
when :borderless then @borderless
|
|
229
|
-
when :fullscreen then @fullscreen
|
|
230
|
-
when :highdpi then @highdpi
|
|
231
|
-
when :frames then @frames
|
|
232
|
-
when :fps then @fps
|
|
233
|
-
when :fps_cap then @fps_cap
|
|
234
|
-
when :mouse_x then @mouse_x
|
|
235
|
-
when :mouse_y then @mouse_y
|
|
236
|
-
when :diagnostics then @diagnostics
|
|
237
|
-
when :screenshot then screenshot(opts)
|
|
172
|
+
unless opts[:diagnostics].nil?
|
|
173
|
+
@diagnostics = opts[:diagnostics]
|
|
174
|
+
Ext.window_diagnostics(self, @diagnostics)
|
|
238
175
|
end
|
|
239
176
|
end
|
|
240
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
241
|
-
# rubocop:enable Metrics/AbcSize
|
|
242
|
-
# --- end exception
|
|
243
|
-
|
|
244
|
-
# Set a window attribute
|
|
245
|
-
# @param opts [Hash] The attributes to set
|
|
246
|
-
# @option opts [Color] :background
|
|
247
|
-
# @option opts [String] :title
|
|
248
|
-
# @option opts [Numeric] :width
|
|
249
|
-
# @option opts [Numeric] :height
|
|
250
|
-
# @option opts [Numeric] :viewport_width
|
|
251
|
-
# @option opts [Numeric] :viewport_height
|
|
252
|
-
# @option opts [Boolean] :highdpi
|
|
253
|
-
# @option opts [Boolean] :resizable
|
|
254
|
-
# @option opts [Boolean] :borderless
|
|
255
|
-
# @option opts [Boolean] :fullscreen
|
|
256
|
-
# @option opts [Numeric] :fps_cap
|
|
257
|
-
# @option opts [Numeric] :diagnostics
|
|
258
|
-
def set(opts)
|
|
259
|
-
# Store new window attributes, or ignore if nil
|
|
260
|
-
_set_any_window_properties opts
|
|
261
|
-
_set_any_window_dimensions opts
|
|
262
|
-
|
|
263
|
-
@fps_cap = opts[:fps_cap] if opts[:fps_cap]
|
|
264
|
-
return if opts[:diagnostics].nil?
|
|
265
|
-
|
|
266
|
-
@diagnostics = opts[:diagnostics]
|
|
267
|
-
ext_diagnostics(@diagnostics)
|
|
268
|
-
end
|
|
269
177
|
|
|
270
178
|
# Add an object to the window
|
|
271
179
|
def add(object)
|
|
272
180
|
case object
|
|
273
181
|
when nil
|
|
274
|
-
raise Error, "Cannot add
|
|
182
|
+
raise Error, "Cannot add `#{object.class}` to window!"
|
|
275
183
|
when Array
|
|
276
184
|
object.each { |x| add_object(x) }
|
|
277
185
|
else
|
|
@@ -281,425 +189,556 @@ module Ruby2D
|
|
|
281
189
|
|
|
282
190
|
# Remove an object from the window
|
|
283
191
|
def remove(object)
|
|
284
|
-
raise Error, "Cannot remove
|
|
192
|
+
raise Error, "Cannot remove `#{object.class}` from window!" if object.nil?
|
|
193
|
+
return false unless @objects.delete(object)
|
|
285
194
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
@objects.delete_at(ix)
|
|
195
|
+
@object_set.delete(object)
|
|
196
|
+
unregister_interactive(object)
|
|
290
197
|
true
|
|
291
198
|
end
|
|
292
199
|
|
|
293
200
|
# Clear all objects from the window
|
|
294
201
|
def clear
|
|
295
202
|
@objects.clear
|
|
203
|
+
@object_set.clear
|
|
204
|
+
init_object_event_stores
|
|
296
205
|
end
|
|
297
206
|
|
|
298
207
|
# Set the update callback
|
|
299
208
|
def update(&proc)
|
|
209
|
+
raise Error, '`update` requires a block' unless proc
|
|
300
210
|
@update_proc = proc
|
|
211
|
+
# Cache whether the block takes a delta-time arg; the arity never changes
|
|
212
|
+
# after assignment, so the per-frame loop reads this instead of recomputing.
|
|
213
|
+
@update_wants_dt = !proc.arity.zero?
|
|
301
214
|
true
|
|
302
215
|
end
|
|
303
216
|
|
|
304
|
-
# Set the render callback
|
|
305
|
-
|
|
217
|
+
# Set the render callback. `z:` places the block in the scene's z-order:
|
|
218
|
+
# `:foreground` (default) draws it on top of every object, `:background`
|
|
219
|
+
# behind them, or a number interleaves it at that depth on the same scale
|
|
220
|
+
# as object `z` (objects with `z` at or below it draw first, then the
|
|
221
|
+
# block, then the rest).
|
|
222
|
+
def render(z: :foreground, &proc)
|
|
223
|
+
raise Error, '`render` requires a block' unless proc
|
|
306
224
|
@render_proc = proc
|
|
225
|
+
@render_z = render_z_for(z)
|
|
307
226
|
true
|
|
308
227
|
end
|
|
309
228
|
|
|
310
|
-
#
|
|
311
|
-
|
|
312
|
-
|
|
229
|
+
# Monotonic seconds since engine start — a cross-platform, overflow-safe
|
|
230
|
+
# clock for cooldowns, scheduling, and "time since" math. Unlike `Time.now`
|
|
231
|
+
# it never jumps or jitters, and reads the same on CRuby and mruby/web.
|
|
232
|
+
# For per-frame motion, prefer the `dt` argument to `update`.
|
|
233
|
+
def elapsed
|
|
234
|
+
Ext.now
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Maps event types to the predicate used in the kwarg form of `on` —
|
|
238
|
+
# e.g. `on key_down: :escape` filters via `event.key?(:escape)`. For
|
|
239
|
+
# gamepad events the entries map to the *primary* predicate (the one a
|
|
240
|
+
# bare scalar matcher targets); hash matchers like
|
|
241
|
+
# `{ gamepad: pad1, button: :south }` derive the predicate from each key.
|
|
242
|
+
EVENT_FILTER_PREDICATES = {
|
|
243
|
+
key_down: :key?, key_held: :key?, key_up: :key?,
|
|
244
|
+
mouse_down: :button?, mouse_held: :button?, mouse_up: :button?,
|
|
245
|
+
gamepad_button_down: :button?, gamepad_button_held: :button?,
|
|
246
|
+
gamepad_button_up: :button?, gamepad_axis: :axis?
|
|
247
|
+
}.freeze
|
|
248
|
+
|
|
249
|
+
# Gamepad events dispatch an internal data struct, but user blocks
|
|
250
|
+
# receive the unpacked args (gamepad / button / axis / value). This map
|
|
251
|
+
# describes the unpack for each gamepad event type.
|
|
252
|
+
GAMEPAD_EVENT_UNPACK = {
|
|
253
|
+
gamepad_connect: ->(d) { [d.gamepad] },
|
|
254
|
+
gamepad_disconnect: ->(d) { [d.gamepad] },
|
|
255
|
+
gamepad_button_down: ->(d) { [d.gamepad, d.button] },
|
|
256
|
+
gamepad_button_held: ->(d) { [d.gamepad, d.button] },
|
|
257
|
+
gamepad_button_up: ->(d) { [d.gamepad, d.button] },
|
|
258
|
+
gamepad_axis: ->(d) { [d.gamepad, d.axis, d.value] }
|
|
259
|
+
}.freeze
|
|
260
|
+
|
|
261
|
+
# Set an event handler. Forms:
|
|
262
|
+
#
|
|
263
|
+
# on(:key_down) { |event| ... } # all events of type
|
|
264
|
+
# on(key_down: :escape) { ... } # filtered by value
|
|
265
|
+
# on(key_down: [:left, :a]) { ... } # array → match any
|
|
266
|
+
# on(key_down: :left, gamepad_button_down: :dpad_left) { } # multi-event
|
|
267
|
+
# on(gamepad_button_down: { gamepad: pad1, button: :south }) # hash → AND match
|
|
268
|
+
def on(event = nil, **filters, &proc)
|
|
269
|
+
raise Error, '`on` requires a block' unless proc
|
|
270
|
+
if event.is_a?(Symbol) && filters.empty?
|
|
271
|
+
register_event_handler(event, wrap_for_event(event, proc))
|
|
272
|
+
elsif event.nil? && !filters.empty?
|
|
273
|
+
descriptors = filters.map do |type, matcher|
|
|
274
|
+
register_event_handler(type, build_filter_wrapper(type, matcher, proc))
|
|
275
|
+
end
|
|
276
|
+
descriptors.size == 1 ? descriptors.first : descriptors
|
|
277
|
+
else
|
|
278
|
+
raise Error, '`on` requires either an event symbol or event filters'
|
|
279
|
+
end
|
|
313
280
|
end
|
|
314
281
|
|
|
315
|
-
|
|
316
|
-
def on(event, &proc)
|
|
282
|
+
private def register_event_handler(event, proc)
|
|
317
283
|
raise Error, "`#{event}` is not a valid event type" unless @events.key? event
|
|
318
284
|
|
|
285
|
+
# Only one close handler is allowed; registering a new one replaces the old
|
|
286
|
+
@events[:close].clear if event == :close
|
|
287
|
+
|
|
319
288
|
event_id = new_event_key
|
|
320
289
|
@events[event][event_id] = proc
|
|
321
290
|
EventDescriptor.new(event, event_id)
|
|
322
291
|
end
|
|
323
292
|
|
|
324
|
-
#
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
293
|
+
# Wrap a user proc for direct (no-filter) registration. Gamepad events
|
|
294
|
+
# unpack the dispatch struct into multi-arg form; everything else passes
|
|
295
|
+
# the event struct straight through.
|
|
296
|
+
private def wrap_for_event(type, proc)
|
|
297
|
+
unpack = GAMEPAD_EVENT_UNPACK[type]
|
|
298
|
+
return proc unless unpack
|
|
328
299
|
|
|
329
|
-
|
|
330
|
-
def key_down(key)
|
|
331
|
-
@keys_down.include? key
|
|
300
|
+
->(d) { proc.call(*unpack.call(d)) }
|
|
332
301
|
end
|
|
333
302
|
|
|
334
|
-
#
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
303
|
+
# Wrap a user proc with a filter matcher. Hash matchers AND every
|
|
304
|
+
# `key?(value)` predicate; scalar/array matchers fall through to the
|
|
305
|
+
# event type's primary predicate. Gamepad event handlers also unpack
|
|
306
|
+
# the dispatch struct into multi-arg form.
|
|
307
|
+
private def build_filter_wrapper(type, matcher, proc)
|
|
308
|
+
unpack = GAMEPAD_EVENT_UNPACK[type]
|
|
309
|
+
args = unpack ? ->(e) { unpack.call(e) } : ->(e) { [e] }
|
|
338
310
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
311
|
+
if matcher.is_a?(Hash)
|
|
312
|
+
unless unpack
|
|
313
|
+
raise Error, "`#{type}` does not support hash filters with `on event: { ... }`"
|
|
314
|
+
end
|
|
315
|
+
->(e) {
|
|
316
|
+
if matcher.all? { |k, v| e.send(:"#{k}?", v) }
|
|
317
|
+
proc.call(*args.call(e))
|
|
318
|
+
end
|
|
319
|
+
}
|
|
320
|
+
else
|
|
321
|
+
predicate = EVENT_FILTER_PREDICATES[type] or
|
|
322
|
+
raise Error, "`#{type}` does not support filtering with `on event: value`"
|
|
323
|
+
values = Array(matcher)
|
|
324
|
+
->(e) {
|
|
325
|
+
if values.any? { |v| e.send(predicate, v) }
|
|
326
|
+
proc.call(*args.call(e))
|
|
327
|
+
end
|
|
328
|
+
}
|
|
329
|
+
end
|
|
342
330
|
end
|
|
343
331
|
|
|
344
|
-
#
|
|
345
|
-
|
|
346
|
-
|
|
332
|
+
# Remove an event handler (or several). Accepts a descriptor returned by
|
|
333
|
+
# `on`, or an array of them (as `on` returns when given multiple filters).
|
|
334
|
+
def off(event_descriptor)
|
|
335
|
+
return event_descriptor.each { |d| off(d) } if event_descriptor.is_a?(Array)
|
|
347
336
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
337
|
+
case event_descriptor
|
|
338
|
+
when ObjectEventDescriptor
|
|
339
|
+
event_descriptor.object.off(event_descriptor)
|
|
340
|
+
when EventDescriptor
|
|
341
|
+
@events[event_descriptor.type].delete(event_descriptor.id)
|
|
342
|
+
else
|
|
343
|
+
raise Error,
|
|
344
|
+
"Cannot remove event handler: expected a descriptor returned by `on`, got #{event_descriptor.inspect}"
|
|
351
345
|
end
|
|
346
|
+
end
|
|
352
347
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
#
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
#
|
|
361
|
-
|
|
362
|
-
|
|
348
|
+
# Update callback method, called by the native and web extentions
|
|
349
|
+
def update_callback
|
|
350
|
+
# Monotonic seconds since the previous update. Clamped to 0.1s so a paused
|
|
351
|
+
# window or stalled frame doesn't teleport the simulation when updates
|
|
352
|
+
# resume; zero on the first frame. `Ext.now` (SDL_GetTicksNS, and
|
|
353
|
+
# performance.now on web) is the single clock used on every runtime — the
|
|
354
|
+
# same source as the public `elapsed`. A wall clock like Time.now would
|
|
355
|
+
# jitter and stutter dt-scaled motion.
|
|
356
|
+
now = Ext.now
|
|
357
|
+
if @last_update_time
|
|
358
|
+
dt = now - @last_update_time
|
|
359
|
+
@delta_time = dt > 0.1 ? 0.1 : dt
|
|
360
|
+
else
|
|
361
|
+
@delta_time = 0.0
|
|
363
362
|
end
|
|
364
|
-
|
|
363
|
+
@last_update_time = now
|
|
365
364
|
|
|
366
|
-
|
|
367
|
-
def mouse_down(btn)
|
|
368
|
-
@mouse_buttons_down.include? btn
|
|
369
|
-
end
|
|
365
|
+
update if @overrides_update
|
|
370
366
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
367
|
+
if @update_wants_dt
|
|
368
|
+
@update_proc.call(@delta_time)
|
|
369
|
+
else
|
|
370
|
+
@update_proc.call
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# Frame-scoped polling state (pressed/released, axes_moved, scroll/move
|
|
374
|
+
# flags) lives one frame and is cleared here every tick — independent of
|
|
375
|
+
# whether the user is on the DSL or class pattern, so both can poll.
|
|
376
|
+
clear_event_stores
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# Iterate the z-sorted scene graph and render each visible object, splicing
|
|
380
|
+
# the user's render block into the same z-order at `@render_z`: objects with
|
|
381
|
+
# `z` at or below it draw first, then the block, then the rest. The default
|
|
382
|
+
# `:foreground` (+∞) draws the block last, on top of everything; `:background`
|
|
383
|
+
# (-∞) draws it first. Called from the native extension once per frame via
|
|
384
|
+
# `tick`. Each object draws via its zero-arg `_render_scene` hook, not the
|
|
385
|
+
# public keyword `render`: on wasm mruby a zero-arg call into a
|
|
386
|
+
# keyword-heavy method still pays ~5µs of keyword setup, so 100 sprites
|
|
387
|
+
# would burn half a millisecond per frame on pure dispatch.
|
|
388
|
+
def render_objects
|
|
389
|
+
# Fast paths for the symbolic block positions: with the block pinned at
|
|
390
|
+
# +∞ (`:foreground`, the default) or -∞ (`:background`) no object can
|
|
391
|
+
# ever sort after (resp. before) it, so the per-object `z` read and
|
|
392
|
+
# compare in the interleaving loop below could never fire — skip them.
|
|
393
|
+
if @render_z == Float::INFINITY
|
|
394
|
+
@objects.each { |obj| obj._render_scene if obj.visible? }
|
|
395
|
+
render_callback
|
|
396
|
+
elsif @render_z == -Float::INFINITY
|
|
397
|
+
render_callback
|
|
398
|
+
@objects.each { |obj| obj._render_scene if obj.visible? }
|
|
399
|
+
else
|
|
400
|
+
block_drawn = false
|
|
401
|
+
@objects.each do |obj|
|
|
402
|
+
if !block_drawn && obj.z > @render_z
|
|
403
|
+
render_callback
|
|
404
|
+
block_drawn = true
|
|
405
|
+
end
|
|
406
|
+
obj._render_scene if obj.visible?
|
|
407
|
+
end
|
|
408
|
+
render_callback unless block_drawn
|
|
409
|
+
end
|
|
374
410
|
end
|
|
375
411
|
|
|
376
|
-
#
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
412
|
+
# Run the user's render block (and the overridden `render` method under the
|
|
413
|
+
# class pattern). Spliced into the scene by `render_objects`.
|
|
414
|
+
def render_callback
|
|
415
|
+
render if @overrides_render
|
|
380
416
|
|
|
381
|
-
|
|
382
|
-
def mouse_move
|
|
383
|
-
@mouse_move_event
|
|
417
|
+
@render_proc.call
|
|
384
418
|
end
|
|
385
419
|
|
|
386
|
-
#
|
|
387
|
-
def
|
|
388
|
-
|
|
389
|
-
@events[:mouse].each do |_id, e|
|
|
390
|
-
e.call(MouseEvent.new(type, button, direction, x, y, delta_x, delta_y))
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
case type
|
|
394
|
-
# When mouse button pressed
|
|
395
|
-
when :down
|
|
396
|
-
_handle_mouse_down type, button, x, y
|
|
397
|
-
# When mouse button released
|
|
398
|
-
when :up
|
|
399
|
-
_handle_mouse_up type, button, x, y
|
|
400
|
-
# When mouse motion / movement
|
|
401
|
-
when :scroll
|
|
402
|
-
_handle_mouse_scroll type, direction, delta_x, delta_y
|
|
403
|
-
# When mouse scrolling, wheel or trackpad
|
|
404
|
-
when :move
|
|
405
|
-
_handle_mouse_move type, x, y, delta_x, delta_y
|
|
406
|
-
end
|
|
420
|
+
# Close callback method, called by the native extension
|
|
421
|
+
def close_callback
|
|
422
|
+
@events[:close].each_value(&:call)
|
|
407
423
|
end
|
|
408
424
|
|
|
409
|
-
#
|
|
410
|
-
def
|
|
411
|
-
|
|
412
|
-
|
|
425
|
+
# One frame: poll events, update, render.
|
|
426
|
+
def tick
|
|
427
|
+
Ext.poll_events(self)
|
|
428
|
+
# drain_events returns nil (not an empty array) on event-less frames
|
|
429
|
+
raw = Ext.drain_events(self)
|
|
430
|
+
dispatch_events(raw) if raw
|
|
413
431
|
|
|
414
|
-
|
|
415
|
-
def controller_axis(axis)
|
|
416
|
-
@controller_axes_moved.include? axis
|
|
417
|
-
end
|
|
432
|
+
update_callback
|
|
418
433
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
end
|
|
434
|
+
if Ext.begin_frame(self)
|
|
435
|
+
render_objects
|
|
436
|
+
end
|
|
423
437
|
|
|
424
|
-
|
|
425
|
-
def controller_button_up(btn)
|
|
426
|
-
@controller_buttons_up.include? btn
|
|
438
|
+
Ext.end_frame(self)
|
|
427
439
|
end
|
|
428
440
|
|
|
429
|
-
#
|
|
430
|
-
def
|
|
431
|
-
#
|
|
432
|
-
|
|
433
|
-
|
|
441
|
+
# Show the window
|
|
442
|
+
def show
|
|
443
|
+
raise Error, 'Window#show called multiple times; Ruby 2D supports a single window per process' if Window.shown?
|
|
444
|
+
|
|
445
|
+
@close = false
|
|
446
|
+
load_default_gamepad_mappings
|
|
447
|
+
|
|
448
|
+
if RUBY_ENGINE == 'ruby'
|
|
449
|
+
# CRuby: window_show creates the window and returns — Ruby owns the loop.
|
|
450
|
+
# Mark shown only after it succeeds; on failure it raises, so shown? stays
|
|
451
|
+
# false and no frame dereferences a NULL renderer.
|
|
452
|
+
Ext.window_show(self)
|
|
453
|
+
Window.shown = true
|
|
454
|
+
@running = true
|
|
455
|
+
tick until @close
|
|
456
|
+
else
|
|
457
|
+
# mruby/WASM: window_show creates the window AND runs the loop, blocking
|
|
458
|
+
# until close. Mark shown first so live updates (request_render, set title,
|
|
459
|
+
# etc.) work during the run; a creation failure raises before the loop.
|
|
460
|
+
Window.shown = true
|
|
461
|
+
@running = true
|
|
462
|
+
Ext.window_show(self)
|
|
434
463
|
end
|
|
435
464
|
|
|
436
|
-
|
|
437
|
-
# When controller axis motion, like analog sticks
|
|
438
|
-
when :axis
|
|
439
|
-
_handle_controller_axis which, axis, value
|
|
440
|
-
# When controller button is pressed
|
|
441
|
-
when :button_down
|
|
442
|
-
_handle_controller_button_down which, button
|
|
443
|
-
# When controller button is released
|
|
444
|
-
when :button_up
|
|
445
|
-
_handle_controller_button_up which, button
|
|
446
|
-
end
|
|
465
|
+
@running = false
|
|
447
466
|
end
|
|
448
467
|
|
|
449
|
-
#
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
468
|
+
# Take a screenshot, saving to `path` (or a timestamped file if omitted).
|
|
469
|
+
#
|
|
470
|
+
# The write is deferred to the end of the current frame, after the scene is
|
|
471
|
+
# drawn but before it is presented, so the capture is this frame rather than
|
|
472
|
+
# the last one. `path` therefore comes back before the file exists; it lands
|
|
473
|
+
# by the time the next `update` runs. Requesting one also forces the frame to
|
|
474
|
+
# render, so a capture in `:on_demand` mode never grabs a parked frame, and
|
|
475
|
+
# capturing and closing in the same tick still writes the file.
|
|
476
|
+
#
|
|
477
|
+
# A closed window has no end-of-frame left to write on, so that raises rather
|
|
478
|
+
# than returning a path to a file that will never appear.
|
|
479
|
+
#
|
|
480
|
+
# A no-op on the web, returning nil: the only filesystem there is Emscripten's
|
|
481
|
+
# in-memory one, so a capture would cost a framebuffer read and a PNG encode
|
|
482
|
+
# to produce a file nobody can open, and that vanishes on reload.
|
|
483
|
+
def screenshot(path = nil)
|
|
484
|
+
return if Ruby2D.web?
|
|
461
485
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
486
|
+
if Window.shown? && !@running
|
|
487
|
+
raise Error, '`screenshot` called after the window closed; the file is ' \
|
|
488
|
+
'written at the end of a frame, so nothing would be saved'
|
|
489
|
+
end
|
|
465
490
|
|
|
466
|
-
|
|
491
|
+
path ||= "./screenshot-#{Time.now.utc.strftime('%Y-%m-%d--%H-%M-%S')}.png"
|
|
492
|
+
Ext.window_screenshot(self, path)
|
|
467
493
|
end
|
|
468
494
|
|
|
469
|
-
#
|
|
470
|
-
def
|
|
471
|
-
|
|
495
|
+
# Get the current cursor state
|
|
496
|
+
def cursor
|
|
497
|
+
return :hidden unless Ext.window_cursor_visible(self)
|
|
472
498
|
|
|
473
|
-
|
|
474
|
-
ext_show
|
|
499
|
+
@cursor_style || :default
|
|
475
500
|
end
|
|
476
501
|
|
|
477
|
-
#
|
|
478
|
-
def
|
|
479
|
-
|
|
480
|
-
|
|
502
|
+
# Set the cursor: `:visible`, `:hidden`, or a system cursor name
|
|
503
|
+
def cursor=(name)
|
|
504
|
+
case name
|
|
505
|
+
when :visible
|
|
506
|
+
@cursor_style = :default
|
|
507
|
+
Ext.window_show_cursor(self)
|
|
508
|
+
when :hidden
|
|
509
|
+
@cursor_style = nil
|
|
510
|
+
Ext.window_hide_cursor(self)
|
|
481
511
|
else
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
Time.now.utc.to_i
|
|
486
|
-
end
|
|
487
|
-
ext_screenshot("./screenshot-#{time}.png")
|
|
512
|
+
name = name.to_sym
|
|
513
|
+
@cursor_style = name
|
|
514
|
+
Ext.window_set_system_cursor(self, name.to_s)
|
|
488
515
|
end
|
|
489
516
|
end
|
|
490
517
|
|
|
491
|
-
# Close the window
|
|
518
|
+
# Close the window. A no-op on the web, where a page can't close itself —
|
|
519
|
+
# only the person viewing it can — so there's nothing to shut down: the
|
|
520
|
+
# `:close` handler doesn't fire, the window isn't marked closed, and the
|
|
521
|
+
# loop keeps running. The user's own quit still arrives as a `:close`
|
|
522
|
+
# event, which is handled in the event loop rather than here.
|
|
492
523
|
def close
|
|
493
|
-
|
|
494
|
-
end
|
|
495
|
-
|
|
496
|
-
# Private instance methods
|
|
497
|
-
|
|
498
|
-
private
|
|
524
|
+
return if Ruby2D.web?
|
|
499
525
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
index = @objects.index do |obj|
|
|
504
|
-
obj.z > object.z
|
|
505
|
-
end
|
|
506
|
-
if index
|
|
507
|
-
@objects.insert(index, object)
|
|
508
|
-
else
|
|
509
|
-
@objects.push(object)
|
|
510
|
-
end
|
|
511
|
-
true
|
|
512
|
-
else
|
|
513
|
-
false
|
|
514
|
-
end
|
|
526
|
+
close_callback
|
|
527
|
+
Ext.window_close(self)
|
|
528
|
+
@close = true
|
|
515
529
|
end
|
|
516
530
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
@resizable = opts[:resizable] if opts[:resizable]
|
|
522
|
-
@borderless = opts[:borderless] if opts[:borderless]
|
|
523
|
-
@fullscreen = opts[:fullscreen] if opts[:fullscreen]
|
|
531
|
+
# Request that the next tick render a frame. No-op in :continuous mode.
|
|
532
|
+
# Safe to call from any thread.
|
|
533
|
+
def request_render
|
|
534
|
+
Ext.window_request_render(self) if Window.shown?
|
|
524
535
|
end
|
|
525
536
|
|
|
526
|
-
|
|
527
|
-
@width = opts[:width] if opts[:width]
|
|
528
|
-
@height = opts[:height] if opts[:height]
|
|
529
|
-
@viewport_width = opts[:viewport_width] if opts[:viewport_width]
|
|
530
|
-
@viewport_height = opts[:viewport_height] if opts[:viewport_height]
|
|
531
|
-
@highdpi = opts[:highdpi] unless opts[:highdpi].nil?
|
|
532
|
-
end
|
|
537
|
+
# Private instance methods
|
|
533
538
|
|
|
534
|
-
|
|
535
|
-
# For class pattern
|
|
536
|
-
@keys_down << key if !@using_dsl && !(@keys_down.include? key)
|
|
539
|
+
private
|
|
537
540
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
+
# Resolve a render-block `z:` to a numeric depth. `:foreground` puts the
|
|
542
|
+
# block on top of every object, `:background` behind them; a number places
|
|
543
|
+
# it at that depth on the same scale as object `z`.
|
|
544
|
+
def render_z_for(z)
|
|
545
|
+
case z
|
|
546
|
+
when :foreground then Float::INFINITY
|
|
547
|
+
when :background then -Float::INFINITY
|
|
548
|
+
when Numeric then z
|
|
549
|
+
else
|
|
550
|
+
raise Error, "render `z:` must be a number, :foreground, or :background, got #{z.inspect}"
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
# Event buffer stride and category/type constants (match C-side defines)
|
|
555
|
+
EVT_STRIDE = 12
|
|
556
|
+
EVT_KEY = 1
|
|
557
|
+
EVT_MOUSE = 2
|
|
558
|
+
EVT_GAMEPAD = 3
|
|
559
|
+
EVT_CLOSE = 4
|
|
560
|
+
|
|
561
|
+
KEY_TYPE_MAP = { 1 => :down, 2 => :held, 3 => :up }.freeze
|
|
562
|
+
MOUSE_TYPE_MAP = { 1 => :down, 2 => :up, 3 => :scroll, 4 => :move,
|
|
563
|
+
5 => :held, 6 => :enter, 7 => :leave }.freeze
|
|
564
|
+
MOUSE_BTN_MAP = { 1 => :left, 2 => :middle, 3 => :right, 4 => :x1, 5 => :x2 }.freeze
|
|
565
|
+
SCROLL_DIR_MAP = { 0 => :normal, 1 => :inverted }.freeze
|
|
566
|
+
GP_AXIS_MAP = { 0 => :left_x, 1 => :left_y, 2 => :right_x, 3 => :right_y,
|
|
567
|
+
4 => :left_trigger, 5 => :right_trigger }.freeze
|
|
568
|
+
GP_BUTTON_MAP = { 0 => :south, 1 => :east, 2 => :west, 3 => :north,
|
|
569
|
+
4 => :back, 5 => :guide, 6 => :start,
|
|
570
|
+
7 => :left_stick, 8 => :right_stick,
|
|
571
|
+
9 => :left_shoulder, 10 => :right_shoulder,
|
|
572
|
+
11 => :dpad_up, 12 => :dpad_down,
|
|
573
|
+
13 => :dpad_left, 14 => :dpad_right,
|
|
574
|
+
15 => :misc1, 16 => :paddle1, 17 => :paddle2,
|
|
575
|
+
18 => :paddle3, 19 => :paddle4, 20 => :touchpad,
|
|
576
|
+
21 => :misc2, 22 => :misc3, 23 => :misc4,
|
|
577
|
+
24 => :misc5, 25 => :misc6 }.freeze
|
|
578
|
+
|
|
579
|
+
def dispatch_events(raw)
|
|
580
|
+
i = 0
|
|
581
|
+
while i < raw.size
|
|
582
|
+
cat = raw[i]
|
|
583
|
+
case cat
|
|
584
|
+
when EVT_KEY
|
|
585
|
+
key_callback(KEY_TYPE_MAP[raw[i + 1]], key_name(raw[i + 2]))
|
|
586
|
+
when EVT_MOUSE
|
|
587
|
+
mouse_callback(
|
|
588
|
+
MOUSE_TYPE_MAP[raw[i + 1]], MOUSE_BTN_MAP[raw[i + 3]],
|
|
589
|
+
SCROLL_DIR_MAP[raw[i + 4]],
|
|
590
|
+
raw[i + 6], raw[i + 7], raw[i + 8], raw[i + 9]
|
|
591
|
+
)
|
|
592
|
+
when EVT_GAMEPAD
|
|
593
|
+
gp_type = raw[i + 1]
|
|
594
|
+
gp_id = raw[i + 2]
|
|
595
|
+
case gp_type
|
|
596
|
+
when 1 then gamepad_callback(gp_id, :connect, nil, nil, raw[i + 11])
|
|
597
|
+
when 2 then gamepad_callback(gp_id, :disconnect, nil, nil, nil)
|
|
598
|
+
when 3
|
|
599
|
+
axis_sym = GP_AXIS_MAP[raw[i + 5]]
|
|
600
|
+
raw_val = raw[i + 10]
|
|
601
|
+
value = raw_val > 0 ? raw_val / 32767.0 : raw_val / 32768.0
|
|
602
|
+
gamepad_callback(gp_id, :axis, axis_sym, value, nil)
|
|
603
|
+
when 4 then gamepad_callback(gp_id, :button_down, GP_BUTTON_MAP[raw[i + 3]], nil, nil)
|
|
604
|
+
when 5 then gamepad_callback(gp_id, :button_up, GP_BUTTON_MAP[raw[i + 3]], nil, nil)
|
|
605
|
+
when 6 then gamepad_callback(gp_id, :button_held, GP_BUTTON_MAP[raw[i + 3]], nil, nil)
|
|
606
|
+
end
|
|
607
|
+
when EVT_CLOSE
|
|
608
|
+
close_callback
|
|
609
|
+
Ext.window_close(self)
|
|
610
|
+
@close = true
|
|
611
|
+
end
|
|
612
|
+
i += EVT_STRIDE
|
|
541
613
|
end
|
|
542
614
|
end
|
|
543
615
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
616
|
+
# Fire every handler registered for `type`, building a fresh event object
|
|
617
|
+
# per handler via the block (a handler may mutate the event it receives, so
|
|
618
|
+
# handlers don't share one). Skips the values-array allocation when no
|
|
619
|
+
# handlers are registered — the common case on per-event hot paths, where
|
|
620
|
+
# it costs ~1µs per empty event type on wasm mruby.
|
|
621
|
+
def fire_event_handlers(type)
|
|
622
|
+
handlers = @events[type]
|
|
623
|
+
return if handlers.empty?
|
|
547
624
|
|
|
548
|
-
|
|
549
|
-
@events[:key_held].each do |_id, e|
|
|
550
|
-
e.call(KeyEvent.new(type, key))
|
|
551
|
-
end
|
|
625
|
+
handlers.values.each { |e| e.call(yield) }
|
|
552
626
|
end
|
|
553
627
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
@
|
|
560
|
-
e.call(KeyEvent.new(type, key))
|
|
561
|
-
end
|
|
628
|
+
# Resolve an SDL scancode to its cached, frozen, lowercased name. The
|
|
629
|
+
# held-key path sends only the integer scancode each frame; the name is
|
|
630
|
+
# looked up (and downcased + frozen) once per distinct key and reused, so
|
|
631
|
+
# no per-frame key-name string is allocated.
|
|
632
|
+
def key_name(code)
|
|
633
|
+
@key_names[code] ||= Ext.scancode_name(code).downcase.freeze
|
|
562
634
|
end
|
|
563
635
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
@
|
|
567
|
-
|
|
568
|
-
# Call event handler
|
|
569
|
-
@events[:mouse_down].each do |_id, e|
|
|
570
|
-
e.call(MouseEvent.new(type, button, nil, x, y, nil, nil))
|
|
571
|
-
end
|
|
636
|
+
# Generate a new event key (ID)
|
|
637
|
+
def new_event_key
|
|
638
|
+
@event_key += 1
|
|
572
639
|
end
|
|
573
640
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
641
|
+
# Add an object to the window, used by the public `add` method
|
|
642
|
+
def add_object(object)
|
|
643
|
+
return false if @object_set.key?(object)
|
|
577
644
|
|
|
578
|
-
|
|
579
|
-
@
|
|
580
|
-
|
|
581
|
-
end
|
|
582
|
-
end
|
|
645
|
+
index = @objects.bsearch_index { |obj| obj.z > object.z }
|
|
646
|
+
@objects.insert(index || @objects.size, object)
|
|
647
|
+
@object_set[object] = true
|
|
583
648
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
@mouse_scroll_direction = direction
|
|
589
|
-
@mouse_scroll_delta_x = delta_x
|
|
590
|
-
@mouse_scroll_delta_y = delta_y
|
|
649
|
+
# Re-register for correct z-order if the object is interactive
|
|
650
|
+
if object.respond_to?(:interactive?) && object.interactive?
|
|
651
|
+
@interactive_objects.delete(object)
|
|
652
|
+
register_interactive(object)
|
|
591
653
|
end
|
|
592
654
|
|
|
593
|
-
|
|
594
|
-
@events[:mouse_scroll].each do |_id, e|
|
|
595
|
-
e.call(MouseEvent.new(type, nil, direction, nil, nil, delta_x, delta_y))
|
|
596
|
-
end
|
|
655
|
+
true
|
|
597
656
|
end
|
|
598
657
|
|
|
599
|
-
def
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
@
|
|
603
|
-
|
|
604
|
-
@mouse_move_delta_y = delta_y
|
|
658
|
+
def set_any_window_properties(opts)
|
|
659
|
+
@background = Color.new(opts[:background]) if Color.valid? opts[:background]
|
|
660
|
+
if opts[:title]
|
|
661
|
+
@title = opts[:title]
|
|
662
|
+
Ext.window_set_title(self) if Window.shown?
|
|
605
663
|
end
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
e.call(MouseEvent.new(type, nil, nil, x, y, delta_x, delta_y))
|
|
664
|
+
if opts[:icon]
|
|
665
|
+
@icon = opts[:icon]
|
|
666
|
+
Ext.window_set_icon(self) if Window.shown?
|
|
610
667
|
end
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
# For class pattern
|
|
615
|
-
unless @using_dsl
|
|
616
|
-
@controller_id = which
|
|
617
|
-
@controller_axes_moved << axis unless @controller_axes_moved.include? axis
|
|
618
|
-
_set_controller_axis_value axis, value
|
|
619
|
-
end
|
|
620
|
-
|
|
621
|
-
# Call event handler
|
|
622
|
-
@events[:controller_axis].each do |_id, e|
|
|
623
|
-
e.call(ControllerAxisEvent.new(which, axis, value))
|
|
668
|
+
unless opts[:resizable].nil?
|
|
669
|
+
@resizable = opts[:resizable]
|
|
670
|
+
Ext.window_set_resizable(self) if Window.shown?
|
|
624
671
|
end
|
|
625
672
|
end
|
|
626
673
|
|
|
627
|
-
def
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
@
|
|
635
|
-
|
|
636
|
-
@controller_axis_right_y = value
|
|
674
|
+
def set_any_window_dimensions(opts)
|
|
675
|
+
# Before `show`, the viewport auto-follows width/height (its documented
|
|
676
|
+
# default of "same as width/height"). After `show`, a bare `set width:` is
|
|
677
|
+
# a live resize: leave the fixed logical viewport alone so it letterboxes
|
|
678
|
+
# into the new window size instead of being silently overwritten. Only
|
|
679
|
+
# `:expand` tracks the window on resize, and that is handled C-side.
|
|
680
|
+
if opts[:width]
|
|
681
|
+
@width = opts[:width]
|
|
682
|
+
@viewport_width = @width unless opts[:viewport_width] || Window.shown?
|
|
637
683
|
end
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
# For class pattern
|
|
642
|
-
unless @using_dsl
|
|
643
|
-
@controller_id = which
|
|
644
|
-
@controller_buttons_down << button unless @controller_buttons_down.include? button
|
|
684
|
+
if opts[:height]
|
|
685
|
+
@height = opts[:height]
|
|
686
|
+
@viewport_height = @height unless opts[:viewport_height] || Window.shown?
|
|
645
687
|
end
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
688
|
+
@viewport_width = opts[:viewport_width] if opts[:viewport_width]
|
|
689
|
+
@viewport_height = opts[:viewport_height] if opts[:viewport_height]
|
|
690
|
+
if opts[:viewport]
|
|
691
|
+
unless VIEWPORT_MODES.include?(opts[:viewport])
|
|
692
|
+
raise Error, "Invalid viewport mode #{opts[:viewport].inspect}; expected one of #{VIEWPORT_MODES.inspect}"
|
|
693
|
+
end
|
|
694
|
+
@viewport_mode = opts[:viewport]
|
|
695
|
+
end
|
|
696
|
+
# highdpi is baked into the native window at creation and re-read once at
|
|
697
|
+
# `show`; it cannot change afterward. Keep the reader honest — never mutate
|
|
698
|
+
# @highdpi post-show — and warn only when the call would actually differ.
|
|
699
|
+
unless opts[:highdpi].nil?
|
|
700
|
+
if Window.shown?
|
|
701
|
+
if opts[:highdpi] != @highdpi
|
|
702
|
+
Ruby2D.warn 'highdpi is fixed when the window is created and cannot change after `show`; ignoring.'
|
|
703
|
+
end
|
|
704
|
+
else
|
|
705
|
+
@highdpi = opts[:highdpi]
|
|
706
|
+
end
|
|
650
707
|
end
|
|
708
|
+
@pixel_scale = opts[:pixel_scale] unless opts[:pixel_scale].nil?
|
|
651
709
|
end
|
|
652
710
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
@controller_buttons_up << button unless @controller_buttons_up.include? button
|
|
658
|
-
end
|
|
659
|
-
|
|
660
|
-
# Call event handler
|
|
661
|
-
@events[:controller_button_up].each do |_id, e|
|
|
662
|
-
e.call(ControllerButtonEvent.new(which, button))
|
|
663
|
-
end
|
|
711
|
+
# The symbol :infinity is an ergonomic alias for Float::INFINITY (uncapped);
|
|
712
|
+
# normalize it so the rest of the pipeline only sees nil / number / INFINITY.
|
|
713
|
+
def normalize_fps_cap(value)
|
|
714
|
+
value == :infinity ? Float::INFINITY : value
|
|
664
715
|
end
|
|
665
716
|
|
|
666
|
-
#
|
|
667
|
-
#
|
|
668
|
-
#
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
def _handle_console_input
|
|
672
|
-
cmd = $stdin.gets
|
|
673
|
-
begin
|
|
674
|
-
res = eval(cmd, TOPLEVEL_BINDING)
|
|
675
|
-
$stdout.puts "=> #{res.inspect}"
|
|
676
|
-
$stdout.flush
|
|
677
|
-
rescue SyntaxError => e
|
|
678
|
-
$stdout.puts e
|
|
679
|
-
$stdout.flush
|
|
680
|
-
rescue Exception => e
|
|
681
|
-
$stdout.puts e
|
|
682
|
-
$stdout.flush
|
|
683
|
-
end
|
|
717
|
+
# A valid (normalized) fps_cap is nil (no cap) or a positive number —
|
|
718
|
+
# including Float::INFINITY, which is positive. 0, negatives, NaN, and other
|
|
719
|
+
# types are rejected.
|
|
720
|
+
def fps_cap_valid?(value)
|
|
721
|
+
value.nil? || (value.is_a?(Numeric) && value > 0)
|
|
684
722
|
end
|
|
685
|
-
# rubocop:enable Lint/RescueException
|
|
686
|
-
# rubocop:enable Security/Eval
|
|
687
|
-
# ---- end exception
|
|
688
723
|
|
|
689
|
-
def
|
|
724
|
+
def clear_event_stores
|
|
690
725
|
@keys_down.clear
|
|
691
726
|
@keys_held.clear
|
|
692
727
|
@keys_up.clear
|
|
693
728
|
@mouse_buttons_down.clear
|
|
694
729
|
@mouse_buttons_up.clear
|
|
695
|
-
@
|
|
696
|
-
@
|
|
697
|
-
@
|
|
698
|
-
@
|
|
699
|
-
@
|
|
730
|
+
@mouse_buttons_held.clear
|
|
731
|
+
@mouse_scroll_event = false
|
|
732
|
+
@mouse_scroll_direction = nil
|
|
733
|
+
@mouse_scroll_delta_x = 0
|
|
734
|
+
@mouse_scroll_delta_y = 0
|
|
735
|
+
@mouse_move_event = false
|
|
736
|
+
@mouse_move_delta_x = 0
|
|
737
|
+
@mouse_move_delta_y = 0
|
|
738
|
+
clear_gamepad_frame_state
|
|
700
739
|
end
|
|
701
740
|
|
|
702
|
-
def
|
|
741
|
+
def init_window_defaults
|
|
703
742
|
# Window background color
|
|
704
743
|
@background = Color.new([0.0, 0.0, 0.0, 1.0])
|
|
705
744
|
|
|
@@ -708,63 +747,39 @@ module Ruby2D
|
|
|
708
747
|
|
|
709
748
|
# Window characteristics
|
|
710
749
|
@resizable = false
|
|
711
|
-
@
|
|
712
|
-
@
|
|
713
|
-
@highdpi = false
|
|
750
|
+
@highdpi = true
|
|
751
|
+
@pixel_scale = false
|
|
714
752
|
|
|
715
753
|
# Size of the window's viewport (the drawable area)
|
|
716
|
-
@viewport_width =
|
|
717
|
-
@viewport_height =
|
|
754
|
+
@viewport_width = @width
|
|
755
|
+
@viewport_height = @height
|
|
756
|
+
|
|
757
|
+
# Viewport scaling mode for resizable windows
|
|
758
|
+
@viewport_mode = :letterbox
|
|
759
|
+
|
|
760
|
+
# Render mode: :continuous renders every tick up to fps_cap; :on_demand
|
|
761
|
+
# only renders when request_render is called or the OS signals a redraw.
|
|
762
|
+
@render_mode = :continuous
|
|
718
763
|
|
|
719
764
|
# Size of the computer's display
|
|
720
765
|
@display_width = nil
|
|
721
766
|
@display_height = nil
|
|
767
|
+
@display_pixel_width = nil
|
|
768
|
+
@display_pixel_height = nil
|
|
722
769
|
end
|
|
723
770
|
|
|
724
|
-
def
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
771
|
+
def init_event_stores
|
|
772
|
+
init_key_event_stores
|
|
773
|
+
init_mouse_event_stores
|
|
774
|
+
init_gamepad_event_stores
|
|
775
|
+
init_object_event_stores
|
|
728
776
|
end
|
|
729
777
|
|
|
730
|
-
def
|
|
731
|
-
# Event stores for class pattern
|
|
732
|
-
@keys_down = []
|
|
733
|
-
@keys_held = []
|
|
734
|
-
@keys_up = []
|
|
735
|
-
end
|
|
736
|
-
|
|
737
|
-
def _init_mouse_event_stores
|
|
738
|
-
@mouse_buttons_down = []
|
|
739
|
-
@mouse_buttons_up = []
|
|
740
|
-
@mouse_scroll_event = false
|
|
741
|
-
@mouse_scroll_direction = nil
|
|
742
|
-
@mouse_scroll_delta_x = 0
|
|
743
|
-
@mouse_scroll_delta_y = 0
|
|
744
|
-
@mouse_move_event = false
|
|
745
|
-
@mouse_move_delta_x = 0
|
|
746
|
-
@mouse_move_delta_y = 0
|
|
747
|
-
end
|
|
748
|
-
|
|
749
|
-
def _init_controller_event_stores
|
|
750
|
-
@controller_id = nil
|
|
751
|
-
@controller_axes_moved = []
|
|
752
|
-
@controller_axis_left_x = 0
|
|
753
|
-
@controller_axis_left_y = 0
|
|
754
|
-
@controller_axis_right_x = 0
|
|
755
|
-
@controller_axis_right_y = 0
|
|
756
|
-
@controller_buttons_down = []
|
|
757
|
-
@controller_buttons_up = []
|
|
758
|
-
end
|
|
759
|
-
|
|
760
|
-
def _init_event_registrations
|
|
778
|
+
def init_event_registrations
|
|
761
779
|
# Mouse X and Y position in the window
|
|
762
780
|
@mouse_x = 0
|
|
763
781
|
@mouse_y = 0
|
|
764
782
|
|
|
765
|
-
# Controller axis and button mappings file
|
|
766
|
-
@controller_mappings = "#{File.expand_path('~')}/.ruby2d/controllers.txt"
|
|
767
|
-
|
|
768
783
|
# Unique ID for the input event being registered
|
|
769
784
|
@event_key = 0
|
|
770
785
|
|
|
@@ -777,34 +792,66 @@ module Ruby2D
|
|
|
777
792
|
mouse: {},
|
|
778
793
|
mouse_up: {},
|
|
779
794
|
mouse_down: {},
|
|
795
|
+
mouse_held: {},
|
|
780
796
|
mouse_scroll: {},
|
|
781
797
|
mouse_move: {},
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
798
|
+
mouse_enter: {},
|
|
799
|
+
mouse_leave: {},
|
|
800
|
+
gamepad_connect: {},
|
|
801
|
+
gamepad_disconnect: {},
|
|
802
|
+
gamepad_button_down: {},
|
|
803
|
+
gamepad_button_held: {},
|
|
804
|
+
gamepad_button_up: {},
|
|
805
|
+
gamepad_axis: {},
|
|
806
|
+
close: {}
|
|
786
807
|
}
|
|
787
808
|
end
|
|
788
809
|
|
|
789
|
-
def
|
|
810
|
+
def init_procs_and_dsl
|
|
790
811
|
# The window update block
|
|
791
812
|
@update_proc = proc {}
|
|
813
|
+
@update_wants_dt = false
|
|
792
814
|
|
|
793
|
-
# The window render block
|
|
815
|
+
# The window render block, and where it sits in the z-order (see `render`)
|
|
794
816
|
@render_proc = proc {}
|
|
817
|
+
@render_z = Float::INFINITY
|
|
795
818
|
|
|
796
|
-
#
|
|
797
|
-
@
|
|
819
|
+
# Per-frame delta-time state, populated each `update_callback`.
|
|
820
|
+
@last_update_time = nil
|
|
821
|
+
@delta_time = 0.0
|
|
822
|
+
|
|
823
|
+
# Detect the "class pattern": a Window subclass overriding `update` and/or
|
|
824
|
+
# `render`. Each is detected independently so overriding only one still
|
|
825
|
+
# works — an overridden `update` runs even when `render` is left alone, and
|
|
826
|
+
# vice versa. The base `update`/`render` are the DSL setters defined on
|
|
827
|
+
# Ruby2D::Window, so an un-overridden method finds that owner and is
|
|
828
|
+
# skipped in the frame loop (its DSL proc still runs).
|
|
829
|
+
@overrides_update = overrides?(:update)
|
|
830
|
+
@overrides_render = overrides?(:render)
|
|
798
831
|
|
|
799
832
|
# Whether diagnostic messages should be printed
|
|
800
833
|
@diagnostics = false
|
|
834
|
+
@show_fps = false
|
|
835
|
+
@close_on_esc = false
|
|
836
|
+
end
|
|
801
837
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
838
|
+
# Whether `name` (`:update` or `:render`) is a class-pattern override rather
|
|
839
|
+
# than Ruby 2D's own DSL setter.
|
|
840
|
+
#
|
|
841
|
+
# This asks which *class* in the ancestry defines the method, skipping any
|
|
842
|
+
# module Window itself drags along. A module prepended to Window fronts the
|
|
843
|
+
# setter the same way a subclass override does, so reading the immediate
|
|
844
|
+
# owner would mistake instrumentation — wrapping `update` to count frames or
|
|
845
|
+
# hook a screenshot into someone else's app — for the class pattern, and
|
|
846
|
+
# call the setter with no block every frame, which raises. A module mixed
|
|
847
|
+
# into a subclass still counts: that side of the chain is the user's own
|
|
848
|
+
# code, so an `update` there is an override like any other.
|
|
849
|
+
def overrides?(name)
|
|
850
|
+
wrappers = Window.ancestors - [Window]
|
|
851
|
+
owner = self.class.ancestors.find do |mod|
|
|
852
|
+
!wrappers.include?(mod) && mod.instance_methods(false).include?(name)
|
|
853
|
+
end
|
|
854
|
+
owner != Window
|
|
808
855
|
end
|
|
809
856
|
end
|
|
810
857
|
end
|