use std::f32::consts;
use std::error::Error;
use image;
use bytemuck;
use glam;
use wgpu;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Vertex {
pub pos: [f32; 4],
pub norm: [f32; 4],
pub col: [u32; 4],
pub tex_coord: [f32; 2],
pub ix: u32
}
pub fn vtx(pos: [i8; 3], tc: [i8; 2]) -> Vertex {
Vertex{
pos: [pos[0] as f32, pos[1] as f32, pos[2] as f32, 1.0],
norm: [pos[0] as f32, pos[1] as f32, pos[2] as f32, 1.0],
col: (0..4).map(|i| if i < 3 { (pos[i] + 2) as u32 * 255 / 4 } else { 255 }
).collect::<Vec<_>>().try_into().unwrap(),
tex_coord: [tc[0] as f32, tc[1] as f32],
ix: 0
}
}
pub fn vtf(pos: [i8; 3], tc: [f32; 2]) -> Vertex {
Vertex{
pos: [pos[0] as f32, pos[1] as f32, pos[2] as f32, 1.0],
norm: [pos[0] as f32, pos[1] as f32, pos[2] as f32, 1.0],
col: (0..4).map(|i| if i < 3 { (pos[i] + 2) as u32 * 255 / 4 } else { 255 }
).collect::<Vec<_>>().try_into().unwrap(),
tex_coord: tc,
ix: 0
}
}
#[derive(Debug)]
pub struct FaceInf {
pub nfaces: u64,
pub il: Vec<u64>,
pub tf: fn ((usize, usize, usize)) -> usize
}
#[derive(Debug)]
pub struct VIP {
pub vs: wgpu::Buffer,
pub is: wgpu::Buffer,
pub p: FaceInf
}
pub fn locscale(o: &[f32; 3], scale: f32, vi: (Vec<Vertex>, Vec<u16>, FaceInf))
-> (Vec<Vertex>, Vec<u16>, FaceInf) {
(
vi.0.into_iter().enumerate().map(
|(j, Vertex{pos: p, col: c, norm: n, tex_coord: tc, ix: _})| {
Vertex{
pos: p.iter().enumerate().map(|(i, &v)| {
if i < 3 { o[i] + v * scale } else { v } }).collect::<Vec<_>>().try_into().unwrap(),
col: c,
norm: n,
tex_coord: tc,
ix: j as u32
}
}).collect(),
vi.1,
vi.2
)
}
pub fn create_vertices_cube_6_textures(
tf: fn ((usize, usize, usize)) -> usize)
-> (Vec<Vertex>, Vec<u16>, FaceInf) {
let vertex_data = [ vtx([1, -1, 1], [0, 1]),
vtx([1, -1, -1], [1, 1]),
vtx([1, 1, -1], [1, 0]),
vtx([1, 1, 1], [0, 0]),
vtx([-1, -1, 1], [0, 1]),
vtx([-1, 1, 1], [1, 1]),
vtx([-1, 1, -1], [1, 0]),
vtx([-1, -1, -1], [0, 0]),
vtx([1, 1, -1], [0, 1]),
vtx([-1, 1, -1], [1, 1]),
vtx([-1, 1, 1], [1, 0]),
vtx([1, 1, 1], [0, 0]),
vtx([1, -1, -1], [0, 1]),
vtx([1, -1, 1], [1, 1]),
vtx([-1, -1, 1], [1, 0]),
vtx([-1, -1, -1], [0, 0]),
vtx([-1, 1, 1], [0, 1]),
vtx([-1, -1, 1], [1, 1]),
vtx([1, -1, 1], [1, 0]),
vtx([1, 1, 1], [0, 0]),
#[cfg(interrupt_vertex)] vtx([0, 2, 0], [0, 1]),
#[cfg(interrupt_vertex)] vtx([2, 2, 0], [1, 1]),
#[cfg(interrupt_vertex)] vtx([2, 0, 0], [1, 0]),
#[cfg(interrupt_vertex)] vtx([0, 0, 0], [0, 0]),
vtx([-1, 1, -1], [0, 1]),
vtx([1, 1, -1], [1, 1]),
vtx([1, -1, -1], [1, 0]),
vtx([-1, -1, -1], [0, 0])
];
let index_data: &[u16] = &[
0, 1, 3, 2, 3, 1, 4, 5, 7, 6, 7, 5, 8, 9, 11, 10, 11, 9, 12, 13, 15, 14, 15, 13, 16, 17, 19, 18, 19, 17,
#[cfg(interrupt_vertex)] 24,
#[cfg(interrupt_vertex)] 25,
#[cfg(interrupt_vertex)] 27,
#[cfg(interrupt_vertex)] 26,
#[cfg(interrupt_vertex)] 27,
#[cfg(interrupt_vertex)] 25,
20, 21, 23, 22, 23, 21 ];
let nfaces = index_data.len() as u64 / 6;
(vertex_data.to_vec(), index_data.to_vec(), FaceInf{
nfaces,
il: (0..=nfaces).map(|i| i * 6).collect(),
tf: tf}) }
pub fn create_vertices_cube_expansion_plan(
tf: fn ((usize, usize, usize)) -> usize)
-> (Vec<Vertex>, Vec<u16>, FaceInf) {
let vertex_data = [ vtf([1, -1, 1], [0.25, 0.0]),
vtf([1, -1, -1], [0.25, 0.25]),
vtf([1, 1, -1], [0.5, 0.25]),
vtf([1, 1, 1], [0.5, 0.0]),
vtf([-1, -1, 1], [0.25, 0.75]),
vtf([-1, 1, 1], [0.5, 0.75]),
vtf([-1, 1, -1], [0.5, 0.5]),
vtf([-1, -1, -1], [0.25, 0.5]),
vtf([1, 1, -1], [0.5, 0.25]),
vtf([-1, 1, -1], [0.75, 0.25]),
vtf([-1, 1, 1], [0.75, 0.0]),
vtf([1, 1, 1], [0.5, 0.0]),
vtf([1, -1, -1], [0.0, 0.5]),
vtf([1, -1, 1], [0.0, 0.75]),
vtf([-1, -1, 1], [0.25, 0.75]),
vtf([-1, -1, -1], [0.25, 0.5]),
vtf([-1, 1, 1], [0.5, 0.75]),
vtf([-1, -1, 1], [0.25, 0.75]),
vtf([1, -1, 1], [0.25, 1.0]),
vtf([1, 1, 1], [0.5, 1.0]),
vtf([-1, 1, -1], [0.5, 0.5]),
vtf([1, 1, -1], [0.5, 0.25]),
vtf([1, -1, -1], [0.25, 0.25]),
vtf([-1, -1, -1], [0.25, 0.5])
];
let index_data: &[u16] = &[
0, 1, 3, 2, 3, 1, 4, 5, 7, 6, 7, 5, 8, 9, 11, 10, 11, 9, 12, 13, 15, 14, 15, 13, 16, 17, 19, 18, 19, 17, 20, 21, 23, 22, 23, 21 ];
let nfaces = index_data.len() as u64 / 6;
(vertex_data.to_vec(), index_data.to_vec(), FaceInf{
nfaces,
il: (0..=nfaces).map(|i| i * 6).collect(),
tf: tf}) }
pub fn load_texels(fname: &str)
-> Result<((u32, u32, u32, u32), Vec<u8>), Box<dyn Error>> {
let im = image::open(fname)?; let (h, w) = (im.height(), im.width());
let buf = im.into_rgba8().to_vec(); let bytes_per_row = buf.len() as u32 / h; let d = bytes_per_row / w; println!("{} {} {} {} {}", h, w, d, bytes_per_row, buf.len());
Ok(((h, w, d, bytes_per_row), buf))
}
pub fn create_texels_rgba(size: usize, cols4u: &Vec<&[u8; 4]>)
-> ((u32, u32, u32, u32), Vec<u8>) {
let mut hwd = (size as u32, size as u32, 4, 0);
hwd.3 = hwd.2 * hwd.1;
(hwd, (0..(hwd.3 * hwd.0) as usize).map(|id| {
let bpr = 256 * 4;
let v = id / bpr;
let w = id % bpr;
let u = w / 4;
(if v < 128 {
if u < 128 { cols4u[0] } else { cols4u[1] }
} else {
if u < 128 { cols4u[2] } else { cols4u[3] }
})[w % 4]
}).collect())
}
pub fn create_texels_mandelbrot_4c(size: usize, col4f: &[f32; 4])
-> ((u32, u32, u32, u32), Vec<u8>) {
let mut hwd = (size as u32, size as u32, 4, 0);
hwd.3 = hwd.2 * hwd.1;
(hwd, (0..(hwd.3 * hwd.0) as usize).map(|id| { let c = id / 4;
let cx = 3.0 * (c % size) as f32 / (size - 1) as f32 - 2.0;
let cy = 2.0 * (c / size) as f32 / (size - 1) as f32 - 1.0;
let (mut x, mut y, mut count) = (cx, cy, 0);
while count < 0xFF && x * x + y * y < 4.0 {
let old_x = x;
x = x * x - y * y + cx;
y = 2.0 * old_x * y + cy;
count += 1;
}
((1.0 - (count as f32 / 255.0) * col4f[id % 4]) * 255.0) as u8
}).collect())
}
#[derive(Debug)]
pub struct YRP {
pub yaw: f32,
pub roll: f32,
pub pitch: f32,
pub tick: u64
}
#[derive(Debug)]
pub struct CameraAngle {
pub pos: glam::Vec3,
pub lookat: glam::Vec3,
pub top: glam::Vec3
}
impl CameraAngle {
pub fn new(pos: glam::Vec3, lookat: glam::Vec3, top: glam::Vec3) -> Self {
CameraAngle{pos, lookat, top}
}
pub fn from_yrp(yrp: &YRP) -> Self {
log::warn!("y:{} r:{} p:{}", yrp.yaw, yrp.roll, yrp.pitch);
let cs = |t: f32| {let r = t * 3.14159 / 180.0; (r.cos(), r.sin())};
let (yc, ys) = cs(yrp.yaw);
let (rc, rs) = cs(yrp.roll);
let (pc, ps) = cs(yrp.pitch);
let (tc, _ts) = cs(yrp.tick as f32);
let radius = (tc + 2.0) * 2.0; let (radius_c, radius_s) = (radius * pc, radius * ps);
let pos = glam::Vec3::new(radius_c * yc, radius_c * ys, radius_s);
let lookat = glam::Vec3::ZERO;
let top = glam::Vec3::new(yc * rs, -ys * rs, rc); log::warn!("{:5.2} {:5.2} {:5.2} {:5.2} {:5.2} {:5.2}",
pos.x, pos.y, pos.z, top.x, top.y, top.z);
CameraAngle{pos, lookat, top}
}
pub fn generate_mvp(&self, aspect_ratio: f32) -> glam::Mat4 {
let projection = glam::Mat4::perspective_rh(
consts::FRAC_PI_4, aspect_ratio, 1.0, 10.0);
let view = glam::Mat4::look_at_rh(self.pos, self.lookat, self.top); projection * view
}
}
#[repr(C)]
#[derive(Debug)]
pub struct TexSZ {
pub w: u32,
pub h: u32,
pub ext: [u32; 2]
}
impl AsRef<[u32; 4]> for TexSZ {
fn as_ref(&self) -> &[u32; 4] {
unsafe {
std::slice::from_raw_parts(&self.w as *const u32, 4).try_into().unwrap()
}
}
}
#[derive(Debug)]
pub struct TextureBindGroup {
pub group: wgpu::BindGroup,
pub sz: TexSZ,
pub buf: wgpu::Buffer
}
#[derive(Debug)]
pub struct WG {
pub vips: Vec<VIP>,
pub bind_group: Vec<TextureBindGroup>,
pub bg: usize,
pub mvp: glam::Mat4,
pub uniform_buf: wgpu::Buffer,
pub pipeline: wgpu::RenderPipeline,
pub pipeline_wire: Option<wgpu::RenderPipeline>,
pub wire: bool
}
macro_rules! draw_vip {
($self: ident, $rp: ident, // self, wgpu::RenderPass,
$vbuf: ident, ($vs: expr, $ve: expr), $ibuf: ident, ($is: expr, $ie: expr), $tid: expr, $icnt: expr) => { $rp.push_debug_group("Prepare data for draw.");
$rp.set_pipeline(&$self.pipeline);
$rp.set_bind_group(0, &$self.bind_group[$tid].group, &[]);
$rp.set_index_buffer($ibuf.slice($is..$ie), wgpu::IndexFormat::Uint16);
$rp.set_vertex_buffer(0, $vbuf.slice($vs..$ve));
$rp.pop_debug_group();
$rp.insert_debug_marker("Draw!");
if !&$self.wire {
$rp.draw_indexed(0..$icnt, 0, 0..1);
}
if let Some(ref pipe) = &$self.pipeline_wire {
$rp.set_pipeline(pipe);
$rp.draw_indexed(0..$icnt, 0, 0..1);
}
}
}
impl WG {
pub fn update_matrix(
&mut self,
config: &wgpu::SurfaceConfiguration,
_device: &wgpu::Device,
queue: &wgpu::Queue,
yrp: &YRP) {
self.mvp = CameraAngle::from_yrp(yrp).generate_mvp(
config.width as f32 / config.height as f32);
queue.write_buffer(&self.uniform_buf, 0,
bytemuck::cast_slice(self.mvp.as_ref())); }
pub fn draw(
&mut self,
view: &wgpu::TextureView,
device: &wgpu::Device,
queue: &wgpu::Queue) {
device.push_error_scope(wgpu::ErrorFilter::Validation);
let mut encoder = device.create_command_encoder(
&wgpu::CommandEncoderDescriptor{label: None});
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor{
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment{
view,
resolve_target: None,
ops: wgpu::Operations{
load: wgpu::LoadOp::Clear(
wgpu::Color{r: 0.1, g: 0.2, b: 0.3, a: 1.0}),
store: true
}
})],
depth_stencil_attachment: None
});
for VIP{vs: vertex_buf, is: index_buf, p: fi} in &self.vips {
for i in 0..fi.nfaces {
let isz = std::mem::size_of::<u16>() as u64; let ip_s = fi.il[i as usize] * isz; let ip_e = fi.il[i as usize + 1] * isz; let ipf = (ip_e - ip_s) / isz;
let vsz = std::mem::size_of::<Vertex>() as u64; let vpf = (vertex_buf.size() / vsz) / fi.nfaces; let (vp_s, vp_e) = (0, fi.nfaces * vpf * vsz);
let tid = (fi.tf)((i as usize, self.bg, self.bind_group.len()));
draw_vip!(self, rpass,
vertex_buf, (vp_s, vp_e), index_buf, (ip_s, ip_e),
tid, ipf as u32);
}
}
drop(rpass); queue.submit(Some(encoder.finish()));
}
}