mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-24 17:28:40 +00:00
Get basic graphics rendering via Metal
Also, handle window resize.
This commit is contained in:
parent
292b41ad57
commit
e5ffe43bb6
9 changed files with 328 additions and 120 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
.DS_Store
|
||||
/zed.xcworkspace
|
||||
.DS_Store
|
||||
|
|
|
@ -13,7 +13,6 @@ use pathfinder_geometry::{rect::RectF, vector::vec2f};
|
|||
use smol::{channel, prelude::*};
|
||||
use std::{
|
||||
any::{type_name, Any, TypeId},
|
||||
borrow,
|
||||
cell::RefCell,
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
fmt::{self, Debug},
|
||||
|
@ -292,6 +291,7 @@ type ActionCallback =
|
|||
type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext);
|
||||
|
||||
pub struct MutableAppContext {
|
||||
weak_self: Option<rc::Weak<RefCell<Self>>>,
|
||||
platform: Arc<dyn platform::App>,
|
||||
fonts: Arc<FontCache>,
|
||||
assets: Arc<AssetCache>,
|
||||
|
@ -302,7 +302,6 @@ pub struct MutableAppContext {
|
|||
next_entity_id: usize,
|
||||
next_window_id: usize,
|
||||
next_task_id: usize,
|
||||
weak_self: Option<rc::Weak<RefCell<Self>>>,
|
||||
subscriptions: HashMap<usize, Vec<Subscription>>,
|
||||
observations: HashMap<usize, Vec<Observation>>,
|
||||
window_invalidations: HashMap<usize, WindowInvalidation>,
|
||||
|
@ -325,6 +324,7 @@ impl MutableAppContext {
|
|||
asset_source: impl AssetSource,
|
||||
) -> Self {
|
||||
Self {
|
||||
weak_self: None,
|
||||
platform,
|
||||
fonts: Arc::new(FontCache::new()),
|
||||
assets: Arc::new(AssetCache::new(asset_source)),
|
||||
|
@ -339,7 +339,6 @@ impl MutableAppContext {
|
|||
next_entity_id: 0,
|
||||
next_window_id: 0,
|
||||
next_task_id: 0,
|
||||
weak_self: None,
|
||||
subscriptions: HashMap::new(),
|
||||
observations: HashMap::new(),
|
||||
window_invalidations: HashMap::new(),
|
||||
|
@ -355,6 +354,10 @@ impl MutableAppContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn upgrade(&self) -> App {
|
||||
App(self.weak_self.as_ref().unwrap().upgrade().unwrap())
|
||||
}
|
||||
|
||||
pub fn downgrade(&self) -> &AppContext {
|
||||
&self.ctx
|
||||
}
|
||||
|
@ -624,7 +627,7 @@ impl MutableAppContext {
|
|||
self.foreground.clone(),
|
||||
) {
|
||||
Err(e) => log::error!("error opening window: {}", e),
|
||||
Ok(window) => {
|
||||
Ok(mut window) => {
|
||||
let presenter = Rc::new(RefCell::new(Presenter::new(
|
||||
window_id,
|
||||
self.fonts.clone(),
|
||||
|
@ -632,11 +635,26 @@ impl MutableAppContext {
|
|||
self,
|
||||
)));
|
||||
|
||||
{
|
||||
let mut app = self.upgrade();
|
||||
let presenter = presenter.clone();
|
||||
window.on_resize(Box::new(move |window| {
|
||||
app.update(|ctx| {
|
||||
let scene = presenter.borrow_mut().build_scene(
|
||||
window.size(),
|
||||
window.scale_factor(),
|
||||
ctx,
|
||||
);
|
||||
window.present_scene(scene);
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
self.on_window_invalidated(window_id, move |invalidation, ctx| {
|
||||
let mut presenter = presenter.borrow_mut();
|
||||
presenter.invalidate(invalidation, ctx.downgrade());
|
||||
let scene = presenter.build_scene(window.size(), window.scale_factor(), ctx);
|
||||
window.render_scene(scene);
|
||||
window.present_scene(scene);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1909,7 +1927,7 @@ impl<T> Hash for ModelHandle<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> borrow::Borrow<usize> for ModelHandle<T> {
|
||||
impl<T> std::borrow::Borrow<usize> for ModelHandle<T> {
|
||||
fn borrow(&self) -> &usize {
|
||||
&self.model_id
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ impl platform::App for App {
|
|||
&self,
|
||||
options: platform::WindowOptions,
|
||||
executor: Rc<executor::Foreground>,
|
||||
) -> Result<Rc<dyn platform::Window>> {
|
||||
Ok(Rc::new(Window::open(options, executor)?))
|
||||
) -> Result<Box<dyn platform::Window>> {
|
||||
Ok(Box::new(Window::open(options, executor)?))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use std::{ffi::c_void, mem};
|
||||
|
||||
use crate::Scene;
|
||||
use self::shaders::ToUchar4;
|
||||
|
||||
use super::window::RenderContext;
|
||||
use crate::{color::ColorU, scene::Layer, Scene};
|
||||
use anyhow::{anyhow, Result};
|
||||
use metal::{MTLResourceOptions, NSRange};
|
||||
use shaders::ToFloat2 as _;
|
||||
|
||||
const SHADERS_METALLIB: &'static [u8] =
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
|
||||
const INSTANCE_BUFFER_SIZE: u64 = 1024 * 1024;
|
||||
|
||||
pub struct Renderer {
|
||||
quad_pipeline_state: metal::RenderPipelineState,
|
||||
quad_vertices: metal::Buffer,
|
||||
instances: metal::Buffer,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
|
@ -17,6 +24,22 @@ impl Renderer {
|
|||
.new_library_with_data(SHADERS_METALLIB)
|
||||
.map_err(|message| anyhow!("error building metal library: {}", message))?;
|
||||
|
||||
let quad_vertices = [
|
||||
(0., 0.).to_float2(),
|
||||
(1., 0.).to_float2(),
|
||||
(0., 1.).to_float2(),
|
||||
(0., 1.).to_float2(),
|
||||
(1., 0.).to_float2(),
|
||||
(1., 1.).to_float2(),
|
||||
];
|
||||
let quad_vertices = device.new_buffer_with_data(
|
||||
quad_vertices.as_ptr() as *const c_void,
|
||||
(quad_vertices.len() * mem::size_of::<shaders::vector_float2>()) as u64,
|
||||
MTLResourceOptions::StorageModeManaged,
|
||||
);
|
||||
let instances =
|
||||
device.new_buffer(INSTANCE_BUFFER_SIZE, MTLResourceOptions::StorageModeManaged);
|
||||
|
||||
Ok(Self {
|
||||
quad_pipeline_state: build_pipeline_state(
|
||||
device,
|
||||
|
@ -26,10 +49,78 @@ impl Renderer {
|
|||
"quad_fragment",
|
||||
pixel_format,
|
||||
)?,
|
||||
quad_vertices,
|
||||
instances,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render(&mut self, scene: &Scene, ctx: RenderContext) {}
|
||||
pub fn render(&mut self, scene: &Scene, ctx: &RenderContext) {
|
||||
ctx.command_encoder.set_viewport(metal::MTLViewport {
|
||||
originX: 0.0,
|
||||
originY: 0.0,
|
||||
width: ctx.drawable_size.x() as f64,
|
||||
height: ctx.drawable_size.y() as f64,
|
||||
znear: 0.0,
|
||||
zfar: 1.0,
|
||||
});
|
||||
|
||||
for layer in scene.layers() {
|
||||
self.render_quads(layer, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_quads(&mut self, layer: &Layer, ctx: &RenderContext) {
|
||||
ctx.command_encoder
|
||||
.set_render_pipeline_state(&self.quad_pipeline_state);
|
||||
ctx.command_encoder.set_vertex_buffer(
|
||||
shaders::GPUIQuadInputIndex_GPUIQuadInputIndexVertices as u64,
|
||||
Some(&self.quad_vertices),
|
||||
0,
|
||||
);
|
||||
ctx.command_encoder.set_vertex_buffer(
|
||||
shaders::GPUIQuadInputIndex_GPUIQuadInputIndexQuads as u64,
|
||||
Some(&self.instances),
|
||||
0,
|
||||
);
|
||||
ctx.command_encoder.set_vertex_bytes(
|
||||
shaders::GPUIQuadInputIndex_GPUIQuadInputIndexUniforms as u64,
|
||||
mem::size_of::<shaders::GPUIQuadUniforms>() as u64,
|
||||
[shaders::GPUIQuadUniforms {
|
||||
viewport_size: ctx.drawable_size.to_float2(),
|
||||
}]
|
||||
.as_ptr() as *const c_void,
|
||||
);
|
||||
|
||||
let batch_size = self.instances.length() as usize / mem::size_of::<shaders::GPUIQuad>();
|
||||
|
||||
let buffer_contents = self.instances.contents() as *mut shaders::GPUIQuad;
|
||||
for quad_batch in layer.quads().chunks(batch_size) {
|
||||
for (ix, quad) in quad_batch.iter().enumerate() {
|
||||
log::info!("render {} {:?}", ix, quad);
|
||||
unsafe {
|
||||
*(buffer_contents.offset(ix as isize)) = shaders::GPUIQuad {
|
||||
origin: quad.bounds.origin().to_float2(),
|
||||
size: quad.bounds.size().to_float2(),
|
||||
background_color: quad
|
||||
.background
|
||||
.unwrap_or(ColorU::transparent_black())
|
||||
.to_uchar4(),
|
||||
};
|
||||
}
|
||||
}
|
||||
self.instances.did_modify_range(NSRange {
|
||||
location: 0,
|
||||
length: (quad_batch.len() * mem::size_of::<shaders::GPUIQuad>()) as u64,
|
||||
});
|
||||
|
||||
ctx.command_encoder.draw_primitives_instanced(
|
||||
metal::MTLPrimitiveType::Triangle,
|
||||
0,
|
||||
6,
|
||||
quad_batch.len() as u64,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_pipeline_state(
|
||||
|
@ -47,7 +138,7 @@ fn build_pipeline_state(
|
|||
.get_function(fragment_fn_name, None)
|
||||
.map_err(|message| anyhow!("error locating fragment function: {}", message))?;
|
||||
|
||||
let mut descriptor = metal::RenderPipelineDescriptor::new();
|
||||
let descriptor = metal::RenderPipelineDescriptor::new();
|
||||
descriptor.set_label(label);
|
||||
descriptor.set_vertex_function(Some(vertex_fn.as_ref()));
|
||||
descriptor.set_fragment_function(Some(fragment_fn.as_ref()));
|
||||
|
@ -61,3 +152,57 @@ fn build_pipeline_state(
|
|||
.new_render_pipeline_state(&descriptor)
|
||||
.map_err(|message| anyhow!("could not create render pipeline state: {}", message))
|
||||
}
|
||||
|
||||
mod shaders {
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use crate::{color::ColorU, geometry::vector::Vector2F};
|
||||
use std::mem;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
|
||||
|
||||
pub trait ToFloat2 {
|
||||
fn to_float2(&self) -> vector_float2;
|
||||
}
|
||||
|
||||
pub trait ToUchar4 {
|
||||
fn to_uchar4(&self) -> vector_uchar4;
|
||||
}
|
||||
|
||||
impl ToFloat2 for (f32, f32) {
|
||||
fn to_float2(&self) -> vector_float2 {
|
||||
unsafe {
|
||||
let mut output = mem::transmute::<_, u32>(self.1.to_bits()) as vector_float2;
|
||||
output <<= 32;
|
||||
output |= mem::transmute::<_, u32>(self.0.to_bits()) as vector_float2;
|
||||
output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFloat2 for Vector2F {
|
||||
fn to_float2(&self) -> vector_float2 {
|
||||
unsafe {
|
||||
let mut output = mem::transmute::<_, u32>(self.y().to_bits()) as vector_float2;
|
||||
output <<= 32;
|
||||
output |= mem::transmute::<_, u32>(self.x().to_bits()) as vector_float2;
|
||||
output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToUchar4 for ColorU {
|
||||
fn to_uchar4(&self) -> vector_uchar4 {
|
||||
let mut vec = self.a as vector_uchar4;
|
||||
vec <<= 8;
|
||||
vec |= self.b as vector_uchar4;
|
||||
vec <<= 8;
|
||||
vec |= self.g as vector_uchar4;
|
||||
vec <<= 8;
|
||||
vec |= self.r as vector_uchar4;
|
||||
vec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ typedef enum {
|
|||
typedef struct {
|
||||
vector_float2 origin;
|
||||
vector_float2 size;
|
||||
vector_float4 background_color;
|
||||
vector_uchar4 background_color;
|
||||
} GPUIQuad;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
|
||||
using namespace metal;
|
||||
|
||||
float4 coloru_to_colorf(uchar4 coloru) {
|
||||
return float4(coloru) / float4(0xff, 0xff, 0xff, 0xff);
|
||||
}
|
||||
|
||||
struct QuadFragmentInput {
|
||||
float4 position [[position]];
|
||||
GPUIQuad quad;
|
||||
|
@ -17,14 +21,15 @@ vertex QuadFragmentInput quad_vertex(
|
|||
) {
|
||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||
GPUIQuad quad = quads[quad_id];
|
||||
float4 position = float4((unit_vertex * quad.size + quad.origin) / (uniforms->viewport_size / 2.0), 0.0, 1.0);
|
||||
float2 position = (unit_vertex * quad.size + quad.origin) / (uniforms->viewport_size / 2.0);
|
||||
float4 device_position = float4(position * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
||||
|
||||
return QuadFragmentInput {
|
||||
position,
|
||||
device_position,
|
||||
quad,
|
||||
};
|
||||
}
|
||||
|
||||
fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]]) {
|
||||
return input.quad.background_color;
|
||||
}
|
||||
return coloru_to_colorf(input.quad.background_color);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{
|
||||
executor,
|
||||
geometry::vector::Vector2F,
|
||||
platform::{self, Event},
|
||||
platform::{self, Event, WindowContext},
|
||||
util::post_inc,
|
||||
Scene,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
|
@ -27,7 +28,7 @@ use objc::{
|
|||
use pathfinder_geometry::vector::vec2f;
|
||||
use smol::Timer;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
cell::RefCell,
|
||||
ffi::c_void,
|
||||
mem, ptr,
|
||||
rc::Rc,
|
||||
|
@ -111,16 +112,16 @@ unsafe fn build_classes() {
|
|||
};
|
||||
}
|
||||
|
||||
pub struct Window(Rc<WindowState>);
|
||||
pub struct Window(Rc<RefCell<WindowState>>);
|
||||
|
||||
struct WindowState {
|
||||
native_window: id,
|
||||
event_callback: RefCell<Option<Box<dyn FnMut(Event) -> bool>>>,
|
||||
resize_callback: RefCell<Option<Box<dyn FnMut(Vector2F, f32)>>>,
|
||||
synthetic_drag_counter: Cell<usize>,
|
||||
event_callback: Option<Box<dyn FnMut(Event, &mut dyn platform::WindowContext)>>,
|
||||
resize_callback: Option<Box<dyn FnMut(&mut dyn platform::WindowContext)>>,
|
||||
synthetic_drag_counter: usize,
|
||||
executor: Rc<executor::Foreground>,
|
||||
scene_to_render: RefCell<Option<Scene>>,
|
||||
renderer: RefCell<Renderer>,
|
||||
scene_to_render: Option<Scene>,
|
||||
renderer: Renderer,
|
||||
command_queue: metal::CommandQueue,
|
||||
device: metal::Device,
|
||||
layer: id,
|
||||
|
@ -181,18 +182,18 @@ impl Window {
|
|||
return Err(anyhow!("view return nil from initializer"));
|
||||
}
|
||||
|
||||
let window = Self(Rc::new(WindowState {
|
||||
let window = Self(Rc::new(RefCell::new(WindowState {
|
||||
native_window,
|
||||
event_callback: RefCell::new(None),
|
||||
resize_callback: RefCell::new(None),
|
||||
synthetic_drag_counter: Cell::new(0),
|
||||
event_callback: None,
|
||||
resize_callback: None,
|
||||
synthetic_drag_counter: 0,
|
||||
executor,
|
||||
scene_to_render: Default::default(),
|
||||
renderer: RefCell::new(Renderer::new(&device, PIXEL_FORMAT)?),
|
||||
renderer: Renderer::new(&device, PIXEL_FORMAT)?,
|
||||
command_queue: device.new_command_queue(),
|
||||
device,
|
||||
layer,
|
||||
}));
|
||||
})));
|
||||
|
||||
(*native_window).set_ivar(
|
||||
WINDOW_STATE_IVAR,
|
||||
|
@ -236,46 +237,44 @@ impl Window {
|
|||
|
||||
pub fn zoom(&self) {
|
||||
unsafe {
|
||||
self.0.native_window.performZoom_(nil);
|
||||
self.0.as_ref().borrow().native_window.performZoom_(nil);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_event<F: 'static + FnMut(Event) -> bool>(&mut self, callback: F) {
|
||||
*self.0.event_callback.borrow_mut() = Some(Box::new(callback));
|
||||
}
|
||||
|
||||
pub fn on_resize<F: 'static + FnMut(Vector2F, f32)>(&mut self, callback: F) {
|
||||
*self.0.resize_callback.borrow_mut() = Some(Box::new(callback));
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Window {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.0.native_window.close();
|
||||
let _: () = msg_send![self.0.native_window.delegate(), release];
|
||||
self.0.as_ref().borrow().native_window.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl platform::Window for Window {
|
||||
fn size(&self) -> Vector2F {
|
||||
self.0.size()
|
||||
fn on_event(&mut self, callback: Box<dyn FnMut(Event, &mut dyn platform::WindowContext)>) {
|
||||
self.0.as_ref().borrow_mut().event_callback = Some(callback);
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f32 {
|
||||
self.0.scale_factor()
|
||||
}
|
||||
|
||||
fn render_scene(&self, scene: Scene) {
|
||||
*self.0.scene_to_render.borrow_mut() = Some(scene);
|
||||
unsafe {
|
||||
let _: () = msg_send![self.0.native_window.contentView(), setNeedsDisplay: YES];
|
||||
}
|
||||
fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn platform::WindowContext)>) {
|
||||
self.0.as_ref().borrow_mut().resize_callback = Some(callback);
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowState {
|
||||
impl platform::WindowContext for Window {
|
||||
fn size(&self) -> Vector2F {
|
||||
self.0.as_ref().borrow().size()
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f32 {
|
||||
self.0.as_ref().borrow().scale_factor()
|
||||
}
|
||||
|
||||
fn present_scene(&mut self, scene: Scene) {
|
||||
self.0.as_ref().borrow_mut().present_scene(scene);
|
||||
}
|
||||
}
|
||||
|
||||
impl platform::WindowContext for WindowState {
|
||||
fn size(&self) -> Vector2F {
|
||||
let NSSize { width, height, .. } =
|
||||
unsafe { NSView::frame(self.native_window.contentView()) }.size;
|
||||
|
@ -289,16 +288,17 @@ impl WindowState {
|
|||
}
|
||||
}
|
||||
|
||||
fn next_synthetic_drag_id(&self) -> usize {
|
||||
let next_id = self.synthetic_drag_counter.get() + 1;
|
||||
self.synthetic_drag_counter.set(next_id);
|
||||
next_id
|
||||
fn present_scene(&mut self, scene: Scene) {
|
||||
self.scene_to_render = Some(scene);
|
||||
unsafe {
|
||||
let _: () = msg_send![self.native_window.contentView(), setNeedsDisplay: YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn window_state(object: &Object) -> Rc<WindowState> {
|
||||
unsafe fn get_window_state(object: &Object) -> Rc<RefCell<WindowState>> {
|
||||
let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR);
|
||||
let rc1 = Rc::from_raw(raw as *mut WindowState);
|
||||
let rc1 = Rc::from_raw(raw as *mut RefCell<WindowState>);
|
||||
let rc2 = rc1.clone();
|
||||
mem::forget(rc1);
|
||||
rc2
|
||||
|
@ -328,23 +328,25 @@ extern "C" fn dealloc_view(this: &Object, _: Sel) {
|
|||
}
|
||||
|
||||
extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||
let window = unsafe { window_state(this) };
|
||||
let window_state = unsafe { get_window_state(this) };
|
||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
||||
|
||||
let event = unsafe { Event::from_native(native_event, Some(window.size().y())) };
|
||||
let event = unsafe { Event::from_native(native_event, Some(window_state_borrow.size().y())) };
|
||||
|
||||
if let Some(event) = event {
|
||||
match event {
|
||||
Event::LeftMouseDragged { position } => schedule_synthetic_drag(&window, position),
|
||||
Event::LeftMouseDragged { position } => {
|
||||
schedule_synthetic_drag(&&window_state, position)
|
||||
}
|
||||
Event::LeftMouseUp { .. } => {
|
||||
window.next_synthetic_drag_id();
|
||||
post_inc(&mut window_state_borrow.synthetic_drag_counter);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(callback) = window.event_callback.borrow_mut().as_mut() {
|
||||
if callback(event) {
|
||||
return;
|
||||
}
|
||||
if let Some(mut callback) = window_state_borrow.event_callback.take() {
|
||||
callback(event, &mut *window_state_borrow);
|
||||
window_state_borrow.event_callback = Some(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,55 +358,62 @@ extern "C" fn send_event(this: &Object, _: Sel, native_event: id) {
|
|||
}
|
||||
|
||||
extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id {
|
||||
let window = unsafe { window_state(this) };
|
||||
window.layer
|
||||
let window_state = unsafe { get_window_state(this) };
|
||||
let window_state = window_state.as_ref().borrow();
|
||||
window_state.layer
|
||||
}
|
||||
|
||||
extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) {
|
||||
let window;
|
||||
let window_state = unsafe { get_window_state(this) };
|
||||
let mut window_state = window_state.as_ref().borrow_mut();
|
||||
|
||||
unsafe {
|
||||
window = window_state(this);
|
||||
let _: () = msg_send![window.layer, setContentsScale: window.scale_factor() as f64];
|
||||
let _: () =
|
||||
msg_send![window_state.layer, setContentsScale: window_state.scale_factor() as f64];
|
||||
}
|
||||
|
||||
if let Some(callback) = window.resize_callback.borrow_mut().as_mut() {
|
||||
let size = window.size();
|
||||
let scale_factor = window.scale_factor();
|
||||
callback(size, scale_factor);
|
||||
if let Some(mut callback) = window_state.resize_callback.take() {
|
||||
callback(&mut *window_state);
|
||||
window_state.resize_callback = Some(callback);
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) {
|
||||
let window;
|
||||
unsafe {
|
||||
window = window_state(this);
|
||||
if window.size() == vec2f(size.width as f32, size.height as f32) {
|
||||
return;
|
||||
}
|
||||
let window_state = unsafe { get_window_state(this) };
|
||||
let mut window_state = window_state.as_ref().borrow_mut();
|
||||
|
||||
let _: () = msg_send![super(this, class!(NSView)), setFrameSize: size];
|
||||
|
||||
let scale_factor = window.scale_factor() as f64;
|
||||
let drawable_size: NSSize = NSSize {
|
||||
width: size.width * scale_factor,
|
||||
height: size.height * scale_factor,
|
||||
};
|
||||
let _: () = msg_send![window.layer, setDrawableSize: drawable_size];
|
||||
if window_state.size() == vec2f(size.width as f32, size.height as f32) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(callback) = window.resize_callback.borrow_mut().as_mut() {
|
||||
let size = window.size();
|
||||
let scale_factor = window.scale_factor();
|
||||
callback(size, scale_factor);
|
||||
unsafe {
|
||||
let _: () = msg_send![super(this, class!(NSView)), setFrameSize: size];
|
||||
}
|
||||
|
||||
let scale_factor = window_state.scale_factor() as f64;
|
||||
let drawable_size: NSSize = NSSize {
|
||||
width: size.width * scale_factor,
|
||||
height: size.height * scale_factor,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let _: () = msg_send![window_state.layer, setDrawableSize: drawable_size];
|
||||
}
|
||||
|
||||
if let Some(mut callback) = window_state.resize_callback.take() {
|
||||
callback(&mut *window_state);
|
||||
window_state.resize_callback = Some(callback);
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
|
||||
log::info!("display layer");
|
||||
unsafe {
|
||||
let window = window_state(this);
|
||||
let window_state = get_window_state(this);
|
||||
let mut window_state = window_state.as_ref().borrow_mut();
|
||||
|
||||
if let Some(scene) = window.scene_to_render.borrow_mut().take() {
|
||||
let drawable: &metal::MetalDrawableRef = msg_send![window.layer, nextDrawable];
|
||||
if let Some(scene) = window_state.scene_to_render.take() {
|
||||
let drawable: &metal::MetalDrawableRef = msg_send![window_state.layer, nextDrawable];
|
||||
|
||||
let render_pass_descriptor = metal::RenderPassDescriptor::new();
|
||||
let color_attachment = render_pass_descriptor
|
||||
|
@ -416,14 +425,19 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
|
|||
color_attachment.set_store_action(MTLStoreAction::Store);
|
||||
color_attachment.set_clear_color(MTLClearColor::new(0., 0., 0., 1.));
|
||||
|
||||
let command_buffer = window.command_queue.new_command_buffer();
|
||||
let command_queue = window_state.command_queue.clone();
|
||||
let command_buffer = command_queue.new_command_buffer();
|
||||
let command_encoder = command_buffer.new_render_command_encoder(render_pass_descriptor);
|
||||
|
||||
window.renderer.borrow_mut().render(
|
||||
let size = window_state.size();
|
||||
let scale_factor = window_state.scale_factor();
|
||||
let device = window_state.device.clone();
|
||||
|
||||
window_state.renderer.render(
|
||||
&scene,
|
||||
RenderContext {
|
||||
drawable_size: window.size() * window.scale_factor(),
|
||||
device: &window.device,
|
||||
&RenderContext {
|
||||
drawable_size: size * scale_factor,
|
||||
device: &device,
|
||||
command_encoder,
|
||||
},
|
||||
);
|
||||
|
@ -432,23 +446,33 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
|
|||
command_buffer.commit();
|
||||
command_buffer.wait_until_completed();
|
||||
drawable.present();
|
||||
|
||||
log::info!("present");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn schedule_synthetic_drag(window_state: &Rc<WindowState>, position: Vector2F) {
|
||||
let drag_id = window_state.next_synthetic_drag_id();
|
||||
fn schedule_synthetic_drag(window_state: &Rc<RefCell<WindowState>>, position: Vector2F) {
|
||||
let weak_window_state = Rc::downgrade(window_state);
|
||||
let mut window_state = window_state.as_ref().borrow_mut();
|
||||
|
||||
let drag_id = post_inc(&mut window_state.synthetic_drag_counter);
|
||||
let instant = Instant::now() + Duration::from_millis(16);
|
||||
|
||||
window_state
|
||||
.executor
|
||||
.spawn(async move {
|
||||
Timer::at(instant).await;
|
||||
if let Some(window_state) = weak_window_state.upgrade() {
|
||||
if window_state.synthetic_drag_counter.get() == drag_id {
|
||||
if let Some(callback) = window_state.event_callback.borrow_mut().as_mut() {
|
||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
||||
if window_state_borrow.synthetic_drag_counter == drag_id {
|
||||
if let Some(mut callback) = window_state_borrow.event_callback.take() {
|
||||
schedule_synthetic_drag(&window_state, position);
|
||||
callback(Event::LeftMouseDragged { position });
|
||||
callback(
|
||||
Event::LeftMouseDragged { position },
|
||||
&mut *window_state_borrow,
|
||||
);
|
||||
window_state_borrow.event_callback = Some(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ pub trait App {
|
|||
&self,
|
||||
options: WindowOptions,
|
||||
executor: Rc<executor::Foreground>,
|
||||
) -> Result<Rc<dyn Window>>;
|
||||
) -> Result<Box<dyn Window>>;
|
||||
}
|
||||
|
||||
pub trait Dispatcher: Send + Sync {
|
||||
|
@ -40,10 +40,15 @@ pub trait Dispatcher: Send + Sync {
|
|||
fn run_on_main_thread(&self, task: Runnable);
|
||||
}
|
||||
|
||||
pub trait Window {
|
||||
pub trait Window: WindowContext {
|
||||
fn on_event(&mut self, callback: Box<dyn FnMut(Event, &mut dyn WindowContext)>);
|
||||
fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn WindowContext)>);
|
||||
}
|
||||
|
||||
pub trait WindowContext {
|
||||
fn size(&self) -> Vector2F;
|
||||
fn scale_factor(&self) -> f32;
|
||||
fn render_scene(&self, scene: Scene);
|
||||
fn present_scene(&mut self, scene: Scene);
|
||||
}
|
||||
|
||||
pub struct WindowOptions<'a> {
|
||||
|
|
|
@ -6,12 +6,12 @@ pub struct Scene {
|
|||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Layer {
|
||||
pub struct Layer {
|
||||
clip_bounds: Option<RectF>,
|
||||
quads: Vec<Quad>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Quad {
|
||||
pub bounds: RectF,
|
||||
pub background: Option<ColorU>,
|
||||
|
@ -19,7 +19,7 @@ pub struct Quad {
|
|||
pub corder_radius: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
#[derive(Clone, Copy, Default, Debug)]
|
||||
pub struct Border {
|
||||
pub width: f32,
|
||||
pub color: Option<ColorU>,
|
||||
|
@ -38,13 +38,19 @@ impl Scene {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {}
|
||||
|
||||
pub fn pop_layer(&mut self) {
|
||||
assert!(self.active_layer_stack.len() > 1);
|
||||
self.active_layer_stack.pop();
|
||||
pub fn layers(&self) -> &[Layer] {
|
||||
self.layers.as_slice()
|
||||
}
|
||||
|
||||
// pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
|
||||
|
||||
// }
|
||||
|
||||
// pub fn pop_layer(&mut self) {
|
||||
// assert!(self.active_layer_stack.len() > 1);
|
||||
// self.active_layer_stack.pop();
|
||||
// }
|
||||
|
||||
pub fn push_quad(&mut self, quad: Quad) {
|
||||
self.active_layer().push_quad(quad)
|
||||
}
|
||||
|
@ -58,6 +64,10 @@ impl Layer {
|
|||
fn push_quad(&mut self, quad: Quad) {
|
||||
self.quads.push(quad);
|
||||
}
|
||||
|
||||
pub fn quads(&self) -> &[Quad] {
|
||||
self.quads.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Border {
|
||||
|
|
Loading…
Reference in a new issue