Examples Filter
Operations that involve displaying 2d graphics such as text, shapes, images on to the screen.
// main draw loop
gl.clear_color(0.1, 0.0, 0.2, 1.0)
gl.clear(.color_buffer_bit)
state.draw_quad()
state.draw_tri()


fn create_shader(vert_src, frag_src string) u32 {
	// vertex shader
	vert := gl.create_shader(.vertex_shader)
	gl.shader_source(vert, vert_src)
	gl.compile_shader(vert)
	if gl.get_shader_compile_status(vert) == 0 {
		log := gl.get_shader_info_log(vert)
		println('shader $vert compilation failed')
		println(log)
		exit(1)
	}

	// fragment shader
	frag := gl.create_shader(.fragment_shader)
	gl.shader_source(frag, frag_src)
	gl.compile_shader(frag)
	if gl.get_shader_compile_status(frag) == 0 {
		log := gl.get_shader_info_log(frag)
		println('fragment $frag shader compilation failed')
		println(log)
		exit(1)
	}

	// link shaders
	shader_program := gl.create_program()
	gl.attach_shader(shader_program, vert)
	gl.attach_shader(shader_program, frag)
	gl.link_program(shader_program)

	// check for linking errors
	success := gl.get_program_link_status(shader_program)
	if success == 0 {
		log := gl.get_program_info_log(shader_program)
		println('shader compilation failed')
		println('vertex source = $vert_src')
		println('fragment source = $frag_src')
		println(log)
		exit(1)
	}

	gl.delete_shader(vert)
	gl.delete_shader(frag)

	return shader_program
}

fn (state mut AppState) create_buffers() {
	vertex_data := [
	// positions          // colors           // texture coords
	 0.5,  0.5, 0.0,   1.0, 0.0, 0.0,   1.0, 1.0,   // top right
	 0.5, -0.5, 0.0,   0.0, 1.0, 0.0,   1.0, 0.0,   // bottom right
	-0.5, -0.5, 0.0,   0.0, 0.0, 1.0,   0.0, 0.0,   // bottom left
	-0.5,  0.5, 0.0,   1.0, 1.0, 0.0,   0.0, 1.0    // top left
	]!
	index_data := [
		u16(0), 1, 3, 1, 2, 3
	]!

	state.vao = gl.gen_vertex_array()
	gl.bind_vertex_array(state.vao)

	state.vbo = gl.gen_buffer()
	gl.bind_buffer(.array_buffer, state.vbo)
	gl.buffer_data_f32(.array_buffer, vertex_data, .static_draw)

	state.ibo = gl.gen_buffer()
	gl.bind_buffer(.element_array_buffer, state.ibo)
	gl.buffer_data_u16(.element_array_buffer, index_data, .static_draw)

	// position attribute
	gl.vertex_attrib_pointer(0, 3, .float, .gl_false, 8 * sizeof(f32), C.NULL)
	gl.enable_vertex_attrib_array(0)
	// color attribute
	gl.vertex_attrib_pointer(1, 3, .float, .gl_false, 8 * sizeof(f32), (3 * sizeof(f32)))
	gl.enable_vertex_attrib_array(1)
	// texture coord attribute
	gl.vertex_attrib_pointer(2, 2, .float, .gl_false, 8 * sizeof(f32), (6 * sizeof(f32)))
	gl.enable_vertex_attrib_array(2)
}

fn create_tri_buffers() Mesh {
	vertex_data := [
		// positions	// tex coords 	// colors
		-1.0, -1.0,		1.0, 1.0,		1.0, 0.0, 0.0, 1.0,   // bottom left
		1.0,  -1.0,		1.0, 0.0,		0.0, 1.0, 0.0, 1.0,   // bottom right
		0.0,  0.0, 		0.0, 1.0,		1.0, 1.0, 0.0, 1.0    // top
	]!
	index_data := [
		u16(0), 1, 2
	]!

	vao := gl.gen_vertex_array()
	gl.bind_vertex_array(vao)

	vbo := gl.gen_buffer()
	gl.bind_buffer(.array_buffer, vbo)
	gl.buffer_data_f32(.array_buffer, vertex_data, .static_draw)

	ibo := gl.gen_buffer()
	gl.bind_buffer(.element_array_buffer, ibo)
	gl.buffer_data_u16(.element_array_buffer, index_data, .static_draw)

	// position attribute
	gl.vertex_attrib_pointer(0, 2, .float, .gl_false, 8 * sizeof(f32), C.NULL)
	gl.enable_vertex_attrib_array(0)
	// texture coord attribute
	gl.vertex_attrib_pointer(2, 2, .float, .gl_false, 8 * sizeof(f32), 2 * sizeof(f32))
	gl.enable_vertex_attrib_array(2)
	// color attribute
	gl.vertex_attrib_pointer(2, 4, .float, .gl_false, 8 * sizeof(f32), 2 * sizeof(f32))
	gl.enable_vertex_attrib_array(2)

	return Mesh { vao, vbo, ibo }
}

