1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
// Copyright 2017-2019 Matthew D. Michelotti // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Contains structs relating to application rendering. //! //! Rendering uses OpenGL shaders designed specifically for 2D pixel art, //! looking crisp at any scale or rotation. use std::marker::PhantomData; use crate::asset_id::{AppAssetId, IdU16}; use super::geom::Affine; use super::render_buffer::RenderBuffer; use super::core_renderer::CoreRenderer; /// Contains methods for rendering visuals to screen. /// /// The renderer origin is the bottom-left of the screen, with +X meaning "right" and +Y meaning "up". /// The dimensions of the screen in renderer units ("app pixels") are `AppContext.dims()`. /// The default scaling of each image is such that one source image pixel equals one "app pixel". /// /// This struct has functions for entering different rendering "modes". /// Switching between different modes (or the same mode with different parameters) /// can be expensive, since it involves flushing graphics data and switching shaders, /// so try to minimize these switches. /// /// Note: due to recent refactorings, there is currently only one render mode, the "sprite mode". /// This will likely change in the near future. pub struct Renderer<A: AppAssetId> { b: RenderBuffer, c: CoreRenderer, phantom: PhantomData<A> } impl<A: AppAssetId> Renderer<A> { pub(crate) fn new(buffer: RenderBuffer, core_renderer: CoreRenderer) -> Renderer<A> { let mut result = Renderer { b: buffer, c: core_renderer, phantom: PhantomData }; result.set_scissor(); result } /// Clears the screen with the given `color` in rgb (red-green-blue) format. pub fn clear(&mut self, color: (u8, u8, u8)) { self.b.flush(&mut self.c); self.c.clear(color); } /// Enters "sprite mode", for rendering sprites. pub fn sprite_mode(&mut self) -> SpriteRenderer<A> { SpriteRenderer { r: self } } pub(crate) fn app_dims(&self) -> (f64, f64) { self.b.dims.dims } pub(crate) fn native_px(&self) -> f64 { 1. / self.b.dims.pixel_scalar } pub(crate) fn to_app_pos(&self, raw_x: i32, raw_y: i32) -> (f64, f64) { self.b.dims.to_app_pos(raw_x, raw_y) } pub(crate) fn flush(&mut self) { self.b.flush(&mut self.c); } pub(crate) fn set_screen_dims(&mut self, dims: (u32, u32)) { if dims != self.b.dims.native_dims { self.b.dims.set_native_dims(dims); self.set_scissor(); } } fn set_scissor(&mut self) { let dims = &self.b.dims; self.c.set_scissor( dims.native_pre_pad.0, dims.native_pre_pad.1, dims.used_native_dims.0, dims.used_native_dims.1, ); } } /// A rendering mode for sprites. pub struct SpriteRenderer<'a, A: AppAssetId + 'a> { r: &'a mut Renderer<A>, } impl<'a, A: AppAssetId + 'a> SpriteRenderer<'a, A> { /// Draws the given `sprite` using the given `affine` transformation from the origin. pub fn draw(&mut self, affine: &Affine, sprite: A::Sprite) { self.draw_flash(affine, sprite, 0.); } /// Draws the given `sprite` blended with the color white using the given `affine` transformation from the origin. /// /// `flash_ratio`, capped between `0.0` and `1.0`, controls how much blending occurs with the /// color white (`0.0` means use the image unaltered, `1.0` means use white completely). pub fn draw_flash(&mut self, affine: &Affine, sprite: A::Sprite, flash_ratio: f64) { self.r.b.append_sprite(&mut self.r.c, affine, sprite.id_u16(), flash_ratio); } }