gl_capture/
lib.rs

1#![forbid(elided_lifetimes_in_paths)]
2#![cfg_attr(debug_assertions, allow(dead_code, unreachable_code))]
3
4pub use crate::image::prelude::*;
5pub use crate::pixel::prelude::*;
6
7mod image;
8mod pixel;
9
10use std::ffi::c_void;
11use std::mem;
12
13use gl::types::GLenum;
14
15pub type RgbaImageData = ImageData<Rgba>;
16pub type RgbImageData = ImageData<Rgb>;
17
18pub type BgraImageData = ImageData<Bgra>;
19pub type BgrImageData = ImageData<Bgr>;
20
21#[derive(PartialEq, Eq, Clone, Copy, Debug)]
22pub enum CaptureFormat {
23    Rgba,
24    Rgb,
25    Bgra,
26    Bgr,
27}
28
29impl CaptureFormat {
30    pub fn allocate_pixel_data(self, (w, h): (u32, u32)) -> Vec<u8> {
31        let size = (w as usize) * (h as usize) * self.channel_count();
32        vec![0; size]
33    }
34
35    pub const fn to_gl_format(self) -> GLenum {
36        match self {
37            Self::Rgba => gl::RGBA,
38            Self::Rgb => gl::RGB,
39            Self::Bgra => gl::BGRA,
40            Self::Bgr => gl::BGR,
41        }
42    }
43
44    pub const fn channel_count(self) -> usize {
45        match self {
46            Self::Rgba | Self::Bgra => 4,
47            Self::Rgb | Self::Bgr => 3,
48        }
49    }
50
51    /// Returns the pixel byte size of this capture format.
52    pub const fn pixel_size(self) -> usize {
53        match self {
54            Self::Rgba | Self::Bgra => mem::size_of::<[u8; 4]>(),
55            Self::Rgb | Self::Bgr => mem::size_of::<[u8; 3]>(),
56        }
57    }
58}
59
60pub unsafe fn capture() -> RgbImageData {
61    let mut viewport = [0; 4];
62    gl::GetIntegerv(gl::VIEWPORT, viewport.as_mut_ptr());
63
64    let size = (viewport[2] as u32, viewport[3] as u32);
65    let mut img = RgbImageData::new(size);
66    capture_into(&mut img);
67    img
68}
69
70pub unsafe fn capture_into<P>(img: &mut ImageData<P>)
71where
72    P: Pixel,
73{
74    read_pixels_ptr(
75        (0, 0),
76        img.size,
77        P::FORMAT,
78        img.data.as_mut_ptr() as *mut c_void,
79    );
80    img.flip_vertically();
81}
82
83/// Panics if the length of pixel `data`, is not
84/// at least `w * h * format.`[`byte_size()`](CaptureFormat::byte_size)
85pub unsafe fn read_pixels(
86    (x, y): (u32, u32),
87    (w, h): (u32, u32),
88    format: CaptureFormat,
89    data: &mut [u8],
90) {
91    assert!(w <= (i32::MAX as u32));
92    assert!(h <= (i32::MAX as u32));
93
94    let min_len = (w as usize) * (h as usize) * format.channel_count();
95    assert!(data.len() <= min_len);
96
97    read_pixels_ptr((x, y), (w, h), format, data.as_mut_ptr() as *mut c_void);
98}
99
100pub unsafe fn read_pixels_ptr(
101    (x, y): (u32, u32),
102    (w, h): (u32, u32),
103    format: CaptureFormat,
104    data: *mut c_void,
105) {
106    gl::PixelStorei(gl::PACK_ALIGNMENT, 1);
107    gl::ReadPixels(
108        x as i32,
109        y as i32,
110        w as i32,
111        h as i32,
112        format.to_gl_format(),
113        gl::UNSIGNED_BYTE,
114        data,
115    );
116}