├── README.md ├── opengles ├── hello_opengl │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ └── main.rs └── triangle │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ └── main.rs └── videocore └── change-background-color ├── .gitignore ├── Cargo.toml └── src └── main.rs /README.md: -------------------------------------------------------------------------------- 1 | # Rust Raspberry Pi Examples 2 | 3 | There are several APIs exposed by the Raspberry Pi: 4 | 5 | * [Broadcom VideoCore IV](https://github.com/seankerr/rust-videocore) 6 | * [EGL](https://github.com/seankerr/rust-egl) 7 | * [OpenGL ES 2.0](https://github.com/seankerr/rust-opengles) 8 | * [OpenMAX](https://github.com/seankerr/rust-openmax) (not started) 9 | * [OpenVG](https://github.com/seankerr/rust-openvg) (not started) 10 | 11 | ## Available Examples 12 | 13 | *Broadcom VideoCore IV* 14 | 15 | * [Change background color](https://github.com/seankerr/rust-rpi-examples/tree/master/videocore/change-background-color) 16 | 17 | *OpenGL ES 2.0* 18 | 19 | * [Hello OpenGL](https://github.com/seankerr/rust-rpi-examples/tree/master/opengles/hello_opengl) 20 | * [Triangle](https://github.com/seankerr/rust-rpi-examples/tree/master/opengles/triangle) -------------------------------------------------------------------------------- /opengles/hello_opengl/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /opengles/hello_opengl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "run" 3 | version = "0.1.0" 4 | authors = ["Sean Kerr "] 5 | 6 | [dependencies] 7 | egl = "0.2.4" 8 | opengles = "0.1.1" 9 | videocore = "0.1.2" -------------------------------------------------------------------------------- /opengles/hello_opengl/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate egl; 2 | extern crate opengles; 3 | extern crate videocore; 4 | 5 | use std::ptr; 6 | 7 | use egl::{ EGLConfig, 8 | EGLContext, 9 | EGLDisplay, 10 | EGLNativeDisplayType, 11 | EGLSurface }; 12 | 13 | use opengles::glesv2 as gl; 14 | 15 | use videocore::bcm_host; 16 | use videocore::dispmanx; 17 | use videocore::dispmanx::{ FlagsAlpha, 18 | Transform, 19 | VCAlpha, 20 | Window }; 21 | use videocore::image::Rect; 22 | 23 | // ------------------------------------------------------------------------------------------------- 24 | // STRUCTS 25 | // ------------------------------------------------------------------------------------------------- 26 | 27 | pub struct Context { 28 | pub config: EGLConfig, 29 | pub context: EGLContext, 30 | pub display: EGLDisplay, 31 | pub surface: EGLSurface 32 | } 33 | 34 | // ------------------------------------------------------------------------------------------------- 35 | // FUNCTIONS 36 | // ------------------------------------------------------------------------------------------------- 37 | 38 | fn gl_loop(context: Context) { 39 | // get screen resolution 40 | let dimensions = bcm_host::graphics_get_display_size(0).unwrap(); 41 | 42 | gl::viewport(0, 0, dimensions.width as i32, dimensions.height as i32); 43 | 44 | loop { 45 | gl::clear_color(1.0, 0.0, 1.0, 1.0); 46 | gl::clear(gl::GL_COLOR_BUFFER_BIT); 47 | 48 | egl::swap_buffers(context.display, context.surface); 49 | } 50 | } 51 | 52 | fn init_egl(window: &mut Window) -> Context { 53 | 54 | let context_attr = [egl::EGL_CONTEXT_CLIENT_VERSION, 2, 55 | egl::EGL_NONE]; 56 | 57 | let config_attr = [egl::EGL_RED_SIZE, 8, 58 | egl::EGL_GREEN_SIZE, 8, 59 | egl::EGL_BLUE_SIZE, 8, 60 | egl::EGL_ALPHA_SIZE, 8, 61 | egl::EGL_SURFACE_TYPE, egl::EGL_WINDOW_BIT, 62 | egl::EGL_NONE]; 63 | 64 | // get display 65 | let egl_display = match egl::get_display(egl::EGL_DEFAULT_DISPLAY) { 66 | Some(x) => x, 67 | None => panic!("Failed to get EGL display") 68 | }; 69 | 70 | // init display 71 | if !egl::initialize(egl_display, &mut 0i32, &mut 0i32) { 72 | panic!("Failed to initialize EGL"); 73 | } 74 | 75 | // choose first available configuration 76 | let egl_config = match egl::choose_config(egl_display, &config_attr, 1) { 77 | Some(x) => x, 78 | None => panic!("Failed to get EGL configuration") 79 | }; 80 | 81 | // bind opengl es api 82 | if !egl::bind_api(egl::EGL_OPENGL_ES_API) { 83 | panic!("Failed to bind EGL OpenGL ES API"); 84 | } 85 | 86 | // create egl context 87 | let egl_context = match egl::create_context(egl_display, egl_config, egl::EGL_NO_CONTEXT, 88 | &context_attr) { 89 | Some(c) => c, 90 | None => panic!("Failed to create EGL context") 91 | }; 92 | 93 | // create surface 94 | let egl_surface = match egl::create_window_surface(egl_display, egl_config, 95 | window as *mut _ as EGLNativeDisplayType, 96 | &[]) { 97 | Some(s) => s, 98 | None => panic!("Failed to create EGL surface") 99 | }; 100 | 101 | // set current context 102 | if !egl::make_current(egl_display, egl_surface, egl_surface, egl_context) { 103 | panic!("Failed to make EGL current context"); 104 | } 105 | 106 | Context{ config: egl_config, 107 | context: egl_context, 108 | display: egl_display, 109 | surface: egl_surface } 110 | } 111 | 112 | fn main() { 113 | // first thing to do is initialize the broadcom host (when doing any graphics on RPi) 114 | bcm_host::init(); 115 | 116 | // open the display 117 | let display = dispmanx::display_open(0); 118 | 119 | // get update handle 120 | let update = dispmanx::update_start(0); 121 | 122 | // get screen resolution (same display number as display_open() 123 | let dimensions = match bcm_host::graphics_get_display_size(0) { 124 | Some(x) => x, 125 | None => panic!("Must call bcm_host::init() prior to any display operation on RPi") 126 | }; 127 | 128 | println!("Display size: {}x{}", dimensions.width, dimensions.height); 129 | 130 | // setup the destination rectangle where opengl will be drawing 131 | let mut dest_rect = Rect{ x: 0, 132 | y: 0, 133 | width: dimensions.width as i32, 134 | height: dimensions.height as i32 }; 135 | 136 | // setup the source rectangle where opengl will be drawing 137 | let mut src_rect = Rect{ x: 0, 138 | y: 0, 139 | width: 0, 140 | height: 0 }; 141 | 142 | // draw opengl context on a clean background (cleared by the clear color) 143 | let mut alpha = VCAlpha{ flags: FlagsAlpha::FIXED_ALL_PIXELS, 144 | opacity: 255, 145 | mask: 0 }; 146 | 147 | // draw opengl context on top of whatever is running behind it 148 | // note: changing the layer for the dispmanx element will also adjust where it's drawn, if 149 | // there are other graphical applications running 150 | 151 | //let mut alpha = VCAlpha{ flags: FlagsAlpha::FROM_SOURCE, 152 | // opacity: 0, 153 | // mask: 0 }; 154 | 155 | // create our dispmanx element upon which we'll draw opengl using EGL 156 | let element = dispmanx::element_add(update, display, 157 | 3, // layer upon which to draw 158 | &mut dest_rect, 159 | 0, 160 | &mut src_rect, 161 | dispmanx::DISPMANX_PROTECTION_NONE, 162 | &mut alpha, 163 | ptr::null_mut(), 164 | Transform::NO_ROTATE); 165 | 166 | // submit changes 167 | dispmanx::update_submit_sync(update); 168 | 169 | // create window to hold element, width, height 170 | let mut window = Window{ element: element, 171 | width: dimensions.width as i32, 172 | height: dimensions.height as i32 }; 173 | 174 | // init egl 175 | let context = init_egl(&mut window); 176 | 177 | gl_loop(context); 178 | } -------------------------------------------------------------------------------- /opengles/triangle/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /opengles/triangle/Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "run" 3 | version = "0.1.0" 4 | dependencies = [ 5 | "egl 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "opengles 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "videocore 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 8 | ] 9 | 10 | [[package]] 11 | name = "egl" 12 | version = "0.2.5" 13 | source = "registry+https://github.com/rust-lang/crates.io-index" 14 | dependencies = [ 15 | "khronos 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 16 | "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 17 | ] 18 | 19 | [[package]] 20 | name = "khronos" 21 | version = "0.1.1" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | dependencies = [ 24 | "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 25 | ] 26 | 27 | [[package]] 28 | name = "libc" 29 | version = "0.1.10" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | 32 | [[package]] 33 | name = "opengles" 34 | version = "0.1.2" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | dependencies = [ 37 | "khronos 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 38 | "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 39 | ] 40 | 41 | [[package]] 42 | name = "videocore" 43 | version = "0.1.2" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | dependencies = [ 46 | "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 47 | ] 48 | 49 | -------------------------------------------------------------------------------- /opengles/triangle/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "run" 3 | version = "0.1.0" 4 | authors = ["Sean Kerr "] 5 | 6 | [dependencies] 7 | egl = "0.2.5" 8 | opengles = "0.1.2" 9 | videocore = "0.1.2" -------------------------------------------------------------------------------- /opengles/triangle/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate egl; 2 | extern crate opengles; 3 | extern crate videocore; 4 | 5 | use std::ptr; 6 | 7 | use egl::{ EGLConfig, 8 | EGLContext, 9 | EGLDisplay, 10 | EGLNativeDisplayType, 11 | EGLSurface }; 12 | 13 | use opengles::glesv2 as gl; 14 | 15 | use videocore::bcm_host; 16 | use videocore::dispmanx; 17 | use videocore::dispmanx::{ FlagsAlpha, 18 | Transform, 19 | VCAlpha, 20 | Window }; 21 | use videocore::image::Rect; 22 | 23 | // ------------------------------------------------------------------------------------------------- 24 | // STRUCTS 25 | // ------------------------------------------------------------------------------------------------- 26 | 27 | pub struct Context { 28 | pub config: EGLConfig, 29 | pub context: EGLContext, 30 | pub display: EGLDisplay, 31 | pub surface: EGLSurface 32 | } 33 | 34 | // ------------------------------------------------------------------------------------------------- 35 | // FUNCTIONS 36 | // ------------------------------------------------------------------------------------------------- 37 | 38 | fn gl_loop(context: Context) { 39 | // get screen resolution 40 | let dimensions = bcm_host::graphics_get_display_size(0).unwrap(); 41 | 42 | gl::viewport(0, 0, dimensions.width as i32, dimensions.height as i32); 43 | 44 | // init shaders 45 | let program = init_shaders(); 46 | 47 | // get attributes 48 | let a_color = gl::get_attrib_location(program, "a_color"); 49 | let a_vertex = gl::get_attrib_location(program, "a_vertex"); 50 | 51 | // load triangle vertex data into buffer 52 | let (vertex_vbo, color_vbo) = init_triangle(); 53 | 54 | loop { 55 | gl::clear_color(1.0, 1.0, 1.0, 1.0); 56 | gl::clear(gl::GL_COLOR_BUFFER_BIT); 57 | 58 | // bind color buffer to a_color attribute 59 | gl::enable_vertex_attrib_array(a_color as gl::GLuint); 60 | gl::bind_buffer(gl::GL_ARRAY_BUFFER, color_vbo); 61 | gl::vertex_attrib_pointer_offset(a_color as gl::GLuint, 3, gl::GL_FLOAT, false, 0, 0); 62 | 63 | // bind vertex buffer to a_vertex attribute 64 | gl::enable_vertex_attrib_array(a_vertex as gl::GLuint); 65 | gl::bind_buffer(gl::GL_ARRAY_BUFFER, vertex_vbo); 66 | gl::vertex_attrib_pointer_offset(a_vertex as gl::GLuint, 2, gl::GL_FLOAT, false, 0, 0); 67 | 68 | // draw triangle 69 | gl::draw_arrays(gl::GL_TRIANGLE_FAN, 0, 3); 70 | 71 | // disable attributes 72 | gl::disable_vertex_attrib_array(a_color as gl::GLuint); 73 | gl::disable_vertex_attrib_array(a_vertex as gl::GLuint); 74 | 75 | // remove buffer binding 76 | gl::bind_buffer(gl::GL_ARRAY_BUFFER, 0); 77 | 78 | // swap graphics buffers 79 | egl::swap_buffers(context.display, context.surface); 80 | } 81 | } 82 | 83 | fn init_egl(window: &mut Window) -> Context { 84 | 85 | let context_attr = [egl::EGL_CONTEXT_CLIENT_VERSION, 2, 86 | egl::EGL_NONE]; 87 | 88 | let config_attr = [egl::EGL_RED_SIZE, 8, 89 | egl::EGL_GREEN_SIZE, 8, 90 | egl::EGL_BLUE_SIZE, 8, 91 | egl::EGL_ALPHA_SIZE, 8, 92 | egl::EGL_SURFACE_TYPE, egl::EGL_WINDOW_BIT, 93 | egl::EGL_NONE]; 94 | 95 | // get display 96 | let egl_display = match egl::get_display(egl::EGL_DEFAULT_DISPLAY) { 97 | Some(x) => x, 98 | None => panic!("Failed to get EGL display") 99 | }; 100 | 101 | // init display 102 | if !egl::initialize(egl_display, &mut 0i32, &mut 0i32) { 103 | panic!("Failed to initialize EGL"); 104 | } 105 | 106 | // choose first available configuration 107 | let egl_config = match egl::choose_config(egl_display, &config_attr, 1) { 108 | Some(x) => x, 109 | None => panic!("Failed to get EGL configuration") 110 | }; 111 | 112 | // bind opengl es api 113 | if !egl::bind_api(egl::EGL_OPENGL_ES_API) { 114 | panic!("Failed to bind EGL OpenGL ES API"); 115 | } 116 | 117 | // create egl context 118 | let egl_context = match egl::create_context(egl_display, egl_config, egl::EGL_NO_CONTEXT, 119 | &context_attr) { 120 | Some(c) => c, 121 | None => panic!("Failed to create EGL context") 122 | }; 123 | 124 | // create surface 125 | let egl_surface = match egl::create_window_surface(egl_display, egl_config, 126 | window as *mut _ as EGLNativeDisplayType, 127 | &[]) { 128 | Some(s) => s, 129 | None => panic!("Failed to create EGL surface") 130 | }; 131 | 132 | // set current context 133 | if !egl::make_current(egl_display, egl_surface, egl_surface, egl_context) { 134 | panic!("Failed to make EGL current context"); 135 | } 136 | 137 | // remove the vsync/swap interval 138 | egl::swap_interval(egl_display, 0); 139 | 140 | Context{ config: egl_config, 141 | context: egl_context, 142 | display: egl_display, 143 | surface: egl_surface } 144 | } 145 | 146 | fn init_shaders() -> gl::GLuint { 147 | // create shader program 148 | let program = gl::create_program(); 149 | 150 | // load fragment shader 151 | let frag_shader = gl::create_shader(gl::GL_FRAGMENT_SHADER); 152 | 153 | gl::shader_source(frag_shader, 154 | " 155 | varying vec4 v_color; 156 | 157 | void main () { 158 | gl_FragColor = v_color; 159 | } 160 | ".as_bytes()); 161 | 162 | gl::compile_shader(frag_shader); 163 | gl::attach_shader(program, frag_shader); 164 | 165 | // load vertex shader 166 | let vert_shader = gl::create_shader(gl::GL_VERTEX_SHADER); 167 | 168 | gl::shader_source(vert_shader, 169 | " 170 | attribute vec4 a_color; 171 | attribute vec4 a_vertex; 172 | varying vec4 v_color; 173 | 174 | void main () { 175 | gl_Position = a_vertex; 176 | v_color = a_color; 177 | } 178 | ".as_bytes()); 179 | 180 | gl::compile_shader(vert_shader); 181 | gl::attach_shader(program, vert_shader); 182 | 183 | // link program 184 | gl::link_program(program); 185 | gl::use_program(program); 186 | 187 | program 188 | } 189 | 190 | fn init_triangle() -> (gl::GLuint, gl::GLuint) { 191 | // generate a buffer to hold the vertices and colors 192 | let vbos = gl::gen_buffers(2); 193 | 194 | // vertex coords 195 | let vertices = [ -1.0, -1.0, // bottom left 196 | 1.0, -1.0, // bottom right 197 | 0.0, 1.0 ] as [f32; 6]; // top 198 | 199 | gl::bind_buffer(gl::GL_ARRAY_BUFFER, vbos[0]); 200 | gl::buffer_data(gl::GL_ARRAY_BUFFER, &vertices, gl::GL_STATIC_DRAW); 201 | 202 | // colors 203 | let colors = [ 1.0, 0.0, 0.0, 204 | 0.0, 1.0, 0.0, 205 | 0.0, 0.0, 1.0 ] as [f32; 9]; 206 | 207 | gl::bind_buffer(gl::GL_ARRAY_BUFFER, vbos[1]); 208 | gl::buffer_data(gl::GL_ARRAY_BUFFER, &colors, gl::GL_STATIC_DRAW); 209 | 210 | (vbos[0], vbos[1]) 211 | } 212 | 213 | fn main() { 214 | // first thing to do is initialize the broadcom host (when doing any graphics on RPi) 215 | bcm_host::init(); 216 | 217 | // open the display 218 | let display = dispmanx::display_open(0); 219 | 220 | // get update handle 221 | let update = dispmanx::update_start(0); 222 | 223 | // get screen resolution (same display number as display_open() 224 | let dimensions = match bcm_host::graphics_get_display_size(0) { 225 | Some(x) => x, 226 | None => panic!("Must call bcm_host::init() prior to any display operation on RPi") 227 | }; 228 | 229 | println!("Display size: {}x{}", dimensions.width, dimensions.height); 230 | 231 | // setup the destination rectangle where opengl will be drawing 232 | let mut dest_rect = Rect{ x: 0, 233 | y: 0, 234 | width: dimensions.width as i32, 235 | height: dimensions.height as i32 }; 236 | 237 | // setup the source rectangle where opengl will be drawing 238 | let mut src_rect = Rect{ x: 0, 239 | y: 0, 240 | width: 0, 241 | height: 0 }; 242 | 243 | // draw opengl context on a clean background (cleared by the clear color) 244 | let mut alpha = VCAlpha{ flags: FlagsAlpha::FIXED_ALL_PIXELS, 245 | opacity: 255, 246 | mask: 0 }; 247 | 248 | // draw opengl context on top of whatever is running behind it 249 | // note: changing the layer for the dispmanx element will also adjust where it's drawn, if 250 | // there are other graphical applications running 251 | 252 | //let mut alpha = VCAlpha{ flags: FlagsAlpha::FROM_SOURCE, 253 | // opacity: 0, 254 | // mask: 0 }; 255 | 256 | // create our dispmanx element upon which we'll draw opengl using EGL 257 | let element = dispmanx::element_add(update, display, 258 | 3, // layer upon which to draw 259 | &mut dest_rect, 260 | 0, 261 | &mut src_rect, 262 | dispmanx::DISPMANX_PROTECTION_NONE, 263 | &mut alpha, 264 | ptr::null_mut(), 265 | Transform::NO_ROTATE); 266 | 267 | // submit changes 268 | dispmanx::update_submit_sync(update); 269 | 270 | // create window to hold element, width, height 271 | let mut window = Window{ element: element, 272 | width: dimensions.width as i32, 273 | height: dimensions.height as i32 }; 274 | 275 | // init egl 276 | let context = init_egl(&mut window); 277 | 278 | gl_loop(context); 279 | } -------------------------------------------------------------------------------- /videocore/change-background-color/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /videocore/change-background-color/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "run" 3 | version = "0.1.0" 4 | authors = ["Sean Kerr "] 5 | 6 | [dependencies] 7 | videocore = "0.1.1" -------------------------------------------------------------------------------- /videocore/change-background-color/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate videocore; 2 | 3 | use videocore::bcm_host; 4 | use videocore::dispmanx; 5 | 6 | fn main() { 7 | // first thing to do is initialize the broadcom host (when doing any graphics on RPi) 8 | bcm_host::init(); 9 | 10 | // open the display 11 | let display = dispmanx::display_open(0); 12 | 13 | // get update handle 14 | let update = dispmanx::update_start(0); 15 | 16 | // change background color 17 | dispmanx::display_set_background(update, display, 18 | 255, // red 19 | 0, // green 20 | 0); // blue 21 | 22 | // submit changes 23 | dispmanx::update_submit_sync(update); 24 | } --------------------------------------------------------------------------------