Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion examples/simple/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
//! Simple example.

use anyhow::Result;
use std::f64::consts::{FRAC_PI_2, FRAC_PI_4};
use std::sync::Arc;
use vello::kurbo::{Affine, Circle, Ellipse, Line, RoundedRect, Stroke};
use vello::kurbo::{Affine, BezPath, Circle, Ellipse, Line, RoundedRect, Shape, Stroke};
use vello::peniko::Color;
use vello::peniko::color::palette;
use vello::util::{RenderContext, RenderSurface};
Expand Down
2 changes: 2 additions & 0 deletions examples/with_winit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ scenes = { workspace = true }
anyhow = { workspace = true }
clap = { workspace = true, features = ["derive"] }
pollster = { workspace = true }
wgpu = { workspace = true }
wgpu-profiler = { workspace = true, optional = true }

winit = { workspace = true }
log = { workspace = true }
bytemuck = { workspace = true }

# We're still using env-logger, but we want to use tracing spans to allow using
# tracing_android_trace
Expand Down
61 changes: 61 additions & 0 deletions examples/with_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ use minimal_pipeline_cache::{get_cache_directory, load_pipeline_cache, write_pip
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant;
use vello::low_level::DebugLayers;
use vello::peniko::Blob;
#[cfg(target_arch = "wasm32")]
use web_time::Instant;
use wgpu::TexelCopyTextureInfoBase;
use wgpu_shader::DemoRenderer;
use winit::application::ApplicationHandler;
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent};
use winit::keyboard::{Key, ModifiersState, NamedKey};
Expand Down Expand Up @@ -51,6 +54,7 @@ mod hot_reload;
mod minimal_pipeline_cache;
mod multi_touch;
mod stats;
mod wgpu_shader;

#[derive(Parser, Debug)]
#[command(about, long_about = None, bin_name="cargo run -p with_winit --")]
Expand Down Expand Up @@ -170,6 +174,8 @@ struct VelloApp<'s> {
prev_scene_ix: i32,
modifiers: ModifiersState,

demo_renderer: Option<DemoRenderer>,

debug: DebugLayers,

#[cfg(not(target_arch = "wasm32"))]
Expand Down Expand Up @@ -205,6 +211,14 @@ impl ApplicationHandler<UserEvent> for VelloApp<'_> {
self.renderers
.resize_with(self.context.devices.len(), || None);
let id = render_state.surface.dev_id;

// Initialise demo renderer
let device_handle = &self.context.devices[id];
self.demo_renderer = Some(DemoRenderer::new(
&device_handle.device,
&device_handle.queue,
));

