├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── general-questions.md ├── codecov.yml └── workflows │ ├── audit.yaml │ ├── coverage.yaml │ └── tests.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── Cargo.toml ├── LICENSE ├── README.md ├── SECURITY.md ├── TODO.md ├── assets ├── fonts │ ├── OpenSans-Light.ttf │ ├── Roboto-Bold.ttf │ ├── Roboto-Light.ttf │ ├── Roboto-Regular.ttf │ ├── amiri-regular.ttf │ └── entypo.ttf └── images │ ├── image1.jpg │ ├── image10.jpg │ ├── image11.jpg │ ├── image12.jpg │ ├── image2.jpg │ ├── image3.jpg │ ├── image4.jpg │ ├── image5.jpg │ ├── image6.jpg │ ├── image7.jpg │ ├── image8.jpg │ ├── image9.jpg │ ├── lenna.png │ ├── pattern.jpg │ └── rust-logo.png └── src ├── engine ├── d2 │ ├── animation │ │ ├── animated_float.rs │ │ ├── behavior.rs │ │ ├── binding.rs │ │ ├── ease.rs │ │ ├── jitter.rs │ │ ├── mod.rs │ │ ├── sine.rs │ │ └── tween.rs │ ├── asset │ │ ├── asset.rs │ │ ├── asset_entry.rs │ │ ├── asset_pack.rs │ │ ├── file.rs │ │ ├── manifest.rs │ │ └── mod.rs │ ├── component.rs │ ├── context │ │ ├── coloredpainter.rs │ │ ├── gles_extensions.rs │ │ ├── image.rs │ │ ├── imagepainter.rs │ │ ├── mod.rs │ │ ├── pipeline.rs │ │ ├── textpainter.rs │ │ └── webgl_extensions.rs │ ├── debug │ │ ├── fps_display.rs │ │ └── mod.rs │ ├── director.rs │ ├── display │ │ ├── blend_mode.rs │ │ ├── emitter_mold.rs │ │ ├── emitter_sprite.rs │ │ ├── fill_sprite.rs │ │ ├── font.rs │ │ ├── graphics.rs │ │ ├── image_sprite.rs │ │ ├── mod.rs │ │ ├── orientation.rs │ │ ├── pattern_sprite.rs │ │ ├── sprite.rs │ │ ├── sub_texture.rs │ │ ├── text_sprite.rs │ │ └── texture.rs │ ├── disposer.rs │ ├── entity.rs │ ├── input │ │ ├── acceleration.rs │ │ ├── attitude.rs │ │ ├── key.rs │ │ ├── keyboard_event.rs │ │ ├── mod.rs │ │ ├── mouse_button.rs │ │ ├── mouse_cursor.rs │ │ ├── mouse_event.rs │ │ ├── pointer_event.rs │ │ └── touch_point.rs │ ├── math │ │ ├── fmath.rs │ │ ├── matrix.rs │ │ ├── mod.rs │ │ ├── point.rs │ │ └── rectangle.rs │ ├── mod.rs │ ├── platform │ │ ├── basic_asset.rs │ │ ├── basic_asset_pack_loader.rs │ │ ├── basic_file.rs │ │ ├── basic_keyboard.rs │ │ ├── basic_mouse.rs │ │ ├── basic_pointer.rs │ │ ├── basic_texture.rs │ │ ├── basic_touch.rs │ │ ├── component_builder.rs │ │ ├── debug_logic.rs │ │ ├── dummy_external.rs │ │ ├── dummy_keyboard.rs │ │ ├── dummy_motion.rs │ │ ├── dummy_mouse.rs │ │ ├── dummy_sound.rs │ │ ├── dummy_storage.rs │ │ ├── dummy_touch.rs │ │ ├── dummy_web.rs │ │ ├── event_group.rs │ │ ├── heavy_signal1.rs │ │ ├── key_codes.rs │ │ ├── main_loop.rs │ │ ├── manifest_builder.rs │ │ ├── math_util.rs │ │ ├── mod.rs │ │ ├── mouse_codes.rs │ │ ├── overdraw_graphics.rs │ │ ├── platform.rs │ │ ├── shader │ │ │ ├── draw_pattern_gl.rs │ │ │ ├── draw_texture_gl.rs │ │ │ ├── fill_rect_gl.rs │ │ │ ├── mod.rs │ │ │ └── shader_gl.rs │ │ ├── texture_root.rs │ │ ├── tickable.rs │ │ └── wamp_client.rs │ ├── scene │ │ ├── fade_transition.rs │ │ ├── mod.rs │ │ ├── scene.rs │ │ ├── slide_transition.rs │ │ ├── transition.rs │ │ └── tween_transition.rs │ ├── script │ │ ├── action.rs │ │ ├── animate_by.rs │ │ ├── animate_from.rs │ │ ├── animate_to.rs │ │ ├── call_function.rs │ │ ├── delay.rs │ │ ├── first_of.rs │ │ ├── mod.rs │ │ ├── move_by.rs │ │ ├── move_to.rs │ │ ├── parallel.rs │ │ ├── play_movie.rs │ │ ├── play_sound.rs │ │ ├── repeat.rs │ │ ├── script.rs │ │ ├── sequence.rs │ │ └── shake.rs │ ├── sound │ │ ├── mixer.rs │ │ ├── mod.rs │ │ ├── playback.rs │ │ └── sound.rs │ ├── speed_adjuster.rs │ ├── subsystem │ │ ├── external.rs │ │ ├── keyboard.rs │ │ ├── mod.rs │ │ ├── motion.rs │ │ ├── mouse.rs │ │ ├── pointer.rs │ │ ├── renderer.rs │ │ ├── stage.rs │ │ ├── storage.rs │ │ ├── touch.rs │ │ └── web.rs │ ├── swf │ │ ├── bitmap_symbol.rs │ │ ├── flipbook.rs │ │ ├── format.rs │ │ ├── library.rs │ │ ├── mod.rs │ │ ├── movie_player.rs │ │ ├── movie_sprite.rs │ │ ├── movie_symbol.rs │ │ └── symbol.rs │ ├── system.rs │ ├── util │ │ ├── bit_sets.rs │ │ ├── config.rs │ │ ├── disposable.rs │ │ ├── iterables.rs │ │ ├── macros.rs │ │ ├── maps.rs │ │ ├── message_bundle.rs │ │ ├── mod.rs │ │ ├── multi_promise.rs │ │ ├── pool.rs │ │ ├── promise.rs │ │ ├── random.rs │ │ ├── signal0.rs │ │ ├── signal1.rs │ │ ├── signal2.rs │ │ ├── signal_base.rs │ │ ├── signal_connection.rs │ │ ├── strings.rs │ │ ├── value.rs │ │ └── xmls.rs │ └── web │ │ ├── mod.rs │ │ └── web_view.rs └── mod.rs ├── foundation ├── application.rs ├── application_settings.rs ├── async_application.rs ├── asyncwinit │ ├── future.rs │ └── mod.rs ├── camera │ ├── arcball.rs │ ├── first_person.rs │ └── mod.rs ├── default_preloader.rs ├── error.rs ├── mod.rs ├── resource │ ├── error.rs │ ├── key.rs │ └── mod.rs ├── scene │ ├── light.rs │ ├── mod.rs │ └── model.rs ├── time.rs └── vertex │ ├── mod.rs │ ├── p2.rs │ ├── p2c4.rs │ ├── p2t2.rs │ ├── p2t2c4.rs │ ├── p3.rs │ ├── p3c4.rs │ ├── p3n3.rs │ ├── p3n3c4.rs │ ├── p3n3t2.rs │ ├── p3n3t2c4.rs │ ├── p3t2.rs │ └── p3t2c4.rs ├── lib.rs ├── platform ├── core │ ├── alias.rs │ ├── atlas.rs │ ├── atlas_texture.rs │ ├── attribute.rs │ ├── attribute_buffer.rs │ ├── bitmap.rs │ ├── buffer.rs │ ├── color.rs │ ├── context.rs │ ├── debug_object_type_info.rs │ ├── depth_state.rs │ ├── display.rs │ ├── enums.rs │ ├── euler.rs │ ├── fence.rs │ ├── fence_closure.rs │ ├── fixed.rs │ ├── flags.rs │ ├── frame_closure.rs │ ├── frame_info.rs │ ├── framebuffer.rs │ ├── gles2_context.rs │ ├── gles2_vtable.rs │ ├── gpuinfo.rs │ ├── gtype_object.rs │ ├── handle.rs │ ├── index_buffer.rs │ ├── indices.rs │ ├── kms_crtc.rs │ ├── material.rs │ ├── material_layer.rs │ ├── matrix.rs │ ├── matrix_entry.rs │ ├── matrix_stack.rs │ ├── mimic.rs │ ├── mod.rs │ ├── offscreen.rs │ ├── onscreen.rs │ ├── onscreen_dirty_closure.rs │ ├── onscreen_dirty_info.rs │ ├── onscreen_resize_closure.rs │ ├── onscreen_template.rs │ ├── output.rs │ ├── path │ │ └── mod.rs │ ├── pipeline.rs │ ├── pixel_buffer.rs │ ├── platform │ │ ├── canvas │ │ │ └── mod.rs │ │ ├── cogl │ │ │ └── mod.rs │ │ ├── egl │ │ │ └── mod.rs │ │ ├── evdev │ │ │ └── mod.rs │ │ ├── gdk │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── osx │ │ │ └── mod.rs │ │ ├── sdl │ │ │ └── mod.rs │ │ ├── stage_window.rs │ │ ├── tslib │ │ │ └── mod.rs │ │ ├── vulkan │ │ │ └── mod.rs │ │ ├── wayland │ │ │ └── mod.rs │ │ ├── win │ │ │ └── mod.rs │ │ └── x11 │ │ │ └── mod.rs │ ├── poll_fd.rs │ ├── primitive.rs │ ├── primitives.rs │ ├── quaternion.rs │ ├── rectangle_map.rs │ ├── renderer.rs │ ├── snippet.rs │ ├── sub_texture.rs │ ├── swapchain.rs │ ├── texture.rs │ ├── texture2d.rs │ ├── texture2d_sliced.rs │ ├── texture3d.rs │ ├── texture_pixmap_x11.rs │ ├── texture_rectangle.rs │ ├── texture_vertex.rs │ ├── traits.rs │ └── user_data_key.rs ├── gles │ ├── README.md │ ├── canvas │ │ ├── mod.rs │ │ ├── shader.frag │ │ └── shader.vert │ ├── core20.rs │ ├── core30.rs │ ├── core31.rs │ ├── core32.rs │ ├── enums.rs │ ├── ffi │ │ ├── mod.rs │ │ └── structloader.rs │ ├── mod.rs │ ├── types.rs │ └── utils.rs └── mod.rs ├── prelude ├── mod.rs └── renderable.rs ├── support ├── glyph │ ├── Cargo.toml │ ├── README.md │ ├── builder.rs │ ├── examples │ │ ├── Inconsolata-Regular.ttf │ │ ├── clipping.rs │ │ └── hello.rs │ ├── mod.rs │ ├── pipeline.rs │ ├── pipeline │ │ └── cache.rs │ ├── region.rs │ └── shader │ │ ├── fragment.frag │ │ └── vertex.vert ├── iced │ ├── backend.rs │ ├── clipboard.rs │ ├── conversion.rs │ ├── mod.rs │ ├── mode.rs │ ├── program.rs │ ├── quad.rs │ ├── settings.rs │ ├── shader │ │ ├── quad.frag │ │ ├── quad.vert │ │ ├── triangle.frag │ │ └── triangle.vert │ ├── text.rs │ ├── themes │ │ ├── dark.rs │ │ └── mod.rs │ ├── triangle.rs │ ├── widget.rs │ ├── widget │ │ ├── button.rs │ │ ├── canvas.rs │ │ ├── checkbox.rs │ │ ├── container.rs │ │ ├── pane_grid.rs │ │ ├── pick_list.rs │ │ ├── progress_bar.rs │ │ ├── qr_code.rs │ │ ├── radio.rs │ │ ├── rule.rs │ │ ├── scrollable.rs │ │ ├── slider.rs │ │ ├── text_input.rs │ │ └── tooltip.rs │ ├── window.rs │ └── window │ │ └── compositor.rs ├── mod.rs └── vg │ ├── framebuffer.rs │ ├── gl_texture.rs │ ├── main-fs.glsl │ ├── main-vs.glsl │ ├── mod.rs │ ├── program.rs │ └── uniform_array.rs ├── ui ├── immediate │ ├── ext.rs │ ├── id.rs │ ├── inspect │ │ ├── README.md │ │ ├── default │ │ │ ├── default_bool.rs │ │ │ ├── default_f32.rs │ │ │ ├── default_option.rs │ │ │ ├── default_string.rs │ │ │ ├── default_u32.rs │ │ │ ├── default_usize.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── slider │ │ │ ├── mod.rs │ │ │ └── slider_f32.rs │ ├── macros.rs │ ├── mod.rs │ ├── nodes.rs │ └── themes.rs └── mod.rs └── utils ├── clamp.rs └── mod.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | ko_fi: dudochkin 4 | liberapay: dudochkin 5 | open_collective: dudochkin -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: About unexpected behaviors 4 | title: "[BUG] " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | Describe what is expected, what you actually get. 12 | It would be nice to have screenshot or result image uploaded 13 | 14 | **To Reproduce** 15 | Some minimal reproduce code is highly recommended 16 | 17 | **Version Information** 18 | Please give us what version you are using. If you are pulling `UX-DX` directly from git repo, please mention this as well 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea to UX-DX maintainers 4 | title: "[Feature Request]" 5 | labels: feature request 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### What is the feature ? 11 | *Detailed feature descrption* 12 | 13 | ### (Optional) Why this feature is useful and how people would use the feature ? 14 | *Explain why this feature is important* 15 | 16 | ### (Optional) Additional Information 17 | *More details are appreciated:)* 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general-questions.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General Questions 3 | about: Any other issues 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: "diff, flags, files" 3 | require_changes: true 4 | 5 | coverage: 6 | status: 7 | project: 8 | default: 9 | informational: true 10 | -------------------------------------------------------------------------------- /.github/workflows/audit.yaml: -------------------------------------------------------------------------------- 1 | name: Security audit 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | schedule: 8 | - cron: '0 0 * * 0' 9 | 10 | jobs: 11 | security_audit: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions-rs/audit-check@v1 16 | with: 17 | token: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yaml: -------------------------------------------------------------------------------- 1 | name: Coverage 2 | 3 | #on: 4 | # push: 5 | # branches: 6 | # - main 7 | # pull_request: 8 | 9 | on: [push, pull_request] 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | RUST_BACKTRACE: full 14 | 15 | jobs: 16 | coverage: 17 | name: Coverage 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v2 22 | 23 | - name: Install Rust 24 | uses: actions-rs/toolchain@v1 25 | with: 26 | toolchain: nightly 27 | profile: minimal 28 | default: true 29 | 30 | - name: Install udev 31 | run: sudo apt-get install libudev-dev 32 | 33 | - name: Restore cache 34 | uses: Swatinem/rust-cache@v1 35 | 36 | - name: Run cargo-tarpaulin 37 | uses: actions-rs/tarpaulin@v0.1 38 | with: 39 | args: '--run-types Doctests,Tests' 40 | timeout: 120 41 | 42 | - name: Upload to codecov.io 43 | uses: codecov/codecov-action@239febf655bba88b16ff5dea1d3135ea8663a1f9 44 | with: 45 | token: ${{ secrets.CODECOV_TOKEN }} 46 | 47 | - name: Archive code coverage results 48 | uses: actions/upload-artifact@v2 49 | with: 50 | name: code-coverage-report 51 | path: cobertura.xml 52 | retention-days: 30 53 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | name: Build and test 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout repository 11 | uses: actions/checkout@v2 12 | 13 | - name: Install Rust 14 | uses: actions-rs/toolchain@v1 15 | with: 16 | toolchain: nightly 17 | profile: minimal 18 | default: true 19 | components: rustfmt, clippy 20 | 21 | - name: Install udev 22 | run: sudo apt-get install libudev-dev 23 | 24 | - name: Build 25 | run: cargo build --verbose 26 | - name: Run tests 27 | run: cargo test --verbose 28 | 29 | clippy_check: 30 | name: Clippy check 31 | runs-on: ubuntu-latest 32 | steps: 33 | - name: Checkout repository 34 | uses: actions/checkout@v2 35 | 36 | - name: Install Rust 37 | uses: actions-rs/toolchain@v1 38 | with: 39 | toolchain: nightly 40 | profile: minimal 41 | default: true 42 | components: rustfmt, clippy 43 | 44 | - name: Install udev 45 | run: sudo apt-get install libudev-dev 46 | 47 | - uses: actions-rs/clippy-check@v1 48 | with: 49 | token: ${{ secrets.GITHUB_TOKEN }} 50 | args: --all-features 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | /refs 13 | /examples 14 | **/*.h 15 | **/*.c 16 | **/*.rc 17 | **/*.cur 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Package vX.X.X (YYYY-MM-DD) 4 | 5 | ### Improved 6 | 7 | - A here your changes 8 | 9 | ### Added 10 | 11 | - A here your changes 12 | 13 | ### Fixed 14 | 15 | - A here your changes 16 | 17 | ### Improvement 18 | 19 | - A here your changes 20 | 21 | ### Removed 22 | 23 | - A here your changes 24 | 25 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | Cogl-rs contributors (sorted alphabetically) 2 | ============================================ 3 | 4 | * **[Victor Dudochkin](https://github.com/dudochkin.victor)** 5 | 6 | * Core development 7 | 8 | 9 | 10 | **[Full contributors list](https://github.com/angular-rust/ux-dx/contributors).** -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | If you believe you have found a security vulnerability in Angular Rust, we encourage you to let us know right away. We will investigate all legitimate reports and do our best to quickly fix the problem. 4 | 5 | ## Reporting a Vulnerability 6 | 7 | To report a security vulnerability, please create a Github issue [here](https://github.com/angular-rust/ux-dx/issues/new). 8 | 9 | If you can, please include the following details: 10 | * An MCVE (minimum complete verifiable example) – this is a short code snippet which demonstrates the error in the 11 | the simplest possible (or just a simple) way. 12 | * Which versions of Angular Rust the vulnerability is present in 13 | * What effects the vulnerability has and how serious the vulnerability is -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | - [ ] Fix the type of CoglFixed -------------------------------------------------------------------------------- /assets/fonts/OpenSans-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/fonts/OpenSans-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/amiri-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/fonts/amiri-regular.ttf -------------------------------------------------------------------------------- /assets/fonts/entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/fonts/entypo.ttf -------------------------------------------------------------------------------- /assets/images/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image1.jpg -------------------------------------------------------------------------------- /assets/images/image10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image10.jpg -------------------------------------------------------------------------------- /assets/images/image11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image11.jpg -------------------------------------------------------------------------------- /assets/images/image12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image12.jpg -------------------------------------------------------------------------------- /assets/images/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image2.jpg -------------------------------------------------------------------------------- /assets/images/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image3.jpg -------------------------------------------------------------------------------- /assets/images/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image4.jpg -------------------------------------------------------------------------------- /assets/images/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image5.jpg -------------------------------------------------------------------------------- /assets/images/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image6.jpg -------------------------------------------------------------------------------- /assets/images/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image7.jpg -------------------------------------------------------------------------------- /assets/images/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image8.jpg -------------------------------------------------------------------------------- /assets/images/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/image9.jpg -------------------------------------------------------------------------------- /assets/images/lenna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/lenna.png -------------------------------------------------------------------------------- /assets/images/pattern.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/pattern.jpg -------------------------------------------------------------------------------- /assets/images/rust-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/assets/images/rust-logo.png -------------------------------------------------------------------------------- /src/engine/d2/animation/behavior.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::PartialEq; 2 | 3 | pub trait Behavior { 4 | fn update(&self, dt: f32) -> f32; 5 | fn is_complete(&self) -> bool; 6 | } 7 | -------------------------------------------------------------------------------- /src/engine/d2/animation/binding.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::util::Value; 2 | 3 | use super::Behavior; 4 | 5 | pub type BindingFunction = Box f32>; 6 | 7 | pub struct Binding { 8 | target: Value, 9 | func: Option, 10 | } 11 | 12 | impl Binding { 13 | pub fn new(target: Value, func: Option) -> Self { 14 | Self { target, func } 15 | } 16 | } 17 | 18 | impl Behavior for Binding { 19 | fn update(&self, dt: f32) -> f32 { 20 | let value = self.target.get(); 21 | 22 | // TODO: Be lazy and only call _fn when the value is changed? 23 | if let Some(ref func) = self.func { 24 | func(*value) 25 | } else { 26 | *value 27 | } 28 | } 29 | 30 | fn is_complete(&self) -> bool { 31 | false 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/engine/d2/animation/jitter.rs: -------------------------------------------------------------------------------- 1 | use super::Behavior; 2 | 3 | #[derive(Default, Clone, Copy, Debug)] 4 | pub struct Jitter { 5 | pub base: f32, 6 | pub strength: f32, 7 | } 8 | 9 | impl Jitter { 10 | pub fn new(base: f32, strength: f32) -> Self { 11 | Self { base, strength } 12 | } 13 | } 14 | 15 | impl Behavior for Jitter { 16 | fn update(&self, dt: f32) -> f32 { 17 | self.base + 2.0 * rand::random::() * self.strength - self.strength 18 | } 19 | 20 | fn is_complete(&self) -> bool { 21 | false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/engine/d2/animation/mod.rs: -------------------------------------------------------------------------------- 1 | //! Animation 2 | 3 | mod animated_float; 4 | pub use self::animated_float::*; 5 | 6 | mod behavior; 7 | pub use self::behavior::*; 8 | 9 | mod binding; 10 | pub use self::binding::*; 11 | 12 | mod ease; 13 | pub use self::ease::*; 14 | 15 | mod jitter; 16 | pub use self::jitter::*; 17 | 18 | mod sine; 19 | pub use self::sine::*; 20 | 21 | mod tween; 22 | pub use self::tween::*; 23 | -------------------------------------------------------------------------------- /src/engine/d2/animation/tween.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::RefCell, rc::Rc}; 2 | 3 | use crate::engine::d2::animation::Ease; 4 | 5 | use super::{Behavior, EaseFunction}; 6 | 7 | struct TweenProps { 8 | elapsed: f32, 9 | from: f32, 10 | to: f32, 11 | duration: f32, 12 | } 13 | 14 | pub struct Tween { 15 | props: RefCell, 16 | easing: EaseFunction, 17 | } 18 | 19 | impl Tween { 20 | pub fn new(from: f32, to: f32, seconds: f32, easing: Option) -> Self { 21 | let props = RefCell::new(TweenProps { 22 | from, 23 | to, 24 | elapsed: 0.0, 25 | duration: seconds, 26 | }); 27 | 28 | Self { 29 | props, 30 | easing: easing.unwrap_or(Rc::new(Ease::linear)), 31 | } 32 | } 33 | 34 | pub fn elapsed(&self) -> f32 { 35 | self.props.borrow().elapsed 36 | } 37 | } 38 | 39 | impl Behavior for Tween { 40 | fn update(&self, dt: f32) -> f32 { 41 | let mut props = self.props.borrow_mut(); 42 | props.elapsed += dt; 43 | 44 | if props.elapsed >= props.duration { 45 | props.to 46 | } else { 47 | props.from + (props.to - props.from) * (self.easing)(props.elapsed / props.duration) 48 | } 49 | } 50 | 51 | fn is_complete(&self) -> bool { 52 | let props = self.props.borrow(); 53 | props.elapsed >= props.duration 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/engine/d2/asset/asset.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::util::{Disposable, Value}; 2 | 3 | /// A fully loaded asset. 4 | pub trait Asset: Disposable { 5 | /// The number of times this asset has been live-reloaded. Asset reloading is only enabled in 6 | /// debug builds, and only from the /assets directory. 7 | fn reload_count(&self) -> usize; 8 | 9 | // /// Frees up the underlying resources used by this asset. An asset must not be used after it has 10 | // /// been disposed. 11 | // fn dispose(&self); 12 | } 13 | -------------------------------------------------------------------------------- /src/engine/d2/asset/asset_entry.rs: -------------------------------------------------------------------------------- 1 | /// Specifies all supported asset formats 2 | 3 | #[derive(Debug, Copy, Clone, PartialEq)] 4 | pub enum AssetFormat { 5 | // Images 6 | WEBP, 7 | JXR, 8 | PNG, 9 | JPG, 10 | GIF, 11 | 12 | // Compressed textures 13 | DDS, 14 | PVR, 15 | PKM, 16 | 17 | // Audio 18 | MP3, 19 | M4A, 20 | OPUS, 21 | OGG, 22 | WAV, 23 | 24 | // Raw text/data 25 | BLOB, 26 | } 27 | 28 | impl Default for AssetFormat { 29 | fn default() -> Self { 30 | Self::BLOB 31 | } 32 | } 33 | 34 | /// Defines an asset that will be loaded. 35 | 36 | #[derive(Default, Clone, Debug)] 37 | pub struct AssetEntry { 38 | /// The name of this asset. 39 | pub name: String, 40 | 41 | /// The URL or file path this asset will be loaded from. Will be appended to `Manifest.localBase` 42 | /// or `Manifest.remoteBase` to get the actual URL to load from. 43 | pub url: String, 44 | 45 | /// The format this asset will be loaded as. 46 | pub format: AssetFormat, 47 | 48 | /// The size of this asset in bytes, or 0 if unknown. 49 | pub bytes: usize, 50 | } 51 | 52 | impl AssetEntry { 53 | pub fn new(name: String, url: String, format: AssetFormat, bytes: usize) -> Self { 54 | Self { 55 | name, 56 | url, 57 | format, 58 | bytes, 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/engine/d2/asset/asset_pack.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::engine::d2::{display::Texture, sound::Sound, util::Disposable}; 4 | 5 | use super::File; 6 | 7 | /// Represents a collection of fully loaded assets. 8 | pub trait AssetPack: Disposable { 9 | /// The manifest that was used to load this asset pack. 10 | // let manifest (get, None) ->Manifest; 11 | 12 | /// Gets a texture by name from the asset pack. The name must NOT contain a filename extension. 13 | /// Textures are cached, so it's safe to get the same texture multiple times. 14 | /// @param required If true and the asset was not found, an error is thrown. 15 | // required :bool = true 16 | fn texture(&self, name: String, required: bool) -> Option>; 17 | 18 | /// Gets a sound by name from the asset pack. The name must NOT contain a filename extension. 19 | /// Sounds are cached, so it's safe to get the same sound multiple times. 20 | /// @param required If true and the asset was not found, an error is thrown. 21 | // required :bool = true 22 | fn sound(&self, name: String, required: bool) -> Option>; 23 | 24 | /// Gets a file by name from the asset pack, returning its raw content. Files are cached, so it's 25 | /// safe to get the same file multiple times. 26 | /// @param required If true and the asset was not found, an error is thrown. 27 | // required :bool = true 28 | fn file(&self, name: String, required: bool) -> Option>; 29 | } 30 | -------------------------------------------------------------------------------- /src/engine/d2/asset/file.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use super::Asset; 4 | 5 | /// A loaded file containing raw data. 6 | pub trait File: Asset + fmt::Display + fmt::Debug { 7 | // To return the contents of this file as a string. use fmt::Display 8 | } 9 | -------------------------------------------------------------------------------- /src/engine/d2/asset/mod.rs: -------------------------------------------------------------------------------- 1 | //! Asset management 2 | 3 | mod asset_entry; 4 | pub use self::asset_entry::*; 5 | 6 | mod asset_pack; 7 | pub use self::asset_pack::*; 8 | 9 | mod asset; 10 | pub use self::asset::*; 11 | 12 | mod file; 13 | pub use self::file::*; 14 | 15 | mod manifest; 16 | pub use self::manifest::*; 17 | -------------------------------------------------------------------------------- /src/engine/d2/context/webgl_extensions.rs: -------------------------------------------------------------------------------- 1 | // https://www.khronos.org/registry/webgl/extensions/ 2 | #[allow(non_camel_case_types)] 3 | pub enum WebGLExtension { 4 | OES_texture_float, 5 | OES_texture_half_float, 6 | WEBGL_lose_context, 7 | OES_standard_derivatives, 8 | OES_vertex_array_object, 9 | WEBGL_debug_renderer_info, 10 | WEBGL_debug_shaders, 11 | WEBGL_compressed_texture_s3tc, 12 | WEBGL_depth_texture, 13 | OES_element_index_uint, 14 | EXT_texture_filter_anisotropic, 15 | WEBGL_compressed_texture_pvrtc, 16 | EXT_color_buffer_half_float, 17 | WEBGL_color_buffer_float, 18 | EXT_frag_depth, 19 | EXT_sRGB, 20 | WEBGL_draw_buffers, 21 | ANGLE_instanced_arrays, 22 | OES_texture_float_linear, 23 | OES_texture_half_float_linear, 24 | WEBGL_compressed_texture_etc1, 25 | EXT_blend_minmax, 26 | EXT_disjoint_timer_query, 27 | EXT_shader_texture_lod, 28 | OES_fbo_render_mipmap, 29 | WEBGL_compressed_texture_etc, 30 | WEBGL_compressed_texture_astc, 31 | EXT_color_buffer_float, 32 | WEBGL_compressed_texture_s3tc_srgb, 33 | EXT_disjoint_timer_query_webgl2, 34 | EXT_float_blend, 35 | OVR_multiview2, 36 | KHR_parallel_shader_compile, 37 | EXT_texture_compression_bptc, 38 | EXT_texture_compression_rgtc, 39 | WEBGL_multi_draw, 40 | WEBGL_blend_equation_advanced_coherent, 41 | EXT_clip_cull_distance, 42 | OES_draw_buffers_indexed, 43 | EXT_texture_norm16, 44 | WEBGL_draw_instanced_base_vertex_base_instance, 45 | WEBGL_multi_draw_instanced_base_vertex_base_instance, 46 | } 47 | -------------------------------------------------------------------------------- /src/engine/d2/debug/fps_display.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{display::TextSprite, Component}; 2 | 3 | /// A component that uses its entity's TextSprite to display an FPS log. 4 | pub struct FpsDisplay { 5 | pub inner: Component, 6 | fps_frames: usize, 7 | fps_time: f32, 8 | } 9 | 10 | impl FpsDisplay { 11 | pub fn new() -> Self { 12 | Self { 13 | inner: Component::default(), 14 | fps_frames: 0, 15 | fps_time: 0.0, 16 | } 17 | } 18 | 19 | // override 20 | pub fn on_update(&mut self, dt: f32) { 21 | self.fps_frames += 1; 22 | self.fps_time += dt; 23 | if self.fps_time > 1.0 { 24 | let fps = self.fps_frames as f32 / self.fps_time; 25 | let text = format!("FPS: {}", (fps * 100.0) as i32 / 100); 26 | 27 | todo!("should deal with it"); 28 | // Use our owner's TextSprite if available, otherwise just log it 29 | // let sprite = EntityManager::::get(&self.inner.owner); 30 | // if sprite.is_some() { 31 | // sprite.set_text(text); 32 | // } else { 33 | // log::info!("{}", text); 34 | // } 35 | 36 | // self.reset(); 37 | } 38 | } 39 | 40 | fn reset(&mut self) { 41 | self.fps_time = 0.0; 42 | self.fps_frames = 0; 43 | } 44 | } 45 | 46 | impl AsRef for FpsDisplay { 47 | fn as_ref(&self) -> &Component { 48 | &self.inner 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/engine/d2/debug/mod.rs: -------------------------------------------------------------------------------- 1 | //! Debug utilites 2 | mod fps_display; 3 | pub use self::fps_display::*; 4 | -------------------------------------------------------------------------------- /src/engine/d2/display/blend_mode.rs: -------------------------------------------------------------------------------- 1 | /// Blend mode used to composite a sprite. 2 | /// * 3 | /// See [Wikipedia](https://en.wikipedia.org/wiki/Blend_modes) for more info. 4 | 5 | #[derive(Clone, Copy, Debug)] 6 | pub enum BlendMode { 7 | /// Blends the source color on top of the destination, respecting transparency. 8 | /// * 9 | Normal, 10 | 11 | /// Adds the source and destination colors, lightening the final image. 12 | /// * 13 | Add, 14 | 15 | /// Multiplies the source and destination colors, darkening the final image. 16 | /// * 17 | Multiply, 18 | 19 | /// Inverts and multiplies the source and destination colors, lightening the final image. 20 | /// * 21 | Screen, 22 | 23 | /// Masks the overlapping area by applying the source alpha to the destination image. 24 | /// * 25 | /// __WARNING__: In HTML5 canvas, this blend mode is unbounded. It will clear the entire 26 | /// destination image, not just the bounds within the source image. 27 | /// * 28 | Mask, 29 | 30 | /// Ignores the destination color, and copies the source without handling transparency. 31 | /// * 32 | /// __WARNING__: In HTML5 canvas, this blend mode is unbounded. It will clear the entire 33 | /// destination image, not just the bounds within the source image. 34 | /// * 35 | Copy, 36 | } 37 | 38 | impl Default for BlendMode { 39 | fn default() -> Self { 40 | Self::Normal 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/engine/d2/display/fill_sprite.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::animation::AnimatedFloat; 2 | 3 | use super::{Graphics, Sprite}; 4 | 5 | /// A sprite that displays a rectangle filled with a given color. 6 | #[derive(Default, Clone, Debug)] 7 | pub struct FillSprite { 8 | pub inner: Sprite, 9 | pub color: i32, 10 | pub width: AnimatedFloat, 11 | pub height: AnimatedFloat, 12 | } 13 | 14 | impl FillSprite { 15 | pub fn new(color: i32, width: f32, height: f32) -> Self { 16 | Self { 17 | inner: Sprite::new(), 18 | color, 19 | width: AnimatedFloat::new(width, None), 20 | height: AnimatedFloat::new(height, None), 21 | } 22 | } 23 | 24 | // override 25 | pub fn draw(&self, gfx: &Box) { 26 | gfx.fill_rect(self.color, 0.0, 0.0, self.width.get(), self.height.get()); 27 | } 28 | 29 | // override 30 | pub fn natural_width(&self) -> f32 { 31 | self.width.get() 32 | } 33 | 34 | // override 35 | pub fn natural_height(&self) -> f32 { 36 | self.height.get() 37 | } 38 | 39 | /// Chainable convenience method to set the width and height. 40 | /// @returns This instance, for chaining. 41 | pub fn set_size(&mut self, width: f32, height: f32) -> &Self { 42 | self.width.set(width); 43 | self.height.set(height); 44 | 45 | self 46 | } 47 | 48 | // override 49 | pub fn on_update(&mut self, dt: f32) { 50 | self.inner.on_update(dt); 51 | self.width.update(dt); 52 | self.height.update(dt); 53 | } 54 | } 55 | 56 | impl AsRef for FillSprite { 57 | fn as_ref(&self) -> &Sprite { 58 | &self.inner 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/engine/d2/display/image_sprite.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use super::{Graphics, Sprite, Texture}; 4 | 5 | /// A fixed-size sprite that displays a single texture. 6 | #[derive(Default, Clone, Debug)] 7 | pub struct ImageSprite { 8 | pub inner: Sprite, 9 | /// The texture being displayed, or None if none. 10 | pub texture: Option>, 11 | } 12 | 13 | impl ImageSprite { 14 | pub fn new(texture: Option>) -> Self { 15 | Self { 16 | inner: Sprite::new(), 17 | texture, 18 | } 19 | } 20 | 21 | // override 22 | pub fn draw(&self, gfx: &Box) { 23 | if let Some(ref texture) = self.texture { 24 | gfx.draw_texture(texture, 0.0, 0.0); 25 | } 26 | } 27 | 28 | // override 29 | pub fn natural_width(&self) -> f32 { 30 | if let Some(ref texture) = self.texture { 31 | texture.width() as f32 32 | } else { 33 | 0.0 34 | } 35 | } 36 | 37 | // override 38 | pub fn natural_height(&self) -> f32 { 39 | if let Some(ref texture) = self.texture { 40 | texture.height() as f32 41 | } else { 42 | 0.0 43 | } 44 | } 45 | } 46 | 47 | impl AsRef for ImageSprite { 48 | fn as_ref(&self) -> &Sprite { 49 | &self.inner 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/engine/d2/display/mod.rs: -------------------------------------------------------------------------------- 1 | //! Display 2 | 3 | mod blend_mode; 4 | pub use self::blend_mode::*; 5 | 6 | mod emitter_mold; 7 | pub use self::emitter_mold::*; 8 | 9 | mod emitter_sprite; 10 | pub use self::emitter_sprite::*; 11 | 12 | mod fill_sprite; 13 | pub use self::fill_sprite::*; 14 | 15 | mod font; 16 | pub use self::font::*; 17 | 18 | mod graphics; 19 | pub use self::graphics::*; 20 | 21 | mod image_sprite; 22 | pub use self::image_sprite::*; 23 | 24 | mod orientation; 25 | pub use self::orientation::*; 26 | 27 | mod pattern_sprite; 28 | pub use self::pattern_sprite::*; 29 | 30 | mod sprite; 31 | pub use self::sprite::*; 32 | 33 | mod sub_texture; 34 | pub use self::sub_texture::*; 35 | 36 | mod text_sprite; 37 | pub use self::text_sprite::*; 38 | 39 | mod texture; 40 | pub use self::texture::*; 41 | -------------------------------------------------------------------------------- /src/engine/d2/display/orientation.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | /// A display orientation for devices, used by `Stage.lockOrientation()`. 4 | #[derive(Clone, Copy, PartialEq, Debug)] 5 | pub enum Orientation { 6 | Portrait, 7 | Landscape, 8 | } 9 | 10 | impl fmt::Display for Orientation { 11 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 12 | match self { 13 | Orientation::Landscape => write!(f, "Orientation::Landscape"), 14 | Orientation::Portrait => write!(f, "Orientation::Portrait"), 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/engine/d2/display/sub_texture.rs: -------------------------------------------------------------------------------- 1 | use super::Texture; 2 | 3 | /// A sub-region of a texture atlas, created by `Texture.subTexture`. 4 | pub trait SubTexture: Texture { 5 | /// The original texture that this sub-texture is a part of. 6 | fn parent(&self) -> Option>; 7 | 8 | /// The X offset into the parent texture, in pixels. 9 | fn x(&self) -> i32; 10 | 11 | /// The Y offset into the parent texture, in pixels. 12 | fn y(&self) -> i32; 13 | } 14 | -------------------------------------------------------------------------------- /src/engine/d2/input/acceleration.rs: -------------------------------------------------------------------------------- 1 | /// A 3D vector that represents the linear acceleration being applied to the device. 2 | #[derive(Default, Clone, Copy, Debug)] 3 | pub struct Acceleration { 4 | /// The acceleration on the X-axis, in m/s^2. 5 | pub x: f32, 6 | 7 | /// The acceleration on the Y-axis, in m/s^2. 8 | pub y: f32, 9 | 10 | /// The acceleration on the Z-axis, in m/s^2. 11 | pub z: f32, 12 | } 13 | 14 | impl Acceleration { 15 | fn new() -> Self { 16 | Default::default() 17 | } 18 | 19 | fn init(&mut self, x: f32, y: f32, z: f32) { 20 | self.x = x; 21 | self.y = y; 22 | self.z = z; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/engine/d2/input/attitude.rs: -------------------------------------------------------------------------------- 1 | /// Three angles that represent the device's attitude, one around each axis. 2 | #[derive(Default, Clone, Copy, Debug)] 3 | pub struct Attitude { 4 | /// The angle in degrees around the X-axis; that is, how far the device is pitched forward or 5 | /// backward. 6 | pub pitch: f32, 7 | 8 | /// The angle in degrees around the Y-axis; that is, how far the device is rolled left or right. 9 | pub roll: f32, 10 | 11 | /// The angle in degrees around the Z-axis. 12 | pub azimuth: f32, 13 | } 14 | 15 | impl Attitude { 16 | fn new() -> Self { 17 | Default::default() 18 | } 19 | 20 | fn init(&mut self, pitch: f32, roll: f32, azimuth: f32) { 21 | self.pitch = pitch; 22 | self.roll = roll; 23 | self.azimuth = azimuth; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/engine/d2/input/key.rs: -------------------------------------------------------------------------------- 1 | /// All the possible keyboard keys that can be handled. Use Unknown to handle any platform-specific 2 | /// key codes not yet supported here. 3 | #[derive(Copy, Clone, Debug, PartialEq)] 4 | pub enum Key { 5 | A, 6 | B, 7 | C, 8 | D, 9 | E, 10 | F, 11 | G, 12 | H, 13 | I, 14 | J, 15 | K, 16 | L, 17 | M, 18 | N, 19 | O, 20 | P, 21 | Q, 22 | R, 23 | S, 24 | T, 25 | U, 26 | V, 27 | W, 28 | X, 29 | Y, 30 | Z, 31 | 32 | Number0, 33 | Number1, 34 | Number2, 35 | Number3, 36 | Number4, 37 | Number5, 38 | Number6, 39 | Number7, 40 | Number8, 41 | Number9, 42 | 43 | Numpad0, 44 | Numpad1, 45 | Numpad2, 46 | Numpad3, 47 | Numpad4, 48 | Numpad5, 49 | Numpad6, 50 | Numpad7, 51 | Numpad8, 52 | Numpad9, 53 | NumpadAdd, 54 | NumpadDecimal, 55 | NumpadDivide, 56 | NumpadEnter, 57 | NumpadMultiply, 58 | NumpadSubtract, 59 | 60 | F1, 61 | F2, 62 | F3, 63 | F4, 64 | F5, 65 | F6, 66 | F7, 67 | F8, 68 | F9, 69 | F10, 70 | F11, 71 | F12, 72 | F13, 73 | F14, 74 | F15, 75 | 76 | Left, 77 | Up, 78 | Right, 79 | Down, 80 | 81 | Alt, 82 | Backquote, 83 | Backslash, 84 | Backspace, 85 | CapsLock, 86 | Comma, 87 | Command, 88 | Control, 89 | Delete, 90 | End, 91 | Enter, 92 | Equals, 93 | Escape, 94 | Home, 95 | Insert, 96 | LeftBracket, 97 | Minus, 98 | PageDown, 99 | PageUp, 100 | Period, 101 | Quote, 102 | RightBracket, 103 | Semicolon, 104 | Shift, 105 | Slash, 106 | Space, 107 | Tab, 108 | 109 | // Android keys 110 | Menu, 111 | Search, 112 | 113 | /// Used if the environment sends an unknown key code. 114 | Unknown { 115 | keycode: i32, 116 | }, 117 | } 118 | -------------------------------------------------------------------------------- /src/engine/d2/input/keyboard_event.rs: -------------------------------------------------------------------------------- 1 | use super::Key; 2 | 3 | /// Represents an event coming from a physical key press. 4 | /// * 5 | /// NOTE: For performance reasons, KeyboardEvent instances are reused. Use `clone()` to 6 | /// retain a reference to an event. 7 | #[derive(Default, Clone, Debug)] 8 | pub struct KeyboardEvent { 9 | /// The key that caused this event. 10 | pub key: Option, 11 | 12 | /// An incrementing ID unique to every dispatched key event. 13 | pub id: i32, 14 | } 15 | 16 | impl KeyboardEvent { 17 | pub fn new() -> Self { 18 | Self { id: 0, key: None } 19 | } 20 | 21 | pub fn init(&mut self, id: i32, key: Option) { 22 | self.id = id; 23 | self.key = key; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/engine/d2/input/mod.rs: -------------------------------------------------------------------------------- 1 | //! Input 2 | 3 | mod acceleration; 4 | pub use self::acceleration::*; 5 | 6 | mod attitude; 7 | pub use self::attitude::*; 8 | 9 | mod key; 10 | pub use self::key::*; 11 | 12 | mod keyboard_event; 13 | pub use self::keyboard_event::*; 14 | 15 | mod mouse_button; 16 | pub use self::mouse_button::*; 17 | 18 | mod mouse_cursor; 19 | pub use self::mouse_cursor::*; 20 | 21 | mod mouse_event; 22 | pub use self::mouse_event::*; 23 | 24 | mod pointer_event; 25 | pub use self::pointer_event::*; 26 | 27 | mod touch_point; 28 | pub use self::touch_point::*; 29 | -------------------------------------------------------------------------------- /src/engine/d2/input/mouse_button.rs: -------------------------------------------------------------------------------- 1 | /// All the possible mouse buttons that can be handled. Use Unknown to handle any platform-specific 2 | /// buttons not supported here. 3 | 4 | #[derive(Copy, Clone, Debug)] 5 | pub enum MouseButton { 6 | Left, 7 | Middle, 8 | Right, 9 | 10 | /// Used if the environment sends an unknown button. 11 | Unknown { 12 | button_code: u32, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /src/engine/d2/input/mouse_cursor.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug)] 2 | pub enum MouseCursor { 3 | /// The default system cursor, typically an arrow. 4 | Default, 5 | 6 | /// The system cursor used when hovering over buttons and links, typically a hand. 7 | Button, 8 | 9 | /// An invisible cursor. 10 | None, 11 | // Image(texture :Texture, anchorX: i32, anchorY: i32); 12 | } 13 | -------------------------------------------------------------------------------- /src/engine/d2/input/mouse_event.rs: -------------------------------------------------------------------------------- 1 | use super::MouseButton; 2 | /// Represents an event coming from a mouse. 3 | /// * 4 | /// NOTE: For performance reasons, MouseEvent instances are reused. Use `clone()` to 5 | /// retain a reference to an event. 6 | #[derive(Default, Clone, Debug)] 7 | 8 | pub struct MouseEvent { 9 | /// The X position of the mouse, in view (stage) coordinates. 10 | pub view_x: f32, 11 | 12 | /// The Y position of the mouse, in view (stage) coordinates. 13 | pub view_y: f32, 14 | 15 | /// The mouse button that caused this event, or None for movement events. 16 | pub button: Option, 17 | 18 | /// An incrementing ID unique to every dispatched mouse event. 19 | pub id: i32, 20 | } 21 | 22 | impl MouseEvent { 23 | pub fn new() -> Self { 24 | Self { 25 | id: 0, 26 | view_x: 0.0, 27 | view_y: 0.0, 28 | button: None, 29 | } 30 | } 31 | 32 | pub fn init(&mut self, id: i32, view_x: f32, view_y: f32, button: Option) { 33 | self.id = id; 34 | self.view_x = view_x; 35 | self.view_y = view_y; 36 | self.button = button; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/engine/d2/input/touch_point.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use super::EventSource; 4 | 5 | /// Represents a touch screen contact point, such as a finger. It is possible to retain a reference 6 | /// to a TouchPoint, and track changes to it over time. 7 | #[derive(Default, Clone, Debug)] 8 | pub struct TouchPoint { 9 | /// The X position of the touch, in view (stage) coordinates. This value is modified when the 10 | /// point moves. 11 | pub view_x: f32, 12 | 13 | /// The Y position of the touch, in view (stage) coordinates. This value is modified when the 14 | /// point moves. 15 | pub view_y: f32, 16 | 17 | /// An identifier unique to this touch. 18 | pub id: i32, 19 | // Cached to avoid lots of allocation 20 | pub source: Option>, 21 | } 22 | 23 | impl TouchPoint { 24 | pub fn new(id: i32) -> Self { 25 | Self { 26 | id, 27 | // source: None, //EventSource::Touch(self) 28 | ..Default::default() 29 | } 30 | } 31 | 32 | pub fn init(&mut self, view_x: f32, view_y: f32) { 33 | self.view_x = view_x; 34 | self.view_y = view_y; 35 | } 36 | } 37 | 38 | impl PartialEq for TouchPoint { 39 | fn eq(&self, other: &Self) -> bool { 40 | self.id == other.id 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/engine/d2/math/fmath.rs: -------------------------------------------------------------------------------- 1 | use std::f32::consts::PI; 2 | 3 | // use std::f32::consts::{E, FRAC_1_SQRT_2, LN_10, LN_2, LOG10_E, LOG2_E, PI, SQRT_2}; 4 | 5 | /// Some handy math functions, and inlinable constants. 6 | pub struct Math {} 7 | 8 | impl Math { 9 | pub const SQRT1_2: f32 = std::f32::consts::FRAC_1_SQRT_2; // 0.7071067811865476; // FRAC_1_SQRT_2 10 | 11 | // doesn't specify the size of an int or float, in practice it's 32 bits 12 | /// The lowest integer value. 13 | pub const INT_MIN: i32 = -2147483648; 14 | 15 | /// The highest integer value. 16 | pub const INT_MAX: i32 = 2147483647; 17 | 18 | /// The lowest float value. 19 | pub const FLOAT_MIN: f32 = std::f32::MIN; //-1.79769313486231e+308; 20 | 21 | /// The highest float value. 22 | 23 | pub const FLOAT_MAX: f32 = std::f32::MAX; //1.79769313486231e+308; 24 | 25 | /// Converts an angle in degrees to radians. 26 | // static 27 | #[inline] 28 | pub fn to_radians(degrees: f32) -> f32 { 29 | degrees * PI / 180.0 30 | } 31 | 32 | /// Converts an angle in radians to degrees. 33 | // static 34 | #[inline] 35 | pub fn to_degrees(radians: f32) -> f32 { 36 | radians * 180.0 / PI 37 | } 38 | 39 | // // static 40 | // #[inline] 41 | // pub fn max(a: T, b: T) -> T { 42 | // if a > b { 43 | // a 44 | // } else { 45 | // b 46 | // } 47 | // } 48 | 49 | // // static 50 | // #[inline] 51 | // pub fn min(a: T, b: T) -> T { 52 | // if a < b { 53 | // a 54 | // } else { 55 | // b 56 | // } 57 | // } 58 | 59 | // // static 60 | // pub fn clamp(value: T, min: T, max: T) -> T { 61 | // if value < min { 62 | // min 63 | // } else if value > max { 64 | // max 65 | // } else { 66 | // value; 67 | // } 68 | // } 69 | 70 | // static 71 | pub fn sign(value: f32) -> i32 { 72 | if value < 0.0 { 73 | -1 74 | } else if value > 0.0 { 75 | 1 76 | } else { 77 | 0 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/engine/d2/math/mod.rs: -------------------------------------------------------------------------------- 1 | //! Math 2 | 3 | mod fmath; 4 | pub use self::fmath::*; 5 | 6 | mod matrix; 7 | pub use self::matrix::*; 8 | 9 | mod point; 10 | pub use self::point::*; 11 | 12 | mod rectangle; 13 | pub use self::rectangle::*; 14 | -------------------------------------------------------------------------------- /src/engine/d2/mod.rs: -------------------------------------------------------------------------------- 1 | //! 2D game-engine 2 | 3 | #![allow(unused_imports)] 4 | pub mod animation; 5 | 6 | pub mod asset; 7 | 8 | mod context; 9 | pub use context::*; 10 | 11 | pub mod debug; 12 | 13 | pub mod display; 14 | 15 | pub mod input; 16 | 17 | pub mod math; 18 | 19 | pub mod platform; 20 | 21 | pub mod scene; 22 | 23 | pub mod script; 24 | 25 | pub mod sound; 26 | 27 | pub mod subsystem; 28 | 29 | pub mod swf; 30 | 31 | pub mod util; 32 | 33 | pub mod web; 34 | 35 | mod component; 36 | pub use self::component::*; 37 | 38 | mod director; 39 | pub use self::director::*; 40 | 41 | mod disposer; 42 | pub use self::disposer::*; 43 | 44 | mod entity; 45 | pub use self::entity::*; 46 | 47 | mod speed_adjuster; 48 | pub use self::speed_adjuster::*; 49 | 50 | mod system; 51 | pub use self::system::*; 52 | -------------------------------------------------------------------------------- /src/engine/d2/platform/basic_asset.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::RefCell, marker::PhantomData}; 2 | 3 | use crate::engine::d2::{ 4 | asset::Asset, 5 | util::{Disposable, Value}, 6 | }; 7 | 8 | #[derive(Clone, Debug)] 9 | struct BasicAssetProps { 10 | pub disposed: bool, 11 | reload_count: Value, 12 | } 13 | 14 | #[derive(Clone, Debug)] 15 | pub struct BasicAsset { 16 | props: RefCell, 17 | marker: PhantomData, 18 | } 19 | 20 | impl BasicAsset { 21 | pub fn new() -> Self { 22 | Default::default() 23 | } 24 | 25 | #[inline] 26 | pub fn assert_not_disposed(&self) { 27 | let props = self.props.borrow(); 28 | assert!(!props.disposed, "Asset cannot be used after being disposed"); 29 | } 30 | 31 | pub fn reload(&self, asset: A) { 32 | let mut props = self.props.borrow_mut(); 33 | self.dispose(); 34 | props.disposed = false; 35 | self.copy_from(asset); 36 | let reload_count = *props.reload_count.get(); 37 | props.reload_count.set(reload_count + 1); 38 | } 39 | 40 | /// Fully copy the content from another asset type, for reloading. 41 | pub fn copy_from(&self, asset: A) { 42 | panic!("See subclasses"); 43 | } 44 | 45 | /// Handle disposing. 46 | pub fn on_disposed(&self) { 47 | panic!("See subclasses"); 48 | } 49 | } 50 | 51 | impl Default for BasicAsset { 52 | fn default() -> Self { 53 | Self { 54 | props: RefCell::new(BasicAssetProps { 55 | disposed: false, 56 | reload_count: Value::::new(0, None), 57 | }), 58 | marker: PhantomData, 59 | } 60 | } 61 | } 62 | 63 | impl Asset for BasicAsset { 64 | // Overridden in subclasses! 65 | fn reload_count(&self) -> usize { 66 | let props = self.props.borrow(); 67 | *props.reload_count.get() 68 | } 69 | } 70 | 71 | impl Disposable for BasicAsset { 72 | fn dispose(&self) { 73 | let mut props = self.props.borrow_mut(); 74 | if !props.disposed { 75 | props.disposed = true; 76 | self.on_disposed(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/engine/d2/platform/basic_file.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use crate::engine::d2::{ 4 | asset::{Asset, File}, 5 | util::{Disposable, Value}, 6 | }; 7 | 8 | use super::BasicAsset; 9 | 10 | pub struct BasicFile { 11 | pub inner: BasicAsset, 12 | content: Option, 13 | } 14 | 15 | impl BasicFile { 16 | pub fn new(content: Option) -> Self { 17 | Self { 18 | inner: BasicAsset::new(), 19 | content, 20 | } 21 | } 22 | 23 | // override 24 | fn copy_from(&mut self, that: BasicFile) { 25 | self.content = that.content; 26 | } 27 | 28 | // override 29 | fn on_disposed(&mut self) { 30 | self.content = None; 31 | } 32 | } 33 | 34 | impl AsRef> for BasicFile { 35 | fn as_ref(&self) -> &BasicAsset { 36 | &self.inner 37 | } 38 | } 39 | 40 | impl File for BasicFile {} 41 | 42 | impl Asset for BasicFile { 43 | fn reload_count(&self) -> usize { 44 | self.inner.reload_count() 45 | } 46 | } 47 | 48 | impl Disposable for BasicFile { 49 | fn dispose(&self) { 50 | self.inner.dispose() 51 | } 52 | } 53 | 54 | impl fmt::Display for BasicFile { 55 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 56 | self.inner.assert_not_disposed(); 57 | write!( 58 | f, 59 | "{}", 60 | self.content.clone().unwrap_or(String::from("None")) 61 | ) 62 | } 63 | } 64 | 65 | impl fmt::Debug for BasicFile { 66 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 67 | f.debug_struct("BasicFile") 68 | // .field("x", &self.x) 69 | // .field("y", &self.y) 70 | .finish() 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/engine/d2/platform/debug_logic.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{display::Graphics, input::Key, System}; 2 | 3 | use super::OverdrawGraphics; 4 | 5 | /// Internal helper for shared debug logic across all platforms. 6 | pub struct DebugLogic { 7 | // platform: Box, 8 | /// The normal Graphics saved by toggleOverdrawGraphics so it can restored. 9 | saved_graphics: Option>, 10 | } 11 | 12 | impl DebugLogic { 13 | pub fn init() { 14 | let instance = Self { 15 | // platform: Box::new(platform), 16 | saved_graphics: None, 17 | }; 18 | 19 | System::keyboard().down_signal().connect( 20 | Box::new(move |event| { 21 | if let Some(key) = event.key { 22 | if key == Key::O && System::keyboard().is_down(Key::Control) { 23 | if instance.toggle_overdraw_graphics() { 24 | log::info!( 25 | "Enabled overdraw visualizer, press Ctrl-O again to disable" 26 | ); 27 | } 28 | } 29 | } 30 | }), 31 | false, 32 | ); 33 | 34 | // instance 35 | } 36 | 37 | /// Toggles the overdraw debug renderer. 38 | /// @return Whether the overdraw renderer was enabled. 39 | pub fn toggle_overdraw_graphics(&self) -> bool { 40 | // let renderer = self.platform.renderer(); 41 | 42 | if self.saved_graphics.is_some() { 43 | // renderer.set_graphics(self.saved_graphics); 44 | // self.saved_graphics = None; 45 | // } else if renderer.graphics().is_some() { 46 | // self.saved_graphics = renderer.get_graphics(); 47 | // renderer.set_graphics(OverdrawGraphics::new(self.saved_graphics)); 48 | // return true; 49 | } 50 | 51 | false 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/engine/d2/platform/dummy_external.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::subsystem::ExternalSystem; 2 | 3 | use super::Dynamic; 4 | 5 | #[derive(Default, Clone, Copy, Debug)] 6 | pub struct DummyExternal { 7 | pub supported: bool, 8 | } 9 | 10 | impl DummyExternal { 11 | pub fn new() -> Self { 12 | Default::default() 13 | } 14 | } 15 | 16 | impl ExternalSystem for DummyExternal { 17 | fn is_supported(&self) -> bool { 18 | false 19 | } 20 | 21 | fn call(&self, name: String, params: Option>) -> Option { 22 | None 23 | } 24 | 25 | fn bind(&self, name: String, function: Dynamic) {} 26 | } 27 | -------------------------------------------------------------------------------- /src/engine/d2/platform/dummy_keyboard.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{ 2 | input::{Key, KeyboardEvent}, 3 | subsystem::KeyboardSystem, 4 | util::{Signal0, Signal1}, 5 | }; 6 | 7 | pub struct DummyKeyboard { 8 | pub down: Signal1, 9 | pub up: Signal1, 10 | pub back_button: Signal0, 11 | } 12 | 13 | impl DummyKeyboard { 14 | pub fn new() -> Self { 15 | Self { 16 | down: Signal1::new(None), 17 | up: Signal1::new(None), 18 | back_button: Signal0::new(None), 19 | } 20 | } 21 | } 22 | 23 | impl KeyboardSystem for DummyKeyboard { 24 | fn back_button(&self) -> &Signal0 { 25 | &self.back_button 26 | } 27 | 28 | fn down_signal(&self) -> &Signal1 { 29 | &self.down 30 | } 31 | 32 | fn up_signal(&self) -> &Signal1 { 33 | &self.up 34 | } 35 | 36 | fn is_supported(&self) -> bool { 37 | false 38 | } 39 | 40 | fn is_down(&self, key: Key) -> bool { 41 | false 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/engine/d2/platform/dummy_motion.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{ 2 | input::{Acceleration, Attitude}, 3 | subsystem::MotionSystem, 4 | util::Signal1, 5 | }; 6 | 7 | pub struct DummyMotion { 8 | pub acceleration: Signal1, 9 | pub acceleration_including_gravity: Signal1, 10 | pub attitude: Signal1, 11 | } 12 | 13 | impl DummyMotion { 14 | pub fn new() -> Self { 15 | Self { 16 | acceleration: Signal1::new(None), 17 | acceleration_including_gravity: Signal1::new(None), 18 | attitude: Signal1::new(None), 19 | } 20 | } 21 | } 22 | 23 | impl MotionSystem for DummyMotion { 24 | fn acceleration(&self) -> &Signal1 { 25 | &self.acceleration 26 | } 27 | 28 | fn acceleration_including_gravity(&self) -> &Signal1 { 29 | &self.acceleration_including_gravity 30 | } 31 | 32 | fn attitude(&self) -> &Signal1 { 33 | &self.attitude 34 | } 35 | 36 | fn is_acceleration_supported(&self) -> bool { 37 | false 38 | } 39 | 40 | fn is_attitude_supported(&self) -> bool { 41 | false 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/engine/d2/platform/dummy_mouse.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{ 2 | input::{MouseButton, MouseCursor, MouseEvent}, 3 | subsystem::MouseSystem, 4 | util::Signal1, 5 | }; 6 | 7 | pub struct DummyMouse { 8 | pub down: Signal1, 9 | pub move_: Signal1, 10 | pub up: Signal1, 11 | pub scroll: Signal1, 12 | cursor: MouseCursor, 13 | } 14 | 15 | impl DummyMouse { 16 | pub fn new() -> Self { 17 | Self { 18 | down: Signal1::new(None), 19 | move_: Signal1::new(None), 20 | up: Signal1::new(None), 21 | scroll: Signal1::new(None), 22 | cursor: MouseCursor::Default, 23 | } 24 | } 25 | 26 | pub fn set_cursor(&mut self, cursor: MouseCursor) { 27 | self.cursor = cursor; 28 | } 29 | } 30 | 31 | impl MouseSystem for DummyMouse { 32 | fn down_signal(&self) -> &Signal1 { 33 | &self.down 34 | } 35 | 36 | fn move_signal(&self) -> &Signal1 { 37 | &self.move_ 38 | } 39 | 40 | fn scroll_signal(&self) -> &Signal1 { 41 | &self.scroll 42 | } 43 | 44 | fn up_signal(&self) -> &Signal1 { 45 | &self.up 46 | } 47 | 48 | fn is_supported(&self) -> bool { 49 | false 50 | } 51 | 52 | fn x(&self) -> f32 { 53 | 0.0 54 | } 55 | 56 | fn y(&self) -> f32 { 57 | 0.0 58 | } 59 | 60 | fn is_down(&self, button: MouseButton) -> bool { 61 | false 62 | } 63 | 64 | fn cursor(&self) -> MouseCursor { 65 | self.cursor 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/engine/d2/platform/dummy_storage.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::engine::d2::subsystem::StorageSystem; 4 | 5 | use super::Dynamic; 6 | 7 | pub struct DummyStorage { 8 | hash: HashMap, 9 | } 10 | 11 | impl DummyStorage { 12 | pub fn new() -> Self { 13 | Self { 14 | hash: HashMap::new(), 15 | } 16 | } 17 | } 18 | 19 | impl StorageSystem for DummyStorage { 20 | fn is_supported(&self) -> bool { 21 | false 22 | } 23 | 24 | fn set(&self, key: String, value: A) -> bool { 25 | // self.hash.insert(key, value); 26 | // true 27 | unimplemented!() 28 | } 29 | 30 | fn get(&self, key: String) -> Option<&A> { 31 | // self.hash.get(&key) 32 | unimplemented!() 33 | } 34 | 35 | fn remove(&mut self, key: String) { 36 | self.hash.remove(&key); 37 | } 38 | 39 | fn clear(&mut self) { 40 | self.hash.clear(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/engine/d2/platform/dummy_touch.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{input::TouchPoint, subsystem::TouchSystem, util::Signal1}; 2 | 3 | pub struct DummyTouch { 4 | // pub supported: bool, 5 | // pub maxPoints: i32, 6 | // pub points: Vec, 7 | pub down: Signal1, 8 | pub move_: Signal1, 9 | pub up: Signal1, 10 | } 11 | 12 | impl DummyTouch { 13 | pub fn new() -> Self { 14 | Self { 15 | down: Signal1::new(None), 16 | move_: Signal1::new(None), 17 | up: Signal1::new(None), 18 | } 19 | } 20 | } 21 | 22 | impl TouchSystem for DummyTouch { 23 | fn is_supported(&self) -> bool { 24 | return false; 25 | } 26 | 27 | fn max_points(&self) -> i32 { 28 | return 0; 29 | } 30 | 31 | fn down_signal(&self) -> &Signal1 { 32 | &self.down 33 | } 34 | 35 | fn move_signal(&self) -> &Signal1 { 36 | &self.move_ 37 | } 38 | 39 | fn up_signal(&self) -> &Signal1 { 40 | &self.up 41 | } 42 | 43 | fn points(&self) -> Vec { 44 | Vec::new() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/engine/d2/platform/dummy_web.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{subsystem::WebSystem, web::WebView}; 2 | 3 | pub struct DummyWeb; 4 | 5 | impl DummyWeb { 6 | pub fn new() -> Self { 7 | Self {} 8 | } 9 | } 10 | 11 | impl WebSystem for DummyWeb { 12 | fn create_view(&self, x: f32, y: f32, width: f32, height: f32) -> Box { 13 | panic!("Web.createView is unsupported in this environment, check the `supported` flag."); 14 | } 15 | 16 | fn is_supported(&self) -> bool { 17 | false 18 | } 19 | 20 | fn open_browser(&self, url: String) { 21 | // Nothing 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/engine/d2/platform/event_group.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::util::Disposable; 2 | 3 | use super::{Dynamic, Event, IEventDispatcher}; 4 | 5 | pub type Listener = Box; 6 | 7 | /// Manages a group of event listeners. When the group is disposed, all listeners are removed. 8 | pub struct EventGroup { 9 | entries: Vec, 10 | } 11 | 12 | impl EventGroup { 13 | pub fn new() -> Self { 14 | Self { 15 | entries: Vec::new(), 16 | } 17 | } 18 | 19 | /// Register a listener with this group. 20 | pub fn add_listener(&self, dispatcher: IEventDispatcher, type_: String, listener: Listener) { 21 | // dispatcher.addEventListener(type_, listener, false); 22 | // self.entries.push(Entry::new(dispatcher, type_, listener)); 23 | unimplemented!() 24 | } 25 | 26 | /// Register a listener with this group, all listeners are removed when it's fired. 27 | pub fn add_disposing_listener( 28 | &self, 29 | dispatcher: IEventDispatcher, 30 | type_: String, 31 | listener: Listener, 32 | ) { 33 | // self.add_listener(dispatcher, type_, Box::new(|event: Event| { 34 | // self.dispose(); 35 | // listener(event); 36 | // })); 37 | unimplemented!() 38 | } 39 | } 40 | 41 | impl Disposable for EventGroup { 42 | /// Detach all listeners registered with this group. 43 | fn dispose(&self) { 44 | // for entry in self.entries { 45 | // entry.dispatcher.removeEventListener(entry.type_, entry.listener, false); 46 | // } 47 | // self.entries = Vec::new(); 48 | unimplemented!() 49 | } 50 | } 51 | 52 | pub struct Entry { 53 | pub dispatcher: IEventDispatcher, 54 | pub type_: String, 55 | pub listener: Listener, 56 | } 57 | 58 | impl Entry { 59 | pub fn new(dispatcher: IEventDispatcher, type_: String, listener: Listener) -> Self { 60 | Self { 61 | dispatcher, 62 | type_, 63 | listener, 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/engine/d2/platform/heavy_signal1.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::util::{Listener1, Signal1, SignalConnection, Value}; 2 | 3 | /// An internal Signal1 with extra frills. 4 | pub struct HeavySignal1 { 5 | pub inner: Signal1, 6 | /// A watchable value, for detecting when the first listener was connected, or the last 7 | /// connection was disposed. 8 | pub has_listeners_value: Value, 9 | } 10 | 11 | impl HeavySignal1 { 12 | pub fn new(listener: Option>) -> Self { 13 | let inner = Signal1::new(listener); 14 | let has_listeners_value = Value::::new(inner.inner.has_listeners(), None); 15 | 16 | Self { 17 | inner, 18 | has_listeners_value, 19 | } 20 | } 21 | 22 | // override 23 | // prioritize :bool = false 24 | pub fn connect(&mut self, listener: Listener1, prioritize: bool) -> SignalConnection { 25 | let connection = self.inner.connect(listener, prioritize); 26 | self.has_listeners_value 27 | .set(self.inner.inner.has_listeners()); 28 | return connection; 29 | } 30 | 31 | // override 32 | fn disconnect(&mut self, conn: SignalConnection) { 33 | self.inner.inner.disconnect(&conn); 34 | self.has_listeners_value 35 | .set(self.inner.inner.has_listeners()); 36 | } 37 | 38 | // override 39 | fn did_emit(&mut self, head: SignalConnection) { 40 | self.inner.inner.did_emit(head); 41 | self.has_listeners_value 42 | .set(self.inner.inner.has_listeners()); 43 | } 44 | } 45 | 46 | impl AsRef> for HeavySignal1 { 47 | fn as_ref(&self) -> &Signal1 { 48 | &self.inner 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/engine/d2/platform/math_util.rs: -------------------------------------------------------------------------------- 1 | pub struct MathUtil {} 2 | 3 | impl MathUtil { 4 | /// Returns the smallest power of two >= n. 5 | // static 6 | pub fn next_power_of_two(n: i32) -> i32 { 7 | let mut p = 1; 8 | while p < n { 9 | p <<= 1; 10 | } 11 | return p; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/engine/d2/platform/mouse_codes.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::input::MouseButton; 2 | 3 | /// Mouse button codes used internally. 4 | pub struct MouseCodes {} 5 | 6 | impl MouseCodes { 7 | const LEFT: u32 = 0; 8 | const MIDDLE: u32 = 1; 9 | const RIGHT: u32 = 2; 10 | 11 | // static 12 | pub fn to_button(button_code: u32) -> MouseButton { 13 | match button_code { 14 | Self::LEFT => MouseButton::Left, 15 | Self::MIDDLE => MouseButton::Middle, 16 | Self::RIGHT => MouseButton::Right, 17 | _ => MouseButton::Unknown { button_code }, 18 | } 19 | } 20 | 21 | // static 22 | pub fn to_button_code(button: MouseButton) -> u32 { 23 | match button { 24 | MouseButton::Left => Self::LEFT, 25 | MouseButton::Middle => Self::MIDDLE, 26 | MouseButton::Right => Self::RIGHT, 27 | MouseButton::Unknown { button_code } => button_code, 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/engine/d2/platform/platform.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{ 2 | asset::{AssetPack, Manifest}, 3 | subsystem::*, 4 | util::Promise, 5 | }; 6 | 7 | use super::WampClient; 8 | 9 | pub trait Platform { 10 | fn init(&self); 11 | 12 | fn external(&self) -> Box; 13 | fn keyboard(&self) -> Box; 14 | fn motion(&self) -> Box; 15 | fn mouse(&self) -> Box; 16 | fn pointer(&self) -> Box; 17 | fn renderer(&self) -> Box; 18 | fn stage(&self) -> Box; 19 | fn storage(&self) -> Box; 20 | fn touch(&self) -> Box; 21 | fn web(&self) -> Box; 22 | 23 | fn load_asset_pack(&self, manifest: Manifest) -> Promise>; 24 | fn wamp_client(&self) -> Option; 25 | 26 | fn locale(&self) -> Option; 27 | fn time(&self) -> f32; 28 | } 29 | -------------------------------------------------------------------------------- /src/engine/d2/platform/shader/mod.rs: -------------------------------------------------------------------------------- 1 | mod draw_pattern_gl; 2 | pub use self::draw_pattern_gl::*; 3 | 4 | mod draw_texture_gl; 5 | pub use self::draw_texture_gl::*; 6 | 7 | mod fill_rect_gl; 8 | pub use self::fill_rect_gl::*; 9 | 10 | mod shader_gl; 11 | pub use self::shader_gl::*; 12 | -------------------------------------------------------------------------------- /src/engine/d2/platform/texture_root.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | 3 | use crate::engine::d2::{ 4 | display::{Graphics, Texture}, 5 | util::Disposable, 6 | }; 7 | 8 | /// The "root" of a texture atlas. An internal abstraction that makes implementing subTexture() easier 9 | /// across platforms. 10 | pub trait TextureRoot: Disposable { 11 | fn width(&self) -> i32; 12 | fn height(&self) -> i32; 13 | 14 | fn create_texture(&self, width: i32, height: i32) -> Box; // BasicTexture 15 | 16 | fn read_pixels(&self, x: i32, y: i32, width: i32, height: i32) -> Bytes; 17 | fn write_pixels(&self, pixels: Bytes, x: i32, y: i32, source_w: i32, source_h: i32); 18 | 19 | fn graphics(&self) -> Box; 20 | } 21 | -------------------------------------------------------------------------------- /src/engine/d2/platform/tickable.rs: -------------------------------------------------------------------------------- 1 | /// An object that exists outside of the entity hierarchy, but still needs to be updated each frame. 2 | /// This is an implementation detail, nothing outside of d2::platform should implement self. 3 | pub trait Tickable { 4 | /// @param dt The elapsed delta-time in seconds. 5 | /// @returns True if this Tickable should no longer be updated. 6 | fn update(&self, dt: f32) -> bool; 7 | } 8 | -------------------------------------------------------------------------------- /src/engine/d2/platform/wamp_client.rs: -------------------------------------------------------------------------------- 1 | use super::BasicAssetPackLoader; 2 | 3 | /// Handles communication with the Wamp server run by `cargo ux serve`, for live reloading. 4 | pub struct WampClient { 5 | loaders: Vec, 6 | } 7 | 8 | impl WampClient { 9 | fn new() -> Self { 10 | Self { 11 | loaders: Vec::new(), 12 | } 13 | } 14 | 15 | pub fn add(&mut self, loader: BasicAssetPackLoader) { 16 | // Only care about packs loaded from the assets directory 17 | #[cfg(not(feature = "disable_reloading"))] 18 | { 19 | if let Some(ref local_base) = loader.manifest.local_base { 20 | if local_base.as_str() == "assets" { 21 | self.loaders.push(loader); 22 | } 23 | } 24 | } 25 | } 26 | 27 | pub fn remove(&mut self, loader: &BasicAssetPackLoader) { 28 | self.loaders.retain(|x| x != loader); 29 | } 30 | 31 | fn on_error(&self, cause: String) { 32 | log::warn!("Unable to connect to Wamp {}", cause); 33 | } 34 | 35 | fn on_message(&self, message: String) { 36 | // let message = Json::parse(message); 37 | // match message.type_ { 38 | // "file_changed" => { 39 | // let url = message.name + "?v=" + message.md5; 40 | // url = url.replace("\\", "/"); // Handle backslash paths in Windows 41 | // for loader in self._loaders { 42 | // loader.reload(url); 43 | // } 44 | // } 45 | // "restart" => { 46 | // self.on_restart(); 47 | // } 48 | // } 49 | unimplemented!() 50 | } 51 | 52 | fn on_restart(&self) { 53 | panic!("See subclasses"); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/engine/d2/scene/fade_transition.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{animation::EaseFunction, display::Sprite, Entity, EntityManager}; 2 | 3 | use super::TweenTransition; 4 | 5 | /// Fades the new scene in front of the old scene. 6 | 7 | pub struct FadeTransition { 8 | pub inner: TweenTransition, 9 | } 10 | 11 | impl FadeTransition { 12 | pub fn new(duration: f32, ease: Option) -> Self { 13 | Self { 14 | inner: TweenTransition::new(duration, ease), 15 | } 16 | } 17 | 18 | // override 19 | pub fn init(&mut self, from: Entity, to: Entity) { 20 | self.inner.init(from, to); 21 | if let Some(ref mut sprite) = EntityManager::::get(&self.inner.inner.to) { 22 | sprite.alpha.set(0.0); 23 | } else { 24 | let sprite = Sprite::new(); 25 | self.inner.inner.to.add(sprite.component); 26 | sprite.alpha.set(0.0); 27 | } 28 | } 29 | 30 | // override 31 | pub fn update(&mut self, dt: f32) -> bool { 32 | let done = self.inner.update(dt); 33 | if let Some(ref mut sprite) = EntityManager::::get(&self.inner.inner.to) { 34 | sprite.alpha.set(self.inner.interp(0.0, 1.0)); 35 | } 36 | done 37 | } 38 | 39 | // override 40 | pub fn complete(&self) { 41 | if let Some(ref mut sprite) = EntityManager::::get(&self.inner.inner.to) { 42 | sprite.alpha.set(1.0); 43 | } 44 | } 45 | } 46 | 47 | impl AsRef for FadeTransition { 48 | fn as_ref(&self) -> &TweenTransition { 49 | &self.inner 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/engine/d2/scene/mod.rs: -------------------------------------------------------------------------------- 1 | //! Scene management 2 | 3 | mod fade_transition; 4 | pub use self::fade_transition::*; 5 | 6 | mod scene; 7 | pub use self::scene::*; 8 | 9 | mod slide_transition; 10 | pub use self::slide_transition::*; 11 | 12 | mod transition; 13 | pub use self::transition::*; 14 | 15 | mod tween_transition; 16 | pub use self::tween_transition::*; 17 | -------------------------------------------------------------------------------- /src/engine/d2/scene/scene.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{util::Signal0, Component}; 2 | 3 | /// Optional, extra functionality for scene entities that are added to a Director. 4 | #[derive(Default, Clone, Debug)] 5 | pub struct Scene2D { 6 | pub inner: Component, 7 | /// Emitted by the Director when this scene becomes the top scene. 8 | pub shown: Signal0, 9 | 10 | /// Emitted by the Director when this scene is no longer the top scene. 11 | pub hidden: Signal0, 12 | 13 | /// When true, hints that scenes below this one don't need to be rendered. Scenes that don't fill 14 | /// the entire stage or have a transparent background should set this to false. 15 | pub opaque: bool, 16 | } 17 | 18 | impl Scene2D { 19 | // opaque :bool = true 20 | pub fn new(opaque: bool) -> Self { 21 | Self { 22 | inner: Component::default(), 23 | opaque, 24 | shown: Signal0::new(None), 25 | hidden: Signal0::new(None), 26 | } 27 | } 28 | } 29 | 30 | impl AsRef for Scene2D { 31 | fn as_ref(&self) -> &Component { 32 | &self.inner 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/engine/d2/scene/transition.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::Entity; 2 | 3 | /// A transition between two scenes. 4 | #[derive(Default, Clone, Debug)] 5 | pub struct Transition { 6 | pub from: Entity, 7 | pub to: Entity, 8 | } 9 | 10 | impl Transition { 11 | /// Called by the Director to start the transition. 12 | /// @param from The old scene being transitioned from. 13 | /// @param to The new scene being transitioned to. 14 | pub fn init(&mut self, from: Entity, to: Entity) { 15 | self.from = from; 16 | self.to = to; 17 | } 18 | 19 | /// Called by the Director to update the transition. 20 | /// @returns True if the transition is complete. 21 | pub fn update(&self, dt: f32) -> bool { 22 | // See subclasses 23 | true 24 | } 25 | 26 | /// Completes the transition. Note that the Director may call this at any time to fast-forward 27 | /// the transition. 28 | pub fn complete(&self) { 29 | // See subclasses 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/engine/d2/scene/tween_transition.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::engine::d2::{ 4 | animation::{Ease, EaseFunction}, 5 | Entity, 6 | }; 7 | 8 | use super::Transition; 9 | 10 | /// A helper extended by transitions that tween between two states. 11 | pub struct TweenTransition { 12 | pub inner: Transition, 13 | pub ease: EaseFunction, 14 | pub elapsed: f32, 15 | pub duration: f32, 16 | } 17 | 18 | impl TweenTransition { 19 | pub fn new(duration: f32, ease: Option) -> Self { 20 | Self { 21 | inner: Transition::default(), 22 | elapsed: 0.0, 23 | duration, 24 | ease: if let Some(ease) = ease { 25 | ease 26 | } else { 27 | Rc::new(Ease::linear) 28 | }, 29 | } 30 | } 31 | 32 | // override 33 | pub fn init(&mut self, from: Entity, to: Entity) { 34 | self.inner.init(from, to); 35 | self.elapsed = 0.0; 36 | } 37 | 38 | // override 39 | pub fn update(&mut self, dt: f32) -> bool { 40 | self.elapsed += dt; 41 | 42 | self.elapsed >= self.duration 43 | } 44 | 45 | pub fn interp(&self, from: f32, to: f32) -> f32 { 46 | from + (to - from) * (self.ease)(self.elapsed / self.duration) 47 | } 48 | } 49 | 50 | impl AsRef for TweenTransition { 51 | fn as_ref(&self) -> &Transition { 52 | &self.inner 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/engine/d2/script/action.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::Entity; 2 | 3 | /// Represents a unit of execution that is called over time. 4 | pub trait Action { 5 | /// Called when the acting entity has been updated. 6 | /// * 7 | /// @param dt The time elapsed since the last frame, in seconds. 8 | /// @param actor The entity of the Script that this action was added to. 9 | /// @returns The amount of time in seconds spent this frame to finish the action, which may be 10 | /// less than dt. Or -1 if the action is not yet finished. 11 | fn update(&self, dt: f32, actor: &mut Entity) -> f32; 12 | } 13 | -------------------------------------------------------------------------------- /src/engine/d2/script/animate_by.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::engine::d2::{ 4 | animation::{AnimatedFloat, Ease, EaseFunction, Tween}, 5 | Entity, 6 | }; 7 | 8 | use super::Action; 9 | 10 | /// An action that tweens an AnimatedFloat by a certain delta. 11 | pub struct AnimateBy { 12 | tween: Rc, 13 | 14 | value: AnimatedFloat, 15 | by: f32, 16 | seconds: f32, 17 | } 18 | 19 | impl AnimateBy { 20 | pub fn new(value: AnimatedFloat, by: f32, seconds: f32, easing: Option) -> Self { 21 | let easing = easing.unwrap_or(Rc::new(Ease::linear)); 22 | let tween = Rc::new(Tween::new( 23 | value.get(), 24 | value.get() + by, 25 | seconds, 26 | Some(easing), 27 | )); 28 | value.set_behavior(Some(tween.clone())); 29 | 30 | Self { 31 | value, 32 | by, 33 | seconds, 34 | tween, 35 | } 36 | } 37 | } 38 | 39 | impl Action for AnimateBy { 40 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 41 | self.value.update(dt); // Fake an update to account for this frame 42 | let overtime = self.tween.elapsed() - self.seconds; 43 | if overtime > 0.0 { 44 | 0_f32.max(dt - overtime) 45 | } else { 46 | 0.0 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/engine/d2/script/animate_from.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::engine::d2::{ 4 | animation::{AnimatedFloat, Ease, EaseFunction, Tween}, 5 | Entity, 6 | }; 7 | 8 | use super::Action; 9 | 10 | /// An action that tweens an AnimatedFloat from a certain value to its current value. 11 | pub struct AnimateFrom { 12 | tween: Rc, 13 | 14 | value: AnimatedFloat, 15 | from: f32, 16 | to: f32, 17 | seconds: f32, 18 | } 19 | 20 | impl AnimateFrom { 21 | pub fn new( 22 | value: AnimatedFloat, 23 | from: f32, 24 | seconds: f32, 25 | easing: Option, 26 | ) -> Self { 27 | let easing = easing.unwrap_or(Rc::new(Ease::linear)); 28 | let to = value.get(); 29 | let tween = Rc::new(Tween::new(from, to, seconds, Some(easing))); 30 | // Move to initial value 31 | value.set(from); 32 | value.set_behavior(Some(tween.clone())); 33 | 34 | Self { 35 | tween, 36 | value, 37 | from, 38 | to, 39 | seconds, 40 | } 41 | } 42 | } 43 | 44 | impl Action for AnimateFrom { 45 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 46 | self.value.update(dt); // Fake an update to account for this frame 47 | let overtime = self.tween.elapsed() - self.seconds; 48 | if overtime > 0.0 { 49 | 0_f32.max(dt - overtime) 50 | } else { 51 | 0.0 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/engine/d2/script/animate_to.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::engine::d2::{ 4 | animation::{AnimatedFloat, Ease, EaseFunction, Tween}, 5 | Entity, 6 | }; 7 | 8 | use super::Action; 9 | 10 | /// An action that tweens an AnimatedFloat to a certain value. 11 | pub struct AnimateTo { 12 | tween: Rc, 13 | 14 | value: AnimatedFloat, 15 | to: f32, 16 | seconds: f32, 17 | } 18 | 19 | impl AnimateTo { 20 | pub fn new(value: AnimatedFloat, to: f32, seconds: f32, easing: Option) -> Self { 21 | let easing = easing.unwrap_or(Rc::new(Ease::linear)); 22 | let tween = Rc::new(Tween::new(value.get(), to, seconds, Some(easing))); 23 | value.set_behavior(Some(tween.clone())); 24 | 25 | Self { 26 | tween, 27 | value, 28 | to, 29 | seconds, 30 | } 31 | } 32 | } 33 | 34 | impl Action for AnimateTo { 35 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 36 | self.value.update(dt); // Fake an update to account for this frame 37 | let overtime = self.tween.elapsed() - self.seconds; 38 | if overtime > 0.0 { 39 | 0_f32.max(dt - overtime) 40 | } else { 41 | 0.0 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/engine/d2/script/call_function.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::Entity; 2 | 3 | use super::Action; 4 | 5 | /// An action that calls a given fn once and immediately completes. 6 | pub struct CallFunction { 7 | func: Box, 8 | } 9 | 10 | impl CallFunction { 11 | /// @param fn The fn to call when this action is run. 12 | pub fn new(func: Box) -> Self { 13 | Self { func } 14 | } 15 | } 16 | 17 | impl Action for CallFunction { 18 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 19 | (self.func)(); 20 | 0.0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/engine/d2/script/delay.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | 3 | use crate::engine::d2::Entity; 4 | 5 | use super::Action; 6 | 7 | struct DelayProps { 8 | duration: f32, 9 | elapsed: f32, 10 | } 11 | /// An action that simply waits for a certain amount of time to pass before finishing. 12 | pub struct Delay { 13 | props: RefCell, 14 | } 15 | 16 | impl Delay { 17 | pub fn new(seconds: f32) -> Self { 18 | Self { 19 | props: RefCell::new(DelayProps { 20 | duration: seconds, 21 | elapsed: 0.0, 22 | }), 23 | } 24 | } 25 | } 26 | 27 | impl Action for Delay { 28 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 29 | let mut props = self.props.borrow_mut(); 30 | props.elapsed += dt; 31 | if props.elapsed >= props.duration { 32 | let overtime = props.elapsed - props.duration; 33 | props.elapsed = 0.0; 34 | 35 | dt - overtime 36 | } else { 37 | -1.0 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/engine/d2/script/first_of.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | 3 | use crate::engine::d2::Entity; 4 | 5 | use super::Action; 6 | 7 | struct FirstOfProps { 8 | running_actions: Vec>, 9 | } 10 | /// An action that manages a list of other actions, running them together in parallel until the 11 | /// first of them finishes. 12 | pub struct FirstOf { 13 | props: RefCell, 14 | } 15 | 16 | impl FirstOf { 17 | pub fn new(actions: Option>>) -> Self { 18 | Self { 19 | props: RefCell::new(FirstOfProps { 20 | running_actions: actions.unwrap_or_default(), 21 | }), 22 | } 23 | } 24 | 25 | pub fn add(&self, action: Box) { 26 | let mut props = self.props.borrow_mut(); 27 | props.running_actions.push(action); 28 | } 29 | 30 | // pub fn remove(&self, action: Box) -> bool { 31 | // match self.running_actions.iter().position(|&item| item == action) { 32 | // Some(idx) => { 33 | // self.running_actions.remove(idx); 34 | // true 35 | // }, 36 | // None => false 37 | // } 38 | // } 39 | 40 | pub fn remove_all(&self) { 41 | let mut props = self.props.borrow_mut(); 42 | props.running_actions.clear(); 43 | } 44 | } 45 | 46 | impl Action for FirstOf { 47 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 48 | let mut props = self.props.borrow_mut(); 49 | for action in props.running_actions.iter_mut() { 50 | let spent = action.update(dt, actor); 51 | if spent >= 0.0 { 52 | return spent; 53 | } 54 | } 55 | 56 | -1.0 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/engine/d2/script/mod.rs: -------------------------------------------------------------------------------- 1 | //! Scription support 2 | 3 | mod action; 4 | pub use self::action::*; 5 | 6 | mod animate_by; 7 | pub use self::animate_by::*; 8 | 9 | mod animate_from; 10 | pub use self::animate_from::*; 11 | 12 | mod animate_to; 13 | pub use self::animate_to::*; 14 | 15 | mod call_function; 16 | pub use self::call_function::*; 17 | 18 | mod delay; 19 | pub use self::delay::*; 20 | 21 | mod first_of; 22 | pub use self::first_of::*; 23 | 24 | mod move_by; 25 | pub use self::move_by::*; 26 | 27 | mod move_to; 28 | pub use self::move_to::*; 29 | 30 | mod parallel; 31 | pub use self::parallel::*; 32 | 33 | mod play_movie; 34 | pub use self::play_movie::*; 35 | 36 | mod play_sound; 37 | pub use self::play_sound::*; 38 | 39 | mod repeat; 40 | pub use self::repeat::*; 41 | 42 | mod script; 43 | pub use self::script::*; 44 | 45 | mod sequence; 46 | pub use self::sequence::*; 47 | 48 | mod shake; 49 | pub use self::shake::*; 50 | -------------------------------------------------------------------------------- /src/engine/d2/script/move_to.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::engine::d2::{ 4 | animation::{Ease, EaseFunction, Tween}, 5 | display::Sprite, 6 | Entity, EntityManager, 7 | }; 8 | 9 | use super::Action; 10 | 11 | /// An action that translates the owner's sprite to a certain position. 12 | pub struct MoveTo { 13 | tween_x: Rc, 14 | tween_y: Rc, 15 | 16 | x: f32, 17 | y: f32, 18 | seconds: f32, 19 | } 20 | 21 | impl MoveTo { 22 | pub fn new( 23 | actor: Entity, 24 | x: f32, 25 | y: f32, 26 | seconds: f32, 27 | easing_x: Option, 28 | easing_y: Option, 29 | ) -> Self { 30 | let sprite = EntityManager::::get(&actor).unwrap_or_default(); 31 | 32 | let easing_x = easing_x.unwrap_or(Rc::new(Ease::linear)); 33 | // let easing_y = easing_y.unwrap_or(easing_x); // TODO: DV this should be correct 34 | let easing_y = easing_y.unwrap_or(Rc::new(Ease::linear)); 35 | 36 | let tween_x = Rc::new(Tween::new(sprite.x.get(), x, seconds, Some(easing_x))); 37 | sprite.x.set_behavior(Some(tween_x.clone())); 38 | 39 | let tween_y = Rc::new(Tween::new(sprite.y.get(), y, seconds, Some(easing_y))); 40 | sprite.y.set_behavior(Some(tween_y.clone())); 41 | 42 | Self { 43 | x, 44 | y, 45 | seconds, 46 | // easing_x, 47 | // easing_y, 48 | tween_x, 49 | tween_y, 50 | } 51 | } 52 | } 53 | 54 | impl Action for MoveTo { 55 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 56 | if let Some(ref mut sprite) = EntityManager::::get(actor) { 57 | sprite.x.update(dt); // Fake an update to account for this frame 58 | sprite.y.update(dt); // Fake an update to account for this frame 59 | let overtime = self.tween_x.elapsed().max(self.tween_y.elapsed()) - self.seconds; 60 | if overtime > 0.0 { 61 | 0_f32.max(dt - overtime) 62 | } else { 63 | 0.0 64 | } 65 | } else { 66 | -1.0 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/engine/d2/script/play_movie.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | 3 | use crate::engine::d2::{ 4 | swf::{MoviePlayer, MovieSprite}, 5 | Entity, EntityManager, 6 | }; 7 | 8 | use super::Action; 9 | 10 | struct PlayMovieProps { 11 | name: String, 12 | movie: Option, 13 | } 14 | 15 | /// An action that plays a movie once using the actor's MoviePlayer, completing when the movie 16 | /// finishes. 17 | pub struct PlayMovie { 18 | props: RefCell, 19 | } 20 | 21 | impl PlayMovie { 22 | /// @param The name of the movie to play. 23 | pub fn new(name: String) -> Self { 24 | Self { 25 | props: RefCell::new(PlayMovieProps { name, movie: None }), 26 | } 27 | } 28 | } 29 | 30 | impl Action for PlayMovie { 31 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 32 | let mut props = self.props.borrow_mut(); 33 | if let Some(mut player) = EntityManager::::get(actor) { 34 | match props.movie { 35 | Some(ref movie) => match player.movie { 36 | Some(ref player_movie) => { 37 | // if movie != player_movie.get() { // DV watching movie progress 38 | // self.movie = None; 39 | // return 0.0; 40 | // } 41 | 42 | if movie != player_movie { 43 | // DV without watching movie progress 44 | props.movie = None; 45 | return 0.0; 46 | } 47 | } 48 | None => { 49 | props.movie = None; 50 | return 0.0; 51 | } 52 | }, 53 | None => { 54 | player.play(props.name.clone(), true); 55 | // self.movie = player.movie.map(|v| v.get()); // DV watching movie progress 56 | props.movie = player.movie; // DV without watching movie progress 57 | } 58 | } 59 | } 60 | 61 | -1.0 // Keep going 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/engine/d2/script/play_sound.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::RefCell, rc::Rc}; 2 | 3 | use crate::engine::d2::{ 4 | sound::{Playback, Sound}, 5 | Entity, 6 | }; 7 | 8 | use super::Action; 9 | 10 | struct PlaySoundProps { 11 | sound: Box, 12 | volume: f32, 13 | playback: Option>, 14 | } 15 | 16 | /// An action that plays a sound and waits for it to complete. 17 | /// 18 | // ``` 19 | // script.run(Sequence::new([ 20 | // // Play a sound 21 | // PlaySound::new(sound1), 22 | // 23 | // // Then wait 2 seconds 24 | // Delay::new(2), 25 | // 26 | // // Then play another sound 27 | // PlaySound::new(sound2), 28 | // ])); 29 | // ``` 30 | pub struct PlaySound { 31 | props: RefCell, 32 | } 33 | 34 | impl PlaySound { 35 | /// @param sound The sound to play. 36 | /// @param volume The volume to pass to `Sound.play`. 37 | // volume: Option = 1.0 38 | pub fn new(sound: Box, volume: Option) -> Self { 39 | Self { 40 | props: RefCell::new(PlaySoundProps { 41 | sound, 42 | volume: volume.unwrap_or(1.0), 43 | playback: None, 44 | }), 45 | } 46 | } 47 | } 48 | 49 | impl Action for PlaySound { 50 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 51 | let mut props = self.props.borrow_mut(); 52 | let volume = props.volume; 53 | if props.playback.is_none() { 54 | props.playback = Some(props.sound.play(volume)); 55 | } 56 | 57 | if let Some(ref playback) = props.playback { 58 | if *playback.complete().get() { 59 | props.playback = None; 60 | return 0.0; // Finished 61 | } 62 | } 63 | 64 | -1.0 // Keep waiting 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/engine/d2/script/repeat.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | 3 | use crate::engine::d2::Entity; 4 | 5 | use super::Action; 6 | 7 | struct RepeatProps { 8 | action: Box, 9 | count: i32, 10 | remaining: i32, 11 | } 12 | /// An action that repeats another action until it finishes a certain number of times. 13 | pub struct Repeat { 14 | props: RefCell, 15 | } 16 | 17 | impl Repeat { 18 | /// @param count The number of times to repeat the action, or -1 to repeat forever. 19 | // count: i32 = -1 20 | pub fn new(action: Box, count: i32) -> Self { 21 | Self { 22 | props: RefCell::new(RepeatProps { 23 | action, 24 | count, 25 | remaining: count, 26 | }), 27 | } 28 | } 29 | } 30 | 31 | impl Action for Repeat { 32 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 33 | let mut props = self.props.borrow_mut(); 34 | if props.count == 0 { 35 | // Handle the special case of a 0-count Repeat 36 | return 0.0; 37 | } 38 | 39 | let spent = props.action.update(dt, actor); 40 | props.remaining -= 1; 41 | if props.count > 0 && spent >= 0.0 && props.remaining == 0 { 42 | props.remaining = props.count; // Reset state in case this Action is reused 43 | return spent; 44 | } 45 | 46 | // Keep repeating 47 | -1.0 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/engine/d2/script/shake.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::RefCell, rc::Rc}; 2 | 3 | use crate::engine::d2::{animation::Jitter, display::Sprite, Entity, EntityManager}; 4 | 5 | use super::Action; 6 | 7 | struct ShakeProps { 8 | elapsed: f32, 9 | strength_x: f32, 10 | strength_y: f32, 11 | duration: f32, 12 | } 13 | /// Shakes an entity's sprite by jittering its X and Y for a set duration. 14 | pub struct Shake { 15 | props: RefCell, 16 | } 17 | 18 | impl Shake { 19 | pub fn new(actor: Entity, strength_x: f32, strength_y: f32, seconds: f32) -> Self { 20 | let sprite = EntityManager::::get(&actor).unwrap_or_default(); 21 | 22 | let jitter_x = Rc::new(Jitter::new(sprite.x.get(), strength_x)); 23 | let jitter_y = Rc::new(Jitter::new(sprite.y.get(), strength_y)); 24 | 25 | sprite.x.set_behavior(Some(jitter_x)); 26 | sprite.y.set_behavior(Some(jitter_y)); 27 | 28 | Self { 29 | props: RefCell::new(ShakeProps { 30 | strength_x, 31 | strength_y, 32 | duration: seconds, 33 | elapsed: 0.0, 34 | }), 35 | } 36 | } 37 | } 38 | 39 | impl Action for Shake { 40 | fn update(&self, dt: f32, actor: &mut Entity) -> f32 { 41 | if let Some(ref mut sprite) = EntityManager::::get(actor) { 42 | let mut props = self.props.borrow_mut(); 43 | props.elapsed += dt; 44 | if props.elapsed >= props.duration { 45 | let overtime = props.elapsed - props.duration; 46 | 47 | sprite.x.update(dt); // Fake an update to account for this frame 48 | sprite.y.update(dt); // Fake an update to account for this frame 49 | 50 | props.elapsed = 0.0; 51 | return dt - overtime; 52 | } 53 | } 54 | 55 | -1.0 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/engine/d2/sound/mod.rs: -------------------------------------------------------------------------------- 1 | //! Sound system 2 | 3 | mod mixer; 4 | pub use self::mixer::*; 5 | 6 | mod playback; 7 | pub use self::playback::*; 8 | 9 | mod sound; 10 | pub use self::sound::*; 11 | -------------------------------------------------------------------------------- /src/engine/d2/sound/playback.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::engine::d2::{ 4 | animation::AnimatedFloat, 5 | util::{Disposable, Value}, 6 | }; 7 | 8 | use super::Sound; 9 | 10 | /// Represents a currently playing sound. 11 | pub trait Playback: Disposable { 12 | /// The volume of the sound being played, between 0 and 1 (inclusive). 13 | fn volume(&self) -> AnimatedFloat; 14 | 15 | fn set_volume(&self, val: AnimatedFloat); 16 | 17 | /// Whether the playback is currently paused. Playbacks are automatically paused while the app is 18 | /// hidden, such as when minimized or placed in a background browser tab. 19 | fn paused(&self) -> bool; 20 | 21 | fn set_paused(&self, val: bool); 22 | 23 | /// Whether the playback has finished playing or has been disposed. Looping playbacks will never 24 | /// complete naturally, and are complete only after being disposed. 25 | /// * 26 | /// In environments that don't support audio, this will be true. 27 | /// * 28 | /// Do not set this value! To pause the playback, set `paused`. To stop it completely, call 29 | /// `dispose()`. 30 | fn complete(&self) -> Value; 31 | 32 | fn set_complete(&self, val: Value); 33 | 34 | /// The current playback position in seconds. 35 | fn position(&self) -> f32; 36 | 37 | fn set_position(&self, pos: f32); 38 | 39 | /// The sound being played. 40 | fn sound(&self) -> Rc; 41 | } 42 | -------------------------------------------------------------------------------- /src/engine/d2/sound/sound.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::engine::d2::asset::Asset; 4 | 5 | use super::Playback; 6 | 7 | /// A loaded sound file. 8 | pub trait Sound: Asset { 9 | /// The length of the sound in seconds. 10 | fn duration(&self) -> f32; 11 | 12 | /// Plays the sound once, suitable for one-shot sound effects. 13 | /// * 14 | /// @param volume The playback volume between 0 (silence) and 1 (full volume). Defaults to 1. 15 | /// @returns A playback that can be used to control the sound. 16 | // volume: f32 = 1.0 17 | fn play(&self, volume: f32) -> Rc; 18 | 19 | /// Loops the sound forever, suitable for background music. 20 | /// * 21 | /// @param volume The playback volume between 0 (silence) and 1 (full volume). Defaults to 1. 22 | /// @returns A playback that can be used to control the sound. 23 | // volume: f32 = 1.0 24 | fn play_with_loop(&self, volume: f32) -> Rc; 25 | } 26 | -------------------------------------------------------------------------------- /src/engine/d2/speed_adjuster.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::animation::AnimatedFloat; 2 | 3 | use super::Component; 4 | 5 | /// Adjusts the update speed of an entity (and its components and children). Can be used for slow 6 | /// motion and fast forward effects. 7 | 8 | #[derive(Default, Clone, Debug)] 9 | pub struct SpeedAdjuster { 10 | pub inner: Component, 11 | /// The scale that time should pass for the owning entity and its children. Values lower than 12 | /// 1.0 will play slower than realtime, and values higher than 1.0 will play faster. When the 13 | /// scale is 0, the entity is basically paused. 14 | pub scale: AnimatedFloat, 15 | pub real_dt: f32, 16 | } 17 | 18 | impl SpeedAdjuster { 19 | // scale: f32 = 1 20 | pub fn new(scale: f32) -> Self { 21 | Self { 22 | inner: Default::default(), 23 | scale: AnimatedFloat::new(scale, None), 24 | real_dt: 0.0, 25 | } 26 | } 27 | 28 | // Note that this may be called by MainLoop before on_started! 29 | // override 30 | pub fn on_update(&mut self, dt: f32) { 31 | let mut dt = dt; 32 | // Ensure this component is immune to its own time scaling 33 | if self.real_dt > 0.0 { 34 | dt = self.real_dt; 35 | self.real_dt = 0.0; 36 | } 37 | 38 | self.scale.update(dt); 39 | } 40 | } 41 | 42 | impl AsRef for SpeedAdjuster { 43 | fn as_ref(&self) -> &Component { 44 | &self.inner 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/external.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::platform::Dynamic; 2 | 3 | /// Functions for interacting with external code. When running in a web browser, this means 4 | /// Javascript running on the page. 5 | pub trait ExternalSystem { 6 | /// Whether the environment supports interaction with external code. 7 | fn is_supported(&self) -> bool; 8 | 9 | /// Call an external fn with the given parameters, and returns the result. Errors thrown by 10 | /// the called fn will propogate. 11 | fn call(&self, name: String, params: Option>) -> Option; 12 | 13 | /// Bind a fn to be called by external code. 14 | /// @param name The name to bind to. The namespace may be shared with third party code, so it's 15 | /// good practice to prefix names. In Javascript, the fn will be hooked onto the window 16 | /// object. 17 | /// @param fn The function, or None to unbind. 18 | fn bind(&self, name: String, function: Dynamic); 19 | } 20 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/keyboard.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{ 2 | input::{Key, KeyboardEvent}, 3 | util::{Signal0, Signal1}, 4 | }; 5 | 6 | /// Functions related to the environment's physical keyboard. 7 | pub trait KeyboardSystem { 8 | /// Whether the environment has a physical keyboard. Phones and tablets will generally return 9 | /// false here. 10 | fn is_supported(&self) -> bool; 11 | 12 | /// Emitted when a key is pressed down. 13 | fn down_signal(&self) -> &Signal1; 14 | 15 | /// Emitted when a key is released. 16 | fn up_signal(&self) -> &Signal1; 17 | 18 | /// Emitted when a hardware back button is pressed. If no listeners are connected to this signal 19 | /// when the back button is pressed, the platform's default action will be taken (which is 20 | /// usually to close the app). Only supported on Android. 21 | fn back_button(&self) -> &Signal0; 22 | 23 | /// @returns True if the given key is currently being held down. 24 | fn is_down(&self, key: Key) -> bool; 25 | } 26 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/mod.rs: -------------------------------------------------------------------------------- 1 | //! Subsystems 2 | 3 | mod external; 4 | pub use self::external::*; 5 | 6 | mod keyboard; 7 | pub use self::keyboard::*; 8 | 9 | mod motion; 10 | pub use self::motion::*; 11 | 12 | mod mouse; 13 | pub use self::mouse::*; 14 | 15 | mod pointer; 16 | pub use self::pointer::*; 17 | 18 | mod renderer; 19 | pub use self::renderer::*; 20 | 21 | mod stage; 22 | pub use self::stage::*; 23 | 24 | mod storage; 25 | pub use self::storage::*; 26 | 27 | mod touch; 28 | pub use self::touch::*; 29 | 30 | mod web; 31 | pub use self::web::*; 32 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/motion.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{ 2 | input::{Acceleration, Attitude}, 3 | util::Signal1, 4 | }; 5 | 6 | /// Functions related to the device's motion sensors. 7 | pub trait MotionSystem { 8 | /// Whether device acceleration events are supported. If true, the acceleration and/or 9 | /// accelerationIncludingGravity signals will be emitted. 10 | fn is_acceleration_supported(&self) -> bool; 11 | 12 | /// Periodically emits the device's current linear acceleration, excluding the pull of gravity. 13 | /// This will only be emitted if the device has a gyroscope. 14 | fn acceleration(&self) -> &Signal1; 15 | 16 | /// Periodically emits the devices's current linear acceleration, including the pull of gravity. 17 | fn acceleration_including_gravity(&self) -> &Signal1; 18 | 19 | /// Whether device orientation (attitude) events are supported. 20 | fn is_attitude_supported(&self) -> bool; 21 | 22 | /// Periodically emits the device's current attitude. 23 | fn attitude(&self) -> &Signal1; 24 | } 25 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/mouse.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{ 2 | input::{MouseButton, MouseCursor, MouseEvent}, 3 | util::Signal1, 4 | }; 5 | 6 | /// Functions related to the environment's mouse. 7 | pub trait MouseSystem { 8 | /// True if the environment has a mouse. 9 | fn is_supported(&self) -> bool; 10 | 11 | /// Emitted when a mouse button is pressed down. 12 | fn down_signal(&self) -> &Signal1; 13 | 14 | /// Emitted when the mouse cursor is moved while over the stage. 15 | fn move_signal(&self) -> &Signal1; 16 | 17 | /// Emitted when a mouse button is released. 18 | fn up_signal(&self) -> &Signal1; 19 | 20 | /// A velocity emitted when the mouse wheel or trackpad is scrolled. A positive value is an 21 | /// upward scroll, negative is a downward scroll. Typically, each scroll wheel "click" equates to 22 | /// 1 velocity. 23 | fn scroll_signal(&self) -> &Signal1; 24 | 25 | /// The last recorded X coordinate of the mouse. 26 | fn x(&self) -> f32; 27 | 28 | /// The last recorded Y coordinate of the mouse. 29 | fn y(&self) -> f32; 30 | 31 | /// The style of the mouse cursor. 32 | fn cursor(&self) -> MouseCursor; 33 | 34 | /// @returns True if the given button is currently being held down. 35 | fn is_down(&self, button: MouseButton) -> bool; 36 | } 37 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/pointer.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{input::PointerEvent, util::Signal1}; 2 | 3 | /// Functions related to the environment's pointing device. On desktop computers, this is a mouse. On 4 | /// touch screens, it's a finger. 5 | pub trait PointerSystem { 6 | /// True if the environment has a pointing device. 7 | fn is_supported(&self) -> bool; 8 | 9 | /// Emitted when the pointing device is pressed down (when the mouse button is held or a finger 10 | /// is pressed to the screen). 11 | fn down(&self) -> &Signal1; 12 | 13 | /// Emitted when the pointing device moves while over the stage. 14 | fn move_signal(&self) -> &Signal1; 15 | 16 | /// Emitted when the pointing device is released (when the mouse button is released or the finger 17 | /// is lifted from the screen). 18 | fn up_signal(&self) -> &Signal1; 19 | 20 | /// The last recorded X coordinate of the pointer. 21 | fn x(&self) -> f32; 22 | 23 | /// The last recorded Y coordinate of the pointer. 24 | fn y(&self) -> f32; 25 | 26 | /// True if the pointer is currently pressed down. 27 | fn is_down(&self) -> bool; 28 | } 29 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/stage.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{ 2 | display::Orientation, 3 | util::{Signal0, Value}, 4 | }; 5 | 6 | /// Functions related to the environment's display viewport. 7 | pub trait StageSystem { 8 | /// The width of the stage viewport, in pixels. 9 | fn width(&self) -> i32; 10 | 11 | /// The height of the stage viewport, in pixels. 12 | fn height(&self) -> i32; 13 | 14 | /// The current screen orientation, or a wrapped None value if the environment doesn't support 15 | /// multiple orientations. 16 | fn orientation(&self) -> Value; 17 | 18 | /// True if the stage is currently fullscreen. 19 | fn fullscreen(&self) -> Value; 20 | 21 | /// Whether the stage may change its fullscreen state. False if the stage is fullscreen and can't 22 | /// go into windowed mode, or vise versa. 23 | fn is_fullscreen_supported(&self) -> bool; 24 | 25 | /// Emitted after the stage size changes, such as when the window is resized or the device is 26 | /// rotated. 27 | fn resize_signal(&self) -> Signal0; 28 | 29 | /// Request to lock the orientation, so that rotating the device will not adjust the screen. Has 30 | /// no effect if the environment doesn't support orientation locking. 31 | /// @param orient The orientation to lock to. 32 | fn lock_orientation(&self, orient: Orientation); 33 | 34 | /// Request to unlock the orientation, so that rotating the device will adjust the screen. Has no 35 | /// effect if the environment doesn't support orientation locking. 36 | fn unlock_orientation(&self); 37 | 38 | /// Request that the stage be resized to a certain size. 39 | fn request_resize(&self, width: i32, height: i32); 40 | 41 | /// Request that fullscreen be enabled or disabled. No effect if changing fullscreen is not 42 | /// supported. 43 | // enable :bool = true 44 | fn request_fullscreen(&self, enable: bool); 45 | } 46 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/storage.rs: -------------------------------------------------------------------------------- 1 | pub trait StorageItem {} 2 | 3 | /// A simple key/value store that persists between sessions. 4 | pub trait StorageSystem { 5 | /// True if the environment supports persisted storage. Otherwise, the storage is backed by a 6 | /// Map and not actually persisted between sessions. 7 | fn is_supported(&self) -> bool; 8 | 9 | /// Add a key to the storage, replacing any existing value. 10 | /// @param value An object that can be serialized with Serializer. 11 | /// @returns True if the value was successfully serialized and persisted. 12 | fn set(&self, key: String, value: A) -> bool 13 | where 14 | Self: Sized; 15 | 16 | /// Retrieve a value from storage for a given key. 17 | fn get(&self, key: String) -> Option<&A> 18 | where 19 | Self: Sized; 20 | 21 | /// Deletes a key/value pair from storage. 22 | fn remove(&mut self, key: String); 23 | 24 | /// Clears the entire storage contents. 25 | fn clear(&mut self); 26 | } 27 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/touch.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{input::TouchPoint, util::Signal1}; 2 | 3 | /// Functions related to the environment's touch screen. 4 | pub trait TouchSystem { 5 | /// True if the environment has a touch screen. 6 | fn is_supported(&self) -> bool; 7 | 8 | /// The maximum number of touch points that can be detected at once. 9 | fn max_points(&self) -> i32; 10 | 11 | /// Emits a new TouchPoint when a finger presses down on the screen. 12 | fn down_signal(&self) -> &Signal1; 13 | 14 | /// Emits the modified TouchPoint when a finger changes position. 15 | fn move_signal(&self) -> &Signal1; 16 | 17 | /// Emits the removed TouchPoint when a finger is raised from the screen. 18 | fn up_signal(&self) -> &Signal1; 19 | 20 | /// The touch points currently pressed to the screen. 21 | fn points(&self) -> Vec; 22 | } 23 | -------------------------------------------------------------------------------- /src/engine/d2/subsystem/web.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::web::WebView; 2 | 3 | /// Functions related to the environment's web browser. 4 | pub trait WebSystem { 5 | /// True if the environment supports WebViews. Note that this will always be false 6 | /// 7 | fn is_supported(&self) -> bool; 8 | 9 | /// Creates a blank WebView with the given viewport bounds, in pixels. Fails with an assertion if 10 | /// this environment doesn't support WebViews. 11 | fn create_view(&self, x: f32, y: f32, width: f32, height: f32) -> Box; 12 | 13 | /// Open a new browser window or tab to the given URL. This operation is always supported. URI 14 | /// schemes such as mailto: are also available. On mobile, sms: and tel: are supported. On 15 | /// Android, market: is supported. 16 | fn open_browser(&self, url: String); 17 | } 18 | -------------------------------------------------------------------------------- /src/engine/d2/swf/bitmap_symbol.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt, rc::Rc}; 2 | 3 | use crate::engine::d2::{ 4 | display::{ImageSprite, Sprite, SubTexture, Texture}, 5 | swf::TextureFormat, 6 | }; 7 | 8 | use super::Symbol; 9 | 10 | /// Defines a Flump atlased texture. 11 | pub struct BitmapSymbol { 12 | pub texture: Rc, 13 | pub anchor_x: f32, 14 | pub anchor_y: f32, 15 | 16 | name: Option, 17 | } 18 | 19 | impl BitmapSymbol { 20 | pub fn new(json: TextureFormat, atlas: impl Texture) -> Self { 21 | let rect = json.rect; 22 | 23 | let mut instance = Self { 24 | name: json.symbol, 25 | texture: atlas.sub_texture(rect[0], rect[1], rect[2], rect[3]), 26 | anchor_x: 0.0, 27 | anchor_y: 0.0, 28 | }; 29 | 30 | if let Some(origin) = json.origin { 31 | instance.anchor_x = origin[0]; 32 | instance.anchor_y = origin[1]; 33 | } 34 | 35 | instance 36 | } 37 | } 38 | 39 | impl Symbol for BitmapSymbol { 40 | #[inline] 41 | fn name(&self) -> Option { 42 | self.name.clone() 43 | } 44 | 45 | fn create_sprite(&self) -> ImageSprite { 46 | // let sprite = ImageSprite::new(Some(self.texture)); 47 | // sprite.inner.set_anchor(self.anchor_x, self.anchor_y); 48 | 49 | // sprite 50 | unimplemented!() 51 | } 52 | } 53 | 54 | impl fmt::Debug for BitmapSymbol { 55 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 56 | f.debug_struct("BitmapSymbol") 57 | // .field("x", &self.x) 58 | // .field("y", &self.y) 59 | .finish() 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/engine/d2/swf/mod.rs: -------------------------------------------------------------------------------- 1 | //! Swf support 2 | 3 | mod bitmap_symbol; 4 | pub use self::bitmap_symbol::*; 5 | 6 | mod flipbook; 7 | pub use self::flipbook::*; 8 | 9 | mod format; 10 | pub use self::format::*; 11 | 12 | mod library; 13 | pub use self::library::*; 14 | 15 | mod movie_player; 16 | pub use self::movie_player::*; 17 | 18 | mod movie_sprite; 19 | pub use self::movie_sprite::*; 20 | 21 | mod movie_symbol; 22 | pub use self::movie_symbol::*; 23 | 24 | mod symbol; 25 | pub use self::symbol::*; 26 | -------------------------------------------------------------------------------- /src/engine/d2/swf/symbol.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use crate::engine::d2::display::Sprite; 4 | 5 | /// Defines an exported SWF symbol. 6 | 7 | pub trait Symbol: fmt::Debug 8 | where 9 | T: AsRef, 10 | { 11 | /// The name of this symbol. 12 | fn name(&self) -> Option; 13 | 14 | /// Instantiate a sprite that displays this symbol. 15 | fn create_sprite(&self) -> T; 16 | } 17 | -------------------------------------------------------------------------------- /src/engine/d2/util/disposable.rs: -------------------------------------------------------------------------------- 1 | // 2 | // Any object that can be disposed to free its resources and clean things up properly. 3 | // 4 | pub trait Disposable { 5 | fn dispose(&self); 6 | } 7 | -------------------------------------------------------------------------------- /src/engine/d2/util/iterables.rs: -------------------------------------------------------------------------------- 1 | /// Utility mixins for Iterables. Designed to be imported with 'using'. 2 | pub struct Iterable; 3 | 4 | pub struct Iterables {} 5 | 6 | impl Iterables { 7 | // /// Searches for the first element using a predicate and returns it. 8 | // // static 9 | // pub fn find(&self, it: Iterable, pred: impl Fn(A) -> bool) -> A { 10 | // for a in it { 11 | // if pred(a) { 12 | // return a; 13 | // } 14 | // } 15 | // return None; 16 | // } 17 | } 18 | -------------------------------------------------------------------------------- /src/engine/d2/util/maps.rs: -------------------------------------------------------------------------------- 1 | /// Utility mixins for Maps. Designed to be imported with 'using'. 2 | pub struct Maps {} 3 | 4 | impl Maps { 5 | // /// Fetch a string from a hash, converting it from another type if necessary. 6 | // // static 7 | // pub fn getString(&self, hash: HashMap, key: String) -> String { 8 | // hash.get(key) 9 | // } 10 | 11 | // /// Fetch a float from a hash, converting it from another type if necessary. 12 | // // static 13 | // pub fn getFloat(&self, hash: HashMap, key: String) -> f32 { 14 | // hash.get(key) 15 | // } 16 | 17 | // /// Fetch a integer from a hash, converting it from another type if necessary. 18 | // // static 19 | // pub fn getInt(&self, hash: HashMap, key: String) -> i32 { 20 | // hash.get(key) 21 | // } 22 | 23 | // /// Fetch a boolean from a hash, converting it from another type if necessary. 24 | // // static 25 | // pub fn getbool(&self, hash: HashMap, key: String) -> bool { 26 | // hash.get(key) 27 | // } 28 | } 29 | -------------------------------------------------------------------------------- /src/engine/d2/util/message_bundle.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::util::StringExtensions; 2 | 3 | use super::{Config, Signal1}; 4 | 5 | /// Stupid-simple text localization. 6 | pub struct MessageBundle { 7 | pub config: Config, 8 | 9 | /// Emitted when a translation is requested that this bundle doesn't provide. 10 | pub missing_translation: Signal1, 11 | } 12 | 13 | impl MessageBundle { 14 | pub fn new(config: Config) -> Self { 15 | Self { 16 | config, 17 | missing_translation: Signal1::new(None), 18 | } 19 | } 20 | 21 | // static 22 | #[inline] 23 | pub fn parse(&self, text: String) -> MessageBundle { 24 | MessageBundle::new(Config::parse(text)) 25 | } 26 | 27 | /// Fetch a translation from the config, and substitute in params with Strings.substitute. If 28 | /// the path doesn't exist in the config, missingTranslation is emitted and the original path is 29 | /// returned. 30 | pub fn get(&self, path: &String, params: Option>) -> String { 31 | match self.config.get(path) { 32 | Some(value) => { 33 | if let Some(params) = params { 34 | value.substitute(params) 35 | } else { 36 | value.clone() 37 | } 38 | } 39 | None => { 40 | // log::warn!("Requested a missing translation from bundle [path: {}]", path); 41 | self.missing_translation.emit(path.clone()); 42 | // Return the best we can 43 | path.clone() 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/engine/d2/util/mod.rs: -------------------------------------------------------------------------------- 1 | //! General engine utilites 2 | 3 | mod bit_sets; 4 | pub use self::bit_sets::*; 5 | 6 | mod config; 7 | pub use self::config::*; 8 | 9 | mod disposable; 10 | pub use self::disposable::*; 11 | 12 | mod iterables; 13 | pub use self::iterables::*; 14 | 15 | mod macros; 16 | pub use self::macros::*; 17 | 18 | mod maps; 19 | pub use self::maps::*; 20 | 21 | mod message_bundle; 22 | pub use self::message_bundle::*; 23 | 24 | mod multi_promise; 25 | pub use self::multi_promise::*; 26 | 27 | mod pool; 28 | pub use self::pool::*; 29 | 30 | mod promise; 31 | pub use self::promise::*; 32 | 33 | mod random; 34 | pub use self::random::*; 35 | 36 | mod signal_base; 37 | pub use self::signal_base::*; 38 | 39 | mod signal_connection; 40 | pub use self::signal_connection::*; 41 | 42 | mod signal0; 43 | pub use self::signal0::*; 44 | 45 | mod signal1; 46 | pub use self::signal1::*; 47 | 48 | mod signal2; 49 | pub use self::signal2::*; 50 | 51 | mod strings; 52 | pub use self::strings::*; 53 | 54 | mod value; 55 | pub use self::value::*; 56 | 57 | mod xmls; 58 | pub use self::xmls::*; 59 | -------------------------------------------------------------------------------- /src/engine/d2/util/random.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::math::Math; 2 | 3 | /// A seedable, portable random number generator. Fast and random enough for games. 4 | /// [http://en.wikipedia.org/wiki/Linear_congruential_generator][1] 5 | /// 6 | /// [1]: http://en.wikipedia.org/wiki/Linear_congruential_generator 7 | pub struct Random { 8 | state: i32, 9 | } 10 | 11 | impl Random { 12 | pub fn new(seed: Option) -> Self { 13 | Self { 14 | state: if let Some(seed) = seed { 15 | seed 16 | } else { 17 | rand::random::() 18 | }, 19 | } 20 | } 21 | 22 | /// Returns an integer between >= 0 and < INT_MAX 23 | pub fn next_int(&mut self) -> i32 { 24 | // These constants borrowed from glibc 25 | // Force float multiplication here to avoid overflow 26 | self.state = (1103515245.0 * self.state as f32 + 12345.0) as i32 % Math::INT_MAX; 27 | 28 | self.state 29 | } 30 | 31 | /// Returns a number >= 0 and < 1 32 | pub fn next_float(&self) -> f32 { 33 | rand::random::() 34 | } 35 | 36 | pub fn reset(&mut self, value: i32) { 37 | self.state = value; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/engine/d2/util/signal0.rs: -------------------------------------------------------------------------------- 1 | use super::{Disposable, SignalBase, SignalConnection}; 2 | 3 | /// An alias for Signal0 listeners. 4 | pub type Listener0 = Box; 5 | 6 | /// A zero-argument signal. See Signal1 and Signal2 for different arities. 7 | 8 | #[derive(Default, Clone, Debug)] 9 | pub struct Signal0 { 10 | pub inner: SignalBase, 11 | } 12 | 13 | impl Signal0 { 14 | /// @param listener An optional listener to immediately connect to the signal. 15 | pub fn new(listener: Option) -> Self { 16 | // Self { 17 | // inner: SignalBase::new(listener), 18 | // } 19 | todo!("should deal with it"); 20 | } 21 | 22 | /// Connects a listener to this signal. 23 | /// @param prioritize True if this listener should fire before others. 24 | /// @returns A SignalConnection, that can be disposed to remove the listener. 25 | // prioritize :bool = false 26 | pub fn connect(&self, listener: Listener0, prioritize: bool) -> SignalConnection { 27 | // self.inner.connect_impl(listener, prioritize) 28 | todo!("should deal with it"); 29 | } 30 | 31 | /// Emit the signal, notifying each connected listener. 32 | pub fn emit(&self) { 33 | if self.inner.dispatching() { 34 | todo!("should deal with it"); 35 | // self.inner.defer(Box::new(|| { 36 | // self.emitImpl(); 37 | // })); 38 | } else { 39 | self.emit_impl(); 40 | } 41 | } 42 | 43 | fn emit_impl(&self) { 44 | let head = self.inner.will_emit(); 45 | let p = head; 46 | todo!("should deal with it"); 47 | // while let Some(ref val) = p { 48 | // if let Some(listener) = val.listener { 49 | // (listener)(); 50 | // } 51 | // if !val.stayInList { 52 | // val.dispose(); 53 | // } 54 | // p = val.next; 55 | // } 56 | // self.inner.didEmit(head.unwrap()); 57 | } 58 | } 59 | 60 | impl AsRef for Signal0 { 61 | fn as_ref(&self) -> &SignalBase { 62 | &self.inner 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/engine/d2/util/signal_connection.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::platform::Dynamic; 2 | 3 | use super::{Disposable, SignalBase}; 4 | 5 | /// Represents a connected signal listener. 6 | #[derive(Default, Clone, Debug)] 7 | pub struct SignalConnection { 8 | /// True if the listener will remain connected after being used. 9 | pub stay_in_list: bool, 10 | pub next: Box>, 11 | 12 | pub listener: Option, 13 | pub signal: Option, 14 | } 15 | 16 | impl SignalConnection { 17 | pub fn new(signal: Option, listener: Option) -> Self { 18 | // Self { 19 | // signal, 20 | // listener, 21 | // stayInList: true, 22 | // next: None, 23 | // } 24 | todo!("should deal with it"); 25 | } 26 | 27 | /// Tells the connection to dispose itself after being used once. 28 | /// @returns This instance, for chaining. 29 | pub fn once(&mut self) -> &Self { 30 | self.stay_in_list = false; 31 | 32 | self 33 | } 34 | } 35 | 36 | impl Disposable for SignalConnection { 37 | /// Disconnects the listener from the signal. 38 | fn dispose(&self) { 39 | if let Some(ref signal) = self.signal { 40 | signal.disconnect(self); 41 | // self.signal = None; // DV 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/engine/d2/util/xmls.rs: -------------------------------------------------------------------------------- 1 | pub struct Fast; 2 | 3 | /// Utility mixins for xml.Fast objects. Designed to be imported with 'using'. 4 | pub struct Xmls {} 5 | 6 | impl Xmls { 7 | // static 8 | pub fn string_attr( 9 | &self, 10 | reader: Fast, 11 | attr: String, 12 | default: Option, 13 | ) -> Option { 14 | todo!("should implement xml logic"); 15 | // if reader.has.resolve(attr) { 16 | // return Some(reader.att.resolve(attr)); 17 | // } 18 | 19 | // default 20 | } 21 | 22 | // static 23 | pub fn float_attr(&self, reader: Fast, attr: String, default: Option) -> Option { 24 | todo!("should implement xml logic"); 25 | // if reader.has.resolve(attr) { 26 | // let s: String = reader.att.resolve(attr); 27 | // let value = s.parse::().unwrap(); 28 | // if let Ok(value) = s.parse::() { 29 | // return Some(value); 30 | // } 31 | // } 32 | 33 | // default 34 | } 35 | 36 | // static 37 | pub fn int_attr(&self, reader: Fast, attr: String, default: Option) -> Option { 38 | todo!("should implement xml logic"); 39 | // if reader.has.resolve(attr) { 40 | // let s: String = reader.att.resolve(attr); 41 | // if let Ok(value) = s.parse::() { 42 | // return Some(value); 43 | // } 44 | // } 45 | 46 | // default 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/engine/d2/web/mod.rs: -------------------------------------------------------------------------------- 1 | //! Web support 2 | 3 | mod web_view; 4 | pub use self::web_view::*; 5 | -------------------------------------------------------------------------------- /src/engine/d2/web/web_view.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::d2::{ 2 | animation::AnimatedFloat, 3 | util::{Disposable, Signal1, Value}, 4 | }; 5 | 6 | /// Displays a web page over the stage. In the HTML target, this is implemented with an iframe. In 7 | /// AIR, it uses StageWebView. On Android, make sure your app manifest contains the INTERNET 8 | /// permission. 9 | pub trait WebView: Disposable { 10 | /// The URL currently being displayed. Can be set to load a different URL. In AIR, this value 11 | /// will change automatically if the user navigates to a different page. 12 | fn url(&self) -> Value; 13 | 14 | /// An error message emitted if the page could not be loaded. 15 | fn error(&self) -> Signal1; 16 | 17 | /// Viewport X position, in pixels. 18 | fn x(&self) -> AnimatedFloat; 19 | 20 | /// Viewport Y position, in pixels. 21 | fn y(&self) -> AnimatedFloat; 22 | 23 | /// Viewport width, in pixels. 24 | fn width(&self) -> AnimatedFloat; 25 | 26 | /// Viewport height, in pixels. 27 | fn height(&self) -> AnimatedFloat; 28 | } 29 | -------------------------------------------------------------------------------- /src/engine/mod.rs: -------------------------------------------------------------------------------- 1 | //! Game engines 2 | pub mod d2; 3 | -------------------------------------------------------------------------------- /src/foundation/application_settings.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | use crate::prelude::Renderable; 3 | 4 | use super::DefaultPreloader; 5 | 6 | /// Application settings 7 | pub struct ApplicationSettings { 8 | /// The initial title of the application window. 9 | pub title: String, 10 | 11 | /// Width of the viewport. 12 | pub width: u32, 13 | 14 | /// Height of the viewport. 15 | pub height: u32, 16 | 17 | /// Shall the viewport be in fullscreen mode? 18 | pub fullscreen: bool, 19 | 20 | /// Called before initializing the application host, usually to clear the window. 21 | pub before: Box, 22 | 23 | /// Called during application host initialization, usually to display progress. 24 | pub preloader: Box Box>, 25 | } 26 | 27 | impl Default for ApplicationSettings { 28 | fn default() -> Self { 29 | Self { 30 | title: String::from("UX Application"), 31 | width: 960, 32 | height: 540, 33 | fullscreen: Default::default(), 34 | before: box |w, h| {}, 35 | preloader: box || box DefaultPreloader::default(), 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/foundation/camera/mod.rs: -------------------------------------------------------------------------------- 1 | //! Camera implementations 2 | 3 | use cgmath::Point3; 4 | 5 | use crate::utils::clamp; 6 | 7 | mod arcball; 8 | pub use self::arcball::*; 9 | 10 | mod first_person; 11 | pub use self::first_person::*; 12 | 13 | pub enum CameraBehaviour { 14 | FirstPerson, 15 | Spectator, 16 | Flight, 17 | Orbit, 18 | } 19 | 20 | // Spherical coordinate system 21 | #[derive(Clone, Copy)] 22 | pub struct Camera { 23 | theta: f32, // polar angle 24 | phi: f32, // azimuthal angle 25 | r: f32, // radial distance (distance to origin) 26 | } 27 | 28 | impl Camera { 29 | pub fn position(&self) -> Point3 { 30 | Point3::new( 31 | self.r * self.phi.sin() * self.theta.sin(), 32 | self.r * self.phi.cos(), 33 | self.r * self.phi.sin() * self.theta.cos(), 34 | ) 35 | } 36 | } 37 | 38 | impl Camera { 39 | pub fn rotate(&mut self, theta: f32, phi: f32) { 40 | self.theta += theta; 41 | let phi = self.phi + phi; 42 | self.phi = clamp(phi, 10.0_f32.to_radians(), 170.0_f32.to_radians()); 43 | } 44 | 45 | pub fn forward(&mut self, r: f32) { 46 | self.r -= r; 47 | } 48 | } 49 | 50 | impl Default for Camera { 51 | fn default() -> Self { 52 | Camera { 53 | theta: 0.0_f32.to_radians(), 54 | phi: 45.0_f32.to_radians(), 55 | r: 3.0, 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/foundation/default_preloader.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | use crate::prelude::Renderable; 3 | 4 | use super::time; 5 | 6 | /// Default dummy preloader implementation 7 | pub struct DefaultPreloader; 8 | 9 | impl Default for DefaultPreloader { 10 | fn default() -> Self { 11 | Self {} 12 | } 13 | } 14 | 15 | impl Renderable for DefaultPreloader { 16 | fn render(&self, t: time::Time) {} 17 | } 18 | -------------------------------------------------------------------------------- /src/foundation/error.rs: -------------------------------------------------------------------------------- 1 | //! General errors 2 | 3 | #![allow(dead_code)] 4 | 5 | use std::fmt; 6 | 7 | /// Possible runner errors. 8 | #[derive(Debug)] 9 | pub enum Error { 10 | CannotCreateWindow(String), 11 | CannotCreateStore(String), 12 | DemoInitializationFailure(String), 13 | } 14 | 15 | impl Error { 16 | pub fn cannot_create_window(reason: R) -> Self 17 | where 18 | R: Into, 19 | { 20 | Error::CannotCreateWindow(reason.into()) 21 | } 22 | 23 | pub fn cannot_create_store(reason: R) -> Self 24 | where 25 | R: Into, 26 | { 27 | Error::CannotCreateStore(reason.into()) 28 | } 29 | 30 | pub fn app_initialization_failure(reason: R) -> Self 31 | where 32 | R: Into, 33 | { 34 | Error::DemoInitializationFailure(reason.into()) 35 | } 36 | } 37 | 38 | impl fmt::Display for Error { 39 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 40 | match *self { 41 | Error::CannotCreateWindow(ref reason) => write!(f, "cannot create window: {}", reason), 42 | Error::CannotCreateStore(ref reason) => write!(f, "cannot create store: {}", reason), 43 | Error::DemoInitializationFailure(ref reason) => { 44 | write!(f, "app failed to initialize: {}", reason) 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/foundation/resource/error.rs: -------------------------------------------------------------------------------- 1 | //! Error that might occur while loading a resource. 2 | 3 | use std::{fmt, path::PathBuf}; 4 | 5 | /// Error that might occur while loading resources. 6 | #[derive(Clone, Debug)] 7 | pub enum Error { 8 | /// The resource couldn’t be loaded from the file system. 9 | CannotLoadFromFS(PathBuf, Reason), 10 | /// The resource couldn’t be loaded. 11 | CannotLoadFromLogical(String, Reason), 12 | IOError(String), 13 | } 14 | 15 | /// Reason of a load failure. 16 | pub type Reason = String; 17 | 18 | impl fmt::Display for Error { 19 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 20 | match *self { 21 | Error::CannotLoadFromFS(ref path, ref reason) => { 22 | write!( 23 | f, 24 | "cannot load {} from file system: {}", 25 | path.display(), 26 | reason 27 | ) 28 | } 29 | Error::CannotLoadFromLogical(ref s, ref reason) => { 30 | write!(f, "cannot load <{}>: {}", s, reason) 31 | } 32 | Error::IOError(ref e) => write!(f, "{}", e), 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/foundation/resource/key.rs: -------------------------------------------------------------------------------- 1 | //! Key type used to index resources. 2 | 3 | use std::{fmt, ops::Deref, path::Path}; 4 | 5 | use warmy::SimpleKey; 6 | 7 | /// Type of key used to index resources. 8 | #[derive(Debug, Clone, Eq, Hash, PartialEq)] 9 | pub struct StoreKey(pub warmy::SimpleKey); 10 | 11 | impl fmt::Display for StoreKey { 12 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 13 | self.0.fmt(f) 14 | } 15 | } 16 | 17 | impl warmy::Key for StoreKey { 18 | fn prepare_key(self, root: &Path) -> Self { 19 | StoreKey(self.0.prepare_key(root)) 20 | } 21 | } 22 | 23 | impl Deref for StoreKey { 24 | type Target = warmy::SimpleKey; 25 | 26 | fn deref(&self) -> &Self::Target { 27 | &self.0 28 | } 29 | } 30 | 31 | impl StoreKey { 32 | pub fn from_path(path: &str) -> Self { 33 | Self(SimpleKey::from_path(path)) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/foundation/resource/mod.rs: -------------------------------------------------------------------------------- 1 | //! Resource management 2 | 3 | pub use warmy::{Res, Store, StoreOpt}; 4 | 5 | pub mod error; 6 | 7 | mod key; 8 | pub use self::key::*; 9 | 10 | // /// Load helper. 11 | // /// 12 | // /// Call this fn whenever you need to load a resource and that you want logged information, 13 | // /// such as failures, timing, etc. 14 | // pub fn load_with( 15 | // path: &Path, 16 | // loader: F 17 | // ) -> Result 18 | // where F: FnOnce() -> Result, 19 | // T: TyDesc { 20 | // info!("loading {} {}", T::TY_DESC, path.display()); 21 | // 22 | // let start_time = Instant::now(); 23 | // let r = loader(); 24 | // let t = start_time.elapsed(); 25 | // let ns = t.as_secs() as f64 * 1e9 + t.subsec_nanos() as f64; 26 | // let (pretty_time, suffix) = load_time(ns); 27 | // 28 | // if let Ok(_) = r { 29 | // info!("loaded {} {}: {:.3}{}", T::TY_DESC, path.display(), pretty_time, suffix); 30 | // } else { 31 | // err!("fail to load {} {}: {:.3}{}", T::TY_DESC, path.display(), pretty_time, suffix); 32 | // } 33 | // 34 | // r 35 | // } 36 | -------------------------------------------------------------------------------- /src/foundation/scene/light.rs: -------------------------------------------------------------------------------- 1 | use cgmath::Vector4; 2 | 3 | #[repr(C)] 4 | pub struct DirectionalLight { 5 | pub direction: Vector4, 6 | pub illuminance: Vector4, // in lx = lm / m^2 7 | } 8 | 9 | #[repr(C)] 10 | pub struct PointLight { 11 | pub position: Vector4, 12 | // luminos in flux (in lm) 13 | pub luminos: Vector4, 14 | } 15 | 16 | #[repr(C)] 17 | pub struct SpotLight { 18 | pub position: Vector4, 19 | // luminos in flux (in lm) 20 | pub luminos: Vector4, // seems it chould be vec3 for aligning 21 | pub cuttoff: f32, 22 | } 23 | 24 | impl From for Light { 25 | fn from(value: DirectionalLight) -> Self { 26 | Light::Directional(value) 27 | } 28 | } 29 | 30 | impl From for Light { 31 | fn from(value: PointLight) -> Self { 32 | Light::Point(value) 33 | } 34 | } 35 | 36 | impl From for Light { 37 | fn from(value: SpotLight) -> Self { 38 | Light::Spot(value) 39 | } 40 | } 41 | 42 | pub enum Light { 43 | Directional(DirectionalLight), 44 | Point(PointLight), 45 | Spot(SpotLight), 46 | } 47 | 48 | #[derive(Default)] 49 | pub struct LightManager { 50 | pub directional_lights: Vec, 51 | pub point_lights: Vec, 52 | pub spot_lights: Vec, 53 | } 54 | 55 | impl LightManager { 56 | pub fn add_light>(&mut self, light: T) { 57 | use Light::*; 58 | match light.into() { 59 | Directional(light) => { 60 | self.directional_lights.push(light); 61 | } 62 | Point(light) => { 63 | self.point_lights.push(light); 64 | } 65 | Spot(light) => { 66 | self.spot_lights.push(light); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/foundation/scene/mod.rs: -------------------------------------------------------------------------------- 1 | //! Scene management 2 | 3 | pub mod light; 4 | use self::light::*; 5 | 6 | pub mod model; 7 | use self::model::*; 8 | 9 | #[derive(Default)] 10 | pub struct Scene { 11 | pub lights: LightManager, 12 | pub models: Vec, 13 | } 14 | 15 | impl Scene { 16 | // user can create as much scenes as it possible 17 | // becouse scene also is actor and can have transitions in director 18 | pub fn new() -> Self { 19 | Default::default() 20 | } 21 | 22 | pub fn add(&mut self, model: Model) { 23 | self.models.push(model) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/foundation/scene/model.rs: -------------------------------------------------------------------------------- 1 | pub struct Model; 2 | -------------------------------------------------------------------------------- /src/foundation/vertex/mod.rs: -------------------------------------------------------------------------------- 1 | //! Different vertex structures 2 | 3 | mod p2; 4 | pub use p2::P2; 5 | 6 | mod p2c4; 7 | pub use p2c4::P2C4; 8 | 9 | mod p2t2; 10 | pub use p2t2::P2T2; 11 | 12 | mod p2t2c4; 13 | pub use p2t2c4::P2T2C4; 14 | 15 | mod p3; 16 | pub use p3::P3; 17 | 18 | mod p3c4; 19 | pub use p3c4::P3C4; 20 | 21 | mod p3n3; 22 | pub use p3n3::P3N3; 23 | 24 | mod p3n3c4; 25 | pub use p3n3c4::P3N3C4; 26 | 27 | mod p3n3t2; 28 | pub use p3n3t2::P3N3T2; 29 | 30 | mod p3n3t2c4; 31 | pub use p3n3t2c4::P3N3T2C4; 32 | 33 | mod p3t2; 34 | pub use p3t2::P3T2; 35 | 36 | mod p3t2c4; 37 | pub use p3t2c4::P3T2C4; 38 | -------------------------------------------------------------------------------- /src/foundation/vertex/p2.rs: -------------------------------------------------------------------------------- 1 | use cgmath::Point2; 2 | use std::mem; 3 | 4 | use crate::platform::core::{ 5 | traits::{VertexAttributesLayout, VertexBufferLayout}, 6 | BufferAddress, VertexAttribute, VertexFormat, VertexStepMode, 7 | }; 8 | 9 | // Vertex2p: 10 | // @pos: The actual position component of the position attribute 11 | // 12 | // A convenience vertex definition that can be used with 13 | // primitive_new_p2(). 14 | #[repr(C)] 15 | #[derive(Clone, Copy, Debug, PartialEq)] 16 | pub struct P2 { 17 | pub pos: Point2, 18 | } 19 | 20 | impl Default for P2 { 21 | fn default() -> Self { 22 | Self { 23 | pos: Point2 { x: 0.0, y: 0.0 }, 24 | } 25 | } 26 | } 27 | 28 | impl P2 { 29 | pub fn new(pos: Point2) -> Self { 30 | Self { pos } 31 | } 32 | 33 | pub fn from_components(pos: [f32; 2]) -> Self { 34 | Self { 35 | pos: Point2 { 36 | x: pos[0], 37 | y: pos[1], 38 | }, 39 | } 40 | } 41 | } 42 | 43 | impl VertexAttributesLayout for P2 { 44 | fn layout() -> &'static VertexBufferLayout<'static> { 45 | &VertexBufferLayout { 46 | array_stride: mem::size_of::() as BufferAddress, 47 | step_mode: VertexStepMode::Vertex, 48 | attributes: &[VertexAttribute { 49 | offset: 0, 50 | shader_location: 0, 51 | format: VertexFormat::Float32x2, 52 | }], 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/foundation/vertex/p2t2.rs: -------------------------------------------------------------------------------- 1 | use cgmath::Point2; 2 | use std::mem; 3 | 4 | use crate::platform::core::{ 5 | traits::{VertexAttributesLayout, VertexBufferLayout}, 6 | BufferAddress, VertexAttribute, VertexFormat, VertexStepMode, 7 | }; 8 | 9 | // Vertex2p2t: 10 | // @pos: The actual position component of the position attribute 11 | // @uv: The actual uv component of a texture coordinate attribute 12 | // 13 | // A convenience vertex definition that can be used with 14 | // primitive_new_p2t2(). 15 | #[repr(C)] 16 | #[derive(Clone, Copy, Debug, PartialEq)] 17 | pub struct P2T2 { 18 | pub pos: Point2, 19 | pub uv: Point2, 20 | } 21 | 22 | impl Default for P2T2 { 23 | fn default() -> Self { 24 | Self { 25 | pos: Point2 { x: 0.0, y: 0.0 }, 26 | uv: Point2 { x: 0.0, y: 0.0 }, 27 | } 28 | } 29 | } 30 | 31 | impl P2T2 { 32 | pub fn new(pos: Point2, uv: Point2) -> Self { 33 | Self { pos, uv } 34 | } 35 | 36 | pub fn from_components(pos: [f32; 2], uv: [f32; 2]) -> Self { 37 | Self { 38 | pos: Point2 { 39 | x: pos[0], 40 | y: pos[1], 41 | }, 42 | uv: Point2 { x: uv[0], y: uv[1] }, 43 | } 44 | } 45 | } 46 | 47 | impl VertexAttributesLayout for P2T2 { 48 | fn layout() -> &'static VertexBufferLayout<'static> { 49 | &VertexBufferLayout { 50 | array_stride: mem::size_of::() as BufferAddress, 51 | step_mode: VertexStepMode::Vertex, 52 | attributes: &[ 53 | VertexAttribute { 54 | offset: 0, 55 | shader_location: 0, 56 | format: VertexFormat::Float32x2, 57 | }, 58 | VertexAttribute { 59 | offset: std::mem::size_of::<[f32; 2]>() as BufferAddress, // size of previous parts 60 | shader_location: 1, 61 | format: VertexFormat::Float32x2, 62 | }, 63 | ], 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/foundation/vertex/p3.rs: -------------------------------------------------------------------------------- 1 | use cgmath::Point3; 2 | use std::mem; 3 | 4 | use crate::platform::core::{ 5 | traits::{VertexAttributesLayout, VertexBufferLayout}, 6 | BufferAddress, VertexAttribute, VertexFormat, VertexStepMode, 7 | }; 8 | 9 | // Vertex3p: 10 | // @pos: The actual position component of the position attribute 11 | // 12 | // A convenience vertex definition that can be used with 13 | // primitive_new_p3(). 14 | #[repr(C)] 15 | #[derive(Clone, Copy, Debug, PartialEq)] 16 | pub struct P3 { 17 | pub pos: Point3, 18 | } 19 | 20 | impl Default for P3 { 21 | fn default() -> Self { 22 | Self { 23 | pos: Point3 { 24 | x: 0.0, 25 | y: 0.0, 26 | z: 0.0, 27 | }, 28 | } 29 | } 30 | } 31 | 32 | impl P3 { 33 | pub fn new(pos: Point3) -> Self { 34 | Self { pos } 35 | } 36 | 37 | pub fn from_components(pos: [f32; 3]) -> Self { 38 | Self { 39 | pos: Point3 { 40 | x: pos[0], 41 | y: pos[1], 42 | z: pos[2], 43 | }, 44 | } 45 | } 46 | } 47 | 48 | impl VertexAttributesLayout for P3 { 49 | fn layout() -> &'static VertexBufferLayout<'static> { 50 | &VertexBufferLayout { 51 | array_stride: mem::size_of::() as BufferAddress, 52 | step_mode: VertexStepMode::Vertex, 53 | attributes: &[VertexAttribute { 54 | offset: 0, 55 | shader_location: 0, 56 | format: VertexFormat::Float32x3, 57 | }], 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/foundation/vertex/p3t2.rs: -------------------------------------------------------------------------------- 1 | use cgmath::{Point2, Point3}; 2 | use std::mem; 3 | 4 | use crate::platform::core::{ 5 | traits::{VertexAttributesLayout, VertexBufferLayout}, 6 | BufferAddress, VertexAttribute, VertexFormat, VertexStepMode, 7 | }; 8 | 9 | // Vertex3p2t: 10 | // @pos: The actual position component of the position attribute 11 | // @uv: The actual uv component of a texture coordinate attribute 12 | // 13 | // A convenience vertex definition that can be used with 14 | // primitive_new_p3t2(). 15 | #[repr(C)] 16 | #[derive(Clone, Copy, Debug, PartialEq)] 17 | pub struct P3T2 { 18 | pub pos: Point3, 19 | pub uv: Point2, 20 | } 21 | 22 | impl Default for P3T2 { 23 | fn default() -> Self { 24 | Self { 25 | pos: Point3 { 26 | x: 0.0, 27 | y: 0.0, 28 | z: 0.0, 29 | }, 30 | uv: Point2 { x: 0.0, y: 0.0 }, 31 | } 32 | } 33 | } 34 | 35 | impl P3T2 { 36 | pub fn new(pos: Point3, uv: Point2) -> Self { 37 | Self { pos, uv } 38 | } 39 | 40 | pub fn from_components(pos: [f32; 3], uv: [f32; 2]) -> Self { 41 | Self { 42 | pos: Point3 { 43 | x: pos[0], 44 | y: pos[1], 45 | z: pos[2], 46 | }, 47 | uv: Point2 { x: uv[0], y: uv[1] }, 48 | } 49 | } 50 | } 51 | 52 | impl VertexAttributesLayout for P3T2 { 53 | fn layout() -> &'static VertexBufferLayout<'static> { 54 | &VertexBufferLayout { 55 | array_stride: mem::size_of::() as BufferAddress, 56 | step_mode: VertexStepMode::Vertex, 57 | attributes: &[ 58 | VertexAttribute { 59 | offset: 0, 60 | shader_location: 0, 61 | format: VertexFormat::Float32x3, 62 | }, 63 | VertexAttribute { 64 | offset: mem::size_of::<[f32; 3]>() as BufferAddress, // size of previous parts 65 | shader_location: 1, 66 | format: VertexFormat::Float32x2, 67 | }, 68 | ], 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/platform/core/alias.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::c_void; 2 | 3 | pub type Angle = i32; 4 | pub type Handle = c_void; 5 | pub type MetaTexture = (); 6 | 7 | // @short_description: Interface for low-level textures like 8 | // #Texture2D and #Texture3D. 9 | // 10 | // A #PrimitiveTexture is a texture that is directly represented 11 | // by a single texture on the GPU. For example these could be a 12 | // #Texture2D, #Texture3D or #TextureRectangle. This is 13 | // opposed to high level meta textures which may be composed of 14 | // multiple primitive textures or a sub-region of another texture such 15 | // as #AtlasTexture and #Texture2DSliced. 16 | // 17 | // A texture that implements this interface can be directly used with 18 | // the low level primitive_draw() API. Other types of textures 19 | // need to be first resolved to primitive textures using the 20 | // #MetaTexture interface. 21 | // 22 | // Most developers won't need to use this interface directly but 23 | // still it is worth understanding the distinction between high-level 24 | // and primitive textures because you may find other references in the 25 | // documentation that detail limitations of using 26 | // primitive textures. 27 | pub type PrimitiveTexture = (); 28 | pub type UserDataDestroyCallback = Box; 29 | -------------------------------------------------------------------------------- /src/platform/core/atlas.rs: -------------------------------------------------------------------------------- 1 | use super::{PixelFormat, RectangleMap, Texture}; 2 | 3 | pub enum AtlasFlags { 4 | ClearTexture = (1 << 0), 5 | DisableMigration = (1 << 1), 6 | } 7 | 8 | pub struct AtlasRepositionData { 9 | // // The current user data for this texture */ 10 | // void *user_data; 11 | // // The old and new positions of the texture */ 12 | // RectangleMapEntry old_position; 13 | // RectangleMapEntry new_position; 14 | } 15 | 16 | pub struct GetRectanglesData { 17 | // AtlasRepositionData *textures; 18 | // // Number of textures found so far */ 19 | // unsigned int n_textures; 20 | } 21 | 22 | pub struct Atlas { 23 | map: Option, 24 | texture: Option, 25 | texture_format: PixelFormat, 26 | flags: AtlasFlags, 27 | // AtlasUpdatePositionCallback update_position_cb; 28 | 29 | // GHookList pre_reorganize_callbacks; 30 | // GHookList post_reorganize_callbacks; 31 | } 32 | 33 | impl Atlas { 34 | fn new( 35 | texture_format: PixelFormat, 36 | flags: AtlasFlags, /* AtlasUpdatePositionCallback update_position_cb */ 37 | ) -> Self { 38 | // atlas->update_position_cb = update_position_cb; 39 | // g_hook_list_init (&atlas->pre_reorganize_callbacks, sizeof (GHook)); 40 | // g_hook_list_init (&atlas->post_reorganize_callbacks, sizeof (GHook)); 41 | 42 | Self { 43 | map: None, 44 | texture: None, 45 | flags, 46 | texture_format, 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/platform/core/debug_object_type_info.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | use std::mem; 3 | 4 | pub enum DebugFlags { 5 | // DEBUG_SLICING, 6 | // DEBUG_OFFSCREEN, 7 | // DEBUG_DRAW, 8 | // DEBUG_PANGO, 9 | // DEBUG_RECTANGLES, 10 | // DEBUG_OBJECT, 11 | // DEBUG_BLEND_STRINGS, 12 | // DEBUG_DISABLE_BATCHING, 13 | // DEBUG_DISABLE_VBOS, 14 | // DEBUG_DISABLE_PBOS, 15 | // DEBUG_JOURNAL, 16 | // DEBUG_BATCHING, 17 | // DEBUG_DISABLE_SOFTWARE_TRANSFORM, 18 | // DEBUG_MATRICES, 19 | // DEBUG_ATLAS, 20 | // DEBUG_DUMP_ATLAS_IMAGE, 21 | // DEBUG_DISABLE_ATLAS, 22 | // DEBUG_DISABLE_SHARED_ATLAS, 23 | // DEBUG_OPENGL, 24 | // DEBUG_DISABLE_TEXTURING, 25 | // DEBUG_DISABLE_ARBFP, 26 | // DEBUG_DISABLE_FIXED, 27 | // DEBUG_DISABLE_GLSL, 28 | // DEBUG_SHOW_SOURCE, 29 | // DEBUG_DISABLE_BLENDING, 30 | // DEBUG_TEXTURE_PIXMAP, 31 | // DEBUG_BITMAP, 32 | // DEBUG_DISABLE_NPOT_TEXTURES, 33 | // DEBUG_WIREFRAME, 34 | // DEBUG_DISABLE_SOFTWARE_CLIP, 35 | // DEBUG_DISABLE_PROGRAM_CACHES, 36 | // DEBUG_DISABLE_FAST_READ_PIXEL, 37 | // DEBUG_CLIPPING, 38 | // DEBUG_WINSYS, 39 | // DEBUG_PERFORMANCE, 40 | 41 | // DEBUG_N_FLAGS 42 | } 43 | 44 | #[repr(C)] 45 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 46 | pub struct DebugObjectTypeInfo<'a> { 47 | pub name: &'a str, // TODO: may be Option, see gdk::WindowAttr 48 | pub instance_count: u64, 49 | } 50 | -------------------------------------------------------------------------------- /src/platform/core/fence.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::ptr; 3 | 4 | // @short_description: Functions for notification of command completion 5 | // 6 | // allows notification of GPU command completion; users may mark 7 | // points in the GPU command stream and receive notification when the GPU 8 | // has executed to that point. 9 | 10 | //* 11 | // * FenceCallback: 12 | // * @fence: Unused. In the future this parameter may be used to pass 13 | // * extra information about the fence completion but for now it 14 | // * should be ignored. 15 | // * @user_data: The private data passed to framebuffer_add_fence_callback() 16 | // * 17 | // * The callback prototype used with 18 | // * framebuffer_add_fence_callback() for notification of GPU 19 | // * command completion. 20 | // * 21 | // * Since: 2.0 22 | // * Stability: Unstable 23 | // */ 24 | // typedef void (* FenceCallback) (Fence *fence, 25 | // void *user_data); 26 | 27 | // Fence: 28 | // 29 | // An opaque object representing a fence. This type is currently 30 | // unused but in the future may be used to pass extra information 31 | // about the fence completion. 32 | // 33 | // Since: 2.0 34 | // Stability: Unstable 35 | #[repr(C)] 36 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 37 | pub struct Fence {} 38 | -------------------------------------------------------------------------------- /src/platform/core/frame_closure.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 2 | pub struct FrameClosure {} 3 | -------------------------------------------------------------------------------- /src/platform/core/gles2_vtable.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | clippy::too_many_arguments, 3 | clippy::let_and_return, 4 | clippy::from_over_into, 5 | clippy::upper_case_acronyms 6 | )] 7 | 8 | use std::mem; 9 | 10 | #[repr(C)] 11 | pub struct GLES2Vtable { 12 | // TODO: 13 | } 14 | -------------------------------------------------------------------------------- /src/platform/core/gtype_object.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | #[repr(C)] 4 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 5 | pub struct GtypeObject { 6 | // pub parent_instance: gobject::GTypeInstance, // TODO: deal with it 7 | pub dummy: u32, 8 | } 9 | -------------------------------------------------------------------------------- /src/platform/core/handle.rs: -------------------------------------------------------------------------------- 1 | use std::{ffi::c_void, mem, ptr}; 2 | 3 | #[repr(C)] 4 | #[derive(Debug)] 5 | pub struct Handle(c_void); 6 | -------------------------------------------------------------------------------- /src/platform/core/kms_crtc.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | #[repr(C)] 4 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 5 | pub struct KmsCrtc { 6 | // uint32_t id; 7 | // uint32_t x, y; 8 | // drmModeModeInfo mode; 9 | 10 | // uint32_t *connectors; 11 | // uint32_t count; 12 | 13 | // Bool ignore; 14 | } 15 | -------------------------------------------------------------------------------- /src/platform/core/material.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::ptr; 3 | 4 | #[repr(C)] 5 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 6 | pub struct Material {} 7 | -------------------------------------------------------------------------------- /src/platform/core/material_layer.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::ptr; 3 | 4 | #[repr(C)] 5 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 6 | pub struct MaterialLayer {} 7 | -------------------------------------------------------------------------------- /src/platform/core/onscreen_dirty_closure.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 2 | pub struct OnscreenDirtyClosure {} 3 | -------------------------------------------------------------------------------- /src/platform/core/onscreen_dirty_info.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | #[repr(C)] 4 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 5 | pub struct OnscreenDirtyInfo { 6 | pub x: i32, 7 | pub y: i32, 8 | pub width: i32, 9 | pub height: i32, 10 | } 11 | -------------------------------------------------------------------------------- /src/platform/core/onscreen_resize_closure.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 2 | pub struct OnscreenResizeClosure {} 3 | -------------------------------------------------------------------------------- /src/platform/core/path/mod.rs: -------------------------------------------------------------------------------- 1 | /// Represens Path 2 | #[derive(Debug, Clone)] 3 | pub struct Path; 4 | -------------------------------------------------------------------------------- /src/platform/core/platform/canvas/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/cogl/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/egl/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/evdev/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/gdk/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | 3 | #[cfg(target_arch = "wasm32")] 4 | mod canvas; 5 | #[cfg(target_arch = "wasm32")] 6 | pub(crate) use self::canvas::*; 7 | 8 | mod cogl; 9 | pub(crate) use self::cogl::*; 10 | 11 | // Android, Wayland, Mesa, SDL, NVIDIA, Tizen, Blackberry 12 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 13 | mod egl; 14 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 15 | pub(crate) use self::egl::*; 16 | 17 | // Handler library for evdev events 18 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 19 | mod evdev; 20 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 21 | pub(crate) use self::evdev::*; 22 | 23 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 24 | mod gdk; 25 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 26 | pub(crate) use self::gdk::*; 27 | 28 | #[cfg(all(not(target_arch = "wasm32"), target_os = "macos"))] 29 | mod osx; 30 | #[cfg(all(not(target_arch = "wasm32"), target_os = "macos"))] 31 | pub(crate) use self::osx::*; 32 | 33 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 34 | mod sdl; 35 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 36 | pub(crate) use self::sdl::*; 37 | 38 | // Touchscreen Access Library 39 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 40 | mod tslib; 41 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 42 | pub(crate) use self::tslib::*; 43 | 44 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 45 | mod vulkan; 46 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 47 | pub(crate) use self::vulkan::*; 48 | 49 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 50 | mod wayland; 51 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 52 | pub(crate) use self::wayland::*; 53 | 54 | #[cfg(all(not(target_arch = "wasm32"), target_os = "windows"))] 55 | mod win; 56 | #[cfg(all(not(target_arch = "wasm32"), target_os = "windows"))] 57 | pub(crate) use self::win::*; 58 | 59 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 60 | mod x11; 61 | #[cfg(all(not(target_arch = "wasm32"), target_os = "linux"))] 62 | pub(crate) use self::x11::*; 63 | 64 | mod stage_window; 65 | pub(crate) use self::stage_window::*; 66 | -------------------------------------------------------------------------------- /src/platform/core/platform/osx/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/sdl/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/stage_window.rs: -------------------------------------------------------------------------------- 1 | // use crate::pure::platform::cogl::Stage; 2 | struct StageWindowProps { 3 | // parent_instance: Stage, 4 | 5 | // xwin: Window, 6 | xwin_width: u32, 7 | xwin_height: u32, // FIXME target_width / height 8 | 9 | title: Option, 10 | 11 | clipped_redraws_cool_off: u32, 12 | 13 | // wm_state: StageX11State, 14 | scale_factor: f32, 15 | 16 | is_foreign_xwin: bool, 17 | fullscreening: bool, 18 | is_cursor_visible: bool, 19 | viewport_initialized: bool, 20 | accept_focus: bool, 21 | fullscreen_on_realize: bool, 22 | } 23 | #[derive(Debug, Clone)] 24 | pub struct StageWindow {} 25 | 26 | impl StageWindow {} 27 | -------------------------------------------------------------------------------- /src/platform/core/platform/tslib/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/vulkan/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/wayland/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/win/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/platform/x11/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/platform/core/poll_fd.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | clippy::too_many_arguments, 3 | clippy::let_and_return, 4 | clippy::from_over_into, 5 | clippy::upper_case_acronyms 6 | )] 7 | 8 | use std::mem; 9 | 10 | // @short_description: Functions for integrating with an 11 | // application's main loop 12 | // 13 | // needs to integrate with the application's main loop so that it 14 | // can internally handle some events from the driver. All 15 | // applications must use these functions. They provide enough 16 | // information to describe the state that will need to wake up 17 | // on. An application using the GLib main loop can instead use 18 | // source_new() which provides a #GSource ready to be added 19 | // to the main loop. 20 | 21 | // struct _PollSource 22 | // { 23 | // int fd; 24 | // PollPrepareCallback prepare; 25 | // PollDispatchCallback dispatch; 26 | // void *user_data; 27 | // }; 28 | 29 | // PollFD: 30 | // @fd: The file descriptor to block on 31 | // @events: A bitmask of events to block on 32 | // @revents: A bitmask of returned events 33 | // 34 | // A struct for describing the state of a file descriptor that 35 | // needs to block on. The @events field contains a bitmask of 36 | // #PollFDEvents that should cause the application to wake 37 | // up. After the application is woken up from idle it should pass back 38 | // an array of #PollFDs to and update the @revents 39 | // mask to the actual events that occurred on the file descriptor. 40 | // 41 | // Note that PollFD is deliberately exactly the same as struct 42 | // pollfd on Unix so that it can simply be cast when calling poll. 43 | #[repr(C)] 44 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 45 | pub struct PollFD { 46 | pub fd: i32, 47 | pub events: i16, 48 | pub revents: i16, 49 | } 50 | -------------------------------------------------------------------------------- /src/platform/core/swapchain.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::RefCell, fmt}; 2 | 3 | #[derive(Debug, Clone)] 4 | struct SwapChainProps { 5 | has_alpha: bool, 6 | length: i32, 7 | } 8 | 9 | impl Default for SwapChainProps { 10 | fn default() -> Self { 11 | Self { 12 | has_alpha: false, 13 | length: -1, 14 | } 15 | } 16 | } 17 | 18 | #[derive(Default, Debug, Clone)] 19 | pub struct LegacySwapChain { 20 | props: RefCell, 21 | } 22 | 23 | impl LegacySwapChain { 24 | pub fn new() -> LegacySwapChain { 25 | Self { 26 | props: Default::default(), 27 | } 28 | } 29 | 30 | pub fn set_has_alpha(&self, has_alpha: bool) { 31 | let mut props = self.props.borrow_mut(); 32 | props.has_alpha = has_alpha; 33 | } 34 | 35 | pub fn set_length(&self, length: i32) { 36 | let mut props = self.props.borrow_mut(); 37 | props.length = length; 38 | } 39 | } 40 | 41 | impl fmt::Display for LegacySwapChain { 42 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 43 | write!(f, "SwapChain") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/platform/core/texture_vertex.rs: -------------------------------------------------------------------------------- 1 | use crate::foundation::colorspace::Color; 2 | 3 | #[repr(C)] 4 | #[derive(Clone, Debug, PartialEq)] 5 | pub struct TextureVertex { 6 | pub x: f32, 7 | pub y: f32, 8 | pub z: f32, 9 | pub tx: f32, 10 | pub ty: f32, 11 | pub color: Color, 12 | } 13 | -------------------------------------------------------------------------------- /src/platform/core/traits.rs: -------------------------------------------------------------------------------- 1 | use super::{BufferAddress, VertexAttribute, VertexStepMode}; 2 | 3 | pub use super::FramebufferExt; 4 | pub use super::TextureExt; 5 | 6 | #[derive(Clone, Copy, Debug, PartialEq)] 7 | pub struct VertexBufferLayout<'a> { 8 | pub array_stride: BufferAddress, 9 | pub step_mode: VertexStepMode, 10 | pub attributes: &'a [VertexAttribute], 11 | } 12 | 13 | pub trait VertexAttributesLayout { 14 | /// `shader_location` in VertexAttribute should be adjusted inside application in glsl100 mode 15 | fn layout() -> &'static VertexBufferLayout<'static>; 16 | } 17 | -------------------------------------------------------------------------------- /src/platform/core/user_data_key.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | #[repr(C)] 4 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 5 | pub struct UserDataKey { 6 | pub unused: i32, 7 | } 8 | -------------------------------------------------------------------------------- /src/platform/gles/README.md: -------------------------------------------------------------------------------- 1 | https://www.khronos.org/registry/OpenGL-Refpages/es3/ 2 | 3 | ✔ -------------------------------------------------------------------------------- /src/platform/gles/canvas/shader.vert: -------------------------------------------------------------------------------- 1 | #version 150 core 2 | 3 | uniform vec2 viewSize; 4 | in vec2 vertex; 5 | in vec2 tcoord; 6 | out vec2 ftcoord; 7 | out vec2 fpos; 8 | 9 | void main(void) { 10 | ftcoord = tcoord; 11 | fpos = vertex; 12 | gl_Position = vec4(2.0 * vertex.x / viewSize.x - 1.0, 1.0 - 2.0 * vertex.y / viewSize.y, 0, 1); 13 | } 14 | -------------------------------------------------------------------------------- /src/platform/gles/core32.rs: -------------------------------------------------------------------------------- 1 | //! OpenGL ES 3.2 Core support 2 | 3 | // #![no_std] 4 | #![allow( 5 | dead_code, 6 | non_snake_case, 7 | non_camel_case_types, 8 | non_upper_case_globals, 9 | unused_imports, 10 | improper_ctypes 11 | )] 12 | 13 | use std::{ 14 | ffi::{CStr, CString}, 15 | mem::size_of, 16 | ptr, 17 | str::from_utf8, 18 | }; 19 | 20 | use libc::c_char; 21 | 22 | use super::ffi; 23 | use crate::gles::{ 24 | enums::{GL_RGBA, GL_TRUE, GL_UNSIGNED_BYTE}, 25 | types::*, 26 | }; 27 | 28 | pub mod gl { 29 | use super::*; 30 | 31 | // module-cascade infrastructure 32 | pub use crate::gles::core31::gl::*; 33 | // glBlendBarrier 34 | // glBlendEquationi 35 | // glBlendEquationSeparatei 36 | // glBlendFunci 37 | // glBlendFuncSeparatei 38 | // glColorMaski 39 | // glCopyImageSubData 40 | // glDebugMessageCallback 41 | // glDebugMessageControl 42 | // glDebugMessageInsert 43 | // glDisablei 44 | // glDrawElementsBaseVertex 45 | // glDrawElementsInstancedBaseVertex 46 | // glDrawRangeElementsBaseVertex 47 | // glEnablei 48 | // glFramebufferTexture 49 | // glGetDebugMessageLog 50 | // glGetGraphicsResetStatus 51 | // glGetnUniformfv 52 | // glGetnUniformiv 53 | // glGetnUniformuiv 54 | // glGetObjectLabel 55 | // glGetObjectPtrLabel 56 | // glGetPointerv 57 | // glGetSamplerParameterIiv 58 | // glGetSamplerParameterIuiv 59 | // glGetTexParameterIiv 60 | // glGetTexParameterIuiv 61 | // glGetnUniformfv 62 | // glGetnUniformiv 63 | // glGetnUniformuiv 64 | // glIsEnabledi 65 | // glMinSampleShading 66 | // glObjectLabel 67 | // glObjectPtrLabel 68 | // glPatchParameteri 69 | // glPopDebugGroup 70 | // glPrimitiveBoundingBox 71 | // glPushDebugGroup 72 | // glReadnPixels 73 | // glSamplerParameterIiv 74 | // glSamplerParameterIuiv 75 | // glTexBuffer 76 | // glTexBufferRange 77 | // glTexParameterIiv 78 | // glTexParameterIuiv 79 | // glTexStorage3DMultisample 80 | } -------------------------------------------------------------------------------- /src/platform/mod.rs: -------------------------------------------------------------------------------- 1 | //! Platform support 2 | pub mod core; 3 | 4 | pub mod gles; 5 | -------------------------------------------------------------------------------- /src/prelude/mod.rs: -------------------------------------------------------------------------------- 1 | //! The `dx` prelude. 2 | //! 3 | //! The purpose of this module is to alleviate imports of many common dx 4 | //! traits by adding a glob import to the top of dx heavy modules: 5 | //! 6 | //! ``` 7 | //! # #![allow(unused_imports)] 8 | //! use dx::prelude::*; 9 | //! ``` 10 | 11 | pub use crate::platform::core::traits::*; 12 | 13 | pub use primitives::prelude::*; 14 | pub use ruex::prelude::*; 15 | 16 | // pub use crate::collision::bound::{PlaneBound, Relation}; 17 | // pub use crate::collision::traits::*; 18 | // pub use crate::collision::volume::{Aabb, MinMax}; 19 | 20 | mod renderable; 21 | pub use self::renderable::*; 22 | -------------------------------------------------------------------------------- /src/prelude/renderable.rs: -------------------------------------------------------------------------------- 1 | use crate::foundation::time; 2 | 3 | /// Just a simnple renderable trait 4 | pub trait Renderable { 5 | fn render(&self, t: time::Time); 6 | } 7 | -------------------------------------------------------------------------------- /src/support/glyph/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "glow_glyph" 3 | version = "0.4.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | description = "A fast text renderer for glow, powered by glyph_brush" 7 | license = "MIT" 8 | keywords = ["font", "ttf", "truetype", "glow", "text"] 9 | repository = "https://github.com/hecrj/glow_glyph" 10 | documentation = "https://docs.rs/glow_glyph" 11 | readme = "README.md" 12 | 13 | [dependencies] 14 | glow = "0.6" 15 | glyph_brush = "0.7" 16 | log = "0.4" 17 | bytemuck = "1.4" 18 | 19 | [dev-dependencies] 20 | glutin = "0.25" 21 | env_logger = "0.8" 22 | -------------------------------------------------------------------------------- /src/support/glyph/README.md: -------------------------------------------------------------------------------- 1 | # glow_glyph 2 | 3 | [![Integration status](https://github.com/hecrj/glow_glyph/workflows/Integration/badge.svg)](https://github.com/hecrj/glow_glyph/actions) 4 | [![crates.io](https://img.shields.io/crates/v/glow_glyph.svg)](https://crates.io/crates/glow_glyph) 5 | [![Documentation](https://docs.rs/glow_glyph/badge.svg)](https://docs.rs/glow_glyph) 6 | [![License](https://img.shields.io/crates/l/glow_glyph.svg)](https://github.com/hecrj/glow_glyph/blob/master/LICENSE) 7 | 8 | A fast text renderer for [glow](https://github.com/grovesNL/glow), powered by 9 | [glyph_brush](https://github.com/alexheretic/glyph-brush/tree/master/glyph-brush) 10 | 11 | ```rust 12 | use glow_glyph::{Section, GlyphBrushBuilder}; 13 | 14 | let font: &[u8] = include_bytes!("SomeFont.ttf"); 15 | let mut glyph_brush = GlyphBrushBuilder::using_font_bytes(font) 16 | .expect("Load font") 17 | .build(&glow_context); 18 | 19 | let section = Section { 20 | text: "Hello glow_glyph", 21 | ..Section::default() // color, position, etc 22 | }; 23 | 24 | glyph_brush.queue(section); 25 | glyph_brush.queue(some_other_section); 26 | 27 | glyph_brush.draw_queued( 28 | &glow_context, 29 | window_width, 30 | window_height, 31 | ); 32 | ``` 33 | 34 | ## Examples 35 | 36 | Have a look at 37 | * `cargo run --example hello` 38 | * `cargo run --example clipping` 39 | -------------------------------------------------------------------------------- /src/support/glyph/examples/Inconsolata-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-rust/ux-dx/06facf510d595d84ea1d7f5a263e6d91e2b398d4/src/support/glyph/examples/Inconsolata-Regular.ttf -------------------------------------------------------------------------------- /src/support/glyph/pipeline/cache.rs: -------------------------------------------------------------------------------- 1 | use crate::platform::gles::{core30::gl, enums::*}; 2 | 3 | pub struct Cache { 4 | pub(crate) texture: u32, 5 | } 6 | 7 | impl Cache { 8 | pub fn new(width: u32, height: u32) -> Cache { 9 | gl::pixel_storei(GL_UNPACK_ALIGNMENT, 1); 10 | 11 | let texture = { 12 | let handle = gl::gen_texture(); 13 | 14 | gl::bind_texture(GL_TEXTURE_2D, handle); 15 | 16 | gl::tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE as i32); 17 | gl::tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE as i32); 18 | gl::tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR as i32); 19 | gl::tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR as i32); 20 | 21 | gl::empty_tex_image_2d( 22 | GL_TEXTURE_2D, 23 | 0, 24 | GL_R8 as i32, 25 | width as i32, 26 | height as i32, 27 | 0, 28 | GL_RED, 29 | GL_UNSIGNED_BYTE, 30 | ); 31 | gl::bind_texture(GL_TEXTURE_2D, 0); 32 | 33 | handle 34 | }; 35 | 36 | Cache { texture } 37 | } 38 | 39 | pub fn update(&self, offset: [u16; 2], size: [u16; 2], data: &[u8]) { 40 | let [offset_x, offset_y] = offset; 41 | let [width, height] = size; 42 | 43 | gl::bind_texture(GL_TEXTURE_2D, self.texture); 44 | 45 | gl::tex_sub_image_2d( 46 | GL_TEXTURE_2D, 47 | 0, 48 | i32::from(offset_x), 49 | i32::from(offset_y), 50 | i32::from(width), 51 | i32::from(height), 52 | GL_RED, 53 | GL_UNSIGNED_BYTE, 54 | data, 55 | ); 56 | 57 | gl::bind_texture(GL_TEXTURE_2D, 0); 58 | } 59 | 60 | pub fn destroy(&self) { 61 | gl::delete_textures(&[self.texture]); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/support/glyph/region.rs: -------------------------------------------------------------------------------- 1 | /// A region of the screen. 2 | pub struct Region { 3 | pub x: u32, 4 | pub y: u32, 5 | pub width: u32, 6 | pub height: u32, 7 | } 8 | -------------------------------------------------------------------------------- /src/support/glyph/shader/fragment.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision mediump float; 3 | 4 | uniform sampler2D font_sampler; 5 | 6 | in vec2 f_tex_pos; 7 | in vec4 f_color; 8 | 9 | out vec4 Target0; 10 | 11 | void main() { 12 | float alpha = texture(font_sampler, f_tex_pos).r; 13 | 14 | if (alpha <= 0.0) { 15 | discard; 16 | } 17 | 18 | Target0 = f_color * vec4(1.0, 1.0, 1.0, alpha); 19 | } 20 | -------------------------------------------------------------------------------- /src/support/glyph/shader/vertex.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform mat4 transform; 4 | 5 | layout(location = 0) in vec3 left_top; 6 | layout(location = 1) in vec2 right_bottom; 7 | layout(location = 2) in vec2 tex_left_top; 8 | layout(location = 3) in vec2 tex_right_bottom; 9 | layout(location = 4) in vec4 color; 10 | 11 | out vec2 f_tex_pos; 12 | out vec4 f_color; 13 | 14 | // generate positional data based on vertex ID 15 | void main() { 16 | vec2 pos = vec2(0.0); 17 | float left = left_top.x; 18 | float right = right_bottom.x; 19 | float top = left_top.y; 20 | float bottom = right_bottom.y; 21 | 22 | switch (gl_VertexID) { 23 | case 0: 24 | pos = vec2(left, top); 25 | f_tex_pos = tex_left_top; 26 | break; 27 | 28 | case 1: 29 | pos = vec2(right, top); 30 | f_tex_pos = vec2(tex_right_bottom.x, tex_left_top.y); 31 | break; 32 | 33 | case 2: 34 | pos = vec2(left, bottom); 35 | f_tex_pos = vec2(tex_left_top.x, tex_right_bottom.y); 36 | break; 37 | 38 | case 3: 39 | pos = vec2(right, bottom); 40 | f_tex_pos = tex_right_bottom; 41 | break; 42 | } 43 | 44 | f_color = color; 45 | gl_Position = transform * vec4(pos, left_top.z, 1.0); 46 | } 47 | -------------------------------------------------------------------------------- /src/support/iced/clipboard.rs: -------------------------------------------------------------------------------- 1 | /// A buffer for short-term storage and transfer within and between 2 | /// applications. 3 | #[allow(missing_debug_implementations)] 4 | pub struct Clipboard { 5 | state: State, 6 | } 7 | 8 | enum State { 9 | Connected(window_clipboard::Clipboard), 10 | Unavailable, 11 | } 12 | 13 | impl Clipboard { 14 | /// Creates a new [`Clipboard`] for the given window. 15 | pub fn connect(window: &winit::window::Window) -> Clipboard { 16 | let state = window_clipboard::Clipboard::connect(window) 17 | .ok() 18 | .map(State::Connected) 19 | .unwrap_or(State::Unavailable); 20 | 21 | Clipboard { state } 22 | } 23 | 24 | /// Reads the current content of the [`Clipboard`] as text. 25 | pub fn read(&self) -> Option { 26 | match &self.state { 27 | State::Connected(clipboard) => clipboard.read().ok(), 28 | State::Unavailable => None, 29 | } 30 | } 31 | 32 | /// Writes the given text contents to the [`Clipboard`]. 33 | pub fn write(&mut self, contents: String) { 34 | match &mut self.state { 35 | State::Connected(clipboard) => match clipboard.write(contents) { 36 | Ok(()) => {} 37 | Err(error) => { 38 | log::warn!("error writing to clipboard: {}", error) 39 | } 40 | }, 41 | State::Unavailable => {} 42 | } 43 | } 44 | } 45 | 46 | impl iced_native::Clipboard for Clipboard { 47 | fn read(&self) -> Option { 48 | self.read() 49 | } 50 | 51 | fn write(&mut self, contents: String) { 52 | self.write(contents) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/support/iced/mod.rs: -------------------------------------------------------------------------------- 1 | //! A [`ux-dx`] renderer for [`iced_native`]. 2 | //! 3 | //! ![The native path of the Iced ecosystem](https://github.com/hecrj/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true) 4 | //! 5 | //! [`ux-dx`]: https://github.com/angular-rust/ux-dx 6 | //! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native 7 | #![deny(missing_docs)] 8 | #![deny(missing_debug_implementations)] 9 | #![deny(unused_results)] 10 | // #![forbid(rust_2018_idioms)] 11 | #![cfg_attr(docsrs, feature(doc_cfg))] 12 | 13 | mod backend; 14 | mod clipboard; 15 | mod mode; 16 | mod program; 17 | mod quad; 18 | mod text; 19 | mod triangle; 20 | 21 | pub mod conversion; 22 | pub mod themes; 23 | 24 | pub mod settings; 25 | pub mod widget; 26 | pub mod window; 27 | 28 | pub use backend::Backend; 29 | pub use clipboard::Clipboard; 30 | pub use mode::Mode; 31 | pub use settings::Settings; 32 | 33 | pub(crate) use iced_graphics::Transformation; 34 | 35 | #[doc(no_inline)] 36 | pub use widget::*; 37 | 38 | // promote some subject from iced_graphics 39 | pub use iced_graphics::{ 40 | triangle::{Mesh2D, Vertex2D}, 41 | Defaults, Error, Primitive, Viewport, 42 | }; 43 | pub use iced_native::{ 44 | Background, Color, Command, HorizontalAlignment, Length, Vector, VerticalAlignment, 45 | }; 46 | 47 | /// A [`ux-dx`] graphics renderer for [`iced`]. 48 | /// 49 | /// [`ux-dx`]: https://github.com/angular-rust/ux-dx 50 | /// [`iced`]: https://github.com/hecrj/iced 51 | pub type Renderer = iced_graphics::Renderer; 52 | -------------------------------------------------------------------------------- /src/support/iced/mode.rs: -------------------------------------------------------------------------------- 1 | /// The mode of a window-based application. 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 3 | pub enum Mode { 4 | /// The application appears in its own window. 5 | Windowed, 6 | 7 | /// The application takes the whole screen of its current monitor. 8 | Fullscreen, 9 | } 10 | -------------------------------------------------------------------------------- /src/support/iced/program.rs: -------------------------------------------------------------------------------- 1 | use crate::platform::gles::{core30::gl, enums::*}; 2 | 3 | pub fn create(shader_sources: &[(u32, &str)]) -> u32 { 4 | let program = gl::create_program(); 5 | 6 | let mut shaders = Vec::with_capacity(shader_sources.len()); 7 | 8 | for (shader_type, shader_source) in shader_sources.iter() { 9 | let shader = gl::create_shader(*shader_type); 10 | 11 | gl::shader_source(shader, shader_source.as_bytes()); 12 | gl::compile_shader(shader); 13 | 14 | if gl::get_shaderiv(shader, GL_COMPILE_STATUS) == 0 { 15 | let len = gl::get_shaderiv(shader, GL_INFO_LOG_LENGTH); 16 | 17 | match gl::get_shader_info_log(shader, len) { 18 | Some(message) => { 19 | panic!("failed to compile shader: {}: {}", *shader_source, message) 20 | } 21 | None => panic!("failed to compile shader: {}", *shader_source), 22 | } 23 | } 24 | 25 | gl::attach_shader(program, shader); 26 | 27 | shaders.push(shader); 28 | } 29 | 30 | gl::link_program(program); 31 | if gl::get_programiv(program, GL_LINK_STATUS) == 0 { 32 | let len = gl::get_programiv(program, GL_INFO_LOG_LENGTH); 33 | 34 | match gl::get_program_info_log(program, len) { 35 | Some(message) => panic!("failed to link program: {}", message), 36 | None => panic!("failed to link program"), 37 | } 38 | } 39 | 40 | for shader in shaders { 41 | gl::detach_shader(program, shader); 42 | gl::delete_shader(shader); 43 | } 44 | 45 | program 46 | } 47 | -------------------------------------------------------------------------------- /src/support/iced/settings.rs: -------------------------------------------------------------------------------- 1 | //! Configure a renderer. 2 | pub use iced_graphics::Antialiasing; 3 | 4 | /// The settings of a backend. 5 | /// 6 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 7 | pub struct Settings { 8 | /// The bytes of the font that will be used by default. 9 | /// 10 | /// If `None` is provided, a default system font will be chosen. 11 | pub default_font: Option<&'static [u8]>, 12 | 13 | /// The default size of text. 14 | /// 15 | /// By default, it will be set to 20. 16 | pub default_text_size: u16, 17 | 18 | /// The antialiasing strategy that will be used for triangle primitives. 19 | pub antialiasing: Option, 20 | } 21 | 22 | impl Default for Settings { 23 | fn default() -> Settings { 24 | Settings { 25 | default_font: None, 26 | default_text_size: 20, 27 | antialiasing: None, 28 | } 29 | } 30 | } 31 | 32 | impl Settings { 33 | /// Creates new [`Settings`] using environment configuration. 34 | /// 35 | /// Currently, this is equivalent to calling [`Settings::default`]. 36 | pub fn from_env() -> Self { 37 | Self::default() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/support/iced/shader/quad.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision mediump float; 3 | 4 | uniform float u_ScreenHeight; 5 | 6 | in vec4 v_Color; 7 | in vec4 v_BorderColor; 8 | in vec2 v_Pos; 9 | in vec2 v_Scale; 10 | in float v_BorderRadius; 11 | in float v_BorderWidth; 12 | 13 | out vec4 o_Color; 14 | 15 | float distance(in vec2 frag_coord, in vec2 position, in vec2 size, float radius) 16 | { 17 | // TODO: Try SDF approach: https://www.shadertoy.com/view/wd3XRN 18 | vec2 inner_size = size - vec2(radius, radius) * 2.0; 19 | vec2 top_left = position + vec2(radius, radius); 20 | vec2 bottom_right = top_left + inner_size; 21 | 22 | vec2 top_left_distance = top_left - frag_coord; 23 | vec2 bottom_right_distance = frag_coord - bottom_right; 24 | 25 | vec2 distance = vec2( 26 | max(max(top_left_distance.x, bottom_right_distance.x), 0.0), 27 | max(max(top_left_distance.y, bottom_right_distance.y), 0.0) 28 | ); 29 | 30 | return sqrt(distance.x * distance.x + distance.y * distance.y); 31 | } 32 | 33 | void main() { 34 | vec4 mixed_color; 35 | 36 | vec2 fragCoord = vec2(gl_FragCoord.x, u_ScreenHeight - gl_FragCoord.y); 37 | 38 | // TODO: Remove branching (?) 39 | if(v_BorderWidth > 0.0) { 40 | float internal_border = max(v_BorderRadius - v_BorderWidth, 0.0); 41 | 42 | float internal_distance = distance( 43 | fragCoord, 44 | v_Pos + vec2(v_BorderWidth), 45 | v_Scale - vec2(v_BorderWidth * 2.0), 46 | internal_border 47 | ); 48 | 49 | float border_mix = smoothstep( 50 | max(internal_border - 0.5, 0.0), 51 | internal_border + 0.5, 52 | internal_distance 53 | ); 54 | 55 | mixed_color = mix(v_Color, v_BorderColor, border_mix); 56 | } else { 57 | mixed_color = v_Color; 58 | } 59 | 60 | float d = distance( 61 | fragCoord, 62 | v_Pos, 63 | v_Scale, 64 | v_BorderRadius 65 | ); 66 | 67 | float radius_alpha = 68 | 1.0 - smoothstep(max(v_BorderRadius - 0.5, 0.0), v_BorderRadius + 0.5, d); 69 | 70 | o_Color = vec4(mixed_color.xyz, mixed_color.w * radius_alpha); 71 | } 72 | -------------------------------------------------------------------------------- /src/support/iced/shader/quad.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform mat4 u_Transform; 4 | uniform float u_Scale; 5 | 6 | layout(location = 0) in vec2 i_Pos; 7 | layout(location = 1) in vec2 i_Scale; 8 | layout(location = 2) in vec4 i_Color; 9 | layout(location = 3) in vec4 i_BorderColor; 10 | layout(location = 4) in float i_BorderRadius; 11 | layout(location = 5) in float i_BorderWidth; 12 | 13 | out vec4 v_Color; 14 | out vec4 v_BorderColor; 15 | out vec2 v_Pos; 16 | out vec2 v_Scale; 17 | out float v_BorderRadius; 18 | out float v_BorderWidth; 19 | 20 | const vec2 positions[4] = vec2[]( 21 | vec2(0.0, 0.0), 22 | vec2(0.0, 1.0), 23 | vec2(1.0, 0.0), 24 | vec2(1.0, 1.0) 25 | ); 26 | 27 | void main() { 28 | vec2 q_Pos = positions[gl_VertexID]; 29 | vec2 p_Pos = i_Pos * u_Scale; 30 | vec2 p_Scale = i_Scale * u_Scale; 31 | 32 | float i_BorderRadius = min( 33 | i_BorderRadius, 34 | min(i_Scale.x, i_Scale.y) / 2.0 35 | ); 36 | 37 | mat4 i_Transform = mat4( 38 | vec4(p_Scale.x + 1.0, 0.0, 0.0, 0.0), 39 | vec4(0.0, p_Scale.y + 1.0, 0.0, 0.0), 40 | vec4(0.0, 0.0, 1.0, 0.0), 41 | vec4(p_Pos - vec2(0.5, 0.5), 0.0, 1.0) 42 | ); 43 | 44 | v_Color = i_Color; 45 | v_BorderColor = i_BorderColor; 46 | v_Pos = p_Pos; 47 | v_Scale = p_Scale; 48 | v_BorderRadius = i_BorderRadius * u_Scale; 49 | v_BorderWidth = i_BorderWidth * u_Scale; 50 | 51 | gl_Position = u_Transform * i_Transform * vec4(q_Pos, 0.0, 1.0); 52 | } 53 | -------------------------------------------------------------------------------- /src/support/iced/shader/triangle.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision mediump float; 3 | 4 | in vec4 v_Color; 5 | 6 | out vec4 o_Color; 7 | 8 | void main() { 9 | o_Color = v_Color; 10 | } 11 | -------------------------------------------------------------------------------- /src/support/iced/shader/triangle.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform mat4 u_Transform; 4 | 5 | layout(location = 0) in vec2 i_Position; 6 | layout(location = 1) in vec4 i_Color; 7 | 8 | out vec4 v_Color; 9 | 10 | void main() { 11 | gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0); 12 | v_Color = i_Color; 13 | } 14 | -------------------------------------------------------------------------------- /src/support/iced/themes/mod.rs: -------------------------------------------------------------------------------- 1 | //! Supported themes for [`iced_native`]. 2 | //! 3 | #![allow(missing_docs)] 4 | #![allow(missing_debug_implementations)] 5 | #![allow(unused_results)] 6 | pub mod dark; 7 | -------------------------------------------------------------------------------- /src/support/iced/widget.rs: -------------------------------------------------------------------------------- 1 | //! Use the widgets supported out-of-the-box. 2 | //! 3 | //! # Re-exports 4 | //! For convenience, the contents of this module are available at the root 5 | //! module. Therefore, you can directly type: 6 | //! 7 | use super::Renderer; 8 | 9 | pub mod button; 10 | pub mod checkbox; 11 | pub mod container; 12 | pub mod pane_grid; 13 | pub mod pick_list; 14 | pub mod progress_bar; 15 | pub mod radio; 16 | pub mod rule; 17 | pub mod scrollable; 18 | pub mod slider; 19 | pub mod text_input; 20 | pub mod tooltip; 21 | 22 | #[doc(no_inline)] 23 | pub use button::Button; 24 | #[doc(no_inline)] 25 | pub use checkbox::Checkbox; 26 | #[doc(no_inline)] 27 | pub use container::Container; 28 | #[doc(no_inline)] 29 | pub use pane_grid::PaneGrid; 30 | #[doc(no_inline)] 31 | pub use pick_list::PickList; 32 | #[doc(no_inline)] 33 | pub use progress_bar::ProgressBar; 34 | #[doc(no_inline)] 35 | pub use radio::Radio; 36 | #[doc(no_inline)] 37 | pub use rule::Rule; 38 | #[doc(no_inline)] 39 | pub use scrollable::Scrollable; 40 | #[doc(no_inline)] 41 | pub use slider::Slider; 42 | #[doc(no_inline)] 43 | pub use text_input::TextInput; 44 | #[doc(no_inline)] 45 | pub use tooltip::Tooltip; 46 | 47 | #[cfg(feature = "canvas")] 48 | #[cfg_attr(docsrs, doc(cfg(feature = "canvas")))] 49 | pub mod canvas; 50 | 51 | #[cfg(feature = "canvas")] 52 | #[doc(no_inline)] 53 | pub use canvas::Canvas; 54 | 55 | #[cfg(feature = "qr_code")] 56 | #[cfg_attr(docsrs, doc(cfg(feature = "qr_code")))] 57 | pub mod qr_code; 58 | 59 | #[cfg(feature = "qr_code")] 60 | #[doc(no_inline)] 61 | pub use qr_code::QRCode; 62 | 63 | pub use iced_native::{Image, Space}; 64 | 65 | /// A container that distributes its contents vertically. 66 | pub type Column<'a, Message> = iced_native::Column<'a, Message, Renderer>; 67 | 68 | /// A container that distributes its contents horizontally. 69 | pub type Row<'a, Message> = iced_native::Row<'a, Message, Renderer>; 70 | 71 | /// A paragraph of text. 72 | pub type Text = iced_native::Text; 73 | -------------------------------------------------------------------------------- /src/support/iced/widget/button.rs: -------------------------------------------------------------------------------- 1 | //! Allow your users to perform actions by pressing a button. 2 | //! 3 | //! A [`Button`] has some local [`State`]. 4 | use crate::support::iced::Renderer; 5 | 6 | pub use iced_graphics::button::{Style, StyleSheet}; 7 | pub use iced_native::button::State; 8 | 9 | /// A widget that produces a message when clicked. 10 | /// 11 | /// This is an alias of an `iced_native` button with an `iced_wgpu::Renderer`. 12 | pub type Button<'a, Message> = iced_native::Button<'a, Message, Renderer>; 13 | -------------------------------------------------------------------------------- /src/support/iced/widget/canvas.rs: -------------------------------------------------------------------------------- 1 | //! Draw 2D graphics for your users. 2 | //! 3 | //! A [`Canvas`] widget can be used to draw different kinds of 2D shapes in a 4 | //! [`Frame`]. It can be used for animation, data visualization, game graphics, 5 | //! and more! 6 | pub use iced_graphics::canvas::*; 7 | -------------------------------------------------------------------------------- /src/support/iced/widget/checkbox.rs: -------------------------------------------------------------------------------- 1 | //! Show toggle controls using checkboxes. 2 | use crate::support::iced::Renderer; 3 | 4 | pub use iced_graphics::checkbox::{Style, StyleSheet}; 5 | 6 | /// A box that can be checked. 7 | /// 8 | /// This is an alias of an `iced_native` checkbox with an `iced_wgpu::Renderer`. 9 | pub type Checkbox = iced_native::Checkbox; 10 | -------------------------------------------------------------------------------- /src/support/iced/widget/container.rs: -------------------------------------------------------------------------------- 1 | //! Decorate content and apply alignment. 2 | use crate::support::iced::Renderer; 3 | 4 | pub use iced_graphics::container::{Style, StyleSheet}; 5 | 6 | /// An element decorating some content. 7 | /// 8 | /// This is an alias of an `iced_native` container with a default 9 | /// `Renderer`. 10 | pub type Container<'a, Message> = iced_native::Container<'a, Message, Renderer>; 11 | -------------------------------------------------------------------------------- /src/support/iced/widget/pane_grid.rs: -------------------------------------------------------------------------------- 1 | //! Let your users split regions of your application and organize layout dynamically. 2 | //! 3 | //! [![Pane grid - Iced](https://thumbs.gfycat.com/MixedFlatJellyfish-small.gif)](https://gfycat.com/mixedflatjellyfish) 4 | //! 5 | //! # Example 6 | //! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, 7 | //! drag and drop, and hotkey support. 8 | //! 9 | //! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.2/examples/pane_grid 10 | use crate::support::iced::Renderer; 11 | 12 | pub use iced_graphics::pane_grid::{ 13 | Axis, Configuration, Direction, DragEvent, Line, Node, Pane, ResizeEvent, Split, State, 14 | StyleSheet, 15 | }; 16 | 17 | /// A collection of panes distributed using either vertical or horizontal splits 18 | /// to completely fill the space available. 19 | /// 20 | /// [![Pane grid - Iced](https://thumbs.gfycat.com/MixedFlatJellyfish-small.gif)](https://gfycat.com/mixedflatjellyfish) 21 | /// 22 | /// This is an alias of an `iced_native` pane grid with an `iced_wgpu::Renderer`. 23 | pub type PaneGrid<'a, Message> = iced_native::PaneGrid<'a, Message, Renderer>; 24 | 25 | /// The content of a [`Pane`]. 26 | pub type Content<'a, Message> = iced_native::pane_grid::Content<'a, Message, Renderer>; 27 | 28 | /// The title bar of a [`Pane`]. 29 | pub type TitleBar<'a, Message> = iced_native::pane_grid::TitleBar<'a, Message, Renderer>; 30 | -------------------------------------------------------------------------------- /src/support/iced/widget/pick_list.rs: -------------------------------------------------------------------------------- 1 | //! Display a dropdown list of selectable values. 2 | pub use iced_native::pick_list::State; 3 | 4 | pub use iced_graphics::{ 5 | overlay::menu::Style as Menu, 6 | pick_list::{Style, StyleSheet}, 7 | }; 8 | 9 | /// A widget allowing the selection of a single value from a list of options. 10 | pub type PickList<'a, T, Message> = 11 | iced_native::PickList<'a, T, Message, crate::support::iced::Renderer>; 12 | -------------------------------------------------------------------------------- /src/support/iced/widget/progress_bar.rs: -------------------------------------------------------------------------------- 1 | //! Allow your users to visually track the progress of a computation. 2 | //! 3 | //! A [`ProgressBar`] has a range of possible values and a current value, 4 | //! as well as a length, height and style. 5 | use crate::support::iced::Renderer; 6 | 7 | pub use iced_graphics::progress_bar::{Style, StyleSheet}; 8 | 9 | /// A bar that displays progress. 10 | /// 11 | /// This is an alias of an `iced_native` progress bar with an 12 | /// `iced_wgpu::Renderer`. 13 | pub type ProgressBar = iced_native::ProgressBar; 14 | -------------------------------------------------------------------------------- /src/support/iced/widget/qr_code.rs: -------------------------------------------------------------------------------- 1 | //! Encode and display information in a QR code. 2 | pub use iced_graphics::qr_code::*; 3 | -------------------------------------------------------------------------------- /src/support/iced/widget/radio.rs: -------------------------------------------------------------------------------- 1 | //! Create choices using radio buttons. 2 | use crate::support::iced::Renderer; 3 | 4 | pub use iced_graphics::radio::{Style, StyleSheet}; 5 | 6 | /// A circular button representing a choice. 7 | /// 8 | /// This is an alias of an `iced_native` radio button with an 9 | /// `iced_wgpu::Renderer`. 10 | pub type Radio = iced_native::Radio; 11 | -------------------------------------------------------------------------------- /src/support/iced/widget/rule.rs: -------------------------------------------------------------------------------- 1 | //! Display a horizontal or vertical rule for dividing content. 2 | 3 | use crate::support::iced::Renderer; 4 | 5 | pub use iced_graphics::rule::{FillMode, Style, StyleSheet}; 6 | 7 | /// Display a horizontal or vertical rule for dividing content. 8 | /// 9 | /// This is an alias of an `iced_native` rule with an `iced_glow::Renderer`. 10 | pub type Rule = iced_native::Rule; 11 | -------------------------------------------------------------------------------- /src/support/iced/widget/scrollable.rs: -------------------------------------------------------------------------------- 1 | //! Navigate an endless amount of content with a scrollbar. 2 | use crate::support::iced::Renderer; 3 | 4 | pub use iced_graphics::scrollable::{Scrollbar, Scroller, StyleSheet}; 5 | pub use iced_native::scrollable::State; 6 | 7 | /// A widget that can vertically display an infinite amount of content 8 | /// with a scrollbar. 9 | /// 10 | /// This is an alias of an `iced_native` scrollable with a default 11 | /// `Renderer`. 12 | pub type Scrollable<'a, Message> = iced_native::Scrollable<'a, Message, Renderer>; 13 | -------------------------------------------------------------------------------- /src/support/iced/widget/slider.rs: -------------------------------------------------------------------------------- 1 | //! Display an interactive selector of a single value from a range of values. 2 | //! 3 | //! A [`Slider`] has some local [`State`]. 4 | use crate::support::iced::Renderer; 5 | 6 | pub use iced_graphics::slider::{Handle, HandleShape, Style, StyleSheet}; 7 | pub use iced_native::slider::State; 8 | 9 | /// An horizontal bar and a handle that selects a single value from a range of 10 | /// values. 11 | /// 12 | /// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`. 13 | pub type Slider<'a, T, Message> = iced_native::Slider<'a, T, Message, Renderer>; 14 | -------------------------------------------------------------------------------- /src/support/iced/widget/text_input.rs: -------------------------------------------------------------------------------- 1 | //! Display fields that can be filled with text. 2 | //! 3 | //! A [`TextInput`] has some local [`State`]. 4 | use crate::support::iced::Renderer; 5 | 6 | pub use iced_graphics::text_input::{Style, StyleSheet}; 7 | pub use iced_native::text_input::State; 8 | 9 | /// A field that can be filled with text. 10 | /// 11 | /// This is an alias of an `iced_native` text input with an `iced_wgpu::Renderer`. 12 | pub type TextInput<'a, Message> = iced_native::TextInput<'a, Message, Renderer>; 13 | -------------------------------------------------------------------------------- /src/support/iced/widget/tooltip.rs: -------------------------------------------------------------------------------- 1 | //! Display a widget over another. 2 | /// A widget allowing the selection of a single value from a list of options. 3 | pub type Tooltip<'a, Message> = iced_native::Tooltip<'a, Message, crate::support::iced::Renderer>; 4 | 5 | pub use iced_native::tooltip::Position; 6 | -------------------------------------------------------------------------------- /src/support/iced/window.rs: -------------------------------------------------------------------------------- 1 | //! Display rendering results on windows. 2 | mod compositor; 3 | 4 | pub use compositor::Compositor; 5 | -------------------------------------------------------------------------------- /src/support/iced/window/compositor.rs: -------------------------------------------------------------------------------- 1 | use core::ffi::c_void; 2 | use iced_graphics::{Antialiasing, Size}; 3 | use iced_native::mouse; 4 | 5 | use crate::{ 6 | platform::gles::{core30::gl, enums::*}, 7 | support::iced::{Backend, Color, Error, Renderer, Settings, Viewport}, 8 | }; 9 | 10 | /// A window graphics backend for iced powered by `glow`. 11 | #[allow(missing_debug_implementations)] 12 | pub struct Compositor {} 13 | 14 | impl iced_graphics::window::GLCompositor for Compositor { 15 | type Settings = Settings; 16 | type Renderer = Renderer; 17 | 18 | unsafe fn new( 19 | settings: Self::Settings, 20 | loader_function: impl FnMut(&str) -> *const c_void, 21 | ) -> Result<(Self, Self::Renderer), Error> { 22 | // Enable auto-conversion from/to sRGB 23 | // gl::enable(GL_FRAMEBUFFER_SRGB); // DV 24 | 25 | // Enable alpha blending 26 | gl::enable(GL_BLEND); 27 | gl::blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 28 | 29 | // Disable multisampling by default 30 | // gl::disable(GL_MULTISAMPLE); // DV 31 | 32 | let renderer = Renderer::new(Backend::new(settings)); 33 | 34 | Ok((Self {}, renderer)) 35 | } 36 | 37 | fn sample_count(settings: &Settings) -> u32 { 38 | settings 39 | .antialiasing 40 | .map(Antialiasing::sample_count) 41 | .unwrap_or(0) 42 | } 43 | 44 | fn resize_viewport(&mut self, physical_size: Size) { 45 | gl::viewport( 46 | 0, 47 | 0, 48 | physical_size.width as i32, 49 | physical_size.height as i32, 50 | ); 51 | } 52 | 53 | fn draw>( 54 | &mut self, 55 | renderer: &mut Self::Renderer, 56 | viewport: &Viewport, 57 | color: Color, 58 | output: &::Output, 59 | overlay: &[T], 60 | ) -> mouse::Interaction { 61 | let [r, g, b, a] = color.into_linear(); 62 | 63 | gl::clear_color(r, g, b, a); 64 | gl::clear(GL_COLOR_BUFFER_BIT); 65 | 66 | renderer.backend_mut().draw(viewport, output, overlay) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/support/mod.rs: -------------------------------------------------------------------------------- 1 | //! Features and third party libraries support 2 | 3 | // #[cfg(feature="vg")] 4 | pub mod vg; 5 | 6 | pub mod glyph; 7 | 8 | pub mod iced; 9 | -------------------------------------------------------------------------------- /src/support/vg/main-vs.glsl: -------------------------------------------------------------------------------- 1 | 2 | uniform vec2 viewSize; 3 | 4 | attribute vec2 vertex; 5 | attribute vec2 tcoord; 6 | 7 | varying vec2 ftcoord; 8 | varying vec2 fpos; 9 | 10 | void main(void) { 11 | ftcoord = tcoord; 12 | fpos = vertex; 13 | 14 | gl_Position = vec4(2.0 * vertex.x / viewSize.x - 1.0, 1.0 - 2.0 * vertex.y / viewSize.y, 0, 1); 15 | } 16 | -------------------------------------------------------------------------------- /src/ui/immediate/id.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | pub struct Id; 3 | 4 | impl Id { 5 | pub fn handle(id: u64, ops: Option) -> Handle { 6 | // TODO: should prevent overrride the ROOT_HANDLE 7 | Handle::global().nest(id, ops) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/immediate/inspect/README.md: -------------------------------------------------------------------------------- 1 | Default traits and implementations for inspecting values with UX-DX immediate mode UI 2 | 3 | This is an adaptation of the project https://github.com/aclysma/imgui-inspect. 4 | 5 | I think this module only needs to be included in the debug profile. 6 | So figure out the `cfg` annotation in your code yourself. 7 | At the moment, it is available in any profile mode. 8 | 9 | Huge respect to the guys from the project https://github.com/aclysma/imgui-inspect -------------------------------------------------------------------------------- /src/ui/immediate/inspect/default/default_bool.rs: -------------------------------------------------------------------------------- 1 | use crate::ui::immediate::*; 2 | 3 | use super::*; 4 | 5 | impl InspectRenderDefault for bool { 6 | fn render(data: &[&bool], label: &'static str, ui: &mut Ui, _args: &InspectArgsDefault) { 7 | if data.is_empty() { 8 | // Values are inconsistent 9 | let label = format!("{}: ", label); 10 | // TODO: seems should be RED color 11 | ui.text(label.as_str(), Align::Left, None); 12 | return; 13 | } 14 | 15 | match same_or_none(data) { 16 | Some(_v) => { 17 | // Values are consistent 18 | let label = format!("{}: {}", label, data[0]); 19 | ui.text(label.as_str(), Align::Left, None); 20 | } 21 | None => { 22 | // Values are inconsistent 23 | // TODO: seems should be YELLOW color 24 | let label = format!("{}: ", label); 25 | ui.text(label.as_str(), Align::Left, None); 26 | } 27 | } 28 | } 29 | 30 | fn render_mut( 31 | data: &mut [&mut bool], 32 | label: &'static str, 33 | ui: &mut Ui, 34 | _args: &InspectArgsDefault, 35 | ) -> bool { 36 | let same_or_none_value = same_or_none_mut(data); 37 | 38 | // Some reasonable default 39 | let mut value = same_or_none_value.unwrap_or(false); 40 | 41 | let style_token = if same_or_none_value.is_none() { 42 | // If values are inconsistent, push a style 43 | Some(color::YELLOW_5) 44 | } else { 45 | None 46 | }; 47 | 48 | let mut changed = false; 49 | let label = format!("{}", label); 50 | // if ui.check(label.as_str(), &mut value) { 51 | // for d in data { 52 | // **d = value; 53 | // changed = true; 54 | // } 55 | // } 56 | 57 | // if let Some(style_token) = style_token { 58 | // style_token.pop(ui); 59 | // } 60 | 61 | changed 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ui/immediate/inspect/default/default_f32.rs: -------------------------------------------------------------------------------- 1 | use crate::ui::immediate::*; 2 | 3 | use super::*; 4 | 5 | impl InspectRenderDefault for f32 { 6 | fn render(data: &[&f32], label: &'static str, ui: &mut Ui, _args: &InspectArgsDefault) { 7 | if data.is_empty() { 8 | // Values are inconsistent 9 | let label = format!("{}: ", label); 10 | // TODO: seems should be RED color 11 | ui.text(label.as_str(), Align::Left, None); 12 | return; 13 | } 14 | 15 | match same_or_none(data) { 16 | Some(_v) => { 17 | // Values are consistent 18 | let label = format!("{}: {}", label, data[0]); 19 | ui.text(label.as_str(), Align::Left, None); 20 | } 21 | None => { 22 | // Values are inconsistent 23 | // TODO: seems should be YELLOW color 24 | let label = format!("{}: ", label); 25 | ui.text(label.as_str(), Align::Left, None); 26 | } 27 | } 28 | } 29 | 30 | fn render_mut( 31 | data: &mut [&mut f32], 32 | label: &'static str, 33 | ui: &mut Ui, 34 | _args: &InspectArgsDefault, 35 | ) -> bool { 36 | let same_or_none_value = same_or_none_mut(data); 37 | 38 | // Some reasonable default 39 | let mut value = same_or_none_value.unwrap_or(0.0); 40 | 41 | let style_token = if same_or_none_value.is_none() { 42 | // If values are inconsistent, push a style 43 | Some(color::YELLOW_5) 44 | } else { 45 | None 46 | }; 47 | 48 | let mut changed = false; 49 | let label = format!("{}", label); 50 | // if ui 51 | // .text_input(label.as_str(), &mut value) 52 | // .build() 53 | // { 54 | // for d in data { 55 | // **d = value; 56 | // changed = true; 57 | // } 58 | // } 59 | 60 | // if let Some(style_token) = style_token { 61 | // style_token.pop(ui); 62 | // } 63 | 64 | changed 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/ui/immediate/inspect/default/default_option.rs: -------------------------------------------------------------------------------- 1 | use crate::ui::immediate::*; 2 | 3 | use super::*; 4 | 5 | impl> InspectRenderDefault> for Option { 6 | fn render(data: &[&Option], label: &'static str, ui: &mut Ui, args: &InspectArgsDefault) { 7 | if data.is_empty() { 8 | let label = format!("{}: None", label); 9 | ui.text(label.as_str(), Align::Left, None); 10 | return; 11 | } 12 | 13 | let d = data[0]; 14 | match d { 15 | Some(value) => >::render(&[value], label, ui, args), 16 | None => { 17 | let label = format!("{}: None", label); 18 | ui.text(label.as_str(), Align::Left, None); 19 | } 20 | }; 21 | } 22 | 23 | fn render_mut( 24 | data: &mut [&mut Option], 25 | label: &'static str, 26 | ui: &mut Ui, 27 | args: &InspectArgsDefault, 28 | ) -> bool { 29 | if data.is_empty() { 30 | let label = format!("{}: None", label); 31 | ui.text(label.as_str(), Align::Left, None); 32 | return false; 33 | } 34 | 35 | let d = &mut data[0]; 36 | match d { 37 | Some(value) => { 38 | >::render_mut(&mut [value], label, ui, args) 39 | } 40 | None => { 41 | let label = format!("{}: None", label); 42 | ui.text(label.as_str(), Align::Left, None); 43 | false 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/ui/immediate/inspect/default/default_usize.rs: -------------------------------------------------------------------------------- 1 | use crate::ui::immediate::*; 2 | 3 | use super::*; 4 | 5 | impl InspectRenderDefault for usize { 6 | fn render(data: &[&usize], label: &'static str, ui: &mut Ui, _args: &InspectArgsDefault) { 7 | if data.is_empty() { 8 | // Values are inconsistent 9 | let label = format!("{}: ", label); 10 | ui.text(label.as_str(), Align::Left, None); 11 | return; 12 | } 13 | 14 | match same_or_none(data) { 15 | Some(_v) => { 16 | // Values are consistent 17 | let label = format!("{}: {}", label, data[0]); 18 | ui.text(label.as_str(), Align::Left, None); 19 | } 20 | None => { 21 | // Values are inconsistent 22 | // TODO: seems should be YELLOW color 23 | let label = format!("{}: ", label); 24 | ui.text(label.as_str(), Align::Left, None); 25 | } 26 | } 27 | } 28 | 29 | fn render_mut( 30 | data: &mut [&mut usize], 31 | label: &'static str, 32 | ui: &mut Ui, 33 | _args: &InspectArgsDefault, 34 | ) -> bool { 35 | let same_or_none_value = same_or_none_mut(data); 36 | 37 | // Some reasonable default 38 | let value = same_or_none_value.unwrap_or(0); 39 | 40 | // CAST 41 | let mut value = value as i32; 42 | 43 | let style_token = if same_or_none_value.is_none() { 44 | // If values are inconsistent, push a style 45 | Some(color::YELLOW_5) 46 | } else { 47 | None 48 | }; 49 | 50 | let mut changed = false; 51 | let label = format!("{}", label); 52 | // if ui 53 | // .text_input(label.as_str(), label), &mut value) 54 | // .build() 55 | // { 56 | // for d in data { 57 | // // CAST 58 | // let value = value as usize; 59 | 60 | // **d = value; 61 | // changed = true; 62 | // } 63 | // } 64 | 65 | // if let Some(style_token) = style_token { 66 | // style_token.pop(ui); 67 | // } 68 | 69 | changed 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/ui/immediate/inspect/default/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::ui::immediate::Ui; 2 | 3 | mod default_bool; 4 | mod default_f32; 5 | mod default_option; 6 | mod default_string; 7 | mod default_u32; 8 | mod default_usize; 9 | 10 | use super::*; 11 | 12 | /// Options for using the default rendering style for the element. 13 | /// 14 | /// The options here are a superset of all other options since "default" could be any of the widgets. 15 | /// 16 | /// So, not all elements will necessarily be used/respected. Use the non-default traits for typesafe 17 | /// changes. 18 | /// 19 | /// Marking a struct element with something like `#[inspect(min_value = 5.0, max_value = 53.0)]` 20 | /// will make the widget for that member default to those values. 21 | #[derive(Debug, Default, Clone)] 22 | pub struct InspectArgsDefault { 23 | /// If true, the struct will have a visual/expandable header added to it. This defaults to true. 24 | /// 25 | /// To customize this, disable this header programmatically by passing your own 26 | /// InspectArgsDefault into `render` or `render_mut` 27 | pub header: Option, 28 | 29 | /// If true, any child elements (i.e. struct members) will be indented. This defaults to true. 30 | pub indent_children: Option, 31 | 32 | /// Minimum value for the widget. The precise meaning of this can vary depending on the widget type 33 | pub min_value: Option, 34 | 35 | /// Maximum value for the widget. The precise meaning of this can vary depending on the widget type 36 | pub max_value: Option, 37 | 38 | /// Minimum value for the widget. The precise meaning of this can vary depending on the widget type 39 | pub step: Option, 40 | } 41 | 42 | /// Renders a value using the default widget 43 | pub trait InspectRenderDefault { 44 | /// Render the element in an immutable way (i.e. static text) 45 | /// 46 | fn render(data: &[&T], label: &'static str, ui: &mut Ui, args: &InspectArgsDefault); 47 | 48 | /// Render the element in a mutable way. Using this trait, the default widget to use is based 49 | /// on the type. 50 | fn render_mut( 51 | data: &mut [&mut T], 52 | label: &'static str, 53 | ui: &mut Ui, 54 | args: &InspectArgsDefault, 55 | ) -> bool; 56 | } 57 | -------------------------------------------------------------------------------- /src/ui/immediate/inspect/mod.rs: -------------------------------------------------------------------------------- 1 | //! Object Inspector using Immediate UI 2 | 3 | #![allow(dead_code)] 4 | #![allow(unused_variables)] 5 | #![allow(unused_mut)] 6 | 7 | use crate::ui::immediate::Ui; 8 | 9 | mod default; 10 | mod slider; 11 | 12 | pub use default::*; 13 | pub use slider::*; 14 | 15 | /// Options for rendering a value as a struct (i.e. draw all of its subfields) 16 | #[derive(Debug, Default)] 17 | pub struct InspectArgsStruct { 18 | pub header: Option, 19 | pub indent_children: Option, 20 | } 21 | 22 | impl From for InspectArgsStruct { 23 | fn from(default_args: InspectArgsDefault) -> Self { 24 | Self { 25 | header: default_args.header, 26 | indent_children: default_args.indent_children, 27 | } 28 | } 29 | } 30 | 31 | /// Renders a struct (i.e. draw all of its subfields). 32 | /// 33 | /// Most traits are implemented by hand-written code, but this trait 34 | /// is normally generated by putting `#[derive(Inspect)]` on a struct 35 | pub trait InspectRenderStruct { 36 | fn render(data: &[&T], label: &'static str, ui: &mut Ui, args: &InspectArgsStruct); 37 | fn render_mut( 38 | data: &mut [&mut T], 39 | label: &'static str, 40 | ui: &mut Ui, 41 | args: &InspectArgsStruct, 42 | ) -> bool; 43 | } 44 | 45 | /// Utility fn that, given a list of references, returns Some(T) if they are the same, otherwise None 46 | pub fn same_or_none(data: &[&T]) -> Option { 47 | if data.is_empty() { 48 | return None; 49 | } 50 | 51 | let first = data[0].clone(); 52 | for d in data { 53 | if **d != first { 54 | return None; 55 | } 56 | } 57 | 58 | Some(first) 59 | } 60 | 61 | /// Utility fn that, given a list of references, returns Some(T) if they are the same, otherwise None 62 | fn same_or_none_mut(data: &mut [&mut T]) -> Option { 63 | if data.is_empty() { 64 | return None; 65 | } 66 | 67 | let first = data[0].clone(); 68 | for d in data { 69 | if **d != first { 70 | return None; 71 | } 72 | } 73 | 74 | Some(first) 75 | } 76 | -------------------------------------------------------------------------------- /src/ui/immediate/inspect/slider/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::ui::immediate::Ui; 2 | 3 | mod slider_f32; 4 | 5 | use super::*; 6 | 7 | /// Options for rendering a values as a slider. 8 | /// 9 | /// Marking a struct member will give it a default rendering behavior. For example, 10 | /// `#[inspect_slider(min_value = 5.0, max_value = 53.0)]` 11 | #[derive(Debug, Default)] 12 | pub struct InspectArgsSlider { 13 | /// The minimum value for the slider 14 | pub min_value: Option, 15 | 16 | /// The maximum value on the slider 17 | pub max_value: Option, 18 | } 19 | 20 | impl From for InspectArgsSlider { 21 | fn from(default_args: InspectArgsDefault) -> Self { 22 | Self { 23 | min_value: default_args.min_value, 24 | max_value: default_args.max_value, 25 | } 26 | } 27 | } 28 | 29 | /// Renders a value as a slider 30 | pub trait InspectRenderSlider { 31 | /// Render the element in an immutable way (i.e. static text) 32 | /// 33 | fn render(data: &[&T], label: &'static str, ui: &mut Ui, args: &InspectArgsSlider); 34 | 35 | /// Render the element as a mutable slider 36 | fn render_mut( 37 | data: &mut [&mut T], 38 | label: &'static str, 39 | ui: &mut Ui, 40 | args: &InspectArgsSlider, 41 | ) -> bool; 42 | } 43 | -------------------------------------------------------------------------------- /src/ui/immediate/inspect/slider/slider_f32.rs: -------------------------------------------------------------------------------- 1 | use crate::ui::immediate::*; 2 | 3 | use super::*; 4 | 5 | impl InspectRenderSlider for f32 { 6 | fn render(data: &[&Self], label: &'static str, ui: &mut Ui, _args: &InspectArgsSlider) { 7 | if data.is_empty() { 8 | let label = format!("{}: None", label); 9 | ui.text(label.as_str(), Align::Left, None); 10 | return; 11 | } 12 | 13 | let label = format!("{}: {}", label, data[0]); 14 | ui.text(label.as_str(), Align::Left, None); 15 | } 16 | 17 | fn render_mut( 18 | data: &mut [&mut Self], 19 | label: &'static str, 20 | ui: &mut Ui, 21 | args: &InspectArgsSlider, 22 | ) -> bool { 23 | let same_or_none_value = same_or_none_mut(data); 24 | 25 | // Some reasonable default 26 | let mut value = same_or_none_value.unwrap_or(0.0); 27 | 28 | let style_token = if same_or_none_value.is_none() { 29 | // If values are inconsistent, push a style 30 | Some(color::YELLOW_5) 31 | } else { 32 | None 33 | }; 34 | 35 | let mut min = -100.0; 36 | let mut max = 100.0; 37 | if let Some(min_value) = args.min_value { 38 | min = min_value; 39 | } 40 | 41 | if let Some(max_value) = args.max_value { 42 | max = max_value; 43 | } 44 | 45 | let mut changed = false; 46 | let label = format!("{}", label); 47 | // if ui.slider(label.as_str())) 48 | // .range(std::ops::RangeInclusive::new(min, max)) 49 | // .build(ui, &mut value) 50 | // { 51 | // for d in data { 52 | // **d = value; 53 | // changed = true; 54 | // } 55 | // } 56 | 57 | // if let Some(style_token) = style_token { 58 | // style_token.pop(ui); 59 | // } 60 | 61 | changed 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ui/immediate/macros.rs: -------------------------------------------------------------------------------- 1 | pub(crate) const fn hash(s: &str) -> u32 { 2 | let s = s.as_bytes(); 3 | let mut hash = 3581u32; 4 | let mut i = 0usize; 5 | while i < s.len() { 6 | hash = hash.wrapping_mul(33).wrapping_add(s[i] as u32); 7 | i += 1; 8 | } 9 | 10 | hash 11 | } 12 | 13 | pub(crate) const fn splitmix(seed: u64) -> u64 { 14 | let next = seed.wrapping_add(0x9e3779b97f4a7c15); 15 | let mut z = next; 16 | z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9); 17 | z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb); 18 | 19 | z ^ (z >> 31) 20 | } 21 | 22 | pub(crate) const SEED: u64 = splitmix(hash(env!("CARGO")) as u64); // Pick some other env var... 23 | 24 | pub const fn entropy(file: &str, line: u32, column: u32) -> u64 { 25 | splitmix( 26 | SEED ^ (hash(file) as u64 27 | ^ (line as u64).rotate_left(32) 28 | ^ (column as u64).rotate_left(48)), 29 | ) 30 | } 31 | 32 | /// Create constant uiid based on the location in sources 33 | #[macro_export] 34 | macro_rules! uiid { 35 | () => {{ 36 | const ENTROPY: u64 = $crate::ui::immediate::entropy(file!(), line!(), column!()); 37 | ENTROPY 38 | }}; 39 | } 40 | -------------------------------------------------------------------------------- /src/ui/mod.rs: -------------------------------------------------------------------------------- 1 | //! User interface support 2 | 3 | pub mod immediate; 4 | -------------------------------------------------------------------------------- /src/utils/clamp.rs: -------------------------------------------------------------------------------- 1 | /// Clamp `value` between `min` and `max`. 2 | pub fn clamp(value: T, min: T, max: T) -> T { 3 | let value = if value > max { max } else { value }; 4 | if value < min { 5 | min 6 | } else { 7 | value 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | //! General utilities 2 | 3 | #![allow(unused_imports)] 4 | use std::{ 5 | env, 6 | path::{Path, PathBuf}, 7 | time::SystemTime, 8 | }; 9 | 10 | mod clamp; 11 | pub use self::clamp::*; 12 | 13 | /// Return string representation of elapsed time 14 | pub fn elapsed(start_time: &SystemTime) -> String { 15 | let elapsed = start_time.elapsed().unwrap(); 16 | format!( 17 | "{}s {:.*}ms", 18 | elapsed.as_secs(), 19 | 1, 20 | elapsed.subsec_nanos() as f64 / 1_000_000.0 21 | ) 22 | } 23 | 24 | /// Return elapsed time in seconds 25 | pub fn time(start_time: &SystemTime) -> f32 { 26 | start_time.elapsed().unwrap().as_millis() as f32 / 1000.0 27 | } 28 | 29 | /// Detect framework assets only 30 | pub fn assets_library(value: &str) -> PathBuf { 31 | let path = PathBuf::from(value); 32 | if path.is_relative() { 33 | // deal with relative paths 34 | if cfg!(debug_assertions) { 35 | Path::new(env!("CARGO_MANIFEST_DIR")) 36 | .join("assets") 37 | .join(path) 38 | } else { 39 | match env::current_exe().unwrap().parent() { 40 | Some(dir) => dir.join("assets").join(path), 41 | None => { 42 | // exe located in root. aka "/" 43 | path 44 | } 45 | } 46 | } 47 | } else { 48 | path 49 | } 50 | } 51 | --------------------------------------------------------------------------------