fn (state mut AppState) load_textures() {
	image.set_flip_vertically_on_load(true)

 	state.tex = gl.gen_texture()
	gl.bind_texture(.texture_2d, state.tex)

	// set the texture wrapping parameters
	gl.tex_parameteri(.texture_2d, .texture_wrap_s, C.GL_REPEAT)
	gl.tex_parameteri(.texture_2d, .texture_wrap_t, C.GL_REPEAT)

	// set texture filtering parameters
	gl.tex_parameteri(.texture_2d, .texture_min_filter, C.GL_LINEAR)
	gl.tex_parameteri(.texture_2d, .texture_mag_filter, C.GL_LINEAR)

	img := image.load('assets/container.jpg')
	gl.tex_image_2d(.texture_2d, 0, .rgb, img.width, img.height, 0, .rgb, .unsigned_byte, img.data)
	img.free()


	state.tex2 = gl.gen_texture()
	gl.bind_texture(.texture_2d, state.tex2)

	 // set the texture wrapping parameters
	gl.tex_parameteri(.texture_2d, .texture_wrap_s, C.GL_REPEAT)
	gl.tex_parameteri(.texture_2d, .texture_wrap_t, C.GL_REPEAT)

	// set texture filtering parameters
	gl.tex_parameteri(.texture_2d, .texture_min_filter, C.GL_LINEAR)
	gl.tex_parameteri(.texture_2d, .texture_mag_filter, C.GL_LINEAR)

	img2 := image.load('assets/face.png')
	gl.tex_image_2d(.texture_2d, 0, .rgba, img2.width, img2.height, 0, .rgba, .unsigned_byte, img2.data)
	img2.free()

	gl.use_program(state.program1)
	gl.uniform1i(gl.get_uniform_location(state.program1, "texture1"), 0)
	gl.uniform1i(gl.get_uniform_location(state.program1, "texture2"), 1)
}

fn (state AppState) draw_quad() {
	gl.use_program(state.program1)

	gl.active_texture(.texture0)
	gl.bind_texture(.texture_2d, state.tex)
	gl.active_texture(.texture1)
	gl.bind_texture(.texture_2d, state.tex2)

	gl.bind_vertex_array(state.vao)
	gl.draw_elements(.triangle_fan, 6, .unsigned_short, C.NULL)
}

fn (state AppState) draw_tri() {
	gl.use_program(state.program2)

	gl.active_texture(.texture0)
	gl.bind_texture(.texture_2d, 0)
	gl.active_texture(.texture1)
	gl.bind_texture(.texture_2d, 0)

	gl.bind_vertex_array(state.tri_mesh.vao)
	gl.draw_elements(.triangle_fan, 3, .unsigned_short, C.NULL)
}
This code snippet draws text by loading a font via rusttype and computes the vertex data needed to draw a string and feeds that to an OpenGL shader. Supports arbitrary font sizes and colors. This is a nice way to draw text with raw opengl without a framework.
use glow::*;
use text;

fn main() {
  // Setup window gl context ...
  // possibly_current_ctx is something that you can create from glutin.
  let gl = glow::Context::from_loader_function(|s| {
      possibly_current_ctx.get_proc_address(s) as *const _
  });
  
  let mut gfx_ctx = Graphics::create(gl);
  gfx_ctx.init_font();
  
  // Inside some render loop.
  gfx_ctx.current_font_size = 18;
  gfx_ctx.current_fill_color = graphics::Color::create_rgba(r, g, b, a);
  gfx_ctx.fill_text(&text, x, y);
}

pub struct Graphics {
  pub gl: T,
  pub current_fill_color: Color,
  pub current_font_size: f32,
}

impl Graphics {
  pub fn create(gl: T) -> Self {
    unsafe {
      // Initialize the shader program.
      // Unsafe since we're using glow.
      // Not shown here are also buffer initializations.
      let text_program = Self::create_program(&gl, text::VERT_300_SRC, text::FRAG_300_SRC);
      Graphics:: {
        gl: gl,
        simple_program: gl_simple_program,
        current_fill_color: Color::create_rgba(0.0, 0.0, 0.0, 0.0),
        current_font_size: 20.0,
        projection_transform_matrix: projection_transform_matrix,
        text_program: gl_text_program,
        font: None,
      }
    }
  }
  pub fn init_font(&mut self) {
    // Load default font.
    let font = text::FontTexture::new(self, &include_bytes!("Montserrat-Regular.ttf")[..],
      70, text::ascii_character_list());
    self.font = Some(font);
  }
  pub fn fill_text(&mut self, text: &str, x: f32, y: f32) {
    pub current_fill_color: Color,
  	pub current_font_size: f32,
    let font = self.font.as_ref().unwrap();
    text::fill_text(self, &font, text, x, y, &self.current_fill_color, self.current_font_size);
  }
}