Compare commits

..

No commits in common. "master" and "v0.1.1" have entirely different histories.

7 changed files with 88 additions and 3119 deletions

50
.github/workflows/docs.yml vendored Normal file
View File

@ -0,0 +1,50 @@
name: Docs
on:
push:
branches: [master]
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: deploy
cancel-in-progress: false
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Dependencies
run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Configure cache
uses: Swatinem/rust-cache@v2
- name: Setup pages
id: pages
uses: actions/configure-pages@v4
- name: Clean docs folder
run: cargo clean --doc
- name: Build docs
run: cargo doc --no-deps
- name: Add redirect
run: echo '<meta http-equiv="refresh" content="0;url=framebuffer_extract/index.html">' > target/doc/index.html
- name: Remove lock file
run: rm target/doc/.lock
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: target/doc
deploy:
name: Deploy
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

1
.gitignore vendored
View File

@ -1 +0,0 @@
target/

3075
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,15 @@
[package] [package]
name = "bevy_headless_render" name = "bevy_headless_render"
version = "0.2.0" version = "0.1.1"
edition = "2021" edition = "2021"
description = "A plugin for the bevy engine which enables headless rendering to an image for use in the main world." description = "A plugin for the bevy engine which enables headless rendering to an image for use in the main world."
license = "0BSD OR MIT OR Apache-2.0" license = "0BSD OR MIT OR Apache-2.0"
[dependencies] [dependencies]
oneshot = "0.1" oneshot = "0.1.6"
pollster = "0.4" pollster = "0.3.0"
[dependencies.bevy] [dependencies.bevy]
version = "0.15" version = "0.14"
default-features = false default-features = false
features = ["bevy_render", "bevy_asset", "png", "bevy_pbr"] features = ["bevy_render", "bevy_asset"]

View File

