
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_mut)]

extern crate cgmath;
extern crate image;
extern crate nalgebra as na;
extern crate rand;
extern crate sfml;
extern crate time;
extern crate hprof;

use sfml::system::*;
use vulkano::sync;
use crate::timer::Timer;
use vulkano::instance::{Instance};
use vulkano::sync::GpuFuture;
use winit::{EventsLoop, WindowBuilder, WindowEvent, Event, DeviceEvent, VirtualKeyCode, ElementState};
use winit::dpi::LogicalSize;
use vulkano_win::VkSurfaceBuild;
use sprite::Sprite;
use crate::compu_state::CompuState;
use crate::compu_frame::CompuFrame;
use crate::compu_sprite::CompuSprite;
use crate::compu_kernel::CompuKernel;
use crate::compu_buffer::CompuBuffers;
use crate::util::load_raw;
use crate::canvas_frame::CanvasFrame;

mod util;
mod timer;
mod input;
mod vkprocessor;
mod vertex_2d;
mod vertex_3d;
mod sprite;

mod canvas;
mod canvas_frame;
mod canvas_shader;
mod canvas_buffer;

mod compu_state;
mod compu_frame;
mod compu_sprite;
mod compu_kernel;
mod compu_buffer;


/*

Alright, what the hell do I do next...

Canvas works, but I want to use CPU accessible buffer instead of immutable buffer
    I think it would be faster if we reuse fewer oversized buffers than vis versa
*/

fn main() {

    hprof::start_frame();

    let q1 = hprof::enter("setup");

    let instance = {
        let extensions = vulkano_win::required_extensions();
        Instance::new(None, &extensions, None).unwrap()
    };

    let mut events_loop = EventsLoop::new();
    let mut surface = WindowBuilder::new()
        .with_dimensions(LogicalSize::from((800, 800)))
        .build_vk_surface(&events_loop, instance.clone()).unwrap();
    let mut window = surface.window();

    let mut processor = vkprocessor::VkProcessor::new(&instance, &surface);
    {
        let g = hprof::enter("vulkan preload");
        processor.create_swapchain(&surface);

        processor.preload_kernels();
        processor.preload_shaders();
        processor.preload_textures();
    }

    let q2 = hprof::enter("Game Objects");

    let mut timer = Timer::new();
    let mut frame_future = Box::new(sync::now(processor.device.clone())) as Box<dyn GpuFuture>;

    let step_size: f32 = 0.005;
    let mut elapsed_time: f32;
    let mut delta_time: f32;
    let mut accumulator_time: f32 = 0.0;
    let mut current_time: f32 = timer.elap_time();

    let mut mouse_xy = Vector2i::new(0,0);

    let sprite = Sprite::new_with_color((0.,0.), (0.1,0.1), (1.,0.,0.,1.));
    let sprite2 = Sprite::new_with_color((-1.,-0.5), (0.1,0.1), (0.,1.,0.,1.));

    let compu_sprite1 = CompuSprite::new((-1.,-0.5), (0.1,0.1),
                                         // This swap image needs to match the size of the compute
                                         processor.new_swap_image((720, 756)));

    let image_data = load_raw(String::from("funky-bird.jpg"));
    let compute_buffer = processor.new_compute_buffer(image_data.0, image_data.1, 4);

    let compute_kernel = processor.get_kernel_handle(String::from("simple-edge.compute"))
        .expect("Can't find that kernel");

    let handle = processor.get_texture_handle(String::from("funky-bird.jpg")).unwrap();

    let sprite3 = Sprite::new_with_texture((0.3, 0.5), (0.1,0.1), handle.clone());

    drop(q2);
    drop(q1);

    let l = hprof::enter("Loop");

    let mut exit = false;

    while let Some(p) = window.get_position() {
        elapsed_time = timer.elap_time();
        delta_time = elapsed_time - current_time;
        current_time = elapsed_time;
        if delta_time > 0.02 {
            delta_time = 0.02;
        }
        accumulator_time += delta_time;

        while (accumulator_time - step_size) >= step_size {
            accumulator_time -= step_size;
        }

        //  println!("{}", delta_time);
        events_loop.poll_events(|event| {
            match event {
                Event::WindowEvent { event: WindowEvent::CloseRequested, .. } =>
                    {
                        exit = true;
                    },
                Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
                    processor.recreate_swapchain(&surface);
                },
                Event::DeviceEvent { event: DeviceEvent::Key(keyboard_input), .. } => {
                    match keyboard_input.virtual_keycode.unwrap() {
                        VirtualKeyCode::A => {
                            if keyboard_input.state == ElementState::Pressed {
                                // processor.save_edges_image();
                            }
                        }
                        _ => ()
                    }
                },
//                Event::DeviceEvent { event: DeviceEvent::Button(mouse_input), .. } => {
//                    mouse_xy.x
//                },
                _ => ()
            }
        });

        if exit {
            break;
        }

        let mut compu_frame = CompuFrame::new();
       // compu_frame.add(compute_buffer.clone(), compute_kernel.clone());
       // compu_frame.add_with_image_swap(compute_buffer.clone(), compute_kernel.clone(), &compu_sprite1);

        let mut canvas = CanvasFrame::new();
        canvas.draw(&sprite);
        //canvas.draw(&sprite2);
        //canvas.draw(&sprite3);
        //canvas.draw(&compu_sprite1);
        {
            let g = hprof::enter("Run");
            (frame_future) = processor.run(&surface, frame_future,
                                           canvas,
                                           compu_frame);
        }
    }

    drop(l);

    hprof::end_frame();
    hprof::profiler().print_timing();
}

