self.renderers[id].get_or_insert_with(|| {
let device_handle = &self.context.devices[id];
let cache = if let Some((dir, tx)) = self.cache_data.as_ref() {
Expand Down Expand Up @@ -484,6 +498,40 @@ impl ApplicationHandler<UserEvent> for VelloApp<'_> {
let device_handle = &self.context.devices[surface.dev_id];
let snapshot = self.stats.snapshot();

// Render demo and store as override_image
// TODO: reuse dummy images and texture mapping

let mut demo_texture = None;
let demo_w = width / 2;
let demo_h = height / 2;
let demo_x = width / 4;
let demo_y = height / 4;
if let Some(renderer) = self.renderers[surface.dev_id].as_mut() {
if let Some(demo) = self.demo_renderer.as_mut() {
let texture = demo.render(1.0, 0.0, 0.0, demo_w, demo_h);
let dummy_image = vello::peniko::Image {
data: Blob::new(Arc::new([])), // will be ignored
format: vello::peniko::ImageFormat::Rgba8,
width: demo_w,
height: demo_h,
x_extend: vello::peniko::Extend::Pad,
y_extend: vello::peniko::Extend::Pad,
quality: vello::peniko::ImageQuality::High,
alpha: 1.0,
};

let base = TexelCopyTextureInfoBase {
texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
};
renderer.override_image(&dummy_image, Some(base));

demo_texture = Some(dummy_image);
}
}

// Allow looping forever
self.scene_ix = self.scene_ix.rem_euclid(self.scenes.len() as i32);
self.aa_config_ix = self.aa_config_ix.rem_euclid(AA_CONFIGS.len() as i32);
Expand Down Expand Up @@ -531,6 +579,17 @@ impl ApplicationHandler<UserEvent> for VelloApp<'_> {
transform *= Affine::scale(scale_factor);
}
self.scene.append(&self.fragment, Some(transform));

if let Some(demo_texture) = demo_texture {
self.scene.draw_image(
&demo_texture,
Affine::translate(Vec2 {
x: demo_x as f64,
y: demo_y as f64,
}),
);
};

if self.stats_shown {
snapshot.draw_layer(
&mut self.scene,
Expand Down Expand Up @@ -821,6 +880,8 @@ fn run(
frame_start_time: Instant::now(),
start: Instant::now(),

demo_renderer: None,

touch_state: multi_touch::TouchState::new(),
navigation_fingers: HashSet::new(),
transform: Affine::IDENTITY,
Expand Down
111 changes: 111 additions & 0 deletions examples/with_winit/src/shader.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright © SixtyFPS GmbH <[email protected]>
// SPDX-License-Identifier: MIT

struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) frag_position: vec2<f32>,
};

@vertex
fn vs_main(
@builtin(vertex_index) vertex_index: u32
) -> VertexOutput {
var output: VertexOutput;

var positions = array<vec2<f32>, 3>(
vec2<f32>(-1.0, 3.0),
vec2<f32>(-1.0, -1.0),
vec2<f32>( 3.0, -1.0)
);

let pos = positions[vertex_index];
output.position = vec4<f32>(pos.x, -pos.y, 0.0, 1.0);
output.frag_position = pos;
return output;
}

struct PushConstants {
light_color_and_time: vec4<f32>,
};

var<push_constant> pc: PushConstants;

fn sdRoundBox(p: vec3<f32>, b: vec3<f32>, r: f32) -> f32 {
let q = abs(p) - b;
return length(max(q, vec3<f32>(0.0))) + min(max(q.x, max(q.y, q.z)), 0.0) - r;
}

fn rotateY(r: vec3<f32>, angle: f32) -> vec3<f32> {
let c = cos(angle);
let s = sin(angle);
let rotation_matrix = mat3x3<f32>(
vec3<f32>( c, 0.0, s),
vec3<f32>(0.0, 1.0, 0.0),
vec3<f32>(-s, 0.0, c)
);
return rotation_matrix * r;
}

fn rotateZ(r: vec3<f32>, angle: f32) -> vec3<f32> {
let c = cos(angle);
let s = sin(angle);
let rotation_matrix = mat3x3<f32>(
vec3<f32>( c, -s, 0.0),
vec3<f32>( s, c, 0.0),
vec3<f32>(0.0, 0.0, 1.0)
);
return rotation_matrix * r;
}

// Distance from the scene
fn scene(r: vec3<f32>) -> f32 {
let iTime = pc.light_color_and_time.w;
let pos = rotateZ(rotateY(r + vec3<f32>(-1.0, -1.0, 4.0), iTime), iTime);
let cube = vec3<f32>(0.5, 0.5, 0.5);
let edge = 0.1;
return sdRoundBox(pos, cube, edge);
}

// https://iquilezles.org/articles/normalsSDF
fn normal(pos: vec3<f32>) -> vec3<f32> {
let e = vec2<f32>(1.0, -1.0) * 0.5773;
let eps = 0.0005;
return normalize(
e.xyy * scene(pos + e.xyy * eps) +
e.yyx * scene(pos + e.yyx * eps) +
e.yxy * scene(pos + e.yxy * eps) +
e.xxx * scene(pos + e.xxx * eps)
);
}

fn render(fragCoord: vec2<f32>, light_color: vec3<f32>) -> vec4<f32> {
var color = vec4<f32>(0.0, 0.0, 0.0, 1.0);

var camera = vec3<f32>(1.0, 2.0, 1.0);
var p = vec3<f32>(fragCoord.x, fragCoord.y + 1.0, -1.0);
var dir = normalize(p - camera);

var i = 0;
loop {
if (i >= 90) { break; }
let dist = scene(p);
if (dist < 0.0001) { break; }
p = p + dir * dist;
i = i + 1;
}

let surf_normal = normal(p);
let light_position = vec3<f32>(2.0, 4.0, -0.5);
var light = 7.0 + 2.0 * dot(surf_normal, light_position);
light = light / (0.2 * pow(length(light_position - p), 3.5));

let alpha = select(0.0, 1.0, i < 90);
return vec4<f32>(light * light_color, alpha) * 2.0;
}

@fragment
fn fs_main(@location(0) frag_position: vec2<f32>) -> @location(0) vec4<f32> {
let selected_light_color = pc.light_color_and_time.xyz;
let r = vec2<f32>(0.5 * frag_position.x + 1.0, 0.5 - 0.5 * frag_position.y);
return render(r, selected_light_color);
}
Loading
Loading