Bump wgpu from 0.13
to 0.14
(#320)
* feat(wgpu): upgrade wgpu from 13 to 14 * Address feedback * Bump tao in `minimal-tao` example * Bump fltk in `minimal-fltk` example * Bump egui in `minimal-egui` example * Bump MSRV to `1.65` * Bump crates in `imgui-winit` example * Delete `minimal-sdl2` example * Fix clippy lints * Update examples/minimal-egui/src/gui.rs Co-authored-by: Zageron <hello@zageron.ca> Co-authored-by: Jay Oster <jay@kodewerx.org>
This commit is contained in:
parent
bc8235fdb1
commit
e8d5cf3ebc
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
||||||
rust:
|
rust:
|
||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- 1.61.0
|
- 1.65.0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
@ -73,7 +73,7 @@ jobs:
|
||||||
rust:
|
rust:
|
||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- 1.61.0
|
- 1.65.0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
|
@ -21,10 +21,13 @@ include = [
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = "1.12"
|
bytemuck = "1.12"
|
||||||
raw-window-handle = "0.4"
|
raw-window-handle = "0.5"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
ultraviolet = "0.9"
|
ultraviolet = "0.9"
|
||||||
wgpu = "0.13"
|
wgpu = "0.14"
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
wgpu = { version = "0.14", features = ["webgl"] }
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
pollster = "0.2"
|
pollster = "0.2"
|
||||||
|
|
2
MSRV.md
2
MSRV.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
| `pixels` version | `rustc` version |
|
| `pixels` version | `rustc` version |
|
||||||
|------------------|-----------------|
|
|------------------|-----------------|
|
||||||
| `0.11.0` | `1.61.0` |
|
| `0.11.0` | `1.65.0` |
|
||||||
| `0.10.0` | `1.61.0` |
|
| `0.10.0` | `1.61.0` |
|
||||||
| `0.9.0` | `1.57.0` |
|
| `0.9.0` | `1.57.0` |
|
||||||
| `0.8.0` | `1.52.0` |
|
| `0.8.0` | `1.52.0` |
|
||||||
|
|
|
@ -33,7 +33,6 @@ The Minimum Supported Rust Version for `pixels` will always be made available in
|
||||||
- [Dear ImGui example with `winit`](./examples/imgui-winit)
|
- [Dear ImGui example with `winit`](./examples/imgui-winit)
|
||||||
- [Egui example with `winit`](./examples/minimal-egui)
|
- [Egui example with `winit`](./examples/minimal-egui)
|
||||||
- [Minimal example for WebGL2](./examples/minimal-web)
|
- [Minimal example for WebGL2](./examples/minimal-web)
|
||||||
- [Minimal example with SDL2](./examples/minimal-sdl2)
|
|
||||||
- [Minimal example with `winit`](./examples/minimal-winit)
|
- [Minimal example with `winit`](./examples/minimal-winit)
|
||||||
- [Minimal example with `tao`](./examples/minimal-tao)
|
- [Minimal example with `tao`](./examples/minimal-tao)
|
||||||
- [Minimal example with `fltk`](./examples/minimal-fltk)
|
- [Minimal example with `fltk`](./examples/minimal-fltk)
|
||||||
|
|
|
@ -196,7 +196,7 @@ impl Cell {
|
||||||
|
|
||||||
fn cool_off(&mut self, decay: f32) {
|
fn cool_off(&mut self, decay: f32) {
|
||||||
if !self.alive {
|
if !self.alive {
|
||||||
let heat = (self.heat as f32 * decay).min(255.0).max(0.0);
|
let heat = (self.heat as f32 * decay).clamp(0.0, 255.0);
|
||||||
assert!(heat.is_finite());
|
assert!(heat.is_finite());
|
||||||
self.heat = heat as u8;
|
self.heat = heat as u8;
|
||||||
}
|
}
|
||||||
|
@ -313,8 +313,8 @@ impl ConwayGrid {
|
||||||
// probably should do sutherland-hodgeman if this were more serious.
|
// probably should do sutherland-hodgeman if this were more serious.
|
||||||
// instead just clamp the start pos, and draw until moving towards the
|
// instead just clamp the start pos, and draw until moving towards the
|
||||||
// end pos takes us out of bounds.
|
// end pos takes us out of bounds.
|
||||||
let x0 = x0.max(0).min(self.width as isize);
|
let x0 = x0.clamp(0, self.width as isize);
|
||||||
let y0 = y0.max(0).min(self.height as isize);
|
let y0 = y0.clamp(0, self.height as isize);
|
||||||
for (x, y) in line_drawing::Bresenham::new((x0, y0), (x1, y1)) {
|
for (x, y) in line_drawing::Bresenham::new((x0, y0), (x1, y1)) {
|
||||||
if let Some(i) = self.grid_idx(x, y) {
|
if let Some(i) = self.grid_idx(x, y) {
|
||||||
self.cells[i].set_alive(alive);
|
self.cells[i].set_alive(alive);
|
||||||
|
|
|
@ -11,10 +11,10 @@ default = ["optimize"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
imgui = "0.8"
|
imgui = "0.9"
|
||||||
imgui-wgpu = "0.20"
|
imgui-wgpu = "0.21"
|
||||||
imgui-winit-support = { version = "0.8", default-features = false, features = ["winit-26"] }
|
imgui-winit-support = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
winit = "0.26"
|
winit = "0.27"
|
||||||
winit_input_helper = "0.12"
|
winit_input_helper = "0.13"
|
||||||
|
|
|
@ -87,14 +87,14 @@ impl Gui {
|
||||||
let mouse_cursor = ui.mouse_cursor();
|
let mouse_cursor = ui.mouse_cursor();
|
||||||
if self.last_cursor != mouse_cursor {
|
if self.last_cursor != mouse_cursor {
|
||||||
self.last_cursor = mouse_cursor;
|
self.last_cursor = mouse_cursor;
|
||||||
self.platform.prepare_render(&ui, window);
|
self.platform.prepare_render(ui, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw windows and GUI elements here
|
// Draw windows and GUI elements here
|
||||||
let mut about_open = false;
|
let mut about_open = false;
|
||||||
ui.main_menu_bar(|| {
|
ui.main_menu_bar(|| {
|
||||||
ui.menu("Help", || {
|
ui.menu("Help", || {
|
||||||
about_open = imgui::MenuItem::new("About...").build(&ui);
|
about_open = ui.menu_item("About...");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if about_open {
|
if about_open {
|
||||||
|
@ -119,8 +119,12 @@ impl Gui {
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.renderer
|
self.renderer.render(
|
||||||
.render(ui.render(), &context.queue, &context.device, &mut rpass)
|
self.imgui.render(),
|
||||||
|
&context.queue,
|
||||||
|
&context.device,
|
||||||
|
&mut rpass,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle any outstanding events.
|
/// Handle any outstanding events.
|
||||||
|
|
|
@ -67,7 +67,7 @@ fn load_pcx(pcx: &[u8]) -> CachedSprite {
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
buffer.resize_with(width * height, Default::default);
|
buffer.resize_with(width * height, Default::default);
|
||||||
for y in 0..height {
|
for y in 0..height {
|
||||||
let a = y as usize * width;
|
let a = y * width;
|
||||||
let b = a + width;
|
let b = a + width;
|
||||||
reader.next_row_paletted(&mut buffer[a..b]).unwrap();
|
reader.next_row_paletted(&mut buffer[a..b]).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@ optimize = ["log/release_max_level_warn"]
|
||||||
default = ["optimize"]
|
default = ["optimize"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
egui = "0.19"
|
egui = "0.20"
|
||||||
egui-wgpu = "0.19"
|
egui-wgpu = "0.20"
|
||||||
egui-winit = { version = "0.19", default-features = false, features = ["links"] }
|
egui-winit = { version = "0.20", default-features = false, features = ["links"] }
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use egui::{ClippedPrimitive, Context, TexturesDelta};
|
use egui::{ClippedPrimitive, Context, TexturesDelta};
|
||||||
use egui_wgpu::renderer::{RenderPass, ScreenDescriptor};
|
use egui_wgpu::renderer::{Renderer, ScreenDescriptor};
|
||||||
use pixels::{wgpu, PixelsContext};
|
use pixels::{wgpu, PixelsContext};
|
||||||
use winit::event_loop::EventLoopWindowTarget;
|
use winit::event_loop::EventLoopWindowTarget;
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
@ -10,7 +10,7 @@ pub(crate) struct Framework {
|
||||||
egui_ctx: Context,
|
egui_ctx: Context,
|
||||||
egui_state: egui_winit::State,
|
egui_state: egui_winit::State,
|
||||||
screen_descriptor: ScreenDescriptor,
|
screen_descriptor: ScreenDescriptor,
|
||||||
rpass: RenderPass,
|
renderer: Renderer,
|
||||||
paint_jobs: Vec<ClippedPrimitive>,
|
paint_jobs: Vec<ClippedPrimitive>,
|
||||||
textures: TexturesDelta,
|
textures: TexturesDelta,
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ impl Framework {
|
||||||
size_in_pixels: [width, height],
|
size_in_pixels: [width, height],
|
||||||
pixels_per_point: scale_factor,
|
pixels_per_point: scale_factor,
|
||||||
};
|
};
|
||||||
let rpass = RenderPass::new(pixels.device(), pixels.render_texture_format(), 1);
|
let renderer = Renderer::new(pixels.device(), pixels.render_texture_format(), None, 1);
|
||||||
let textures = TexturesDelta::default();
|
let textures = TexturesDelta::default();
|
||||||
let gui = Gui::new();
|
let gui = Gui::new();
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ impl Framework {
|
||||||
egui_ctx,
|
egui_ctx,
|
||||||
egui_state,
|
egui_state,
|
||||||
screen_descriptor,
|
screen_descriptor,
|
||||||
rpass,
|
renderer,
|
||||||
paint_jobs: Vec::new(),
|
paint_jobs: Vec::new(),
|
||||||
textures,
|
textures,
|
||||||
gui,
|
gui,
|
||||||
|
@ -60,7 +60,7 @@ impl Framework {
|
||||||
|
|
||||||
/// Handle input events from the window manager.
|
/// Handle input events from the window manager.
|
||||||
pub(crate) fn handle_event(&mut self, event: &winit::event::WindowEvent) {
|
pub(crate) fn handle_event(&mut self, event: &winit::event::WindowEvent) {
|
||||||
self.egui_state.on_event(&self.egui_ctx, event);
|
let _ = self.egui_state.on_event(&self.egui_ctx, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resize egui.
|
/// Resize egui.
|
||||||
|
@ -99,29 +99,40 @@ impl Framework {
|
||||||
) {
|
) {
|
||||||
// Upload all resources to the GPU.
|
// Upload all resources to the GPU.
|
||||||
for (id, image_delta) in &self.textures.set {
|
for (id, image_delta) in &self.textures.set {
|
||||||
self.rpass
|
self.renderer
|
||||||
.update_texture(&context.device, &context.queue, *id, image_delta);
|
.update_texture(&context.device, &context.queue, *id, image_delta);
|
||||||
}
|
}
|
||||||
self.rpass.update_buffers(
|
self.renderer.update_buffers(
|
||||||
&context.device,
|
&context.device,
|
||||||
&context.queue,
|
&context.queue,
|
||||||
|
encoder,
|
||||||
&self.paint_jobs,
|
&self.paint_jobs,
|
||||||
&self.screen_descriptor,
|
&self.screen_descriptor,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Record all render passes.
|
// Render egui with WGPU
|
||||||
self.rpass.execute(
|
{
|
||||||
encoder,
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
render_target,
|
label: Some("egui"),
|
||||||
&self.paint_jobs,
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
&self.screen_descriptor,
|
view: render_target,
|
||||||
None,
|
resolve_target: None,
|
||||||
);
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||||
|
store: true,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.renderer
|
||||||
|
.render(&mut rpass, &self.paint_jobs, &self.screen_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
let textures = std::mem::take(&mut self.textures);
|
let textures = std::mem::take(&mut self.textures);
|
||||||
for id in &textures.free {
|
for id in &textures.free {
|
||||||
self.rpass.free_texture(id);
|
self.renderer.free_texture(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ optimize = ["log/release_max_level_warn"]
|
||||||
default = ["optimize"]
|
default = ["optimize"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fltk = { version = "=1.3.13", features = ["raw-window-handle", "no-images", "no-pango"] }
|
fltk = { version = "1.3.17", features = ["rwh05", "no-images", "no-pango"] }
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "minimal-sdl2"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Jay Oster <jay@kodewerx.org>"]
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[features]
|
|
||||||
optimize = ["log/release_max_level_warn"]
|
|
||||||
default = ["optimize"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
env_logger = "0.9"
|
|
||||||
fermium = { version = "20022.0.0", features = ["raw-window-handle"] }
|
|
||||||
log = "0.4"
|
|
||||||
pixels = { path = "../.." }
|
|
||||||
thiserror = "1.0"
|
|
||||||
zstring = "0.1"
|
|
|
@ -1,15 +0,0 @@
|
||||||
# Hello Pixels
|
|
||||||
|
|
||||||
![Hello Pixels](../../img/minimal-sdl2.png)
|
|
||||||
|
|
||||||
Minimal example with SDL2 using `beryllium`.
|
|
||||||
|
|
||||||
## Running
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo run --release --package minimal-sdl2
|
|
||||||
```
|
|
||||||
|
|
||||||
## About
|
|
||||||
|
|
||||||
This example demonstrates the absolute minimum for creating an SDL2 window and pixel buffer. It animates a purple box moving on a blue background, just for _something_ interesting to display.
|
|
|
@ -1,105 +0,0 @@
|
||||||
#![deny(clippy::all)]
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
|
||||||
|
|
||||||
use crate::sdl::{Event, Sdl};
|
|
||||||
use pixels::{Pixels, SurfaceTexture};
|
|
||||||
use zstring::zstr;
|
|
||||||
|
|
||||||
mod sdl;
|
|
||||||
|
|
||||||
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() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
env_logger::init();
|
|
||||||
|
|
||||||
let sdl = Sdl::new(zstr!("Hello Pixels"), WIDTH, HEIGHT)?;
|
|
||||||
|
|
||||||
let mut pixels = {
|
|
||||||
let (width, height) = sdl.drawable_size();
|
|
||||||
let surface_texture = SurfaceTexture::new(width, height, &sdl);
|
|
||||||
Pixels::new(WIDTH, HEIGHT, surface_texture)?
|
|
||||||
};
|
|
||||||
let mut world = World::new();
|
|
||||||
|
|
||||||
'game_loop: loop {
|
|
||||||
while let Some(event) = sdl.poll_event() {
|
|
||||||
match event {
|
|
||||||
// Close events
|
|
||||||
Event::Quit { .. } => break 'game_loop,
|
|
||||||
Event::Keyboard(key) if key == fermium::keycode::SDLK_ESCAPE => break 'game_loop,
|
|
||||||
|
|
||||||
// Resize the window
|
|
||||||
Event::WindowResized { width, height, .. } => pixels.resize_surface(width, height),
|
|
||||||
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update internal state
|
|
||||||
world.update();
|
|
||||||
|
|
||||||
// Draw the current frame
|
|
||||||
world.draw(pixels.get_frame_mut());
|
|
||||||
pixels.render()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
//! This module implements the bare minimum of a high-level abstraction for SDL2 over fermium.
|
|
||||||
//!
|
|
||||||
//! We used to use beryllium, but that crate has lagged behind fermium in maintenance releases.
|
|
||||||
|
|
||||||
use ::pixels::raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
|
||||||
use fermium::prelude::*;
|
|
||||||
use thiserror::Error;
|
|
||||||
use zstring::ZStr;
|
|
||||||
|
|
||||||
pub struct Sdl {
|
|
||||||
sdl_win: *mut SDL_Window,
|
|
||||||
_winfo: SDL_SysWMinfo,
|
|
||||||
rwh: RawWindowHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum SdlError {
|
|
||||||
#[error("SDL init failed")]
|
|
||||||
Init,
|
|
||||||
|
|
||||||
#[error("Invalid pixel buffer size")]
|
|
||||||
Size,
|
|
||||||
|
|
||||||
#[error("Create SDL window failed")]
|
|
||||||
Window,
|
|
||||||
|
|
||||||
#[error("Create SDL WM Info failed")]
|
|
||||||
WMinfo,
|
|
||||||
|
|
||||||
#[error("Create Window Handle failed")]
|
|
||||||
WindowHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Event {
|
|
||||||
Quit,
|
|
||||||
Keyboard(SDL_Keycode),
|
|
||||||
WindowResized { width: u32, height: u32 },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sdl {
|
|
||||||
pub fn new(title: ZStr, width: u32, height: u32) -> Result<Self, SdlError> {
|
|
||||||
// SAFETY: Ensure SDL is initialized and we get a non-null Window pointer.
|
|
||||||
unsafe {
|
|
||||||
if SDL_Init(SDL_INIT_EVERYTHING) != 0 {
|
|
||||||
return Err(SdlError::Init);
|
|
||||||
}
|
|
||||||
|
|
||||||
let window_type = if cfg!(target_os = "macos") {
|
|
||||||
SDL_WINDOW_METAL
|
|
||||||
} else {
|
|
||||||
SDL_WINDOW_VULKAN
|
|
||||||
};
|
|
||||||
|
|
||||||
let sdl_win = SDL_CreateWindow(
|
|
||||||
title.as_ptr() as *const i8,
|
|
||||||
SDL_WINDOWPOS_CENTERED,
|
|
||||||
SDL_WINDOWPOS_CENTERED,
|
|
||||||
width.try_into().map_err(|_| SdlError::Size)?,
|
|
||||||
height.try_into().map_err(|_| SdlError::Size)?,
|
|
||||||
(window_type | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE).0,
|
|
||||||
);
|
|
||||||
if sdl_win.is_null() {
|
|
||||||
return Err(SdlError::Window);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut winfo = SDL_SysWMinfo::default();
|
|
||||||
if SDL_GetWindowWMInfo(sdl_win, &mut winfo) == SDL_FALSE {
|
|
||||||
return Err(SdlError::WMinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
let rwh = winfo.try_into().ok_or(SdlError::WindowHandle)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
sdl_win,
|
|
||||||
_winfo: winfo,
|
|
||||||
rwh,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: Fermium doesn't support `SDL_Metal_GetDrawableSize`
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
pub fn drawable_size(&self) -> (u32, u32) {
|
|
||||||
// SAFETY: We have a valid Vulkan window.
|
|
||||||
unsafe {
|
|
||||||
let mut width = 0;
|
|
||||||
let mut height = 0;
|
|
||||||
SDL_Vulkan_GetDrawableSize(self.sdl_win, &mut width, &mut height);
|
|
||||||
|
|
||||||
(width.try_into().unwrap(), height.try_into().unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn poll_event(&self) -> Option<Event> {
|
|
||||||
let mut e = SDL_Event::default();
|
|
||||||
if unsafe { SDL_PollEvent(&mut e) } == 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Event::try_from(e).ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl HasRawWindowHandle for Sdl {
|
|
||||||
fn raw_window_handle(&self) -> RawWindowHandle {
|
|
||||||
self.rwh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<SDL_Event> for Event {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(event: SDL_Event) -> Result<Self, Self::Error> {
|
|
||||||
// SAFETY: Only access union fields in when the combinations are known to be valid.
|
|
||||||
unsafe {
|
|
||||||
Ok(match event.type_ {
|
|
||||||
SDL_QUIT => Self::Quit,
|
|
||||||
SDL_KEYDOWN | SDL_KEYUP => Self::Keyboard(event.key.keysym.sym),
|
|
||||||
SDL_WINDOWEVENT => match event.window.event {
|
|
||||||
SDL_WINDOWEVENT_RESIZED => Self::WindowResized {
|
|
||||||
width: event.window.data1 as _,
|
|
||||||
height: event.window.data2 as _,
|
|
||||||
},
|
|
||||||
_ => return Err(()),
|
|
||||||
},
|
|
||||||
_ => return Err(()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,4 +13,4 @@ default = ["optimize"]
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pixels = { path = "../.." }
|
pixels = { path = "../.." }
|
||||||
tao = "0.12"
|
tao = "0.15"
|
||||||
|
|
|
@ -20,8 +20,7 @@ console_error_panic_hook = "0.1"
|
||||||
console_log = "0.2"
|
console_log = "0.2"
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
web-sys = "0.3"
|
web-sys = { version = "0.3", features = ["GpuTextureFormat"] }
|
||||||
wgpu = { version = "0.13", features = ["webgl"] }
|
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
|
|
|
@ -6,4 +6,4 @@ edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
raw-window-handle = "0.4"
|
raw-window-handle = "0.5"
|
||||||
|
|
|
@ -5,7 +5,9 @@ pub struct Rwh;
|
||||||
unsafe impl raw_window_handle::HasRawWindowHandle for Rwh {
|
unsafe impl raw_window_handle::HasRawWindowHandle for Rwh {
|
||||||
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
|
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
return raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitHandle::empty());
|
return raw_window_handle::RawWindowHandle::AppKit(
|
||||||
|
raw_window_handle::AppKitWindowHandle::empty(),
|
||||||
|
);
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
target_os = "linux",
|
target_os = "linux",
|
||||||
target_os = "dragonfly",
|
target_os = "dragonfly",
|
||||||
|
@ -14,11 +16,42 @@ unsafe impl raw_window_handle::HasRawWindowHandle for Rwh {
|
||||||
target_os = "openbsd",
|
target_os = "openbsd",
|
||||||
))]
|
))]
|
||||||
return raw_window_handle::RawWindowHandle::Wayland(
|
return raw_window_handle::RawWindowHandle::Wayland(
|
||||||
raw_window_handle::WaylandHandle::empty(),
|
raw_window_handle::WaylandWindowHandle::empty(),
|
||||||
);
|
);
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
return raw_window_handle::RawWindowHandle::Win32(raw_window_handle::Win32Handle::empty());
|
return raw_window_handle::RawWindowHandle::Win32(
|
||||||
|
raw_window_handle::Win32WindowHandle::empty(),
|
||||||
|
);
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
return raw_window_handle::RawWindowHandle::UiKit(raw_window_handle::UiKitHandle::empty());
|
return raw_window_handle::RawWindowHandle::UiKit(
|
||||||
|
raw_window_handle::UiKitWindowHandle::empty(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl raw_window_handle::HasRawDisplayHandle for Rwh {
|
||||||
|
fn raw_display_handle(&self) -> raw_window_handle::RawDisplayHandle {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
return raw_window_handle::RawDisplayHandle::AppKit(
|
||||||
|
raw_window_handle::AppKitDisplayHandle::empty(),
|
||||||
|
);
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "dragonfly",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "openbsd",
|
||||||
|
))]
|
||||||
|
return raw_window_handle::RawDisplayHandle::Wayland(
|
||||||
|
raw_window_handle::WaylandDisplayHandle::empty(),
|
||||||
|
);
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
return raw_window_handle::RawDisplayHandle::Windows(
|
||||||
|
raw_window_handle::WindowsDisplayHandle::empty(),
|
||||||
|
);
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
|
return raw_window_handle::RawDisplayHandle::UiKit(
|
||||||
|
raw_window_handle::UiKitDisplayHandle::empty(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::renderers::{ScalingMatrix, ScalingRenderer};
|
use crate::renderers::{ScalingMatrix, ScalingRenderer};
|
||||||
use crate::SurfaceSize;
|
use crate::SurfaceSize;
|
||||||
use crate::{Error, Pixels, PixelsContext, SurfaceTexture};
|
use crate::{Error, Pixels, PixelsContext, SurfaceTexture};
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||||
|
|
||||||
/// A builder to help create customized pixel buffers.
|
/// A builder to help create customized pixel buffers.
|
||||||
pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle> {
|
pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle + HasRawDisplayHandle> {
|
||||||
request_adapter_options: Option<wgpu::RequestAdapterOptions<'req>>,
|
request_adapter_options: Option<wgpu::RequestAdapterOptions<'req>>,
|
||||||
device_descriptor: Option<wgpu::DeviceDescriptor<'dev>>,
|
device_descriptor: Option<wgpu::DeviceDescriptor<'dev>>,
|
||||||
backend: wgpu::Backends,
|
backend: wgpu::Backends,
|
||||||
|
@ -20,7 +20,9 @@ pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle> {
|
||||||
blend_state: wgpu::BlendState,
|
blend_state: wgpu::BlendState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W> {
|
impl<'req, 'dev, 'win, W: HasRawWindowHandle + HasRawDisplayHandle>
|
||||||
|
PixelsBuilder<'req, 'dev, 'win, W>
|
||||||
|
{
|
||||||
/// Create a builder that can be finalized into a [`Pixels`] pixel buffer.
|
/// Create a builder that can be finalized into a [`Pixels`] pixel buffer.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -325,6 +327,8 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
||||||
let mut pixels = Vec::with_capacity(pixels_buffer_size);
|
let mut pixels = Vec::with_capacity(pixels_buffer_size);
|
||||||
pixels.resize_with(pixels_buffer_size, Default::default);
|
pixels.resize_with(pixels_buffer_size, Default::default);
|
||||||
|
|
||||||
|
let alpha_mode = surface.get_supported_alpha_modes(&adapter)[0];
|
||||||
|
|
||||||
// Instantiate the Pixels struct
|
// Instantiate the Pixels struct
|
||||||
let context = PixelsContext {
|
let context = PixelsContext {
|
||||||
device,
|
device,
|
||||||
|
@ -346,6 +350,7 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
|
||||||
blend_state,
|
blend_state,
|
||||||
pixels,
|
pixels,
|
||||||
scaling_matrix_inverse,
|
scaling_matrix_inverse,
|
||||||
|
alpha_mode,
|
||||||
};
|
};
|
||||||
pixels.reconfigure_surface();
|
pixels.reconfigure_surface();
|
||||||
|
|
||||||
|
@ -488,7 +493,8 @@ const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
|
||||||
| Rg8Snorm
|
| Rg8Snorm
|
||||||
| Rg8Uint
|
| Rg8Uint
|
||||||
| Rg8Sint
|
| Rg8Sint
|
||||||
| Rgb9e5Ufloat => 2.0, // 16.0 / 8.0
|
| Rgb9e5Ufloat
|
||||||
|
| Depth16Unorm => 2.0, // 16.0 / 8.0
|
||||||
|
|
||||||
// 32-bit formats, 8 bits per component
|
// 32-bit formats, 8 bits per component
|
||||||
R32Uint
|
R32Uint
|
||||||
|
@ -510,8 +516,7 @@ const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
|
||||||
| Rg11b10Float
|
| Rg11b10Float
|
||||||
| Depth32Float
|
| Depth32Float
|
||||||
| Depth24Plus
|
| Depth24Plus
|
||||||
| Depth24PlusStencil8
|
| Depth24PlusStencil8 => 4.0, // 32.0 / 8.0
|
||||||
| Depth24UnormStencil8 => 4.0, // 32.0 / 8.0
|
|
||||||
|
|
||||||
// 64-bit formats, 8 bits per component
|
// 64-bit formats, 8 bits per component
|
||||||
Rg32Uint
|
Rg32Uint
|
||||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -34,7 +34,7 @@
|
||||||
pub use crate::builder::PixelsBuilder;
|
pub use crate::builder::PixelsBuilder;
|
||||||
pub use crate::renderers::ScalingRenderer;
|
pub use crate::renderers::ScalingRenderer;
|
||||||
pub use raw_window_handle;
|
pub use raw_window_handle;
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
pub use wgpu;
|
pub use wgpu;
|
||||||
|
@ -44,7 +44,7 @@ mod renderers;
|
||||||
|
|
||||||
/// A logical texture for a window surface.
|
/// A logical texture for a window surface.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SurfaceTexture<'win, W: HasRawWindowHandle> {
|
pub struct SurfaceTexture<'win, W: HasRawWindowHandle + HasRawDisplayHandle> {
|
||||||
window: &'win W,
|
window: &'win W,
|
||||||
size: SurfaceSize,
|
size: SurfaceSize,
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,7 @@ pub struct Pixels {
|
||||||
render_texture_format: wgpu::TextureFormat,
|
render_texture_format: wgpu::TextureFormat,
|
||||||
surface_texture_format: wgpu::TextureFormat,
|
surface_texture_format: wgpu::TextureFormat,
|
||||||
blend_state: wgpu::BlendState,
|
blend_state: wgpu::BlendState,
|
||||||
|
alpha_mode: wgpu::CompositeAlphaMode,
|
||||||
|
|
||||||
// Pixel buffer
|
// Pixel buffer
|
||||||
pixels: Vec<u8>,
|
pixels: Vec<u8>,
|
||||||
|
@ -127,7 +128,7 @@ pub enum Error {
|
||||||
|
|
||||||
type DynError = Box<dyn std::error::Error + Send + Sync + 'static>;
|
type DynError = Box<dyn std::error::Error + Send + Sync + 'static>;
|
||||||
|
|
||||||
impl<'win, W: HasRawWindowHandle> SurfaceTexture<'win, W> {
|
impl<'win, W: HasRawWindowHandle + HasRawDisplayHandle> SurfaceTexture<'win, W> {
|
||||||
/// Create a logical texture for a window surface.
|
/// Create a logical texture for a window surface.
|
||||||
///
|
///
|
||||||
/// It is recommended (but not required) that the `width` and `height` are equivalent to the
|
/// It is recommended (but not required) that the `width` and `height` are equivalent to the
|
||||||
|
@ -193,7 +194,7 @@ impl Pixels {
|
||||||
///
|
///
|
||||||
/// Panics when `width` or `height` are 0.
|
/// Panics when `width` or `height` are 0.
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn new<W: HasRawWindowHandle>(
|
pub fn new<W: HasRawWindowHandle + HasRawDisplayHandle>(
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
surface_texture: SurfaceTexture<'_, W>,
|
surface_texture: SurfaceTexture<'_, W>,
|
||||||
|
@ -224,7 +225,7 @@ impl Pixels {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics when `width` or `height` are 0.
|
/// Panics when `width` or `height` are 0.
|
||||||
pub async fn new_async<W: HasRawWindowHandle>(
|
pub async fn new_async<W: HasRawWindowHandle + HasRawDisplayHandle>(
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
surface_texture: SurfaceTexture<'_, W>,
|
surface_texture: SurfaceTexture<'_, W>,
|
||||||
|
@ -487,6 +488,7 @@ impl Pixels {
|
||||||
width: self.surface_size.width,
|
width: self.surface_size.width,
|
||||||
height: self.surface_size.height,
|
height: self.surface_size.height,
|
||||||
present_mode: self.present_mode,
|
present_mode: self.present_mode,
|
||||||
|
alpha_mode: self.alpha_mode,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -588,11 +590,9 @@ impl Pixels {
|
||||||
pub fn clamp_pixel_pos(&self, pos: (isize, isize)) -> (usize, usize) {
|
pub fn clamp_pixel_pos(&self, pos: (isize, isize)) -> (usize, usize) {
|
||||||
(
|
(
|
||||||
pos.0
|
pos.0
|
||||||
.max(0)
|
.clamp(0, self.context.texture_extent.width as isize - 1) as usize,
|
||||||
.min(self.context.texture_extent.width as isize - 1) as usize,
|
|
||||||
pos.1
|
pos.1
|
||||||
.max(0)
|
.clamp(0, self.context.texture_extent.height as isize - 1) as usize,
|
||||||
.min(self.context.texture_extent.height as isize - 1) as usize,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -232,8 +232,7 @@ impl ScalingMatrix {
|
||||||
|
|
||||||
// Get smallest scale size
|
// Get smallest scale size
|
||||||
let scale = (screen_width / texture_width)
|
let scale = (screen_width / texture_width)
|
||||||
.min(screen_height / texture_height)
|
.clamp(1.0, screen_height / texture_height)
|
||||||
.max(1.0)
|
|
||||||
.floor();
|
.floor();
|
||||||
|
|
||||||
let scaled_width = texture_width * scale;
|
let scaled_width = texture_width * scale;
|
||||||
|
|
Loading…
Reference in a new issue