Detailed changes
@@ -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| {