
#![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;

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::canvas::CanvasFrame;
use crate::compu_wip::{CompuSprite, ComputeFrame, CompuBuffers, CompuState};
use crate::util::compute_image::ComputeImage;

mod util;
mod slider;
mod timer;
mod input;
mod vkprocessor;
mod button;
mod vertex_2d;
mod vertex_3d;
mod sprite;
mod canvas;
mod compu_wip;

/*

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

Texturing is broken


8/13 :
Okay. So I've decided to keep compute image and compute kernel in their own 'canvas'
Canvas still needs to be cleaned up. I would like a contract type of thing going on
with the loaded textures. Where you need to request a texture_handle from vkprocessor
to attach to a Sprite. The problem is kinda what I do with the swap image. I only need
a reference to it and the general buffer coming back from the compute kernel. I could
continue to hold the image in the Canvas, and just give out an ID when a Sprite wants it.

The issue here is that kinda muddles the API a bit. I would need to do something like




8/27 :

But I dont always want to draw a computable...
Which I guess is fine. I could have another datatype implement computable

CompuSprite
    -> Drawable, Computable
TxturSprite
    -> Drawable
ColorSprite
    -> Drawable

Computable
    -> get pipeline id (need to assoc. compiled kernel)
    -> 

Drawable
    -> get texture id
    -> get image id
    -> get color
    -> get vertices

Computable
    get data
    set data?
    set settings?
    get swap image id

Drawable:
    get vertices
    get color
    get texture id

    get descriptor set

need some sort of computable interface for the Sprite. It already has drawable
so why not computable


Pipeline is the compiled kernel/shader
    in the shaders case, it has the vertex definition, constants, and the compiled code
    in kernel, its just constants and compiled code

Descriptor set holds the buffers which we will pass to the pipeline
    rw and settings buffers for the compu
    texture buffer for the textured
    image buffer for the image (swap)


Need to have certain stages in the building of the command buffer.
(Z level????)

1.) computes
2.) compute swaps
3.) render images
4.) render textures
5.) render solids

So to start with we need to know the compute data which we want to run and the kernel we want to run it on. We combine the buffers along with the pipeline generated from the compiled kernel and get
the descriptor set. We also need the XY for the compute run


CompuSprite
    holds the image handle
    impl's drawable
CompuBuffers
    holds the buffer handles
    creates the descriptor set?
CompuState
    holds the compute buffers
    holds the compute kernels
ComputeFrame
    preserves order of entered elements
    holds compute buffer ids and their tied kernel ids
    holds compute buffer ids, their swap image ids and their kernel ids
    holds compute buffer ids, their swap buffer ids, and their kernel ids

// Creates the compu sprite with an associated image stored in canvas
let compu_sprite    = CompuSprite::new(&mut canvas)

// Compiles and stores the kernel in CompuState
// Returns the handle to the stored kernel (immutable at this state probably)
let KernelID        = ComputeState.new_kernel(kernel_path)

// Pushes the data to the GPU and returns a handle
let ComputeBuffer_1 = ComputeState.new_compute_buffer(input_data, input_settings)

// One by one, assign the buffers to their kernels for run
ComputeFrame.add(ComputeBuffer_1, KernelID)

// If the buffer needs to be swapped in first
ComputeFrame.add_with_buffer_swap(ComputeBuffer_1, ComputeBuffer_2, KernelID)

// If the buffer should be swappd out to an image after it computes
ComputeFrame.add_with_image_swap(ComputeBuffer_1, compu_sprite, KernelID)

CompuState.compute()


// Full example if API:

CompuFrame.add(ComputeBuffer1ID, Kernel1ID)
CompuFrame.add(ComputeBuffer2ID, Kernel2ID)
CompuFrame.add_with_image_swap(ComputeBuffer1ID, CompuSprite, KernelID)

CanvasFrame.draw(Sprite1)
CanvasFrame.draw(Sprite2)
CanvasFrame.draw(CompuSprite)

vkprocessor.run(CanvasFrame, CompuFrame)




*/


fn main() {

    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);
//    processor.compile_kernel(String::from("simple-edge.compute"));
//    processor.load_compute_image(String::from("background.jpg"));
//    processor.load_textures(String::from("funky-bird.jpg"));
    processor.create_swapchain(&surface);

    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.));

    /*
        I need to get the image id from the CompuState
        But the CompuState is owned by the vkprocessor I think...

        I will also need to get the texture id
    */



    let compu_sprite1 = CompuSprite::new((-1.,-0.5), (0.1,0.1), processor.new_swap_image((300, 300)));

    let image_data = ComputeImage::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");

    


    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);

        let mut exit = false;
        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 {
            return;
        }

        let mut compu_frame = ComputeFrame::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(&compu_sprite1);

        (frame_future) = processor.run(&surface, frame_future,
                                       canvas,
                                       compu_frame);
    }
}

































