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
use super::offscreen_trait::*;
use crate::action::*;
use crate::gl_renderer::*;
use gl;
use std::ffi::{c_void};
///
/// An offscreen renderer that uses OpenGL (whichever variety is initialised)
///
pub struct OpenGlOffscreenRenderer {
/// The width of the main render target
width: usize,
/// The height of the main render target
height: usize,
/// The render target that the result is rendered to
main_render_target: RenderTarget,
/// The renderer, as it is set up for the current render target
renderer: GlRenderer
}
impl OpenGlOffscreenRenderer {
///
/// Creates a new OpenGL offscreen renderer with a texture of the specified size
///
pub fn new(width: usize, height: usize) -> OpenGlOffscreenRenderer {
// Create the main render target
let main_render_target = RenderTarget::new(width as u16, height as u16, RenderTargetType::Standard);
// Set up the renderer to render to this target
let renderer = GlRenderer::new();
// Generate the offscreen renderer
OpenGlOffscreenRenderer {
width: width,
height: height,
main_render_target: main_render_target,
renderer: renderer
}
}
}
impl OffscreenRenderTarget for OpenGlOffscreenRenderer {
///
/// Sends render actions to this offscreen render target
///
fn render<ActionIter: IntoIterator<Item=RenderAction>>(&mut self, actions: ActionIter) {
unsafe {
panic_on_gl_error("Preparing to render to offscreen buffer");
// Remember the active render target
let mut previous_frame_buffer = 0;
gl::GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut previous_frame_buffer);
// Render to the main render target
gl::BindFramebuffer(gl::FRAMEBUFFER, *self.main_render_target);
self.renderer.prepare_to_render_to_active_framebuffer(self.width, self.height);
// Perform the rendering actions
self.renderer.render(actions);
gl::Flush();
// Reset to the original render target
gl::BindFramebuffer(gl::FRAMEBUFFER, previous_frame_buffer as gl::types::GLuint);
panic_on_gl_error("After rendering to offscreen buffer");
}
}
///
/// Consumes this render target and returns the realized pixels as a byte array
///
fn realize(self) -> Vec<u8> {
// Allocate space for the image
let size_bytes = self.width * self.height * 4;
let mut pixels = vec![0; size_bytes];
// Read the image from the main texture into the pixel array
let texture = self.main_render_target.texture().expect("Offscreen texture");
unsafe {
gl::BindTexture(gl::TEXTURE_2D, *texture);
gl::GetTexImage(gl::TEXTURE_2D, 0, gl::RGBA, gl::UNSIGNED_BYTE, pixels.as_mut_ptr() as *mut c_void);
panic_on_gl_error("Read offscreen texture");
}
pixels
}
}