parent
2ba4777443
commit
4c0268997c
@ -0,0 +1,366 @@
|
|||||||
|
//! `NcVisual*` methods and associated functions.
|
||||||
|
|
||||||
|
use core::ptr::null_mut;
|
||||||
|
use libc::c_void;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
// cstring, error, error_ref_mut, rstring, NcBlitter, NcDim, NcError, NcIntResult, NcPixel,
|
||||||
|
// NcPlane, NcResult, NcRgba, NcScale, NcTime, NcVisual, NcVisualOptions, Notcurses, NCBLIT_PIXEL,
|
||||||
|
// NCRESULT_ERR,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// # NcVisualOptions Constructors
|
||||||
|
impl NcSubprocOptions {
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn new(
|
||||||
|
curry: *mut c_void,
|
||||||
|
restart_period: u64,
|
||||||
|
// flags: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
curry:,
|
||||||
|
// restart this many seconds after an exit (watch)
|
||||||
|
restart_period,
|
||||||
|
// bitfield over NCOPTION_SUBPROC_* (none yet)
|
||||||
|
flags: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # NcSubproc Constructors & Destructors
|
||||||
|
impl NcSubproc {
|
||||||
|
/// Opens a visual at `file`, extracts the codec and parameters and
|
||||||
|
/// decodes the first image to memory.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_from_file()][crate::ncvisual_from_file].*
|
||||||
|
pub fn new<'a>(file: &str) -> NcResult<&'a mut NcVisual> {
|
||||||
|
error_ref_mut![
|
||||||
|
unsafe { crate::ncvisual_from_file(cstring![file]) },
|
||||||
|
&format!("NcVisual::from_file()")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Promotes an NcPlane to an NcVisual.
|
||||||
|
///
|
||||||
|
/// The plane may contain only spaces, half blocks, and full blocks.
|
||||||
|
/// This will be checked, and any other glyph will result in an error.
|
||||||
|
///
|
||||||
|
/// This function exists so that planes can be subjected to NcVisual transformations.
|
||||||
|
/// If possible, it's better to create the ncvisual from memory using
|
||||||
|
/// [from_rgba][NcVisual#method.from_rgba].
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_from_plane()][crate::ncvisual_from_plane].*
|
||||||
|
pub fn from_plane<'a>(
|
||||||
|
plane: &NcPlane,
|
||||||
|
blitter: NcBlitter,
|
||||||
|
beg_y: NcDim,
|
||||||
|
beg_x: NcDim,
|
||||||
|
len_y: NcDim,
|
||||||
|
len_x: NcDim,
|
||||||
|
) -> NcResult<&'a mut NcVisual> {
|
||||||
|
error_ref_mut![
|
||||||
|
unsafe {
|
||||||
|
crate::ncvisual_from_plane(
|
||||||
|
plane,
|
||||||
|
blitter,
|
||||||
|
beg_y as i32,
|
||||||
|
beg_x as i32,
|
||||||
|
len_y as i32,
|
||||||
|
len_x as i32,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
&format!("NcVisual::from_file()")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepares an NcVisual, and its underlying NcPlane, based off RGBA content
|
||||||
|
/// in memory at `rgba`.
|
||||||
|
///
|
||||||
|
/// `rgba` is laid out as `rows` lines, each of which is `rowstride` bytes in length.
|
||||||
|
/// Each line has `cols` 32-bit 8bpc RGBA pixels followed by possible padding
|
||||||
|
/// (there will be rowstride - cols * 4 bytes of padding).
|
||||||
|
///
|
||||||
|
/// The total size of `rgba` is thus (rows * rowstride) bytes, of which
|
||||||
|
/// (rows * cols * 4) bytes are actual non-padding data.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_from_rgba()][crate::ncvisual_from_rgba].*
|
||||||
|
pub fn from_rgba<'a>(
|
||||||
|
rgba: &[u8],
|
||||||
|
rows: NcDim,
|
||||||
|
rowstride: NcDim,
|
||||||
|
cols: NcDim,
|
||||||
|
) -> NcResult<&'a mut NcVisual> {
|
||||||
|
error_ref_mut![
|
||||||
|
unsafe {
|
||||||
|
crate::ncvisual_from_rgba(
|
||||||
|
rgba.as_ptr() as *const c_void,
|
||||||
|
rows as i32,
|
||||||
|
rowstride as i32,
|
||||||
|
cols as i32,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
&format!("NcVisual::from_rgba()")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys this NcVisual.
|
||||||
|
///
|
||||||
|
/// Rendered elements will not be disrupted, but the visual can be neither
|
||||||
|
/// decoded nor rendered any further.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_destroy()][crate::ncvisual_destroy].*
|
||||||
|
pub fn destroy(&mut self) {
|
||||||
|
unsafe { crate::ncvisual_destroy(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # NcVisual Methods
|
||||||
|
impl NcVisual {
|
||||||
|
/// Gets the specified pixel from this NcVisual.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_at_yx()][crate::ncvisual_at_yx].*
|
||||||
|
pub fn at_yx(&self, y: NcDim, x: NcDim) -> NcResult<NcPixel> {
|
||||||
|
let mut pixel = 0;
|
||||||
|
let res = unsafe { crate::ncvisual_at_yx(self, y as i32, x as i32, &mut pixel) };
|
||||||
|
error![res, "NcVisual.at_yx()", pixel]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the next frame from the NcVisual.
|
||||||
|
///
|
||||||
|
/// Returns 0 for normal frames, and 1 to indicate EOF.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_decode()][crate::ncvisual_decode].*
|
||||||
|
pub fn decode(&mut self) -> NcResult<NcIntResult> {
|
||||||
|
let res = unsafe { crate::ncvisual_decode(self) };
|
||||||
|
if res == NCRESULT_ERR {
|
||||||
|
return Err(NcError::with_msg(res, "NcVisual.decode()"));
|
||||||
|
} else {
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the next frame from the NcVisual, ala [decode][NcVisual#method.decode],
|
||||||
|
/// but if we have reached the end, rewinds to the first frame.
|
||||||
|
///
|
||||||
|
/// *A subsequent [NcVisual.render]() will render the first frame,
|
||||||
|
/// as if the ncvisual had been closed and reopened.*
|
||||||
|
///
|
||||||
|
/// Returns 0 for normal frames and 1 to indicate EOF.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_decode_loop()][crate::ncvisual_decode_loop].*
|
||||||
|
pub fn decode_loop(&mut self) -> NcResult<NcIntResult> {
|
||||||
|
let res = unsafe { crate::ncvisual_decode_loop(self) };
|
||||||
|
if res == NCRESULT_ERR {
|
||||||
|
return Err(NcError::with_msg(res, "NcVisual.decode_loop()"));
|
||||||
|
} else {
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inflates each pixel in the image to 'scale'x'scale' pixels.
|
||||||
|
///
|
||||||
|
/// The original color is retained.
|
||||||
|
pub fn inflate(&mut self, scale: u32) -> NcResult<NcIntResult> {
|
||||||
|
let res = unsafe { crate::ncvisual_inflate(self, scale as i32) };
|
||||||
|
error![res, &format!["NcVisual.inflate({})", scale], res]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the size and ratio of NcVisual pixels to output cells along the
|
||||||
|
/// `y→to_y` and `x→to_x` axes.
|
||||||
|
///
|
||||||
|
/// Returns a tuple with (y, x, to_y, to_x)
|
||||||
|
///
|
||||||
|
/// An NcVisual of `y` by `x` pixels will require
|
||||||
|
/// (`y` * `to_y`) by (`x` * `to_x`) cells for full output.
|
||||||
|
///
|
||||||
|
/// Errors on invalid blitter in `options`. Scaling is taken into consideration.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_blitter_geom()][crate::ncvisual_blitter_geom].*
|
||||||
|
pub fn geom(
|
||||||
|
&self,
|
||||||
|
nc: &Notcurses,
|
||||||
|
options: &NcVisualOptions,
|
||||||
|
) -> NcResult<(NcDim, NcDim, NcDim, NcDim)> {
|
||||||
|
let mut y = 0;
|
||||||
|
let mut x = 0;
|
||||||
|
let mut to_y = 0;
|
||||||
|
let mut to_x = 0;
|
||||||
|
|
||||||
|
let res = unsafe {
|
||||||
|
crate::ncvisual_blitter_geom(
|
||||||
|
nc,
|
||||||
|
self,
|
||||||
|
options,
|
||||||
|
&mut y,
|
||||||
|
&mut x,
|
||||||
|
&mut to_y,
|
||||||
|
&mut to_x,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
error![
|
||||||
|
res,
|
||||||
|
"NcVisual.geom()",
|
||||||
|
(y as NcDim, x as NcDim, to_y as NcDim, to_x as NcDim)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the default media (not plot) blitter for this environment when using
|
||||||
|
/// the specified scaling method.
|
||||||
|
///
|
||||||
|
/// Currently, this means:
|
||||||
|
/// - if lacking UTF-8, NCBLIT_1x1.
|
||||||
|
/// - otherwise, if not NCSCALE_STRETCH, NCBLIT_2x1.
|
||||||
|
/// - otherwise, if sextants are not known to be good, NCBLIT_2x2.
|
||||||
|
/// - otherwise NCBLIT_3x2 NCBLIT_2x2 and NCBLIT_3x2 both distort the original
|
||||||
|
/// aspect ratio, thus NCBLIT_2x1 is used outside of NCSCALE_STRETCH.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_media_defblitter()][crate::ncvisual_media_defblitter].*
|
||||||
|
pub fn media_defblitter(nc: &Notcurses, scale: NcScale) -> NcBlitter {
|
||||||
|
unsafe { crate::ncvisual_media_defblitter(nc, scale) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Polyfills at the specified location using `rgba`.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_polyfill_yx()][crate::ncvisual_polyfill_yx].*
|
||||||
|
pub fn polyfill_yx(&mut self, y: NcDim, x: NcDim, rgba: NcRgba) -> NcResult<()> {
|
||||||
|
error![
|
||||||
|
unsafe { crate::ncvisual_polyfill_yx(self, y as i32, x as i32, rgba) },
|
||||||
|
&format!["NcVisual.polyfill_yx({}, {}, {})", y, x, rgba]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Renders the decoded frame to the specified [NcPlane].
|
||||||
|
///
|
||||||
|
/// See [`NcVisualOptions`].
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_render()][crate::ncvisual_render].*
|
||||||
|
pub fn render(
|
||||||
|
&mut self,
|
||||||
|
nc: &mut Notcurses,
|
||||||
|
options: &NcVisualOptions,
|
||||||
|
) -> NcResult<&mut NcPlane> {
|
||||||
|
error_ref_mut![
|
||||||
|
unsafe { crate::ncvisual_render(nc, self, options) },
|
||||||
|
"NcVisual.render()"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resizes the visual to `rows` X `columns` pixels.
|
||||||
|
///
|
||||||
|
/// This is a lossy transformation, unless the size is unchanged.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_resize()][crate::ncvisual_resize].*
|
||||||
|
pub fn resize(&mut self, rows: NcDim, cols: NcDim) -> NcResult<()> {
|
||||||
|
error![
|
||||||
|
unsafe { crate::ncvisual_resize(self, rows as i32, cols as i32) },
|
||||||
|
&format!["NcVisual.resize({}, {})", rows, cols]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rotates the visual `rads` radians.
|
||||||
|
///
|
||||||
|
/// Only M_PI/2 and -M_PI/2 are supported at the moment,
|
||||||
|
/// but this will change. (FIXME)
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_rotate()][crate::ncvisual_rotate].*
|
||||||
|
pub fn rotate(&mut self, rads: f64) -> NcResult<()> {
|
||||||
|
error![
|
||||||
|
unsafe { crate::ncvisual_rotate(self, rads) },
|
||||||
|
&format!["NcVisual.rotate({})", rads]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the specified pixel.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_set_yx()][crate::ncvisual_set_yx].*
|
||||||
|
pub fn set_yx(&mut self, y: NcDim, x: NcDim, pixel: NcPixel) -> NcResult<()> {
|
||||||
|
error![
|
||||||
|
unsafe { crate::ncvisual_set_yx(self, y as i32, x as i32, pixel) },
|
||||||
|
&format!["NcVisual.set_yx({}, {}, {})", y, x, pixel]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Displays frames.
|
||||||
|
///
|
||||||
|
/// *Provide as an argument to ncvisual_stream().*
|
||||||
|
///
|
||||||
|
/// If you'd like subtitles to be decoded, provide an ncplane as the curry.
|
||||||
|
/// If the curry is NULL, subtitles will not be displayed.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_simple_streamer()][crate::ncvisual_simple_streamer].*
|
||||||
|
pub fn simple_streamer(
|
||||||
|
&mut self,
|
||||||
|
options: &mut NcVisualOptions,
|
||||||
|
time: &NcTime,
|
||||||
|
curry: Option<&mut NcPlane>,
|
||||||
|
) -> NcResult<()> {
|
||||||
|
if let Some(plane) = curry {
|
||||||
|
error![
|
||||||
|
unsafe {
|
||||||
|
crate::ncvisual_simple_streamer(
|
||||||
|
self,
|
||||||
|
options,
|
||||||
|
time,
|
||||||
|
plane as *mut _ as *mut libc::c_void,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
&format![
|
||||||
|
"NcVisual.simple_streamer({:?}, {:?}, ncplane)",
|
||||||
|
options, time
|
||||||
|
]
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
error![
|
||||||
|
unsafe { crate::ncvisual_simple_streamer(self, options, time, null_mut()) },
|
||||||
|
&format!["NcVisual.simple_streamer({:?}, {:?}, null)", options, time]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // TODO
|
||||||
|
//
|
||||||
|
// /// Streams the entirety of the media, according to its own timing.
|
||||||
|
// ///
|
||||||
|
// /// Blocking, obviously.
|
||||||
|
// ///
|
||||||
|
// /// If `streamer` is provided it will be called for each frame, and its return
|
||||||
|
// /// value handled as outlined for streamcb.
|
||||||
|
// /// If streamer() returns non-zero, the stream is aborted, and that value is
|
||||||
|
// /// returned. By convention, return a positive number to indicate intentional
|
||||||
|
// /// abort from within streamer().
|
||||||
|
// ///
|
||||||
|
// /// `timescale` allows the frame duration time to be scaled.
|
||||||
|
// /// For a visual naturally running at 30FPS, a 'timescale' of 0.1 will result
|
||||||
|
// /// in 300 FPS, and a `timescale` of 10 will result in 3 FPS.
|
||||||
|
// /// It is an error to supply `timescale` less than or equal to 0.
|
||||||
|
// ///
|
||||||
|
// /// *C style function: [ncvisual_streamer()][crate::ncvisual_streamer].*
|
||||||
|
// //
|
||||||
|
// // TODO: add streamcb
|
||||||
|
// // INFO: QUESTION: is curry also optional like in simple_streamer?
|
||||||
|
// //
|
||||||
|
// pub fn simple_streamer(
|
||||||
|
// &mut self,
|
||||||
|
// nc: &mut Notcurses,
|
||||||
|
// timescale: f32,
|
||||||
|
// //streamer: Option<streamcb>
|
||||||
|
// options: &NcVisualOptions,
|
||||||
|
// curry: Option<&mut NcPlane>,
|
||||||
|
// ) -> NcResult<()> {
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// If a subtitle ought be displayed at this time, returns a heap-allocated
|
||||||
|
/// copy of the UTF8 text.
|
||||||
|
///
|
||||||
|
/// *C style function: [ncvisual_subtitle()][crate::ncvisual_subtitle].*
|
||||||
|
pub fn subtitle(&self) -> NcResult<&str> {
|
||||||
|
let res = unsafe { crate::ncvisual_subtitle(self) };
|
||||||
|
if res != null_mut() {
|
||||||
|
return Ok(rstring![res]);
|
||||||
|
} else {
|
||||||
|
Err(NcError::with_msg(NCRESULT_ERR, "NcVisual.subtitle()"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue