From e22cd5abb5f6d50422e8102144769c323d8cb75c Mon Sep 17 00:00:00 2001 From: QuantumBadger Date: Fri, 26 Feb 2021 15:49:02 +0000 Subject: [PATCH] Initial commit --- .github/workflows/build.yml | 93 + .gitignore | 3 + Cargo.toml | 67 + LICENSE | 202 ++ README.md | 132 ++ assets/fonts/NotoSans-Regular.ttf | Bin 0 -> 455188 bytes assets/screenshots/hello_world.png | Bin 0 -> 9594 bytes examples/hello_world.rs | 57 + examples/input_callbacks.rs | 161 ++ examples/user_events.rs | 73 + rustfmt.toml | 18 + src/color.rs | 226 +++ src/dimen.rs | 311 +++ src/error.rs | 194 ++ src/font.rs | 1079 ++++++++++ src/font_cache.rs | 675 +++++++ src/glwrapper.rs | 1092 ++++++++++ src/image.rs | 72 + src/lib.rs | 974 +++++++++ src/numeric.rs | 128 ++ src/renderer2d.rs | 708 +++++++ src/shaders/r2d_fragment.glsl | 39 + src/shaders/r2d_vertex.glsl | 45 + src/shape.rs | 153 ++ src/texture_packer.rs | 224 +++ src/utils.rs | 49 + src/window.rs | 1774 +++++++++++++++++ .../expected_images/test_basic_circles.png | Bin 0 -> 256 bytes .../expected_images/test_basic_rectangles.png | Bin 0 -> 189 bytes .../expected_images/test_basic_text.png | Bin 0 -> 26479 bytes .../expected_images/test_half_circle.png | Bin 0 -> 1516 bytes .../expected_images/test_lines_horizontal.png | Bin 0 -> 178 bytes .../expected_images/test_lines_vertical.png | Bin 0 -> 196 bytes .../expected_images/test_text_alignment.png | Bin 0 -> 40608 bytes .../test_text_line_spacing.png | Bin 0 -> 40579 bytes .../expected_images/test_text_tracking.png | Bin 0 -> 18334 bytes .../expected_images/test_wrapped_text_1.png | Bin 0 -> 58873 bytes test/main.rs | 542 +++++ 38 files changed, 9091 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 assets/fonts/NotoSans-Regular.ttf create mode 100644 assets/screenshots/hello_world.png create mode 100644 examples/hello_world.rs create mode 100644 examples/input_callbacks.rs create mode 100644 examples/user_events.rs create mode 100644 rustfmt.toml create mode 100644 src/color.rs create mode 100644 src/dimen.rs create mode 100644 src/error.rs create mode 100644 src/font.rs create mode 100644 src/font_cache.rs create mode 100644 src/glwrapper.rs create mode 100644 src/image.rs create mode 100644 src/lib.rs create mode 100644 src/numeric.rs create mode 100644 src/renderer2d.rs create mode 100644 src/shaders/r2d_fragment.glsl create mode 100644 src/shaders/r2d_vertex.glsl create mode 100644 src/shape.rs create mode 100644 src/texture_packer.rs create mode 100644 src/utils.rs create mode 100644 src/window.rs create mode 100644 test/assets/expected_images/test_basic_circles.png create mode 100644 test/assets/expected_images/test_basic_rectangles.png create mode 100644 test/assets/expected_images/test_basic_text.png create mode 100644 test/assets/expected_images/test_half_circle.png create mode 100644 test/assets/expected_images/test_lines_horizontal.png create mode 100644 test/assets/expected_images/test_lines_vertical.png create mode 100644 test/assets/expected_images/test_text_alignment.png create mode 100644 test/assets/expected_images/test_text_line_spacing.png create mode 100644 test/assets/expected_images/test_text_tracking.png create mode 100644 test/assets/expected_images/test_wrapped_text_1.png create mode 100644 test/main.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..530084a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,93 @@ +name: CI + +on: [push, pull_request] + +jobs: + + build: + name: Build + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macOS-latest ] + + steps: + - uses: actions/checkout@v2 + + - name: Build + run: cargo build + + test: + name: Test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Install xvfb + run: sudo apt-get --yes install xvfb + + - name: Start X server and run tests + run: xvfb-run --auto-servernum cargo test + + clippy: + name: Clippy + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Clippy + run: cargo clippy + + fmt: + name: Formatting + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Install nightly toolchain + run: rustup install nightly + + - name: Install rustfmt + run: rustup component add rustfmt --toolchain nightly + + - name: Formatting + run: cargo +nightly fmt -- --check + + doc: + name: Documentation + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Documentation + run: cargo doc + + build_nowindowing: + name: Build (no windowing) + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macOS-latest ] + + steps: + - uses: actions/checkout@v2 + + - name: Build + run: cargo build --no-default-features + + test_nowindowing: + name: Test (no windowing) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Install xvfb + run: sudo apt-get --yes install xvfb + + - name: Start X server and run tests + run: xvfb-run --auto-servernum cargo test --no-default-features --lib --examples --tests \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b471067 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +.idea diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..cc6920e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,67 @@ +[package] +name = "speedy2d" +version = "1.0.0" +authors = ["QuantumBadger "] +edition = "2018" +license = "Apache-2.0" +readme = "README.md" +description = """ +Hardware-accelerated drawing of shapes, images, and text, with an easy to use API. + +Speedy2D aims to be: + + - The simplest Rust API for creating a window, rendering graphics, and handling input + - Compatible with any device supporting OpenGL 2.0+ or OpenGL ES 2.0+ + - Very fast + +Documentation and getting started guide: https://docs.rs/speedy2d + +By default, Speedy2D contains support for setting up a window with an OpenGL context. If +you'd like to handle this yourself, and use Speedy2D only for rendering, you can disable +the `windowing` feature. +""" +keywords = ["opengl", "gamedev", "graphics", "font"] +categories = ["rendering::graphics-api", "game-development", "graphics"] +repository = "https://github.com/QuantumBadger/Speedy2D" +documentation = "https://docs.rs/speedy2d" + +[features] +default = ["windowing"] +windowing = ["glutin"] + +[dependencies] +gl = "0.14" +log = "0.4" +backtrace = "0.3" +rusttype = { version = "0.9", default-features = false } +unicode-normalization = "0.1" +num-traits = "0.2" + +# For windowing feature +glutin = { version = "0.26", optional = true } + +# Tests using a headless GL context. + +[[test]] +name = "test" +path = "test/main.rs" +harness = false + +[dev-dependencies] +simple_logger = "1.11" +glutin = "0.26" +image = { version = "0.23", default-features = false, features = ["png"] } + +# Examples: must be listed manually as they require the "windowing" feature. + +[[example]] +name = "hello_world" +required-features = ["windowing"] + +[[example]] +name = "user_events" +required-features = ["windowing"] + +[[example]] +name = "input_callbacks" +required-features = ["windowing"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..92a49a5 --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +# Speedy2D + +[![Crate](https://img.shields.io/crates/v/speedy2d.svg)](https://crates.io/crates/speedy2d) +[![Documentation](https://docs.rs/speedy2d/badge.svg)](https://docs.rs/speedy2d) +[![CI](https://github.com/QuantumBadger/Speedy2D/actions/workflows/build.yml/badge.svg)](hhttps://github.com/QuantumBadger/Speedy2D/actions) + +Hardware-accelerated drawing of shapes, images, and text, with an easy to +use API. + +Speedy2D aims to be: + + - The simplest Rust API for creating a window, rendering graphics/text, and + handling input + - Compatible with any device supporting OpenGL 2.0+ or OpenGL ES 2.0+ + - Very fast + +By default, Speedy2D contains support for setting up a window with an OpenGL +context, and receiving input events. If you'd like to handle this yourself, and +use Speedy2D only for rendering, you can disable the `windowing` feature. + +## Useful Links + +* Documentation and getting started guide: https://docs.rs/speedy2d +* Crate: https://crates.io/crates/speedy2d +* Example code: https://github.com/QuantumBadger/Speedy2D + +## Example code + +* [Hello world, with text rendering](examples/hello_world.rs) +* [All input callbacks](examples/input_callbacks.rs) +* [User-generated events](examples/user_events.rs) + +The example projects can be run using `cargo run --example=hello_world` (just +change `hello_world` to the name of the example source file). + +[![Screenshot](assets/screenshots/hello_world.png)](examples/hello_world.rs) + +## Quick Start + +**Step 1:** Add Speedy2D to your `Cargo.toml` dependencies: + +```toml +[dependencies] +speedy2d = "1.0" +``` + +**Step 2:** Create a window: + +```rust +use speedy2d::Window; + +let window = Window::new_centered("Title", (640, 480)).unwrap(); +``` + +**Step 3:** Create a struct implementing the `WindowHandler` trait. Override +whichever callbacks you're interested in, for example `on_draw()`, +`on_mouse_move()`, or `on_key_down()`. + +```rust +use speedy2d::window::{WindowHandler, WindowHelper}; +use speedy2d::Graphics2D; + +struct MyWindowHandler {} + +impl WindowHandler for MyWindowHandler +{ + fn on_draw(&mut self, helper: &mut WindowHelper, graphics: &mut Graphics2D) + { + graphics.clear_screen(Color::from_rgb(0.8, 0.9, 1.0)); + graphics.draw_circle((100.0, 100.0), 75.0, Color::BLUE); + + // Request that we draw another frame once this one has finished + helper.request_redraw(); + } + + // If desired, on_mouse_move(), on_key_down(), etc... +} +``` + +**Step 4:** Finally, start the event loop by passing your new `WindowHandler` +to the `run_loop()` function. + +```rust +window.run_loop(MyWindowHandler{}); +``` + +For a more detailed getting started guide, including a full list of `WindowHandler` +callbacks, and how to render text, go to +[docs.rs/speedy2d](https://docs.rs/speedy2d). + +### Alternative: Managing the GL context yourself + +If you'd rather handle the window creation and OpenGL context management +yourself, simply disable Speedy2D's `windowing` feature in your `Cargo.toml` +file, and create a context as follows: + +```rust +use speedy2d::GLRenderer; + +let mut renderer = unsafe { + GLRenderer::new_for_current_context((640, 480)) +}.unwrap(); +``` + +Then, draw a frame using `GLRenderer::draw_frame()`: + +```rust +renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + graphics.draw_circle((100.0, 100.0), 75.0, Color::BLUE); +}); +``` + +## License + +Speedy2D is licensed under the Apache license, version 2.0. See +[LICENSE](LICENSE) for more details. + +## Contributing + +Pull requests for Speedy2D are always welcome. Please ensure the following +checks pass locally before submitting: + +```bash +cargo test +cargo test --no-default-features --lib --examples --tests +cargo clippy +cargo +nightly fmt -- --check +cargo doc +``` + +Some tests require the ability to create a headless OpenGL context. diff --git a/assets/fonts/NotoSans-Regular.ttf b/assets/fonts/NotoSans-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a1b8994edeacd70067de843a4691b15a0ce5921b GIT binary patch literal 455188 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

%|9xe=xvH&G46fdEyKf_sZg6mtr>)|xqgLj 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

