1use crate::*;
58use crate::rs_math3d::*;
59use crate::nc_renderer::*;
60use rs_ctypes::*;
61
62use egui::{
63 paint::{Color32, Mesh, Texture},
64 vec2, ClippedMesh,
65};
66
67render_data! {
68 vertex Vertex {
69 a_pos : Vec2f,
70 a_tc : Vec2f,
71 s_rgba : Color4b,
72
73 }
74
75 uniforms Uniforms {
76 u_screen_size : Vec2f,
77 }
78}
79
80#[derive(Default)]
81struct UserTexture {
82 size: (usize, usize),
83
84 pixels: Vec<u8>,
86
87 texture: Option<TexturePtr>,
89
90 filtering: bool,
93
94 dirty: bool,
98}
99
100const VS_SRC: &str = r#"
101 #version 300 es
102 uniform vec2 u_screen_size;
103 in highp vec2 a_pos;
104 in highp vec4 s_rgba;
105 in highp vec2 a_tc;
106 in highp vec3 b;
107 out highp vec4 v_rgba;
108 out vec2 v_tc;
109
110 void main() {
111 gl_Position = vec4(
112 2.0 * a_pos.x / u_screen_size.x - 1.0,
113 1.0 - 2.0 * a_pos.y / u_screen_size.y,
114 0.0,
115 1.0);
116 v_rgba = s_rgba;
117 v_tc = a_tc;
118 }
119"#;
120
121const FS_SRC: &str = r#"
122 #version 300 es
123 uniform lowp sampler2D u_sampler;
124 in highp vec4 v_rgba;
125 in highp vec2 v_tc;
126 in highp vec3 v_b;
127 layout(location = 0) out lowp vec4 f_color;
128
129 void main() {
130 highp vec4 tcol = texture(u_sampler, v_tc);
131 f_color = tcol * v_rgba;
132 }
133"#;
134
135pub struct Painter {
136 driver : DriverPtr,
137 pipeline: PipelinePtr,
138 index_buffer: DeviceBufferPtr,
139 vertex_buffer: DeviceBufferPtr,
140 canvas_width: u32,
141 canvas_height: u32,
142 egui_texture: Option<TexturePtr>,
143 egui_texture_version: Option<u64>,
144 user_textures: Vec<UserTexture>,
145}
146
147impl Painter {
148 pub fn new(
149 drv: &mut DriverPtr,
150 window: &mut glfw::Window,
151 canvas_width: u32,
152 canvas_height: u32,
153 ) -> Painter {
154
155 let program = drv.create_shader(ShaderDesc {
156 vertex_shader : String::from(VS_SRC),
157 pixel_shader : String::from(FS_SRC),
158
159 vertex_attributes : vec!{
160 Vertex::get_attribute_names(),
161 },
162 vertex_uniforms : Uniforms::get_uniform_names(),
163 vertex_surfaces : vec!{},
164
165 pixel_uniforms : vec!{},
166 pixel_surfaces : vec!{ String::from("u_sampler") }
167 }).unwrap();
168
169 let vertex_layout = VertexBufferLayout {
170 buffer_id : 0,
171 vertex_attributes : Vertex::get_attribute_descriptors(),
172 stride : Vertex::stride(),
173 divisor : 0,
174 };
175
176 let pipeline_desc = PipelineDesc {
177 primitive_type : PrimitiveType::Triangles,
178 shader : program,
179 buffer_layouts : vec! { vertex_layout.clone() },
180 uniform_descs : Uniforms::get_uniform_descriptors(),
181 index_type : IndexType::UInt16,
182 face_winding : FaceWinding::CCW,
183 cull_mode : CullMode::None,
184 depth_write : true,
185 depth_test : false,
186 blend : BlendOp::Add(Blend::default()),
187 };
188
189 let pipeline = drv.create_pipeline(pipeline_desc).unwrap();
190
191 let index_buffer = drv.create_device_buffer(DeviceBufferDesc::Index(Usage::Dynamic(65536 * 4))).unwrap();
192 let vertex_buffer = drv.create_device_buffer(DeviceBufferDesc::Vertex(Usage::Dynamic(65536 * 4 * std::mem::size_of::<Vertex>()))).unwrap();
193 Painter {
194 driver: drv.clone(),
195 pipeline,
196 canvas_width,
197 canvas_height,
198 index_buffer,
199 vertex_buffer,
200 egui_texture: None,
201 egui_texture_version: None,
202 user_textures: Default::default(),
203 }
204 }
205
206 pub fn new_user_texture(
207 &mut self,
208 size: (usize, usize),
209 srgba_pixels: &[Color32],
210 filtering: bool,
211 ) -> egui::TextureId {
212 assert_eq!(size.0 * size.1, srgba_pixels.len());
213
214 let mut pixels: Vec<u8> = Vec::with_capacity(srgba_pixels.len() * 4);
215 for srgba in srgba_pixels {
216 pixels.push(srgba.r());
217 pixels.push(srgba.g());
218 pixels.push(srgba.b());
219 pixels.push(srgba.a());
220 }
221
222 let id = egui::TextureId::User(self.user_textures.len() as u64);
223 self.user_textures.push(UserTexture {
224 size,
225 pixels,
226 texture: None,
227 filtering,
228 dirty: true,
229 });
230 id
231 }
232
233 fn upload_egui_texture(&mut self, texture: &Texture) {
234 if self.egui_texture_version == Some(texture.version) {
235 return; }
237
238 println!("uploading egui texture: {}x{}", texture.width, texture.height);
239 let mut pixels: Vec<u8> = Vec::with_capacity(texture.pixels.len() * 4);
240 for &alpha in &texture.pixels {
241 let srgba = Color32::from_white_alpha(alpha);
242
243 pixels.push(srgba.r());
244 pixels.push(srgba.g());
245 pixels.push(srgba.b());
246 pixels.push(srgba.a());
247 }
248
249 let tex_desc = TextureDesc {
250 sampler_desc : SamplerDesc::default(texture.width, texture.height)
251 .with_pixel_format(PixelFormat::RGBA8(MinMagFilter::default()
252 .with_mag_filter(Filter::Linear)
253 .with_min_filter(Filter::Linear)))
254 .with_wrap_mode(WrapMode::ClampToEdge),
255 payload : Some(Box::new(pixels))
256 };
257
258 let tex = self.driver.create_texture(tex_desc).unwrap();
259 self.egui_texture = Some(tex);
260 self.egui_texture_version = Some(texture.version);
261 }
262
263 fn upload_user_textures(&mut self) {
264 for user_texture in &mut self.user_textures {
265 if !user_texture.texture.is_none() && !user_texture.dirty {
266 continue;
267 }
268
269 let pixels = std::mem::take(&mut user_texture.pixels);
270
271 let tex_desc = TextureDesc {
272 sampler_desc : SamplerDesc::default(user_texture.size.0, user_texture.size.1).with_pixel_format(PixelFormat::RGBA8(MinMagFilter::default().with_mag_filter(Filter::Linear).with_min_filter(Filter::Linear))),
273 payload : Some(Box::new(pixels))
274 };
275
276 if user_texture.texture.is_none() {
277 println!("uploading user texture");
278
279 let tex = self.driver.create_texture(tex_desc).unwrap();
280 user_texture.texture = Some(tex);
281 } else {
282 self.driver.update_texture(&mut user_texture.texture.as_mut().unwrap(), tex_desc.payload.unwrap())
283 }
284 user_texture.dirty = false;
285 }
286 }
287
288 fn get_texture(&self, texture_id: egui::TextureId) -> TexturePtr {
289 match texture_id {
290 egui::TextureId::Egui => {
291 self.egui_texture.as_ref().unwrap().clone()
292 },
293
294 egui::TextureId::User(id) => {
295
296 let id = id as usize;
297 assert!(id < self.user_textures.len());
298 let texture = self.user_textures[id].texture.clone();
299 texture.expect("Should have been uploaded")
300 }
301 }
302 }
303
304 pub fn update_user_texture_data(&mut self, texture_id: egui::TextureId, pixels: &[Color32]) {
305 match texture_id {
306 egui::TextureId::Egui => {}
307 egui::TextureId::User(id) => {
308 let id = id as usize;
309 assert!(id < self.user_textures.len());
310 self.user_textures[id].pixels = Vec::with_capacity(pixels.len() * 4);
311
312 for p in pixels {
313 self.user_textures[id].pixels.push(p.r());
314 self.user_textures[id].pixels.push(p.g());
315 self.user_textures[id].pixels.push(p.b());
316 self.user_textures[id].pixels.push(p.a());
317 }
318 self.user_textures[id].dirty = true;
319 }
320 }
321 }
322
323 pub fn paint_jobs(
324 &mut self,
325 frame_buffer: Option<FrameBufferPtr>,
326 bg_color: Option<Color32>,
327 meshes: Vec<ClippedMesh>,
328 egui_texture: &Texture,
329 pixels_per_point: f32,
330 ) {
331 self.upload_egui_texture(egui_texture);
332 self.upload_user_textures();
333
334 let screen_size_pixels = vec2(self.canvas_width as f32, self.canvas_height as f32);
335 let screen_size_points = screen_size_pixels / pixels_per_point;
336
337
338 for ClippedMesh(clip_rect, mesh) in meshes {
339
340 let clip_min_x = pixels_per_point * clip_rect.min.x;
341 let clip_min_y = pixels_per_point * clip_rect.min.y;
342 let clip_max_x = pixels_per_point * clip_rect.max.x;
343 let clip_max_y = pixels_per_point * clip_rect.max.y;
344 let clip_min_x = clip_min_x.clamp(0.0, screen_size_pixels.x);
345 let clip_min_y = clip_min_y.clamp(0.0, screen_size_pixels.y);
346 let clip_max_x = clip_max_x.clamp(clip_min_x, screen_size_pixels.x);
347 let clip_max_y = clip_max_y.clamp(clip_min_y, screen_size_pixels.y);
348 let clip_min_x = clip_min_x.round() as i32;
349 let clip_min_y = clip_min_y.round() as i32;
350 let clip_max_x = clip_max_x.round() as i32;
351 let clip_max_y = clip_max_y.round() as i32;
352
353 self.driver.set_scissor (
355 clip_min_x as u32,
356 self.canvas_height as u32 - clip_max_y as u32,
357 (clip_max_x - clip_min_x) as u32,
358 (clip_max_y - clip_min_y) as u32,
359 );
360
361 if mesh.vertices.len() > 0 {
362 self.paint_mesh(&mesh, Vec2f::new(screen_size_points.x, screen_size_points.y));
363 }
364 }
365 }
366
367 fn paint_mesh(&mut self, mesh: &Mesh, screen_size: Vec2f) {
368 debug_assert!(mesh.is_valid());
369 let indices: Vec<u16> = mesh.indices.iter().map(|idx| *idx as u16).collect();
370
371 let mut vertices: Vec<Vertex> = Vec::with_capacity(mesh.vertices.len());
372 for v in &mesh.vertices {
373 let vert = Vertex {
374 a_pos : Vec2f::new(v.pos.x, v.pos.y),
375 s_rgba : color4b(v.color[0], v.color[1], v.color[2], v.color[3]),
376 a_tc : Vec2f::new(v.uv.x, v.uv.y),
377 };
378
379 vertices.push(vert);
380 }
381
382 self.driver.update_device_buffer(&mut self.vertex_buffer, 0, &vertices);
383 self.driver.update_device_buffer(&mut self.index_buffer, 0, &indices);
384
385 let bindings = Bindings {
386 vertex_buffers : vec!{ self.vertex_buffer.clone() },
387 index_buffer : Some(self.index_buffer.clone()),
388
389 vertex_images : Vec::new(),
390 pixel_images : Vec::from([self.get_texture(mesh.texture_id)]),
391 };
392
393 let u = Uniforms { u_screen_size: screen_size };
394 self.driver.draw(&self.pipeline, &bindings, &u as *const Uniforms as *const c_void, (indices.len() / 3) as u32, 1);
395 }
396}