@ -3,7 +3,8 @@
[![Crates](https://img.shields.io/crates/v/bevy_headless_render)](https://crates.io/crates/bevy_headless_render) [![Crates](https://img.shields.io/crates/v/bevy_headless_render)](https://crates.io/crates/bevy_headless_render)
![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg) ![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)
![Tag](https://img.shields.io/github/v/tag/exvacuum/bevy_headless_render) ![Tag](https://img.shields.io/github/v/tag/exvacuum/bevy_headless_render)
[![Docs](https://img.shields.io/docsrs/bevy_headless_render)](https://exvacuum.github.io/bevy_headless_render) ![Build](https://img.shields.io/github/actions/workflow/status/exvacuum/bevy_headless_render/rust.yml)
[![Docs](https://img.shields.io/website?url=https%3A%2F%2Fexvacuum.github.io%2Fbevy_headless_render%2F&label=docs)](https://exvacuum.github.io/bevy_headless_render)
A plugin for the [Bevy](https://bevyengine.org) engine which allows for headless rendering. A plugin for the [Bevy](https://bevyengine.org) engine which allows for headless rendering.
@ -14,20 +15,19 @@ Every frame will be copied from `HeadlessRenderSource` render textures into `Hea
| Crate Version | Bevy Version | | Crate Version | Bevy Version |
|--- |--- | |--- |--- |
| 0.1 | 0.14 | | 0.1 | 0.14 |
| 0.2 | 0.15 |
## Installation ## Installation
### crates.io ### crates.io
```toml ```toml
[dependencies] [dependencies]
bevy_headless_render = "0.2" bevy_headless_render = "0.1"
``` ```
### Using git URL in Cargo.toml ### Using git URL in Cargo.toml
```toml ```toml
[dependencies.bevy_headless_render] [dependencies.bevy_headless_render]
git = "https://git.exvacuum.dev/bevy_headless_render" git = "https://github.com/exvacuum/bevy_headless_render.git"
``` ```
## Usage ## Usage
@ -40,7 +40,7 @@ use bevy_headless_render;
fn main() { fn main() {
App::new() App::new()
.add_plugins(( .add_plugins((
DefaultPlugins DefaultPlugins,
bevy_headless_render::HeadlessRenderPlugin, bevy_headless_render::HeadlessRenderPlugin,
)) ))
.run(); .run();
@ -60,7 +60,7 @@ let mut image = Image {
label: None, label: None,
size, size,
dimension: TextureDimension::D2, dimension: TextureDimension::D2,
format: TextureFormat::Rgba8UnormSrgb, format: TextureFormat::R8Unorm,
mip_level_count: 1, mip_level_count: 1,
sample_count: 1, sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING usage: TextureUsages::TEXTURE_BINDING
@ -73,15 +73,20 @@ let mut image = Image {
image.resize(size); image.resize(size);
let image_handle = asset_server.add(image); let image_handle = images.add(image); // ResMut<Assets<Image>>
commands.spawn(( commands.spawn((
HeadlessRenderSource::new(&asset_server, image_handle.clone()), Camera3dBundle {
Camera3d::default(), camera: Camera {
Camera { target: image_handle.clone().into();
target: image_handle.into(), ..Default::default()
},
..Default::default() ..Default::default()
}, },
bevy_headless_render::HeadlessRenderBundle {
source: headless_render_sources.add(HeadlessRenderSource(image_handle.clone())), // ResMut<Assets<HeadlessRenderSource>>
destination: HeadlessRenderDestination::default(),
},
)); ));
``` ```

View File

@ -1,19 +1,19 @@
use std::sync::{Arc, Mutex, MutexGuard, PoisonError}; use std::sync::{Arc, Mutex};
use bevy::{ecs::query::QueryItem, prelude::*, render::extract_component::ExtractComponent}; use bevy::{ecs::query::QueryItem, prelude::*, render::extract_component::ExtractComponent};
use crate::render_assets; use crate::render_assets::HeadlessRenderSource;
/// Headless render destination. Contains the image which the rendered frame is copied to. /// Headless render destination. Contains the image which the rendered frame is copied to.
#[derive(Component, Default, Clone)] #[derive(Component, Default, Clone)]
pub struct HeadlessRenderDestination(pub Arc<Mutex<Image>>); pub struct HeadlessRenderDestination(pub Arc<Mutex<Image>>);
impl ExtractComponent for HeadlessRenderDestination { impl ExtractComponent for HeadlessRenderDestination {
type QueryData = (&'static Self, &'static HeadlessRenderSource); type QueryData = (&'static Self, &'static Handle<HeadlessRenderSource>);
type QueryFilter = (); type QueryFilter = ();
type Out = (Self, HeadlessRenderSource); type Out = (Self, Handle<HeadlessRenderSource>);
fn extract_component( fn extract_component(
(destination, source_handle): QueryItem<'_, Self::QueryData>, (destination, source_handle): QueryItem<'_, Self::QueryData>,
@ -22,21 +22,11 @@ impl ExtractComponent for HeadlessRenderDestination {
} }
} }
impl HeadlessRenderDestination { /// Bundle containing both a source and destination for headless rendering.
/// Get lock on this destination's image #[derive(Bundle)]
pub fn image(&self) -> Result<MutexGuard<Image>, PoisonError<MutexGuard<Image>>> { pub struct HeadlessRenderBundle {
self.0.lock() /// Source
} pub source: Handle<HeadlessRenderSource>,
} /// Destination
pub dest: HeadlessRenderDestination,
/// Headless render source
#[derive(Component, Debug, Clone, DerefMut, Deref)]
#[require(HeadlessRenderDestination, Camera3d)]
pub struct HeadlessRenderSource(pub Handle<render_assets::HeadlessRenderSource>);
impl HeadlessRenderSource {
/// Create a new headless render source from the provided image
pub fn new(asset_server: &AssetServer, image: Handle<Image>) -> Self {
Self(asset_server.add(render_assets::HeadlessRenderSource(image)))
}
} }

View File

@ -9,18 +9,18 @@ use bevy::{
use pollster::FutureExt; use pollster::FutureExt;
use crate::{ use crate::{components::HeadlessRenderDestination, render_assets::{HeadlessRenderSource, GpuHeadlessRenderSource}};
components::{HeadlessRenderDestination, HeadlessRenderSource},
render_assets::GpuHeadlessRenderSource,
};
pub fn copy_buffers( pub fn copy_buffers(
mut headless_render_query: Query<(&HeadlessRenderSource, &mut HeadlessRenderDestination)>, mut headless_render_query: Query<(
&Handle<HeadlessRenderSource>,
&mut HeadlessRenderDestination,
)>,
sources: Res<RenderAssets<GpuHeadlessRenderSource>>, sources: Res<RenderAssets<GpuHeadlessRenderSource>>,
device: Res<RenderDevice>, device: Res<RenderDevice>,
) { ) {
for (source_handle, destination_handle) in headless_render_query.iter_mut() { for (source_handle, destination_handle) in headless_render_query.iter_mut() {
let Some(gpu_source) = sources.get(source_handle.id()) else { let Some(gpu_source) = sources.get(source_handle) else {
continue; continue;
}; };