raw_miniquad/
raw_miniquad.rs

1use macroquad::prelude::*;
2
3#[macroquad::main("Raw miniquad")]
4async fn main() {
5    let stage = {
6        let InternalGlContext {
7            quad_context: ctx, ..
8        } = unsafe { get_internal_gl() };
9
10        raw_miniquad::Stage::new(ctx)
11    };
12
13    loop {
14        clear_background(LIGHTGRAY);
15
16        // Render some primitives in camera space
17
18        set_camera(&Camera2D {
19            zoom: vec2(1., screen_width() / screen_height()),
20            ..Default::default()
21        });
22        draw_line(-0.4, 0.4, -0.8, 0.9, 0.05, BLUE);
23        draw_rectangle(-0.3, 0.3, 0.2, 0.2, GREEN);
24        draw_circle(0., 0., 0.1, YELLOW);
25
26        {
27            let mut gl = unsafe { get_internal_gl() };
28
29            // Ensure that macroquad's shapes are not going to be lost
30            gl.flush();
31
32            let t = get_time();
33
34            gl.quad_context.apply_pipeline(&stage.pipeline);
35
36            gl.quad_context
37                .begin_default_pass(miniquad::PassAction::Nothing);
38            gl.quad_context.apply_bindings(&stage.bindings);
39
40            for i in 0..10 {
41                let t = t + i as f64 * 0.3;
42
43                gl.quad_context
44                    .apply_uniforms(miniquad::UniformsSource::table(
45                        &raw_miniquad::shader::Uniforms {
46                            offset: (t.sin() as f32 * 0.5, (t * 3.).cos() as f32 * 0.5),
47                        },
48                    ));
49                gl.quad_context.draw(0, 6, 1);
50            }
51            gl.quad_context.end_render_pass();
52        }
53
54        // Back to screen space, render some text
55
56        set_default_camera();
57        draw_text("HELLO", 30.0, 200.0, 30.0, BLACK);
58
59        next_frame().await
60    }
61}
62
63mod raw_miniquad {
64    use miniquad::*;
65
66    #[repr(C)]
67    struct Vec2 {
68        x: f32,
69        y: f32,
70    }
71    #[repr(C)]
72    struct Vertex {
73        pos: Vec2,
74        uv: Vec2,
75    }
76
77    pub struct Stage {
78        pub pipeline: Pipeline,
79        pub bindings: Bindings,
80    }
81
82    impl Stage {
83        pub fn new(ctx: &mut dyn RenderingBackend) -> Stage {
84            #[rustfmt::skip]
85            let vertices: [Vertex; 4] = [
86                Vertex { pos : Vec2 { x: -0.5, y: -0.5 }, uv: Vec2 { x: 0., y: 0. } },
87                Vertex { pos : Vec2 { x:  0.5, y: -0.5 }, uv: Vec2 { x: 1., y: 0. } },
88                Vertex { pos : Vec2 { x:  0.5, y:  0.5 }, uv: Vec2 { x: 1., y: 1. } },
89                Vertex { pos : Vec2 { x: -0.5, y:  0.5 }, uv: Vec2 { x: 0., y: 1. } },
90            ];
91            let vertex_buffer = ctx.new_buffer(
92                BufferType::VertexBuffer,
93                BufferUsage::Immutable,
94                BufferSource::slice(&vertices),
95            );
96
97            let indices: [u16; 6] = [0, 1, 2, 0, 2, 3];
98            let index_buffer = ctx.new_buffer(
99                BufferType::IndexBuffer,
100                BufferUsage::Immutable,
101                BufferSource::slice(&indices[..]),
102            );
103
104            let pixels: [u8; 4 * 4 * 4] = [
105                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
106                0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
107                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
108                0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
109                0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
110            ];
111            let texture = ctx.new_texture_from_rgba8(4, 4, &pixels);
112
113            let bindings = Bindings {
114                vertex_buffers: vec![vertex_buffer],
115                index_buffer,
116                images: vec![texture],
117            };
118
119            let shader = ctx
120                .new_shader(
121                    miniquad::ShaderSource::Glsl {
122                        vertex: shader::VERTEX,
123                        fragment: shader::FRAGMENT,
124                    },
125                    shader::meta(),
126                )
127                .unwrap();
128
129            let pipeline = ctx.new_pipeline(
130                &[BufferLayout::default()],
131                &[
132                    VertexAttribute::new("pos", VertexFormat::Float2),
133                    VertexAttribute::new("uv", VertexFormat::Float2),
134                ],
135                shader,
136                Default::default(),
137            );
138
139            Stage { pipeline, bindings }
140        }
141    }
142
143    pub mod shader {
144        use miniquad::*;
145
146        pub const VERTEX: &str = r#"#version 100
147attribute vec2 pos;
148attribute vec2 uv;
149
150uniform vec2 offset;
151
152varying lowp vec2 texcoord;
153
154void main() {
155    gl_Position = vec4(pos + offset, 0, 1);
156    texcoord = uv;
157}"#;
158
159        pub const FRAGMENT: &str = r#"#version 100
160varying lowp vec2 texcoord;
161
162uniform sampler2D tex;
163
164void main() {
165    gl_FragColor = texture2D(tex, texcoord);
166}"#;
167
168        pub fn meta() -> ShaderMeta {
169            ShaderMeta {
170                images: vec!["tex".to_string()],
171                uniforms: UniformBlockLayout {
172                    uniforms: vec![UniformDesc::new("offset", UniformType::Float2)],
173                },
174            }
175        }
176
177        #[repr(C)]
178        pub struct Uniforms {
179            pub offset: (f32, f32),
180        }
181    }
182}