1#![allow(unsafe_code)]
5use crate::types::{Direction, PositionedGlyph, ShapingResult};
35
36#[repr(C)]
48#[derive(Debug, Clone, Copy, PartialEq)]
49pub struct PositionedGlyphC {
50 pub glyph_id: u32,
52 pub x: f32,
54 pub y: f32,
56 pub advance: f32,
58 pub cluster: u32,
60}
61
62impl From<&PositionedGlyph> for PositionedGlyphC {
63 fn from(g: &PositionedGlyph) -> Self {
64 Self {
65 glyph_id: g.id,
66 x: g.x,
67 y: g.y,
68 advance: g.advance,
69 cluster: g.cluster,
70 }
71 }
72}
73
74impl From<PositionedGlyph> for PositionedGlyphC {
75 fn from(g: PositionedGlyph) -> Self {
76 Self::from(&g)
77 }
78}
79
80impl From<&PositionedGlyphC> for PositionedGlyph {
81 fn from(g: &PositionedGlyphC) -> Self {
82 Self {
83 id: g.glyph_id,
84 x: g.x,
85 y: g.y,
86 advance: g.advance,
87 cluster: g.cluster,
88 }
89 }
90}
91
92#[repr(u8)]
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum DirectionC {
102 LeftToRight = 0,
103 RightToLeft = 1,
104 TopToBottom = 2,
105 BottomToTop = 3,
106}
107
108impl From<Direction> for DirectionC {
109 fn from(d: Direction) -> Self {
110 match d {
111 Direction::LeftToRight => DirectionC::LeftToRight,
112 Direction::RightToLeft => DirectionC::RightToLeft,
113 Direction::TopToBottom => DirectionC::TopToBottom,
114 Direction::BottomToTop => DirectionC::BottomToTop,
115 }
116 }
117}
118
119impl From<DirectionC> for Direction {
120 fn from(d: DirectionC) -> Self {
121 match d {
122 DirectionC::LeftToRight => Direction::LeftToRight,
123 DirectionC::RightToLeft => Direction::RightToLeft,
124 DirectionC::TopToBottom => Direction::TopToBottom,
125 DirectionC::BottomToTop => Direction::BottomToTop,
126 }
127 }
128}
129
130#[repr(C)]
145#[derive(Debug)]
146pub struct ShapingResultC {
147 pub glyphs: *mut PositionedGlyphC,
149 pub glyph_count: u32,
151 pub advance_width: f32,
153 pub advance_height: f32,
155 pub direction: DirectionC,
157 pub _reserved: [u8; 3],
159}
160
161impl ShapingResultC {
162 pub fn from_rust(result: &ShapingResult) -> Self {
167 let glyph_count = result.glyphs.len() as u32;
168 let glyphs = if glyph_count > 0 {
169 let mut vec: Vec<PositionedGlyphC> =
170 result.glyphs.iter().map(PositionedGlyphC::from).collect();
171 let ptr = vec.as_mut_ptr();
172 std::mem::forget(vec); ptr
174 } else {
175 std::ptr::null_mut()
176 };
177
178 Self {
179 glyphs,
180 glyph_count,
181 advance_width: result.advance_width,
182 advance_height: result.advance_height,
183 direction: result.direction.into(),
184 _reserved: [0; 3],
185 }
186 }
187
188 pub unsafe fn free(&mut self) {
195 if !self.glyphs.is_null() && self.glyph_count > 0 {
196 let _ = Vec::from_raw_parts(
197 self.glyphs,
198 self.glyph_count as usize,
199 self.glyph_count as usize,
200 );
201 self.glyphs = std::ptr::null_mut();
202 self.glyph_count = 0;
203 }
204 }
205
206 pub unsafe fn glyphs_slice(&self) -> &[PositionedGlyphC] {
213 if self.glyphs.is_null() || self.glyph_count == 0 {
214 &[]
215 } else {
216 std::slice::from_raw_parts(self.glyphs, self.glyph_count as usize)
217 }
218 }
219
220 pub unsafe fn to_rust(&self) -> ShapingResult {
228 let glyphs: Vec<PositionedGlyph> = self
229 .glyphs_slice()
230 .iter()
231 .map(PositionedGlyph::from)
232 .collect();
233
234 ShapingResult {
235 glyphs,
236 advance_width: self.advance_width,
237 advance_height: self.advance_height,
238 direction: self.direction.into(),
239 }
240 }
241}
242
243pub struct GlyphIterator<'a> {
262 glyphs: &'a [PositionedGlyph],
263 index: usize,
264}
265
266impl<'a> GlyphIterator<'a> {
267 pub fn new(result: &'a ShapingResult) -> Self {
269 Self {
270 glyphs: &result.glyphs,
271 index: 0,
272 }
273 }
274
275 pub fn len(&self) -> usize {
277 self.glyphs.len()
278 }
279
280 pub fn is_empty(&self) -> bool {
282 self.glyphs.is_empty()
283 }
284
285 pub fn remaining(&self) -> usize {
287 self.glyphs.len().saturating_sub(self.index)
288 }
289}
290
291impl<'a> Iterator for GlyphIterator<'a> {
292 type Item = PositionedGlyphC;
293
294 fn next(&mut self) -> Option<Self::Item> {
295 if self.index < self.glyphs.len() {
296 let glyph = PositionedGlyphC::from(&self.glyphs[self.index]);
297 self.index += 1;
298 Some(glyph)
299 } else {
300 None
301 }
302 }
303
304 fn size_hint(&self) -> (usize, Option<usize>) {
305 let remaining = self.remaining();
306 (remaining, Some(remaining))
307 }
308}
309
310impl<'a> ExactSizeIterator for GlyphIterator<'a> {}
311
312#[repr(C)]
343#[derive(Debug, Clone, Copy, PartialEq, Default)]
344pub struct Vertex2D {
345 pub x: f32,
347 pub y: f32,
349}
350
351impl Vertex2D {
352 #[inline]
354 pub const fn new(x: f32, y: f32) -> Self {
355 Self { x, y }
356 }
357
358 #[inline]
364 pub fn as_bytes(&self) -> &[u8] {
365 unsafe { std::slice::from_raw_parts(self as *const Self as *const u8, 8) }
367 }
368}
369
370#[repr(C)]
382#[derive(Debug, Clone, Copy, PartialEq, Default)]
383pub struct VertexUV {
384 pub x: f32,
386 pub y: f32,
388 pub u: f32,
390 pub v: f32,
392}
393
394impl VertexUV {
395 #[inline]
397 pub const fn new(x: f32, y: f32, u: f32, v: f32) -> Self {
398 Self { x, y, u, v }
399 }
400
401 #[inline]
403 pub fn as_bytes(&self) -> &[u8] {
404 unsafe { std::slice::from_raw_parts(self as *const Self as *const u8, 16) }
406 }
407}
408
409#[repr(C)]
419#[derive(Debug, Clone, Copy, PartialEq, Default)]
420pub struct VertexColor {
421 pub x: f32,
423 pub y: f32,
425 pub r: f32,
427 pub g: f32,
429 pub b: f32,
431 pub a: f32,
433}
434
435impl VertexColor {
436 #[inline]
438 pub const fn new(x: f32, y: f32, r: f32, g: f32, b: f32, a: f32) -> Self {
439 Self { x, y, r, g, b, a }
440 }
441
442 #[inline]
444 pub fn as_bytes(&self) -> &[u8] {
445 unsafe { std::slice::from_raw_parts(self as *const Self as *const u8, 24) }
447 }
448}
449
450#[derive(Debug, Clone)]
474pub struct GlyphMesh<V> {
475 pub vertices: Vec<V>,
477 pub indices: Vec<u32>,
479 pub glyph_id: u32,
481}
482
483impl<V> GlyphMesh<V> {
484 pub fn new(glyph_id: u32) -> Self {
486 Self {
487 vertices: Vec::new(),
488 indices: Vec::new(),
489 glyph_id,
490 }
491 }
492
493 pub fn with_capacity(glyph_id: u32, vertex_capacity: usize, index_capacity: usize) -> Self {
495 Self {
496 vertices: Vec::with_capacity(vertex_capacity),
497 indices: Vec::with_capacity(index_capacity),
498 glyph_id,
499 }
500 }
501
502 pub fn triangle_count(&self) -> usize {
504 self.indices.len() / 3
505 }
506
507 pub fn is_empty(&self) -> bool {
509 self.vertices.is_empty() || self.indices.is_empty()
510 }
511}
512
513impl<V: Copy> GlyphMesh<V> {
514 pub fn vertices_bytes(&self) -> &[u8] {
521 if self.vertices.is_empty() {
522 return &[];
523 }
524 let ptr = self.vertices.as_ptr() as *const u8;
525 let len = self.vertices.len() * std::mem::size_of::<V>();
526 unsafe { std::slice::from_raw_parts(ptr, len) }
528 }
529}
530
531impl<V> GlyphMesh<V> {
532 pub fn indices_bytes(&self) -> &[u8] {
534 if self.indices.is_empty() {
535 return &[];
536 }
537 let ptr = self.indices.as_ptr() as *const u8;
538 let len = self.indices.len() * 4; unsafe { std::slice::from_raw_parts(ptr, len) }
541 }
542}
543
544#[derive(Debug, Clone)]
567pub struct RenderMesh<V> {
568 pub glyphs: Vec<GlyphMesh<V>>,
570 pub total_vertices: usize,
572 pub total_indices: usize,
574}
575
576impl<V> Default for RenderMesh<V> {
577 fn default() -> Self {
578 Self::new()
579 }
580}
581
582impl<V> RenderMesh<V> {
583 pub fn new() -> Self {
585 Self {
586 glyphs: Vec::new(),
587 total_vertices: 0,
588 total_indices: 0,
589 }
590 }
591
592 pub fn with_capacity(glyph_count: usize) -> Self {
594 Self {
595 glyphs: Vec::with_capacity(glyph_count),
596 total_vertices: 0,
597 total_indices: 0,
598 }
599 }
600
601 pub fn push(&mut self, mesh: GlyphMesh<V>) {
603 self.total_vertices += mesh.vertices.len();
604 self.total_indices += mesh.indices.len();
605 self.glyphs.push(mesh);
606 }
607
608 pub fn glyph_count(&self) -> usize {
610 self.glyphs.len()
611 }
612
613 pub fn is_empty(&self) -> bool {
615 self.glyphs.is_empty()
616 }
617
618 pub fn total_triangles(&self) -> usize {
620 self.total_indices / 3
621 }
622}
623
624impl<V: Copy> RenderMesh<V> {
625 pub fn merge_all(&self) -> (Vec<V>, Vec<u32>) {
632 let mut vertices = Vec::with_capacity(self.total_vertices);
633 let mut indices = Vec::with_capacity(self.total_indices);
634
635 for glyph in &self.glyphs {
636 let base_index = vertices.len() as u32;
637 vertices.extend_from_slice(&glyph.vertices);
638 indices.extend(glyph.indices.iter().map(|i| i + base_index));
639 }
640
641 (vertices, indices)
642 }
643
644 pub fn merge_to_bytes(&self) -> (Vec<u8>, Vec<u8>) {
648 let (vertices, indices) = self.merge_all();
649
650 let vertex_bytes = if vertices.is_empty() {
651 Vec::new()
652 } else {
653 let ptr = vertices.as_ptr() as *const u8;
654 let len = vertices.len() * std::mem::size_of::<V>();
655 unsafe { std::slice::from_raw_parts(ptr, len).to_vec() }
657 };
658
659 let index_bytes = if indices.is_empty() {
660 Vec::new()
661 } else {
662 let ptr = indices.as_ptr() as *const u8;
663 let len = indices.len() * 4;
664 unsafe { std::slice::from_raw_parts(ptr, len).to_vec() }
666 };
667
668 (vertex_bytes, index_bytes)
669 }
670}
671
672const _: () = {
677 assert!(std::mem::size_of::<PositionedGlyphC>() == 20);
679 assert!(std::mem::align_of::<PositionedGlyphC>() == 4);
681 assert!(std::mem::size_of::<DirectionC>() == 1);
683
684 assert!(std::mem::size_of::<Vertex2D>() == 8);
686 assert!(std::mem::align_of::<Vertex2D>() == 4);
687 assert!(std::mem::size_of::<VertexUV>() == 16);
688 assert!(std::mem::align_of::<VertexUV>() == 4);
689 assert!(std::mem::size_of::<VertexColor>() == 24);
690 assert!(std::mem::align_of::<VertexColor>() == 4);
691};
692
693#[cfg(test)]
694mod tests {
695 use super::*;
696
697 #[test]
698 fn test_positioned_glyph_c_conversion() {
699 let rust_glyph = PositionedGlyph {
700 id: 42,
701 x: 10.5,
702 y: 20.5,
703 advance: 15.0,
704 cluster: 3,
705 };
706
707 let c_glyph = PositionedGlyphC::from(&rust_glyph);
708 assert_eq!(c_glyph.glyph_id, 42);
709 assert_eq!(c_glyph.x, 10.5);
710 assert_eq!(c_glyph.y, 20.5);
711 assert_eq!(c_glyph.advance, 15.0);
712 assert_eq!(c_glyph.cluster, 3);
713
714 let back = PositionedGlyph::from(&c_glyph);
715 assert_eq!(back, rust_glyph);
716 }
717
718 #[test]
719 fn test_direction_c_conversion() {
720 assert_eq!(
721 DirectionC::from(Direction::LeftToRight),
722 DirectionC::LeftToRight
723 );
724 assert_eq!(
725 DirectionC::from(Direction::RightToLeft),
726 DirectionC::RightToLeft
727 );
728 assert_eq!(
729 DirectionC::from(Direction::TopToBottom),
730 DirectionC::TopToBottom
731 );
732 assert_eq!(
733 DirectionC::from(Direction::BottomToTop),
734 DirectionC::BottomToTop
735 );
736
737 assert_eq!(
738 Direction::from(DirectionC::LeftToRight),
739 Direction::LeftToRight
740 );
741 assert_eq!(
742 Direction::from(DirectionC::RightToLeft),
743 Direction::RightToLeft
744 );
745 }
746
747 #[test]
748 fn test_shaping_result_c_roundtrip() {
749 let rust_result = ShapingResult {
750 glyphs: vec![
751 PositionedGlyph {
752 id: 1,
753 x: 0.0,
754 y: 0.0,
755 advance: 10.0,
756 cluster: 0,
757 },
758 PositionedGlyph {
759 id: 2,
760 x: 10.0,
761 y: 0.0,
762 advance: 12.0,
763 cluster: 1,
764 },
765 PositionedGlyph {
766 id: 3,
767 x: 22.0,
768 y: 0.0,
769 advance: 8.0,
770 cluster: 2,
771 },
772 ],
773 advance_width: 30.0,
774 advance_height: 0.0,
775 direction: Direction::LeftToRight,
776 };
777
778 let mut c_result = ShapingResultC::from_rust(&rust_result);
779 assert_eq!(c_result.glyph_count, 3);
780 assert_eq!(c_result.advance_width, 30.0);
781 assert_eq!(c_result.direction, DirectionC::LeftToRight);
782
783 unsafe {
784 let slice = c_result.glyphs_slice();
785 assert_eq!(slice.len(), 3);
786 assert_eq!(slice[0].glyph_id, 1);
787 assert_eq!(slice[1].x, 10.0);
788 assert_eq!(slice[2].advance, 8.0);
789
790 let back = c_result.to_rust();
791 assert_eq!(back.glyphs.len(), 3);
792 assert_eq!(back.advance_width, 30.0);
793 assert_eq!(back.direction, Direction::LeftToRight);
794
795 c_result.free();
796 assert!(c_result.glyphs.is_null());
797 assert_eq!(c_result.glyph_count, 0);
798 }
799 }
800
801 #[test]
802 fn test_shaping_result_c_empty() {
803 let rust_result = ShapingResult {
804 glyphs: vec![],
805 advance_width: 0.0,
806 advance_height: 0.0,
807 direction: Direction::LeftToRight,
808 };
809
810 let mut c_result = ShapingResultC::from_rust(&rust_result);
811 assert_eq!(c_result.glyph_count, 0);
812 assert!(c_result.glyphs.is_null());
813
814 unsafe {
815 let slice = c_result.glyphs_slice();
816 assert!(slice.is_empty());
817 c_result.free(); }
819 }
820
821 #[test]
822 fn test_glyph_iterator() {
823 let result = ShapingResult {
824 glyphs: vec![
825 PositionedGlyph {
826 id: 1,
827 x: 0.0,
828 y: 0.0,
829 advance: 10.0,
830 cluster: 0,
831 },
832 PositionedGlyph {
833 id: 2,
834 x: 10.0,
835 y: 0.0,
836 advance: 12.0,
837 cluster: 1,
838 },
839 ],
840 advance_width: 22.0,
841 advance_height: 0.0,
842 direction: Direction::LeftToRight,
843 };
844
845 let iter = GlyphIterator::new(&result);
846 assert_eq!(iter.len(), 2);
847 assert!(!iter.is_empty());
848 assert_eq!(iter.remaining(), 2);
849
850 let collected: Vec<_> = GlyphIterator::new(&result).collect();
851 assert_eq!(collected.len(), 2);
852 assert_eq!(collected[0].glyph_id, 1);
853 assert_eq!(collected[1].glyph_id, 2);
854 }
855
856 #[test]
857 fn test_size_alignment() {
858 assert_eq!(std::mem::size_of::<PositionedGlyphC>(), 20);
860 assert_eq!(std::mem::align_of::<PositionedGlyphC>(), 4);
861 assert_eq!(std::mem::size_of::<DirectionC>(), 1);
862 }
863
864 #[test]
869 fn test_vertex2d_size_alignment() {
870 assert_eq!(std::mem::size_of::<Vertex2D>(), 8);
871 assert_eq!(std::mem::align_of::<Vertex2D>(), 4);
872 }
873
874 #[test]
875 fn test_vertex_uv_size_alignment() {
876 assert_eq!(std::mem::size_of::<VertexUV>(), 16);
877 assert_eq!(std::mem::align_of::<VertexUV>(), 4);
878 }
879
880 #[test]
881 fn test_vertex_color_size_alignment() {
882 assert_eq!(std::mem::size_of::<VertexColor>(), 24);
883 assert_eq!(std::mem::align_of::<VertexColor>(), 4);
884 }
885
886 #[test]
887 fn test_vertex2d_as_bytes() {
888 let v = Vertex2D::new(1.0, 2.0);
889 let bytes = v.as_bytes();
890 assert_eq!(bytes.len(), 8);
891
892 let x_bytes = 1.0_f32.to_ne_bytes();
894 let y_bytes = 2.0_f32.to_ne_bytes();
895 assert_eq!(&bytes[0..4], &x_bytes);
896 assert_eq!(&bytes[4..8], &y_bytes);
897 }
898
899 #[test]
900 fn test_vertex_uv_as_bytes() {
901 let v = VertexUV::new(1.0, 2.0, 0.5, 0.75);
902 let bytes = v.as_bytes();
903 assert_eq!(bytes.len(), 16);
904
905 let x_bytes = 1.0_f32.to_ne_bytes();
907 let u_bytes = 0.5_f32.to_ne_bytes();
908 assert_eq!(&bytes[0..4], &x_bytes);
909 assert_eq!(&bytes[8..12], &u_bytes);
910 }
911
912 #[test]
913 fn test_vertex_color_as_bytes() {
914 let v = VertexColor::new(1.0, 2.0, 1.0, 0.0, 0.0, 1.0);
915 let bytes = v.as_bytes();
916 assert_eq!(bytes.len(), 24);
917
918 let r_bytes = 1.0_f32.to_ne_bytes();
920 assert_eq!(&bytes[8..12], &r_bytes); }
922
923 #[test]
924 fn test_glyph_mesh_creation() {
925 let mesh: GlyphMesh<Vertex2D> = GlyphMesh::new(42);
926 assert_eq!(mesh.glyph_id, 42);
927 assert!(mesh.is_empty());
928 assert_eq!(mesh.triangle_count(), 0);
929 }
930
931 #[test]
932 fn test_glyph_mesh_with_triangle() {
933 let mut mesh: GlyphMesh<Vertex2D> = GlyphMesh::new(1);
934 mesh.vertices = vec![
935 Vertex2D::new(0.0, 0.0),
936 Vertex2D::new(1.0, 0.0),
937 Vertex2D::new(0.5, 1.0),
938 ];
939 mesh.indices = vec![0, 1, 2];
940
941 assert!(!mesh.is_empty());
942 assert_eq!(mesh.triangle_count(), 1);
943
944 let vb = mesh.vertices_bytes();
945 assert_eq!(vb.len(), 24); let ib = mesh.indices_bytes();
948 assert_eq!(ib.len(), 12); }
950
951 #[test]
952 fn test_render_mesh_push() {
953 let mut rm: RenderMesh<Vertex2D> = RenderMesh::new();
954 assert!(rm.is_empty());
955
956 let mut mesh1 = GlyphMesh::new(1);
957 mesh1.vertices = vec![
958 Vertex2D::new(0.0, 0.0),
959 Vertex2D::new(1.0, 0.0),
960 Vertex2D::new(0.5, 1.0),
961 ];
962 mesh1.indices = vec![0, 1, 2];
963
964 rm.push(mesh1);
965 assert_eq!(rm.glyph_count(), 1);
966 assert_eq!(rm.total_vertices, 3);
967 assert_eq!(rm.total_indices, 3);
968 assert_eq!(rm.total_triangles(), 1);
969 }
970
971 #[test]
972 fn test_render_mesh_merge() {
973 let mut rm: RenderMesh<Vertex2D> = RenderMesh::new();
974
975 let mut mesh1 = GlyphMesh::new(1);
977 mesh1.vertices = vec![
978 Vertex2D::new(0.0, 0.0),
979 Vertex2D::new(1.0, 0.0),
980 Vertex2D::new(0.5, 1.0),
981 ];
982 mesh1.indices = vec![0, 1, 2];
983
984 let mut mesh2 = GlyphMesh::new(2);
986 mesh2.vertices = vec![
987 Vertex2D::new(2.0, 0.0),
988 Vertex2D::new(3.0, 0.0),
989 Vertex2D::new(2.5, 1.0),
990 ];
991 mesh2.indices = vec![0, 1, 2];
992
993 rm.push(mesh1);
994 rm.push(mesh2);
995
996 let (vertices, indices) = rm.merge_all();
997 assert_eq!(vertices.len(), 6);
998 assert_eq!(indices.len(), 6);
999
1000 assert_eq!(indices[0], 0);
1002 assert_eq!(indices[1], 1);
1003 assert_eq!(indices[2], 2);
1004
1005 assert_eq!(indices[3], 3);
1007 assert_eq!(indices[4], 4);
1008 assert_eq!(indices[5], 5);
1009 }
1010
1011 #[test]
1012 fn test_render_mesh_merge_to_bytes() {
1013 let mut rm: RenderMesh<Vertex2D> = RenderMesh::new();
1014
1015 let mut mesh = GlyphMesh::new(1);
1016 mesh.vertices = vec![
1017 Vertex2D::new(0.0, 0.0),
1018 Vertex2D::new(1.0, 0.0),
1019 Vertex2D::new(0.5, 1.0),
1020 ];
1021 mesh.indices = vec![0, 1, 2];
1022
1023 rm.push(mesh);
1024
1025 let (vb, ib) = rm.merge_to_bytes();
1026 assert_eq!(vb.len(), 24); assert_eq!(ib.len(), 12); }
1029
1030 #[test]
1031 fn test_render_mesh_empty() {
1032 let rm: RenderMesh<Vertex2D> = RenderMesh::new();
1033 let (vertices, indices) = rm.merge_all();
1034 assert!(vertices.is_empty());
1035 assert!(indices.is_empty());
1036
1037 let (vb, ib) = rm.merge_to_bytes();
1038 assert!(vb.is_empty());
1039 assert!(ib.is_empty());
1040 }
1041
1042 #[test]
1043 fn test_vertex_default() {
1044 let v2d = Vertex2D::default();
1045 assert_eq!(v2d.x, 0.0);
1046 assert_eq!(v2d.y, 0.0);
1047
1048 let vuv = VertexUV::default();
1049 assert_eq!(vuv.x, 0.0);
1050 assert_eq!(vuv.u, 0.0);
1051
1052 let vc = VertexColor::default();
1053 assert_eq!(vc.x, 0.0);
1054 assert_eq!(vc.r, 0.0);
1055 assert_eq!(vc.a, 0.0);
1056 }
1057}