// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Also licensed under MIT license, at your choice.

//! A simple application to run a compute shader.

use std::{fs::File, io::BufWriter};

use engine::Engine;

use wgpu::{Device, Limits, Queue};

mod debug;
mod engine;
mod pico_svg;
mod ramp;
mod render;
mod shaders;
mod test_scene;

async fn run() -> Result<(), Box<dyn std::error::Error>> {
    let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY);
    let adapter = instance.request_adapter(&Default::default()).await.unwrap();
    let features = adapter.features();
    let mut limits = Limits::default();
    limits.max_storage_buffers_per_shader_stage = 16;
    let (device, queue) = adapter
        .request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                features: features & wgpu::Features::TIMESTAMP_QUERY,
                limits,
            },
            None,
        )
        .await?;
    let mut engine = Engine::new();
    do_render(&device, &queue, &mut engine).await?;

    Ok(())
}

fn dump_buf(buf: &[u32]) {
    for (i, val) in buf.iter().enumerate() {
        if *val != 0 {
            let lo = val & 0x7fff_ffff;
            if lo >= 0x3000_0000 && lo < 0x5000_0000 {
                println!("{}: {:x} {}", i, val, f32::from_bits(*val));
            } else {
                println!("{}: {:x}", i, val);
            }
        }
    }
}

async fn do_render(
    device: &Device,
    queue: &Queue,
    engine: &mut Engine,
) -> Result<(), Box<dyn std::error::Error>> {
    #[allow(unused)]
    let shaders = shaders::init_shaders(device, engine)?;
    let full_shaders = shaders::full_shaders(device, engine)?;
    let scene = test_scene::gen_test_scene();
    //test_scene::dump_scene_info(&scene);
    //let (recording, buf) = render::render(&scene, &shaders);
    let (recording, buf) = render::render_full(&scene, &full_shaders);
    let downloads = engine.run_recording(&device, &queue, &recording)?;
    let mapped = downloads.map();
    device.poll(wgpu::Maintain::Wait);
    let buf = mapped.get_mapped(buf).await?;

    if false {
        dump_buf(bytemuck::cast_slice(&buf));
    } else {
        let file = File::create("image.png")?;
        let w = BufWriter::new(file);
        let mut encoder = png::Encoder::new(w, 1024, 1024);
        encoder.set_color(png::ColorType::Rgba);
        let mut writer = encoder.write_header()?;
        writer.write_image_data(&buf)?;
    }
    Ok(())
}

fn main() {
    pollster::block_on(run()).unwrap();
}
