ffgl_glium/
lib.rs

1//! Utilities for creating FFGL plugins using the glium library.
2//!
3//! Use [FFGLGlium] in your plugin to render frames with a glium context.
4//!
5//! Just call [FFGLGlium::draw] inside your [ffgl_core::handler::FFGLInstance::draw] method.
6//!
7//! See example-isf for a good example
8//!
9//!### !WARNING!
10//!
11//! I make assumptions about the OpenGL context inside the host. Bugs and crashes may occur. Testing infrastructure is required.
12//!
13use std::{error::Error, fmt::Formatter, rc::Rc};
14
15use ffgl_core::*;
16use glium::{
17    backend::Context,
18    framebuffer::{RenderBuffer, SimpleFrameBuffer},
19    BlitTarget, CapabilitiesSource, Frame, Surface, Texture2d,
20};
21use std::fmt::Debug;
22
23mod gl_backend;
24pub mod texture;
25pub mod validate_gl;
26
27///Use this struct to render frames with a glium context, making assumptions about the OpenGL context inside an FFGL host.
28pub struct FFGLGlium {
29    pub ctx: Rc<Context>,
30    backend: Rc<gl_backend::RawGlBackend>,
31}
32
33impl Debug for FFGLGlium {
34    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
35        f.debug_struct("FFGLGliumHandler").finish()
36    }
37}
38
39impl FFGLGlium {
40    pub fn new(inst_data: &FFGLData) -> Self {
41        let backend = Rc::new(gl_backend::RawGlBackend::new(inst_data.get_dimensions()));
42
43        tracing::debug!("BACKEND: {backend:?}");
44
45        let ctx = unsafe {
46            glium::backend::Context::new(
47                backend.clone(),
48                false,
49                glium::debug::DebugCallbackBehavior::Ignore,
50            )
51            .unwrap()
52        };
53
54        let valid_versions = &ctx.get_capabilities().supported_glsl_versions;
55
56        tracing::debug!("VALID VERSIONS: {valid_versions:?}");
57
58        tracing::debug!("OPENGL_VERSION {}", ctx.get_opengl_version_string());
59
60        Self { ctx, backend }
61    }
62
63    pub fn draw(
64        &self,
65        output_res: (u32, u32),
66        render_res: (u32, u32),
67        frame_data: GLInput<'_>,
68        render_frame: &mut impl FnMut(
69            &mut SimpleFrameBuffer,
70            Vec<Texture2d>,
71        ) -> Result<(), Box<dyn Error>>,
72    ) {
73        unsafe { self.ctx.rebuild(self.backend.clone()).unwrap() };
74
75        let frame = Frame::new(self.ctx.clone(), (render_res.0, render_res.1));
76        let rb = RenderBuffer::new(
77            &self.ctx,
78            glium::texture::UncompressedFloatFormat::U8U8U8U8,
79            render_res.0,
80            render_res.1,
81        )
82        .unwrap();
83
84        let fb = &mut SimpleFrameBuffer::new(&self.ctx, &rb).unwrap();
85
86        let textures: Vec<_> = frame_data
87            .textures
88            .iter()
89            .map(|texture_info| unsafe {
90                Texture2d::from_id(
91                    &self.ctx,
92                    glium::texture::UncompressedFloatFormat::U8U8U8U8,
93                    texture_info.Handle,
94                    false,
95                    glium::texture::MipmapsOption::NoMipmap,
96                    glium::texture::Dimensions::Texture2d {
97                        width: texture_info.Width,
98                        height: texture_info.Height,
99                    },
100                )
101            })
102            .collect();
103
104        if let Err(err) = render_frame(fb, textures) {
105            tracing::error!("Render ERROR: {err:?}");
106        }
107
108        // validate_viewport(&viewport);
109
110        //puts the texture into the framebuffer
111        fb.fill(&frame, glium::uniforms::MagnifySamplerFilter::Nearest);
112
113        // gl::BindFramebuffer(gl::READ_FRAMEBUFFER, 0);
114        unsafe {
115            gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, frame_data.host);
116            blit_fb(render_res, output_res);
117        }
118
119        frame.finish().unwrap();
120
121        //reset to what host expects
122        // gl_reset(frame_data);
123        // validate::validate_context_state();
124
125        // validate_viewport(&viewport);
126    }
127}
128
129unsafe fn blit_fb((read_w, read_h): (u32, u32), (write_w, write_h): (u32, u32)) {
130    let src_rect = BlitTarget {
131        left: 0,
132        bottom: 0,
133        width: read_w as i32,
134        height: read_h as i32,
135    };
136
137    let target_rect = BlitTarget {
138        left: 0 as u32,
139        bottom: 0 as u32,
140        width: write_w as i32,
141        height: write_h as i32,
142    };
143
144    gl::BlitFramebuffer(
145        src_rect.left as gl::types::GLint,
146        src_rect.bottom as gl::types::GLint,
147        (src_rect.left as i32 + src_rect.width) as gl::types::GLint,
148        (src_rect.bottom as i32 + src_rect.height) as gl::types::GLint,
149        (target_rect.left) as gl::types::GLint,
150        (target_rect.bottom) as gl::types::GLint,
151        (target_rect.left as i32 + target_rect.width) as gl::types::GLint,
152        (target_rect.bottom as i32 + target_rect.height) as gl::types::GLint,
153        gl::COLOR_BUFFER_BIT,
154        gl::NEAREST,
155    );
156}