Ql&Yk*=nEBPXJ)j7KBUse{ucUPuDZZ{>(+0O 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

;yPY5v|6v!{LM0K*I3aQftq9dNA-=@fw;K3Q6sY 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%0ASENd@`aBfAqQz~-N7-!m!%|#O(?4o7rGCF) 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

ShWRVdNJlpc|04kVRFVp?|@!WKZ$*x%7)45 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 +} + +impl WindowHandler for MyWindowHandler +{ + fn on_draw(&mut self, helper: &mut WindowHelper, graphics: &mut Graphics2D) + { + graphics.clear_screen(Color::WHITE); + + graphics.draw_circle((150.0, 120.0), 75.0, Color::from_rgb(0.8, 0.9, 1.0)); + + graphics.draw_text((290.0, 90.0), Color::BLACK, &self.text); + + // Request that we draw another frame once this one has finished + helper.request_redraw(); + } +} diff --git a/examples/input_callbacks.rs b/examples/input_callbacks.rs new file mode 100644 index 0000000..9cde8f2 --- /dev/null +++ b/examples/input_callbacks.rs @@ -0,0 +1,161 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#![deny(warnings)] + +use speedy2d::color::Color; +use speedy2d::dimen::Vector2; +use speedy2d::window::{ + KeyScancode, + ModifiersState, + MouseButton, + VirtualKeyCode, + WindowHandler, + WindowHelper, + WindowStartupInfo +}; +use speedy2d::{Graphics2D, Window}; + +fn main() +{ + simple_logger::SimpleLogger::new().init().unwrap(); + + let window = + Window::new_centered("Speedy2D: Input Callbacks Example", (640, 480)).unwrap(); + + window.run_loop(MyWindowHandler { + mouse_pos: Vector2::ZERO, + mouse_button_down: false + }) +} + +struct MyWindowHandler +{ + mouse_pos: Vector2, + mouse_button_down: bool +} + +impl WindowHandler for MyWindowHandler +{ + fn on_start(&mut self, helper: &mut WindowHelper, info: WindowStartupInfo) + { + log::info!("Got on_start callback: {:?}", info); + helper.set_cursor_visible(false); + helper.set_resizable(false); + } + + fn on_resize(&mut self, _helper: &mut WindowHelper, size_pixels: Vector2) + { + log::info!("Got on_resize callback: {:?}", size_pixels); + } + + fn on_scale_factor_changed(&mut self, _helper: &mut WindowHelper, scale_factor: f64) + { + log::info!("Got on_scale_factor_changed callback: {:.3}", scale_factor); + } + + fn on_draw(&mut self, _helper: &mut WindowHelper, graphics: &mut Graphics2D) + { + // Clear the screen + graphics.clear_screen(Color::from_rgb(0.8, 0.9, 1.0)); + + // Red for down, blue for up + let color = match self.mouse_button_down { + true => Color::RED, + false => Color::BLUE + }; + + // Draw a circle at the mouse pointer location + graphics.draw_circle(self.mouse_pos, 20.0, color); + } + + fn on_mouse_move(&mut self, helper: &mut WindowHelper, position: Vector2) + { + log::info!( + "Got on_mouse_move callback: ({:.1}, {:.1})", + position.x, + position.y + ); + + self.mouse_pos = position; + + helper.request_redraw(); + } + + fn on_mouse_button_down(&mut self, helper: &mut WindowHelper, button: MouseButton) + { + log::info!("Got on_mouse_button_down callback: {:?}", button); + + if button == MouseButton::Left { + self.mouse_button_down = true; + } + + helper.request_redraw(); + } + + fn on_mouse_button_up(&mut self, helper: &mut WindowHelper, button: MouseButton) + { + log::info!("Got on_mouse_button_up callback: {:?}", button); + + if button == MouseButton::Left { + self.mouse_button_down = false; + } + + helper.request_redraw(); + } + + fn on_key_down( + &mut self, + _helper: &mut WindowHelper, + virtual_key_code: Option, + scancode: KeyScancode + ) + { + log::info!( + "Got on_key_down callback: {:?}, scancode {}", + virtual_key_code, + scancode + ); + } + + fn on_key_up( + &mut self, + _helper: &mut WindowHelper, + virtual_key_code: Option, + scancode: KeyScancode + ) + { + log::info!( + "Got on_key_up callback: {:?}, scancode {}", + virtual_key_code, + scancode + ); + } + + fn on_keyboard_char(&mut self, _helper: &mut WindowHelper, unicode_codepoint: char) + { + log::info!("Got on_keyboard_char callback: '{}'", unicode_codepoint); + } + + fn on_keyboard_modifiers_changed( + &mut self, + _helper: &mut WindowHelper, + state: ModifiersState + ) + { + log::info!("Got on_keyboard_modifiers_changed callback: {:?}", state); + } +} diff --git a/examples/user_events.rs b/examples/user_events.rs new file mode 100644 index 0000000..a107fe1 --- /dev/null +++ b/examples/user_events.rs @@ -0,0 +1,73 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#![deny(warnings)] + +use speedy2d::color::Color; +use speedy2d::dimen::Vector2; +use speedy2d::window::{ + UserEventSender, + WindowCreationOptions, + WindowHandler, + WindowHelper, + WindowSize +}; +use speedy2d::{Graphics2D, Window}; + +fn main() +{ + simple_logger::SimpleLogger::new().init().unwrap(); + + let window: Window = Window::new_with_user_events( + "Speedy2D: User Events Example", + WindowCreationOptions::new_windowed( + WindowSize::PhysicalPixels(Vector2::new(640, 480)), + None + ) + ) + .unwrap(); + + // Creates a UserEventSender, which can be used to post custom + // events to this event loop from another thread. + // + // It's also possible to create an event sender using + // `WindowHelper::create_user_event_sender()`. + let user_event_sender = window.create_user_event_sender(); + + window.run_loop(MyWindowHandler { user_event_sender }) +} + +struct MyWindowHandler +{ + user_event_sender: UserEventSender +} + +impl WindowHandler for MyWindowHandler +{ + fn on_user_event(&mut self, _helper: &mut WindowHelper, user_event: String) + { + log::info!("Received user event: '{}'", user_event); + } + + fn on_draw(&mut self, _helper: &mut WindowHelper, graphics: &mut Graphics2D) + { + graphics.clear_screen(Color::from_rgb(0.8, 0.9, 1.0)); + + self.user_event_sender + .send_event("Hello World".to_string()) + .unwrap(); + } +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..91bd065 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,18 @@ +max_width = 90 +newline_style = "Unix" +use_field_init_shorthand = true + +unstable_features = true +combine_control_expr = false +condense_wildcard_suffixes = true +error_on_line_overflow = true +error_on_unformatted = true +format_strings = true +imports_layout = "HorizontalVertical" +imports_granularity = "Module" +group_imports = "StdExternalCrate" +wrap_comments = true +trailing_comma = "Never" +brace_style = "AlwaysNextLine" +report_fixme = "Always" +report_todo = "Always" \ No newline at end of file diff --git a/src/color.rs b/src/color.rs new file mode 100644 index 0000000..f07fcc7 --- /dev/null +++ b/src/color.rs @@ -0,0 +1,226 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// A struct representing a color with red, green, blue, and alpha components. +/// Each component is stored as a float. +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct Color +{ + r: f32, + g: f32, + b: f32, + a: f32 +} + +impl Color +{ + /// Color constant for transparency, with the alpha value set to zero. + pub const TRANSPARENT: Color = Color::from_rgba(0.0, 0.0, 0.0, 0.0); + + /// Constant for the color black. + pub const BLACK: Color = Color::from_rgb(0.0, 0.0, 0.0); + + /// Constant for the color white. + pub const WHITE: Color = Color::from_rgb(1.0, 1.0, 1.0); + + /// Constant for the color red. + pub const RED: Color = Color::from_rgb(1.0, 0.0, 0.0); + + /// Constant for the color green. + pub const GREEN: Color = Color::from_rgb(0.0, 1.0, 0.0); + + /// Constant for the color blue. + pub const BLUE: Color = Color::from_rgb(0.0, 0.0, 1.0); + + /// Constant for the color yellow. + pub const YELLOW: Color = Color::from_rgb(1.0, 1.0, 0.0); + + /// Constant for the color cyan. + pub const CYAN: Color = Color::from_rgb(0.0, 1.0, 1.0); + + /// Constant for the color magenta. + pub const MAGENTA: Color = Color::from_rgb(1.0, 0.0, 1.0); + + /// Constant for the color gray. + pub const GRAY: Color = Color::from_rgb(0.5, 0.5, 0.5); + + /// Constant for the color light gray. + pub const LIGHT_GRAY: Color = Color::from_rgb(0.75, 0.75, 0.75); + + /// Constant for the color dark gray. + pub const DARK_GRAY: Color = Color::from_rgb(0.25, 0.25, 0.25); + + /// Creates a color with the specified components, including an alpha + /// component. Each component should be in the range `0.0` to `1.0`. + #[inline] + pub const fn from_rgba(r: f32, g: f32, b: f32, a: f32) -> Self + { + Color { r, g, b, a } + } + + /// Creates a color with the specified components. The alpha component will + /// be set to 1.0 (full opacity). Each component should be in the range + /// `0.0` to `1.0`. + #[inline] + pub const fn from_rgb(r: f32, g: f32, b: f32) -> Self + { + Color { r, g, b, a: 1.0 } + } + + /// Creates a color with the specified components, including an alpha + /// component. Each component should be in the range `0` to `255`. + #[inline] + pub fn from_int_rgba(r: u8, g: u8, b: u8, a: u8) -> Self + { + Color { + r: r as f32 / 255.0, + g: g as f32 / 255.0, + b: b as f32 / 255.0, + a: a as f32 / 255.0 + } + } + + /// Creates a color with the specified components. The alpha component will + /// be set to 255 (full opacity). Each component should be in the range + /// `0` to `255`. + #[inline] + pub fn from_int_rgb(r: u8, g: u8, b: u8) -> Self + { + Color { + r: r as f32 / 255.0, + g: g as f32 / 255.0, + b: b as f32 / 255.0, + a: 1.0 + } + } + + /// Creates a color from the specified integer value, including an alpha + /// component. + /// + /// For example, the input value `0xAABBCCDD` will result in a color with: + /// + /// * Alpha = `0xAA` + /// * Red = `0xBB` + /// * Green = `0xCC` + /// * Blue = `0xDD` + /// + /// Note: If you don't specify the alpha component, the color will be + /// transparent. + #[inline] + pub fn from_hex_argb(argb: u32) -> Self + { + Color::from_int_rgba( + (argb >> 16) as u8, + (argb >> 8) as u8, + argb as u8, + (argb >> 24) as u8 + ) + } + + /// Creates a color from the specified integer value, with the alpha + /// component set to `255` (full opacity). + /// + /// For example, the input value `0xAABBCC` will result in a color with: + /// + /// * Alpha = `0xFF` + /// * Red = `0xAA` + /// * Green = `0xBB` + /// * Blue = `0xCC` + /// + /// Note: if an alpha component is specified in the high bits of the + /// integer, it will be ignored. See [Color::from_hex_argb] if you wish to + /// specify the alpha component. + #[inline] + pub fn from_hex_rgb(rgb: u32) -> Self + { + Color::from_int_rgb((rgb >> 16) as u8, (rgb >> 8) as u8, rgb as u8) + } + + /// Returns the red component of the color, as a value in the range `0.0` to + /// `1.0`. + #[inline] + pub const fn r(&self) -> f32 + { + self.r + } + + /// Returns the green component of the color, as a value in the range `0.0` + /// to `1.0`. + #[inline] + pub const fn g(&self) -> f32 + { + self.g + } + + /// Returns the blue component of the color, as a value in the range `0.0` + /// to `1.0`. + #[inline] + pub const fn b(&self) -> f32 + { + self.b + } + + /// Returns the alpha component of the color, as a value in the range `0.0` + /// to `1.0`. The value `0.0` is fully transparent, and the value `1.0` + /// is fully opaque. + #[inline] + pub const fn a(&self) -> f32 + { + self.a + } + + /// Returns the brightness of the color as perceived by a human, as a value + /// in the range `0.0` to `1.0`. + /// + /// This is calculated using the following formula: + /// + /// ``` + /// # let red = 0.0; + /// # let green = 0.0; + /// # let blue = 0.0; + /// # let result = + /// red * 0.299 + green * 0.587 + blue * 0.114 + /// # ; + /// ``` + pub fn subjective_brightness(&self) -> f32 + { + self.r * 0.299 + self.g * 0.587 + self.b * 0.114 + } +} + +#[cfg(test)] +mod tests +{ + use super::*; + + #[test] + fn test_from_hex() + { + // We're comparing floats for equality here, which is normally a bad idea, but + // here the result should be deterministic as it's computed the same way both + // times. + + assert_eq!( + Color::from_hex_rgb(0xFF5511), + Color::from_int_rgb(0xFF, 0x55, 0x11) + ); + + assert_eq!( + Color::from_hex_argb(0xAAFF5511), + Color::from_int_rgba(0xFF, 0x55, 0x11, 0xAA) + ); + } +} diff --git a/src/dimen.rs b/src/dimen.rs new file mode 100644 index 0000000..8bd539e --- /dev/null +++ b/src/dimen.rs @@ -0,0 +1,311 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::convert::TryInto; + +use rusttype::Point; + +use crate::numeric::{PrimitiveZero, RoundFloat}; + +/// A vector containing two numeric values. This may represent a size or +/// position. +#[repr(C)] +#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)] +pub struct Vector2 +{ + /// The horizontal component of the vector. + pub x: T, + /// The vertical component of the vector. + pub y: T +} + +impl Vector2 +{ + /// Instantiates a new `Vector2` from the specified horizontal and vertical + /// components. + #[inline] + #[must_use] + pub const fn new(x: T, y: T) -> Self + { + Vector2 { x, y } + } +} + +impl Vector2 +{ + /// A constant representing a vector of zero magnitude. Each component is + /// set to zero. + pub const ZERO: Vector2 = Vector2::new(T::ZERO, T::ZERO); +} + +impl Vector2 +{ + /// Returns the magnitude of the vector, squared. + #[inline] + #[must_use] + pub fn magnitude_squared(&self) -> f32 + { + self.x * self.x + self.y * self.y + } + + /// Returns the magnitude of the vector. + #[inline] + #[must_use] + pub fn magnitude(&self) -> f32 + { + self.magnitude_squared().sqrt() + } + + /// Normalizes the vector so that the magnitude is `1.0`. If the current + /// magnitude of the vector is `0.0`, then `None` is returned to avoid a + /// division by zero. + #[inline] + #[must_use] + pub fn normalize(&self) -> Option> + { + let magnitude = self.magnitude(); + + if magnitude == 0.0 { + return None; + } + + Some(self / magnitude) + } +} + +impl + Copy> Vector2 +{ + /// Rotates the vector by 90 degrees in the clockwise direction. + #[inline] + #[must_use] + pub fn rotate_90_degrees_clockwise(&self) -> Vector2 + { + Vector2::new(-self.y, self.x) + } + + /// Rotates the vector by 90 degrees in the anti-clockwise direction. + #[inline] + #[must_use] + pub fn rotate_90_degrees_anticlockwise(&self) -> Vector2 + { + Vector2::new(self.y, -self.x) + } +} + +impl> Vector2 +{ + /// Returns a new vector with each element cast to `f32`, using the `as` + /// operator. + #[inline] + #[must_use] + pub fn into_f32(self) -> Vector2 + { + Vector2::new(self.x.as_(), self.y.as_()) + } +} + +impl> Vector2 +{ + /// Returns a new vector with each element cast to `i32`, using the `as` + /// operator. + #[inline] + #[must_use] + pub fn into_i32(self) -> Vector2 + { + Vector2::new(self.x.as_(), self.y.as_()) + } +} + +impl> Vector2 +{ + /// Attempts to convert each element of this vector to an `i32`, returning + /// an error if this fails. + #[inline] + pub fn try_into_i32(self) -> Result, T::Error> + { + Ok(Vector2::new(self.x.try_into()?, self.y.try_into()?)) + } +} + +impl From<(T, T)> for Vector2 +where + T: Copy +{ + #[inline] + #[must_use] + fn from(value: (T, T)) -> Self + { + Vector2::new(value.0, value.1) + } +} + +impl> std::ops::Add> for Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn add(self, rhs: Self) -> Self::Output + { + Vector2::new(self.x + rhs.x, self.y + rhs.y) + } +} + +impl> std::ops::Add<&Vector2> for Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn add(self, rhs: &Self) -> Self::Output + { + Vector2::new(self.x + rhs.x, self.y + rhs.y) + } +} + +impl> std::ops::Add> for &Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn add(self, rhs: Vector2) -> Self::Output + { + Vector2::new(self.x + rhs.x, self.y + rhs.y) + } +} + +impl> std::ops::Sub> for Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn sub(self, rhs: Self) -> Self::Output + { + Vector2::new(self.x - rhs.x, self.y - rhs.y) + } +} + +impl> std::ops::Sub<&Vector2> for Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn sub(self, rhs: &Self) -> Self::Output + { + Vector2::new(self.x - rhs.x, self.y - rhs.y) + } +} + +impl> std::ops::Sub> for &Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn sub(self, rhs: Vector2) -> Self::Output + { + Vector2::new(self.x - rhs.x, self.y - rhs.y) + } +} + +impl> std::ops::Mul for &Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn mul(self, rhs: T) -> Self::Output + { + Vector2::new(self.x * rhs, self.y * rhs) + } +} + +impl> std::ops::Mul for Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn mul(self, rhs: T) -> Self::Output + { + Vector2::new(self.x * rhs, self.y * rhs) + } +} + +impl> std::ops::Div for &Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn div(self, rhs: T) -> Self::Output + { + Vector2::new(self.x / rhs, self.y / rhs) + } +} + +impl> std::ops::Div for Vector2 +{ + type Output = Vector2; + + #[inline] + #[must_use] + fn div(self, rhs: T) -> Self::Output + { + Vector2::new(self.x / rhs, self.y / rhs) + } +} + +impl RoundFloat for Vector2 +{ + fn round(&self) -> Self + { + Vector2::new(self.x.round(), self.y.round()) + } +} + +impl From> for Vector2 +{ + #[inline] + #[must_use] + fn from(point: Point) -> Self + { + Vector2::new(point.x, point.y) + } +} + +#[cfg(test)] +mod test +{ + use super::*; + + #[test] + fn test_arithmetic() + { + assert_eq!( + Vector2::new(15, 20), + Vector2::new(10, 4) + Vector2::new(5, 16) + ); + + assert_eq!( + Vector2::new(5, -12), + Vector2::new(10, 4) - Vector2::new(5, 16) + ); + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..b25b594 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,194 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::fmt::{Debug, Display, Formatter}; +use std::rc::Rc; + +use backtrace::Backtrace; + +/// An error with an associated backtrace, and an optional cause. +#[derive(Clone)] +pub struct BacktraceError +where + E: Debug + Display + 'static +{ + value: Rc> +} + +struct BacktraceErrorImpl +where + E: Debug + Display +{ + error: E, + backtrace: Backtrace, + cause: Option> +} + +impl std::error::Error for BacktraceError {} + +impl Display for BacktraceError +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result + { + Display::fmt(self.error(), f) + } +} + +impl Debug for BacktraceError +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result + { + f.debug_struct("BacktraceError") + .field("error", self.error()) + .field("backtrace", self.get_backtrace()) + .field("cause", self.cause()) + .finish() + } +} + +impl BacktraceError +{ + #[must_use] + pub(crate) fn new_with_cause( + error: E, + cause: Cause + ) -> Self + { + BacktraceError { + value: Rc::new(BacktraceErrorImpl { + backtrace: Backtrace::new(), + error, + cause: Some(Box::new(cause)) + }) + } + } + + #[must_use] + pub(crate) fn new(error: E) -> Self + { + BacktraceError { + value: Rc::new(BacktraceErrorImpl { + backtrace: Backtrace::new(), + error, + cause: None + }) + } + } + + /// Returns the backtrace for this error. + #[must_use] + pub fn get_backtrace(&self) -> &Backtrace + { + &self.value.backtrace + } + + /// Returns the error. + #[must_use] + pub fn error(&self) -> &E + { + &self.value.error + } + + /// Returns the original cause of the error, if one is present. + #[must_use] + pub fn cause(&self) -> &Option> + { + &self.value.cause + } + + #[must_use] + pub(crate) fn context>( + self, + description: S + ) -> BacktraceError + { + BacktraceError::new_with_cause( + ErrorMessage { + description: description.as_ref().to_string() + }, + self + ) + } +} + +/// A human-readable error message. +#[derive(Clone, Debug)] +pub struct ErrorMessage +{ + description: String +} + +impl ErrorMessage +{ + pub(crate) fn msg>(description: S) -> BacktraceError + { + BacktraceError::new(Self { + description: description.as_ref().to_string() + }) + } + + pub(crate) fn msg_with_cause( + description: S, + cause: Cause + ) -> BacktraceError + where + S: AsRef, + Cause: std::error::Error + 'static + { + BacktraceError::new_with_cause( + Self { + description: description.as_ref().to_string() + }, + cause + ) + } +} + +impl Display for ErrorMessage +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result + { + Display::fmt(&self.description, f) + } +} + +pub(crate) trait Context +{ + fn context>( + self, + description: S + ) -> Result>; +} + +impl Context for Result +{ + fn context>( + self, + description: S + ) -> Result> + { + if self.is_ok() { + return Ok(self.ok().unwrap()); + } + + Err(BacktraceError::new_with_cause( + ErrorMessage { + description: description.as_ref().to_string() + }, + self.err().unwrap() + )) + } +} diff --git a/src/font.rs b/src/font.rs new file mode 100644 index 0000000..714c567 --- /dev/null +++ b/src/font.rs @@ -0,0 +1,1079 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::collections::VecDeque; +use std::convert::TryInto; +use std::fmt::{Debug, Formatter}; +use std::hash::{Hash, Hasher}; +use std::iter::Peekable; +use std::rc::Rc; +use std::slice::Iter; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::vec::IntoIter; + +use unicode_normalization::UnicodeNormalization; + +use crate::dimen::Vector2; +use crate::error::{BacktraceError, ErrorMessage}; +use crate::shape::Rectangle; + +static FONT_ID_GENERATOR: AtomicUsize = AtomicUsize::new(10000); + +/// Type of the [Codepoint::user_index] and [FormattedGlyph::user_index] fields. +/// +/// The `user_index` field allows you to determine which output glyph +/// corresponds to which input codepoint. +pub type UserGlyphIndex = u32; + +/// An internal identifier for a font. Each font which is loaded receives a +/// unique ID. +pub type FontId = usize; + +/// A struct representing a Unicode codepoint, for the purposes of text layout. +/// The `user_index` field allows you to determine which output glyph +/// corresponds to which input codepoint. +#[derive(Debug, Hash, Eq, PartialEq, Clone)] +pub struct Codepoint +{ + user_index: UserGlyphIndex, + codepoint: char +} + +impl Codepoint +{ + /// The Unicode codepoint for a zero width space. You may use this to denote + /// places where it would be appropriate to insert a line break when + /// wrapping. + pub const ZERO_WIDTH_SPACE: char = '\u{200B}'; + + /// Instantiates a new `Codepoint`. The value provided for `user_index` will + /// be present in the corresponding `FormattedGlyph` object returned + /// during layout. + #[inline] + #[must_use] + pub fn new(user_index: UserGlyphIndex, codepoint: char) -> Self + { + Codepoint { + user_index, + codepoint + } + } + + fn from_unindexed_codepoints(unindexed_codepoints: &[char]) -> Vec + { + let mut codepoints = Vec::new(); + codepoints.reserve(unindexed_codepoints.len()); + + for (i, codepoint) in unindexed_codepoints.iter().enumerate() { + codepoints.push(Codepoint::new(i.try_into().unwrap(), *codepoint)); + } + + codepoints + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Hash)] +struct Word +{ + codepoints: Vec, + is_whitespace: bool +} + +impl Word +{ + fn starting_from_codepoint_location(mut self, location: usize) -> Self + { + self.codepoints.drain(0..location); + + Word { + codepoints: self.codepoints, + is_whitespace: self.is_whitespace + } + } + + fn split_words(codepoints: &[Codepoint]) -> Vec + { + let mut reader = codepoints.iter().peekable(); + + let mut result = Vec::new(); + + while let Some(first_token) = reader.next() { + let mut word_codepoints = Vec::new(); + word_codepoints.push(first_token.clone()); + + match first_token.codepoint { + Codepoint::ZERO_WIDTH_SPACE => { + // Do nothing here, just ignore it + } + + ' ' | '\t' | '\r' | '\n' => { + // Whitespace + + while let Some(next) = reader.peek() { + match next.codepoint { + ' ' | '\t' | '\r' | '\n' => { + word_codepoints.push(reader.next().unwrap().clone()) + } + _ => break + } + } + + result.push(Word { + codepoints: word_codepoints, + is_whitespace: true + }); + } + + _ => { + // Non-whitespace word + + while let Some(next) = reader.peek() { + match next.codepoint { + ' ' | '\t' | '\r' | '\n' | Codepoint::ZERO_WIDTH_SPACE => { + break + } + _ => word_codepoints.push(reader.next().unwrap().clone()) + } + } + + result.push(Word { + codepoints: word_codepoints, + is_whitespace: false + }); + } + } + } + + result + } +} + +/// A struct representing a glyph in a font. +pub struct FontGlyph +{ + glyph: rusttype::Glyph<'static>, + font: Font +} + +struct WordsIterator +{ + words: Peekable>, + pending: VecDeque +} + +impl WordsIterator +{ + fn from(words: Vec) -> Self + { + WordsIterator { + words: words.into_iter().peekable(), + pending: VecDeque::new() + } + } + + #[inline] + #[must_use] + fn has_next(&self) -> bool + { + self.words.len() > 0 || self.pending.len() > 0 + } + + #[inline] + #[must_use] + fn peek(&mut self) -> Option<&Word> + { + if let Some(word) = self.pending.front() { + return Some(word); + } + + if let Some(word) = self.words.peek() { + return Some(word); + } + + None + } + + #[inline] + fn next(&mut self) -> Option + { + if let Some(word) = self.pending.pop_front() { + return Some(word); + } + + if let Some(word) = self.words.next() { + return Some(word); + } + + None + } + + #[inline] + fn add_pending(&mut self, word: Word) + { + self.pending.push_back(word); + } +} + +#[derive(Clone, Debug)] +struct LineLayoutMetrics +{ + x_pos: f32, + max_ascent: f32, + min_descent: f32, + max_line_gap: f32, + last_glyph_id: Option, + last_font_id: Option +} + +impl LineLayoutMetrics +{ + fn new() -> Self + { + LineLayoutMetrics { + x_pos: 0.0, + max_ascent: 0.0, + min_descent: 0.0, + max_line_gap: 0.0, + last_glyph_id: None, + last_font_id: None + } + } + + #[inline] + #[must_use] + fn height(&self) -> f32 + { + self.max_ascent - self.min_descent + } + + fn update_and_get_render_pos_x( + &mut self, + glyph: &rusttype::ScaledGlyph, + font_id: FontId, + scale: &rusttype::Scale, + options: &TextOptions + ) -> f32 + { + if let Some(last_glyph_id) = self.last_glyph_id { + if self.last_font_id == Some(font_id) { + self.x_pos += + glyph.font().pair_kerning(*scale, last_glyph_id, glyph.id()); + } + + self.x_pos += options.tracking; + } + + if self.last_font_id != Some(font_id) { + let v_metrics = glyph.font().v_metrics(*scale); + + self.max_ascent = crate::numeric::max(self.max_ascent, v_metrics.ascent); + self.min_descent = crate::numeric::min(self.min_descent, v_metrics.descent); + self.max_line_gap = + crate::numeric::max(self.max_line_gap, v_metrics.line_gap); + } + + let advance_width = glyph.h_metrics().advance_width; + + let glyph_x_pos_start = self.x_pos; + self.x_pos += advance_width; + + self.last_font_id = Some(font_id); + self.last_glyph_id = Some(glyph.id()); + + glyph_x_pos_start + } +} + +enum WordLayoutResult +{ + Success(LineLayoutMetrics), + PartialWord(LineLayoutMetrics), + NotEnoughSpace +} + +impl WordLayoutResult +{ + fn get_metrics(&self) -> Option<&LineLayoutMetrics> + { + match self { + WordLayoutResult::Success(metrics) => Some(metrics), + WordLayoutResult::PartialWord(metrics) => Some(metrics), + WordLayoutResult::NotEnoughSpace => None + } + } + + fn end_of_line(&self) -> bool + { + match self { + WordLayoutResult::Success(_) => false, + WordLayoutResult::PartialWord(_) => true, + WordLayoutResult::NotEnoughSpace => true + } + } +} + +#[allow(clippy::too_many_arguments)] +fn try_layout_word_internal( + layout_helper: &T, + word: Word, + remaining_words: &mut WordsIterator, + scale: &rusttype::Scale, + options: &TextOptions, + pos_y_baseline: f32, + first_word_on_line: bool, + previous_metrics: &LineLayoutMetrics, + output: &mut Vec +) -> WordLayoutResult +{ + let mut new_word_metrics = previous_metrics.clone(); + let pos_x_max = options.wrap_words_after_width; + + let mut glyphs = Vec::new(); + + for ( + i, + Codepoint { + user_index, + codepoint: c + } + ) in word.codepoints.iter().enumerate() + { + // We can't modify the actual values until we're sure we can render this glyph + let mut new_glyph_metrics = new_word_metrics.clone(); + + let glyph = match layout_helper.lookup_glyph_for_codepoint(*c) { + None => { + match layout_helper + .lookup_glyph_for_codepoint('□') + .or_else(|| layout_helper.lookup_glyph_for_codepoint('?')) + { + None => continue, + Some(glyph) => glyph + } + } + Some(glyph) => glyph + }; + + let scaled_glyph = glyph.glyph.scaled(*scale); + + let glyph_x_pos_start = new_glyph_metrics.update_and_get_render_pos_x( + &scaled_glyph, + glyph.font.id(), + scale, + options + ); + + let formatted_glyph = FormattedGlyph { + user_index: *user_index, + glyph: scaled_glyph.positioned(rusttype::point(glyph_x_pos_start, 0.0)), + font_id: glyph.font.id() + }; + + if let Some(pos_x_max) = pos_x_max { + if new_glyph_metrics.x_pos > pos_x_max { + if first_word_on_line { + if i == 0 { + // First glyph in word, we should render it even though it goes + // over the boundary + glyphs.push(formatted_glyph); + new_word_metrics = new_glyph_metrics; + + // If there are more codepoints, we need to split the word + if word.codepoints.len() > 1 { + remaining_words.add_pending( + word.starting_from_codepoint_location(i + 1) + ); + } + } else { + remaining_words + .add_pending(word.starting_from_codepoint_location(i)); + } + + glyphs.iter_mut().for_each(|glyph| { + glyph.reposition_y(pos_y_baseline + new_word_metrics.max_ascent); + }); + + output.append(&mut glyphs); + return WordLayoutResult::PartialWord(new_word_metrics); + } else { + remaining_words.add_pending(word); + return WordLayoutResult::NotEnoughSpace; + } + } + } + + glyphs.push(formatted_glyph); + new_word_metrics = new_glyph_metrics; + } + + glyphs.iter_mut().for_each(|glyph| { + glyph.reposition_y(pos_y_baseline + new_word_metrics.max_ascent); + }); + + output.append(&mut glyphs); + + WordLayoutResult::Success(new_word_metrics) +} + +fn layout_line_internal( + layout_helper: &T, + words: &mut WordsIterator, + scale: &rusttype::Scale, + options: &TextOptions, + pos_y_baseline: f32 +) -> FormattedTextLine +{ + let mut line_metrics = LineLayoutMetrics::new(); + let mut glyphs = Vec::new(); + + let mut first_word_on_line = true; + + // Skip whitespace + while let Some(word) = words.peek() { + if word.is_whitespace { + words.next().unwrap(); + } else { + break; + } + } + + while let Some(word) = words.next() { + let result = try_layout_word_internal( + layout_helper, + word, + words, + scale, + options, + pos_y_baseline, + first_word_on_line, + &line_metrics, + &mut glyphs + ); + + if let Some(metrics) = result.get_metrics() { + line_metrics = metrics.clone(); + } + + if result.end_of_line() { + break; + } + + first_word_on_line = false; + } + + FormattedTextLine { + glyphs, + baseline_vertical_position: pos_y_baseline, + width: line_metrics.x_pos, + height: line_metrics.height(), + ascent: line_metrics.max_ascent, + descent: line_metrics.min_descent, + line_gap: line_metrics.max_line_gap + } +} + +fn layout_multiple_lines_internal( + layout_helper: &T, + codepoints: &[Codepoint], + scale: f32, + options: TextOptions +) -> Rc +{ + let scale = rusttype::Scale::uniform(scale); + + let mut iterator = WordsIterator::from(Word::split_words(codepoints)); + + let mut pos_y = 0.0; + let mut lines = Vec::new(); + + let mut width = 0.0; + + while iterator.has_next() { + let mut line = + layout_line_internal(layout_helper, &mut iterator, &scale, &options, pos_y); + + if let Some(max_width) = options.wrap_words_after_width { + match options.alignment { + TextAlignment::Left => {} + TextAlignment::Center => { + line.add_offset_x((max_width - line.width) / 2.0) + } + TextAlignment::Right => line.add_offset_x(max_width - line.width) + } + } + + pos_y += line.height * options.line_spacing_multiplier; + + if iterator.has_next() { + pos_y += line.line_gap * options.line_spacing_multiplier; + } + + width = crate::numeric::max(width, line.width); + + lines.push(Rc::new(line)); + } + + Rc::new(FormattedTextBlock { + lines, + width, + height: pos_y + }) +} + +/// Objects implementing this trait are able to lay out text, ready for +/// rendering. +pub trait TextLayout +{ + /// Returns the glyph corresponding to the provided codepoint. If the glyph + /// cannot be found, `None` is returned. + fn lookup_glyph_for_codepoint(&self, codepoint: char) -> Option; + + /// Lays out a block of text with the specified scale and options. The + /// result may be passed to `Graphics2D::draw_text`. + /// + /// As the string undergoes normalization before being laid out, the + /// `user_index` of each `FormattedGlyph` is undefined. To gain control + /// over the `user_index` field, consider using + /// either `layout_text_line_from_codepoints()` or + /// `layout_text_line_from_unindexed_codepoints()`. + #[inline] + #[must_use] + fn layout_text( + &self, + text: &str, + scale: f32, + options: TextOptions + ) -> Rc + where + Self: Sized + { + let codepoints: Vec = text.nfc().collect(); + self.layout_text_from_unindexed_codepoints(codepoints.as_slice(), scale, options) + } + + /// Lays out a block of text with the specified scale and options. The + /// result may be passed to `Graphics2D::draw_text`. + /// + /// The `user_index` field of each `FormattedGlyph` will be set to the + /// location of the input codepoint in `unindexed_codepoints`, starting + /// from zero. + #[inline] + #[must_use] + fn layout_text_from_unindexed_codepoints( + &self, + unindexed_codepoints: &[char], + scale: f32, + options: TextOptions + ) -> Rc + where + Self: Sized + { + self.layout_text_from_codepoints( + Codepoint::from_unindexed_codepoints(unindexed_codepoints).as_slice(), + scale, + options + ) + } + + /// Lays out a block of text with the specified scale and options. The + /// result may be passed to `Graphics2D::draw_text`. + /// + /// The `user_index` field of each `FormattedGlyph` will be set to the + /// `user_index` of the corresponding `Codepoint`. + #[must_use] + fn layout_text_from_codepoints( + &self, + codepoints: &[Codepoint], + scale: f32, + options: TextOptions + ) -> Rc + where + Self: Sized + { + layout_multiple_lines_internal(self, codepoints, scale, options) + } +} + +/// A struct representing a font. +#[repr(transparent)] +#[derive(Clone)] +pub struct Font +{ + data: Rc +} + +#[derive(Debug)] +struct FontImpl +{ + id: usize, + font: rusttype::Font<'static> +} + +impl Font +{ + /// Constructs a new font from the specified bytes. + /// + /// The font may be in TrueType or OpenType format. Support for OpenType + /// fonts may be limited. + pub fn new(bytes: &[u8]) -> Result> + { + let font = rusttype::Font::try_from_vec(bytes.to_vec()) + .ok_or_else(|| ErrorMessage::msg("Failed to load font"))?; + + Ok(Font { + data: Rc::new(FontImpl { + id: FONT_ID_GENERATOR.fetch_add(1, Ordering::SeqCst), + font + }) + }) + } + + #[inline] + fn id(&self) -> usize + { + self.data.id + } + + #[inline] + fn font(&self) -> &rusttype::Font<'static> + { + &self.data.font + } +} + +impl TextLayout for FontFamily +{ + fn lookup_glyph_for_codepoint(&self, codepoint: char) -> Option + { + for font in &*self.fonts { + if let Some(glyph) = font.lookup_glyph_for_codepoint(codepoint) { + return Some(glyph); + } + } + + None + } +} + +impl TextLayout for Font +{ + fn lookup_glyph_for_codepoint(&self, codepoint: char) -> Option + { + let glyph = self.font().glyph(codepoint); + + if glyph.id().0 == 0 { + None + } else { + Some(FontGlyph { + glyph, + font: self.clone() + }) + } + } +} + +impl PartialEq for Font +{ + #[inline] + fn eq(&self, other: &Self) -> bool + { + self.id() == other.id() + } +} + +impl Eq for Font {} + +impl Hash for Font +{ + #[inline] + fn hash(&self, state: &mut H) + { + self.id().hash(state); + } +} + +impl Debug for Font +{ + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result + { + f.debug_struct("Font").field("id", &self.id()).finish() + } +} + +/// A collection of fonts, in decreasing order of priority. When laying out +/// text, if a codepoint cannot be found in the first font in the list, the +/// subsequent fonts will also be searched. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct FontFamily +{ + fonts: Rc> +} + +impl FontFamily +{ + /// Instantiates a new font family, containing the specified fonts in + /// decreasing order of priority. + #[must_use] + pub fn new(fonts: Vec) -> Self + { + FontFamily { + fonts: Rc::new(fonts) + } + } +} + +/// The horizontal alignment of a block of text. This can be set when calling +/// `TextOptions::with_wrap_words_after_width`. +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +pub enum TextAlignment +{ + /// Align the text to the left. + Left, + /// Center the text in the maximum width. + Center, + /// Align the text to the rightmost point within the maximum width. + Right +} + +/// A series of options for specifying how text should be laid out. +pub struct TextOptions +{ + tracking: f32, + wrap_words_after_width: Option, + alignment: TextAlignment, + line_spacing_multiplier: f32 +} + +impl TextOptions +{ + /// Instantiates a new `TextOptions` with the default settings. + #[inline] + #[must_use] + pub fn new() -> Self + { + TextOptions { + tracking: 0.0, + wrap_words_after_width: None, + alignment: TextAlignment::Left, + line_spacing_multiplier: 1.0 + } + } + + /// Sets the tracking of the font. This is the amount of extra space (in + /// pixels) to put between each character. + /// + /// The default is `0.0`. + #[inline] + #[must_use] + pub fn with_tracking(mut self, tracking: f32) -> Self + { + self.tracking = tracking; + self + } + + /// Limits the width of the text block to the specified pixel value, + /// wrapping words to a new line if they exceed that limit. + /// + /// This function also sets the alignment, within the specified width. + /// + /// The default is to not wrap text. + #[inline] + #[must_use] + pub fn with_wrap_to_width( + mut self, + wrap_words_after_width_px: f32, + alignment: TextAlignment + ) -> Self + { + self.wrap_words_after_width = Some(wrap_words_after_width_px); + self.alignment = alignment; + self + } + + /// Sets the amount of space between each line of text. The gap between the + /// baseline of each line of text is multiplied by this value. + /// + /// The default is `1.0`. + #[inline] + #[must_use] + pub fn with_line_spacing_multiplier(mut self, line_spacing_multiplier: f32) -> Self + { + self.line_spacing_multiplier = line_spacing_multiplier; + self + } +} + +impl Default for TextOptions +{ + fn default() -> Self + { + Self::new() + } +} + +/// Represents a glyph which has been laid out as part of a line of text. +#[derive(Clone)] +pub struct FormattedGlyph +{ + glyph: rusttype::PositionedGlyph<'static>, + font_id: FontId, + user_index: UserGlyphIndex +} + +impl FormattedGlyph +{ + #[inline] + #[must_use] + pub(crate) fn glyph(&self) -> &rusttype::PositionedGlyph<'static> + { + &self.glyph + } + + /// The identifier of the font which was used to render this glyph. + #[inline] + #[must_use] + pub fn font_id(&self) -> FontId + { + self.font_id + } + + /// The `user_index` of the corresponding `Codepoint`. This allows you to + /// identify which input `Codepoint` corresponds to the output + /// `FormattedGlyph`. + #[inline] + #[must_use] + pub fn user_index(&self) -> UserGlyphIndex + { + self.user_index + } + + #[inline] + fn reposition_y(&mut self, y_pos: f32) + { + let existing_pos = self.glyph.position(); + self.glyph + .set_position(rusttype::point(existing_pos.x, y_pos)); + } + + #[inline] + fn add_offset_x(&mut self, offset_x: f32) + { + let existing_pos = self.glyph.position(); + self.glyph + .set_position(rusttype::point(existing_pos.x + offset_x, existing_pos.y)); + } +} + +/// Represents a block of text which has been laid out. +pub struct FormattedTextBlock +{ + lines: Vec>, + width: f32, + height: f32 +} + +impl FormattedTextBlock +{ + /// Iterate over the lines of text in this block. + #[inline] + #[must_use] + pub fn iter_lines(&self) -> Iter<'_, Rc> + { + self.lines.iter() + } + + /// The width (in pixels) of this text block. + #[inline] + #[must_use] + pub fn width(&self) -> f32 + { + self.width + } + + /// The height (in pixels) of this text block. + #[inline] + #[must_use] + pub fn height(&self) -> f32 + { + self.height + } +} + +/// Represents a line of text which has been laid out as part of a block. +pub struct FormattedTextLine +{ + glyphs: Vec, + baseline_vertical_position: f32, + width: f32, + height: f32, + ascent: f32, + descent: f32, + line_gap: f32 +} + +impl FormattedTextLine +{ + /// Iterate over the glyphs in this line. + #[inline] + #[must_use] + pub fn iter_glyphs(&self) -> Iter<'_, FormattedGlyph> + { + self.glyphs.iter() + } + + /// The width (in pixels) of this text line. + #[inline] + #[must_use] + pub fn width(&self) -> f32 + { + self.width + } + + /// The height (in pixels) of this text line. This is equal to the + /// `ascent()` minus the `descent()`. + #[inline] + #[must_use] + pub fn height(&self) -> f32 + { + self.height + } + + /// The ascent (in pixels) of this text line. This is the maximum height of + /// each glyph above the text baseline. + #[inline] + #[must_use] + pub fn ascent(&self) -> f32 + { + self.ascent + } + + /// The descent (in pixels) of this text line. This is the furthest distance + /// of each glyph below the text baseline. + /// + /// This is negative: a value of `-10.0` means the font can descend `10` + /// pixels below the baseline. + #[inline] + #[must_use] + pub fn descent(&self) -> f32 + { + self.descent + } + + /// The recommended gap to put between each line of text, as encoded by the + /// font authors. + #[inline] + #[must_use] + pub fn line_gap(&self) -> f32 + { + self.line_gap + } + + /// The vertical position of this line's baseline within the block of text. + #[inline] + #[must_use] + pub fn baseline_position(&self) -> f32 + { + self.baseline_vertical_position + } + + fn add_offset_x(&mut self, offset_x: f32) + { + for glyph in self.glyphs.iter_mut() { + glyph.add_offset_x(offset_x); + } + } +} + +impl From<&rusttype::Rect> for Rectangle +{ + #[inline] + #[must_use] + fn from(rect: &rusttype::Rect) -> Self + { + Rectangle::new( + Vector2::new(rect.min.x, rect.min.y), + Vector2::new(rect.max.x, rect.max.y) + ) + } +} + +#[cfg(test)] +mod test +{ + use super::*; + + #[test] + fn test_word_split_1() + { + let codepoints = Codepoint::from_unindexed_codepoints(&['a', 'b', ' ', 'c', 'd']); + + let words = Word::split_words(&codepoints); + + assert_eq!( + vec![ + Word { + codepoints: vec![Codepoint::new(0, 'a'), Codepoint::new(1, 'b')], + is_whitespace: false + }, + Word { + codepoints: vec![Codepoint::new(2, ' ')], + is_whitespace: true + }, + Word { + codepoints: vec![Codepoint::new(3, 'c'), Codepoint::new(4, 'd')], + is_whitespace: false + } + ], + words + ) + } + + #[test] + fn test_word_split_2() + { + let codepoints = Codepoint::from_unindexed_codepoints(&[ + 'a', 'b', '\t', ' ', '\n', 'c', 'd', ' ' + ]); + + let words = Word::split_words(&codepoints); + + assert_eq!( + vec![ + Word { + codepoints: vec![Codepoint::new(0, 'a'), Codepoint::new(1, 'b')], + is_whitespace: false + }, + Word { + codepoints: vec![ + Codepoint::new(2, '\t'), + Codepoint::new(3, ' '), + Codepoint::new(4, '\n') + ], + is_whitespace: true + }, + Word { + codepoints: vec![Codepoint::new(5, 'c'), Codepoint::new(6, 'd')], + is_whitespace: false + }, + Word { + codepoints: vec![Codepoint::new(7, ' ')], + is_whitespace: true + } + ], + words + ) + } +} diff --git a/src/font_cache.rs b/src/font_cache.rs new file mode 100644 index 0000000..bc8533a --- /dev/null +++ b/src/font_cache.rs @@ -0,0 +1,675 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::collections::hash_map::Entry; +use std::collections::{HashMap, HashSet}; +use std::convert::TryInto; +use std::fmt::{Display, Formatter}; +use std::ops::Div; +use std::rc::Rc; + +use crate::color::Color; +use crate::dimen::Vector2; +use crate::error::{BacktraceError, Context, ErrorMessage}; +use crate::font; +use crate::glwrapper::{ + GLContextManager, + GLError, + GLTexture, + GLTextureImageFormatU8, + GLTextureSmoothing +}; +use crate::numeric::RoundFloat; +use crate::renderer2d::{Renderer2DAction, Renderer2DVertex}; +use crate::shape::Rectangle; +use crate::texture_packer::{TexturePacker, TexturePackerError}; + +pub(crate) trait GlyphCacheInterface +{ + fn get_renderer2d_actions( + &self, + glyph: &font::FormattedGlyph, + position: Vector2, + color: Color, + output: &mut Vec + ); + + fn add_to_cache( + &mut self, + context: &Rc, + glyph: &font::FormattedGlyph + ); + + fn on_new_frame_start(&mut self); + + fn prepare_for_draw( + &mut self, + context: &Rc + ) -> Result<(), BacktraceError>; +} + +#[repr(transparent)] +#[derive(Debug, Hash, Eq, PartialEq, Clone)] +struct QuantizedDimension +{ + /// The number of pixels, multiplied by 10 + inner_value: i32 +} + +impl QuantizedDimension +{ + fn from_pixels(pixels: f32) -> Self + { + QuantizedDimension { + // Round to nearest + inner_value: ((10.0 * pixels) + 0.5) as i32 + } + } + + fn to_pixels(&self) -> f32 + { + (self.inner_value as f32) / 10.0 + } +} + +#[derive(Debug, Hash, Eq, PartialEq, Clone)] +struct GlyphCacheKey +{ + font_id: usize, + + /// Value between -0.5 and 0.5 + subpixel_offset: (QuantizedDimension, QuantizedDimension), + + scale: QuantizedDimension, + glyph_id: rusttype::GlyphId +} + +impl GlyphCacheKey +{ + fn from(font_id: usize, positioned_glyph: &rusttype::PositionedGlyph) -> Self + { + // Assuming scale is uniform + let scale = QuantizedDimension::from_pixels(positioned_glyph.scale().y); + + let pos = + Vector2::new(positioned_glyph.position().x, positioned_glyph.position().y); + + let subpixel_offset = ( + QuantizedDimension::from_pixels(pos.x - pos.x.round()), + QuantizedDimension::from_pixels(pos.y - pos.y.round()) + ); + + GlyphCacheKey { + font_id, + subpixel_offset, + scale, + glyph_id: positioned_glyph.id() + } + } +} + +pub(crate) struct GlyphCache +{ + last_frame: HashSet, + this_frame: HashSet, + + cache_entries: HashMap, + textures: Vec +} + +impl GlyphCacheInterface for GlyphCache +{ + #[inline] + fn get_renderer2d_actions( + &self, + glyph: &font::FormattedGlyph, + position: Vector2, + color: Color, + output: &mut Vec + ) + { + let positioned_glyph = glyph.glyph(); + + let key = GlyphCacheKey::from(glyph.font_id(), positioned_glyph); + + let entry = match self.cache_entries.get(&key) { + None => return, // This is valid for many glyphs, e.g. space + Some(entry) => entry + }; + + let texture_cache = self.textures.get(entry.texture_id.unwrap()).unwrap(); + + let texture_entry = texture_cache.entries.get(&key).unwrap(); + + let texture_size = GlyphCacheTexture::SIZE as f32; + + let texture_region = Rectangle::new( + texture_entry + .texture_area + .top_left() + .into_f32() + .div(texture_size), + texture_entry + .texture_area + .bottom_right() + .into_f32() + .div(texture_size) + ); + + let position = position + Vector2::from(positioned_glyph.position()); + + let screen_region_start = position.round().into_i32() + entry.bounding_box_offset; + + let screen_region = Rectangle::new( + screen_region_start, + screen_region_start + texture_entry.texture_area.size().into_i32() + ) + .into_f32(); + + output.push(Renderer2DAction { + texture: Some(texture_cache.texture.clone()), + vertices_clockwise: [ + Renderer2DVertex { + position: *screen_region.top_left(), + texture_coord: *texture_region.top_left(), + color, + texture_mix: 1.0, + circle_mix: 0.0 + }, + Renderer2DVertex { + position: screen_region.top_right(), + texture_coord: texture_region.top_right(), + color, + texture_mix: 1.0, + circle_mix: 0.0 + }, + Renderer2DVertex { + position: *screen_region.bottom_right(), + texture_coord: *texture_region.bottom_right(), + color, + texture_mix: 1.0, + circle_mix: 0.0 + } + ] + }); + + output.push(Renderer2DAction { + texture: Some(texture_cache.texture.clone()), + vertices_clockwise: [ + Renderer2DVertex { + position: *screen_region.bottom_right(), + texture_coord: *texture_region.bottom_right(), + color, + texture_mix: 1.0, + circle_mix: 0.0 + }, + Renderer2DVertex { + position: screen_region.bottom_left(), + texture_coord: texture_region.bottom_left(), + color, + texture_mix: 1.0, + circle_mix: 0.0 + }, + Renderer2DVertex { + position: *screen_region.top_left(), + texture_coord: *texture_region.top_left(), + color, + texture_mix: 1.0, + circle_mix: 0.0 + } + ] + }); + } + + fn add_to_cache( + &mut self, + _context: &Rc, + formatted_glyph: &font::FormattedGlyph + ) + { + let key = GlyphCacheKey::from(formatted_glyph.font_id(), formatted_glyph.glyph()); + + self.this_frame.insert(key.clone()); + + let cache_entries = &mut self.cache_entries; + + match cache_entries.entry(key.clone()) { + Entry::Occupied(_) => { + // Already in the cache, nothing to do + } + + Entry::Vacant(entry) => { + let glyph = formatted_glyph + .glyph() + .unpositioned() + .unscaled() + .clone() + .scaled(rusttype::Scale::uniform(key.scale.to_pixels())) + .positioned(rusttype::point( + key.subpixel_offset.0.to_pixels(), + key.subpixel_offset.1.to_pixels() + )); + + let bounding_box = match glyph.pixel_bounding_box() { + None => return, // This is valid for some glyphs, e.g. space + Some(bounding_box) => bounding_box + }; + + let bounding_box_size = Vector2::new( + bounding_box.width() as u32, + bounding_box.height() as u32 + ); + + if bounding_box_size.x > GlyphCacheTexture::SIZE + || bounding_box_size.y > GlyphCacheTexture::SIZE + { + log::error!( + "Glyph too big to render ({}x{}). Limit is {} px.", + bounding_box_size.x, + bounding_box_size.y, + GlyphCacheTexture::SIZE + ); + + return; + } + + let mut bitmap = BitmapRGBA::new(bounding_box_size); + + bitmap.draw_glyph(&glyph); + + entry.insert(GlyphCacheEntry { + glyph_bitmap: Rc::new(bitmap), + bounding_box_offset: Vector2::new( + bounding_box.min.x, + bounding_box.min.y + ), + texture_id: None + }); + } + } + } + + fn on_new_frame_start(&mut self) + { + self.last_frame.clear(); + std::mem::swap(&mut self.last_frame, &mut self.this_frame); + } + + fn prepare_for_draw( + &mut self, + context: &Rc + ) -> Result<(), BacktraceError> + { + if self.try_insert_pending().is_err() { + // Not enough space. Rearrange everything! + + self.textures.iter_mut().for_each(|texture| texture.clear()); + + let cache_entries = &mut self.cache_entries; + let last_frame = &self.last_frame; + let this_frame = &self.this_frame; + + cache_entries + .iter_mut() + .for_each(|(_, entry)| entry.texture_id = None); + + cache_entries + .retain(|key, _| last_frame.contains(key) || this_frame.contains(key)); + + // Sort entries by height + + let mut all_entries: Vec<_> = cache_entries.iter_mut().collect(); + + all_entries.sort_unstable_by(|(_, a), (_, b)| { + b.glyph_bitmap.size.y.cmp(&a.glyph_bitmap.size.y) + }); + + // Insert in height order + + let mut cleared_textures = Vec::new(); + std::mem::swap(&mut self.textures, &mut cleared_textures); + + cleared_textures + .iter_mut() + .for_each(|texture| texture.clear()); + + for (key, entry) in &mut all_entries { + let texture_id = GlyphCache::internal_rearrange_append_glyph( + context, + &mut self.textures, + &mut cleared_textures, + key, + &entry.glyph_bitmap + ) + .map_err(|err| { + ErrorMessage::msg_with_cause("Glyph rearrangement failed", err) + })?; + + entry.texture_id = Some(texture_id); + } + + // Delete all but one spare texture + if let Some(texture) = cleared_textures.pop() { + self.textures.push(texture); + } + } + + for texture in &self.textures { + texture + .revalidate(context) + .map_err(|err| err.context("Failed to revalidate texture"))?; + } + + Ok(()) + } +} + +impl GlyphCache +{ + pub(crate) fn new() -> Self + { + Self { + last_frame: HashSet::new(), + this_frame: HashSet::new(), + cache_entries: HashMap::new(), + textures: Vec::new() + } + } + + fn try_insert_pending(&mut self) -> Result<(), GlyphCacheTextureAppendError> + { + for (key, entry) in &mut self.cache_entries { + if entry.texture_id == None { + let texture_id = Self::try_append_to_existing_texture( + &mut self.textures, + key, + &entry.glyph_bitmap + )?; + + entry.texture_id = Some(texture_id); + } + } + + Ok(()) + } + + fn try_append_to_existing_texture( + all_textures: &mut Vec, + key: &GlyphCacheKey, + glyph_bitmap: &Rc + ) -> Result + { + let mut last_error: GlyphCacheTextureAppendError = + GlyphCacheTextureAppendError::NotEnoughSpace; + + for (i, texture) in all_textures.iter_mut().enumerate() { + match texture.try_append_glyph(key, glyph_bitmap) { + Ok(_) => return Ok(i), + Err(err) => last_error = err + } + } + + Err(last_error) + } + + fn internal_rearrange_append_glyph( + context: &Rc, + current_textures: &mut Vec, + previous_textures: &mut Vec, + key: &GlyphCacheKey, + glyph_bitmap: &Rc + ) -> Result> + { + for (i, texture) in current_textures.iter_mut().enumerate() { + if texture.try_append_glyph(&key, glyph_bitmap).is_ok() { + return Ok(i); + } + } + + if !previous_textures.is_empty() { + current_textures.push(previous_textures.pop().unwrap()); + + if current_textures + .last_mut() + .unwrap() + .try_append_glyph(&key, glyph_bitmap) + .is_ok() + { + return Ok(current_textures.len() - 1); + } + } + + log::info!( + "No more space in existing textures ({}). Creating new.", + current_textures.len() + ); + + current_textures.push(match GlyphCacheTexture::new(context) { + Ok(texture) => texture, + Err(err) => { + return Err(ErrorMessage::msg_with_cause( + "Failed to create new texture", + err + )) + } + }); + + match current_textures + .last_mut() + .unwrap() + .try_append_glyph(&key, glyph_bitmap) + { + Ok(_) => Ok(current_textures.len() - 1), + Err(err) => Err(ErrorMessage::msg_with_cause( + "Internal bug: Could not append to new texture", + err + )) + } + } +} + +struct BitmapRGBA +{ + data: Vec, + size: Vector2 +} + +impl BitmapRGBA +{ + #[inline] + fn new(size: Vector2) -> Self + { + let data = vec![255; (size.x * size.y * 4).try_into().unwrap()]; + BitmapRGBA { data, size } + } + + #[inline] + fn draw_glyph(&mut self, glyph: &rusttype::PositionedGlyph) + { + glyph.draw(|x, y, alpha| { + let start = (4 * (self.size.x * y + x)) as usize; + self.data[start + 3] = (alpha * 255.0).round() as u8; + }) + } + + #[inline] + fn draw_bitmap_at(&mut self, bitmap: &Self, position: &Vector2) + { + let src_w_px: usize = bitmap.size.x.try_into().unwrap(); + let dest_w_px: usize = self.size.x.try_into().unwrap(); + + let pos_x: usize = position.x.try_into().unwrap(); + let pos_y: usize = position.y.try_into().unwrap(); + + let line_size_bytes: usize = src_w_px * 4; + let dest_line_stride_bytes: usize = dest_w_px * 4; + + let mut src_pos_bytes: usize = 0; + let mut dest_pos_bytes: usize = pos_y * dest_line_stride_bytes + pos_x * 4; + + while src_pos_bytes < bitmap.data.len() { + assert!(bitmap.data.len() >= src_pos_bytes + line_size_bytes); + assert!(self.data.len() >= dest_pos_bytes + line_size_bytes); + + // As much as I hate to use unsafe here, this more than doubles performance + // with large glyphs in debug builds, compared to using + // clone_from_slice. + unsafe { + std::ptr::copy_nonoverlapping( + bitmap.data.as_ptr().add(src_pos_bytes), + self.data.as_mut_ptr().add(dest_pos_bytes), + line_size_bytes + ); + } + + src_pos_bytes += line_size_bytes; + dest_pos_bytes += dest_line_stride_bytes; + } + } + + fn upload_to_texture( + &self, + context: &Rc, + texture: &Rc + ) -> Result<(), BacktraceError> + { + texture.set_image_data( + context, + GLTextureImageFormatU8::RGBA, + GLTextureSmoothing::NearestNeighbour, + &self.size, + self.data.as_slice() + ) + } +} + +#[derive(Clone)] +struct GlyphCacheEntry +{ + glyph_bitmap: Rc, + bounding_box_offset: Vector2, + texture_id: Option +} + +struct GlyphTextureCacheEntry +{ + texture_area: Rectangle +} + +struct GlyphCacheTexture +{ + bitmap: BitmapRGBA, + texture: Rc, + invalidated: bool, + + packer: TexturePacker, + + entries: HashMap +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] +pub(crate) enum GlyphCacheTextureAppendError +{ + NotEnoughSpace +} + +impl Display for GlyphCacheTextureAppendError +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result + { + match self { + GlyphCacheTextureAppendError::NotEnoughSpace => { + f.write_str("Not enough space") + } + } + } +} + +impl std::error::Error for GlyphCacheTextureAppendError {} + +impl From for GlyphCacheTextureAppendError +{ + fn from(value: TexturePackerError) -> Self + { + match value { + TexturePackerError::NotEnoughSpace => { + GlyphCacheTextureAppendError::NotEnoughSpace + } + } + } +} + +impl GlyphCacheTexture +{ + const SIZE: u32 = 1024; + + fn new(context: &Rc) -> Result> + { + Ok(GlyphCacheTexture { + bitmap: BitmapRGBA::new(Vector2::new( + GlyphCacheTexture::SIZE, + GlyphCacheTexture::SIZE + )), + + texture: context + .new_texture() + .context("GPU texture creation failed")?, + + invalidated: false, + + packer: TexturePacker::new(GlyphCacheTexture::SIZE, GlyphCacheTexture::SIZE), + + entries: HashMap::new() + }) + } + + fn clear(&mut self) + { + self.invalidated = false; + + self.packer = + TexturePacker::new(GlyphCacheTexture::SIZE, GlyphCacheTexture::SIZE); + + self.entries.clear(); + } + + fn try_append_glyph( + &mut self, + key: &GlyphCacheKey, + glyph_bitmap: &Rc + ) -> Result<(), GlyphCacheTextureAppendError> + { + let texture_area = self.packer.try_allocate(glyph_bitmap.size)?; + + self.bitmap + .draw_bitmap_at(glyph_bitmap, texture_area.top_left()); + + self.entries + .insert(key.clone(), GlyphTextureCacheEntry { texture_area }); + + self.invalidated = true; + + Ok(()) + } + + fn revalidate( + &self, + context: &Rc + ) -> Result<(), BacktraceError> + { + self.bitmap.upload_to_texture(context, &self.texture) + } +} diff --git a/src/glwrapper.rs b/src/glwrapper.rs new file mode 100644 index 0000000..e538899 --- /dev/null +++ b/src/glwrapper.rs @@ -0,0 +1,1092 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::cell::RefCell; +use std::collections::HashMap; +use std::convert::TryInto; +use std::error::Error; +use std::fmt::{Debug, Display, Formatter}; +use std::hash::{Hash, Hasher}; +use std::num::TryFromIntError; +use std::rc::{Rc, Weak}; + +use gl::types::*; + +use crate::color::Color; +use crate::dimen::Vector2; +use crate::error::BacktraceError; + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +enum GLErrorCode +{ + InvalidEnum, + InvalidValue, + InvalidOperation, + InvalidFramebufferOperation, + OutOfMemory, + StackUnderflow, + StackOverflow, + Other(GLenum) +} + +impl From for GLErrorCode +{ + fn from(constant: GLenum) -> Self + { + match constant { + gl::INVALID_ENUM => GLErrorCode::InvalidEnum, + gl::INVALID_VALUE => GLErrorCode::InvalidValue, + gl::INVALID_OPERATION => GLErrorCode::InvalidOperation, + gl::INVALID_FRAMEBUFFER_OPERATION => GLErrorCode::InvalidFramebufferOperation, + gl::OUT_OF_MEMORY => GLErrorCode::OutOfMemory, + gl::STACK_UNDERFLOW => GLErrorCode::StackUnderflow, + gl::STACK_OVERFLOW => GLErrorCode::StackOverflow, + _ => GLErrorCode::Other(constant) + } + } +} + +#[derive(Debug, Clone)] +pub struct GLError +{ + description: String +} + +impl Display for GLError +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result + { + Display::fmt("GL error: ", f)?; + Display::fmt(&self.description, f) + } +} + +impl From for BacktraceError +{ + fn from(err: GLErrorCode) -> Self + { + GLError::msg(format!("Got GL error code {:?}", err)) + } +} + +impl From for BacktraceError +{ + fn from(_: TryFromIntError) -> Self + { + GLError::msg("Integer conversion failed/out of bounds") + } +} + +impl Error for GLError {} + +impl GLError +{ + fn for_zero_handle(alloc_type: GLHandleType) -> BacktraceError + { + GLError::msg(format!("GL allocation returned zero for {:?}", alloc_type)) + } + + fn msg>(description: S) -> BacktraceError + { + BacktraceError::new(GLError { + description: description.into() + }) + } +} + +fn gl_check_error_always() -> Result<(), BacktraceError> +{ + let err = unsafe { gl::GetError() }; + + if err != gl::NO_ERROR { + return Err(BacktraceError::::from(GLErrorCode::from(err))); + } + + Ok(()) +} + +fn gl_clear_and_log_old_error() +{ + if let Err(err) = gl_check_error_always() { + log::error!("Ignoring GL error from previous command: {:?}", err); + } +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] +enum GLHandleType +{ + Program, + Shader, + Buffer, + Texture +} + +struct GLHandle +{ + context: Weak>, + handle: GLuint, + handle_type: GLHandleType +} + +impl Debug for GLHandle +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result + { + f.debug_struct("GLHandle") + .field("handle", &self.handle) + .field("handle_type", &self.handle_type) + .finish() + } +} + +impl std::hash::Hash for GLHandle +{ + fn hash(&self, state: &mut H) + { + self.handle.hash(state); + self.handle_type.hash(state); + } +} + +impl PartialEq for GLHandle +{ + fn eq(&self, other: &Self) -> bool + { + match self.context.upgrade() { + None => return false, + Some(self_context) => match other.context.upgrade() { + None => return false, + Some(other_context) => { + if *self_context.borrow() != *other_context.borrow() { + return false; + } + } + } + } + + self.handle == other.handle && self.handle_type == other.handle_type + } +} + +impl Eq for GLHandle {} + +impl GLHandle +{ + fn wrap GLuint>( + context: &Rc>, + handle_type: GLHandleType, + handle_creator: F + ) -> Result> + { + match handle_type { + GLHandleType::Program => gl_clear_and_log_old_error(), + GLHandleType::Shader => gl_clear_and_log_old_error(), + GLHandleType::Buffer => {} + GLHandleType::Texture => {} + } + + let handle = handle_creator(); + + match handle_type { + GLHandleType::Program => gl_check_error_always()?, + GLHandleType::Shader => gl_check_error_always()?, + GLHandleType::Buffer => {} + GLHandleType::Texture => {} + } + + if handle == 0 { + return Err(GLError::for_zero_handle(handle_type)); + } + + Ok(GLHandle { + context: Rc::downgrade(&context), + handle, + handle_type + }) + } + + #[inline] + #[must_use] + fn is_context_still_valid(&self) -> bool + { + is_gl_context_valid_weak(&self.context) + } +} + +impl Drop for GLHandle +{ + fn drop(&mut self) + { + if !self.is_context_still_valid() { + // No need to drop, the context is gone + return; + } + + match self.handle_type { + GLHandleType::Program => { + unsafe { gl::DeleteProgram(self.handle) }; + } + + GLHandleType::Shader => { + unsafe { gl::DeleteShader(self.handle) }; + } + + GLHandleType::Buffer => { + unsafe { gl::DeleteBuffers(1, &self.handle) }; + } + + GLHandleType::Texture => { + unsafe { gl::DeleteTextures(1, &self.handle) }; + } + } + } +} + +#[derive(Debug)] +pub struct GLProgram +{ + handle: GLHandle, + attribute_handles: HashMap<&'static str, GLAttributeHandle> +} + +impl Hash for GLProgram +{ + fn hash(&self, state: &mut H) + { + self.handle.hash(state); + } +} + +impl PartialEq for GLProgram +{ + fn eq(&self, other: &Self) -> bool + { + std::ptr::eq(self, other) + } +} + +impl Eq for GLProgram {} + +impl GLProgram +{ + fn new( + context: &Rc> + ) -> Result> + { + Ok(GLProgram { + handle: GLHandle::wrap(context, GLHandleType::Program, || unsafe { + gl::CreateProgram() + })?, + attribute_handles: HashMap::new() + }) + } + + fn attach_shader(&mut self, shader: &GLShader) + -> Result<(), BacktraceError> + { + unsafe { + gl::AttachShader(self.handle.handle, shader.handle.handle); + } + + gl_check_error_always()?; + + Ok(()) + } + + fn link( + context: &Rc>, + vertex_shader: &GLShader, + fragment_shader: &GLShader, + attribute_names: impl IntoIterator + ) -> Result> + { + gl_clear_and_log_old_error(); + + let mut program = GLProgram::new(context)?; + + program.attach_shader(vertex_shader)?; + program.attach_shader(fragment_shader)?; + + unsafe { + gl::LinkProgram(program.handle.handle); + } + + gl_check_error_always()?; + + let mut link_status: GLint = 0; + + unsafe { + gl::GetProgramiv(program.handle.handle, gl::LINK_STATUS, &mut link_status); + } + + if link_status == 0 { + let msg = gl_get_program_info_log(&program)?; + return Err(GLError::msg(format!("Program linking failed: '{}'", msg))); + } + + unsafe { + gl::ValidateProgram(program.handle.handle); + } + + gl_check_error_always()?; + + { + let validate_msg = gl_get_program_info_log(&program)?; + + if !validate_msg.is_empty() { + return Err(GLError::msg(format!( + "Program validate log was not empty: '{}'", + validate_msg + ))); + } + } + + for attribute_name in attribute_names.into_iter() { + program.attribute_handles.insert( + attribute_name.as_ref(), + program.get_attribute_handle(attribute_name.as_ref())? + ); + } + + Ok(program) + } + + fn enable(&self) + { + unsafe { + gl::UseProgram(self.handle.handle); + } + + for attribute in self.attribute_handles.values() { + unsafe { + gl::EnableVertexAttribArray(attribute.handle); + } + } + } + + fn disable(&self) + { + for attribute in self.attribute_handles.values() { + unsafe { + gl::DisableVertexAttribArray(attribute.handle); + } + } + } + + pub fn get_attribute_handle( + &self, + name: &str + ) -> Result> + { + if !is_gl_context_valid_weak(&self.handle.context) { + return Err(GLError::msg("GL context no longer valid")); + } + + let name_cstr = std::ffi::CString::new(name) + .map_err(|_| GLError::msg("Attribute name contained NUL"))?; + + let handle = + unsafe { gl::GetAttribLocation(self.handle.handle, name_cstr.as_ptr()) }; + + gl_check_error_always()?; + + if handle < 0 { + return Err(GLError::msg(format!( + "Attribute handle {} is invalid", + name + ))); + } + + let handle: u32 = handle.try_into()?; + + Ok(GLAttributeHandle { handle }) + } + + pub fn get_uniform_handle( + &self, + name: &str + ) -> Result> + { + if !is_gl_context_valid_weak(&self.handle.context) { + return Err(GLError::msg("GL context no longer valid")); + } + + let name_cstr = std::ffi::CString::new(name) + .map_err(|_| GLError::msg("Uniform name contained NUL"))?; + + let handle = + unsafe { gl::GetUniformLocation(self.handle.handle, name_cstr.as_ptr()) }; + + gl_check_error_always()?; + + if handle < 0 { + return Err(GLError::msg(format!( + "Attribute handle {} is invalid", + name + ))); + } + + Ok(GLUniformHandle { handle }) + } +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub enum GLShaderType +{ + Vertex, + Fragment +} + +impl GLShaderType +{ + fn gl_constant(&self) -> GLenum + { + match self { + GLShaderType::Vertex => gl::VERTEX_SHADER, + GLShaderType::Fragment => gl::FRAGMENT_SHADER + } + } +} + +pub struct GLShader +{ + handle: GLHandle +} + +impl GLShader +{ + fn new( + context: &Rc>, + shader_type: GLShaderType + ) -> Result> + { + Ok(GLShader { + handle: GLHandle::wrap(context, GLHandleType::Shader, || unsafe { + gl::CreateShader(shader_type.gl_constant()) + })? + }) + } + + fn compile( + context: &Rc>, + shader_type: GLShaderType, + source: &str + ) -> Result> + { + gl_clear_and_log_old_error(); + + let shader = GLShader::new(context, shader_type)?; + + let source_str: *const GLchar = source.as_ptr() as *const GLchar; + let source_len: i32 = source.len().try_into()?; + + unsafe { gl::ShaderSource(shader.handle.handle, 1, &source_str, &source_len) }; + + gl_check_error_always()?; + + unsafe { gl::CompileShader(shader.handle.handle) }; + + gl_check_error_always()?; + + let mut compile_status: GLint = 0; + + unsafe { + gl::GetShaderiv( + shader.handle.handle, + gl::COMPILE_STATUS, + &mut compile_status + ); + }; + + if compile_status == 0 { + let msg = gl_call_get_info_log(|buf_capacity, out_buf_len, buf| unsafe { + gl::GetShaderInfoLog( + shader.handle.handle, + buf_capacity, + out_buf_len, + buf + ); + + gl_check_error_always()?; + Ok(()) + })?; + + return Err(GLError::msg(format!( + "Shader compilation failed: '{}'", + msg + ))); + } + + Ok(shader) + } +} + +#[derive(Debug)] +pub struct GLAttributeHandle +{ + handle: GLuint +} + +#[derive(Debug)] +pub struct GLUniformHandle +{ + handle: GLint +} + +impl GLUniformHandle +{ + pub fn set_value_float(&self, value: f32) + { + unsafe { + gl::Uniform1f(self.handle, value); + } + } + + pub fn set_value_int(&self, value: i32) + { + unsafe { + gl::Uniform1i(self.handle, value); + } + } +} + +fn gl_get_program_info_log(program: &GLProgram) + -> Result> +{ + gl_call_get_info_log(|buf_capacity, out_buf_len, buf| unsafe { + gl::GetProgramInfoLog(program.handle.handle, buf_capacity, out_buf_len, buf); + + gl_check_error_always()?; + Ok(()) + }) +} + +fn gl_call_get_info_log(callback: F) -> Result> +where + F: FnOnce(GLsizei, *mut GLsizei, *mut GLchar) -> Result<(), BacktraceError> +{ + gl_clear_and_log_old_error(); + + let log_buf_capacity: GLsizei = 16384; + let mut log_buf: Vec = vec![0; log_buf_capacity as usize]; + + let mut log_buf_length: GLsizei = -1; + + callback( + log_buf_capacity, + &mut log_buf_length, + log_buf.as_mut_ptr() as *mut GLchar + )?; + + gl_clear_and_log_old_error(); + + if log_buf_length < 0 || log_buf_length > log_buf_capacity { + return Err(GLError::msg(format!( + "GL info log failed, log had invalid length {}", + log_buf_length + ))); + } + + unsafe { log_buf.set_len(log_buf_length as usize) }; + + let msg = String::from_utf8_lossy(log_buf.as_slice()); + + Ok(String::from(msg)) +} + +pub enum GLBufferTarget +{ + Array, + #[allow(dead_code)] + ElementArray +} + +impl GLBufferTarget +{ + fn gl_constant(&self) -> GLenum + { + match self { + GLBufferTarget::Array => gl::ARRAY_BUFFER, + GLBufferTarget::ElementArray => gl::ELEMENT_ARRAY_BUFFER + } + } +} + +pub struct GLBuffer +{ + handle: GLHandle, + target: GLBufferTarget, + components_per_vertex: GLint, + attrib_index: GLAttributeHandle +} + +impl GLBuffer +{ + fn new( + context: &Rc>, + target: GLBufferTarget, + components_per_vertex: GLint, + attrib_index: GLAttributeHandle + ) -> Result> + { + gl_clear_and_log_old_error(); + + let handle = GLHandle::wrap(context, GLHandleType::Buffer, || unsafe { + let mut handle: GLuint = 0; + gl::GenBuffers(1, &mut handle); + handle + })?; + + Ok(GLBuffer { + handle, + target, + components_per_vertex, + attrib_index + }) + } + + pub fn set_data(&mut self, data: &[GLfloat]) + { + if !is_gl_context_valid_weak(&self.handle.context) { + log::warn!("Ignoring buffer set_data: invalid GL context"); + return; + } + + self.gl_bind_buffer(); + self.gl_buffer_data_dynamic_draw(data); + self.gl_set_attrib_pointer_data(); + } + + fn gl_bind_buffer(&mut self) + { + unsafe { + gl::BindBuffer(self.target.gl_constant(), self.handle.handle); + } + } + + fn gl_buffer_data_dynamic_draw(&mut self, data: &[GLfloat]) + { + unsafe { + gl::BufferData( + self.target.gl_constant(), + (data.len() * std::mem::size_of::()) + .try_into() + .unwrap(), + data.as_ptr() as *const GLvoid, + gl::DYNAMIC_DRAW + ); + } + } + + fn gl_set_attrib_pointer_data(&mut self) + { + unsafe { + gl::VertexAttribPointer( + self.attrib_index.handle, + self.components_per_vertex, + gl::FLOAT, + gl::FALSE, + 0, + std::ptr::null() + ); + } + } +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub enum GLTextureSmoothing +{ + NearestNeighbour, + Linear +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub enum GLTextureImageFormatU8 +{ + #[allow(dead_code)] + Red, + RGB, + RGBA +} + +impl GLTextureImageFormatU8 +{ + fn get_internal_format(&self) -> GLenum + { + match self { + GLTextureImageFormatU8::Red => gl::R8, + GLTextureImageFormatU8::RGB => gl::RGB8, + GLTextureImageFormatU8::RGBA => gl::RGBA8 + } + } + + fn get_format(&self) -> GLenum + { + match self { + GLTextureImageFormatU8::Red => gl::RED, + GLTextureImageFormatU8::RGB => gl::RGB, + GLTextureImageFormatU8::RGBA => gl::RGBA + } + } +} + +#[derive(Debug, Hash, PartialEq, Eq)] +pub struct GLTexture +{ + handle: GLHandle +} + +impl GLTexture +{ + fn new( + context: &Rc> + ) -> Result, BacktraceError> + { + let handle = GLHandle::wrap(context, GLHandleType::Texture, || unsafe { + let mut handle: GLuint = 0; + gl::GenTextures(1, &mut handle); + handle + })?; + + Ok(Rc::new(GLTexture { handle })) + } + + pub fn set_image_data( + self: &Rc, + context: &Rc, + format: GLTextureImageFormatU8, + smoothing: GLTextureSmoothing, + size: &Vector2, + data: &[u8] + ) -> Result<(), BacktraceError> + { + if !is_gl_context_valid_weak(&self.handle.context) { + log::warn!("Ignoring texture set_image_data: invalid GL context"); + return Ok(()); + } + + let smoothing_constant = match smoothing { + GLTextureSmoothing::NearestNeighbour => gl::NEAREST, + GLTextureSmoothing::Linear => gl::LINEAR + } as GLint; + + context.bind_texture(self); + + unsafe { + gl::BindTexture(gl::TEXTURE_2D, self.handle.handle); + gl::TexParameteri( + gl::TEXTURE_2D, + gl::TEXTURE_WRAP_S, + gl::CLAMP_TO_EDGE as GLint + ); + gl::TexParameteri( + gl::TEXTURE_2D, + gl::TEXTURE_WRAP_T, + gl::CLAMP_TO_EDGE as GLint + ); + gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, smoothing_constant); + gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, smoothing_constant); + } + + unsafe { + gl::TexImage2D( + gl::TEXTURE_2D, + 0, + format.get_internal_format().try_into()?, + size.x.try_into()?, + size.y.try_into()?, + 0, + format.get_format(), + gl::UNSIGNED_BYTE, + data.as_ptr() as *const std::os::raw::c_void + ); + } + + Ok(()) + } + + #[allow(dead_code)] + pub fn set_sub_image_data( + &self, + format: GLTextureImageFormatU8, + x: usize, + y: usize, + width: usize, + height: usize, + data: &[u8] + ) -> Result<(), BacktraceError> + { + if !is_gl_context_valid_weak(&self.handle.context) { + log::warn!("Ignoring texture set_sub_image_data: invalid GL context"); + return Ok(()); + } + + unsafe { + gl::TexSubImage2D( + gl::TEXTURE_2D, + 0, + x.try_into()?, + y.try_into()?, + width.try_into()?, + height.try_into()?, + format.get_format(), + gl::UNSIGNED_BYTE, + data.as_ptr() as *const std::os::raw::c_void + ); + } + + Ok(()) + } + + fn unbind_texture() + { + unsafe { + gl::ActiveTexture(gl::TEXTURE0); + gl::BindTexture(gl::TEXTURE_2D, 0); + } + } +} + +#[must_use] +fn is_gl_context_valid(state: &RefCell) -> bool +{ + state.borrow().is_valid +} + +#[inline] +#[must_use] +fn is_gl_context_valid_weak(state: &Weak>) -> bool +{ + match state.upgrade() { + None => false, + Some(state) => is_gl_context_valid(&state) + } +} + +#[derive(Eq)] +struct GLContextManagerState +{ + is_valid: bool, + active_texture: Option>, + active_program: Option>, + active_blend_mode: Option +} + +impl PartialEq for GLContextManagerState +{ + fn eq(&self, other: &Self) -> bool + { + std::ptr::eq(self, other) + } +} + +pub struct GLContextManager +{ + state: Rc> +} + +impl GLContextManager +{ + pub fn create() -> Result, BacktraceError> + { + let manager = Rc::new(GLContextManager { + state: Rc::new(RefCell::new(GLContextManagerState { + is_valid: true, + active_texture: None, + active_program: None, + active_blend_mode: None + })) + }); + + log::info!("GL context manager created"); + + Ok(manager) + } + + pub fn mark_invalid(&self) + { + log::info!("GL context manager is now inactive"); + self.state.borrow_mut().is_valid = false; + } + + pub fn new_buffer( + &self, + target: GLBufferTarget, + components_per_vertex: GLint, + attrib_index: GLAttributeHandle + ) -> Result> + { + if !is_gl_context_valid(&self.state) { + return Err(GLError::msg("GL context no longer valid")); + } + + GLBuffer::new(&self.state, target, components_per_vertex, attrib_index) + } + + pub fn new_shader( + &self, + shader_type: GLShaderType, + source: &str + ) -> Result> + { + if !is_gl_context_valid(&self.state) { + return Err(GLError::msg("GL context no longer valid")); + } + + GLShader::compile(&self.state, shader_type, source) + } + + pub fn new_program( + &self, + vertex_shader: &GLShader, + fragment_shader: &GLShader, + attribute_names: impl IntoIterator + ) -> Result, BacktraceError> + { + if !is_gl_context_valid(&self.state) { + return Err(GLError::msg("GL context no longer valid")); + } + + Ok(Rc::new(GLProgram::link( + &self.state, + vertex_shader, + fragment_shader, + attribute_names + )?)) + } + + pub fn new_texture(&self) -> Result, BacktraceError> + { + if !is_gl_context_valid(&self.state) { + return Err(GLError::msg("GL context no longer valid")); + } + + GLTexture::new(&self.state) + } + + pub fn bind_texture(&self, texture: &Rc) + { + if !is_gl_context_valid(&self.state) { + log::warn!("Ignoring bind_texture: invalid GL context"); + return; + } + + if self.state.borrow().active_texture.as_ref() == Some(texture) { + // Already bound + return; + } + + self.state.borrow_mut().active_texture = Some(texture.clone()); + + unsafe { + gl::ActiveTexture(gl::TEXTURE0); + gl::BindTexture(gl::TEXTURE_2D, texture.handle.handle); + } + } + + pub fn unbind_texture(&self) + { + if !is_gl_context_valid(&self.state) { + log::warn!("Ignoring unbind_texture: invalid GL context"); + return; + } + + GLTexture::unbind_texture(); + } + + pub fn use_program(&self, program: &Rc) + { + if !is_gl_context_valid(&self.state) { + log::warn!("Ignoring use_program: invalid GL context"); + return; + } + + if self.state.borrow().active_program.as_ref() == Some(program) { + // Already bound + return; + } + + if let Some(existing_program) = &self.state.borrow_mut().active_program { + existing_program.disable(); + } + + self.state.borrow_mut().active_program = Some(program.clone()); + program.enable(); + } + + fn set_blend_mode(&self, blend_mode: GLBlendEnabled) + { + if self.state.borrow().active_blend_mode == Some(blend_mode.clone()) { + return; + } + + self.state.borrow_mut().active_blend_mode = Some(blend_mode.clone()); + + match blend_mode { + GLBlendEnabled::Enabled(mode) => match mode { + GLBlendMode::OneMinusSrcAlpha => unsafe { + gl::Enable(gl::BLEND); + gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); + } + }, + + GLBlendEnabled::Disabled => unsafe { + gl::Disable(gl::BLEND); + } + } + } + + pub fn draw_triangles(&self, blend_mode: GLBlendEnabled, vertex_count: usize) + { + if !is_gl_context_valid(&self.state) { + log::warn!("Ignoring draw_triangles: invalid GL context"); + return; + } + + self.set_blend_mode(blend_mode); + + unsafe { + gl::DrawArrays(gl::TRIANGLES, 0, vertex_count.try_into().unwrap()); + } + } + + pub fn clear_screen(&self, color: Color) + { + if !is_gl_context_valid(&self.state) { + log::warn!("Ignoring clear_screen: invalid GL context"); + return; + } + + unsafe { + gl::ClearColor(color.r(), color.g(), color.b(), color.a()); + gl::Clear(gl::COLOR_BUFFER_BIT); + } + } +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub enum GLBlendMode +{ + OneMinusSrcAlpha +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub enum GLBlendEnabled +{ + Enabled(GLBlendMode), + #[allow(dead_code)] + Disabled +} diff --git a/src/image.rs b/src/image.rs new file mode 100644 index 0000000..24aff58 --- /dev/null +++ b/src/image.rs @@ -0,0 +1,72 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::rc::Rc; + +use crate::dimen::Vector2; +use crate::glwrapper::GLTexture; + +/// The data type of the pixels making up the raw image data. +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub enum ImageDataType +{ + /// Each pixel in the image is represented by three `u8` values: red, green, + /// and blue. + RGB, + + /// Each pixel in the image is represented by four `u8` values: red, green, + /// blue, and alpha. + RGBA +} + +/// Represents a handle for a loaded image. +/// +/// Note: this handle can only be used in the graphics context in which it was +/// created. +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub struct ImageHandle +{ + pub(crate) size: Vector2, + pub(crate) texture: Rc +} + +impl ImageHandle +{ + /// Returns the size of the image in pixels. + pub fn size(&self) -> &Vector2 + { + &self.size + } +} + +/// `ImageSmoothingMode` defines how images are rendered when the pixels of the +/// source image don't align perfectly with the pixels of the screen. This could +/// be because the image is a different size, or because it is rendered at a +/// position which is a non-integer number of pixels. +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub enum ImageSmoothingMode +{ + /// The pixel drawn on the screen will be the closest pixel from the source + /// image. This may cause aliasing/jagginess, so for a smoother result + /// the `Linear` mode may be more suitable. + NearestNeighbor, + + /// The pixel drawn on the screen will be the weighted average of the four + /// nearest pixels in the source image. This produces a smoother result + /// than `NearestNeighbor`, but in cases where the image is intended to + /// be pixel-aligned it may cause unnecessary blurriness. + Linear +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9e4b418 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,974 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! Hardware-accelerated drawing of shapes, images, and text, with an easy to +//! use API. +//! +//! Speedy2D aims to be: +//! +//! - The simplest Rust API for creating a window, rendering graphics/text, and +//! handling input +//! - Compatible with any device supporting OpenGL 2.0+ or OpenGL ES 2.0+ +//! - Very fast +//! +//! By default, Speedy2D contains support for setting up a window with an OpenGL +//! context. If you'd like to handle this yourself, and use Speedy2D only for +//! rendering, you can disable the `windowing` feature. +//! +//! # Getting Started +//! +//! ## Create a window +//! +//! After adding Speedy2D to your Cargo.toml dependencies, create a window as +//! follows: +//! +//! ```rust,no_run +//! use speedy2d::Window; +//! +//! let window = Window::new_centered("Title", (640, 480)).unwrap(); +//! ``` +//! +//! You may also use [Window::new_fullscreen_borderless()], +//! [Window::new_with_options()], or [Window::new_with_user_events()]. +//! +//! ## Implement the callbacks +//! +//! Create a struct implementing the `WindowHandler` trait. Override +//! whichever callbacks you're interested in, for example `on_draw()`, +//! `on_mouse_move()`, or `on_key_down()`. +//! +//! ``` +//! use speedy2d::window::{WindowHandler, WindowHelper}; +//! use speedy2d::Graphics2D; +//! +//! struct MyWindowHandler {} +//! +//! impl WindowHandler for MyWindowHandler +//! { +//! fn on_draw(&mut self, helper: &mut WindowHelper, graphics: &mut Graphics2D) +//! { +//! // Draw things here using `graphics` +//! } +//! } +//! ``` +//! +//! The full list of possible callbacks is currently as follows. See +//! [WindowHandler] for full documentation. +//! +//! It's only necessary to implement the callbacks you actually want to use. The +//! default implementation will do nothing and continue the event loop. +//! +//! ```text +//! fn on_start() +//! fn on_user_event() +//! fn on_resize() +//! fn on_scale_factor_changed() +//! fn on_draw() +//! fn on_mouse_move() +//! fn on_mouse_button_down() +//! fn on_mouse_button_up() +//! fn on_key_down() +//! fn on_key_up() +//! fn on_keyboard_char() +//! fn on_keyboard_modifiers_changed() +//! ``` +//! +//! Each callback gives you a [WindowHelper] instance, which +//! lets you perform window-related actions, like requesting that a new frame is +//! drawn using [WindowHelper::request_redraw()]. +//! +//! Note: Unless you call [WindowHelper::request_redraw()], frames will +//! only be drawn when necessary, for example when resizing the window. +//! +//! ## Render some graphics +//! +//! The [WindowHandler::on_draw()] callback gives you a [Graphics2D] +//! instance, which lets you draw shapes, text, and images. +//! +//! ``` +//! # use speedy2d::window::{WindowHandler, WindowHelper}; +//! # use speedy2d::Graphics2D; +//! # use speedy2d::color::Color; +//! # +//! # struct MyWindowHandler {} +//! # +//! # impl WindowHandler for MyWindowHandler +//! # { +//! fn on_draw(&mut self, helper: &mut WindowHelper, graphics: &mut Graphics2D) +//! { +//! graphics.clear_screen(Color::from_rgb(0.8, 0.9, 1.0)); +//! graphics.draw_circle((100.0, 100.0), 75.0, Color::BLUE); +//! +//! // Request that we draw another frame once this one has finished +//! helper.request_redraw(); +//! } +//! # } +//! ``` +//! +//! ## Start it running! +//! +//! Once you've implemented the callbacks you're interested in, start the event +//! loop running with [Window::run_loop()]: +//! +//! ```rust,no_run +//! # use speedy2d::Window; +//! # struct MyWindowHandler {} +//! # impl speedy2d::window::WindowHandler for MyWindowHandler {} +//! let window = Window::<()>::new_centered("Title", (640, 480)).unwrap(); +//! +//! window.run_loop(MyWindowHandler{}); +//! ``` +//! +//! ## Alternative: Managing the GL context yourself +//! +//! If you'd rather handle the window creation and OpenGL context management +//! yourself, simply disable Speedy2D's `windowing` feature in your `Cargo.toml` +//! file, and create a context as follows: +//! +//! ```rust,no_run +//! use speedy2d::GLRenderer; +//! +//! let mut renderer = unsafe { +//! GLRenderer::new_for_current_context((640, 480)) +//! }.unwrap(); +//! ``` +//! +//! Then, draw a frame using [GLRenderer::draw_frame()]: +//! +//! ```rust,no_run +//! # use speedy2d::GLRenderer; +//! # use speedy2d::color::Color; +//! # let mut renderer = unsafe { +//! # GLRenderer::new_for_current_context((640, 480)) +//! # }.unwrap(); +//! renderer.draw_frame(|graphics| { +//! graphics.clear_screen(Color::WHITE); +//! graphics.draw_circle((100.0, 100.0), 75.0, Color::BLUE); +//! }); +//! ``` +//! +//! # Laying out text +//! +//! To render text, a font must be created. Call [font::Font::new()] with the +//! bytes from the TTF or OTF font file. +//! +//! (note: OTF support may be limited) +//! +//! ```rust,no_run +//! use speedy2d::font::Font; +//! +//! let bytes = include_bytes!("../assets/fonts/NotoSans-Regular.ttf"); +//! let font = Font::new(bytes).unwrap(); +//! ``` +//! +//! Then, invoke `font.layout_text()` (part of the [font::TextLayout] trait) to +//! calculate the necessary line breaks and spacing. This will give you +//! a [font::FormattedTextBlock]. +//! +//! ```rust,no_run +//! # use speedy2d::font::{Font, TextOptions}; +//! # let font = Font::new(&[]).unwrap(); +//! use speedy2d::font::TextLayout; +//! +//! let block = font.layout_text("Hello World", 32.0, TextOptions::new()); +//! ``` +//! +//! Finally, call [Graphics2D::draw_text()] to draw the text block! +//! +//! ```rust,no_run +//! # use speedy2d::GLRenderer; +//! # use speedy2d::color::Color; +//! # use speedy2d::font::{Font, TextOptions, TextLayout}; +//! # let font = Font::new(&[]).unwrap(); +//! # let block = font.layout_text("Hello World", 32.0, TextOptions::new()); +//! # let mut renderer = unsafe { +//! # GLRenderer::new_for_current_context((640, 480)) +//! # }.unwrap(); +//! # renderer.draw_frame(|graphics| { +//! graphics.draw_text((100.0, 100.0), Color::BLUE, &block); +//! # }); +//! ``` +//! +//! ## Word wrap +//! +//! To wrap lines of text to a certain width, use +//! [font::TextOptions::with_wrap_to_width()]: +//! +//! ```rust,no_run +//! # use speedy2d::font::{Font, TextOptions}; +//! # let font = Font::new(&[]).unwrap(); +//! use speedy2d::font::{TextLayout, TextAlignment}; +//! +//! let block = font.layout_text( +//! "The quick brown fox jumps over the lazy dog.", +//! 32.0, +//! TextOptions::new().with_wrap_to_width(300.0, TextAlignment::Left)); +//! ``` +#![deny(warnings)] +#![deny(missing_docs)] +// Suggested fix for len_zero is unstable, see +// https://github.com/rust-lang/rust/issues/35428 +#![allow(clippy::len_zero)] + +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +use crate::color::Color; +use crate::dimen::Vector2; +use crate::error::{BacktraceError, ErrorMessage}; +use crate::font::FormattedTextBlock; +use crate::glwrapper::GLContextManager; +use crate::image::{ImageDataType, ImageHandle, ImageSmoothingMode}; +use crate::renderer2d::Renderer2D; +use crate::shape::Rectangle; +#[cfg(any(feature = "windowing", doc, doctest))] +use crate::window::{ + DrawingWindowHandler, + UserEventSender, + WindowCreationError, + WindowCreationOptions, + WindowHandler, + WindowHelper, + WindowImpl, + WindowPosition, + WindowSize +}; + +/// Types representing colors. +pub mod color; + +/// Types representing shapes. +pub mod shape; + +/// Components for loading fonts and laying out text. +pub mod font; + +/// Types representing sizes and positions. +pub mod dimen; + +/// Utilities and traits for numeric values. +pub mod numeric; + +/// Error types. +pub mod error; + +/// Types relating to images. +pub mod image; + +/// Allows for the creation and management of windows. +#[cfg(any(feature = "windowing", doc, doctest))] +pub mod window; + +mod font_cache; +mod glwrapper; +mod renderer2d; +mod texture_packer; +mod utils; + +/// An error encountered during the creation of a [GLRenderer]. +#[derive(Clone, Debug)] +pub struct GLRendererCreationError +{ + description: String +} + +impl GLRendererCreationError +{ + fn msg_with_cause(description: S, cause: Cause) -> BacktraceError + where + S: AsRef, + Cause: std::error::Error + 'static + { + BacktraceError::new_with_cause( + Self { + description: description.as_ref().to_string() + }, + cause + ) + } +} + +impl Display for GLRendererCreationError +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result + { + Display::fmt("GL renderer creation error: ", f)?; + Display::fmt(&self.description, f) + } +} + +/// A graphics renderer using an OpenGL backend. +/// +/// Note: There is no need to use this struct if you are letting Speedy2D create +/// a window for you. +pub struct GLRenderer +{ + context: Rc, + renderer: Graphics2D +} + +impl GLRenderer +{ + /// Creates a `GLRenderer` for the current OpenGL context. + /// `viewport_size_pixels` should be set to the initial viewport size, + /// however this can be changed later using [GLRenderer:: + /// set_viewport_size_pixels()]. + /// + /// Note: This function must not be called if you are letting Speedy2D + /// create a window for you. + /// + /// # Safety + /// + /// While a `GLRenderer` object is active, you must not make any changes to + /// the active GL context. Doing so may lead to undefined behavior, + /// which is why this function is marked `unsafe`. It is strongly + /// advised not to use any other OpenGL libraries in the same thread + /// as `GLRenderer` + pub unsafe fn new_for_current_context>>( + viewport_size_pixels: V + ) -> Result> + { + let viewport_size_pixels = viewport_size_pixels.into(); + + let context = GLContextManager::create().map_err(|err| { + GLRendererCreationError::msg_with_cause( + "GL context manager creation failed", + err + ) + })?; + + let renderer = Graphics2D { + renderer: Renderer2D::new(&context, viewport_size_pixels).map_err(|err| { + GLRendererCreationError::msg_with_cause("Renderer2D creation failed", err) + })? + }; + + Ok(GLRenderer { context, renderer }) + } + + /// Sets the renderer viewport to the specified pixel size, in response to a + /// change in the window size. + pub fn set_viewport_size_pixels(&mut self, viewport_size_pixels: Vector2) + { + self.renderer + .renderer + .set_viewport_size_pixels(viewport_size_pixels) + } + + /// Creates a new [ImageHandle] from the specified raw pixel data. + /// + /// The data provided in the `data` parameter must be in the format + /// specified by `data_type`. + /// + /// The returned [ImageHandle] is valid only for the current graphics + /// context. + pub fn create_image_from_raw_pixels( + &mut self, + data_type: ImageDataType, + smoothing_mode: ImageSmoothingMode, + size: Vector2, + data: &[u8] + ) -> Result> + { + self.renderer + .create_image_from_raw_pixels(data_type, smoothing_mode, size, data) + } + + /// Starts the process of drawing a frame. A `Graphics2D` object will be + /// provided to the callback. When the callback returns, the internal + /// render queue will be flushed. + /// + /// Note: if calling this method, you are responsible for swapping the + /// window context buffers if necessary. + #[inline] + pub fn draw_frame R, R>(&mut self, callback: F) -> R + { + let result = callback(&mut self.renderer); + self.renderer.renderer.flush_render_queue(); + result + } +} + +impl Drop for GLRenderer +{ + fn drop(&mut self) + { + self.context.mark_invalid(); + } +} + +/// A `Graphics2D` object allows you to draw shapes, images, and text to the +/// screen. +/// +/// An instance is provided in the [window::WindowHandler::on_draw] callback. +/// +/// If you are managing the GL context yourself, you must invoke +/// [GLRenderer::draw_frame] to obtain an instance. +pub struct Graphics2D +{ + renderer: Renderer2D +} + +impl Graphics2D +{ + /// Creates a new [ImageHandle] from the specified raw pixel data. + /// + /// The data provided in the `data` parameter must be in the format + /// specified by `data_type`. + /// + /// The returned [ImageHandle] is valid only for the current graphics + /// context. + pub fn create_image_from_raw_pixels>>( + &mut self, + data_type: ImageDataType, + smoothing_mode: ImageSmoothingMode, + size: S, + data: &[u8] + ) -> Result> + { + self.renderer.create_image_from_raw_pixels( + data_type, + smoothing_mode, + size.into(), + data + ) + } + + /// Fills the screen with the specified color. + pub fn clear_screen(&mut self, color: Color) + { + self.renderer.clear_screen(color); + } + + /// Draws the provided line of text at the specified position. + /// + /// Lines of text can be prepared by loading a font (using + /// [crate::font::Font::new]), and calling `layout_text_line()` on that + /// font with your desired text. + /// + /// To fall back to another font if a glyph isn't found, see + /// [crate::font::FontFamily]. + /// + /// To achieve good performance, it's possible to layout a line of text + /// once, and then re-use the same [crate::font::FormattedTextLine] + /// object whenever you need to draw that text to the screen. + /// + /// Note: Text will be rendered with subpixel precision. If the subpixel + /// position changes between frames, performance may be degraded, as the + /// text will need to be re-rendered and re-uploaded. To avoid this, + /// call `round()` on the position coordinates, to ensure that + /// the text is always located at an integer pixel position. + pub fn draw_text>>( + &mut self, + position: V, + color: Color, + text: &Rc + ) + { + self.renderer.draw_text(position, color, text); + } + + /// Draws a triangle with the specified colors (one color for each corner). + /// + /// The vertex positions (and associated colors) must be provided in + /// clockwise order. + pub fn draw_triangle_three_color( + &mut self, + vertex_positions_clockwise: [Vector2; 3], + vertex_colors_clockwise: [Color; 3] + ) + { + self.renderer.draw_triangle_three_color( + vertex_positions_clockwise, + vertex_colors_clockwise + ); + } + + /// Draws part of an image, tinted with the provided colors, at the + /// specified location. The sub-image will be scaled to fill the + /// triangle described by the vertices in `vertex_positions_clockwise`. + /// + /// The coordinates in `image_coords_normalized` should be in the range + /// `0.0` to `1.0`, and define the portion of the source image which + /// should be drawn. + /// + /// The tinting is performed by for each pixel by multiplying each color + /// component in the image pixel by the corresponding color component in + /// the `color` parameter. + /// + /// The vertex positions (and associated colors and image coordinates) must + /// be provided in clockwise order. + pub fn draw_triangle_image_tinted_three_color( + &mut self, + vertex_positions_clockwise: [Vector2; 3], + vertex_colors: [Color; 3], + image_coords_normalized: [Vector2; 3], + image: &ImageHandle + ) + { + self.renderer.draw_triangle_image_tinted( + vertex_positions_clockwise, + vertex_colors, + image_coords_normalized, + image + ); + } + + /// Draws a triangle with the specified color. + /// + /// The vertex positions must be provided in clockwise order. + #[inline] + pub fn draw_triangle( + &mut self, + vertex_positions_clockwise: [Vector2; 3], + color: Color + ) + { + self.draw_triangle_three_color(vertex_positions_clockwise, [color, color, color]); + } + + /// Draws a quadrilateral with the specified colors (one color for each + /// corner). + /// + /// The vertex positions (and associated colors) must be provided in + /// clockwise order. + #[inline] + pub fn draw_quad_four_color( + &mut self, + vertex_positions_clockwise: [Vector2; 4], + vertex_colors: [Color; 4] + ) + { + let vp = vertex_positions_clockwise; + let vc = vertex_colors; + + self.draw_triangle_three_color([vp[0], vp[1], vp[2]], [vc[0], vc[1], vc[2]]); + + self.draw_triangle_three_color([vp[2], vp[3], vp[0]], [vc[2], vc[3], vc[0]]); + } + + /// Draws a quadrilateral with the specified color. + /// + /// The vertex positions must be provided in clockwise order. + #[inline] + pub fn draw_quad( + &mut self, + vertex_positions_clockwise: [Vector2; 4], + color: Color + ) + { + self.draw_quad_four_color( + vertex_positions_clockwise, + [color, color, color, color] + ); + } + + /// Draws part of an image, tinted with the provided colors, at the + /// specified location. The sub-image will be scaled to fill the + /// quadrilateral described by the vertices in + /// `vertex_positions_clockwise`. + /// + /// The coordinates in `image_coords_normalized` should be in the range + /// `0.0` to `1.0`, and define the portion of the source image which + /// should be drawn. + /// + /// The tinting is performed by for each pixel by multiplying each color + /// component in the image pixel by the corresponding color component in + /// the `color` parameter. + /// + /// The vertex positions (and associated colors and image coordinates) must + /// be provided in clockwise order. + #[inline] + pub fn draw_quad_image_tinted_four_color( + &mut self, + vertex_positions_clockwise: [Vector2; 4], + vertex_colors: [Color; 4], + image_coords_normalized: [Vector2; 4], + image: &ImageHandle + ) + { + let vp = vertex_positions_clockwise; + let vc = vertex_colors; + let ic = image_coords_normalized; + + self.draw_triangle_image_tinted_three_color( + [vp[0], vp[1], vp[2]], + [vc[0], vc[1], vc[2]], + [ic[0], ic[1], ic[2]], + image + ); + + self.draw_triangle_image_tinted_three_color( + [vp[2], vp[3], vp[0]], + [vc[2], vc[3], vc[0]], + [ic[2], ic[3], ic[0]], + image + ); + } + + /// Draws part of an image, tinted with the provided color, at the specified + /// location. The sub-image will be scaled to fill the pixel coordinates + /// in the provided rectangle. + /// + /// The coordinates in `image_coords_normalized` should be in the range + /// `0.0` to `1.0`, and define the portion of the source image which + /// should be drawn. + /// + /// The tinting is performed by for each pixel by multiplying each color + /// component in the image pixel by the corresponding color component in + /// the `color` parameter. + #[inline] + pub fn draw_rectangle_image_subset_tinted( + &mut self, + rect: Rectangle, + color: Color, + image_coords_normalized: Rectangle, + image: &ImageHandle + ) + { + self.draw_quad_image_tinted_four_color( + [ + *rect.top_left(), + rect.top_right(), + *rect.bottom_right(), + rect.bottom_left() + ], + [color, color, color, color], + [ + *image_coords_normalized.top_left(), + image_coords_normalized.top_right(), + *image_coords_normalized.bottom_right(), + image_coords_normalized.bottom_left() + ], + image + ); + } + + /// Draws an image, tinted with the provided color, at the specified + /// location. The image will be scaled to fill the pixel coordinates in + /// the provided rectangle. + /// + /// The tinting is performed by for each pixel by multiplying each color + /// component in the image pixel by the corresponding color component in + /// the `color` parameter. + #[inline] + pub fn draw_rectangle_image_tinted( + &mut self, + rect: Rectangle, + color: Color, + image: &ImageHandle + ) + { + self.draw_rectangle_image_subset_tinted( + rect, + color, + Rectangle::new(Vector2::ZERO, Vector2::new(1.0, 1.0)), + image + ); + } + + /// Draws an image at the specified location. The image will be + /// scaled to fill the pixel coordinates in the provided rectangle. + #[inline] + pub fn draw_rectangle_image(&mut self, rect: Rectangle, image: &ImageHandle) + { + self.draw_rectangle_image_tinted(rect, Color::WHITE, image); + } + + /// Draws an image at the specified pixel location. The image will be + /// drawn at its original size with no scaling. + #[inline] + pub fn draw_image(&mut self, position: Vector2, image: &ImageHandle) + { + self.draw_rectangle_image( + Rectangle::new(position, position + image.size().into_f32()), + image + ); + } + + /// Draws a single-color rectangle at the specified location. The + /// coordinates of the rectangle are specified in pixels. + #[inline] + pub fn draw_rectangle(&mut self, rect: Rectangle, color: Color) + { + self.draw_quad( + [ + *rect.top_left(), + rect.top_right(), + *rect.bottom_right(), + rect.bottom_left() + ], + color + ); + } + + /// Draws a single-color line between the given points, specified in pixels. + /// + /// # Pixel alignment + /// + /// On a display with square pixels, an integer-valued coordinate is located + /// at the boundary between two pixels, rather than the center of the + /// pixel. For example: + /// + /// * `(0.0, 0.0)` = Top left of pixel + /// * `(0.5, 0.5)` = Center of pixel + /// * `(1.0, 1.0)` = Bottom right of pixel + /// + /// If drawing a line of odd-numbered thickness, it is advisable to locate + /// the start and end of the line at the centers of pixels, rather than + /// the edges. + /// + /// For example, a one-pixel-thick line between `(0.0, 10.0)` and `(100.0, + /// 10.0)` will be drawn as a rectangle with corners `(0.0, 9.5)` and + /// `(100.0, 10.5)`, meaning that the line's thickness will actually + /// span two half-pixels. Drawing the same line between `(0.0, 10.5)` + /// and `(100.0, 10.5)` will result in a pixel-aligned rectangle between + /// `(0.0, 10.0)` and `(100.0, 11.0)`. + pub fn draw_line>, VEnd: Into>>( + &mut self, + start_position: VStart, + end_position: VEnd, + thickness: f32, + color: Color + ) + { + let start_position = start_position.into(); + let end_position = end_position.into(); + + let gradient_normalized = match (end_position - start_position).normalize() { + None => return, + Some(gradient) => gradient + }; + + let gradient_thickness = gradient_normalized * (thickness / 2.0); + + let offset_anticlockwise = gradient_thickness.rotate_90_degrees_anticlockwise(); + let offset_clockwise = gradient_thickness.rotate_90_degrees_clockwise(); + + let start_anticlockwise = start_position + offset_anticlockwise; + let start_clockwise = start_position + offset_clockwise; + + let end_anticlockwise = end_position + offset_anticlockwise; + let end_clockwise = end_position + offset_clockwise; + + self.draw_quad( + [ + start_anticlockwise, + end_anticlockwise, + end_clockwise, + start_clockwise + ], + color + ); + } + + /// Draws a circle, filled with a single color, at the specified pixel + /// location. + pub fn draw_circle>>( + &mut self, + center_position: V, + radius: f32, + color: Color + ) + { + let center_position = center_position.into(); + + let top_left = center_position + Vector2::new(-radius, -radius); + let top_right = center_position + Vector2::new(radius, -radius); + let bottom_right = center_position + Vector2::new(radius, radius); + let bottom_left = center_position + Vector2::new(-radius, radius); + + self.renderer.draw_circle_section( + [top_left, top_right, bottom_right], + [color, color, color], + [ + Vector2::new(-1.0, -1.0), + Vector2::new(1.0, -1.0), + Vector2::new(1.0, 1.0) + ] + ); + + self.renderer.draw_circle_section( + [bottom_right, bottom_left, top_left], + [color, color, color], + [ + Vector2::new(1.0, 1.0), + Vector2::new(-1.0, 1.0), + Vector2::new(-1.0, -1.0) + ] + ); + } + + /// Draws a triangular subset of a circle. + /// + /// Put simply, this function will draw a triangle on the screen, textured + /// with a region of a circle. + /// + /// The circle region is specified using `vertex_circle_coords_normalized`, + /// which denotes UV coordinates relative to an infinitely-detailed + /// circle of radius `1.0`, and center `(0.0, 0.0)`. + /// + /// For example, to draw the top-right half of a circle with radius 100px: + /// + /// ```rust,no_run + /// # use speedy2d::GLRenderer; + /// # use speedy2d::dimen::Vector2; + /// # use speedy2d::color::Color; + /// # let mut renderer = unsafe {GLRenderer::new_for_current_context((0,0))}.unwrap(); + /// # renderer.draw_frame(|graphics| { + /// graphics.draw_circle_section_triangular_three_color( + /// [ + /// Vector2::new(200.0, 200.0), + /// Vector2::new(300.0, 200.0), + /// Vector2::new(300.0, 300.0)], + /// [Color::MAGENTA; 3], + /// [ + /// Vector2::new(-1.0, -1.0), + /// Vector2::new(1.0, -1.0), + /// Vector2::new(1.0, 1.0)]); + /// # }); + /// ``` + #[inline] + pub fn draw_circle_section_triangular_three_color( + &mut self, + vertex_positions_clockwise: [Vector2; 3], + vertex_colors: [Color; 3], + vertex_circle_coords_normalized: [Vector2; 3] + ) + { + self.renderer.draw_circle_section( + vertex_positions_clockwise, + vertex_colors, + vertex_circle_coords_normalized + ); + } +} + +/// Struct representing a window. +#[cfg(any(feature = "windowing", doc, doctest))] +pub struct Window +where + UserEventType: 'static +{ + window_impl: WindowImpl, + renderer: GLRenderer +} + +#[cfg(any(feature = "windowing", doc, doctest))] +impl Window<()> +{ + /// Create a new window, centered in the middle of the primary monitor. + pub fn new_centered( + title: Str, + size: Size + ) -> Result, BacktraceError> + where + Str: AsRef, + Size: Into> + { + let size = size.into(); + + Self::new_with_options( + title.as_ref(), + WindowCreationOptions::new_windowed( + WindowSize::PhysicalPixels(size), + Some(WindowPosition::Center) + ) + ) + } + + /// Create a new window, in fullscreen borderless mode on the primary + /// monitor. + pub fn new_fullscreen_borderless( + title: Str + ) -> Result, BacktraceError> + where + Str: AsRef + { + Self::new_with_options( + title.as_ref(), + WindowCreationOptions::new_fullscreen_borderless() + ) + } + + /// Create a new window with the specified options. + pub fn new_with_options( + title: &str, + options: WindowCreationOptions + ) -> Result, BacktraceError> + { + Self::new_with_user_events(title, options) + } +} + +#[cfg(any(feature = "windowing", doc, doctest))] +impl Window +{ + /// Create a new window with the specified options, with support for user + /// events. See [window::UserEventSender]. + pub fn new_with_user_events( + title: &str, + options: WindowCreationOptions + ) -> Result> + { + let window_impl = WindowImpl::new(title, options)?; + + let renderer = unsafe { + GLRenderer::new_for_current_context(window_impl.get_inner_size_pixels()) + } + .map_err(|err| { + BacktraceError::new_with_cause( + WindowCreationError::RendererCreationFailed, + err + ) + })?; + + Ok(Window { + window_impl, + renderer + }) + } + + /// Creates a [window::UserEventSender], which can be used to post custom + /// events to this event loop from another thread. + /// + /// If calling this, specify the type of the event data using + /// `Window::::new_with_user_events()`. + /// + /// See [UserEventSender::send_event], [WindowHandler::on_user_event]. + pub fn create_user_event_sender(&self) -> UserEventSender + { + self.window_impl.create_user_event_sender() + } + + /// Run the window event loop, with the specified callback handler. + /// + /// Once the event loop finishes running, the entire app will terminate, + /// even if other threads are still running. See + /// [WindowHelper::terminate_loop()]. + pub fn run_loop(self, handler: H) -> ! + where + H: WindowHandler + 'static + { + let handler = DrawingWindowHandler::new( + handler, + self.renderer, + WindowHelper::new(self.window_impl.helper().clone()) + ); + + self.window_impl.run_loop(handler); + } +} diff --git a/src/numeric.rs b/src/numeric.rs new file mode 100644 index 0000000..3955cc3 --- /dev/null +++ b/src/numeric.rs @@ -0,0 +1,128 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// A trait defined for primitives which have a zero value. +pub trait PrimitiveZero +{ + /// The number zero. + const ZERO: Self; +} + +impl PrimitiveZero for i8 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for i16 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for i32 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for i64 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for i128 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for isize +{ + const ZERO: Self = 0; +} + +impl PrimitiveZero for u8 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for u16 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for u32 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for u64 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for u128 +{ + const ZERO: Self = 0; +} +impl PrimitiveZero for usize +{ + const ZERO: Self = 0; +} + +impl PrimitiveZero for f32 +{ + const ZERO: Self = 0.0; +} +impl PrimitiveZero for f64 +{ + const ZERO: Self = 0.0; +} + +/// Types implementing this trait can be rounded to the nearest integer value. +/// In the case of vectors or other types containing multiple elements, each +/// element will be individually rounded. +pub trait RoundFloat +{ + /// Round this value to the nearest integer. In the case of vectors or other + /// types containing multiple elements, each element will be + /// individually rounded. + fn round(&self) -> Self; +} + +impl RoundFloat for f32 +{ + #[inline] + fn round(&self) -> Self + { + f32::round(*self) + } +} + +impl RoundFloat for f64 +{ + #[inline] + fn round(&self) -> Self + { + f64::round(*self) + } +} + +pub(crate) fn min(a: T, b: T) -> T +{ + if a < b { + a + } else { + b + } +} + +pub(crate) fn max(a: T, b: T) -> T +{ + if a > b { + a + } else { + b + } +} diff --git a/src/renderer2d.rs b/src/renderer2d.rs new file mode 100644 index 0000000..6424197 --- /dev/null +++ b/src/renderer2d.rs @@ -0,0 +1,708 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::rc::Rc; + +use crate::color::Color; +use crate::dimen::Vector2; +use crate::error::{BacktraceError, Context, ErrorMessage}; +use crate::font::FormattedTextBlock; +use crate::font_cache::{GlyphCache, GlyphCacheInterface}; +use crate::glwrapper::*; +use crate::image::{ImageDataType, ImageHandle, ImageSmoothingMode}; + +struct AttributeBuffers +{ + position: Vec, + color: Vec, + texture_coord: Vec, + texture_mix: Vec, + circle_mix: Vec, + + glbuf_position: GLBuffer, + glbuf_color: GLBuffer, + glbuf_texture_coord: GLBuffer, + glbuf_texture_mix: GLBuffer, + glbuf_circle_mix: GLBuffer +} + +impl AttributeBuffers +{ + pub fn new( + context: &GLContextManager, + program: &GLProgram + ) -> Result> + { + Ok(AttributeBuffers { + position: Vec::new(), + color: Vec::new(), + texture_coord: Vec::new(), + texture_mix: Vec::new(), + circle_mix: Vec::new(), + + glbuf_position: context + .new_buffer( + GLBufferTarget::Array, + 2, + program + .get_attribute_handle(Renderer2D::ATTR_NAME_POSITION) + .context("Failed to get attribute POSITION")? + ) + .context("Failed to create buffer for attribute POSITION")?, + + glbuf_color: context + .new_buffer( + GLBufferTarget::Array, + 4, + program + .get_attribute_handle(Renderer2D::ATTR_NAME_COLOR) + .context("Failed to get attribute COLOR")? + ) + .context("Failed to create buffer for attribute COLOR")?, + + glbuf_texture_coord: context + .new_buffer( + GLBufferTarget::Array, + 2, + program + .get_attribute_handle(Renderer2D::ATTR_NAME_TEXTURE_COORD) + .context("Failed to get attribute TEXTURE_COORD")? + ) + .context("Failed to create buffer for attribute TEXTURE_COORD")?, + + glbuf_texture_mix: context + .new_buffer( + GLBufferTarget::Array, + 1, + program + .get_attribute_handle(Renderer2D::ATTR_NAME_TEXTURE_MIX) + .context("Failed to get attribute TEXTURE_MIX")? + ) + .context("Failed to create buffer for attribute TEXTURE_MIX")?, + + glbuf_circle_mix: context + .new_buffer( + GLBufferTarget::Array, + 1, + program + .get_attribute_handle(Renderer2D::ATTR_NAME_CIRCLE_MIX) + .context("Failed to get attribute CIRCLE_MIX")? + ) + .context("Failed to create buffer for attribute CIRCLE_MIX")? + }) + } + + #[inline] + pub fn get_vertex_count(&self) -> usize + { + self.texture_mix.len() + } + + pub fn upload_and_clear(&mut self) + { + self.glbuf_position.set_data(&self.position); + self.glbuf_color.set_data(&self.color); + self.glbuf_texture_coord.set_data(&self.texture_coord); + self.glbuf_texture_mix.set_data(&self.texture_mix); + self.glbuf_circle_mix.set_data(&self.circle_mix); + self.clear(); + } + + pub fn clear(&mut self) + { + self.position.clear(); + self.color.clear(); + self.texture_coord.clear(); + self.texture_mix.clear(); + self.circle_mix.clear(); + } + + #[inline] + pub fn append( + &mut self, + position: &Vector2, + color: &Color, + texture_coord: &Vector2, + texture_mix: f32, + circle_mix: f32 + ) + { + AttributeBuffers::push_vec2(&mut self.position, position); + AttributeBuffers::push_color(&mut self.color, color); + AttributeBuffers::push_vec2(&mut self.texture_coord, texture_coord); + self.texture_mix.push(texture_mix); + self.circle_mix.push(circle_mix); + } + + #[inline] + fn push_vec2(dest: &mut Vec, vertices: &Vector2) + { + dest.push(vertices.x); + dest.push(vertices.y); + } + + #[inline] + fn push_color(dest: &mut Vec, color: &Color) + { + dest.push(color.r()); + dest.push(color.g()); + dest.push(color.b()); + dest.push(color.a()); + } +} + +struct Uniforms +{ + scale_x: GLUniformHandle, + scale_y: GLUniformHandle, + texture: GLUniformHandle +} + +impl Uniforms +{ + fn new(program: &Rc) -> Result> + { + Ok(Uniforms { + scale_x: program + .get_uniform_handle(Renderer2D::UNIFORM_NAME_SCALE_X) + .context("Failed to find SCALE_X uniform")?, + scale_y: program + .get_uniform_handle(Renderer2D::UNIFORM_NAME_SCALE_Y) + .context("Failed to find SCALE_Y uniform")?, + texture: program + .get_uniform_handle(Renderer2D::UNIFORM_NAME_TEXTURE) + .context("Failed to find TEXTURE uniform")? + }) + } + + fn set_viewport_size_pixels(&self, viewport_size_pixels: Vector2) + { + self.scale_x + .set_value_float(2.0 / viewport_size_pixels.x as f32); + self.scale_y + .set_value_float(-2.0 / viewport_size_pixels.y as f32); + } + + fn set_texture_unit(&self, texture_unit: i32) + { + self.texture.set_value_int(texture_unit); + } +} + +pub(crate) struct Renderer2DVertex +{ + pub position: Vector2, + pub texture_coord: Vector2, + pub color: Color, + pub texture_mix: f32, + pub circle_mix: f32 +} + +impl Renderer2DVertex +{ + #[inline] + fn append_to_attribute_buffers(&self, attribute_buffers: &mut AttributeBuffers) + { + attribute_buffers.append( + &self.position, + &self.color, + &self.texture_coord, + self.texture_mix, + self.circle_mix + ); + } +} + +pub(crate) struct Renderer2DAction +{ + pub texture: Option>, + pub vertices_clockwise: [Renderer2DVertex; 3] +} + +impl Renderer2DAction +{ + #[inline] + fn update_current_texture_if_empty( + &self, + current_texture: &mut Option> + ) -> bool + { + match &self.texture { + None => true, + + Some(own_texture) => match current_texture { + None => { + *current_texture = Some(own_texture.clone()); + true + } + Some(current_texture) => *current_texture == *own_texture + } + } + } + + #[inline] + fn append_to_attribute_buffers(&self, attribute_buffers: &mut AttributeBuffers) + { + for vertex in self.vertices_clockwise.iter() { + vertex.append_to_attribute_buffers(attribute_buffers); + } + } +} + +enum RenderQueueItem +{ + FormattedTextBlock + { + position: Vector2, + color: Color, + block: Rc + }, + + CircleSectionColored + { + vertex_positions_clockwise: [Vector2; 3], + vertex_colors_clockwise: [Color; 3], + vertex_normalized_circle_coords_clockwise: [Vector2; 3] + }, + + TriangleColored + { + vertex_positions_clockwise: [Vector2; 3], + vertex_colors_clockwise: [Color; 3] + }, + + TriangleTextured + { + vertex_positions_clockwise: [Vector2; 3], + vertex_colors_clockwise: [Color; 3], + vertex_texture_coords_clockwise: [Vector2; 3], + texture: Rc + } +} + +impl RenderQueueItem +{ + #[inline] + fn generate_actions( + &self, + output: &mut Vec, + glyph_cache: &T + ) + { + match self { + RenderQueueItem::FormattedTextBlock { + position, + color, + block + } => { + for line in block.iter_lines() { + for glyph in line.iter_glyphs() { + glyph_cache + .get_renderer2d_actions(glyph, *position, *color, output); + } + } + } + + RenderQueueItem::CircleSectionColored { + vertex_positions_clockwise, + vertex_colors_clockwise, + vertex_normalized_circle_coords_clockwise + } => output.push(Renderer2DAction { + texture: None, + vertices_clockwise: [ + Renderer2DVertex { + position: vertex_positions_clockwise[0], + texture_coord: vertex_normalized_circle_coords_clockwise[0], + color: vertex_colors_clockwise[0], + texture_mix: 0.0, + circle_mix: 1.0 + }, + Renderer2DVertex { + position: vertex_positions_clockwise[1], + texture_coord: vertex_normalized_circle_coords_clockwise[1], + color: vertex_colors_clockwise[1], + texture_mix: 0.0, + circle_mix: 1.0 + }, + Renderer2DVertex { + position: vertex_positions_clockwise[2], + texture_coord: vertex_normalized_circle_coords_clockwise[2], + color: vertex_colors_clockwise[2], + texture_mix: 0.0, + circle_mix: 1.0 + } + ] + }), + + RenderQueueItem::TriangleColored { + vertex_positions_clockwise, + vertex_colors_clockwise + } => output.push(Renderer2DAction { + texture: None, + vertices_clockwise: [ + Renderer2DVertex { + position: vertex_positions_clockwise[0], + texture_coord: Vector2::ZERO, + color: vertex_colors_clockwise[0], + texture_mix: 0.0, + circle_mix: 0.0 + }, + Renderer2DVertex { + position: vertex_positions_clockwise[1], + texture_coord: Vector2::ZERO, + color: vertex_colors_clockwise[1], + texture_mix: 0.0, + circle_mix: 0.0 + }, + Renderer2DVertex { + position: vertex_positions_clockwise[2], + texture_coord: Vector2::ZERO, + color: vertex_colors_clockwise[2], + texture_mix: 0.0, + circle_mix: 0.0 + } + ] + }), + + RenderQueueItem::TriangleTextured { + vertex_positions_clockwise, + vertex_colors_clockwise, + vertex_texture_coords_clockwise, + texture + } => output.push(Renderer2DAction { + texture: Some(texture.clone()), + vertices_clockwise: [ + Renderer2DVertex { + position: vertex_positions_clockwise[0], + texture_coord: vertex_texture_coords_clockwise[0], + color: vertex_colors_clockwise[0], + texture_mix: 1.0, + circle_mix: 0.0 + }, + Renderer2DVertex { + position: vertex_positions_clockwise[1], + texture_coord: vertex_texture_coords_clockwise[1], + color: vertex_colors_clockwise[1], + texture_mix: 1.0, + circle_mix: 0.0 + }, + Renderer2DVertex { + position: vertex_positions_clockwise[2], + texture_coord: vertex_texture_coords_clockwise[2], + color: vertex_colors_clockwise[2], + texture_mix: 1.0, + circle_mix: 0.0 + } + ] + }) + } + } +} + +pub struct Renderer2D +{ + context: Rc, + + program: Rc, + + render_queue: Vec, + render_action_queue: Vec, + + glyph_cache: crate::font_cache::GlyphCache, + attribute_buffers: AttributeBuffers, + current_texture: Option>, + + #[allow(dead_code)] + uniforms: Uniforms +} + +impl Renderer2D +{ + const ATTR_NAME_POSITION: &'static str = "in_Position"; + const ATTR_NAME_COLOR: &'static str = "in_Color"; + const ATTR_NAME_TEXTURE_COORD: &'static str = "in_TextureCoord"; + const ATTR_NAME_TEXTURE_MIX: &'static str = "in_TextureMix"; + const ATTR_NAME_CIRCLE_MIX: &'static str = "in_CircleMix"; + + const UNIFORM_NAME_SCALE_X: &'static str = "in_ScaleX"; + const UNIFORM_NAME_SCALE_Y: &'static str = "in_ScaleY"; + const UNIFORM_NAME_TEXTURE: &'static str = "in_Texture"; + + const ALL_ATTRIBUTES: [&'static str; 5] = [ + Renderer2D::ATTR_NAME_POSITION, + Renderer2D::ATTR_NAME_COLOR, + Renderer2D::ATTR_NAME_TEXTURE_COORD, + Renderer2D::ATTR_NAME_TEXTURE_MIX, + Renderer2D::ATTR_NAME_CIRCLE_MIX + ]; + + pub fn new( + context: &Rc, + viewport_size_pixels: Vector2 + ) -> Result> + { + let vertex_shader = context + .new_shader( + GLShaderType::Vertex, + include_str!("shaders/r2d_vertex.glsl") + ) + .context("Failed to create Renderer2D vertex shader")?; + + let fragment_shader = context + .new_shader( + GLShaderType::Fragment, + include_str!("shaders/r2d_fragment.glsl") + ) + .context("Failed to create Renderer2D fragment shader")?; + + let program = context + .new_program( + &vertex_shader, + &fragment_shader, + &Renderer2D::ALL_ATTRIBUTES + ) + .context("Failed to create Renderer2D program")?; + + let attribute_buffers = AttributeBuffers::new(context, &program)?; + let uniforms = Uniforms::new(&program)?; + + context.use_program(&program); + + uniforms.set_texture_unit(0); + + uniforms.set_viewport_size_pixels(viewport_size_pixels); + + Ok(Renderer2D { + context: context.clone(), + program, + render_queue: Vec::new(), + render_action_queue: Vec::new(), + glyph_cache: GlyphCache::new(), + attribute_buffers, + current_texture: None, + uniforms + }) + } + + pub fn set_viewport_size_pixels(&self, viewport_size_pixels: Vector2) + { + self.uniforms.set_viewport_size_pixels(viewport_size_pixels); + } + + pub fn flush_render_queue(&mut self) + { + if self.render_queue.is_empty() { + return; + } + + self.render_action_queue.clear(); + self.attribute_buffers.clear(); + + let mut has_text = false; + + for item in &self.render_queue { + if let RenderQueueItem::FormattedTextBlock { block, .. } = item { + for line in block.iter_lines() { + for glyph in line.iter_glyphs() { + self.glyph_cache.add_to_cache(&self.context, glyph); + } + } + + has_text = true; + } + } + + if has_text { + if let Err(err) = self.glyph_cache.prepare_for_draw(&self.context) { + log::error!("Error updating font texture, continuing anyway: {:?}", err); + } + } + + for item in &self.render_queue { + item.generate_actions(&mut self.render_action_queue, &self.glyph_cache); + } + + self.render_queue.clear(); + + for action in &self.render_action_queue { + if !action.update_current_texture_if_empty(&mut self.current_texture) { + Renderer2D::draw_buffers( + &self.context, + &self.program, + &mut self.attribute_buffers, + &mut self.current_texture + ); + + self.current_texture = action.texture.clone(); + } + + action.append_to_attribute_buffers(&mut self.attribute_buffers); + } + + self.render_action_queue.clear(); + + Renderer2D::draw_buffers( + &self.context, + &self.program, + &mut self.attribute_buffers, + &mut self.current_texture + ); + } + + fn draw_buffers( + context: &GLContextManager, + program: &Rc, + attribute_buffers: &mut AttributeBuffers, + current_texture: &mut Option> + ) + { + let vertex_count = attribute_buffers.get_vertex_count(); + + if vertex_count == 0 { + return; + } + + context.use_program(program); + + attribute_buffers.upload_and_clear(); + + let current_texture = current_texture.take(); + + match ¤t_texture { + None => context.unbind_texture(), + Some(texture) => context.bind_texture(texture) + } + + context.draw_triangles( + GLBlendEnabled::Enabled(GLBlendMode::OneMinusSrcAlpha), + vertex_count + ); + } + + pub(crate) fn create_image_from_raw_pixels>>( + &self, + data_type: ImageDataType, + smoothing_mode: ImageSmoothingMode, + size: S, + data: &[u8] + ) -> Result> + { + let size = size.into(); + + let gl_format = match data_type { + ImageDataType::RGB => GLTextureImageFormatU8::RGB, + ImageDataType::RGBA => GLTextureImageFormatU8::RGBA + }; + + let gl_smoothing = match smoothing_mode { + ImageSmoothingMode::NearestNeighbor => GLTextureSmoothing::NearestNeighbour, + ImageSmoothingMode::Linear => GLTextureSmoothing::Linear + }; + + let texture = self + .context + .new_texture() + .context("Failed to create GPU texture")?; + + texture + .set_image_data(&self.context, gl_format, gl_smoothing, &size, data) + .context("Failed to upload image data")?; + + Ok(ImageHandle { size, texture }) + } + + #[inline] + pub(crate) fn clear_screen(&mut self, color: Color) + { + if color.a() < 1.0 { + self.flush_render_queue(); + } else { + self.render_queue.clear(); + } + + self.context.clear_screen(color); + } + + #[inline] + fn add_to_render_queue(&mut self, item: RenderQueueItem) + { + self.render_queue.push(item); + + if self.render_queue.len() > 100000 { + self.flush_render_queue(); + } + } + + #[inline] + pub(crate) fn draw_triangle_three_color( + &mut self, + vertex_positions_clockwise: [Vector2; 3], + vertex_colors_clockwise: [Color; 3] + ) + { + self.add_to_render_queue(RenderQueueItem::TriangleColored { + vertex_positions_clockwise, + vertex_colors_clockwise + }) + } + + #[inline] + pub(crate) fn draw_triangle_image_tinted( + &mut self, + vertex_positions_clockwise: [Vector2; 3], + vertex_colors_clockwise: [Color; 3], + vertex_texture_coords_clockwise: [Vector2; 3], + image: &ImageHandle + ) + { + self.add_to_render_queue(RenderQueueItem::TriangleTextured { + vertex_positions_clockwise, + vertex_colors_clockwise, + vertex_texture_coords_clockwise, + texture: image.texture.clone() + }) + } + + #[inline] + pub(crate) fn draw_text>>( + &mut self, + position: V, + color: Color, + text: &Rc + ) + { + self.add_to_render_queue(RenderQueueItem::FormattedTextBlock { + position: position.into(), + color, + block: text.clone() + }) + } + + #[inline] + pub(crate) fn draw_circle_section( + &mut self, + vertex_positions_clockwise: [Vector2; 3], + vertex_colors_clockwise: [Color; 3], + vertex_normalized_circle_coords_clockwise: [Vector2; 3] + ) + { + self.add_to_render_queue(RenderQueueItem::CircleSectionColored { + vertex_positions_clockwise, + vertex_colors_clockwise, + vertex_normalized_circle_coords_clockwise + }) + } +} diff --git a/src/shaders/r2d_fragment.glsl b/src/shaders/r2d_fragment.glsl new file mode 100644 index 0000000..4603b21 --- /dev/null +++ b/src/shaders/r2d_fragment.glsl @@ -0,0 +1,39 @@ +#version 110 + +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +uniform sampler2D in_Texture; + +varying vec4 pass_Color; +varying vec2 pass_TextureCoord; +varying float pass_TextureMix; +varying float pass_CircleMix; + +void main(void) { + + vec4 texCol = texture2D(in_Texture, pass_TextureCoord); + + float texCoordMagSquared = pass_TextureCoord.x * pass_TextureCoord.x + + pass_TextureCoord.y * pass_TextureCoord.y; + + float circleAlpha = 1.0 - step(1.0, texCoordMagSquared); + + gl_FragColor = pass_Color * ( + vec4(1.0 - pass_TextureMix - pass_CircleMix) + + (texCol * pass_TextureMix) + + (vec4(vec3(1.0), circleAlpha)) * pass_CircleMix); +} \ No newline at end of file diff --git a/src/shaders/r2d_vertex.glsl b/src/shaders/r2d_vertex.glsl new file mode 100644 index 0000000..330c827 --- /dev/null +++ b/src/shaders/r2d_vertex.glsl @@ -0,0 +1,45 @@ +#version 110 + +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +attribute vec2 in_Position; +attribute vec4 in_Color; +attribute vec2 in_TextureCoord; +attribute float in_TextureMix; +attribute float in_CircleMix; + +uniform float in_ScaleX; +uniform float in_ScaleY; + +varying vec4 pass_Color; +varying vec2 pass_TextureCoord; +varying float pass_TextureMix; +varying float pass_CircleMix; + +void main(void) { + + gl_Position = vec4( + in_Position.x * in_ScaleX - 1.0, + in_Position.y * in_ScaleY + 1.0, + 0.0, + 1.0); + + pass_Color = in_Color; + pass_TextureCoord = in_TextureCoord; + pass_TextureMix = in_TextureMix; + pass_CircleMix = in_CircleMix; +} \ No newline at end of file diff --git a/src/shape.rs b/src/shape.rs new file mode 100644 index 0000000..0848b75 --- /dev/null +++ b/src/shape.rs @@ -0,0 +1,153 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use rusttype::Rect; + +use crate::dimen::Vector2; + +/// A struct representing an axis-aligned rectangle. Two points are stored: the +/// top left vertex, and the bottom right vertex. +#[derive(Debug, PartialEq, Clone)] +#[repr(C)] +pub struct Rectangle +{ + top_left: Vector2, + bottom_right: Vector2 +} + +impl Rectangle +{ + /// Constructs a new `Rectangle`. The top left vertex must be above and to + /// the left of the bottom right vertex. + #[inline] + pub const fn new(top_left: Vector2, bottom_right: Vector2) -> Self + { + Rectangle { + top_left, + bottom_right + } + } + + /// Constructs a new `Rectangle`. The top left vertex must be above and to + /// the left of the bottom right vertex. + #[inline] + pub fn from_tuples(top_left: (T, T), bottom_right: (T, T)) -> Self + { + Rectangle { + top_left: Vector2::new(top_left.0, top_left.1), + bottom_right: Vector2::new(bottom_right.0, bottom_right.1) + } + } + + /// Returns a reference to the top left vertex. + #[inline] + pub const fn top_left(&self) -> &Vector2 + { + &self.top_left + } + + /// Returns a reference to the bottom right vertex. + #[inline] + pub const fn bottom_right(&self) -> &Vector2 + { + &self.bottom_right + } +} + +impl Rectangle +{ + /// Returns a vector representing the top right vertex. + #[inline] + pub fn top_right(&self) -> Vector2 + { + Vector2::new(self.bottom_right.x, self.top_left.y) + } + + /// Returns a vector representing the bottom left vertex. + #[inline] + pub fn bottom_left(&self) -> Vector2 + { + Vector2::new(self.top_left.x, self.bottom_right.y) + } +} + +impl + Copy> Rectangle +{ + /// Returns the width of the rectangle. + #[inline] + pub fn width(&self) -> T + { + self.bottom_right.x - self.top_left.x + } + + /// Returns the height of the rectangle. + #[inline] + pub fn height(&self) -> T + { + self.bottom_right.y - self.top_left.y + } + + /// Returns a `Vector2` containing the width and height of the rectangle. + #[inline] + pub fn size(&self) -> Vector2 + { + Vector2::new(self.width(), self.height()) + } +} + +impl Rectangle +{ + /// Returns `true` if the rectangle has zero area. + #[inline] + pub fn is_zero_area(&self) -> bool + { + self.top_left.x == self.bottom_right.x || self.top_left.y == self.bottom_right.y + } +} + +impl Rectangle +where + Vector2: std::ops::Add> +{ + /// Returns a new rectangle, whose vertices are offset relative to the + /// current rectangle by the specified amount. This is equivalent to + /// adding the specified vector to each vertex. + #[inline] + pub fn with_offset(&self, offset: Vector2) -> Self + { + Rectangle::new(self.top_left + offset, self.bottom_right + offset) + } +} + +impl From> for Rectangle +{ + fn from(rect: Rect) -> Self + { + Rectangle::new(Vector2::from(rect.min), Vector2::from(rect.max)) + } +} + +impl> Rectangle +{ + /// Returns a new rectangle where the coordinates have been cast to `f32` + /// values, using the `as` operator. + #[inline] + #[must_use] + pub fn into_f32(self) -> Rectangle + { + Rectangle::new(self.top_left.into_f32(), self.bottom_right.into_f32()) + } +} diff --git a/src/texture_packer.rs b/src/texture_packer.rs new file mode 100644 index 0000000..3cc25b5 --- /dev/null +++ b/src/texture_packer.rs @@ -0,0 +1,224 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::dimen::Vector2; +use crate::shape::Rectangle; +use crate::texture_packer::TexturePackerError::NotEnoughSpace; + +#[derive(Debug)] +struct FreeRegion +{ + rect: Rectangle +} + +impl FreeRegion +{ + #[inline] + fn from_rectangle(rect: Rectangle) -> Self + { + FreeRegion { rect } + } + + #[inline] + fn new(width: u32, height: u32) -> Self + { + FreeRegion::from_rectangle(Rectangle::new( + Vector2::ZERO, + Vector2::new(width, height) + )) + } +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] +pub(crate) enum TexturePackerError +{ + NotEnoughSpace +} + +#[derive(Debug)] +pub(crate) struct TexturePacker +{ + areas: Vec +} + +impl TexturePacker +{ + pub(crate) fn new(width: u32, height: u32) -> Self + { + let mut areas = Vec::new(); + areas.push(FreeRegion::new(width, height)); + + TexturePacker { areas } + } + + pub(crate) fn try_allocate( + &mut self, + size: Vector2 + ) -> Result, TexturePackerError> + { + if size.x == 0 || size.y == 0 { + return Ok(Rectangle::new(Vector2::ZERO, size)); + } + + let width = size.x; + let height = size.y; + + let mut best_area: Option<&mut FreeRegion> = None; + + for area in &mut self.areas { + let area_width = area.rect.width(); + let area_height = area.rect.height(); + + if width > area.rect.width() || height > area.rect.height() { + continue; + } + + let update_best = if let Some(current_best) = &best_area { + current_best.rect.width() >= area_width + && current_best.rect.height() >= area_height + } else { + true + }; + + if update_best { + best_area = Some(area); + } + } + + let best_area = best_area.ok_or(NotEnoughSpace)?; + + let result = + Rectangle::new(*best_area.rect.top_left(), best_area.rect.top_left() + size); + + let space_underneath = Rectangle::new( + Vector2::new(best_area.rect.top_left().x, result.bottom_right().y), + *best_area.rect.bottom_right() + ); + + let space_right = Rectangle::new( + Vector2::new(result.bottom_right().x, best_area.rect.top_left().y), + space_underneath.top_right() + ); + + if space_right.is_zero_area() { + best_area.rect = space_underneath + } else { + best_area.rect = space_right; + + if !space_underneath.is_zero_area() { + self.areas + .push(FreeRegion::from_rectangle(space_underneath)); + } + } + + Ok(result) + } +} + +#[cfg(test)] +mod test +{ + + use super::*; + + #[test] + fn pack_test_fill_four_squares() + { + let mut packer = TexturePacker::new(64, 64); + + assert_eq!( + Ok(Rectangle::from_tuples((0, 0), (32, 32))), + packer.try_allocate(Vector2::new(32, 32)) + ); + + assert_eq!( + Ok(Rectangle::from_tuples((32, 0), (64, 32))), + packer.try_allocate(Vector2::new(32, 32)) + ); + + assert_eq!( + Ok(Rectangle::from_tuples((0, 32), (32, 64))), + packer.try_allocate(Vector2::new(32, 32)) + ); + + assert_eq!( + Ok(Rectangle::from_tuples((32, 32), (64, 64))), + packer.try_allocate(Vector2::new(32, 32)) + ); + + assert_eq!( + Err(NotEnoughSpace), + packer.try_allocate(Vector2::new(32, 32)) + ); + } + + #[test] + fn pack_test_nonfill_four_squares() + { + let mut packer = TexturePacker::new(64, 64); + + assert_eq!( + Ok(Rectangle::from_tuples((0, 0), (30, 30))), + packer.try_allocate(Vector2::new(30, 30)) + ); + + assert_eq!( + Ok(Rectangle::from_tuples((30, 0), (60, 30))), + packer.try_allocate(Vector2::new(30, 30)) + ); + + assert_eq!( + Ok(Rectangle::from_tuples((0, 30), (30, 60))), + packer.try_allocate(Vector2::new(30, 30)) + ); + + assert_eq!( + Ok(Rectangle::from_tuples((30, 30), (60, 60))), + packer.try_allocate(Vector2::new(30, 30)) + ); + + assert_eq!( + Err(NotEnoughSpace), + packer.try_allocate(Vector2::new(30, 30)) + ); + } + + #[test] + fn pack_test_uneven_squares() + { + let mut packer = TexturePacker::new(64, 64); + + assert_eq!( + Ok(Rectangle::from_tuples((0, 0), (16, 16))), + packer.try_allocate(Vector2::new(16, 16)) + ); + + assert_eq!( + Ok(Rectangle::from_tuples((0, 16), (16, 48))), + packer.try_allocate(Vector2::new(16, 32)) + ); + + assert_eq!( + Ok(Rectangle::from_tuples((16, 16), (48, 48))), + packer.try_allocate(Vector2::new(32, 32)) + ); + + assert_eq!( + Ok(Rectangle::from_tuples((16, 0), (32, 16))), + packer.try_allocate(Vector2::new(16, 16)) + ); + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..27e25a3 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,49 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::time::Instant; + +pub(crate) struct BenchmarkTimer +{ + name: String, + start_time: Instant +} + +impl BenchmarkTimer +{ + #[allow(dead_code)] + pub(crate) fn start>(name: S) -> Self + { + log::info!("[Benchmark] [START] {}", name.as_ref()); + + BenchmarkTimer { + name: name.as_ref().to_string(), + start_time: Instant::now() + } + } +} + +impl Drop for BenchmarkTimer +{ + fn drop(&mut self) + { + log::info!( + "[Benchmark] [END] {} (took {:.3} ms)", + self.name, + self.start_time.elapsed().as_secs_f64() * 1000.0 + ); + } +} diff --git a/src/window.rs b/src/window.rs new file mode 100644 index 0000000..5e09a2d --- /dev/null +++ b/src/window.rs @@ -0,0 +1,1774 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::ffi::CStr; +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +use gl::types::*; +use glutin::dpi::{LogicalSize, PhysicalPosition, PhysicalSize}; +use glutin::event::{ + ElementState as GlutinElementState, + Event as GlutinEvent, + VirtualKeyCode as GlutinVirtualKeyCode, + WindowEvent as GlutinWindowEvent +}; +use glutin::event_loop::{ControlFlow, EventLoop, EventLoopClosed, EventLoopProxy}; +use glutin::monitor::MonitorHandle; +use glutin::window::{ + Icon, + Window as GlutinWindow, + WindowBuilder as GlutinWindowBuilder +}; + +use crate::dimen::Vector2; +use crate::error::{BacktraceError, ErrorMessage}; +use crate::{GLRenderer, Graphics2D}; + +/// Error occuring when sending a user event. +#[derive(Clone, Debug, Hash, Eq, PartialEq, Copy)] +pub enum EventLoopSendError +{ + /// Send failed as the event loop no longer exists. + EventLoopNoLongerExists +} + +/// Allows user events to be sent to the event loop from other threads. +#[derive(Clone)] +pub struct UserEventSender +{ + event_proxy: EventLoopProxy +} + +impl UserEventSender +{ + /// Sends a user-defined event to the event loop. This will cause + /// [WindowHandler::on_user_event] to be invoked on the event loop + /// thread. + /// + /// This may be invoked from a different thread to the one running the event + /// loop. + pub fn send_event(&self, event: UserEventType) -> Result<(), EventLoopSendError> + { + self.event_proxy.send_event(event).map_err(|err| match err { + EventLoopClosed(_) => EventLoopSendError::EventLoopNoLongerExists + }) + } +} + +pub(crate) struct WindowImplHelper +{ + window_context: Rc>, + event_proxy: EventLoopProxy +} + +impl Clone for WindowImplHelper +{ + fn clone(&self) -> Self + { + Self { + window_context: self.window_context.clone(), + event_proxy: self.event_proxy.clone() + } + } +} + +impl WindowImplHelper +{ + #[inline] + fn new( + context: &Rc>, + event_proxy: EventLoopProxy + ) -> Self + { + WindowImplHelper { + window_context: context.clone(), + event_proxy + } + } + + pub fn set_icon_from_rgba_pixels( + &self, + data: Vec, + size: Vector2 + ) -> Result<(), BacktraceError> + { + self.window_context.window().set_window_icon(Some( + Icon::from_rgba(data, size.x, size.y).map_err(|err| { + ErrorMessage::msg_with_cause("Icon data was invalid", err) + })? + )); + + Ok(()) + } + + pub fn set_cursor_visible(&self, visible: bool) + { + self.window_context.window().set_cursor_visible(visible); + } + + pub fn set_cursor_grab( + &self, + grabbed: bool + ) -> Result<(), BacktraceError> + { + self.window_context + .window() + .set_cursor_grab(grabbed) + .map_err(|err| ErrorMessage::msg_with_cause("Could not grab cursor", err)) + } + + pub fn set_resizable(&self, resizable: bool) + { + self.window_context.window().set_resizable(resizable); + } + + #[inline] + pub fn request_redraw(&self) + { + self.window_context.window().request_redraw(); + } + + pub fn set_title(&self, title: &str) + { + self.window_context.window().set_title(title); + } + + pub fn set_fullscreen_mode(&self, mode: WindowFullscreenMode) + { + let window = self.window_context.window(); + + window.set_fullscreen(match mode { + WindowFullscreenMode::Windowed => None, + WindowFullscreenMode::FullscreenBorderless => { + Some(glutin::window::Fullscreen::Borderless(None)) + } + }); + } + + pub fn set_size_pixels>>(&self, size: S) + { + let size = size.into(); + + self.window_context + .window() + .set_inner_size(glutin::dpi::PhysicalSize::new(size.x, size.y)); + } + + pub fn set_position_pixels>>(&self, position: P) + { + let position = position.into(); + + self.window_context.window().set_outer_position( + glutin::dpi::PhysicalPosition::new(position.x, position.y) + ); + } + + pub fn set_size_scaled_pixels>>(&self, size: S) + { + let size = size.into(); + + self.window_context + .window() + .set_inner_size(glutin::dpi::LogicalSize::new(size.x, size.y)); + } + + pub fn set_position_scaled_pixels>>(&self, position: P) + { + let position = position.into(); + + self.window_context.window().set_outer_position( + glutin::dpi::LogicalPosition::new(position.x, position.y) + ); + } + + #[inline] + pub fn get_scale_factor(&self) -> f64 + { + self.window_context.window().scale_factor() + } + + pub fn create_user_event_sender(&self) -> UserEventSender + { + UserEventSender { + event_proxy: self.event_proxy.clone() + } + } +} + +pub(crate) trait WindowImplHandler +{ + fn on_start(&mut self, info: WindowStartupInfo) -> WindowEventLoopAction; + + fn on_user_event(&mut self, user_event: UserEventType) -> WindowEventLoopAction; + + fn on_resize(&mut self, size_pixels: Vector2) -> WindowEventLoopAction; + + fn on_scale_factor_changed(&mut self, scale_factor: f64) -> WindowEventLoopAction; + + fn on_draw(&mut self) -> WindowEventLoopAction; + + fn on_mouse_move(&mut self, position: Vector2) -> WindowEventLoopAction; + + fn on_mouse_button_down(&mut self, button: MouseButton) -> WindowEventLoopAction; + + fn on_mouse_button_up(&mut self, button: MouseButton) -> WindowEventLoopAction; + + fn on_key_down( + &mut self, + virtual_key_code: Option, + scancode: KeyScancode + ) -> WindowEventLoopAction; + + fn on_key_up( + &mut self, + virtual_key_code: Option, + scancode: KeyScancode + ) -> WindowEventLoopAction; + + fn on_keyboard_char(&mut self, unicode_character: char) -> WindowEventLoopAction; + + fn on_keyboard_modifiers_changed( + &mut self, + state: ModifiersState + ) -> WindowEventLoopAction; +} + +extern "system" fn gl_log_callback( + _source: GLenum, + _gltype: GLenum, + _id: GLuint, + severity: GLenum, + length: GLsizei, + message: *const GLchar, + _user_param: *mut std::os::raw::c_void +) +{ + let msg = if length < 0 { + unsafe { String::from_utf8_lossy(std::ffi::CStr::from_ptr(message).to_bytes()) } + } else { + unsafe { + String::from_utf8_lossy(std::slice::from_raw_parts( + message as *const u8, + length as usize + )) + } + }; + + match severity { + gl::DEBUG_SEVERITY_HIGH => log::error!("GL debug log: {}", msg), + gl::DEBUG_SEVERITY_MEDIUM => log::warn!("GL debug log: {}", msg), + gl::DEBUG_SEVERITY_LOW => log::info!("GL debug log: {}", msg), + _ => log::debug!("GL debug log: {}", msg) + } +} + +fn gl_setup_debug_log_callback() +{ + if !gl::DebugMessageCallback::is_loaded() { + log::error!("Cannot register GL debug log: function not loaded"); + return; + } + + log::info!("Setting up GL debug log"); + + unsafe { + gl::DebugMessageCallback(Some(gl_log_callback), std::ptr::null()); + gl::Enable(gl::DEBUG_OUTPUT); + gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS); + } +} + +/// Error occurring when creating a window. +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +pub enum WindowCreationError +{ + /// Could not find the primary monitor. + PrimaryMonitorNotFound, + /// Could not find a suitable graphics context. Speedy2D attempts to find + /// the best possible context configuration by trying multiple options for + /// vsync and multisampling. + SuitableContextNotFound, + /// Failed to make the graphics context current. + MakeContextCurrentFailed, + /// Failed to instantiate the renderer. + RendererCreationFailed +} + +impl Display for WindowCreationError +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result + { + match self { + WindowCreationError::PrimaryMonitorNotFound => { + f.write_str("Primary monitor not found") + } + WindowCreationError::SuitableContextNotFound => { + f.write_str("Could not find a suitable graphics context") + } + WindowCreationError::MakeContextCurrentFailed => { + f.write_str("Failed to make the graphics context current") + } + WindowCreationError::RendererCreationFailed => { + f.write_str("Failed to create the renderer") + } + } + } +} + +pub(crate) struct WindowImpl +{ + event_loop: EventLoop, + window_context: Rc>, + helper: WindowImplHelper +} + +impl WindowImpl +{ + pub(crate) fn new( + title: &str, + options: WindowCreationOptions + ) -> Result, BacktraceError> + { + let event_loop: EventLoop = EventLoop::with_user_event(); + + let primary_monitor = event_loop.primary_monitor().ok_or_else(|| { + BacktraceError::new(WindowCreationError::PrimaryMonitorNotFound) + })?; + + for (num, monitor) in event_loop.available_monitors().enumerate() { + log::debug!( + "Monitor #{}{}: {}", + num, + if monitor == primary_monitor { + " (primary)" + } else { + "" + }, + match &monitor.name() { + None => "", + Some(name) => name.as_str() + } + ); + } + + let mut window_builder = GlutinWindowBuilder::new().with_title(title); + + match &options.mode() { + WindowCreationMode::Windowed { size, .. } => { + window_builder = window_builder + .with_inner_size(compute_window_size(&primary_monitor, size)); + } + + WindowCreationMode::FullscreenBorderless => { + window_builder = window_builder.with_fullscreen(Option::Some( + glutin::window::Fullscreen::Borderless(Option::Some( + primary_monitor.clone() + )) + )); + } + } + + let window_context = create_best_context(&window_builder, &event_loop, &options) + .ok_or_else(|| { + BacktraceError::new(WindowCreationError::SuitableContextNotFound) + })?; + + let window_context = Rc::new(match unsafe { window_context.make_current() } { + Ok(window_context) => window_context, + Err((_, err)) => { + return Err(BacktraceError::new_with_cause( + WindowCreationError::MakeContextCurrentFailed, + err + )); + } + }); + + match &options.mode() { + WindowCreationMode::Windowed { position, .. } => { + if let Some(position) = position { + position_window(&primary_monitor, window_context.window(), position); + } + } + + WindowCreationMode::FullscreenBorderless => { + // Nothing to do + } + } + + gl::load_with(|ptr| window_context.get_proc_address(ptr) as *const _); + + let version = unsafe { + let data = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _).to_bytes(); + String::from_utf8_lossy(data) + }; + + log::info!("Using OpenGL version: {}", version); + + gl_setup_debug_log_callback(); + + let helper = WindowImplHelper::new(&window_context, event_loop.create_proxy()); + + Result::Ok(WindowImpl { + event_loop, + window_context, + helper + }) + } + + pub(crate) fn create_user_event_sender(&self) -> UserEventSender + { + UserEventSender { + event_proxy: self.event_loop.create_proxy() + } + } + + pub(crate) fn get_inner_size_pixels(&self) -> Vector2 + { + self.window_context.window().inner_size().into() + } + + fn loop_iter( + window_context: &glutin::ContextWrapper, + handler: &mut Handler, + event: GlutinEvent + ) -> WindowEventLoopAction + where + Handler: WindowImplHandler + 'static + { + match event { + GlutinEvent::LoopDestroyed => WindowEventLoopAction::Exit, + + GlutinEvent::UserEvent(event) => handler.on_user_event(event), + + GlutinEvent::WindowEvent { event, .. } => match event { + GlutinWindowEvent::ScaleFactorChanged { scale_factor, .. } => { + log::info!("Scale factor changed: {:?}", scale_factor); + handler.on_scale_factor_changed(scale_factor) + } + + GlutinWindowEvent::Resized(physical_size) => { + log::info!("Resized: {:?}", physical_size); + window_context.resize(physical_size); + unsafe { + gl::Viewport( + 0, + 0, + physical_size.width as i32, + physical_size.height as i32 + ) + } + handler.on_resize(physical_size.into()) + } + + GlutinWindowEvent::CloseRequested => WindowEventLoopAction::Exit, + + GlutinWindowEvent::CursorMoved { position, .. } => handler + .on_mouse_move(Vector2::new(position.x as f32, position.y as f32)), + + GlutinWindowEvent::MouseInput { state, button, .. } => match state { + GlutinElementState::Pressed => { + handler.on_mouse_button_down(MouseButton::from(button)) + } + GlutinElementState::Released => { + handler.on_mouse_button_up(MouseButton::from(button)) + } + }, + + GlutinWindowEvent::KeyboardInput { input, .. } => { + let virtual_key_code = + input.virtual_keycode.map(VirtualKeyCode::from); + + match input.state { + GlutinElementState::Pressed => { + handler.on_key_down(virtual_key_code, input.scancode) + } + GlutinElementState::Released => { + handler.on_key_up(virtual_key_code, input.scancode) + } + } + } + + GlutinWindowEvent::ReceivedCharacter(character) => { + handler.on_keyboard_char(character) + } + + GlutinWindowEvent::ModifiersChanged(state) => { + handler.on_keyboard_modifiers_changed(ModifiersState::from(state)) + } + + _ => WindowEventLoopAction::Continue + }, + + GlutinEvent::RedrawRequested(_) => { + let result = handler.on_draw(); + window_context.swap_buffers().unwrap(); + result + } + + _ => WindowEventLoopAction::Continue + } + } + + pub(crate) fn run_loop(self, mut handler: Handler) -> ! + where + Handler: WindowImplHandler + 'static + { + let window_context = self.window_context; + + match handler.on_start(WindowStartupInfo::new( + window_context.window().inner_size().into(), + window_context.window().scale_factor() + )) { + WindowEventLoopAction::Continue => {} + WindowEventLoopAction::Exit => { + log::info!("Start callback requested exit!"); + std::mem::drop(handler); + std::process::exit(0); + } + } + + let mut handler = Option::Some(handler); + + self.event_loop.run( + move |event: GlutinEvent, + _, + control_flow: &mut ControlFlow| { + *control_flow = { + if handler.is_none() { + ControlFlow::Exit + } else { + match WindowImpl::loop_iter( + &window_context, + handler.as_mut().unwrap(), + event + ) { + WindowEventLoopAction::Continue => ControlFlow::Wait, + WindowEventLoopAction::Exit => { + handler = Option::None; + ControlFlow::Exit + } + } + } + } + } + ) + } + + pub(crate) fn helper(&self) -> &WindowImplHelper + { + &self.helper + } +} + +fn create_best_context( + window_builder: &GlutinWindowBuilder, + event_loop: &EventLoop, + options: &WindowCreationOptions +) -> Option> +{ + for vsync in &[true, false] { + if *vsync && !options.vsync() { + continue; + } + + for multisampling in &[16, 8, 4, 2, 1, 0] { + if *multisampling > 1 && *multisampling > options.multisampling() { + continue; + } + + log::info!("Trying vsync={}, multisampling={}...", vsync, multisampling); + + let mut windowed_context = glutin::ContextBuilder::new() + .with_vsync(*vsync) + .with_gl_profile(glutin::GlProfile::Core) + .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (2, 0))); + + if *multisampling > 1 { + windowed_context = windowed_context.with_multisampling(*multisampling); + } + + let result = + windowed_context.build_windowed(window_builder.clone(), event_loop); + + match result { + Ok(context) => { + log::info!("Context created"); + return Option::Some(context); + } + Err(err) => { + log::info!("Failed with error: {:?}", err); + } + } + } + } + + log::error!("Failed to create any context."); + Option::None +} + +fn position_window( + monitor: &MonitorHandle, + window: &GlutinWindow, + position: &WindowPosition +) +{ + let monitor_position = monitor.position(); + + match position { + WindowPosition::Center => { + let monitor_size = monitor.size(); + let outer_size = window.outer_size(); + + log::info!( + "Centering window. Monitor size: {:?}. Window outer size: {:?}.", + monitor_size, + outer_size + ); + + window.set_outer_position(PhysicalPosition::new( + monitor_position.x + ((monitor_size.width - outer_size.width) / 2) as i32, + monitor_position.y + + ((monitor_size.height - outer_size.height) / 2) as i32 + )); + } + + WindowPosition::PrimaryMonitorPixelsFromTopLeft(position) => window + .set_outer_position(PhysicalPosition::new( + monitor_position.x + position.x, + monitor_position.y + position.y + )) + } +} + +fn compute_window_size(monitor: &MonitorHandle, size: &WindowSize) -> PhysicalSize +{ + let monitor_size = monitor.size(); + + match size { + WindowSize::PhysicalPixels(size) => PhysicalSize::new(size.x, size.y), + + WindowSize::ScaledPixels(size) => { + LogicalSize::new(size.x, size.y).to_physical(monitor.scale_factor()) + } + + WindowSize::MarginPhysicalPixels(margin) => { + let margin_physical_px = std::cmp::min( + *margin, + std::cmp::min(monitor_size.width, monitor_size.height) / 4 + ); + + PhysicalSize::new( + monitor_size.width - 2 * margin_physical_px, + monitor_size.height - 2 * margin_physical_px + ) + } + + WindowSize::MarginScaledPixels(margin) => { + let margin_physical_px = std::cmp::min( + (*margin as f64 * monitor.scale_factor()).round() as u32, + std::cmp::min(monitor_size.width, monitor_size.height) / 4 + ); + + PhysicalSize::new( + monitor_size.width - 2 * margin_physical_px, + monitor_size.height - 2 * margin_physical_px + ) + } + } +} + +/// A set of callbacks for an active window. If a callback is not implemented, +/// it will do nothing by default, so it is only necessary to implement the +/// callbacks you actually need. +pub trait WindowHandler +{ + /// Invoked once when the window first starts. + #[allow(unused_variables)] + #[inline] + fn on_start( + &mut self, + helper: &mut WindowHelper, + info: WindowStartupInfo + ) + { + } + + /// Invoked when a user-defined event is received, allowing you to wake up + /// the event loop to handle events from other threads. + /// + /// See [WindowHelper::create_user_event_sender]. + #[allow(unused_variables)] + #[inline] + fn on_user_event( + &mut self, + helper: &mut WindowHelper, + user_event: UserEventType + ) + { + } + + /// Invoked when the window is resized. + #[allow(unused_variables)] + #[inline] + fn on_resize( + &mut self, + helper: &mut WindowHelper, + size_pixels: Vector2 + ) + { + } + + /// Invoked when the window scale factor changes. + #[allow(unused_variables)] + #[inline] + fn on_scale_factor_changed( + &mut self, + helper: &mut WindowHelper, + scale_factor: f64 + ) + { + } + + /// Invoked when the contents of the window needs to be redrawn. + /// + /// It is possible to request a redraw from any callback using + /// [WindowHelper::request_redraw]. + #[allow(unused_variables)] + #[inline] + fn on_draw( + &mut self, + helper: &mut WindowHelper, + graphics: &mut Graphics2D + ) + { + } + + /// Invoked when the mouse changes position. + #[allow(unused_variables)] + #[inline] + fn on_mouse_move( + &mut self, + helper: &mut WindowHelper, + position: Vector2 + ) + { + } + + /// Invoked when a mouse button is pressed. + #[allow(unused_variables)] + #[inline] + fn on_mouse_button_down( + &mut self, + helper: &mut WindowHelper, + button: MouseButton + ) + { + } + + /// Invoked when a mouse button is released. + #[allow(unused_variables)] + #[inline] + fn on_mouse_button_up( + &mut self, + helper: &mut WindowHelper, + button: MouseButton + ) + { + } + + /// Invoked when a keyboard key is pressed. + /// + /// To detect when a character is typed, see the + /// [WindowHandler::on_keyboard_char] callback. + #[allow(unused_variables)] + #[inline] + fn on_key_down( + &mut self, + helper: &mut WindowHelper, + virtual_key_code: Option, + scancode: KeyScancode + ) + { + } + + /// Invoked when a keyboard key is released. + #[allow(unused_variables)] + #[inline] + fn on_key_up( + &mut self, + helper: &mut WindowHelper, + virtual_key_code: Option, + scancode: KeyScancode + ) + { + } + + /// Invoked when a character is typed on the keyboard. + /// + /// This is invoked in addition to the [WindowHandler::on_key_up] and + /// [WindowHandler::on_key_down] callbacks. + #[allow(unused_variables)] + #[inline] + fn on_keyboard_char( + &mut self, + helper: &mut WindowHelper, + unicode_codepoint: char + ) + { + } + + /// Invoked when the state of the modifier keys has changed. + #[allow(unused_variables)] + #[inline] + fn on_keyboard_modifiers_changed( + &mut self, + helper: &mut WindowHelper, + state: ModifiersState + ) + { + } +} + +pub(crate) struct DrawingWindowHandler +where + H: WindowHandler, + UserEventType: 'static +{ + window_handler: H, + renderer: GLRenderer, + helper: WindowHelper +} + +impl DrawingWindowHandler +where + H: WindowHandler, + UserEventType: 'static +{ + pub(crate) fn new( + window_handler: H, + renderer: GLRenderer, + helper: WindowHelper + ) -> Self + { + DrawingWindowHandler { + window_handler, + renderer, + helper + } + } +} + +impl WindowImplHandler + for DrawingWindowHandler +where + Handler: WindowHandler +{ + #[inline] + fn on_start(&mut self, info: WindowStartupInfo) -> WindowEventLoopAction + { + self.window_handler.on_start(&mut self.helper, info); + self.helper.get_event_loop_action() + } + + fn on_user_event(&mut self, user_event: UserEventType) -> WindowEventLoopAction + { + self.window_handler + .on_user_event(&mut self.helper, user_event); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_resize(&mut self, size_pixels: Vector2) -> WindowEventLoopAction + { + self.renderer.set_viewport_size_pixels(size_pixels); + self.window_handler.on_resize(&mut self.helper, size_pixels); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_scale_factor_changed(&mut self, scale_factor: f64) -> WindowEventLoopAction + { + self.window_handler + .on_scale_factor_changed(&mut self.helper, scale_factor); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_draw(&mut self) -> WindowEventLoopAction + { + let renderer = &mut self.renderer; + let window_handler = &mut self.window_handler; + let helper = &mut self.helper; + + renderer.draw_frame(|graphics| window_handler.on_draw(helper, graphics)); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_mouse_move(&mut self, position: Vector2) -> WindowEventLoopAction + { + self.window_handler + .on_mouse_move(&mut self.helper, position); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_mouse_button_down(&mut self, button: MouseButton) -> WindowEventLoopAction + { + self.window_handler + .on_mouse_button_down(&mut self.helper, button); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_mouse_button_up(&mut self, button: MouseButton) -> WindowEventLoopAction + { + self.window_handler + .on_mouse_button_up(&mut self.helper, button); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_key_down( + &mut self, + virtual_key_code: Option, + scancode: KeyScancode + ) -> WindowEventLoopAction + { + self.window_handler + .on_key_down(&mut self.helper, virtual_key_code, scancode); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_key_up( + &mut self, + virtual_key_code: Option, + scancode: KeyScancode + ) -> WindowEventLoopAction + { + self.window_handler + .on_key_up(&mut self.helper, virtual_key_code, scancode); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_keyboard_char(&mut self, unicode_codepoint: char) -> WindowEventLoopAction + { + self.window_handler + .on_keyboard_char(&mut self.helper, unicode_codepoint); + self.helper.get_event_loop_action() + } + + #[inline] + fn on_keyboard_modifiers_changed( + &mut self, + state: ModifiersState + ) -> WindowEventLoopAction + { + self.window_handler + .on_keyboard_modifiers_changed(&mut self.helper, state); + self.helper.get_event_loop_action() + } +} + +/// A set of helper methods to perform actions on a [crate::Window]. +pub struct WindowHelper +where + UserEventType: 'static +{ + helper: WindowImplHelper, + event_loop_action: WindowEventLoopAction +} + +impl WindowHelper +{ + #[inline] + fn get_event_loop_action(&self) -> WindowEventLoopAction + { + self.event_loop_action + } + + #[inline] + pub(crate) fn new(helper: WindowImplHelper) -> Self + { + WindowHelper { + helper, + event_loop_action: WindowEventLoopAction::Continue + } + } + + /// Causes the event loop to stop processing events, and terminate the + /// application. + /// + /// Note: The event loop will stop only once the current callback has + /// returned, rather than terminating immediately. + /// + /// Once the event loop has stopped, the entire process will end with error + /// code 0, even if other threads are running. + /// + /// If your `WindowHandler` struct implements `Drop`, it will be safely + /// destructed before exiting. + /// + /// No further callbacks will be given once this function has been called. + pub fn terminate_loop(&mut self) + { + self.event_loop_action = WindowEventLoopAction::Exit; + } + + /// Sets the window icon from the provided RGBA pixels. + /// + /// On Windows, the base icon size is 16x16, however a multiple of this + /// (e.g. 32x32) should be provided for high-resolution displays. + pub fn set_icon_from_rgba_pixels( + &self, + data: Vec, + size: S + ) -> Result<(), BacktraceError> + where + S: Into> + { + self.helper.set_icon_from_rgba_pixels(data, size.into()) + } + + /// Sets the visibility of the mouse cursor. + pub fn set_cursor_visible(&self, visible: bool) + { + self.helper.set_cursor_visible(visible) + } + + /// Grabs the cursor, preventing it from leaving the window. + pub fn set_cursor_grab( + &self, + grabbed: bool + ) -> Result<(), BacktraceError> + { + self.helper.set_cursor_grab(grabbed) + } + + /// Set to false to prevent the user from resizing the window. + pub fn set_resizable(&self, resizable: bool) + { + self.helper.set_resizable(resizable); + } + + /// Request that the window is redrawn. + /// + /// This will cause the [WindowHandler::on_draw] callback to be invoked on + /// the next frame. + #[inline] + pub fn request_redraw(&self) + { + self.helper.request_redraw() + } + + /// Sets the window title. + pub fn set_title(&self, title: &str) + { + self.helper.set_title(title); + } + + /// Sets the window fullscreen mode. + pub fn set_fullscreen_mode(&self, mode: WindowFullscreenMode) + { + self.helper.set_fullscreen_mode(mode) + } + + /// Sets the window size in pixels. This is the window's inner size, + /// excluding the border. + pub fn set_size_pixels>>(&self, size: S) + { + self.helper.set_size_pixels(size) + } + + /// Sets the position of the window in pixels. If multiple monitors are in + /// use, this will be the distance from the top left of the display + /// area, spanning all the monitors. + pub fn set_position_pixels>>(&self, position: P) + { + self.helper.set_position_pixels(position) + } + + /// Sets the window size in scaled device-independent pixels. This is the + /// window's inner size, excluding the border. + pub fn set_size_scaled_pixels>>(&self, size: S) + { + self.helper.set_size_scaled_pixels(size) + } + + /// Sets the position of the window in scaled device-independent pixels. If + /// multiple monitors are in use, this will be the distance from the top + /// left of the display area, spanning all the monitors. + pub fn set_position_scaled_pixels>>(&self, position: P) + { + self.helper.set_position_scaled_pixels(position) + } + + /// Gets the window's scale factor. + #[inline] + pub fn get_scale_factor(&self) -> f64 + { + self.helper.get_scale_factor() + } + + /// Creates a [UserEventSender], which can be used to post custom events to + /// this event loop from another thread. + /// + /// See [UserEventSender::send_event], [WindowHandler::on_user_event]. + pub fn create_user_event_sender(&self) -> UserEventSender + { + self.helper.create_user_event_sender() + } +} + +impl From> for Vector2 +{ + fn from(value: PhysicalSize) -> Self + { + Self::new(value.width, value.height) + } +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] +#[must_use] +pub(crate) enum WindowEventLoopAction +{ + /// Continue running the event loop. + Continue, + + /// Stops the event loop. This will cause the entire process to end with + /// error code 0, even if other threads are running. + /// + /// No further callbacks will be given once a handler has returned this + /// value. The handler itself will be dropped before exiting. + Exit +} + +/// Information about the starting state of the window. +#[derive(Debug, PartialEq, Clone)] +pub struct WindowStartupInfo +{ + viewport_size_pixels: Vector2, + scale_factor: f64 +} + +impl WindowStartupInfo +{ + pub(crate) fn new(viewport_size_pixels: Vector2, scale_factor: f64) -> Self + { + WindowStartupInfo { + viewport_size_pixels, + scale_factor + } + } + + /// The scale factor of the window. When a high-dpi display is in use, + /// this will be greater than `1.0`. + pub fn scale_factor(&self) -> f64 + { + self.scale_factor + } + + /// The size of the viewport in pixels. + pub fn viewport_size_pixels(&self) -> &Vector2 + { + &self.viewport_size_pixels + } +} + +/// Identifies a mouse button. +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] +pub enum MouseButton +{ + /// The left mouse button. + Left, + /// The middle mouse button. + Middle, + /// The right mouse button. + Right, + /// Another mouse button, identified by a number. + Other(u16) +} + +/// A virtual key code. +#[allow(missing_docs)] +#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)] +pub enum VirtualKeyCode +{ + Key1, + Key2, + Key3, + Key4, + Key5, + Key6, + Key7, + Key8, + Key9, + Key0, + + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T, + U, + V, + W, + X, + Y, + Z, + + Escape, + + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + F13, + F14, + F15, + F16, + F17, + F18, + F19, + F20, + F21, + F22, + F23, + F24, + + PrintScreen, + ScrollLock, + PauseBreak, + + Insert, + Home, + Delete, + End, + PageDown, + PageUp, + + Left, + Up, + Right, + Down, + + Backspace, + Return, + Space, + + Compose, + + Caret, + + Numlock, + Numpad0, + Numpad1, + Numpad2, + Numpad3, + Numpad4, + Numpad5, + Numpad6, + Numpad7, + Numpad8, + Numpad9, + NumpadAdd, + NumpadDivide, + NumpadDecimal, + NumpadComma, + NumpadEnter, + NumpadEquals, + NumpadMultiply, + NumpadSubtract, + + AbntC1, + AbntC2, + Apostrophe, + Apps, + Asterisk, + At, + Ax, + Backslash, + Calculator, + Capital, + Colon, + Comma, + Convert, + Equals, + Grave, + Kana, + Kanji, + LAlt, + LBracket, + LControl, + LShift, + LWin, + Mail, + MediaSelect, + MediaStop, + Minus, + Mute, + MyComputer, + NavigateForward, + NavigateBackward, + NextTrack, + NoConvert, + OEM102, + Period, + PlayPause, + Plus, + Power, + PrevTrack, + RAlt, + RBracket, + RControl, + RShift, + RWin, + Semicolon, + Slash, + Sleep, + Stop, + Sysrq, + Tab, + Underline, + Unlabeled, + VolumeDown, + VolumeUp, + Wake, + WebBack, + WebFavorites, + WebForward, + WebHome, + WebRefresh, + WebSearch, + WebStop, + Yen, + Copy, + Paste, + Cut +} + +impl From for MouseButton +{ + fn from(button: glutin::event::MouseButton) -> Self + { + match button { + glutin::event::MouseButton::Left => MouseButton::Left, + glutin::event::MouseButton::Right => MouseButton::Right, + glutin::event::MouseButton::Middle => MouseButton::Middle, + glutin::event::MouseButton::Other(id) => MouseButton::Other(id) + } + } +} + +impl From for VirtualKeyCode +{ + fn from(virtual_key_code: GlutinVirtualKeyCode) -> Self + { + match virtual_key_code { + GlutinVirtualKeyCode::Key1 => VirtualKeyCode::Key1, + GlutinVirtualKeyCode::Key2 => VirtualKeyCode::Key2, + GlutinVirtualKeyCode::Key3 => VirtualKeyCode::Key3, + GlutinVirtualKeyCode::Key4 => VirtualKeyCode::Key4, + GlutinVirtualKeyCode::Key5 => VirtualKeyCode::Key5, + GlutinVirtualKeyCode::Key6 => VirtualKeyCode::Key6, + GlutinVirtualKeyCode::Key7 => VirtualKeyCode::Key7, + GlutinVirtualKeyCode::Key8 => VirtualKeyCode::Key8, + GlutinVirtualKeyCode::Key9 => VirtualKeyCode::Key9, + GlutinVirtualKeyCode::Key0 => VirtualKeyCode::Key0, + GlutinVirtualKeyCode::A => VirtualKeyCode::A, + GlutinVirtualKeyCode::B => VirtualKeyCode::B, + GlutinVirtualKeyCode::C => VirtualKeyCode::C, + GlutinVirtualKeyCode::D => VirtualKeyCode::D, + GlutinVirtualKeyCode::E => VirtualKeyCode::E, + GlutinVirtualKeyCode::F => VirtualKeyCode::F, + GlutinVirtualKeyCode::G => VirtualKeyCode::G, + GlutinVirtualKeyCode::H => VirtualKeyCode::H, + GlutinVirtualKeyCode::I => VirtualKeyCode::I, + GlutinVirtualKeyCode::J => VirtualKeyCode::J, + GlutinVirtualKeyCode::K => VirtualKeyCode::K, + GlutinVirtualKeyCode::L => VirtualKeyCode::L, + GlutinVirtualKeyCode::M => VirtualKeyCode::M, + GlutinVirtualKeyCode::N => VirtualKeyCode::N, + GlutinVirtualKeyCode::O => VirtualKeyCode::O, + GlutinVirtualKeyCode::P => VirtualKeyCode::P, + GlutinVirtualKeyCode::Q => VirtualKeyCode::Q, + GlutinVirtualKeyCode::R => VirtualKeyCode::R, + GlutinVirtualKeyCode::S => VirtualKeyCode::S, + GlutinVirtualKeyCode::T => VirtualKeyCode::T, + GlutinVirtualKeyCode::U => VirtualKeyCode::U, + GlutinVirtualKeyCode::V => VirtualKeyCode::V, + GlutinVirtualKeyCode::W => VirtualKeyCode::W, + GlutinVirtualKeyCode::X => VirtualKeyCode::X, + GlutinVirtualKeyCode::Y => VirtualKeyCode::Y, + GlutinVirtualKeyCode::Z => VirtualKeyCode::Z, + GlutinVirtualKeyCode::Escape => VirtualKeyCode::Escape, + GlutinVirtualKeyCode::F1 => VirtualKeyCode::F1, + GlutinVirtualKeyCode::F2 => VirtualKeyCode::F2, + GlutinVirtualKeyCode::F3 => VirtualKeyCode::F3, + GlutinVirtualKeyCode::F4 => VirtualKeyCode::F4, + GlutinVirtualKeyCode::F5 => VirtualKeyCode::F5, + GlutinVirtualKeyCode::F6 => VirtualKeyCode::F6, + GlutinVirtualKeyCode::F7 => VirtualKeyCode::F7, + GlutinVirtualKeyCode::F8 => VirtualKeyCode::F8, + GlutinVirtualKeyCode::F9 => VirtualKeyCode::F9, + GlutinVirtualKeyCode::F10 => VirtualKeyCode::F10, + GlutinVirtualKeyCode::F11 => VirtualKeyCode::F11, + GlutinVirtualKeyCode::F12 => VirtualKeyCode::F12, + GlutinVirtualKeyCode::F13 => VirtualKeyCode::F13, + GlutinVirtualKeyCode::F14 => VirtualKeyCode::F14, + GlutinVirtualKeyCode::F15 => VirtualKeyCode::F15, + GlutinVirtualKeyCode::F16 => VirtualKeyCode::F16, + GlutinVirtualKeyCode::F17 => VirtualKeyCode::F17, + GlutinVirtualKeyCode::F18 => VirtualKeyCode::F18, + GlutinVirtualKeyCode::F19 => VirtualKeyCode::F19, + GlutinVirtualKeyCode::F20 => VirtualKeyCode::F20, + GlutinVirtualKeyCode::F21 => VirtualKeyCode::F21, + GlutinVirtualKeyCode::F22 => VirtualKeyCode::F22, + GlutinVirtualKeyCode::F23 => VirtualKeyCode::F23, + GlutinVirtualKeyCode::F24 => VirtualKeyCode::F24, + GlutinVirtualKeyCode::Snapshot => VirtualKeyCode::PrintScreen, + GlutinVirtualKeyCode::Scroll => VirtualKeyCode::ScrollLock, + GlutinVirtualKeyCode::Pause => VirtualKeyCode::PauseBreak, + GlutinVirtualKeyCode::Insert => VirtualKeyCode::Insert, + GlutinVirtualKeyCode::Home => VirtualKeyCode::Home, + GlutinVirtualKeyCode::Delete => VirtualKeyCode::Delete, + GlutinVirtualKeyCode::End => VirtualKeyCode::End, + GlutinVirtualKeyCode::PageDown => VirtualKeyCode::PageDown, + GlutinVirtualKeyCode::PageUp => VirtualKeyCode::PageUp, + GlutinVirtualKeyCode::Left => VirtualKeyCode::Left, + GlutinVirtualKeyCode::Up => VirtualKeyCode::Up, + GlutinVirtualKeyCode::Right => VirtualKeyCode::Right, + GlutinVirtualKeyCode::Down => VirtualKeyCode::Down, + GlutinVirtualKeyCode::Back => VirtualKeyCode::Backspace, + GlutinVirtualKeyCode::Return => VirtualKeyCode::Return, + GlutinVirtualKeyCode::Space => VirtualKeyCode::Space, + GlutinVirtualKeyCode::Compose => VirtualKeyCode::Compose, + GlutinVirtualKeyCode::Caret => VirtualKeyCode::Caret, + GlutinVirtualKeyCode::Numlock => VirtualKeyCode::Numlock, + GlutinVirtualKeyCode::Numpad0 => VirtualKeyCode::Numpad0, + GlutinVirtualKeyCode::Numpad1 => VirtualKeyCode::Numpad1, + GlutinVirtualKeyCode::Numpad2 => VirtualKeyCode::Numpad2, + GlutinVirtualKeyCode::Numpad3 => VirtualKeyCode::Numpad3, + GlutinVirtualKeyCode::Numpad4 => VirtualKeyCode::Numpad4, + GlutinVirtualKeyCode::Numpad5 => VirtualKeyCode::Numpad5, + GlutinVirtualKeyCode::Numpad6 => VirtualKeyCode::Numpad6, + GlutinVirtualKeyCode::Numpad7 => VirtualKeyCode::Numpad7, + GlutinVirtualKeyCode::Numpad8 => VirtualKeyCode::Numpad8, + GlutinVirtualKeyCode::Numpad9 => VirtualKeyCode::Numpad9, + GlutinVirtualKeyCode::NumpadAdd => VirtualKeyCode::NumpadAdd, + GlutinVirtualKeyCode::NumpadDivide => VirtualKeyCode::NumpadDivide, + GlutinVirtualKeyCode::NumpadDecimal => VirtualKeyCode::NumpadDecimal, + GlutinVirtualKeyCode::NumpadComma => VirtualKeyCode::NumpadComma, + GlutinVirtualKeyCode::NumpadEnter => VirtualKeyCode::NumpadEnter, + GlutinVirtualKeyCode::NumpadEquals => VirtualKeyCode::NumpadEquals, + GlutinVirtualKeyCode::NumpadMultiply => VirtualKeyCode::NumpadMultiply, + GlutinVirtualKeyCode::NumpadSubtract => VirtualKeyCode::NumpadSubtract, + GlutinVirtualKeyCode::AbntC1 => VirtualKeyCode::AbntC1, + GlutinVirtualKeyCode::AbntC2 => VirtualKeyCode::AbntC2, + GlutinVirtualKeyCode::Apostrophe => VirtualKeyCode::Apostrophe, + GlutinVirtualKeyCode::Apps => VirtualKeyCode::Apps, + GlutinVirtualKeyCode::Asterisk => VirtualKeyCode::Asterisk, + GlutinVirtualKeyCode::At => VirtualKeyCode::At, + GlutinVirtualKeyCode::Ax => VirtualKeyCode::Ax, + GlutinVirtualKeyCode::Backslash => VirtualKeyCode::Backslash, + GlutinVirtualKeyCode::Calculator => VirtualKeyCode::Calculator, + GlutinVirtualKeyCode::Capital => VirtualKeyCode::Capital, + GlutinVirtualKeyCode::Colon => VirtualKeyCode::Colon, + GlutinVirtualKeyCode::Comma => VirtualKeyCode::Comma, + GlutinVirtualKeyCode::Convert => VirtualKeyCode::Convert, + GlutinVirtualKeyCode::Equals => VirtualKeyCode::Equals, + GlutinVirtualKeyCode::Grave => VirtualKeyCode::Grave, + GlutinVirtualKeyCode::Kana => VirtualKeyCode::Kana, + GlutinVirtualKeyCode::Kanji => VirtualKeyCode::Kanji, + GlutinVirtualKeyCode::LAlt => VirtualKeyCode::LAlt, + GlutinVirtualKeyCode::LBracket => VirtualKeyCode::LBracket, + GlutinVirtualKeyCode::LControl => VirtualKeyCode::LControl, + GlutinVirtualKeyCode::LShift => VirtualKeyCode::LShift, + GlutinVirtualKeyCode::LWin => VirtualKeyCode::LWin, + GlutinVirtualKeyCode::Mail => VirtualKeyCode::Mail, + GlutinVirtualKeyCode::MediaSelect => VirtualKeyCode::MediaSelect, + GlutinVirtualKeyCode::MediaStop => VirtualKeyCode::MediaStop, + GlutinVirtualKeyCode::Minus => VirtualKeyCode::Minus, + GlutinVirtualKeyCode::Mute => VirtualKeyCode::Mute, + GlutinVirtualKeyCode::MyComputer => VirtualKeyCode::MyComputer, + GlutinVirtualKeyCode::NavigateForward => VirtualKeyCode::NavigateForward, + GlutinVirtualKeyCode::NavigateBackward => VirtualKeyCode::NavigateBackward, + GlutinVirtualKeyCode::NextTrack => VirtualKeyCode::NextTrack, + GlutinVirtualKeyCode::NoConvert => VirtualKeyCode::NoConvert, + GlutinVirtualKeyCode::OEM102 => VirtualKeyCode::OEM102, + GlutinVirtualKeyCode::Period => VirtualKeyCode::Period, + GlutinVirtualKeyCode::PlayPause => VirtualKeyCode::PlayPause, + GlutinVirtualKeyCode::Plus => VirtualKeyCode::Plus, + GlutinVirtualKeyCode::Power => VirtualKeyCode::Power, + GlutinVirtualKeyCode::PrevTrack => VirtualKeyCode::PrevTrack, + GlutinVirtualKeyCode::RAlt => VirtualKeyCode::RAlt, + GlutinVirtualKeyCode::RBracket => VirtualKeyCode::RBracket, + GlutinVirtualKeyCode::RControl => VirtualKeyCode::RControl, + GlutinVirtualKeyCode::RShift => VirtualKeyCode::RShift, + GlutinVirtualKeyCode::RWin => VirtualKeyCode::RWin, + GlutinVirtualKeyCode::Semicolon => VirtualKeyCode::Semicolon, + GlutinVirtualKeyCode::Slash => VirtualKeyCode::Slash, + GlutinVirtualKeyCode::Sleep => VirtualKeyCode::Sleep, + GlutinVirtualKeyCode::Stop => VirtualKeyCode::Stop, + GlutinVirtualKeyCode::Sysrq => VirtualKeyCode::Sysrq, + GlutinVirtualKeyCode::Tab => VirtualKeyCode::Tab, + GlutinVirtualKeyCode::Underline => VirtualKeyCode::Underline, + GlutinVirtualKeyCode::Unlabeled => VirtualKeyCode::Unlabeled, + GlutinVirtualKeyCode::VolumeDown => VirtualKeyCode::VolumeDown, + GlutinVirtualKeyCode::VolumeUp => VirtualKeyCode::VolumeUp, + GlutinVirtualKeyCode::Wake => VirtualKeyCode::Wake, + GlutinVirtualKeyCode::WebBack => VirtualKeyCode::WebBack, + GlutinVirtualKeyCode::WebFavorites => VirtualKeyCode::WebFavorites, + GlutinVirtualKeyCode::WebForward => VirtualKeyCode::WebForward, + GlutinVirtualKeyCode::WebHome => VirtualKeyCode::WebHome, + GlutinVirtualKeyCode::WebRefresh => VirtualKeyCode::WebRefresh, + GlutinVirtualKeyCode::WebSearch => VirtualKeyCode::WebSearch, + GlutinVirtualKeyCode::WebStop => VirtualKeyCode::WebStop, + GlutinVirtualKeyCode::Yen => VirtualKeyCode::Yen, + GlutinVirtualKeyCode::Copy => VirtualKeyCode::Copy, + GlutinVirtualKeyCode::Paste => VirtualKeyCode::Paste, + GlutinVirtualKeyCode::Cut => VirtualKeyCode::Cut + } + } +} + +/// The state of the modifier keys. +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub struct ModifiersState +{ + ctrl: bool, + alt: bool, + shift: bool, + logo: bool +} + +impl ModifiersState +{ + /// This is true if the CTRL key is pressed. + #[inline] + #[must_use] + pub fn ctrl(&self) -> bool + { + self.ctrl + } + + /// This is true if the ALT key is pressed. + #[inline] + #[must_use] + pub fn alt(&self) -> bool + { + self.alt + } + + /// This is true if the SHIFT key is pressed. + #[inline] + #[must_use] + pub fn shift(&self) -> bool + { + self.shift + } + + /// This is true if the logo key is pressed (normally the Windows key). + #[inline] + #[must_use] + pub fn logo(&self) -> bool + { + self.logo + } +} + +impl From for ModifiersState +{ + fn from(state: glutin::event::ModifiersState) -> Self + { + ModifiersState { + ctrl: state.ctrl(), + alt: state.alt(), + shift: state.shift(), + logo: state.logo() + } + } +} + +/// Configuration options about the mode in which the window should be created, +/// for example fullscreen or windowed. +#[derive(Debug, PartialEq, Clone)] +enum WindowCreationMode +{ + /// Create the window in non-fullscreen mode. + Windowed + { + /// The size of the window. + size: WindowSize, + + /// The position of the window. + position: Option + }, + + /// Create the window in fullscreen borderless mode. + FullscreenBorderless +} + +/// The size of the window to create. +#[derive(Debug, PartialEq, Clone)] +pub enum WindowSize +{ + /// Define the window size in pixels. + PhysicalPixels(Vector2), + /// Define the window size in device-independent scaled pixels. + ScaledPixels(Vector2), + /// Make the window fill the screen, except for a margin around the outer + /// edges. + MarginPhysicalPixels(u32), + /// Make the window fill the screen, except for a margin around the outer + /// edges. + MarginScaledPixels(f32) +} + +/// The position of the window to create. +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub enum WindowPosition +{ + /// Place the window in the center of the primary monitor. + Center, + /// Place the window at the specified pixel location from the top left of + /// the primary monitor. + PrimaryMonitorPixelsFromTopLeft(Vector2) +} + +/// Whether or not the window is in fullscreen mode. +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] +pub enum WindowFullscreenMode +{ + /// Non-fullscreen mode. + Windowed, + /// Fullscreen borderless mode. + FullscreenBorderless +} + +/// Options used during the creation of a window. +#[derive(Debug, Clone, PartialEq)] +pub struct WindowCreationOptions +{ + mode: WindowCreationMode, + multisampling: u16, + vsync: bool +} + +impl WindowCreationOptions +{ + /// Instantiates a new `WindowCreationOptions` structure with the default + /// options, in non-fullscreen mode. + pub fn new_windowed(size: WindowSize, position: Option) -> Self + { + Self::new(WindowCreationMode::Windowed { size, position }) + } + + /// Instantiates a new `WindowCreationOptions` structure with the default + /// options, in borderless fullscreen mode. + #[inline] + #[must_use] + pub fn new_fullscreen_borderless() -> Self + { + Self::new(WindowCreationMode::FullscreenBorderless) + } + + #[inline] + #[must_use] + fn new(mode: WindowCreationMode) -> Self + { + WindowCreationOptions { + mode, + multisampling: 8, + vsync: true + } + } + + /// Sets the maximum level of multisampling which will be applied. By + /// default this is set to `8`. + /// + /// Note that this depends on platform support, and setting this may have no + /// effect. + #[inline] + #[must_use] + pub fn with_multisampling(mut self, multisampling: u16) -> Self + { + self.multisampling = multisampling; + self + } + + /// Sets whether or not vsync should be enabled. This can increase latency, + /// but should eliminate tearing. By default this is set to `true`. + /// + /// Note that this depends on platform support, and setting this may have no + /// effect. + #[inline] + #[must_use] + pub fn with_vsync(mut self, vsync: bool) -> Self + { + self.vsync = vsync; + self + } + + #[inline] + #[must_use] + fn mode(&self) -> &WindowCreationMode + { + &self.mode + } + + #[inline] + #[must_use] + fn multisampling(&self) -> u16 + { + self.multisampling + } + + #[inline] + #[must_use] + fn vsync(&self) -> bool + { + self.vsync + } +} + +/// Type representing a keyboard scancode. +pub type KeyScancode = u32; diff --git a/test/assets/expected_images/test_basic_circles.png b/test/assets/expected_images/test_basic_circles.png new file mode 100644 index 0000000000000000000000000000000000000000..1f46b404f35be6f83ddc56157fc25667a5f6bcf8 GIT binary patch literal 256 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 Uhv_B3MmpD?D5%Mo$e9NI7n|*s2LJ#7 literal 0 HcmV?d00001 diff --git a/test/assets/expected_images/test_half_circle.png b/test/assets/expected_images/test_half_circle.png new file mode 100644 index 0000000000000000000000000000000000000000..1eba85d563b901d14d48a17cd474fe75e0789529 GIT binary patch literal 1516 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4mO}jWo=(60|V=3PZ!6KiaBquaOX*R2)JH6 z`A^)|aZ>F)Crv)I4BTmPT`A2Wx5j)L=s2A+dVMl9SXMmgk!LHF;!R(EV` zWXgqf@{054LFD)@FQ#|1g^TX2uYo>BsE8SPa*|b&a z;;wVcpL1U8a(Qiaf1X;zYN55SYigz?to7Nl?(Ncb&Pe&UuZ`<+aiL`N|Qy z1=gOfsqad7>$1h}^Iy%Tt2c%Vd)FXBaueH}n zv^n_b18e)^X44+Eh#G;l{MQU-C46kp;JjAQbX4=A(AtA6-RH~tr@8j1M#QK^@u)<^ zY%kujCQ0Ssqx)sO(?WYxB5HDvXG9+LXgZqf(#^=yefzDL?r9144L|11U6d;Mm_zLT zcJD1Z$ub8Y*;%`sHaaG#^G-c#&y0kR#;e^=Te%79)a5H&ZF6I#H-x{@LO|r)vnF<&8iKTm~d zSs&O7R=LN|5TYPzD@4KTP>5^Z2X;(L?NN@{bN)+47p00S zbBY!FbbEd(?CJJ#l|>ln!&t;i=TTkA|0C&E`E6dp}(%kh;(R6xcKdI#?OBu z2N%6pzxW9lcSoh(bxu2fUQp-S$GI6lf2kZy(%tTM8W`JRuYYPq+1Yt-h`78pv<)-^EW)y+;cHatZ-T_0%yhy~=o^FVdQ&MBb@0BjXa Av;Y7A literal 0 HcmV?d00001 diff --git a/test/assets/expected_images/test_lines_horizontal.png b/test/assets/expected_images/test_lines_horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..12c6818689a4c0c39338cf3833b0ca922cb886a9 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETN>3NZkcv5P&l~bJCIA`!IG;BF0FzbKom06oF+__$PS+S(eCUfo6b(gEp z*QRsyDw>3!kXZaiM~TOg(>dW0-^uFgwhIzY$sieQj5!sF_p&#=-&+cF1cRrmpUXO@ GgeCy7ltI1# literal 0 HcmV?d00001 diff --git a/test/assets/expected_images/test_lines_vertical.png b/test/assets/expected_images/test_lines_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..ce095a9d786ddafda102b889cdd1084d846e5371 GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETZci7-kcv5P&l~bFD+)MYe3({H zRI|Aya8`!MQlr(WU*jL1I-9>ulT zg(X6YaxEcBN17*iskikQUUNHRdA+U!s76RpT3`~#&4vjjDJRUG%#>6FH!&)9PT=M6 sJl_6C$;pOerAr69;#8m!Px9_PGuU1AJY?N{ptBe}UHx3vIVCg!0D$jB%>V!Z literal 0 HcmV?d00001 diff --git a/test/assets/expected_images/test_text_alignment.png b/test/assets/expected_images/test_text_alignment.png new file mode 100644 index 0000000000000000000000000000000000000000..1bb0c5b65809ecc271dc0b713d55f12144e35e1e GIT binary patch literal 40608 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 LzL_cY@Y(+Y+Msa- literal 0 HcmV?d00001 diff --git a/test/assets/expected_images/test_wrapped_text_1.png b/test/assets/expected_images/test_wrapped_text_1.png new file mode 100644 index 0000000000000000000000000000000000000000..0da6680dfea231dbf763c7a8e77bf50003b57423 GIT binary patch literal 58873 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 literal 0 HcmV?d00001 diff --git a/test/main.rs b/test/main.rs new file mode 100644 index 0000000..659dcd1 --- /dev/null +++ b/test/main.rs @@ -0,0 +1,542 @@ +/* + * Copyright 2021 QuantumBadger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use std::any::Any; +use std::convert::TryInto; +use std::os::raw::c_void; + +use glutin::dpi::PhysicalSize; +use glutin::event_loop::EventLoop; +use glutin::window::WindowBuilder; +use image::{ColorType, ImageFormat}; +use speedy2d::color::Color; +use speedy2d::dimen::Vector2; +use speedy2d::font::{Font, TextAlignment, TextLayout, TextOptions}; +use speedy2d::shape::Rectangle; +use speedy2d::GLRenderer; + +const NOTO_SANS_REGULAR_BYTES: &[u8] = + include_bytes!("../assets/fonts/NotoSans-Regular.ttf"); + +fn get_expected_image_path>(name: S) -> String +{ + format!("test/assets/expected_images/test_{}.png", name.as_ref()) +} + +fn write_rgba_to_png>(name: S, width: u32, height: u32, buf: &[u8]) +{ + image::save_buffer_with_format( + get_expected_image_path(name), + buf, + width, + height, + ColorType::Rgba8, + ImageFormat::Png + ) + .unwrap(); +} + +fn read_png_argb8>(name: S) -> Option> +{ + image::io::Reader::open(get_expected_image_path(name)) + .ok() + .and_then(|reader| reader.decode().ok()) + .map(|image| image.into_rgba8().into_raw()) +} + +fn read_framebuffer_argb(width: u32, height: u32) -> Vec +{ + let mut buf: Vec = vec![0; (width * height * 4).try_into().unwrap()]; + + unsafe { + gl::ReadPixels( + 0, + 0, + width.try_into().unwrap(), + height.try_into().unwrap(), + gl::RGBA, + gl::UNSIGNED_BYTE, + buf.as_mut_ptr() as *mut c_void + ); + } + + let mut flipped_buf: Vec = Vec::new(); + + for y in 0..height { + let in_start = ((height - y - 1) * width * 4).try_into().unwrap(); + let in_slice = &buf[in_start..(in_start + (width * 4) as usize)]; + + flipped_buf.extend_from_slice(in_slice); + } + + flipped_buf +} + +fn write_framebuffer_to_png>(name: S, width: u32, height: u32) +{ + write_rgba_to_png( + name, + width, + height, + read_framebuffer_argb(width, height).as_slice() + ); +} + +fn create_context_and_run R>( + event_loop: &EventLoop<()>, + width: u32, + height: u32, + action: F +) -> R +{ + let context_builder = glutin::ContextBuilder::new() + .with_gl_debug_flag(true) + .with_multisampling(0) + .with_gl_profile(glutin::GlProfile::Core) + .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (2, 0))); + + let _context: Box = if cfg!(target_os = "windows") { + let context = context_builder + .build_windowed( + WindowBuilder::new().with_inner_size(PhysicalSize::new(width, height)), + &event_loop + ) + .unwrap(); + + let context = unsafe { context.make_current().unwrap() }; + + gl::load_with(|ptr| context.get_proc_address(ptr) as *const _); + + Box::new(context) + } else { + let context = context_builder + .with_vsync(false) + .build_headless(&event_loop, PhysicalSize::new(width, height)) + .unwrap(); + + let context = unsafe { context.make_current().unwrap() }; + + gl::load_with(|ptr| context.get_proc_address(ptr) as *const _); + + Box::new(context) + }; + + let mut renderer = + unsafe { GLRenderer::new_for_current_context((width, height)).unwrap() }; + + action(&mut renderer) +} + +fn run_test_with_new_context, F: FnOnce(&mut GLRenderer)>( + event_loop: &EventLoop<()>, + expected_image_name: S, + width: u32, + height: u32, + action: F +) +{ + let expected_image = read_png_argb8(expected_image_name.as_ref()); + + let actual_image = create_context_and_run(event_loop, width, height, |renderer| { + action(renderer); + + let actual_image = read_framebuffer_argb(width, height); + + if expected_image.is_none() + || (&expected_image).as_ref().unwrap() != &actual_image + { + write_framebuffer_to_png( + format!("{}_ACTUAL", expected_image_name.as_ref()), + width, + height + ); + } + + actual_image + }); + + let expected_image = expected_image.unwrap(); + + assert_eq!( + width * height * 4, + expected_image.len().try_into().unwrap(), + "Expected image size mismatch" + ); + + assert_eq!( + width * height * 4, + actual_image.len().try_into().unwrap(), + "Actual image size mismatch" + ); + + assert_eq!( + expected_image, + actual_image, + "Generated image did not match expected ({})", + expected_image_name.as_ref() + ); +} + +struct GLTest +{ + width: u32, + height: u32, + name: String, + action: Box +} + +fn main() +{ + simple_logger::SimpleLogger::new().init().unwrap(); + + let event_loop = EventLoop::new(); + + let mut tests = Vec::new(); + + tests.push(GLTest { + width: 50, + height: 50, + name: "basic_rectangles".to_string(), + action: Box::new(|renderer| { + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::BLUE); + + graphics.draw_rectangle( + Rectangle::from_tuples((10.0, 20.0), (30.0, 40.0)), + Color::MAGENTA + ); + + graphics.draw_rectangle( + Rectangle::from_tuples((15.0, 30.0), (49.0, 48.0)), + Color::GREEN + ); + }); + }) + }); + + tests.push(GLTest { + width: 50, + height: 50, + name: "lines_horizontal".to_string(), + action: Box::new(|renderer| { + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + + graphics.draw_line((10.0, 10.5), (30.0, 10.5), 1.0, Color::BLUE); + + graphics.draw_line((20.0, 14.0), (40.0, 14.0), 2.0, Color::DARK_GRAY); + + graphics.draw_line((1.0, 20.5), (49.0, 20.5), 5.0, Color::LIGHT_GRAY); + }); + }) + }); + + tests.push(GLTest { + width: 50, + height: 50, + name: "lines_vertical".to_string(), + action: Box::new(|renderer| { + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + + graphics.draw_line((10.5, 10.0), (10.5, 30.0), 1.0, Color::BLUE); + + graphics.draw_line((14.0, 20.0), (14.0, 40.0), 2.0, Color::DARK_GRAY); + + graphics.draw_line((20.5, 1.0), (20.5, 49.0), 5.0, Color::LIGHT_GRAY); + }); + }) + }); + + tests.push(GLTest { + width: 50, + height: 50, + name: "basic_circles".to_string(), + action: Box::new(|renderer| { + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + + graphics.draw_circle((20.0, 20.0), 10.0, Color::RED); + + graphics.draw_circle((40.0, 40.0), 5.0, Color::BLUE); + }); + }) + }); + + tests.push(GLTest { + width: 300, + height: 300, + name: "half_circle".to_string(), + action: Box::new(|renderer| { + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + + graphics.draw_circle_section_triangular_three_color( + [ + Vector2::new(100.0, 100.0), + Vector2::new(200.0, 100.0), + Vector2::new(200.0, 200.0) + ], + [ + Color::MAGENTA.clone(), + Color::MAGENTA.clone(), + Color::MAGENTA.clone() + ], + [ + Vector2::new(-1.0, -1.0), + Vector2::new(1.0, -1.0), + Vector2::new(1.0, 1.0) + ] + ); + }); + }) + }); + + tests.push(GLTest { + width: 1400, + height: 100, + name: "basic_text".to_string(), + action: Box::new(|renderer| { + let typeface = Font::new(NOTO_SANS_REGULAR_BYTES).unwrap(); + + let text = typeface.layout_text( + "The quick brown föx jumped over the lazy dog!", + 64.0, + TextOptions::new() + ); + + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + + graphics.draw_rectangle( + Rectangle::from_tuples( + (0.0, 0.0), + (text.width().round(), text.height().round()) + ), + Color::from_rgb(0.9, 0.9, 1.0) + ); + + graphics.draw_rectangle( + Rectangle::from_tuples( + (0.0, 0.0), + ( + text.width().round(), + text.iter_lines().next().unwrap().ascent().round() + ) + ), + Color::from_rgb(0.8, 0.8, 1.0) + ); + + graphics.draw_text(Vector2::new(0.0, 0.0), Color::BLACK, &text); + }); + }) + }); + + tests.push(GLTest { + width: 640, + height: 640, + name: "wrapped_text_1".to_string(), + action: Box::new(|renderer| { + let typeface = Font::new(NOTO_SANS_REGULAR_BYTES).unwrap(); + + let first_text = typeface.layout_text( + "The quick brown föx jumped over the lazy dog!", + 64.0, + TextOptions::new().with_wrap_to_width(400.0, TextAlignment::Left) + ); + + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + + graphics.draw_rectangle( + Rectangle::from_tuples( + (0.0, 0.0), + (first_text.width().round(), first_text.height().round()) + ), + Color::from_rgb(0.9, 0.9, 1.0) + ); + + graphics.draw_rectangle( + Rectangle::from_tuples( + (0.0, 0.0), + ( + first_text.width().round(), + first_text.iter_lines().next().unwrap().ascent().round() + ) + ), + Color::from_rgb(0.8, 0.8, 1.0) + ); + + graphics.draw_text((0.0, 0.0), Color::BLACK, &first_text); + + let small_width = 90.0; + + graphics.draw_rectangle( + Rectangle::from_tuples((100.0, 200.0), (100.0 + small_width, 640.0)), + Color::from_rgb(0.9, 0.9, 1.0) + ); + + graphics.draw_text( + (100.0, 200.0), + Color::BLACK, + &typeface.layout_text( + "The quick brown föx jumped over the lazy dog!", + 64.0, + TextOptions::new() + .with_wrap_to_width(small_width, TextAlignment::Left) + ) + ); + + let small_width = 30.0; + + graphics.draw_rectangle( + Rectangle::from_tuples((200.0, 200.0), (200.0 + small_width, 640.0)), + Color::from_rgb(0.9, 0.9, 1.0) + ); + + graphics.draw_text( + (200.0, 200.0), + Color::BLACK, + &typeface.layout_text( + "The quick brown föx jumped over the lazy dog!", + 64.0, + TextOptions::new() + .with_wrap_to_width(small_width, TextAlignment::Left) + ) + ); + }); + }) + }); + + tests.push(GLTest { + width: 640, + height: 640, + name: "text_tracking".to_string(), + action: Box::new(|renderer| { + let typeface = Font::new(NOTO_SANS_REGULAR_BYTES).unwrap(); + + let text = typeface.layout_text( + "The quick brown föx jumped over the lazy dog!", + 30.0, + TextOptions::new() + .with_wrap_to_width(400.0, TextAlignment::Left) + .with_tracking(100.0) + ); + + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + + graphics.draw_text((10.0, 10.0), Color::BLACK, &text); + }); + }) + }); + + tests.push(GLTest { + width: 640, + height: 640, + name: "text_alignment".to_string(), + action: Box::new(|renderer| { + let typeface = Font::new(NOTO_SANS_REGULAR_BYTES).unwrap(); + + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + + graphics.draw_rectangle( + Rectangle::from_tuples((10.0, 10.0), (410.0, 640.0)), + Color::from_rgb(0.9, 0.9, 1.0) + ); + + graphics.draw_text( + (10.0, 10.0), + Color::BLACK, + &typeface.layout_text( + "The quick brown föx jumped over the lazy dog!", + 40.0, + TextOptions::new() + .with_wrap_to_width(400.0, TextAlignment::Right) + ) + ); + + graphics.draw_text( + (10.0, 210.0), + Color::BLACK, + &typeface.layout_text( + "The quick brown föx jumped over the lazy dog!", + 40.0, + TextOptions::new() + .with_wrap_to_width(400.0, TextAlignment::Center) + ) + ); + }); + }) + }); + + tests.push(GLTest { + width: 640, + height: 640, + name: "text_line_spacing".to_string(), + action: Box::new(|renderer| { + let typeface = Font::new(NOTO_SANS_REGULAR_BYTES).unwrap(); + + renderer.draw_frame(|graphics| { + graphics.clear_screen(Color::WHITE); + + graphics.draw_rectangle( + Rectangle::from_tuples((10.0, 10.0), (410.0, 640.0)), + Color::from_rgb(0.9, 0.9, 1.0) + ); + + graphics.draw_text( + (10.0, 10.0), + Color::BLACK, + &typeface.layout_text( + "The quick brown föx jumped over the lazy dog!", + 40.0, + TextOptions::new() + .with_wrap_to_width(400.0, TextAlignment::Left) + .with_line_spacing_multiplier(0.7) + ) + ); + + graphics.draw_text( + (10.0, 210.0), + Color::BLACK, + &typeface.layout_text( + "The quick brown föx jumped over the lazy dog!", + 40.0, + TextOptions::new() + .with_wrap_to_width(400.0, TextAlignment::Left) + .with_line_spacing_multiplier(2.0) + ) + ); + }); + }) + }); + + for test in tests { + log::info!("Running test {}", test.name); + + run_test_with_new_context( + &event_loop, + test.name, + test.width, + test.height, + test.action + ); + } + + log::info!("All tests succeeded"); +}