old_atlas.rs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. use miniquad::TextureId;
  2. use crate::{
  3. error::Result,
  4. gfx::{Rectangle, RenderApi},
  5. util::ansi_texture,
  6. };
  7. use super::{Glyph, Sprite};
  8. pub struct RenderedAtlas {
  9. pub uv_rects: Vec<Rectangle>,
  10. pub texture_id: TextureId,
  11. }
  12. const ATLAS_GAP: usize = 2;
  13. pub async fn make_texture_atlas(
  14. render_api: &RenderApi,
  15. font_size: f32,
  16. glyphs: &Vec<Glyph>,
  17. ) -> Result<RenderedAtlas> {
  18. // First compute total size of the atlas
  19. let mut total_width = ATLAS_GAP;
  20. let mut total_height = ATLAS_GAP;
  21. // Glyph IDs already rendered so we don't do it twice
  22. let mut rendered = vec![];
  23. for (idx, glyph) in glyphs.iter().enumerate() {
  24. let sprite = &glyph.sprite;
  25. assert_eq!(sprite.bmp.len(), 4 * sprite.bmp_width * sprite.bmp_height);
  26. // Already done this one so skip
  27. if rendered.contains(&glyph.glyph_id) {
  28. continue
  29. }
  30. rendered.push(glyph.glyph_id);
  31. total_width += sprite.bmp_width + ATLAS_GAP;
  32. total_height = std::cmp::max(total_height, sprite.bmp_height);
  33. }
  34. total_width += ATLAS_GAP;
  35. total_height += 2 * ATLAS_GAP;
  36. // Allocate the big texture now
  37. let mut atlas_bmp = vec![0; 4 * total_width * total_height];
  38. // For debug lines we want a single white pixel.
  39. atlas_bmp[0] = 255;
  40. atlas_bmp[1] = 255;
  41. atlas_bmp[2] = 255;
  42. atlas_bmp[3] = 255;
  43. // Calculate dimensions of final product first
  44. let mut current_x = ATLAS_GAP;
  45. let mut rendered_glyphs: Vec<u32> = vec![];
  46. let mut uv_rects: Vec<Rectangle> = vec![];
  47. for (idx, glyph) in glyphs.iter().enumerate() {
  48. let sprite = &glyph.sprite;
  49. // Did we already rendered this glyph?
  50. // If so just copy the UV rect from before.
  51. let mut uv_rect = None;
  52. for (rendered_glyph_id, rendered_uv_rect) in rendered_glyphs.iter().zip(uv_rects.iter()) {
  53. if *rendered_glyph_id == glyph.glyph_id {
  54. uv_rect = Some(rendered_uv_rect.clone());
  55. }
  56. }
  57. let uv_rect = match uv_rect {
  58. Some(uv_rect) => uv_rect,
  59. // Allocating a new glyph sprite in the atlas
  60. None => {
  61. copy_image(sprite, &mut atlas_bmp, total_width, current_x);
  62. // Compute UV coords
  63. let uv_rect = Rectangle {
  64. x: (ATLAS_GAP + current_x) as f32 / total_width as f32,
  65. y: ATLAS_GAP as f32 / total_height as f32,
  66. w: sprite.bmp_width as f32 / total_width as f32,
  67. h: sprite.bmp_height as f32 / total_height as f32,
  68. };
  69. current_x += sprite.bmp_width + ATLAS_GAP;
  70. uv_rect
  71. }
  72. };
  73. rendered_glyphs.push(glyph.glyph_id);
  74. uv_rects.push(uv_rect);
  75. }
  76. // Finally allocate the texture
  77. let texture_id =
  78. render_api.new_texture(total_width as u16, total_height as u16, atlas_bmp).await?;
  79. Ok(RenderedAtlas { uv_rects, texture_id })
  80. }
  81. fn copy_image(sprite: &Sprite, atlas_bmp: &mut Vec<u8>, total_width: usize, current_x: usize) {
  82. for i in 0..sprite.bmp_height {
  83. for j in 0..sprite.bmp_width {
  84. let off_dest = 4 * ((i + ATLAS_GAP) * total_width + j + current_x + ATLAS_GAP);
  85. let off_src = 4 * (i * sprite.bmp_width + j);
  86. atlas_bmp[off_dest] = sprite.bmp[off_src];
  87. atlas_bmp[off_dest + 1] = sprite.bmp[off_src + 1];
  88. atlas_bmp[off_dest + 2] = sprite.bmp[off_src + 2];
  89. atlas_bmp[off_dest + 3] = sprite.bmp[off_src + 3];
  90. }
  91. }
  92. }