render.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use crate::{
  19. gfx::{GfxDrawInstruction, GfxDrawMesh, Rectangle, RenderApi},
  20. mesh::{Color, MeshBuilder, COLOR_WHITE},
  21. };
  22. use super::atlas::Atlas;
  23. #[derive(Copy, Clone, Debug, PartialEq, Eq)]
  24. pub struct DebugRenderOptions(u32);
  25. impl DebugRenderOptions {
  26. pub const Off: DebugRenderOptions = DebugRenderOptions(0b00);
  27. pub const Glyph: DebugRenderOptions = DebugRenderOptions(0b01);
  28. pub const Baseline: DebugRenderOptions = DebugRenderOptions(0b10);
  29. pub fn has(self, other: Self) -> bool {
  30. (self.0 & other.0) == other.0
  31. }
  32. }
  33. impl std::ops::BitOr for DebugRenderOptions {
  34. type Output = Self;
  35. fn bitor(self, rhs: Self) -> Self {
  36. Self(self.0 | rhs.0)
  37. }
  38. }
  39. pub fn render_layout(
  40. layout: &parley::Layout<Color>,
  41. render_api: &RenderApi,
  42. ) -> Vec<GfxDrawInstruction> {
  43. render_layout_with_opts(layout, DebugRenderOptions::Off, render_api)
  44. }
  45. pub fn render_layout_with_opts(
  46. layout: &parley::Layout<Color>,
  47. opts: DebugRenderOptions,
  48. render_api: &RenderApi,
  49. ) -> Vec<GfxDrawInstruction> {
  50. let mut scale_cx = swash::scale::ScaleContext::new();
  51. let mut run_idx = 0;
  52. let mut instrs = vec![];
  53. for line in layout.lines() {
  54. for item in line.items() {
  55. match item {
  56. parley::PositionedLayoutItem::GlyphRun(glyph_run) => {
  57. let mesh =
  58. render_glyph_run(&mut scale_cx, &glyph_run, run_idx, opts, render_api);
  59. instrs.push(GfxDrawInstruction::Draw(mesh));
  60. run_idx += 1;
  61. }
  62. parley::PositionedLayoutItem::InlineBox(_) => {}
  63. }
  64. }
  65. }
  66. instrs
  67. }
  68. fn render_glyph_run(
  69. scale_ctx: &mut swash::scale::ScaleContext,
  70. glyph_run: &parley::GlyphRun<'_, Color>,
  71. run_idx: usize,
  72. opts: DebugRenderOptions,
  73. render_api: &RenderApi,
  74. ) -> GfxDrawMesh {
  75. let mut run_x = glyph_run.offset();
  76. let run_y = glyph_run.baseline();
  77. let style = glyph_run.style();
  78. let color = style.brush;
  79. let run = glyph_run.run();
  80. trace!(target: "text::render", "render_glyph_run run_idx={run_idx}");
  81. let font = run.font();
  82. let font_size = run.font_size();
  83. let normalized_coords = run.normalized_coords();
  84. let font_ref = swash::FontRef::from_index(font.data.as_ref(), font.index as usize).unwrap();
  85. let mut scaler = scale_ctx
  86. .builder(font_ref)
  87. .size(font_size)
  88. .hint(true)
  89. .normalized_coords(normalized_coords)
  90. .build();
  91. let mut atlas = Atlas::new(scaler, render_api);
  92. for glyph in glyph_run.glyphs() {
  93. atlas.push_glyph(glyph);
  94. }
  95. //atlas.dump(&format!("/tmp/atlas_{run_idx}.png"));
  96. let atlas = atlas.make();
  97. let mut mesh = MeshBuilder::new();
  98. for glyph in glyph_run.glyphs() {
  99. let glyph_inf = atlas.fetch_uv(glyph.id).expect("missing glyph UV rect");
  100. let glyph_x = run_x + glyph.x;
  101. let glyph_y = run_y - glyph.y;
  102. run_x += glyph.advance;
  103. let glyph_rect = Rectangle::new(
  104. glyph_x + glyph_inf.place.left as f32,
  105. glyph_y - glyph_inf.place.top as f32,
  106. glyph_inf.place.width as f32,
  107. glyph_inf.place.height as f32,
  108. );
  109. if opts.has(DebugRenderOptions::Glyph) {
  110. mesh.draw_outline(&glyph_rect, [0., 1., 0., 0.7], 1.);
  111. }
  112. let color = if glyph_inf.is_color { COLOR_WHITE } else { color };
  113. mesh.draw_box(&glyph_rect, color, &glyph_inf.uv_rect);
  114. }
  115. if opts.has(DebugRenderOptions::Baseline) {
  116. mesh.draw_filled_box(
  117. &Rectangle::new(glyph_run.offset(), glyph_run.baseline(), glyph_run.advance(), 1.),
  118. [0., 0., 1., 0.7],
  119. );
  120. }
  121. mesh.alloc(render_api).draw_with_texture(atlas.texture)
  122. }