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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! [![crates.io](https://img.shields.io/crates/v/euc.svg)](https://crates.io/crates/euc)
//! [![crates.io](https://docs.rs/euc/badge.svg)](https://docs.rs/euc)
//!
//! <img src="misc/example.png" alt="Utah teapot, rendered with Euc" width="100%"/>
//!
//! # Example
//! ```ignore
//! struct Example;
//!
//! impl Pipeline for Example {
//!     type Vertex = [f32; 2];
//!     type VsOut = ();
//!     type Pixel = [u8; 4];
//!
//!     // Vertex shader
//!     fn vert(&self, pos: &Self::Vertex) -> ([f32; 3], Self::VsOut) {
//!         ([pos[0], pos[1], 0.0], ())
//!     }
//!
//!     // Fragment shader
//!     fn frag(&self, _: &Self::VsOut) -> Self::Pixel {
//!         [255, 0, 0, 255] // Red
//!     }
//! }
//!
//! fn main() {
//!     let mut color = Buffer2d::new([640, 480], [0; 4]);

//!     Example.draw::<Triangles<(f32,)>, _>(
//!         &[
//!             [-1.0, -1.0],
//!             [ 1.0, -1.0],
//!             [ 0.0,  1.0],
//!         ],
//!         &mut color,
//!         None,
//!     );
//! }
//! ```

#![no_std]

#[macro_use]
extern crate alloc;

pub mod buffer;
pub mod interpolate;
pub mod rasterizer;

// Reexports
pub use self::interpolate::Interpolate;
pub use self::rasterizer::{DepthStrategy, Rasterizer};

/// Represents the high-level structure of a rendering pipeline.
///
/// Conventionally, uniform data is stores as state within the type itself.
///
/// This governs the following things:
///
/// - Vertex position and data calculation (computed by the vertex shader)
/// - Determining whether each polygon is 'backfacing', and optionally skipping it
/// - Rasterization (performed internally by `euc`)
/// - Comparing the fragment depth against the depth buffer to determine whether it is occluded,
///   and optionally skipping it
/// - Fragment output calculation (computed by the fragment shader)
///
/// In the future, `euc` may extend its capabilities to include compute, geometry, and tesselation
/// shaders.
pub trait Pipeline
where
    Self: Sized,
{
    /// The type of the vertex shader input data.
    ///
    /// This usually consists of the vertex's position, normal, colour, texture coordinates, and
    /// other such per-vertex information. When vertex indexing is used, this tends to consist of
    /// the vertex index.
    type Vertex;

    /// The type of the data that gets passed on from the vertex shader to the fragment shader.
    ///
    /// This usually consists of the fragment's normal, colour, texture coordinates and other such
    /// per-fragment information.
    type VsOut: Clone + Interpolate;

    /// The type of emitted pixels.
    ///
    /// This type is emitted by the fragment shader and usually corresponds to the colour of the
    /// pixel.
    type Pixel: Clone;

    /// The vertex shader
    fn vert(&self, vertex: &Self::Vertex) -> ([f32; 4], Self::VsOut);

    /// The fragment shader
    fn frag(&self, vs_out: &Self::VsOut) -> Self::Pixel;

    /// A method used to determine what depth buffer strategy should be used when determining
    /// fragment occlusion.
    ///
    /// This method will be called at minimum only once per draw call, but may be called an
    /// arbitrary number of times.
    #[inline(always)]
    fn get_depth_strategy(&self) -> DepthStrategy {
        DepthStrategy::IfLessWrite
    }

    /// Perform a draw call with the given uniform data, vertex array, output target and supplement
    /// type.
    ///
    /// The supplement type is commonly used to represent additional surfaces required by the
    /// rasterizer, such as a depth buffer target.
    fn draw<R: Rasterizer, T: Target<Item = Self::Pixel>>(
        &self,
        vertices: &[Self::Vertex],
        target: &mut T,
        supplement: <R as Rasterizer>::Supplement,
    ) {
        R::draw::<Self, T>(self, vertices, target, supplement)
    }
}

/// Represents a 2-dimensional rendering target that can have pixel data read and written to it.
pub trait Target {
    /// The type of items contained within this target.
    type Item: Clone;

    /// Get the dimensions of the target.
    fn size(&self) -> [usize; 2];

    /// Set the item at the specified location in the target to the given item. The validity of the
    /// location is not checked, and as such this method is marked `unsafe`.
    unsafe fn set(&mut self, pos: [usize; 2], item: Self::Item);

    /// Get a copy of the item at the specified location in the target. The validity of the
    /// location is not checked, and as such this method is marked `unsafe`.
    unsafe fn get(&self, pos: [usize; 2]) -> Self::Item;

    /// Clear the target with copies of the specified item.
    fn clear(&mut self, fill: Self::Item);
}

impl<T: Default + Clone> Target for (T,) {
    type Item = T;

    fn size(&self) -> [usize; 2] { [1; 2] }

    unsafe fn set(&mut self, pos: [usize; 2], item: Self::Item) {}

    unsafe fn get(&self, pos: [usize; 2]) -> Self::Item { Self::Item::default() }

    fn clear(&mut self, fill: Self::Item) {}

}