WIP
This commit is contained in:
parent
4cf2ba20c2
commit
cd1c137542
7 changed files with 235 additions and 15 deletions
|
@ -148,6 +148,7 @@ pub trait PlatformWindow {
|
|||
fn draw(&self, scene: Scene);
|
||||
|
||||
fn monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas>;
|
||||
fn polychrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas>;
|
||||
}
|
||||
|
||||
pub trait PlatformDispatcher: Send + Sync {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{
|
||||
point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, Quad, Scene, Size,
|
||||
point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, PolychromeSprite,
|
||||
Quad, Scene, Size,
|
||||
};
|
||||
use cocoa::{
|
||||
base::{NO, YES},
|
||||
|
@ -21,6 +22,7 @@ pub struct MetalRenderer {
|
|||
unit_vertices: metal::Buffer,
|
||||
instances: metal::Buffer,
|
||||
monochrome_sprite_atlas: Arc<MetalAtlas>,
|
||||
polychrome_sprite_atlas: Arc<MetalAtlas>,
|
||||
}
|
||||
|
||||
impl MetalRenderer {
|
||||
|
@ -107,6 +109,14 @@ impl MetalRenderer {
|
|||
MTLPixelFormat::A8Unorm,
|
||||
device.clone(),
|
||||
));
|
||||
let polychrome_sprite_atlas = Arc::new(MetalAtlas::new(
|
||||
Size {
|
||||
width: DevicePixels(1024),
|
||||
height: DevicePixels(768),
|
||||
},
|
||||
MTLPixelFormat::BGRA8Unorm,
|
||||
device.clone(),
|
||||
));
|
||||
|
||||
Self {
|
||||
layer,
|
||||
|
@ -116,6 +126,7 @@ impl MetalRenderer {
|
|||
unit_vertices,
|
||||
instances,
|
||||
monochrome_sprite_atlas,
|
||||
polychrome_sprite_atlas,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,6 +138,10 @@ impl MetalRenderer {
|
|||
&self.monochrome_sprite_atlas
|
||||
}
|
||||
|
||||
pub fn polychrome_sprite_atlas(&self) -> &Arc<MetalAtlas> {
|
||||
&self.polychrome_sprite_atlas
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, scene: &mut Scene) {
|
||||
let layer = self.layer.clone();
|
||||
let viewport_size = layer.drawable_size();
|
||||
|
@ -180,7 +195,7 @@ impl MetalRenderer {
|
|||
command_encoder,
|
||||
);
|
||||
}
|
||||
crate::PrimitiveBatch::Sprites {
|
||||
crate::PrimitiveBatch::MonochromeSprites {
|
||||
texture_id,
|
||||
sprites,
|
||||
} => {
|
||||
|
@ -192,6 +207,18 @@ impl MetalRenderer {
|
|||
command_encoder,
|
||||
);
|
||||
}
|
||||
crate::PrimitiveBatch::PolychromeSprites {
|
||||
texture_id,
|
||||
sprites,
|
||||
} => {
|
||||
self.draw_polychrome_sprites(
|
||||
texture_id,
|
||||
sprites,
|
||||
&mut instance_offset,
|
||||
viewport_size,
|
||||
command_encoder,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -337,6 +364,81 @@ impl MetalRenderer {
|
|||
);
|
||||
*offset = next_offset;
|
||||
}
|
||||
|
||||
fn draw_polychrome_sprites(
|
||||
&mut self,
|
||||
texture_id: AtlasTextureId,
|
||||
sprites: &[PolychromeSprite],
|
||||
offset: &mut usize,
|
||||
viewport_size: Size<DevicePixels>,
|
||||
command_encoder: &metal::RenderCommandEncoderRef,
|
||||
) {
|
||||
todo!()
|
||||
// if sprites.is_empty() {
|
||||
// return;
|
||||
// }
|
||||
// align_offset(offset);
|
||||
|
||||
// let texture = self.monochrome_sprite_atlas.texture(texture_id);
|
||||
// let texture_size = size(
|
||||
// DevicePixels(texture.width() as i32),
|
||||
// DevicePixels(texture.height() as i32),
|
||||
// );
|
||||
// command_encoder.set_render_pipeline_state(&self.sprites_pipeline_state);
|
||||
// command_encoder.set_vertex_buffer(
|
||||
// MonochromeSpriteInputIndex::Vertices as u64,
|
||||
// Some(&self.unit_vertices),
|
||||
// 0,
|
||||
// );
|
||||
// command_encoder.set_vertex_buffer(
|
||||
// MonochromeSpriteInputIndex::Sprites as u64,
|
||||
// Some(&self.instances),
|
||||
// *offset as u64,
|
||||
// );
|
||||
// command_encoder.set_vertex_bytes(
|
||||
// MonochromeSpriteInputIndex::ViewportSize as u64,
|
||||
// mem::size_of_val(&viewport_size) as u64,
|
||||
// &viewport_size as *const Size<DevicePixels> as *const _,
|
||||
// );
|
||||
// command_encoder.set_vertex_bytes(
|
||||
// MonochromeSpriteInputIndex::AtlasTextureSize as u64,
|
||||
// mem::size_of_val(&texture_size) as u64,
|
||||
// &texture_size as *const Size<DevicePixels> as *const _,
|
||||
// );
|
||||
// command_encoder.set_fragment_buffer(
|
||||
// MonochromeSpriteInputIndex::Sprites as u64,
|
||||
// Some(&self.instances),
|
||||
// *offset as u64,
|
||||
// );
|
||||
// command_encoder.set_fragment_texture(
|
||||
// MonochromeSpriteInputIndex::AtlasTexture as u64,
|
||||
// Some(&texture),
|
||||
// );
|
||||
|
||||
// let sprite_bytes_len = mem::size_of::<MonochromeSprite>() * sprites.len();
|
||||
// let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) };
|
||||
// unsafe {
|
||||
// ptr::copy_nonoverlapping(
|
||||
// sprites.as_ptr() as *const u8,
|
||||
// buffer_contents,
|
||||
// sprite_bytes_len,
|
||||
// );
|
||||
// }
|
||||
|
||||
// let next_offset = *offset + sprite_bytes_len;
|
||||
// assert!(
|
||||
// next_offset <= INSTANCE_BUFFER_SIZE,
|
||||
// "instance buffer exhausted"
|
||||
// );
|
||||
|
||||
// command_encoder.draw_primitives_instanced(
|
||||
// metal::MTLPrimitiveType::Triangle,
|
||||
// 0,
|
||||
// 6,
|
||||
// sprites.len() as u64,
|
||||
// );
|
||||
// *offset = next_offset;
|
||||
}
|
||||
}
|
||||
|
||||
fn build_pipeline_state(
|
||||
|
|
|
@ -889,6 +889,10 @@ impl PlatformWindow for MacWindow {
|
|||
fn monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
|
||||
self.0.lock().renderer.monochrome_sprite_atlas().clone()
|
||||
}
|
||||
|
||||
fn polychrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
|
||||
self.0.lock().renderer.polychrome_sprite_atlas().clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_scale_factor(native_window: id) -> f32 {
|
||||
|
|
|
@ -38,8 +38,11 @@ impl Scene {
|
|||
Primitive::Quad(quad) => {
|
||||
layer.quads.push(quad);
|
||||
}
|
||||
Primitive::Sprite(sprite) => {
|
||||
layer.sprites.push(sprite);
|
||||
Primitive::MonochromeSprite(sprite) => {
|
||||
layer.monochrome_sprites.push(sprite);
|
||||
}
|
||||
Primitive::PolychromeSprite(sprite) => {
|
||||
layer.polychrome_sprites.push(sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,19 +55,20 @@ impl Scene {
|
|||
#[derive(Debug, Default)]
|
||||
pub(crate) struct SceneLayer {
|
||||
pub quads: Vec<Quad>,
|
||||
pub sprites: Vec<MonochromeSprite>,
|
||||
pub monochrome_sprites: Vec<MonochromeSprite>,
|
||||
pub polychrome_sprites: Vec<PolychromeSprite>,
|
||||
}
|
||||
|
||||
impl SceneLayer {
|
||||
pub fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> {
|
||||
self.quads.sort_unstable();
|
||||
self.sprites.sort_unstable();
|
||||
self.monochrome_sprites.sort_unstable();
|
||||
|
||||
BatchIterator::new(
|
||||
&self.quads,
|
||||
self.quads.iter().peekable(),
|
||||
&self.sprites,
|
||||
self.sprites.iter().peekable(),
|
||||
&self.monochrome_sprites,
|
||||
self.monochrome_sprites.iter().peekable(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +135,7 @@ where
|
|||
})
|
||||
.count();
|
||||
self.sprites_start = sprites_end;
|
||||
Some(PrimitiveBatch::Sprites {
|
||||
Some(PrimitiveBatch::MonochromeSprites {
|
||||
texture_id,
|
||||
sprites: &self.sprites[sprites_start..sprites_end],
|
||||
})
|
||||
|
@ -171,15 +175,20 @@ pub enum PrimitiveKind {
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum Primitive {
|
||||
Quad(Quad),
|
||||
Sprite(MonochromeSprite),
|
||||
MonochromeSprite(MonochromeSprite),
|
||||
PolychromeSprite(PolychromeSprite),
|
||||
}
|
||||
|
||||
pub(crate) enum PrimitiveBatch<'a> {
|
||||
Quads(&'a [Quad]),
|
||||
Sprites {
|
||||
MonochromeSprites {
|
||||
texture_id: AtlasTextureId,
|
||||
sprites: &'a [MonochromeSprite],
|
||||
},
|
||||
PolychromeSprites {
|
||||
texture_id: AtlasTextureId,
|
||||
sprites: &'a [PolychromeSprite],
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
|
@ -256,7 +265,37 @@ impl PartialOrd for MonochromeSprite {
|
|||
|
||||
impl From<MonochromeSprite> for Primitive {
|
||||
fn from(sprite: MonochromeSprite) -> Self {
|
||||
Primitive::Sprite(sprite)
|
||||
Primitive::MonochromeSprite(sprite)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct PolychromeSprite {
|
||||
pub order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ScaledContentMask,
|
||||
pub tile: AtlasTile,
|
||||
}
|
||||
|
||||
impl Ord for PolychromeSprite {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
match self.order.cmp(&other.order) {
|
||||
std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
|
||||
order => order,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for PolychromeSprite {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PolychromeSprite> for Primitive {
|
||||
fn from(sprite: PolychromeSprite) -> Self {
|
||||
Primitive::PolychromeSprite(sprite)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -404,6 +404,25 @@ impl Hash for RenderGlyphParams {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct RenderEmojiParams {
|
||||
pub(crate) font_id: FontId,
|
||||
pub(crate) glyph_id: GlyphId,
|
||||
pub(crate) font_size: Pixels,
|
||||
pub(crate) scale_factor: f32,
|
||||
}
|
||||
|
||||
impl Eq for RenderEmojiParams {}
|
||||
|
||||
impl Hash for RenderEmojiParams {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.font_id.0.hash(state);
|
||||
self.glyph_id.0.hash(state);
|
||||
self.font_size.0.to_bits().hash(state);
|
||||
self.scale_factor.to_bits().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Font {
|
||||
pub family: SharedString,
|
||||
|
|
|
@ -159,7 +159,13 @@ impl Line {
|
|||
}
|
||||
|
||||
if glyph.is_emoji {
|
||||
todo!()
|
||||
cx.paint_emoji(
|
||||
glyph_origin,
|
||||
layout.order,
|
||||
run.font_id,
|
||||
glyph.id,
|
||||
self.layout.font_size,
|
||||
)?;
|
||||
} else {
|
||||
cx.paint_glyph(
|
||||
glyph_origin,
|
||||
|
|
|
@ -2,8 +2,8 @@ use crate::{
|
|||
px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners,
|
||||
DevicePixels, Effect, Element, EntityId, FontId, GlyphId, Handle, Hsla, IsZero, LayerId,
|
||||
LayoutId, MainThread, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow,
|
||||
Point, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, SharedString, Size,
|
||||
Style, TaffyLayoutEngine, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
Point, PolychromeSprite, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene,
|
||||
SharedString, Size, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use futures::Future;
|
||||
|
@ -17,6 +17,7 @@ pub struct Window {
|
|||
handle: AnyWindowHandle,
|
||||
platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
|
||||
monochrome_sprite_atlas: Arc<dyn PlatformAtlas>,
|
||||
polychrome_sprite_atlas: Arc<dyn PlatformAtlas>,
|
||||
rem_size: Pixels,
|
||||
content_size: Size<Pixels>,
|
||||
layout_engine: TaffyLayoutEngine,
|
||||
|
@ -36,6 +37,7 @@ impl Window {
|
|||
) -> Self {
|
||||
let platform_window = cx.platform().open_window(handle, options);
|
||||
let monochrome_sprite_atlas = platform_window.monochrome_sprite_atlas();
|
||||
let polychrome_sprite_atlas = platform_window.polychrome_sprite_atlas();
|
||||
let mouse_position = platform_window.mouse_position();
|
||||
let content_size = platform_window.content_size();
|
||||
let scale_factor = platform_window.scale_factor();
|
||||
|
@ -59,6 +61,7 @@ impl Window {
|
|||
handle,
|
||||
platform_window,
|
||||
monochrome_sprite_atlas,
|
||||
polychrome_sprite_atlas,
|
||||
rem_size: px(16.),
|
||||
content_size,
|
||||
layout_engine: TaffyLayoutEngine::new(),
|
||||
|
@ -300,6 +303,52 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn paint_emoji(
|
||||
&mut self,
|
||||
origin: Point<Pixels>,
|
||||
order: u32,
|
||||
font_id: FontId,
|
||||
glyph_id: GlyphId,
|
||||
font_size: Pixels,
|
||||
) -> Result<()> {
|
||||
let scale_factor = self.scale_factor();
|
||||
let glyph_origin = origin.scale(scale_factor);
|
||||
let params = RenderGlyphParams {
|
||||
font_id,
|
||||
glyph_id,
|
||||
font_size,
|
||||
subpixel_variant: Default::default(),
|
||||
scale_factor,
|
||||
};
|
||||
|
||||
let raster_bounds = self.text_system().raster_bounds(¶ms)?;
|
||||
if !raster_bounds.is_zero() {
|
||||
let layer_id = self.current_layer_id();
|
||||
let tile = self
|
||||
.window
|
||||
.polychrome_sprite_atlas
|
||||
.get_or_insert_with(¶ms.clone().into(), &mut || {
|
||||
self.text_system().rasterize_glyph(¶ms)
|
||||
})?;
|
||||
let bounds = Bounds {
|
||||
origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
|
||||
size: tile.bounds.size.map(Into::into),
|
||||
};
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
|
||||
self.window.scene.insert(
|
||||
layer_id,
|
||||
PolychromeSprite {
|
||||
order,
|
||||
bounds,
|
||||
content_mask,
|
||||
tile,
|
||||
},
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn draw(&mut self) -> Result<()> {
|
||||
let unit_entity = self.unit_entity.clone();
|
||||
self.update_entity(&unit_entity, |_, cx| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue