1#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))] #[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}