ombre 0.6.7

Shadowy game and graphics library for Rust
Documentation
#[path = "common/runtime.rs"]
mod runtime;

use std::time::SystemTime;

use ombre::prelude::*;

#[repr(C)]
struct Vec2 {
    x: f32,
    y: f32,
}
#[repr(C)]
struct Vertex {
    pos: Vec2,
    uv: Vec2,
}

struct Renderer<T> {
    pipeline: PipelineId,
    bindings: Bindings,
    backend: T,
}

impl<T: RenderBackend> RuntimeRenderer for Renderer<T> {
    type Error = T::Error;

    fn window_resized(&mut self, _size: platform::LogicalSize) {}

    fn frame(&mut self) -> Result<(), Self::Error> {
        let t = SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs_f64();
        let mut frame = self.backend.frame();

        frame.begin_default_pass(Default::default());
        frame.apply_pipeline(&self.pipeline)?;
        frame.apply_bindings(&self.bindings)?;

        for i in 0..10 {
            let t = t + i as f64 * 0.3;

            frame.apply_uniforms(&shader::Uniforms {
                offset: [t.sin() as f32 * 0.5, (t * 3.).cos() as f32 * 0.5],
            })?;
            frame.draw(0, 6, 1)?;
        }
        frame.end_pass();
        frame.commit();

        Ok(())
    }
}

impl<T: RenderBackend> Renderer<T> {
    pub fn init(mut backend: T) -> Result<Renderer<T>, T::Error> {
        #[rustfmt::skip]
        let vertices: [Vertex; 4] = [
            Vertex { pos : Vec2 { x: -0.5, y: -0.5 }, uv: Vec2 { x: 0., y: 0. } },
            Vertex { pos : Vec2 { x:  0.5, y: -0.5 }, uv: Vec2 { x: 1., y: 0. } },
            Vertex { pos : Vec2 { x:  0.5, y:  0.5 }, uv: Vec2 { x: 1., y: 1. } },
            Vertex { pos : Vec2 { x: -0.5, y:  0.5 }, uv: Vec2 { x: 0., y: 1. } },
        ];
        let vertex_buffer = backend.buffer(
            BufferKind::Vertex,
            BufferUsage::Immutable,
            BufferSource::slice(&vertices),
        )?;

        let indices: [u16; 6] = [0, 1, 2, 0, 2, 3];
        let index_buffer = backend.buffer(
            BufferKind::Index,
            BufferUsage::Immutable,
            BufferSource::slice(&indices),
        )?;

        let pixels: [Rgba8; 4 * 4] = [
            Rgba8::new(0xFF, 0xFF, 0xFF, 0xFF),
            Rgba8::new(0xFF, 0x00, 0x00, 0xFF),
            Rgba8::new(0xFF, 0xFF, 0xFF, 0xFF),
            Rgba8::new(0xFF, 0x00, 0x00, 0xFF),
            Rgba8::new(0xFF, 0x00, 0x00, 0xFF),
            Rgba8::new(0xFF, 0xFF, 0xFF, 0xFF),
            Rgba8::new(0xFF, 0x00, 0x00, 0xFF),
            Rgba8::new(0xFF, 0xFF, 0xFF, 0xFF),
            Rgba8::new(0xFF, 0xFF, 0xFF, 0xFF),
            Rgba8::new(0xFF, 0x00, 0x00, 0x00),
            Rgba8::new(0xFF, 0xFF, 0xFF, 0xFF),
            Rgba8::new(0xFF, 0x00, 0x00, 0xFF),
            Rgba8::new(0xFF, 0x00, 0x00, 0xFF),
            Rgba8::new(0xFF, 0xFF, 0xFF, 0xFF),
            Rgba8::new(0xFF, 0x00, 0x00, 0xFF),
            Rgba8::new(0xFF, 0xFF, 0xFF, 0xFF),
        ];
        let texture = backend.texture(gfx::Texture {
            data: pixels.as_slice(),
            size: Size::new(4, 4),
            min_filter: FilterMode::Linear,
            mag_filter: FilterMode::Linear,
            ..gfx::Texture::default()
        })?;

        let bindings = Bindings {
            vertex: vec![vertex_buffer],
            index: Some(index_buffer),
            textures: vec![texture],
        };

        let shader = backend
            .shader(
                ShaderSource {
                    vertex: shader::VERTEX,
                    fragment: shader::FRAGMENT,
                },
                shader::meta(),
            )
            .unwrap();

        let pipeline = backend.pipeline(
            shader,
            gfx::PipelineDescriptor {
                layout: &[gfx::BufferLayout {
                    attrs: &[
                        VertexAttribute::new("in_pos", VertexFormat::Float2),
                        VertexAttribute::new("in_uv", VertexFormat::Float2),
                    ],
                    ..gfx::BufferLayout::default()
                }],
                ..gfx::PipelineDescriptor::default()
            },
        );

        Ok(Self {
            pipeline,
            bindings,
            backend,
        })
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    logger::init(log::Level::Debug)?;

    let (mut win, events) =
        platform::init("texture", 640, 480, &[], platform::GraphicsContext::Gl)?;
    let ctx = unsafe { glow::Context::from_loader_function(|p| win.get_proc_address(p)) };
    let backend = gfx::gl::Context::new(ctx, win.size())?;
    let renderer = Renderer::init(backend)?;

    runtime::run(win, events, renderer)?;

    Ok(())
}

mod shader {
    use super::*;

    pub const VERTEX: &str = r#"#version 100
    attribute vec2 in_pos;
    attribute vec2 in_uv;

    uniform vec2 offset;

    varying lowp vec2 texcoord;

    void main() {
        gl_Position = vec4(in_pos + offset, 0, 1);
        texcoord = in_uv;
    }"#;

    pub const FRAGMENT: &str = r#"#version 100
    varying lowp vec2 texcoord;

    uniform sampler2D tex;

    void main() {
        gl_FragColor = texture2D(tex, texcoord);
    }"#;

    pub fn meta() -> ShaderDescriptor {
        ShaderDescriptor {
            textures: vec!["tex".to_string()],
            uniforms: UniformBlockLayout {
                uniforms: vec![UniformDescriptor::new("offset", UniformKind::Float2)],
            },
        }
    }

    #[repr(C)]
    pub struct Uniforms {
        pub offset: [f32; 2],
    }
    unsafe impl bytes::Packed for Uniforms {}
}