text.rs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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 rand::{rngs::OsRng, Rng};
  19. use std::sync::{Arc, Mutex as SyncMutex, Weak};
  20. use crate::{
  21. gfx::{
  22. GfxDrawCall, GfxDrawInstruction, GfxDrawMesh, GfxTextureId, Rectangle, RenderApi,
  23. RenderApiPtr,
  24. },
  25. mesh::{Color, MeshBuilder, MeshInfo, COLOR_BLUE, COLOR_WHITE},
  26. prop::{
  27. PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr, PropertyUint32,
  28. Role,
  29. },
  30. scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
  31. text::{self, GlyphPositionIter, TextShaper, TextShaperPtr},
  32. ExecutorPtr,
  33. };
  34. use super::{eval_rect, get_parent_rect, read_rect, DrawUpdate, OnModify, Stoppable};
  35. pub type TextPtr = Arc<Text>;
  36. #[derive(Clone)]
  37. struct TextRenderInfo {
  38. mesh: MeshInfo,
  39. texture_id: GfxTextureId,
  40. }
  41. pub struct Text {
  42. sg: SceneGraphPtr2,
  43. render_api: RenderApiPtr,
  44. text_shaper: TextShaperPtr,
  45. _tasks: Vec<smol::Task<()>>,
  46. render_info: SyncMutex<TextRenderInfo>,
  47. dc_key: u64,
  48. node_id: SceneNodeId,
  49. rect: PropertyPtr,
  50. z_index: PropertyUint32,
  51. text: PropertyStr,
  52. font_size: PropertyFloat32,
  53. text_color: PropertyColor,
  54. baseline: PropertyFloat32,
  55. debug: PropertyBool,
  56. }
  57. impl Text {
  58. pub async fn new(
  59. ex: ExecutorPtr,
  60. sg: SceneGraphPtr2,
  61. node_id: SceneNodeId,
  62. render_api: RenderApiPtr,
  63. text_shaper: TextShaperPtr,
  64. ) -> Pimpl {
  65. let scene_graph = sg.lock().await;
  66. let node = scene_graph.get_node(node_id).unwrap();
  67. let node_name = node.name.clone();
  68. let rect = node.get_property("rect").expect("Text::rect");
  69. let z_index = PropertyUint32::wrap(node, Role::Internal, "z_index", 0).unwrap();
  70. let text = PropertyStr::wrap(node, Role::Internal, "text", 0).unwrap();
  71. let font_size = PropertyFloat32::wrap(node, Role::Internal, "font_size", 0).unwrap();
  72. let text_color = PropertyColor::wrap(node, Role::Internal, "text_color").unwrap();
  73. let baseline = PropertyFloat32::wrap(node, Role::Internal, "baseline", 0).unwrap();
  74. let debug = PropertyBool::wrap(node, Role::Internal, "debug", 0).unwrap();
  75. drop(scene_graph);
  76. let render_info = Self::regen_mesh(
  77. &render_api,
  78. &text_shaper,
  79. text.get(),
  80. font_size.get(),
  81. text_color.get(),
  82. baseline.get(),
  83. debug.get(),
  84. )
  85. .await;
  86. let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
  87. let mut on_modify = OnModify::new(ex, node_name, node_id, me.clone());
  88. on_modify.when_change(rect.clone(), Self::redraw);
  89. on_modify.when_change(z_index.prop(), Self::redraw);
  90. on_modify.when_change(text.prop(), Self::redraw);
  91. on_modify.when_change(font_size.prop(), Self::redraw);
  92. on_modify.when_change(text_color.prop(), Self::redraw);
  93. on_modify.when_change(debug.prop(), Self::redraw);
  94. on_modify.when_change(baseline.prop(), Self::redraw);
  95. Self {
  96. sg,
  97. render_api,
  98. text_shaper,
  99. _tasks: on_modify.tasks,
  100. render_info: SyncMutex::new(render_info),
  101. dc_key: OsRng.gen(),
  102. node_id,
  103. rect,
  104. z_index,
  105. text,
  106. font_size,
  107. text_color,
  108. baseline,
  109. debug,
  110. }
  111. });
  112. Pimpl::Text(self_)
  113. }
  114. async fn regen_mesh(
  115. render_api: &RenderApi,
  116. text_shaper: &TextShaper,
  117. text: String,
  118. font_size: f32,
  119. text_color: Color,
  120. baseline: f32,
  121. debug: bool,
  122. ) -> TextRenderInfo {
  123. debug!(target: "ui::text", "Rendering label '{}'", text);
  124. let glyphs = text_shaper.shape(text, font_size).await;
  125. let atlas = text::make_texture_atlas(render_api, &glyphs);
  126. let mut mesh = MeshBuilder::new();
  127. let glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
  128. for (glyph_rect, glyph) in glyph_pos_iter.zip(glyphs.iter()) {
  129. let uv_rect = atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
  130. if debug {
  131. mesh.draw_outline(&glyph_rect, COLOR_BLUE, 2.);
  132. }
  133. let mut color = text_color.clone();
  134. if glyph.sprite.has_color {
  135. color = COLOR_WHITE;
  136. }
  137. mesh.draw_box(&glyph_rect, color, uv_rect);
  138. }
  139. let mesh = mesh.alloc(&render_api);
  140. TextRenderInfo { mesh, texture_id: atlas.texture_id }
  141. }
  142. async fn redraw(self: Arc<Self>) {
  143. let old = self.render_info.lock().unwrap().clone();
  144. // TODO move this to draw
  145. let render_info = Self::regen_mesh(
  146. &self.render_api,
  147. &self.text_shaper,
  148. self.text.get(),
  149. self.font_size.get(),
  150. self.text_color.get(),
  151. self.baseline.get(),
  152. self.debug.get(),
  153. )
  154. .await;
  155. *self.render_info.lock().unwrap() = render_info;
  156. let sg = self.sg.lock().await;
  157. let node = sg.get_node(self.node_id).unwrap();
  158. let Some(parent_rect) = get_parent_rect(&sg, node) else {
  159. return;
  160. };
  161. let Some(draw_update) = self.draw(&sg, &parent_rect) else {
  162. error!(target: "ui::text", "Text {:?} failed to draw", node);
  163. return;
  164. };
  165. self.render_api.replace_draw_calls(draw_update.draw_calls);
  166. debug!(target: "ui::text", "replace draw calls done");
  167. // We're finished with these so clean up.
  168. self.render_api.delete_buffer(old.mesh.vertex_buffer);
  169. self.render_api.delete_buffer(old.mesh.index_buffer);
  170. self.render_api.delete_texture(old.texture_id);
  171. }
  172. pub fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle) -> Option<DrawUpdate> {
  173. debug!(target: "ui::text", "Text::draw()");
  174. // Only used for debug messages
  175. let node = sg.get_node(self.node_id).unwrap();
  176. let render_info = self.render_info.lock().unwrap().clone();
  177. let mesh = GfxDrawMesh {
  178. vertex_buffer: render_info.mesh.vertex_buffer,
  179. index_buffer: render_info.mesh.index_buffer,
  180. texture: Some(render_info.texture_id),
  181. num_elements: render_info.mesh.num_elements,
  182. };
  183. if let Err(err) = eval_rect(self.rect.clone(), parent_rect) {
  184. panic!("Node {:?} bad rect property: {}", node, err);
  185. }
  186. let Ok(rect) = read_rect(self.rect.clone()) else {
  187. panic!("Node {:?} bad rect property", node);
  188. };
  189. let off_x = rect.x / parent_rect.w;
  190. let off_y = rect.y / parent_rect.h;
  191. let scale_x = 1. / parent_rect.w;
  192. let scale_y = 1. / parent_rect.h;
  193. let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
  194. glam::Mat4::from_scale(glam::Vec3::new(scale_x, scale_y, 1.));
  195. Some(DrawUpdate {
  196. key: self.dc_key,
  197. draw_calls: vec![(
  198. self.dc_key,
  199. GfxDrawCall {
  200. instrs: vec![
  201. GfxDrawInstruction::ApplyMatrix(model),
  202. GfxDrawInstruction::Draw(mesh),
  203. ],
  204. dcs: vec![],
  205. z_index: self.z_index.get(),
  206. },
  207. )],
  208. freed_textures: vec![],
  209. freed_buffers: vec![],
  210. })
  211. }
  212. }
  213. impl Stoppable for Text {
  214. async fn stop(&self) {
  215. // TODO: Delete own draw call
  216. // Free buffers
  217. // Should this be in drop?
  218. let render_info = self.render_info.lock().unwrap().clone();
  219. let vertex_buffer = render_info.mesh.vertex_buffer;
  220. let index_buffer = render_info.mesh.index_buffer;
  221. let texture_id = render_info.texture_id;
  222. self.render_api.delete_buffer(vertex_buffer);
  223. self.render_api.delete_buffer(index_buffer);
  224. self.render_api.delete_texture(texture_id);
  225. }
  226. }