mod.rs
1 use crate::cmd::Axis; 2 use crate::draw; 3 use crate::execution::Execution; 4 use crate::font::TextBatch; 5 use crate::platform::{self, LogicalSize}; 6 use crate::renderer; 7 use crate::session::{self, Blending, Effect, Session}; 8 use crate::sprite; 9 use crate::util; 10 use crate::view::resource::ViewResource; 11 use crate::view::{View, ViewId, ViewOp, ViewState}; 12 use crate::{data, data::Assets, image}; 13 14 use crate::gfx::{shape2d, sprite2d, Origin, Rgba, Rgba8, ZDepth}; 15 use crate::gfx::{Matrix4, Rect, Repeat, Vector2}; 16 17 use luminance::context::GraphicsContext; 18 use luminance::depth_test::DepthComparison; 19 use luminance::framebuffer::Framebuffer; 20 use luminance::pipeline::{PipelineState, TextureBinding}; 21 use luminance::pixel; 22 use luminance::render_state::RenderState; 23 use luminance::shader::{Program, Uniform}; 24 use luminance::tess::{Mode, Tess, TessBuilder}; 25 use luminance::texture::{Dim2, GenMipmaps, MagFilter, MinFilter, Sampler, Texture, Wrap}; 26 use luminance::{ 27 blending::{self, Equation, Factor}, 28 pipeline::PipelineError, 29 }; 30 31 use luminance_derive::{Semantics, UniformInterface, Vertex}; 32 use luminance_gl::gl33; 33 34 use std::collections::BTreeMap; 35 use std::error::Error; 36 use std::fmt; 37 use std::io; 38 use std::mem; 39 use std::time; 40 41 type Backend = gl33::GL33; 42 type M44 = [[f32; 4]; 4]; 43 44 const SAMPLER: Sampler = Sampler { 45 wrap_r: Wrap::Repeat, 46 wrap_s: Wrap::Repeat, 47 wrap_t: Wrap::Repeat, 48 min_filter: MinFilter::Nearest, 49 mag_filter: MagFilter::Nearest, 50 depth_comparison: None, 51 }; 52 53 #[derive(UniformInterface)] 54 struct Sprite2dInterface { 55 tex: Uniform<TextureBinding<Dim2, pixel::NormUnsigned>>, 56 ortho: Uniform<M44>, 57 transform: Uniform<M44>, 58 } 59 60 #[derive(Copy, Clone, Debug, Semantics)] 61 pub enum VertexSemantics { 62 #[sem(name = "position", repr = "[f32; 3]", wrapper = "VertexPosition")] 63 Position, 64 #[sem(name = "uv", repr = "[f32; 2]", wrapper = "VertexUv")] 65 Uv, 66 #[sem(name = "color", repr = "[u8; 4]", wrapper = "VertexColor")] 67 Color, 68 #[sem(name = "opacity", repr = "[f32; 1]", wrapper = "VertexOpacity")] 69 Opacity, 70 #[sem(name = "angle", repr = "[f32; 1]", wrapper = "VertexAngle")] 71 Angle, 72 #[sem(name = "center", repr = "[f32; 2]", wrapper = "VertexCenter")] 73 Center, 74 } 75 76 #[repr(C)] 77 #[derive(Copy, Clone, Vertex)] 78 #[vertex(sem = "VertexSemantics")] 79 #[rustfmt::skip] 80 struct Sprite2dVertex { 81 #[allow(dead_code)] position: VertexPosition, 82 #[allow(dead_code)] uv: VertexUv, 83 #[vertex(normalized = "true")] 84 #[allow(dead_code)] color: VertexColor, 85 #[allow(dead_code)] opacity: VertexOpacity, 86 } 87 88 //////////////////////////////////////////////////////////// 89 90 #[derive(UniformInterface)] 91 struct Shape2dInterface { 92 ortho: Uniform<M44>, 93 transform: Uniform<M44>, 94 } 95 96 #[repr(C)] 97 #[derive(Copy, Clone, Vertex)] 98 #[vertex(sem = "VertexSemantics")] 99 #[rustfmt::skip] 100 struct Shape2dVertex { 101 #[allow(dead_code)] position: VertexPosition, 102 #[allow(dead_code)] angle: VertexAngle, 103 #[allow(dead_code)] center: VertexCenter, 104 #[vertex(normalized = "true")] 105 #[allow(dead_code)] color: VertexColor, 106 } 107 108 #[derive(UniformInterface)] 109 struct Cursor2dInterface { 110 cursor: Uniform<TextureBinding<Dim2, pixel::NormUnsigned>>, 111 framebuffer: Uniform<TextureBinding<Dim2, pixel::NormUnsigned>>, 112 ortho: Uniform<M44>, 113 scale: Uniform<f32>, 114 } 115 116 #[repr(C)] 117 #[derive(Copy, Clone, Vertex)] 118 #[vertex(sem = "VertexSemantics")] 119 #[rustfmt::skip] 120 struct Cursor2dVertex { 121 #[allow(dead_code)] position: VertexPosition, 122 #[allow(dead_code)] uv: VertexUv, 123 } 124 125 #[derive(UniformInterface)] 126 struct Screen2dInterface { 127 framebuffer: Uniform<TextureBinding<Dim2, pixel::NormUnsigned>>, 128 } 129 130 pub struct Renderer { 131 pub win_size: LogicalSize, 132 133 ctx: Context, 134 draw_ctx: draw::Context, 135 scale_factor: f64, 136 scale: f64, 137 present_fb: Framebuffer<Backend, Dim2, (), ()>, 138 screen_fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F>, 139 render_st: RenderState, 140 pipeline_st: PipelineState, 141 blending: Blending, 142 143 staging_batch: shape2d::Batch, 144 final_batch: shape2d::Batch, 145 146 font: Texture<Backend, Dim2, pixel::SRGBA8UI>, 147 cursors: Texture<Backend, Dim2, pixel::SRGBA8UI>, 148 checker: Texture<Backend, Dim2, pixel::SRGBA8UI>, 149 paste: Texture<Backend, Dim2, pixel::SRGBA8UI>, 150 paste_outputs: Vec<Tess<Backend, Sprite2dVertex>>, 151 152 sprite2d: Program<Backend, VertexSemantics, (), Sprite2dInterface>, 153 shape2d: Program<Backend, VertexSemantics, (), Shape2dInterface>, 154 cursor2d: Program<Backend, VertexSemantics, (), Cursor2dInterface>, 155 screen2d: Program<Backend, VertexSemantics, (), Screen2dInterface>, 156 157 view_data: BTreeMap<ViewId, ViewData>, 158 } 159 160 struct LayerData { 161 fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F>, 162 tess: Tess<Backend, Sprite2dVertex>, 163 } 164 165 impl LayerData { 166 fn new(w: u32, h: u32, pixels: Option<&[Rgba8]>, ctx: &mut Context) -> Self { 167 let batch = sprite2d::Batch::singleton( 168 w, 169 h, 170 Rect::origin(w as f32, h as f32), 171 Rect::origin(w as f32, h as f32), 172 ZDepth::default(), 173 Rgba::TRANSPARENT, 174 1., 175 Repeat::default(), 176 ); 177 178 let verts: Vec<Sprite2dVertex> = batch 179 .vertices() 180 .iter() 181 .map(|v| unsafe { mem::transmute(*v) }) 182 .collect(); 183 let tess = TessBuilder::new(ctx) 184 .set_vertices(verts) 185 .set_mode(Mode::Triangle) 186 .build() 187 .unwrap(); 188 189 let mut fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F> = 190 Framebuffer::new(ctx, [w, h], 0, self::SAMPLER).unwrap(); 191 192 fb.color_slot().clear(GenMipmaps::No, (0, 0, 0, 0)).unwrap(); 193 194 if let Some(pixels) = pixels { 195 let aligned = util::align_u8(pixels); 196 fb.color_slot().upload_raw(GenMipmaps::No, aligned).unwrap(); 197 } 198 199 Self { fb, tess } 200 } 201 202 fn clear(&mut self) -> Result<(), RendererError> { 203 self.fb 204 .color_slot() 205 .clear(GenMipmaps::No, (0, 0, 0, 0)) 206 .map_err(RendererError::Texture) 207 } 208 209 fn upload_part( 210 &mut self, 211 offset: [u32; 2], 212 size: [u32; 2], 213 texels: &[u8], 214 ) -> Result<(), RendererError> { 215 self.fb 216 .color_slot() 217 .upload_part_raw(GenMipmaps::No, offset, size, texels) 218 .map_err(RendererError::Texture) 219 } 220 221 fn upload(&mut self, texels: &[u8]) -> Result<(), RendererError> { 222 self.fb 223 .color_slot() 224 .upload_raw(GenMipmaps::No, texels) 225 .map_err(RendererError::Texture) 226 } 227 228 fn pixels(&mut self) -> Vec<Rgba8> { 229 let texels = self 230 .fb 231 .color_slot() 232 .get_raw_texels() 233 .expect("getting raw texels never fails"); 234 Rgba8::align(&texels).to_vec() 235 } 236 } 237 238 struct ViewData { 239 layer: LayerData, 240 staging_fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F>, 241 anim_tess: Option<Tess<Backend, Sprite2dVertex>>, 242 layer_tess: Option<Tess<Backend, Sprite2dVertex>>, 243 } 244 245 impl ViewData { 246 fn new(w: u32, h: u32, pixels: Option<&[Rgba8]>, ctx: &mut Context) -> Self { 247 let mut staging_fb: Framebuffer<Backend, Dim2, pixel::SRGBA8UI, pixel::Depth32F> = 248 Framebuffer::new(ctx, [w, h], 0, self::SAMPLER).unwrap(); 249 250 staging_fb 251 .color_slot() 252 .clear(GenMipmaps::No, (0, 0, 0, 0)) 253 .unwrap(); 254 255 Self { 256 layer: LayerData::new(w, h, pixels, ctx), 257 staging_fb, 258 anim_tess: None, 259 layer_tess: None, 260 } 261 } 262 } 263 264 struct Context { 265 ctx: Backend, 266 } 267 268 unsafe impl GraphicsContext for Context { 269 type Backend = self::Backend; 270 271 fn backend(&mut self) -> &mut Self::Backend { 272 &mut self.ctx 273 } 274 } 275 276 impl Context { 277 fn program<T>(&mut self, vert: &str, frag: &str) -> Program<Backend, VertexSemantics, (), T> 278 where 279 T: luminance::shader::UniformInterface<Backend>, 280 { 281 self.new_shader_program() 282 .from_strings(vert, None, None, frag) 283 .unwrap() 284 .ignore_warnings() 285 } 286 287 fn tessellation<T, S>(&mut self, verts: &[T]) -> Tess<Backend, S> 288 where 289 S: luminance::vertex::Vertex + Sized, 290 { 291 let (head, body, tail) = unsafe { verts.align_to::<S>() }; 292 293 assert!(head.is_empty()); 294 assert!(tail.is_empty()); 295 296 TessBuilder::new(self) 297 .set_vertices(body) 298 .set_mode(Mode::Triangle) 299 .build() 300 .unwrap() 301 } 302 } 303 304 #[derive(Debug)] 305 pub enum RendererError { 306 Initialization, 307 Texture(luminance::texture::TextureError), 308 Framebuffer(luminance::framebuffer::FramebufferError), 309 Pipeline(luminance::pipeline::PipelineError), 310 State(luminance_gl::gl33::StateQueryError), 311 } 312 313 impl From<luminance::pipeline::PipelineError> for RendererError { 314 fn from(other: luminance::pipeline::PipelineError) -> Self { 315 Self::Pipeline(other) 316 } 317 } 318 319 impl From<RendererError> for io::Error { 320 fn from(err: RendererError) -> io::Error { 321 io::Error::new(io::ErrorKind::Other, err) 322 } 323 } 324 325 impl fmt::Display for RendererError { 326 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 327 match self { 328 Self::Initialization => write!(f, "initialization error"), 329 Self::Texture(e) => write!(f, "texture error: {}", e), 330 Self::Framebuffer(e) => write!(f, "framebuffer error: {}", e), 331 Self::Pipeline(e) => write!(f, "pipeline error: {}", e), 332 Self::State(e) => write!(f, "state error: {}", e), 333 } 334 } 335 } 336 337 impl Error for RendererError { 338 fn description(&self) -> &str { 339 "Renderer error" 340 } 341 342 fn cause(&self) -> Option<&dyn Error> { 343 None 344 } 345 } 346 347 impl<'a> renderer::Renderer<'a> for Renderer { 348 type Error = RendererError; 349 350 fn new( 351 win: &mut platform::backend::Window, 352 win_size: LogicalSize, 353 scale_factor: f64, 354 assets: Assets<'a>, 355 ) -> io::Result<Self> { 356 use RendererError as Error; 357 358 gl::load_with(|s| win.get_proc_address(s) as *const _); 359 360 let ctx = Backend::new().map_err(Error::State)?; 361 let mut ctx = Context { ctx }; 362 363 let (font_img, font_w, font_h) = image::read(assets.glyphs)?; 364 let (cursors_img, cursors_w, cursors_h) = image::read(data::CURSORS)?; 365 let (checker_w, checker_h) = (2, 2); 366 let (paste_w, paste_h) = (8, 8); 367 368 let mut font = 369 Texture::new(&mut ctx, [font_w, font_h], 0, self::SAMPLER).map_err(Error::Texture)?; 370 let mut cursors = Texture::new(&mut ctx, [cursors_w, cursors_h], 0, self::SAMPLER) 371 .map_err(Error::Texture)?; 372 let paste = 373 Texture::new(&mut ctx, [paste_w, paste_h], 0, self::SAMPLER).map_err(Error::Texture)?; 374 let mut checker = Texture::new(&mut ctx, [checker_w, checker_h], 0, self::SAMPLER) 375 .map_err(Error::Texture)?; 376 377 font.upload_raw(GenMipmaps::No, &font_img) 378 .map_err(Error::Texture)?; 379 cursors 380 .upload_raw(GenMipmaps::No, &cursors_img) 381 .map_err(Error::Texture)?; 382 checker 383 .upload_raw(GenMipmaps::No, &draw::CHECKER) 384 .map_err(Error::Texture)?; 385 386 let sprite2d = ctx.program::<Sprite2dInterface>( 387 include_str!("data/sprite.vert"), 388 include_str!("data/sprite.frag"), 389 ); 390 let shape2d = ctx.program::<Shape2dInterface>( 391 include_str!("data/shape.vert"), 392 include_str!("data/shape.frag"), 393 ); 394 let cursor2d = ctx.program::<Cursor2dInterface>( 395 include_str!("data/cursor.vert"), 396 include_str!("data/cursor.frag"), 397 ); 398 let screen2d = ctx.program::<Screen2dInterface>( 399 include_str!("data/screen.vert"), 400 include_str!("data/screen.frag"), 401 ); 402 403 let physical = win_size.to_physical(scale_factor); 404 let present_fb = 405 Framebuffer::back_buffer(&mut ctx, [physical.width as u32, physical.height as u32]) 406 .map_err(Error::Framebuffer)?; 407 let screen_fb = Framebuffer::new( 408 &mut ctx, 409 [win_size.width as u32, win_size.height as u32], 410 0, 411 self::SAMPLER, 412 ) 413 .map_err(Error::Framebuffer)?; 414 415 let render_st = RenderState::default() 416 .set_blending(blending::Blending { 417 equation: Equation::Additive, 418 src: Factor::SrcAlpha, 419 dst: Factor::SrcAlphaComplement, 420 }) 421 .set_depth_test(Some(DepthComparison::LessOrEqual)); 422 let pipeline_st = PipelineState::default() 423 .set_clear_color([0., 0., 0., 0.]) 424 .enable_srgb(true) 425 .enable_clear_depth(true) 426 .enable_clear_color(true); 427 428 let draw_ctx = draw::Context { 429 ui_batch: shape2d::Batch::new(), 430 text_batch: self::text_batch(font.size()), 431 overlay_batch: self::text_batch(font.size()), 432 cursor_sprite: sprite::Sprite::new(cursors_w, cursors_h), 433 tool_batch: sprite2d::Batch::new(cursors_w, cursors_h), 434 paste_batch: sprite2d::Batch::new(paste_w, paste_h), 435 checker_batch: sprite2d::Batch::new(checker_w, checker_h), 436 }; 437 438 Ok(Renderer { 439 ctx, 440 draw_ctx, 441 win_size, 442 scale_factor, 443 scale: 1.0, 444 blending: Blending::Alpha, 445 present_fb, 446 screen_fb, 447 render_st, 448 pipeline_st, 449 sprite2d, 450 shape2d, 451 cursor2d, 452 screen2d, 453 font, 454 cursors, 455 checker, 456 paste, 457 paste_outputs: Vec::new(), 458 staging_batch: shape2d::Batch::new(), 459 final_batch: shape2d::Batch::new(), 460 view_data: BTreeMap::new(), 461 }) 462 } 463 464 fn init(&mut self, effects: Vec<Effect>, session: &Session) { 465 self.handle_effects(effects, session).unwrap(); 466 } 467 468 fn frame( 469 &mut self, 470 session: &mut Session, 471 execution: &mut Execution, 472 effects: Vec<session::Effect>, 473 avg_frametime: &time::Duration, 474 ) -> Result<(), RendererError> { 475 if session.state != session::State::Running { 476 return Ok(()); 477 } 478 self.staging_batch.clear(); 479 self.final_batch.clear(); 480 481 self.handle_effects(effects, session).unwrap(); 482 self.update_view_animations(session); 483 self.update_view_composites(session); 484 485 let [screen_w, screen_h] = self.screen_fb.size(); 486 let ortho: M44 = Matrix4::ortho(screen_w, screen_h, Origin::TopLeft).into(); 487 let identity: M44 = Matrix4::identity().into(); 488 489 let Self { 490 draw_ctx, 491 font, 492 cursors, 493 checker, 494 sprite2d, 495 shape2d, 496 cursor2d, 497 screen2d, 498 scale_factor, 499 present_fb, 500 blending, 501 screen_fb, 502 render_st, 503 pipeline_st, 504 paste, 505 paste_outputs, 506 view_data, 507 .. 508 } = self; 509 510 draw_ctx.clear(); 511 draw_ctx.draw(session, avg_frametime, execution); 512 513 let text_tess = self 514 .ctx 515 .tessellation::<_, Sprite2dVertex>(&draw_ctx.text_batch.vertices()); 516 let overlay_tess = self 517 .ctx 518 .tessellation::<_, Sprite2dVertex>(&draw_ctx.overlay_batch.vertices()); 519 let ui_tess = self 520 .ctx 521 .tessellation::<_, Shape2dVertex>(&draw_ctx.ui_batch.vertices()); 522 let tool_tess = self 523 .ctx 524 .tessellation::<_, Sprite2dVertex>(&draw_ctx.tool_batch.vertices()); 525 let cursor_tess = self 526 .ctx 527 .tessellation::<_, Cursor2dVertex>(&draw_ctx.cursor_sprite.vertices()); 528 let checker_tess = self 529 .ctx 530 .tessellation::<_, Sprite2dVertex>(&draw_ctx.checker_batch.vertices()); 531 let screen_tess = TessBuilder::<Backend, ()>::new(&mut self.ctx) 532 .set_vertex_nb(6) 533 .set_mode(Mode::Triangle) 534 .build() 535 .unwrap(); 536 537 let paste_tess = if draw_ctx.paste_batch.is_empty() { 538 None 539 } else { 540 Some( 541 self.ctx 542 .tessellation::<_, Sprite2dVertex>(&draw_ctx.paste_batch.vertices()), 543 ) 544 }; 545 let staging_tess = if self.staging_batch.is_empty() { 546 None 547 } else { 548 Some( 549 self.ctx 550 .tessellation::<_, Shape2dVertex>(&self.staging_batch.vertices()), 551 ) 552 }; 553 let final_tess = if self.final_batch.is_empty() { 554 None 555 } else { 556 Some( 557 self.ctx 558 .tessellation::<_, Shape2dVertex>(&self.final_batch.vertices()), 559 ) 560 }; 561 562 let help_tess = if session.mode == session::Mode::Help { 563 let mut win = shape2d::Batch::new(); 564 let mut text = self::text_batch(font.size()); 565 draw::draw_help(session, &mut text, &mut win); 566 567 let win_tess = self 568 .ctx 569 .tessellation::<_, Shape2dVertex>(win.vertices().as_slice()); 570 let text_tess = self 571 .ctx 572 .tessellation::<_, Sprite2dVertex>(text.vertices().as_slice()); 573 Some((win_tess, text_tess)) 574 } else { 575 None 576 }; 577 578 let v = session 579 .views 580 .active() 581 .expect("there must always be an active view"); 582 let v_data = view_data.get(&v.id).unwrap(); 583 let l_data = &v_data.layer; 584 let view_ortho = Matrix4::ortho(v.width(), v.fh, Origin::TopLeft); 585 586 let mut builder = self.ctx.new_pipeline_gate(); 587 588 // Render to view staging buffer. 589 builder.pipeline::<PipelineError, _, _, _, _>( 590 &v_data.staging_fb, 591 pipeline_st, 592 |pipeline, mut shd_gate| { 593 // Render staged brush strokes. 594 if let Some(tess) = staging_tess { 595 shd_gate.shade(shape2d, |mut iface, uni, mut rdr_gate| { 596 iface.set(&uni.ortho, view_ortho.into()); 597 iface.set(&uni.transform, identity); 598 599 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&tess)) 600 })?; 601 } 602 // Render staging paste buffer. 603 if let Some(tess) = paste_tess { 604 let bound_paste = pipeline 605 .bind_texture(paste) 606 .expect("binding textures never fails. qed."); 607 shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| { 608 iface.set(&uni.ortho, view_ortho.into()); 609 iface.set(&uni.transform, identity); 610 iface.set(&uni.tex, bound_paste.binding()); 611 612 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&tess)) 613 })?; 614 } 615 Ok(()) 616 }, 617 ); 618 619 // Render to view final buffer. 620 builder.pipeline::<PipelineError, _, _, _, _>( 621 &l_data.fb, 622 &pipeline_st.clone().enable_clear_color(false), 623 |pipeline, mut shd_gate| { 624 let bound_paste = pipeline 625 .bind_texture(paste) 626 .expect("binding textures never fails. qed."); 627 628 // Render final brush strokes. 629 if let Some(tess) = final_tess { 630 shd_gate.shade(shape2d, |mut iface, uni, mut rdr_gate| { 631 iface.set(&uni.ortho, view_ortho.into()); 632 iface.set(&uni.transform, identity); 633 634 let render_st = if blending == &Blending::Constant { 635 render_st.clone().set_blending(blending::Blending { 636 equation: Equation::Additive, 637 src: Factor::One, 638 dst: Factor::Zero, 639 }) 640 } else { 641 render_st.clone() 642 }; 643 644 rdr_gate.render(&render_st, |mut tess_gate| tess_gate.render(&tess)) 645 })?; 646 } 647 if !paste_outputs.is_empty() { 648 shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| { 649 iface.set(&uni.ortho, view_ortho.into()); 650 iface.set(&uni.transform, identity); 651 iface.set(&uni.tex, bound_paste.binding()); 652 653 for out in paste_outputs.drain(..) { 654 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&out))?; 655 } 656 Ok(()) 657 })?; 658 } 659 Ok(()) 660 }, 661 ); 662 663 // Render to screen framebuffer. 664 let bg = Rgba::from(session.settings["background"].to_rgba8()); 665 let screen_st = &pipeline_st 666 .clone() 667 .set_clear_color([bg.r, bg.g, bg.b, bg.a]); 668 builder.pipeline::<PipelineError, _, _, _, _>( 669 screen_fb, 670 screen_st, 671 |pipeline, mut shd_gate| { 672 // Draw view checkers to screen framebuffer. 673 if session.settings["checker"].is_set() { 674 shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| { 675 let bound_checker = pipeline 676 .bind_texture(checker) 677 .expect("binding textures never fails"); 678 679 iface.set(&uni.ortho, ortho); 680 iface.set(&uni.transform, identity); 681 iface.set(&uni.tex, bound_checker.binding()); 682 683 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&checker_tess)) 684 })?; 685 } 686 687 for (id, v) in view_data.iter_mut() { 688 if let Some(view) = session.views.get(*id) { 689 let transform = 690 Matrix4::from_translation( 691 (session.offset + view.offset).extend(*draw::VIEW_LAYER), 692 ) * Matrix4::from_nonuniform_scale(view.zoom, view.zoom, 1.0); 693 694 // Render views. 695 shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| { 696 let bound_view = pipeline 697 .bind_texture(v.layer.fb.color_slot()) 698 .expect("binding textures never fails"); 699 700 iface.set(&uni.ortho, ortho); 701 iface.set(&uni.transform, transform.into()); 702 iface.set(&uni.tex, bound_view.binding()); 703 704 rdr_gate.render(render_st, |mut tess_gate| { 705 tess_gate.render(&v.layer.tess) 706 })?; 707 708 // TODO: We only need to render this on the active view. 709 let staging_texture = v.staging_fb.color_slot(); 710 let bound_view_staging = pipeline 711 .bind_texture(staging_texture) 712 .expect("binding textures never fails"); 713 714 iface.set(&uni.tex, bound_view_staging.binding()); 715 rdr_gate.render(render_st, |mut tess_gate| { 716 tess_gate.render(&v.layer.tess) 717 })?; 718 719 Ok(()) 720 })?; 721 } 722 } 723 724 // Render UI. 725 shd_gate.shade(shape2d, |mut iface, uni, mut rdr_gate| { 726 iface.set(&uni.ortho, ortho); 727 iface.set(&uni.transform, identity); 728 729 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&ui_tess)) 730 })?; 731 732 // Render text, tool & view animations. 733 shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| { 734 iface.set(&uni.ortho, ortho); 735 iface.set(&uni.transform, identity); 736 737 // Render view animations. 738 if session.settings["animation"].is_set() { 739 for (id, v) in view_data.iter_mut() { 740 match (&v.anim_tess, session.views.get(*id)) { 741 (Some(tess), Some(view)) if view.animation.len() > 1 => { 742 let bound_layer = pipeline 743 .bind_texture(v.layer.fb.color_slot()) 744 .expect("binding textures never fails"); 745 let t = Matrix4::from_translation( 746 Vector2::new(0., view.zoom).extend(0.), 747 ); 748 749 // Render layer animation. 750 iface.set(&uni.tex, bound_layer.binding()); 751 iface.set(&uni.transform, t.into()); 752 rdr_gate.render(render_st, |mut tess_gate| { 753 tess_gate.render(tess) 754 })?; 755 } 756 _ => (), 757 } 758 } 759 } 760 761 { 762 let bound_font = pipeline 763 .bind_texture(font) 764 .expect("binding textures never fails"); 765 iface.set(&uni.tex, bound_font.binding()); 766 iface.set(&uni.transform, identity); 767 768 // Render text. 769 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&text_tess))?; 770 } 771 { 772 let bound_tool = pipeline 773 .bind_texture(cursors) 774 .expect("binding textures never fails"); 775 iface.set(&uni.tex, bound_tool.binding()); 776 777 // Render tool. 778 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&tool_tess))?; 779 } 780 Ok(()) 781 })?; 782 783 // Render help. 784 if let Some((win_tess, text_tess)) = help_tess { 785 shd_gate.shade(shape2d, |_iface, _uni, mut rdr_gate| { 786 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&win_tess)) 787 })?; 788 shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| { 789 let bound_font = pipeline 790 .bind_texture(font) 791 .expect("binding textures never fails"); 792 793 iface.set(&uni.tex, bound_font.binding()); 794 iface.set(&uni.ortho, ortho); 795 iface.set(&uni.transform, identity); 796 797 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&text_tess)) 798 })?; 799 } 800 Ok(()) 801 }, 802 ); 803 804 // Render to back buffer. 805 builder.pipeline::<PipelineError, _, _, _, _>( 806 present_fb, 807 pipeline_st, 808 |pipeline, mut shd_gate| { 809 // Render screen framebuffer. 810 let bound_screen = pipeline 811 .bind_texture(screen_fb.color_slot()) 812 .expect("binding textures never fails"); 813 shd_gate.shade(screen2d, |mut iface, uni, mut rdr_gate| { 814 iface.set(&uni.framebuffer, bound_screen.binding()); 815 816 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&screen_tess)) 817 })?; 818 819 if session.settings["debug"].is_set() || !execution.is_normal() { 820 let bound_font = pipeline 821 .bind_texture(font) 822 .expect("binding textures never fails"); 823 824 shd_gate.shade(sprite2d, |mut iface, uni, mut rdr_gate| { 825 iface.set(&uni.tex, bound_font.binding()); 826 iface.set( 827 &uni.ortho, 828 Matrix4::ortho(screen_w, screen_h, Origin::BottomLeft).into(), 829 ); 830 831 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&overlay_tess)) 832 })?; 833 } 834 835 // Render cursor. 836 let bound_cursors = pipeline 837 .bind_texture(cursors) 838 .expect("binding textures never fails"); 839 shd_gate.shade(cursor2d, |mut iface, uni, mut rdr_gate| { 840 let ui_scale = session.settings["scale"].to_f64(); 841 let pixel_ratio = platform::pixel_ratio(*scale_factor); 842 843 iface.set(&uni.cursor, bound_cursors.binding()); 844 iface.set(&uni.framebuffer, bound_screen.binding()); 845 iface.set(&uni.ortho, ortho); 846 iface.set(&uni.scale, (ui_scale * pixel_ratio) as f32); 847 848 rdr_gate.render(render_st, |mut tess_gate| tess_gate.render(&cursor_tess)) 849 }) 850 }, 851 ); 852 853 // If active view is dirty, record a snapshot of it. 854 if v.is_dirty() { 855 // FIXME: This is ugly. 856 let id = v.id; 857 let state = v.state; 858 let is_resized = v.is_resized(); 859 let extent = v.extent(); 860 861 if let Some(vr) = session.views.get_mut(id) { 862 let v_data = view_data.get_mut(&id).unwrap(); 863 864 match state { 865 ViewState::Dirty(_) if is_resized => { 866 vr.record_view_resized(v_data.layer.pixels(), extent); 867 } 868 ViewState::Dirty(_) => { 869 vr.record_view_painted(v_data.layer.pixels()); 870 } 871 ViewState::Okay | ViewState::Damaged(_) => {} 872 } 873 } 874 } 875 876 if !execution.is_normal() { 877 let texels = screen_fb 878 .color_slot() 879 .get_raw_texels() 880 .expect("binding textures never fails"); 881 let texels = Rgba8::align(&texels); 882 883 execution.record(texels).ok(); 884 } 885 886 Ok(()) 887 } 888 889 fn handle_scale_factor_changed(&mut self, scale_factor: f64) { 890 self.scale_factor = scale_factor; 891 self.handle_resized(self.win_size); 892 } 893 } 894 895 impl Renderer { 896 pub fn handle_resized(&mut self, size: platform::LogicalSize) { 897 let physical = size.to_physical(self.scale_factor); 898 899 self.present_fb = Framebuffer::back_buffer( 900 &mut self.ctx, 901 [physical.width as u32, physical.height as u32], 902 ) 903 .expect("binding textures never fails"); 904 905 self.win_size = size; 906 self.handle_session_scale_changed(self.scale); 907 } 908 909 pub fn handle_session_scale_changed(&mut self, scale: f64) { 910 self.scale = scale; 911 self.screen_fb = Framebuffer::new( 912 &mut self.ctx, 913 [ 914 (self.win_size.width / scale) as u32, 915 (self.win_size.height / scale) as u32, 916 ], 917 0, 918 self::SAMPLER, 919 ) 920 .unwrap(); 921 } 922 923 fn handle_effects( 924 &mut self, 925 mut effects: Vec<Effect>, 926 session: &Session, 927 ) -> Result<(), RendererError> { 928 for eff in effects.drain(..) { 929 match eff { 930 Effect::SessionResized(size) => { 931 self.handle_resized(size); 932 } 933 Effect::SessionScaled(scale) => { 934 self.handle_session_scale_changed(scale); 935 } 936 Effect::ViewActivated(_) => {} 937 Effect::ViewAdded(id) => { 938 // FIXME: This should be done when the view is added in the ViewManager. 939 if let Some((s, pixels)) = session.views.get_snapshot_safe(id) { 940 let (w, h) = (s.width(), s.height()); 941 942 self.view_data 943 .insert(id, ViewData::new(w, h, Some(pixels), &mut self.ctx)); 944 } 945 } 946 Effect::ViewRemoved(id) => { 947 self.view_data.remove(&id); 948 } 949 Effect::ViewOps(id, ops) => { 950 self.handle_view_ops(session.view(id), &ops)?; 951 } 952 Effect::ViewDamaged(id, Some(extent)) => { 953 self.handle_view_resized(session.view(id), extent.width(), extent.height())?; 954 } 955 Effect::ViewDamaged(id, None) => { 956 self.handle_view_damaged(session.view(id))?; 957 } 958 Effect::ViewBlendingChanged(blending) => { 959 self.blending = blending; 960 } 961 Effect::ViewPaintDraft(shapes) => { 962 shapes.into_iter().for_each(|s| self.staging_batch.add(s)); 963 } 964 Effect::ViewPaintFinal(shapes) => { 965 shapes.into_iter().for_each(|s| self.final_batch.add(s)); 966 } 967 Effect::ViewTouched(_) => {} 968 } 969 } 970 Ok(()) 971 } 972 973 fn handle_view_ops( 974 &mut self, 975 v: &View<ViewResource>, 976 ops: &[ViewOp], 977 ) -> Result<(), RendererError> { 978 use RendererError as Error; 979 980 for op in ops { 981 match op { 982 ViewOp::Resize(w, h) => { 983 self.resize_view(v, *w, *h)?; 984 } 985 ViewOp::Clear(color) => { 986 let view = self 987 .view_data 988 .get_mut(&v.id) 989 .expect("views must have associated view data"); 990 991 view.layer 992 .fb 993 .color_slot() 994 .clear(GenMipmaps::No, (color.r, color.g, color.b, color.a)) 995 .map_err(Error::Texture)?; 996 } 997 ViewOp::Blit(src, dst) => { 998 let view = self 999 .view_data 1000 .get_mut(&v.id) 1001 .expect("views must have associated view data"); 1002 1003 let (_, texels) = v.layer.get_snapshot_rect(&src.map(|n| n as i32)).unwrap(); // TODO: Handle this nicely? 1004 let texels = util::align_u8(&texels); 1005 1006 view.layer 1007 .fb 1008 .color_slot() 1009 .upload_part_raw( 1010 GenMipmaps::No, 1011 [dst.x1 as u32, dst.y1 as u32], 1012 [src.width() as u32, src.height() as u32], 1013 texels, 1014 ) 1015 .map_err(Error::Texture)?; 1016 } 1017 ViewOp::Yank(src) => { 1018 let (_, pixels) = v.layer.get_snapshot_rect(&src.map(|n| n)).unwrap(); 1019 let (w, h) = (src.width() as u32, src.height() as u32); 1020 let [paste_w, paste_h] = self.paste.size(); 1021 1022 if paste_w != w || paste_h != h { 1023 self.paste = Texture::new(&mut self.ctx, [w, h], 0, self::SAMPLER) 1024 .map_err(Error::Texture)?; 1025 } 1026 let body = util::align_u8(&pixels); 1027 1028 self.paste 1029 .upload_raw(GenMipmaps::No, body) 1030 .map_err(Error::Texture)?; 1031 } 1032 ViewOp::Flip(src, dir) => { 1033 let (_, mut pixels) = v.layer.get_snapshot_rect(&src.map(|n| n)).unwrap(); 1034 let (w, h) = (src.width() as u32, src.height() as u32); 1035 let [paste_w, paste_h] = self.paste.size(); 1036 1037 if paste_w != w || paste_h != h { 1038 self.paste = Texture::new(&mut self.ctx, [w, h], 0, self::SAMPLER) 1039 .map_err(Error::Texture)?; 1040 } 1041 1042 match dir { 1043 Axis::Vertical => { 1044 let len = pixels.len(); 1045 1046 let (front, back) = pixels.split_at_mut(len / 2); 1047 for (front_row, back_row) in front 1048 .chunks_exact_mut(w as usize) 1049 .zip(back.rchunks_exact_mut(w as usize)) 1050 { 1051 front_row.swap_with_slice(back_row); 1052 } 1053 } 1054 Axis::Horizontal => { 1055 pixels 1056 .chunks_exact_mut(w as usize) 1057 .for_each(|row| row.reverse()); 1058 } 1059 } 1060 1061 let body = util::align_u8(&pixels); 1062 1063 self.paste 1064 .upload_raw(GenMipmaps::No, body) 1065 .map_err(Error::Texture)?; 1066 } 1067 ViewOp::Paste(dst) => { 1068 let [paste_w, paste_h] = self.paste.size(); 1069 let batch = sprite2d::Batch::singleton( 1070 paste_w, 1071 paste_h, 1072 Rect::origin(paste_w as f32, paste_h as f32), 1073 dst.map(|n| n as f32), 1074 ZDepth::default(), 1075 Rgba::TRANSPARENT, 1076 1., 1077 Repeat::default(), 1078 ); 1079 1080 self.paste_outputs.push( 1081 self.ctx 1082 .tessellation::<_, Sprite2dVertex>(batch.vertices().as_slice()), 1083 ); 1084 } 1085 ViewOp::SetPixel(rgba, x, y) => { 1086 let fb = &mut self 1087 .view_data 1088 .get_mut(&v.id) 1089 .expect("views must have associated view data") 1090 .layer 1091 .fb; 1092 let texels = &[*rgba]; 1093 let texels = util::align_u8(texels); 1094 fb.color_slot() 1095 .upload_part_raw(GenMipmaps::No, [*x as u32, *y as u32], [1, 1], texels) 1096 .map_err(Error::Texture)?; 1097 } 1098 } 1099 } 1100 Ok(()) 1101 } 1102 1103 fn handle_view_damaged(&mut self, view: &View<ViewResource>) -> Result<(), RendererError> { 1104 let layer = &mut self 1105 .view_data 1106 .get_mut(&view.id) 1107 .expect("views must have associated view data") 1108 .layer; 1109 1110 let (_, pixels) = view.layer.current_snapshot(); 1111 1112 layer.clear()?; 1113 layer.upload(util::align_u8(pixels))?; 1114 1115 Ok(()) 1116 } 1117 1118 fn handle_view_resized( 1119 &mut self, 1120 view: &View<ViewResource>, 1121 vw: u32, 1122 vh: u32, 1123 ) -> Result<(), RendererError> { 1124 self.resize_view(view, vw, vh) 1125 } 1126 1127 fn resize_view( 1128 &mut self, 1129 view: &View<ViewResource>, 1130 vw: u32, 1131 vh: u32, 1132 ) -> Result<(), RendererError> { 1133 // View size changed. Re-create view resources. 1134 let (ew, eh) = { 1135 let extent = view.resource.extent; 1136 (extent.width(), extent.height()) 1137 }; 1138 1139 // Ensure not to transfer more data than can fit in the view buffer. 1140 let tw = u32::min(ew, vw); 1141 let th = u32::min(eh, vh); 1142 1143 let mut view_data = ViewData::new(vw, vh, None, &mut self.ctx); 1144 let trect = Rect::origin(tw as i32, th as i32); 1145 // The following sequence of commands will try to copy a rect that isn't contained 1146 // in the snapshot, hence we must skip the uploading in that case: 1147 // 1148 // :f/add 1149 // :f/remove 1150 // :undo 1151 // 1152 if let Some((_, texels)) = view.layer.get_snapshot_rect(&trect) { 1153 let texels = util::align_u8(&texels); 1154 let l = &mut view_data.layer; 1155 1156 l.upload_part([0, vh - th], [tw, th], texels)?; 1157 } 1158 1159 self.view_data.insert(view.id, view_data); 1160 1161 Ok(()) 1162 } 1163 1164 fn update_view_animations(&mut self, s: &Session) { 1165 if !s.settings["animation"].is_set() { 1166 return; 1167 } 1168 // TODO: Does this need to run if the view has only one frame? 1169 for v in s.views.iter() { 1170 // FIXME: When `v.animation.val()` doesn't change, we don't need 1171 // to re-create the buffer. 1172 let batch = draw::draw_view_animation(s, v); 1173 1174 if let Some(vd) = self.view_data.get_mut(&v.id) { 1175 vd.anim_tess = Some( 1176 self.ctx 1177 .tessellation::<_, Sprite2dVertex>(batch.vertices().as_slice()), 1178 ); 1179 } 1180 } 1181 } 1182 1183 fn update_view_composites(&mut self, s: &Session) { 1184 for v in s.views.iter() { 1185 let batch = draw::draw_view_composites(s, v); 1186 1187 if let Some(vd) = self.view_data.get_mut(&v.id) { 1188 vd.layer_tess = Some( 1189 self.ctx 1190 .tessellation::<_, Sprite2dVertex>(batch.vertices().as_slice()), 1191 ); 1192 } 1193 } 1194 } 1195 } 1196 1197 fn text_batch([w, h]: [u32; 2]) -> TextBatch { 1198 TextBatch::new(w, h, draw::GLYPH_WIDTH, draw::GLYPH_HEIGHT) 1199 }