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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
//! `NcBlitter`

// functions already exported by bindgen: 4
// ------------------------------------------
// (#) test:  0
// (W) wrap: 4
// ------------------------------------------
//W+ ncblit_bgrx
//W+ ncblit_rgb_loose
//W+ ncblit_rgb_packed
//W+ ncblit_rgba

mod methods;

/// The blitter mode to use for rasterizing an [`NcVisual`][crate::NcVisual].
///
/// We never blit full blocks, but instead spaces (more efficient) with the
/// background set to the desired foreground.
///
/// # Default
/// *[`NcBlitter::Default`]*
///
/// # Degradation
///
/// There is a mechanism of graceful degradation, that works as follows:
/// - without braille support, [`Braille`] decays to [`Sextant`].
/// - without bitmap support, [`Pixel`] decays to [`Sextant`].
/// - without sextant support, [`Sextant`] decays to [`Quadrant`].
/// - without quadrant support, [`Quadrant`] decays to [`Half`].
/// - the only viable blitters in ASCII are [`Ascii`] and [`Pixel`].
///
/// If you don't want this behaviour you have to set the
/// *[`NcVisualFlag::NoDegrade`]* on [`NcVisualOptions`] or call
/// *[`degrade(false)`]* on [`NcVisualOptionsBuilder`].
///
/// [`Braille`]: NcBlitter::Braille
/// [`Pixel`]: NcBlitter::Pixel
/// [`Ascii`]: NcBlitter::Ascii
/// [`Half`]: NcBlitter::Half
/// [`Quadrant`]: NcBlitter::Quadrant
/// [`Sextant`]: NcBlitter::Sextant
/// [`NcVisualFlag::noDegrade`]: crate::NcVisualFlag#associatedconstant.noDegrade
/// [`NcVisualOptions`]: crate::NcVisualOptions
/// [`degrade(false)`]: crate::NcVisualOptionsBuilder#method.degrade
/// [`NcVisualOptionsBuilder`]: crate::NcVisualOptionsBuilder
#[repr(u32)]
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum NcBlitter {
    Default = c_api::NCBLIT_DEFAULT,

    /// Blitter mode using only spaces, compatible with ASCII (1x1).
    Ascii = c_api::NCBLIT_1x1,

    /// Blitter mode using halves + `Ascii` (2x1).
    /// ▄▀
    Half = c_api::NCBLIT_2x1,

    /// Blitter mode using quadrants + `Half` (2x2).
    /// ▗▐ ▖▀▟▌▙
    Quadrant = c_api::NCBLIT_2x2,

    /// Blitter mode using sextants + `Quadrant` (3x2).
    /// 🬀🬁🬂🬃🬄🬅🬆🬇🬈🬉🬊🬋🬌🬍🬎🬏🬐🬑🬒🬓🬔🬕🬖🬗🬘🬙🬚🬛🬜🬝🬞🬟🬠🬡🬢🬣🬤🬥🬦🬧🬨🬩🬪🬫🬬🬭🬮🬯🬰🬱🬲🬳🬴🬵🬶🬷🬸🬹🬺🬻
    Sextant = c_api::NCBLIT_3x2,

    /// Blitter mode using braille (4x2).
    /// ⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿
    Braille = c_api::NCBLIT_BRAILLE,

    /// Blitter mode using Pixels/Sixels.
    Pixel = c_api::NCBLIT_PIXEL,

    /// NcBlitter mode using: four vertical levels (4x1).
    /// █▆▄▂
    _4x1 = c_api::NCBLIT_4x1,

    /// NcBlitter mode using: eight vertical levels (8x1).
    /// █▇▆▅▄▃▂▁
    _8x1 = c_api::NCBLIT_8x1,
}

/// # Aliases
impl NcBlitter {
    pub const _1x1: NcBlitter = NcBlitter::Ascii;
    pub const _2x1: NcBlitter = NcBlitter::Half;
    pub const _2x2: NcBlitter = NcBlitter::Quadrant;
    pub const _3x2: NcBlitter = NcBlitter::Sextant;
}

mod std_impls {
    use super::{c_api, NcBlitter};
    use std::fmt;

    impl Default for NcBlitter {
        fn default() -> Self {
            Self::Default
        }
    }

