Advertisement
Skytrias

luminance text example rubbish

Oct 3rd, 2019
343
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 13.21 KB | None | 0 0
  1. use luminance::context::GraphicsContext;
  2. use luminance::pixel::NormR8UI;
  3. use luminance::shader::program::Program;
  4. use luminance::tess::{Mode, TessBuilder};
  5. use luminance::texture::{Dim2, Flat, Texture};
  6. use luminance_glfw::{
  7.     Action, GlfwSurface, Key, MouseButton, Surface as _, WindowDim, WindowEvent, WindowOpt,
  8. };
  9.  
  10. fn main() {
  11.     // Window
  12.     let mut surface = GlfwSurface::new(
  13.         WindowDim::Windowed(500, 500),
  14.         "KleiPlane Luminance",
  15.         WindowOpt::default(),
  16.     )
  17.     .expect("GLFW: Surface creation");
  18.  
  19.     let mut render_set = RenderSet::new(&mut surface);
  20.  
  21.     let pre_text = include_str!("../text_example.txt").into();
  22.  
  23.     let (text_program, _): (Program<TextVertexSemantics, (), TextShaderInterface>, _) =
  24.         Program::from_strings(None, TEXT_VS_STR, None, TEXT_FS_STR).unwrap();
  25.  
  26.     use glyph_brush::{BrushAction, BrushError, GlyphBrushBuilder, Section};
  27.  
  28.     let inconsolata: &[u8] = include_bytes!("../inconsolata.ttf");
  29.     let mut glyph_brush = GlyphBrushBuilder::using_font_bytes(inconsolata).build();
  30.  
  31.     let mut loop_helper = spin_sleep::LoopHelper::builder()
  32.         .report_interval_s(1.)
  33.         .build_with_target_rate(60.);
  34.  
  35.     let mut text_tess = TessBuilder::new(&mut surface).set_vertex_nb(1).build().unwrap();
  36.  
  37.     let mut back_buffer = surface.back_buffer().unwrap();
  38.     let mut resized = false;
  39.     let (_width, _height) = glyph_brush.texture_dimensions();
  40.     let mut text_texture: Texture<Flat, Dim2, NormR8UI> = get_empty_texture(_width, _height, &mut surface);
  41.     let mut keep_vertices = Vec::new();
  42.  
  43.     'app: loop {
  44.        // achieve 60 fps
  45.        let _delta = loop_helper.loop_start();
  46.  
  47.        // handle events
  48.        for event in surface.poll_events() {
  49.            match event {
  50.                WindowEvent::Close | WindowEvent::Key(Key::Escape, _, Action::Release, _) => {
  51.                    break 'app;
  52.                 }
  53.  
  54.                 WindowEvent::FramebufferSize(_width, _height) => {
  55.                     render_set.projection = Transform3D::<f32, f32, f32>::ortho(
  56.                         0.,
  57.                         _width as f32,
  58.                         _height as f32,
  59.                         0.,
  60.                         -1.,
  61.                         1.,
  62.                     )
  63.                     .to_row_arrays();
  64.                     resized = true;
  65.                 }
  66.                 _ => (),
  67.             };
  68.         }
  69.  
  70.         // when resized, reset backbuffer to new size
  71.         if resized {
  72.             back_buffer = surface.back_buffer().unwrap();
  73.             resized = false;
  74.         };
  75.  
  76.         //
  77.         glyph_brush.queue(Section {
  78.             text: pre_text,
  79.             scale: glyph_brush::rusttype::Scale::uniform(18.),
  80.             screen_position: (100.0, 100.0),
  81.             bounds: (1000., 1000.),
  82.             ..Section::default()
  83.         });
  84.  
  85.         // create texture & verticess for text drawing
  86.         let mut brush_action;
  87.         loop {
  88.             brush_action = glyph_brush.process_queued(
  89.                 |rect, tex_data| {
  90.                     upload_texture_bytes(
  91.                         &mut text_texture,
  92.                         rect.min.x as u32,
  93.                         rect.min.y as u32,
  94.                         rect.width() as u32,
  95.                         rect.height() as u32,
  96.                         tex_data,
  97.                     );
  98.                 },
  99.                 to_vertex,
  100.             );
  101.  
  102.             match brush_action {
  103.                 Ok(_) => break,
  104.                 Err(BrushError::TextureTooSmall { suggested, .. }) => {
  105.                     eprint!("\r                            \r");
  106.                     eprintln!("Resizing glyph texture");
  107.                 },
  108.             }
  109.         }
  110.  
  111.         // create vertices
  112.         match brush_action {
  113.             Ok(BrushAction::Draw(vertices)) => {
  114.                 println!("generated, {}", vertices.len());
  115.  
  116.                 if !vertices.is_empty() {
  117.                     keep_vertices = vertices;
  118.                 }
  119.             },
  120.             _ => (),
  121.         }
  122.  
  123.         if !keep_vertices.is_empty() {
  124.              text_tess = TessBuilder::new(&mut surface)
  125.                 .set_mode(Mode::TriangleStrip)
  126.                 .set_vertex_nb(4)
  127.                 .add_instances(&keep_vertices)
  128.                 .build()
  129.                 .unwrap();
  130.         }
  131.  
  132.         // rendering code goes here
  133.         surface.pipeline_builder().pipeline(
  134.             &back_buffer,
  135.             [1.0, 1.0, 1.0, 1.0],
  136.             |pipeline, mut shd_gate| {
  137.                 if !keep_vertices.is_empty() {
  138.                     let text_bound_texture = pipeline.bind_texture(&text_texture);
  139.  
  140.                     shd_gate.shade(&text_program, |shader, mut render_gate| {
  141.                         shader.transform.update(render_set.projection);
  142.                         shader.font_tex.update(&text_bound_texture);
  143.  
  144.                         render_gate.render(render_set.render_state, |mut tess_gate| {
  145.                             tess_gate.render(&text_tess);
  146.                         });
  147.                     });
  148.                 }
  149.             },
  150.         );
  151.  
  152.         surface.swap_buffers();
  153.  
  154.         if let Some(rate) = loop_helper.report_rate() {
  155.             println!("{:.0} FPS", rate);
  156.         }
  157.  
  158.         loop_helper.loop_sleep();
  159.     }
  160. }
  161.  
  162. use crate::engine::V2;
  163.  
  164. struct Rect {
  165.     pub min: V2,
  166.     pub max: V2,
  167. }
  168.  
  169. impl Rect {
  170.     pub fn width(&self) -> f32 {
  171.         self.max.x - self.min.x
  172.     }
  173.  
  174.     pub fn height(&self) -> f32 {
  175.         self.max.y - self.min.y
  176.     }
  177. }
  178.  
  179. use crate::engine::common::*;
  180. use euclid::Transform3D;
  181.  
  182. #[inline]
  183. fn to_vertex(
  184.     glyph_brush::GlyphVertex {
  185.         mut tex_coords,
  186.         pixel_coords,
  187.         bounds,
  188.         color,
  189.         z,
  190.     }: glyph_brush::GlyphVertex,
  191. ) -> TextVertex {
  192.     let gl_bounds = bounds;
  193.  
  194.     let mut gl_rect = Rect {
  195.         min: V2::new(pixel_coords.min.x as f32, pixel_coords.min.y as f32),
  196.         max: V2::new(pixel_coords.max.x as f32, pixel_coords.max.y as f32),
  197.     };
  198.  
  199.     // handle overlapping bounds, modify uv_rect to preserve texture aspect
  200.     if gl_rect.max.x > gl_bounds.max.x {
  201.         let old_width = gl_rect.width();
  202.         gl_rect.max.x = gl_bounds.max.x;
  203.         tex_coords.max.x = tex_coords.min.x + tex_coords.width() * gl_rect.width() / old_width;
  204.     }
  205.     if gl_rect.min.x < gl_bounds.min.x {
  206.         let old_width = gl_rect.width();
  207.         gl_rect.min.x = gl_bounds.min.x;
  208.         tex_coords.min.x = tex_coords.max.x - tex_coords.width() * gl_rect.width() / old_width;
  209.     }
  210.     if gl_rect.max.y > gl_bounds.max.y {
  211.         let old_height = gl_rect.height();
  212.         gl_rect.max.y = gl_bounds.max.y;
  213.         tex_coords.max.y = tex_coords.min.y + tex_coords.height() * gl_rect.height() / old_height;
  214.     }
  215.     if gl_rect.min.y < gl_bounds.min.y {
  216.         let old_height = gl_rect.height();
  217.         gl_rect.min.y = gl_bounds.min.y;
  218.         tex_coords.min.y = tex_coords.max.y - tex_coords.height() * gl_rect.height() / old_height;
  219.     }
  220.  
  221.     TextVertex {
  222.         left_top: VertexLeftTop::new([gl_rect.min.x, gl_rect.max.y, z]),
  223.         right_bottom: VertexRightBottom::new([gl_rect.max.x, gl_rect.min.y]),
  224.         tex_left_top: VertexTexLeftTop::new([tex_coords.min.x, tex_coords.max.y]),
  225.         tex_right_bottom: VertexTexRightBottom::new([tex_coords.max.x, tex_coords.min.y]),
  226.         color: VertexColor::new(color),
  227.     }
  228. }
  229.  
  230. /* common.rs */
  231.  
  232. use luminance::{
  233.     linear::M44,
  234.     pipeline::BoundTexture,
  235.     pixel::{NormRGBA8UI, NormUnsigned},
  236.     shader::program::Uniform,
  237.     texture::{Dim2, Flat, GenMipmaps, Sampler, Texture},
  238. };
  239. use luminance_derive::{Semantics, UniformInterface, Vertex};
  240. use luminance_glfw::GlfwSurface;
  241. use rgb::*;
  242.  
  243. use euclid::Vector2D;
  244. use luminance::pixel::NormR8UI;
  245.  
  246. // love this
  247. pub type V2 = Vector2D<f32, f32>;
  248.  
  249. // standard shaders
  250. pub const TEXTURE_VS_STR: &str = include_str!("../../shaders/texture.vert");
  251. pub const TEXTURE_FS_STR: &str = include_str!("../../shaders/texture.frag");
  252. pub const SPRITESHEET_VS_STR: &str = include_str!("../../shaders/spritesheet.vert");
  253. pub const SPRITESHEET_FS_STR: &str = include_str!("../../shaders/spritesheet.frag");
  254. pub const TEXT_VS_STR: &str = include_str!("../../shaders/text.vert");
  255. pub const TEXT_FS_STR: &str = include_str!("../../shaders/text.frag");
  256.  
  257. #[derive(Copy, Clone, Debug, Semantics)]
  258. pub enum VertexSemantics {
  259.     #[sem(name = "position", repr = "[f32; 2]", wrapper = "VertexPosition")]
  260.     Position,
  261.     #[sem(
  262.         name = "tex_coords",
  263.         repr = "[f32; 2]",
  264.         wrapper = "VertexTexCoordinates"
  265.     )]
  266.     TexCoordinates,
  267. }
  268.  
  269. #[derive(Vertex)]
  270. #[vertex(sem = "VertexSemantics")]
  271. pub struct Vertex {
  272.     position: VertexPosition,
  273.     tex_coords: VertexTexCoordinates,
  274. }
  275.  
  276. #[derive(Copy, Clone, Debug, Semantics)]
  277. pub enum TextVertexSemantics {
  278.     #[sem(name = "left_top", repr = "[f32; 3]", wrapper = "VertexLeftTop")]
  279.     LeftTop,
  280.     #[sem(
  281.         name = "right_bottom",
  282.         repr = "[f32; 2]",
  283.         wrapper = "VertexRightBottom"
  284.     )]
  285.     RightBottom,
  286.     #[sem(name = "tex_left_top", repr = "[f32; 2]", wrapper = "VertexTexLeftTop")]
  287.     TexLeftBottom,
  288.     #[sem(
  289.         name = "tex_right_bottom",
  290.         repr = "[f32; 2]",
  291.         wrapper = "VertexTexRightBottom"
  292.     )]
  293.     TexRightBottom,
  294.     #[sem(name = "color", repr = "[f32; 4]", wrapper = "VertexColor")]
  295.     Color,
  296. }
  297.  
  298. #[derive(Clone, Debug, Vertex)]
  299. #[vertex(sem = "TextVertexSemantics", instanced = "true")]
  300. pub struct TextVertex {
  301.     pub left_top: VertexLeftTop,
  302.     pub right_bottom: VertexRightBottom,
  303.     pub tex_left_top: VertexTexLeftTop,
  304.     pub tex_right_bottom: VertexTexRightBottom,
  305.     pub color: VertexColor,
  306. }
  307.  
  308. pub const QUAD_VERTICES: [Vertex; 4] = [
  309.     Vertex {
  310.         position: VertexPosition::new([-0.5, -0.5]),
  311.         tex_coords: VertexTexCoordinates::new([0., 0.]),
  312.     },
  313.     Vertex {
  314.         position: VertexPosition::new([-0.5, 0.5]),
  315.         tex_coords: VertexTexCoordinates::new([0., 1.]),
  316.     },
  317.     Vertex {
  318.         position: VertexPosition::new([0.5, 0.5]),
  319.         tex_coords: VertexTexCoordinates::new([1., 1.]),
  320.     },
  321.     Vertex {
  322.         position: VertexPosition::new([0.5, -0.5]),
  323.         tex_coords: VertexTexCoordinates::new([1., 0.]),
  324.     },
  325. ];
  326.  
  327. #[derive(UniformInterface)]
  328. pub struct ShaderInterface {
  329.     #[uniform(name = "projection")]
  330.     pub projection: Uniform<M44>,
  331.     #[uniform(name = "model")]
  332.     pub model: Uniform<M44>,
  333.     #[uniform(name = "image")]
  334.     pub image: Uniform<&'static BoundTexture<'static, Flat, Dim2, NormUnsigned>>,
  335.     #[uniform(name = "color")]
  336.     pub color: Uniform<[f32; 4]>,
  337. }
  338.  
  339. #[derive(UniformInterface)]
  340. pub struct SpritesheetShaderInterface {
  341.     #[uniform(name = "projection")]
  342.     pub projection: Uniform<M44>,
  343.     #[uniform(name = "model")]
  344.     pub model: Uniform<M44>,
  345.     #[uniform(name = "image")]
  346.     pub image: Uniform<&'static BoundTexture<'static, Flat, Dim2, NormUnsigned>>,
  347.     #[uniform(name = "frame")]
  348.     pub frame: Uniform<f32>,
  349.     #[uniform(name = "frame_amount")]
  350.     pub frame_amount: Uniform<f32>,
  351. }
  352.  
  353. #[derive(UniformInterface)]
  354. pub struct TextShaderInterface {
  355.     #[uniform(name = "transform")]
  356.     pub transform: Uniform<M44>,
  357.     #[uniform(name = "font_tex")]
  358.     pub font_tex: Uniform<&'static BoundTexture<'static, Flat, Dim2, NormUnsigned>>,
  359. }
  360.  
  361. // specific sampler for pixel art defined
  362. pub const TEXTURE_SAMPLER: Sampler = Sampler {
  363.     wrap_r: luminance::texture::Wrap::ClampToEdge,
  364.     wrap_s: luminance::texture::Wrap::ClampToEdge,
  365.     wrap_t: luminance::texture::Wrap::ClampToEdge,
  366.     min_filter: luminance::texture::MinFilter::Nearest,
  367.     mag_filter: luminance::texture::MagFilter::Nearest,
  368.     depth_comparison: None,
  369. };
  370.  
  371. // loads a luminance texture from a png file
  372. pub fn load_texture(
  373.     surface: &mut GlfwSurface,
  374.     path: &'static str,
  375. ) -> Texture<Flat, Dim2, NormRGBA8UI> {
  376.    let img = lodepng::decode32_file(path).unwrap();
  377.    let bytes: &[u8] = img.buffer.as_bytes();
  378.  
  379.    let texture = Texture::new(
  380.        surface,
  381.        [img.width as u32, img.height as u32],
  382.        0,
  383.        &TEXTURE_SAMPLER,
  384.    )
  385.    .expect("luminance texture creation");
  386.  
  387.    // no mipmaps
  388.    texture.upload_raw(GenMipmaps::No, &bytes).unwrap();
  389.  
  390.    texture
  391. }
  392.  
  393. pub const TEXT_SAMPLER: Sampler = Sampler {
  394.    wrap_r: luminance::texture::Wrap::ClampToEdge,
  395.    wrap_s: luminance::texture::Wrap::ClampToEdge,
  396.    wrap_t: luminance::texture::Wrap::ClampToEdge,
  397.    min_filter: luminance::texture::MinFilter::Linear,
  398.    mag_filter: luminance::texture::MagFilter::Linear,
  399.    depth_comparison: None,
  400. };
  401.  
  402. pub fn get_empty_texture(
  403.    width: u32,
  404.    height: u32,
  405.    surface: &mut GlfwSurface,
  406. ) -> Texture<Flat, Dim2, NormR8UI> {
  407.    let texture = Texture::new(surface, [width, height], 0, &TEXT_SAMPLER)
  408.        .expect("luminance texture creation");
  409.  
  410.    texture
  411. }
  412.  
  413. pub fn upload_texture_bytes(
  414.    texture: &mut Texture<Flat, Dim2, NormR8UI>,
  415.    x_offset: u32,
  416.    y_offset: u32,
  417.    width: u32,
  418.    height: u32,
  419.    bytes: &[u8],
  420. ) {
  421.    texture.upload_part_raw(
  422.        GenMipmaps::No,
  423.        [x_offset, y_offset],
  424.        [width, height],
  425.        &bytes
  426.    ).unwrap();
  427. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement