1#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] use nuklear::{Buffer as NkBuffer, Context, ConvertConfig, DrawVertexLayoutAttribute, DrawVertexLayoutElements, DrawVertexLayoutFormat, Handle, Size, Vec2};
4use std::{
5 mem::{size_of, size_of_val, forget},
6 slice::from_raw_parts,
7 str::from_utf8,
8};
9use wgpu::*;
10
11pub const TEXTURE_FORMAT: TextureFormat = TextureFormat::Bgra8Unorm;
12
13#[allow(dead_code)]
14struct Vertex {
15 pos: [f32; 2], tex: [f32; 2], col: [u8; 4], }
19#[allow(dead_code)]
20struct WgpuTexture {
21 texture: Texture,
22 sampler: Sampler,
23
24 pub bind_group: BindGroup,
25}
26
27type Ortho = [[f32; 4]; 4];
28
29impl WgpuTexture {
30 pub fn new(device: &mut Device, queue: &mut Queue, drawer: &Drawer, image: &[u8], width: u32, height: u32) -> Self {
31 let texture = device.create_texture(&wgpu::TextureDescriptor {
32 size: Extent3d { width: width, height: height, depth: 1 },
33 array_layer_count: 1,
34 dimension: TextureDimension::D2,
35 format: TEXTURE_FORMAT,
36 mip_level_count: 1,
37 sample_count: 1,
38 usage: TextureUsage::SAMPLED | TextureUsage::COPY_DST,
39 });
40 let sampler = device.create_sampler(&SamplerDescriptor {
41 address_mode_u: AddressMode::ClampToEdge,
42 address_mode_v: AddressMode::ClampToEdge,
43 address_mode_w: AddressMode::ClampToEdge,
44 mag_filter: FilterMode::Linear,
45 min_filter: FilterMode::Linear,
46 mipmap_filter: FilterMode::Linear,
47 lod_min_clamp: -100.0,
48 lod_max_clamp: 100.0,
49 compare_function: CompareFunction::Always,
50 });
51
52 let bytes = image.len();
53 let buffer = device.create_buffer_mapped(bytes, BufferUsage::COPY_SRC);
54 let buffer = buffer.fill_from_slice(image);
55
56 let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor { todo: 0 });
57
58 let pixel_size = bytes as u32 / width / height;
59 encoder.copy_buffer_to_texture(
60 BufferCopyView {
61 buffer: &buffer,
62 offset: 0,
63 row_pitch: pixel_size * width,
64 image_height: height,
65 },
66 TextureCopyView {
67 texture: &texture,
68 mip_level: 0,
69 array_layer: 0,
70 origin: Origin3d { x: 0.0, y: 0.0, z: 0.0 },
71 },
72 Extent3d { width, height, depth: 1 },
73 );
74
75 queue.submit(&[encoder.finish()]);
76
77 WgpuTexture {
78 bind_group: device.create_bind_group(&BindGroupDescriptor {
79 layout: &drawer.tla,
80 bindings: &[
81 wgpu::Binding {
82 binding: 0,
83 resource: BindingResource::TextureView(&texture.create_default_view()),
84 },
85 wgpu::Binding {
86 binding: 1,
87 resource: BindingResource::Sampler(&sampler),
88 },
89 ],
90 }),
91 sampler,
92 texture,
93 }
94 }
95}
96
97pub struct Drawer {
98 cmd: NkBuffer,
99 pso: RenderPipeline,
100 tla: BindGroupLayout,
101 tex: Vec<WgpuTexture>,
102 ubf: Buffer,
103 ubg: BindGroup,
104 vsz: usize,
105 esz: usize,
106 vle: DrawVertexLayoutElements,
107
108 pub col: Option<Color>,
109}
110
111impl Drawer {
112 pub fn new(device: &mut Device, col: Color, texture_count: usize, vbo_size: usize, ebo_size: usize, command_buffer: NkBuffer) -> Drawer {
113 let vs = include_bytes!("../shaders/vs.fx");
114 let fs = include_bytes!("../shaders/ps.fx");
115
116 let vs = device.create_shader_module(compile_glsl(from_utf8(vs).unwrap(), glsl_to_spirv::ShaderType::Vertex).as_slice());
117 let fs = device.create_shader_module(compile_glsl(from_utf8(fs).unwrap(), glsl_to_spirv::ShaderType::Fragment).as_slice());
118
119 let ubf = device.create_buffer(&BufferDescriptor {
120 size: size_of::<Ortho>() as u64,
121 usage: BufferUsage::UNIFORM | BufferUsage::COPY_DST,
122 });
123 let ubg = BindGroupLayoutDescriptor {
124 bindings: &[BindGroupLayoutBinding {
125 binding: 0,
126 visibility: ShaderStage::VERTEX,
127 ty: wgpu::BindingType::UniformBuffer { dynamic: false },
128 }],
129 };
130
131 let tbg = BindGroupLayoutDescriptor {
132 bindings: &[
133 BindGroupLayoutBinding {
134 binding: 0,
135 visibility: ShaderStage::FRAGMENT,
136 ty: wgpu::BindingType::SampledTexture {
137 multisampled: false,
138 dimension: wgpu::TextureViewDimension::D2,
139 },
140 },
141 BindGroupLayoutBinding {
142 binding: 1,
143 visibility: ShaderStage::FRAGMENT,
144 ty: BindingType::Sampler,
145 },
146 ],
147 };
148 let tla = device.create_bind_group_layout(&tbg);
149 let ula = device.create_bind_group_layout(&ubg);
150
151 Drawer {
152 cmd: command_buffer,
153 col: Some(col),
154 pso: device.create_render_pipeline(&RenderPipelineDescriptor {
155 layout: &device.create_pipeline_layout(&PipelineLayoutDescriptor { bind_group_layouts: &[&ula, &tla] }),
156 vertex_stage: ProgrammableStageDescriptor { module: &vs, entry_point: "main" },
157 fragment_stage: Some(ProgrammableStageDescriptor { module: &fs, entry_point: "main" }),
158 rasterization_state: Some(RasterizationStateDescriptor {
159 front_face: FrontFace::Cw,
160 cull_mode: CullMode::None,
161 depth_bias: 0,
162 depth_bias_slope_scale: 0.0,
163 depth_bias_clamp: 0.0,
164 }),
165 primitive_topology: PrimitiveTopology::TriangleList,
166 color_states: &[ColorStateDescriptor {
167 format: TEXTURE_FORMAT,
168 color_blend: BlendDescriptor {
169 src_factor: BlendFactor::SrcAlpha,
170 dst_factor: BlendFactor::OneMinusSrcAlpha,
171 operation: BlendOperation::Add,
172 },
173 alpha_blend: BlendDescriptor {
174 src_factor: BlendFactor::OneMinusDstAlpha,
175 dst_factor: BlendFactor::One,
176 operation: BlendOperation::Add,
177 },
178 write_mask: ColorWrite::ALL,
179 }],
180 depth_stencil_state: None,
181 index_format: IndexFormat::Uint16,
182 vertex_buffers: &[VertexBufferDescriptor {
183 stride: (size_of::<Vertex>()) as u64,
184 step_mode: InputStepMode::Vertex,
185 attributes: &[
186 wgpu::VertexAttributeDescriptor {
187 format: VertexFormat::Float2,
188 shader_location: 0,
189 offset: 0,
190 },
191 wgpu::VertexAttributeDescriptor {
192 format: VertexFormat::Float2,
193 shader_location: 1,
194 offset: 8,
195 },
196 wgpu::VertexAttributeDescriptor {
197 format: VertexFormat::Uint,
198 shader_location: 2,
199 offset: 16,
200 },
201 ],
202 }],
203 sample_count: 1,
204 sample_mask: !0,
205 alpha_to_coverage_enabled: false,
206 }),
207 tex: Vec::with_capacity(texture_count + 1),
208 vsz: vbo_size,
209 esz: ebo_size,
210 ubg: device.create_bind_group(&wgpu::BindGroupDescriptor {
211 layout: &ula,
212 bindings: &[Binding {
213 binding: 0,
214 resource: BindingResource::Buffer {
215 buffer: &ubf,
216 range: 0..(size_of::<Ortho>() as u64),
217 },
218 }],
219 }),
220 ubf: ubf,
221 vle: DrawVertexLayoutElements::new(&[
222 (DrawVertexLayoutAttribute::Position, DrawVertexLayoutFormat::Float, 0),
223 (DrawVertexLayoutAttribute::TexCoord, DrawVertexLayoutFormat::Float, size_of::<f32>() as Size * 2),
224 (DrawVertexLayoutAttribute::Color, DrawVertexLayoutFormat::B8G8R8A8, size_of::<f32>() as Size * 4),
225 (DrawVertexLayoutAttribute::AttributeCount, DrawVertexLayoutFormat::Count, 0),
226 ]),
227 tla: tla,
228 }
229 }
230
231 pub fn add_texture(&mut self, device: &mut Device, queue: &mut Queue, image: &[u8], width: u32, height: u32) -> Handle {
232 self.tex.push(WgpuTexture::new(device, queue, self, image, width, height));
233 Handle::from_id(self.tex.len() as i32)
234 }
235
236 pub fn draw(&mut self, ctx: &mut Context, cfg: &mut ConvertConfig, encoder: &mut CommandEncoder, view: &TextureView, device: &mut Device, width: u32, height: u32, scale: Vec2) {
237 let ortho: Ortho = [
238 [2.0f32 / width as f32, 0.0f32, 0.0f32, 0.0f32],
239 [0.0f32, -2.0f32 / height as f32, 0.0f32, 0.0f32],
240 [0.0f32, 0.0f32, -1.0f32, 0.0f32],
241 [-1.0f32, 1.0f32, 0.0f32, 1.0f32],
242 ];
243 let ubf_size = size_of_val(&ortho);
244 cfg.set_vertex_layout(&self.vle);
245 cfg.set_vertex_size(size_of::<Vertex>());
246
247 let mut vbf = device.create_buffer_mapped(self.vsz, BufferUsage::VERTEX | BufferUsage::COPY_SRC);
248 let mut ebf = device.create_buffer_mapped(self.esz, BufferUsage::INDEX | BufferUsage::COPY_SRC);
249 let ubf = device.create_buffer_mapped(ubf_size, BufferUsage::UNIFORM | BufferUsage::COPY_SRC);
250 {
251 let mut vbuf = NkBuffer::with_fixed(&mut vbf.data);
252 let mut ebuf = NkBuffer::with_fixed(&mut ebf.data);
253
254 ctx.convert(&mut self.cmd, &mut vbuf, &mut ebuf, cfg);
255
256 let vbf = unsafe { std::slice::from_raw_parts_mut(vbf.data as *mut _ as *mut Vertex, vbf.data.len() / std::mem::size_of::<Vertex>()) };
257
258 for v in vbf.iter_mut() {
259 v.pos[1] = height as f32 - v.pos[1];
260 }
261 }
262 let vbf = vbf.finish();
263 let ebf = ebf.finish();
264 let ubf = ubf.fill_from_slice(as_typed_slice(&ortho));
265
266 encoder.copy_buffer_to_buffer(&ubf, 0, &self.ubf, 0, ubf_size as u64);
267
268 let mut rpass = encoder.begin_render_pass(&RenderPassDescriptor {
269 color_attachments: &[RenderPassColorAttachmentDescriptor {
270 attachment: &view,
271 load_op: match self.col {
272 Some(_) => wgpu::LoadOp::Clear,
273 _ => wgpu::LoadOp::Load,
274 },
275 resolve_target: None,
276 store_op: StoreOp::Store,
277 clear_color: self.col.unwrap_or(Color { r: 1.0, g: 2.0, b: 3.0, a: 1.0 }),
278 }],
279 depth_stencil_attachment: None,
280 });
281 rpass.set_pipeline(&self.pso);
282
283 rpass.set_vertex_buffers(0, &[(&vbf, 0)]);
284 rpass.set_index_buffer(&ebf, 0);
285
286 rpass.set_bind_group(0, &self.ubg, &[]);
287
288 let mut start = 0;
289 let mut end;
290
291 for cmd in ctx.draw_command_iterator(&self.cmd) {
292 if cmd.elem_count() < 1 {
293 continue;
294 }
295
296 let id = cmd.texture().id().unwrap();
297 let res = self.find_res(id).unwrap();
298
299 end = start + cmd.elem_count();
300
301 rpass.set_bind_group(1, &res.bind_group, &[]);
302
303 rpass.set_scissor_rect((cmd.clip_rect().x * scale.x) as u32, (cmd.clip_rect().y * scale.y) as u32, (cmd.clip_rect().w * scale.x) as u32, (cmd.clip_rect().h * scale.y) as u32);
304
305 rpass.draw_indexed(start..end, 0 as i32, 0..1);
306
307 start = end;
308 }
309 }
310
311 fn find_res(&self, id: i32) -> Option<&WgpuTexture> {
312 if id > 0 && id as usize <= self.tex.len() {
313 self.tex.get((id - 1) as usize)
314 } else {
315 None
316 }
317 }
318}
319
320fn as_typed_slice<T>(data: &[T]) -> &[u8] {
321 unsafe { from_raw_parts(data.as_ptr() as *const u8, data.len() * size_of::<T>()) }
322}
323fn compile_glsl(code: &str, ty: glsl_to_spirv::ShaderType) -> Vec<u32> {
324 use std::io::Read;
325
326 let mut output = glsl_to_spirv::compile(code, ty).unwrap();
327 let mut spv = Vec::new();
328 output.read_to_end(&mut spv).unwrap();
329 let spv32: Vec<u32> = unsafe { Vec::from_raw_parts(spv.as_mut_ptr() as *mut _ as *mut u32, spv.len() / 4, spv.capacity() / 4) };
330 forget(spv);
331 spv32
332}