Luca Nerlich A blog about Tech, Programming and Games.

Learning Rust - Part 2

Hey there! I am trying to learn rust. In this part, I am creating a simple application window using opengl and sdl2.

Thanks to Nerijus Arlauskas and his extremely helpful blogpost.

All other parts of this series

Earlier

Later

SDL Installation Windows/Mac

Your Cargo.toml should look as follows

[package]
name = "opengl-test"
version = "0.1.0"
authors = ["Firstname Lastname <name@domain.com>"]
build = "build.rs"

[dependencies]
sdl2 = "0.31.0"
gl = "0.11.0"

Noticed the line build = "build.rs"? This is a rust build script. In our case, we use it to load windows specific stuff.

MacOS - Homebrew

As almost always, its easier to use a Unix OS ;-)

Use/install Homebrew and run the following command. You should be good to compile.

brew install sdl2

Windows 10

The following excerpt is copied from the rust-sdl2 repository. You need to download archives for mingw1 and vc2. Extract these, and copy specific files inside corresponding folder on the same level as your Cargo.toml.

SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\i686-w64-mingw32\bin 		-> 	gnu-mingw\dll\32
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\x86_64-w64-mingw32\bin 	-> 	gnu-mingw\dll\64
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\i686-w64-mingw32\lib 		-> 	gnu-mingw\lib\32
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\x86_64-w64-mingw32\lib 	-> 	gnu-mingw\lib\64
SDL2-devel-2.0.8-VC.zip\SDL2-2.0.x\lib\x86\*.dll	 		-> 	msvc\dll\32
SDL2-devel-2.0.8-VC.zip\SDL2-2.0.x\lib\x64\*.dll 			-> 	msvc\dll\64
SDL2-devel-2.0.8-VC.zip\SDL2-2.0.x\lib\x86\*.lib	 		-> 	msvc\lib\32
SDL2-devel-2.0.8-VC.zip\SDL2-2.0.x\lib\x64\*.lib	 		-> 	msvc\lib\64

Your folder structure should look like this:

buildrs_folder_structure


Create your build.rs file with the following content:

use std::env;
use std::path::PathBuf;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("pc-windows") {
        let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        let mut lib_dir = manifest_dir.clone();
        let mut dll_dir = manifest_dir.clone();
        if target.contains("msvc") {
            lib_dir.push("msvc");
            dll_dir.push("msvc");
        }
        else {
            lib_dir.push("gnu-mingw");
            dll_dir.push("gnu-mingw");
        }
        lib_dir.push("lib");
        dll_dir.push("dll");
        if target.contains("x86_64") {
            lib_dir.push("64");
            dll_dir.push("64");
        }
        else {
            lib_dir.push("32");
            dll_dir.push("32");
        }
        println!("cargo:rustc-link-search=all={}", lib_dir.display());
        for entry in std::fs::read_dir(dll_dir).expect("Can't read DLL dir")  {
            let entry_path = entry.expect("Invalid fs entry").path();
            let file_name_result = entry_path.file_name();
            let mut new_file_path = manifest_dir.clone();
            if let Some(file_name) = file_name_result {
                let file_name = file_name.to_str().unwrap();
                if file_name.ends_with(".dll") {
                    new_file_path.push(file_name);
                    std::fs::copy(&entry_path, new_file_path.as_path()).expect("Can't copy from DLL dir");
                }
            }
        }
    }
}

This will create and copy the needed .dll files next to your Cargo.toml file during build time. Copy these to the directory where your .exe file might be placed in the future.

Executing cargo run should now successfully compile and run your program.

Initializing SDL and creating a Window

Simple DirectMedia Layer

[…] a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D […]

As nercury described in his post, we need to instantiate the sdl context and use it to create a video subsystem with which we can open a window.

// main.rs

    let sdl_context: Sdl = sdl2::init().unwrap();

//    initialize video_subsystem
    let video_subsystem: VideoSubsystem = sdl_context.video().unwrap();

//    lets use it and create a window
    let window: Window = video_subsystem
        .window("Window", 800, 600)
        .opengl()
        .resizable()
        .build()
        .unwrap();

    let gl_context: GLContext = window.gl_create_context().unwrap();

//    load gl to forward our opengl calls to the driver.
    let gl = gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const std::os::raw::c_void);

    unsafe {
//        set color to blue
        gl::ClearColor(0.3, 0.3, 0.5, 1.0);
    }

We will then open a potentially infinite loop which will handle all user input and window content.

//main.rs

//    create an EventPump to receive Events for n windows.
    let mut event_pump: EventPump = sdl_context.event_pump().unwrap();

//    label for this loop. Allows us to break free from inside the for loop.
    'main: loop {
//        an underscore as a variable prefix silences compiler warnings
        for event in event_pump.poll_iter() {
//            handle quit event
            match event {
//                pattern match for event 'Quit'. Allows the window to be closed.
                sdl2::event::Event::Quit { .. } => break 'main,
                _ => {}
            }
//            handle user input here.
        }
        unsafe {
//            update buffer/screen
            gl::Clear(gl::COLOR_BUFFER_BIT);
        }

        window.gl_swap_window();
    }

Ive also create a small util.rs file and placed the above find_sdl_gl_driver function in it.

extern crate sdl2;

/// Find and return the OpenGL driver from SDL.
pub fn find_sdl_gl_driver() -> Option<u32> {
    for (index, item) in sdl2::render::drivers().enumerate() {
        if item.name == "opengl" {
            return Some(index as u32);
        }
    }
    None
}

Find the complete files here:


If implemented correctly, running our app will result in an empty, resizable and closable window.

empty_opengl_window

Thats it for now. The next post will place content in this window ;-)

Tutorials / Downloads

luca

  1. sdl2_mingw.tar.gz ~ 9.8mb 

  2. sdl2_vc.zip ~ 1.8mb 

category

rust