blob: cb35e1cc62693a00df842997f8bafdb0cf12176b [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
anyhow::Error,
carnelian::{
app::Config,
color::Color,
make_app_assistant,
render::{rive::load_rive, Context as RenderContext},
scene::{
facets::{FacetId, RiveFacet, SetSizeMessage},
scene::{Scene, SceneBuilder},
},
App, AppAssistant, Size, ViewAssistant, ViewAssistantContext, ViewAssistantPtr, ViewKey,
},
fuchsia_trace_provider,
fuchsia_zircon::{Event, Time},
rive_rs::{self as rive},
std::path::PathBuf,
};
const POINTER: &'static str = "/pkg/data/pointer.riv";
const BACKGROUND_COLOR: Color = Color { r: 0, g: 0, b: 0, a: 0 };
#[derive(Default)]
struct CursorManagerAppAssistant;
impl AppAssistant for CursorManagerAppAssistant {
fn setup(&mut self) -> Result<(), Error> {
Ok(())
}
fn create_view_assistant(&mut self, _view_key: ViewKey) -> Result<ViewAssistantPtr, Error> {
Ok(Box::new(CursorManagerViewAssistant::new()))
}
fn filter_config(&mut self, config: &mut Config) {
config.view_mode = carnelian::app::ViewMode::Hosted;
config.input = false;
config.needs_blending = true;
config.startup_delay = std::time::Duration::from_millis(500);
}
}
struct SceneDetails {
scene: Scene,
_file: rive::File,
rive: FacetId,
artboard: rive::Object<rive::Artboard>,
animation: Option<rive::animation::LinearAnimationInstance>,
}
struct CursorManagerViewAssistant {
last_presentation_time: Option<Time>,
scene_details: Option<SceneDetails>,
}
impl CursorManagerViewAssistant {
fn new() -> CursorManagerViewAssistant {
CursorManagerViewAssistant { last_presentation_time: None, scene_details: None }
}
fn set_size(&mut self, size: &Size) {
if let Some(scene_details) = self.scene_details.as_mut() {
scene_details
.scene
.send_message(&scene_details.rive, Box::new(SetSizeMessage { size: *size }));
}
}
}
impl ViewAssistant for CursorManagerViewAssistant {
fn resize(&mut self, new_size: &Size) -> Result<(), Error> {
self.set_size(new_size);
Ok(())
}
fn render(
&mut self,
render_context: &mut RenderContext,
ready_event: Event,
context: &ViewAssistantContext,
) -> Result<(), Error> {
let mut scene_details = self.scene_details.take().unwrap_or_else(|| {
let file = load_rive(PathBuf::from(POINTER)).expect("failed to load animation");
let mut builder = SceneBuilder::new().background_color(BACKGROUND_COLOR).mutable(false);
let artboard = file.artboard().expect("failed to get artboard");
let artboard_ref = artboard.as_ref();
let rive_facet = RiveFacet::new(context.size, artboard.clone());
let rive = builder.facet(Box::new(rive_facet));
let scene = builder.build();
let animation = artboard_ref
.animations()
.next()
.map(|animation| rive::animation::LinearAnimationInstance::new(animation));
SceneDetails { scene, _file: file, rive, artboard, animation }
});
let artboard_ref = scene_details.artboard.as_ref();
let request_render = if let Some(animation) = scene_details.animation.as_mut() {
let presentation_time = context.presentation_time;
let elapsed = if let Some(last_presentation_time) = self.last_presentation_time {
const NANOS_PER_SECOND: f32 = 1_000_000_000.0;
(presentation_time - last_presentation_time).into_nanos() as f32 / NANOS_PER_SECOND
} else {
0.0
};
self.last_presentation_time = Some(presentation_time);
animation.advance(elapsed);
animation.apply(scene_details.artboard.clone(), 1.0);
artboard_ref.advance(elapsed);
true
} else {
artboard_ref.advance(0.0);
false
};
scene_details.scene.render(render_context, ready_event, context)?;
if request_render {
context.request_render();
}
self.scene_details = Some(scene_details);
Ok(())
}
}
fn main() -> Result<(), Error> {
fuchsia_trace_provider::trace_provider_create_with_fdio();
App::run(make_app_assistant::<CursorManagerAppAssistant>())
}