use miniquad::*;
use glam::{vec3, Mat4};
struct Stage {
display_pipeline: Pipeline,
display_bind: Bindings,
offscreen_pipeline: Pipeline,
offscreen_bind: Bindings,
offscreen_pass: RenderPass,
rx: f32,
ry: f32,
}
impl Stage {
pub fn new(ctx: &mut Context) -> Stage {
let color_img = Texture::new_render_texture(
ctx,
TextureParams {
width: 256,
height: 256,
format: TextureFormat::RGBA8,
..Default::default()
},
);
let depth_img = Texture::new_render_texture(
ctx,
TextureParams {
width: 256,
height: 256,
format: TextureFormat::Depth,
..Default::default()
},
);
let offscreen_pass = RenderPass::new(ctx, color_img, depth_img);
#[rustfmt::skip]
let vertices: &[f32] = &[
-1.0, -1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 0.0,
1.0, -1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 0.0,
1.0, 1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 1.0,
-1.0, 1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 1.0,
-1.0, -1.0, 1.0, 0.5, 1.0, 0.5, 1.0, 0.0, 0.0,
1.0, -1.0, 1.0, 0.5, 1.0, 0.5, 1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 0.5, 1.0, 0.5, 1.0, 1.0, 1.0,
-1.0, 1.0, 1.0, 0.5, 1.0, 0.5, 1.0, 0.0, 1.0,
-1.0, -1.0, -1.0, 0.5, 0.5, 1.0, 1.0, 0.0, 0.0,
-1.0, 1.0, -1.0, 0.5, 0.5, 1.0, 1.0, 1.0, 0.0,
-1.0, 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0,
-1.0, -1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 0.0, 1.0,
1.0, -1.0, -1.0, 1.0, 0.5, 0.0, 1.0, 0.0, 0.0,
1.0, 1.0, -1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 1.0,
1.0, -1.0, 1.0, 1.0, 0.5, 0.0, 1.0, 0.0, 1.0,
-1.0, -1.0, -1.0, 0.0, 0.5, 1.0, 1.0, 0.0, 0.0,
-1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 1.0, 1.0, 1.0,
1.0, -1.0, -1.0, 0.0, 0.5, 1.0, 1.0, 0.0, 1.0,
-1.0, 1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 1.0, 0.0, 0.5, 1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0, 0.0, 0.5, 1.0, 1.0, 1.0,
1.0, 1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 0.0, 1.0
];
let vertex_buffer = Buffer::immutable(ctx, BufferType::VertexBuffer, &vertices);
#[rustfmt::skip]
let indices: &[u16] = &[
0, 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
14, 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20
];
let index_buffer = Buffer::immutable(ctx, BufferType::IndexBuffer, &indices);
let offscreen_bind = Bindings {
vertex_buffers: vec![vertex_buffer.clone()],
index_buffer: index_buffer.clone(),
images: vec![],
};
let display_bind = Bindings {
vertex_buffers: vec![vertex_buffer],
index_buffer: index_buffer,
images: vec![color_img],
};
let default_shader = Shader::new(
ctx,
display_shader::VERTEX,
display_shader::FRAGMENT,
display_shader::meta(),
)
.unwrap();
let display_pipeline = Pipeline::with_params(
ctx,
&[BufferLayout::default()],
&[
VertexAttribute::new("pos", VertexFormat::Float3),
VertexAttribute::new("color0", VertexFormat::Float4),
VertexAttribute::new("uv0", VertexFormat::Float2),
],
default_shader,
PipelineParams {
depth_test: Comparison::LessOrEqual,
depth_write: true,
..Default::default()
},
);
let offscreen_shader = Shader::new(
ctx,
offscreen_shader::VERTEX,
offscreen_shader::FRAGMENT,
offscreen_shader::meta(),
)
.unwrap();
let offscreen_pipeline = Pipeline::with_params(
ctx,
&[BufferLayout {
stride: 36,
..Default::default()
}],
&[
VertexAttribute::new("pos", VertexFormat::Float3),
VertexAttribute::new("color0", VertexFormat::Float4),
],
offscreen_shader,
PipelineParams {
depth_test: Comparison::LessOrEqual,
depth_write: true,
..Default::default()
},
);
Stage {
display_pipeline,
display_bind,
offscreen_pipeline,
offscreen_bind,
offscreen_pass,
rx: 0.,
ry: 0.,
}
}
}
impl EventHandler for Stage {
fn update(&mut self, _ctx: &mut Context) {}
fn draw(&mut self, ctx: &mut Context) {
let (width, height) = ctx.screen_size();
let proj = Mat4::perspective_rh_gl(60.0f32.to_radians(), width / height, 0.01, 10.0);
let view = Mat4::look_at_rh(
vec3(0.0, 1.5, 3.0),
vec3(0.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
);
let view_proj = proj * view;
self.rx += 0.01;
self.ry += 0.03;
let model = Mat4::from_rotation_ypr(self.rx, self.ry, 0.);
let vs_params = display_shader::Uniforms {
mvp: view_proj * model,
};
ctx.begin_pass(
self.offscreen_pass,
PassAction::clear_color(1.0, 1.0, 1.0, 1.),
);
ctx.apply_pipeline(&self.offscreen_pipeline);
ctx.apply_bindings(&self.offscreen_bind);
ctx.apply_uniforms(&vs_params);
ctx.draw(0, 36, 1);
ctx.end_render_pass();
ctx.begin_default_pass(PassAction::clear_color(0.0, 0., 0.45, 1.));
ctx.apply_pipeline(&self.display_pipeline);
ctx.apply_bindings(&self.display_bind);
ctx.apply_uniforms(&vs_params);
ctx.draw(0, 36, 1);
ctx.end_render_pass();
ctx.commit_frame();
}
}
fn main() {
miniquad::start(
conf::Conf {
window_title: "Miniquad".to_string(),
..Default::default()
},
|mut ctx| Box::new(Stage::new(&mut ctx)),
);
}
mod display_shader {
use miniquad::*;
pub const VERTEX: &str = r#"#version 100
attribute vec4 pos;
attribute vec4 color0;
attribute vec2 uv0;
varying lowp vec4 color;
varying lowp vec2 uv;
uniform mat4 mvp;
void main() {
gl_Position = mvp * pos;
color = color0;
uv = uv0;
}
"#;
pub const FRAGMENT: &str = r#"#version 100
varying lowp vec4 color;
varying lowp vec2 uv;
uniform sampler2D tex;
void main() {
gl_FragColor = color * texture2D(tex, uv);
}
"#;
pub fn meta() -> ShaderMeta {
ShaderMeta {
images: vec!["tex".to_string()],
uniforms: UniformBlockLayout {
uniforms: vec![UniformDesc::new("mvp", UniformType::Mat4)],
},
}
}
#[repr(C)]
pub struct Uniforms {
pub mvp: glam::Mat4,
}
}
mod offscreen_shader {
use miniquad::*;
pub const VERTEX: &str = r#"#version 100
attribute vec4 pos;
attribute vec4 color0;
varying lowp vec4 color;
uniform mat4 mvp;
void main() {
gl_Position = mvp * pos;
color = color0;
}
"#;
pub const FRAGMENT: &str = r#"#version 100
varying lowp vec4 color;
void main() {
gl_FragColor = color;
}
"#;
pub fn meta() -> ShaderMeta {
ShaderMeta {
images: vec![],
uniforms: UniformBlockLayout {
uniforms: vec![UniformDesc::new("mvp", UniformType::Mat4)],
},
}
}
}