Initial WebGL2 support. (#218)
Co-authored-by: MarkAnthonyM <37249494+MarkAnthonyM@users.noreply.github.com>
This commit is contained in:
parent
acd42495f2
commit
b185ec32e9
81
.github/workflows/ci.yml
vendored
81
.github/workflows/ci.yml
vendored
|
@ -32,33 +32,6 @@ jobs:
|
|||
with:
|
||||
command: check
|
||||
args: --all
|
||||
tests:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- 1.52.0
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Update apt repos
|
||||
run: sudo apt-get -y update
|
||||
- name: Install dependencies
|
||||
run: sudo apt -y install libsdl2-dev
|
||||
- name: Install toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
- name: Cargo test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
lints:
|
||||
name: Lints
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -91,3 +64,57 @@ jobs:
|
|||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all --tests -- -D warnings
|
||||
tests:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
needs: [checks, lints]
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- 1.52.0
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Update apt repos
|
||||
run: sudo apt-get -y update
|
||||
- name: Install dependencies
|
||||
run: sudo apt -y install libsdl2-dev
|
||||
- name: Install toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
- name: Cargo test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
wasm:
|
||||
name: WASM
|
||||
runs-on: ubuntu-latest
|
||||
needs: [checks, lints]
|
||||
strategy:
|
||||
matrix:
|
||||
example:
|
||||
- minimal-web
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Update apt repos
|
||||
run: sudo apt-get -y update
|
||||
- name: Install dependencies
|
||||
run: sudo apt -y install libsdl2-dev
|
||||
- name: Install toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
- name: Install tools
|
||||
run: cargo install --locked wasm-bindgen-cli just
|
||||
- name: Just build
|
||||
run: just build ${{ matrix.example }}
|
||||
|
|
|
@ -20,12 +20,14 @@ include = [
|
|||
|
||||
[dependencies]
|
||||
bytemuck = "1.7"
|
||||
pollster = "0.2"
|
||||
raw-window-handle = "0.3"
|
||||
thiserror = "1.0"
|
||||
ultraviolet = "0.8"
|
||||
wgpu = "0.11"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
pollster = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
pixels-mocks = { path = "internals/pixels-mocks" }
|
||||
winit = "0.25"
|
||||
|
|
|
@ -32,6 +32,7 @@ The Minimum Supported Rust Version for `pixels` will always be made available in
|
|||
- [Custom Shader](./examples/custom-shader)
|
||||
- [Dear ImGui example with `winit`](./examples/imgui-winit)
|
||||
- [Egui example with `winit`](./examples/minimal-egui)
|
||||
- [Minimal example for WebGL2](./examples/minimal-web)
|
||||
- [Minimal example with SDL2](./examples/minimal-sdl2)
|
||||
- [Minimal example with `winit`](./examples/minimal-winit)
|
||||
- [Minimal example with `fltk`](./examples/minimal-fltk)
|
||||
|
|
30
examples/minimal-web/Cargo.toml
Normal file
30
examples/minimal-web/Cargo.toml
Normal file
|
@ -0,0 +1,30 @@
|
|||
[package]
|
||||
name = "minimal-web"
|
||||
version = "0.1.0"
|
||||
authors = ["Jay Oster <jay@kodewerx.org>"]
|
||||
edition = "2018"
|
||||
resolver = "2"
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
optimize = ["log/release_max_level_warn"]
|
||||
web = ["wgpu/webgl", "winit/web-sys"]
|
||||
default = ["optimize"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
pixels = { path = "../.." }
|
||||
wgpu = "0.11"
|
||||
winit = "0.25"
|
||||
winit_input_helper = "0.10"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "0.2"
|
||||
wasm-bindgen = "0.2.78"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
web-sys = "0.3"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
env_logger = "0.9"
|
||||
pollster = "0.2"
|
42
examples/minimal-web/README.md
Normal file
42
examples/minimal-web/README.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Hello Pixels + Web
|
||||
|
||||
![Hello Pixels + Web](../../img/minimal-web.png)
|
||||
|
||||
Minimal example for WebGL2.
|
||||
|
||||
## Install build dependencies
|
||||
|
||||
Install the WASM32 target and a few CLI tools:
|
||||
|
||||
```bash
|
||||
rustup target add wasm32-unknown-unknown
|
||||
cargo install --locked wasm-bindgen-cli just miniserve
|
||||
```
|
||||
|
||||
## Running on the Web
|
||||
|
||||
Build the project and start a local server to host it:
|
||||
|
||||
```bash
|
||||
just serve minimal-web
|
||||
```
|
||||
|
||||
Open http://localhost:8080/ in your browser to run the example.
|
||||
|
||||
To build the project without serving it:
|
||||
|
||||
```bash
|
||||
just build minimal-web
|
||||
```
|
||||
|
||||
The build files are stored in `./target/minimal-web/`.
|
||||
|
||||
## Running on native targets
|
||||
|
||||
```bash
|
||||
cargo run --release --package minimal-web
|
||||
```
|
||||
|
||||
## About
|
||||
|
||||
This example is based on `minimal-winit`, demonstrating how to build your app for WebGL2 targets.
|
24
examples/minimal-web/index.html
Normal file
24
examples/minimal-web/index.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
background-color: #000;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
<title>Hello Pixels + Web</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module">
|
||||
import init from "./minimal-web.js";
|
||||
window.addEventListener("load", () => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
190
examples/minimal-web/src/main.rs
Normal file
190
examples/minimal-web/src/main.rs
Normal file
|
@ -0,0 +1,190 @@
|
|||
#![deny(clippy::all)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use log::error;
|
||||
use pixels::{Pixels, SurfaceTexture};
|
||||
use std::rc::Rc;
|
||||
use winit::dpi::LogicalSize;
|
||||
use winit::event::{Event, VirtualKeyCode};
|
||||
use winit::event_loop::{ControlFlow, EventLoop};
|
||||
use winit::window::WindowBuilder;
|
||||
use winit_input_helper::WinitInputHelper;
|
||||
|
||||
const WIDTH: u32 = 320;
|
||||
const HEIGHT: u32 = 240;
|
||||
const BOX_SIZE: i16 = 64;
|
||||
|
||||
/// Representation of the application state. In this example, a box will bounce around the screen.
|
||||
struct World {
|
||||
box_x: i16,
|
||||
box_y: i16,
|
||||
velocity_x: i16,
|
||||
velocity_y: i16,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||
console_log::init_with_level(log::Level::Trace).expect("error initializing logger");
|
||||
|
||||
wasm_bindgen_futures::spawn_local(run());
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
env_logger::init();
|
||||
|
||||
pollster::block_on(run());
|
||||
}
|
||||
}
|
||||
|
||||
async fn run() {
|
||||
let event_loop = EventLoop::new();
|
||||
let window = {
|
||||
let size = LogicalSize::new(WIDTH as f64, HEIGHT as f64);
|
||||
WindowBuilder::new()
|
||||
.with_title("Hello Pixels + Web")
|
||||
.with_inner_size(size)
|
||||
.with_min_inner_size(size)
|
||||
.build(&event_loop)
|
||||
.expect("WindowBuilder error")
|
||||
};
|
||||
|
||||
let window = Rc::new(window);
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
use wasm_bindgen::JsCast;
|
||||
use winit::platform::web::WindowExtWebSys;
|
||||
|
||||
// Retrieve current width and height dimensions of browser client window
|
||||
let get_window_size = || {
|
||||
let client_window = web_sys::window().unwrap();
|
||||
LogicalSize::new(
|
||||
client_window.inner_width().unwrap().as_f64().unwrap(),
|
||||
client_window.inner_height().unwrap().as_f64().unwrap(),
|
||||
)
|
||||
};
|
||||
|
||||
let window = Rc::clone(&window);
|
||||
|
||||
// Initialize winit window with current dimensions of browser client
|
||||
window.set_inner_size(get_window_size());
|
||||
|
||||
let client_window = web_sys::window().unwrap();
|
||||
|
||||
// Attach winit canvas to body element
|
||||
web_sys::window()
|
||||
.and_then(|win| win.document())
|
||||
.and_then(|doc| doc.body())
|
||||
.and_then(|body| {
|
||||
body.append_child(&web_sys::Element::from(window.canvas()))
|
||||
.ok()
|
||||
})
|
||||
.expect("couldn't append canvas to document body");
|
||||
|
||||
// Listen for resize event on browser client. Adjust winit window dimensions
|
||||
// on event trigger
|
||||
let closure = wasm_bindgen::closure::Closure::wrap(Box::new(move |_e: web_sys::Event| {
|
||||
let size = get_window_size();
|
||||
window.set_inner_size(size)
|
||||
}) as Box<dyn FnMut(_)>);
|
||||
client_window
|
||||
.add_event_listener_with_callback("resize", closure.as_ref().unchecked_ref())
|
||||
.unwrap();
|
||||
closure.forget();
|
||||
}
|
||||
|
||||
let mut input = WinitInputHelper::new();
|
||||
let mut pixels = {
|
||||
let window_size = window.inner_size();
|
||||
let surface_texture =
|
||||
SurfaceTexture::new(window_size.width, window_size.height, window.as_ref());
|
||||
Pixels::new_async(WIDTH, HEIGHT, surface_texture)
|
||||
.await
|
||||
.expect("Pixels error")
|
||||
};
|
||||
let mut world = World::new();
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
// Draw the current frame
|
||||
if let Event::RedrawRequested(_) = event {
|
||||
world.draw(pixels.get_frame());
|
||||
if pixels
|
||||
.render()
|
||||
.map_err(|e| error!("pixels.render() failed: {}", e))
|
||||
.is_err()
|
||||
{
|
||||
*control_flow = ControlFlow::Exit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle input events
|
||||
if input.update(&event) {
|
||||
// Close events
|
||||
if input.key_pressed(VirtualKeyCode::Escape) || input.quit() {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Resize the window
|
||||
if let Some(size) = input.window_resized() {
|
||||
pixels.resize_surface(size.width, size.height);
|
||||
}
|
||||
|
||||
// Update internal state and request a redraw
|
||||
world.update();
|
||||
window.request_redraw();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
impl World {
|
||||
/// Create a new `World` instance that can draw a moving box.
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
box_x: 24,
|
||||
box_y: 16,
|
||||
velocity_x: 1,
|
||||
velocity_y: 1,
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the `World` internal state; bounce the box around the screen.
|
||||
fn update(&mut self) {
|
||||
if self.box_x <= 0 || self.box_x + BOX_SIZE > WIDTH as i16 {
|
||||
self.velocity_x *= -1;
|
||||
}
|
||||
if self.box_y <= 0 || self.box_y + BOX_SIZE > HEIGHT as i16 {
|
||||
self.velocity_y *= -1;
|
||||
}
|
||||
|
||||
self.box_x += self.velocity_x;
|
||||
self.box_y += self.velocity_y;
|
||||
}
|
||||
|
||||
/// Draw the `World` state to the frame buffer.
|
||||
///
|
||||
/// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb`
|
||||
fn draw(&self, frame: &mut [u8]) {
|
||||
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
|
||||
let x = (i % WIDTH as usize) as i16;
|
||||
let y = (i / WIDTH as usize) as i16;
|
||||
|
||||
let inside_the_box = x >= self.box_x
|
||||
&& x < self.box_x + BOX_SIZE
|
||||
&& y >= self.box_y
|
||||
&& y < self.box_y + BOX_SIZE;
|
||||
|
||||
let rgba = if inside_the_box {
|
||||
[0x5e, 0x48, 0xe8, 0xff]
|
||||
} else {
|
||||
[0x48, 0xb2, 0xe8, 0xff]
|
||||
};
|
||||
|
||||
pixel.copy_from_slice(&rgba);
|
||||
}
|
||||
}
|
||||
}
|
BIN
img/minimal-web.png
Normal file
BIN
img/minimal-web.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
11
justfile
Normal file
11
justfile
Normal file
|
@ -0,0 +1,11 @@
|
|||
serve package: (build package)
|
||||
miniserve --index index.html ./target/{{package}}/
|
||||
|
||||
build package:
|
||||
mkdir -p ./target/{{package}}/
|
||||
cp ./examples/{{package}}/index.html ./target/{{package}}/
|
||||
cargo build --release --package {{package}} --target wasm32-unknown-unknown --features web
|
||||
wasm-bindgen --target web --no-typescript --out-dir ./target/{{package}}/ ./target/wasm32-unknown-unknown/release/{{package}}.wasm
|
||||
|
||||
clean package:
|
||||
rm -rf ./target/{{package}}/
|
|
@ -23,12 +23,14 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
|||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use pixels::wgpu::{PowerPreference, RequestAdapterOptions};
|
||||
///
|
||||
/// # use pixels::PixelsBuilder;
|
||||
/// # let window = pixels_mocks::Rwh;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(1024, 768, &window);
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(256, 240, &window);
|
||||
/// let mut pixels = PixelsBuilder::new(256, 240, surface_texture)
|
||||
/// .request_adapter_options(wgpu::RequestAdapterOptions {
|
||||
/// power_preference: wgpu::PowerPreference::HighPerformance,
|
||||
/// .request_adapter_options(RequestAdapterOptions {
|
||||
/// power_preference: PowerPreference::HighPerformance,
|
||||
/// force_fallback_adapter: false,
|
||||
/// compatible_surface: None,
|
||||
/// })
|
||||
|
@ -47,7 +49,17 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
|||
Self {
|
||||
request_adapter_options: None,
|
||||
device_descriptor: None,
|
||||
backend: wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::PRIMARY),
|
||||
backend: wgpu::util::backend_bits_from_env().unwrap_or({
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
wgpu::Backends::PRIMARY
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
wgpu::Backends::all()
|
||||
}
|
||||
}),
|
||||
width,
|
||||
height,
|
||||
_pixel_aspect_ratio: 1.0,
|
||||
|
@ -166,20 +178,24 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
|||
|
||||
/// Create a pixel buffer from the options builder.
|
||||
///
|
||||
/// This is the private implementation shared by [`PixelsBuilder::build`] and
|
||||
/// [`PixelsBuilder::build_async`].
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error when a [`wgpu::Adapter`] cannot be found.
|
||||
pub fn build(self) -> Result<Pixels, Error> {
|
||||
async fn build_impl(self) -> Result<Pixels, Error> {
|
||||
let instance = wgpu::Instance::new(self.backend);
|
||||
|
||||
// TODO: Use `options.pixel_aspect_ratio` to stretch the scaled texture
|
||||
let surface = unsafe { instance.create_surface(self.surface_texture.window) };
|
||||
let compatible_surface = Some(&surface);
|
||||
let request_adapter_options = &self.request_adapter_options;
|
||||
let adapter =
|
||||
wgpu::util::initialize_adapter_from_env(&instance, self.backend).or_else(|| {
|
||||
let future =
|
||||
instance.request_adapter(&request_adapter_options.as_ref().map_or_else(
|
||||
let adapter = match wgpu::util::initialize_adapter_from_env(&instance, self.backend) {
|
||||
Some(adapter) => Some(adapter),
|
||||
None => {
|
||||
instance
|
||||
.request_adapter(&request_adapter_options.as_ref().map_or_else(
|
||||
|| wgpu::RequestAdapterOptions {
|
||||
compatible_surface,
|
||||
force_fallback_adapter: false,
|
||||
|
@ -188,13 +204,14 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
|||
},
|
||||
|rao| wgpu::RequestAdapterOptions {
|
||||
compatible_surface: rao.compatible_surface.or(compatible_surface),
|
||||
force_fallback_adapter: false,
|
||||
force_fallback_adapter: rao.force_fallback_adapter,
|
||||
power_preference: rao.power_preference,
|
||||
},
|
||||
));
|
||||
))
|
||||
.await
|
||||
}
|
||||
};
|
||||
|
||||
pollster::block_on(future)
|
||||
});
|
||||
let adapter = adapter.ok_or(Error::AdapterNotFound)?;
|
||||
|
||||
let device_descriptor = self
|
||||
|
@ -204,7 +221,9 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
|||
..wgpu::DeviceDescriptor::default()
|
||||
});
|
||||
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(&device_descriptor, None))
|
||||
let (device, queue) = adapter
|
||||
.request_device(&device_descriptor, None)
|
||||
.await
|
||||
.map_err(Error::DeviceNotFound)?;
|
||||
|
||||
let present_mode = self.present_mode;
|
||||
|
@ -256,6 +275,45 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
|||
|
||||
Ok(pixels)
|
||||
}
|
||||
|
||||
/// Create a pixel buffer from the options builder.
|
||||
///
|
||||
/// This method blocks the current thread, making it unusable on Web targets. Use
|
||||
/// [`PixelsBuilder::build_async`] for a non-blocking alternative.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error when a [`wgpu::Adapter`] or [`wgpu::Device`] cannot be found.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn build(self) -> Result<Pixels, Error> {
|
||||
pollster::block_on(self.build_impl())
|
||||
}
|
||||
|
||||
/// Create a pixel buffer from the options builder without blocking the current thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use pixels::wgpu::{Backends, DeviceDescriptor, Limits};
|
||||
///
|
||||
/// # async fn test() -> Result<(), pixels::Error> {
|
||||
/// # use pixels::PixelsBuilder;
|
||||
/// # let window = pixels_mocks::Rwh;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(256, 240, &window);
|
||||
/// let mut pixels = PixelsBuilder::new(256, 240, surface_texture)
|
||||
/// .enable_vsync(false)
|
||||
/// .build_async()
|
||||
/// .await?;
|
||||
/// # Ok::<(), pixels::Error>(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error when a [`wgpu::Adapter`] or [`wgpu::Device`] cannot be found.
|
||||
pub async fn build_async(self) -> Result<Pixels, Error> {
|
||||
self.build_impl().await
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create_backing_texture(
|
||||
|
|
66
src/lib.rs
66
src/lib.rs
|
@ -142,10 +142,7 @@ impl<'win, W: HasRawWindowHandle> SurfaceTexture<'win, W> {
|
|||
/// let window = Window::new(&event_loop).unwrap();
|
||||
/// let size = window.inner_size();
|
||||
///
|
||||
/// let width = size.width;
|
||||
/// let height = size.height;
|
||||
///
|
||||
/// let surface_texture = SurfaceTexture::new(width, height, &window);
|
||||
/// let surface_texture = SurfaceTexture::new(size.width, size.height, &window);
|
||||
/// # Ok::<(), pixels::Error>(())
|
||||
/// ```
|
||||
///
|
||||
|
@ -173,12 +170,15 @@ impl Pixels {
|
|||
/// `320x240`, `640x480`, `960x720`, etc. without adding a border because these are exactly
|
||||
/// 1x, 2x, and 3x scales, respectively.
|
||||
///
|
||||
/// This method blocks the current thread, making it unusable on Web targets. Use
|
||||
/// [`Pixels::new_async`] for a non-blocking alternative.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use pixels::Pixels;
|
||||
/// # let window = pixels_mocks::Rwh;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(1024, 768, &window);
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(320, 240, &window);
|
||||
/// let mut pixels = Pixels::new(320, 240, surface_texture)?;
|
||||
/// # Ok::<(), pixels::Error>(())
|
||||
/// ```
|
||||
|
@ -190,6 +190,7 @@ impl Pixels {
|
|||
/// # Panics
|
||||
///
|
||||
/// Panics when `width` or `height` are 0.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn new<W: HasRawWindowHandle>(
|
||||
width: u32,
|
||||
height: u32,
|
||||
|
@ -198,6 +199,39 @@ impl Pixels {
|
|||
PixelsBuilder::new(width, height, surface_texture).build()
|
||||
}
|
||||
|
||||
/// Asynchronously create a pixel buffer instance with default options.
|
||||
///
|
||||
/// See [`Pixels::new`] for more information.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # async fn test() -> Result<(), pixels::Error> {
|
||||
/// # use pixels::Pixels;
|
||||
/// # let window = pixels_mocks::Rwh;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(320, 240, &window);
|
||||
/// let mut pixels = Pixels::new_async(320, 240, surface_texture).await?;
|
||||
/// # Ok::<(), pixels::Error>(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error when a [`wgpu::Adapter`] cannot be found.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics when `width` or `height` are 0.
|
||||
pub async fn new_async<W: HasRawWindowHandle>(
|
||||
width: u32,
|
||||
height: u32,
|
||||
surface_texture: SurfaceTexture<'_, W>,
|
||||
) -> Result<Self, Error> {
|
||||
PixelsBuilder::new(width, height, surface_texture)
|
||||
.build_async()
|
||||
.await
|
||||
}
|
||||
|
||||
/// Resize the pixel buffer and zero its contents.
|
||||
///
|
||||
/// This does not resize the surface upon which the pixel buffer texture is rendered. Use
|
||||
|
@ -291,7 +325,7 @@ impl Pixels {
|
|||
/// ```no_run
|
||||
/// # use pixels::Pixels;
|
||||
/// # let window = pixels_mocks::Rwh;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(1024, 768, &window);
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(320, 240, &window);
|
||||
/// let mut pixels = Pixels::new(320, 240, surface_texture)?;
|
||||
///
|
||||
/// // Clear the pixel buffer
|
||||
|
@ -336,7 +370,7 @@ impl Pixels {
|
|||
/// ```no_run
|
||||
/// # use pixels::Pixels;
|
||||
/// # let window = pixels_mocks::Rwh;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(1024, 768, &window);
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(320, 240, &window);
|
||||
/// let mut pixels = Pixels::new(320, 240, surface_texture)?;
|
||||
///
|
||||
/// // Clear the pixel buffer
|
||||
|
@ -449,16 +483,15 @@ impl Pixels {
|
|||
/// the screen, using isize instead of usize.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use winit::dpi::PhysicalPosition;
|
||||
///
|
||||
/// # use pixels::Pixels;
|
||||
/// # let window = pixels_mocks::Rwh;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(1024, 768, &window);
|
||||
/// const WIDTH: u32 = 320;
|
||||
/// const HEIGHT: u32 = 240;
|
||||
///
|
||||
/// let mut pixels = Pixels::new(WIDTH, HEIGHT, surface_texture)?;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(320, 240, &window);
|
||||
/// let mut pixels = Pixels::new(320, 240, surface_texture)?;
|
||||
///
|
||||
/// // A cursor position in physical units
|
||||
/// let cursor_position: (f32, f32) = winit::dpi::PhysicalPosition::new(0.0, 0.0).into();
|
||||
/// let cursor_position: (f32, f32) = PhysicalPosition::new(0.0, 0.0).into();
|
||||
///
|
||||
/// // Convert it to a pixel location
|
||||
/// let pixel_position: (usize, usize) = pixels.window_pos_to_pixel(cursor_position)
|
||||
|
@ -509,11 +542,8 @@ impl Pixels {
|
|||
/// ```no_run
|
||||
/// # use pixels::Pixels;
|
||||
/// # let window = pixels_mocks::Rwh;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(1024, 768, &window);
|
||||
/// const WIDTH: u32 = 320;
|
||||
/// const HEIGHT: u32 = 240;
|
||||
///
|
||||
/// let mut pixels = Pixels::new(WIDTH, HEIGHT, surface_texture)?;
|
||||
/// # let surface_texture = pixels::SurfaceTexture::new(320, 240, &window);
|
||||
/// let mut pixels = Pixels::new(320, 240, surface_texture)?;
|
||||
///
|
||||
/// let pixel_pos = pixels.clamp_pixel_pos((-19, 20));
|
||||
/// assert_eq!(pixel_pos, (0, 20));
|
||||
|
|
Loading…
Reference in a new issue