    impl fmt::Display for NcBlitter {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            use NcBlitter::*;
            write!(
                f,
                "{}",
                match self {
                    Default => "Default",
                    Ascii => "Ascii",
                    Half => "Half",
                    Quadrant => "Quadrant",
                    Sextant => "Sextant",
                    Braille => "Braille",
                    Pixel => "Pixel",
                    _4x1 => "4x1",
                    _8x1 => "8x1",
                }
            )
        }
    }

    impl fmt::Debug for NcBlitter {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "NcBlitter::{}", self)
        }
    }

    impl From<c_api::NcBlitter_u32> for NcBlitter {
        fn from(blitter: c_api::NcBlitter_u32) -> Self {
            use {c_api::*, NcBlitter::*};
            match blitter {
                NCBLIT_DEFAULT => Default,
                NCBLIT_1x1 => Ascii,
                NCBLIT_2x1 => Half,
                NCBLIT_2x2 => Quadrant,
                NCBLIT_3x2 => Sextant,
                NCBLIT_BRAILLE => Braille,
                NCBLIT_PIXEL => Pixel,
                NCBLIT_4x1 => _4x1,
                NCBLIT_8x1 => _8x1,
                _ => Self::default(),
            }
        }
    }

    impl From<NcBlitter> for c_api::NcBlitter_u32 {
        fn from(blitter: NcBlitter) -> Self {
            use {c_api::*, NcBlitter::*};
            match blitter {
                Default => NCBLIT_DEFAULT,
                Ascii => NCBLIT_1x1,
                Half => NCBLIT_2x1,
                Quadrant => NCBLIT_2x2,
                Sextant => NCBLIT_3x2,
                Braille => NCBLIT_BRAILLE,
                Pixel => NCBLIT_PIXEL,
                _4x1 => NCBLIT_4x1,
                _8x1 => NCBLIT_8x1,
            }
        }
    }
}

pub(crate) mod c_api {
    use crate::c_api::ffi;

    /// The blitter mode to use for rasterizing an [`NcVisual`][crate::NcVisual].
    ///
    /// It's recommended to use [`NcBlitter`][crate::NcBlitter] instead.
    ///
    /// # Associated `c_api` constants
    ///
    /// - [`NCBLIT_DEFAULT`]
    /// - [`NCBLIT_1x1`]
    /// - [`NCBLIT_2x1`]
    /// - [`NCBLIT_2x2`]
    /// - [`NCBLIT_3x2`]
    /// - [`NCBLIT_4x1`]
    /// - [`NCBLIT_8x1`]
    /// - [`NCBLIT_BRAILLE`]
    /// - [`NCBLIT_PIXEL`]
    pub type NcBlitter_u32 = ffi::ncblitter_e;

    /// [`NcBlitter_u32`] mode where the blitter is automatically chosen.
    pub const NCBLIT_DEFAULT: NcBlitter_u32 = ffi::ncblitter_e_NCBLIT_DEFAULT;
    /// [`NcBlitter_u32`] mode using: space, compatible with ASCII.
    pub const NCBLIT_1x1: NcBlitter_u32 = ffi::ncblitter_e_NCBLIT_1x1;
    /// [`NcBlitter_u32`] mode using: halves + 1x1 (space).
    /// ▄▀
    pub const NCBLIT_2x1: NcBlitter_u32 = ffi::ncblitter_e_NCBLIT_2x1;
    /// [`NcBlitter_u32`] mode using: quadrants + 2x1.
    /// ▗▐ ▖▀▟▌▙
    pub const NCBLIT_2x2: NcBlitter_u32 = ffi::ncblitter_e_NCBLIT_2x2;
    /// [`NcBlitter_u32`] mode using: sextants.
    /// 🬀🬁🬂🬃🬄🬅🬆🬇🬈🬉🬊🬋🬌🬍🬎🬏🬐🬑🬒🬓🬔🬕🬖🬗🬘🬙🬚🬛🬜🬝🬞🬟🬠🬡🬢🬣🬤🬥🬦🬧🬨🬩🬪🬫🬬🬭🬮🬯🬰🬱🬲🬳🬴🬵🬶🬷🬸🬹🬺🬻
    pub const NCBLIT_3x2: NcBlitter_u32 = ffi::ncblitter_e_NCBLIT_3x2;
    /// [`NcBlitter_u32`] mode using: four vertical levels.
    /// █▆▄▂
    pub const NCBLIT_4x1: NcBlitter_u32 = ffi::ncblitter_e_NCBLIT_4x1;
    /// [`NcBlitter_u32`] mode using: eight vertical levels.
    /// █▇▆▅▄▃▂▁
    pub const NCBLIT_8x1: NcBlitter_u32 = ffi::ncblitter_e_NCBLIT_8x1;
    /// [`NcBlitter_u32`] mode using: 4 rows, 2 cols (braille).
    /// ⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿
    pub const NCBLIT_BRAILLE: NcBlitter_u32 = ffi::ncblitter_e_NCBLIT_BRAILLE;
    /// Sixel/Pixel mode.
    ///
    /// See [Sixel in Wikipedia](https://en.wikipedia.org/wiki/Sixel).
    pub const NCBLIT_PIXEL: NcBlitter_u32 = ffi::ncblitter_e_NCBLIT_PIXEL;
}