nuklear_backend_glium/
lib.rs

1#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))] // for clarity
2
3#[macro_use]
4pub extern crate glium;
5
6use nuklear::{Buffer, Context, ConvertConfig, DrawVertexLayoutAttribute, DrawVertexLayoutElements, DrawVertexLayoutFormat, Handle, Vec2};
7
8#[derive(Debug, Copy, Clone)]
9struct Vertex {
10    pos: Vec2,
11    tex: Vec2,
12    col: [u8; 4],
13}
14
15impl glium::vertex::Vertex for Vertex {
16    fn build_bindings() -> glium::vertex::VertexFormat {
17        use std::mem::transmute;
18
19        #[allow(invalid_value)]
20        unsafe {
21            let dummy: &Vertex = ::std::mem::transmute(0usize);
22            ::std::borrow::Cow::Owned(vec![
23                ("Position".into(), transmute(&dummy.pos), <(f32, f32) as glium::vertex::Attribute>::get_type(), false),
24                ("TexCoord".into(), transmute(&dummy.tex), <(f32, f32) as glium::vertex::Attribute>::get_type(), false),
25                ("Color".into(), transmute(&dummy.col), glium::vertex::AttributeType::U8U8U8U8, false),
26            ])
27        }
28    }
29}
30
31impl Default for Vertex {
32    fn default() -> Self {
33        unsafe { ::std::mem::zeroed() }
34    }
35}
36
37const VS: &str = "#version 150
38        uniform mat4 ProjMtx;
39        in vec2 Position;
40        in vec2 TexCoord;
41        in vec4 Color;
42        out vec2 Frag_UV;
43        out vec4 Frag_Color;
44        void main() {
45           Frag_UV = \
46                          TexCoord;
47           Frag_Color = Color / 255.0;
48           gl_Position = ProjMtx * vec4(Position.xy, 0, 1);
49        }";
50const FS: &str = "#version 150
51        precision mediump float;
52	    uniform sampler2D Texture;
53        in vec2 Frag_UV;
54        in vec4 Frag_Color;
55        out vec4 Out_Color;
56        void main(){
57           Out_Color = Frag_Color * \
58                          texture(Texture, Frag_UV.st);
59		}";
60
61pub struct Drawer {
62    cmd: Buffer,
63    prg: glium::Program,
64    tex: Vec<glium::Texture2d>,
65    vbf: Vec<Vertex>,
66    ebf: Vec<u16>,
67    vbo: glium::VertexBuffer<Vertex>,
68    ebo: glium::IndexBuffer<u16>,
69    vle: DrawVertexLayoutElements,
70}
71
72impl Drawer {
73    pub fn new(display: &mut glium::Display, texture_count: usize, vbo_size: usize, ebo_size: usize, command_buffer: Buffer) -> Drawer {
74        Drawer {
75            cmd: command_buffer,
76            prg: glium::Program::from_source(display, VS, FS, None).unwrap(),
77            tex: Vec::with_capacity(texture_count + 1),
78            vbf: vec![Vertex::default(); vbo_size * ::std::mem::size_of::<Vertex>()],
79            ebf: vec![0u16; ebo_size * ::std::mem::size_of::<u16>()],
80            vbo: glium::VertexBuffer::empty_dynamic(display, vbo_size * ::std::mem::size_of::<Vertex>()).unwrap(),
81            ebo: glium::IndexBuffer::empty_dynamic(display, glium::index::PrimitiveType::TrianglesList, ebo_size * ::std::mem::size_of::<u16>()).unwrap(),
82            vle: DrawVertexLayoutElements::new(&[
83                (DrawVertexLayoutAttribute::Position, DrawVertexLayoutFormat::Float, 0),
84                (DrawVertexLayoutAttribute::TexCoord, DrawVertexLayoutFormat::Float, 8),
85                (DrawVertexLayoutAttribute::Color, DrawVertexLayoutFormat::R8G8B8A8, 16),
86                (DrawVertexLayoutAttribute::AttributeCount, DrawVertexLayoutFormat::Count, 32),
87            ]),
88        }
89    }
90
91    pub fn add_texture(&mut self, display: &mut glium::Display, image: &[u8], width: u32, height: u32) -> Handle {
92        let image = glium::texture::RawImage2d {
93            data: std::borrow::Cow::Borrowed(image),
94            width: width,
95            height: height,
96            format: glium::texture::ClientFormat::U8U8U8U8,
97        };
98        let tex = glium::Texture2d::new(display, image).unwrap();
99        let hnd = Handle::from_id(self.tex.len() as i32 + 1);
100        self.tex.push(tex);
101        hnd
102    }
103
104    pub fn draw(&mut self, ctx: &mut Context, cfg: &mut ConvertConfig, frame: &mut glium::Frame, _scale: Vec2) {
105        use glium::uniforms::MagnifySamplerFilter;
106        use glium::Surface;
107        use glium::{Blend, DrawParameters, Rect};
108
109        let (ww, hh) = frame.get_dimensions();
110
111        let ortho = [
112            [2.0f32 / ww as f32, 0.0f32, 0.0f32, 0.0f32],
113            [0.0f32, -2.0f32 / hh as f32, 0.0f32, 0.0f32],
114            [0.0f32, 0.0f32, -1.0f32, 0.0f32],
115            [-1.0f32, 1.0f32, 0.0f32, 1.0f32],
116        ];
117
118        cfg.set_vertex_layout(&self.vle);
119        cfg.set_vertex_size(::std::mem::size_of::<Vertex>());
120
121        {
122            self.vbo.invalidate();
123            self.ebo.invalidate();
124
125            let mut rvbuf = unsafe { ::std::slice::from_raw_parts_mut(self.vbf.as_mut() as *mut [Vertex] as *mut u8, self.vbf.capacity()) };
126            let mut rebuf = unsafe { ::std::slice::from_raw_parts_mut(self.ebf.as_mut() as *mut [u16] as *mut u8, self.ebf.capacity()) };
127            let mut vbuf = Buffer::with_fixed(&mut rvbuf);
128            let mut ebuf = Buffer::with_fixed(&mut rebuf);
129
130            ctx.convert(&mut self.cmd, &mut vbuf, &mut ebuf, &cfg);
131
132            self.vbo.slice_mut(0..self.vbf.capacity()).unwrap().write(&self.vbf);
133            self.ebo.slice_mut(0..self.ebf.capacity()).unwrap().write(&self.ebf);
134        }
135
136        let mut idx_start = 0;
137        let mut idx_end;
138
139        for cmd in ctx.draw_command_iterator(&self.cmd) {
140            if cmd.elem_count() < 1 {
141                continue;
142            }
143
144            let id = cmd.texture().id().unwrap();
145            let ptr = self.find_res(id).unwrap();
146
147            idx_end = idx_start + cmd.elem_count() as usize;
148
149            let x = cmd.clip_rect().x;
150            let y = cmd.clip_rect().y;
151            let w = cmd.clip_rect().w;
152            let h = cmd.clip_rect().h;
153
154            frame
155                .draw(
156                    &self.vbo,
157                    &self.ebo.slice(idx_start..idx_end).unwrap(),
158                    &self.prg,
159                    &uniform! {
160                        ProjMtx: ortho,
161                        Texture: ptr.sampled().magnify_filter(MagnifySamplerFilter::Linear),
162                    },
163                    &DrawParameters {
164                        blend: Blend::alpha_blending(),
165                        scissor: Some(Rect {
166                            left: (if x < 0f32 { 0f32 } else { x }) as u32,
167                            bottom: (if y < 0f32 { 0f32 } else { hh as f32 - y - h }) as u32,
168                            width: (if x < 0f32 { w + x } else { w }) as u32,
169                            height: (if y < 0f32 { h + y } else { h }) as u32,
170                        }),
171                        backface_culling: glium::draw_parameters::BackfaceCullingMode::CullingDisabled,
172
173                        ..DrawParameters::default()
174                    },
175                )
176                .unwrap();
177            idx_start = idx_end;
178        }
179    }
180
181    fn find_res(&self, id: i32) -> Option<&glium::Texture2d> {
182        if id > 0 && id as usize <= self.tex.len() {
183            Some(&self.tex[(id - 1) as usize])
184        } else {
185            None
186        }
187    }
188}