use crate::graphics::*;
use crate::math::*;
use crate::*;
use std::mem::size_of;
use std::mem::size_of_val;
const VERTICES_PER_QUAD: usize = 4;
const INDICES_PER_QUAD: usize = 6;
const MAX_QUAD_VERTS: usize = MAX_QUADS * VERTICES_PER_QUAD;
pub(crate) fn draw_quad(ctx: &mut Ctx, quad: DrawQuad) {
let i = ctx.gl.quads.count;
ctx.gl.quads.count += 1;
ctx.gl.quads.e[i] = quad;
}
pub fn init(ctx: &mut Ctx) {
let shape = &mut ctx.gl.quads.shape;
let (vs_src, fs_src) = match sg_api() {
SgApi::OpenGL33 => (
include_str!("quad.vert.glsl"),
include_str!("quad.frag.glsl"),
),
SgApi::Metal => (include_str!("quad.vs.metal"), include_str!("quad.fs.metal")),
_ => panic!("quad shaders not implemented for this platform"),
};
const WIDTH: usize = 4;
const HEIGHT: usize = 4;
let pixels_a: [u32; WIDTH] = [0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000];
let pixels_b: [u32; WIDTH] = [0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF];
let pixels: [[u32; WIDTH]; HEIGHT] = [pixels_a, pixels_b, pixels_a, pixels_b];
let debug_image = sg_make_image(
Some(&[(&pixels, (size_of_val(&pixels)) as i32)]),
&SgImageDesc {
width: WIDTH as i32,
height: HEIGHT as i32,
..Default::default()
},
);
shape.bindings.fs_images.push(debug_image);
shape.bindings.vertex_buffers.push(sg_make_buffer::<()>(
None,
&SgBufferDesc {
buffer_type: SgBufferType::VertexBuffer,
size: MAX_QUAD_VERTS * size_of::<QuadVert>(),
usage: SgUsage::Stream,
},
));
let mut indices: [[u16; INDICES_PER_QUAD]; MAX_QUADS] = [[0, 1, 2, 2, 1, 3]; MAX_QUADS];
for quad_i in 0..MAX_QUADS {
let offset = (quad_i * VERTICES_PER_QUAD) as u16;
for i in 0..INDICES_PER_QUAD {
indices[quad_i][i] += offset;
}
}
shape.bindings.index_buffer = sg_make_buffer(
Some(&indices),
&SgBufferDesc {
buffer_type: SgBufferType::IndexBuffer,
size: size_of_val(&indices),
usage: SgUsage::Immutable,
},
);
let shd = sg_make_shader(&SgShaderDesc {
attrs: vec![
SgShaderAttrDesc {
name: "in_position",
..Default::default()
},
SgShaderAttrDesc {
name: "in_uv",
..Default::default()
},
],
vs: SgShaderStageDesc {
source: Some(vs_src),
uniform_blocks: vec![std_uniform_block()],
..Default::default()
},
fs: SgShaderStageDesc {
source: Some(fs_src),
images: vec![SgShaderImageDesc {
name: "texture",
image_type: SgImageType::Texture2D,
..Default::default()
}],
..Default::default()
},
});
shape.pipeline = sg_make_pipeline(&SgPipelineDesc {
primitive_type: SgPrimitiveType::Triangles,
shader: shd,
index_type: SgIndexType::UInt16,
layout: SgLayoutDesc {
attrs: vec![
SgVertexAttrDesc {
offset: 0,
format: SgVertexFormat::Float3,
buffer_index: 0,
},
SgVertexAttrDesc {
offset: 12,
format: SgVertexFormat::Float2,
buffer_index: 0,
},
],
..Default::default()
},
blend: SgBlendState {
enabled: true,
dst_factor_rgb: SgBlendFactor::OneMinusSrcAlpha,
src_factor_rgb: SgBlendFactor::SrcAlpha,
..Default::default()
},
..Default::default()
});
}
pub fn present(ctx: &mut Ctx) {
let shape = &mut ctx.gl.quads.shape;
let mut vertices: [QuadCorners; MAX_QUADS] = [Default::default(); MAX_QUADS];
for quad_i in 0..ctx.gl.quads.count {
vertices[quad_i] = ctx.gl.quads.e[quad_i].corners;
}
sg_update_buffer(
shape.bindings.vertex_buffers[0],
&vertices,
(ctx.gl.quads.count * size_of::<QuadCorners>()) as i32,
);
sg_apply_pipeline(shape.pipeline);
sg_apply_bindings(&shape.bindings);
for i in 0..ctx.gl.quads.count {
let quad = &ctx.gl.quads.e[i];
let transform = quad.transform;
let mut mv = ctx.gl.view * transform;
mv.e[0][0] = transform.e[0][0];
mv.e[0][1] = 0.0;
mv.e[0][2] = 0.0;
mv.e[1][0] = 0.0;
mv.e[1][1] = transform.e[1][1];
mv.e[1][2] = 0.0;
mv.e[2][0] = 0.0;
mv.e[2][1] = 0.0;
mv.e[2][2] = transform.e[2][2];
let mvp = ctx.gl.proj * mv;
sg_apply_uniforms(SgShaderStage::Vertex, 0, &mvp, size_of::<M4>() as i32);
let img_id = quad.img_id;
shape.bindings.fs_images[0] = ctx.gl.images.e[img_id].e;
sg_apply_bindings(&shape.bindings);
sg_draw((i * INDICES_PER_QUAD) as i32, INDICES_PER_QUAD as i32, 1);
}
}