vrust 0.0.1

VRust game engine
use std::default::Default;
use std::ffi::CString;
use std::mem::transmute;
use std::ptr::null;
use std::sync::Arc;
use super::super::core::application::ApplicationTrait as CoreAppTrait;
use super::super::render::shader::{
    Id as ShaderId, Shader,
    shader_id_to_vertex_attributes,
};
use super::super::render::shader::manager::Manager as ShaderManager;
use super::super::render::vertex::Attribute as VertexAttribute;
use super::super::system::vulkan as vk;
use super::super::util::cache::Cacher;
use super::super::util::cell::DebugCell;
use super::descriptor::{
    Manager as DescriptorManager,
    Set as DescriptorSet,
};
use super::device::logical::Logical as LogicalDevice;
use super::engine::Engine;
use super::render_pass::RenderPass;

pub struct Layout {
    pub logical_device: Arc<LogicalDevice>,
    pub vk_data: vk::VkPipelineLayout,
    pub descriptor_set: Arc<DebugCell<DescriptorSet>>,
}
impl Layout {
    pub fn new(
        logical_device: Arc<LogicalDevice>,
        descriptor_set: Arc<DebugCell<DescriptorSet>>) -> Self {
        let mut vk_data = 0 as vk::VkPipelineLayout;
        let mut pipeline_layout_create_info = vk::VkPipelineLayoutCreateInfo::default();
        pipeline_layout_create_info.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
        pipeline_layout_create_info.setLayoutCount = 
            descriptor_set.borrow().layout.len() as u32;
        pipeline_layout_create_info.pSetLayouts =
            descriptor_set.borrow().layout.as_ptr();
        vulkan_check!(vk::vkCreatePipelineLayout(
            logical_device.vk_data,
            &pipeline_layout_create_info,
            null(),
            &mut vk_data,
        ));
        Layout {
            descriptor_set: descriptor_set,
            logical_device: logical_device,
            vk_data: vk_data,
        }
    }
}
impl Drop for Layout {
    fn drop(&mut self) {
        unsafe {
            vk::vkDestroyPipelineLayout(self.logical_device.vk_data, self.vk_data, null());
        }
    }
}

pub struct Cache {
    pub logical_device: Arc<LogicalDevice>,
    pub vk_data: vk::VkPipelineCache,
}

impl Cache {
    pub fn new(logical_device: Arc<LogicalDevice>) -> Self {
        let mut vk_data = 0 as vk::VkPipelineCache;
        let mut pipeline_cache_create_info = vk::VkPipelineCacheCreateInfo::default();
        pipeline_cache_create_info.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
        vulkan_check!(vk::vkCreatePipelineCache(
            logical_device.vk_data,
            &pipeline_cache_create_info,
            null(),
            &mut vk_data,
        ));
        Cache {
            logical_device: logical_device,
            vk_data: vk_data,
        }
    }
}

impl Drop for Cache {
    fn drop(&mut self) {
        unsafe {
            vk::vkDestroyPipelineCache(self.logical_device.vk_data, self.vk_data, null());
        }
    }
}

pub struct Pipeline {
    pub cache: Arc<Cache>,
    pub descriptor_set: Arc<DebugCell<DescriptorSet>>,
    pub layout: Layout,
    pub shader: Arc<DebugCell<Shader>>,
    pub render_pass: Arc<RenderPass>,
    pub vk_data: vk::VkPipeline,
}

impl Pipeline {
    fn new(
        manager: &mut Manager,
        sid: ShaderId,
    ) -> Self
    {
        let descriptor_set = manager.descriptor_manager.borrow_mut().get(sid);
        let device = manager.cache.logical_device.clone();
        let shader = manager.shader_manager.borrow_mut().get(sid, device.clone());
        let vertex_attrs = shader_id_to_vertex_attributes(sid);
        let layout = Layout::new(device, descriptor_set.clone());
        let render_pass = manager.render_pass.clone();
        let pipeline_cache = manager.cache.clone();
        let mut input_assembly_state = vk::VkPipelineInputAssemblyStateCreateInfo::default();
        input_assembly_state.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
        input_assembly_state.topology =
            vk::VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
        let mut rasterization_state = vk::VkPipelineRasterizationStateCreateInfo::default();
        rasterization_state.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
        rasterization_state.polygonMode = vk::VkPolygonMode::VK_POLYGON_MODE_FILL;
        rasterization_state.cullMode = vk::VkCullModeFlagBits::VK_CULL_MODE_FRONT_BIT as u32;
        rasterization_state.frontFace = vk::VkFrontFace::VK_FRONT_FACE_COUNTER_CLOCKWISE;
        rasterization_state.lineWidth = 1.0f32;
        let mut blend_attachment_state =
            vec![vk::VkPipelineColorBlendAttachmentState::default(); 1];
        blend_attachment_state[0].colorWriteMask = 0xF;
        let mut color_blend_state = vk::VkPipelineColorBlendStateCreateInfo::default();
        color_blend_state.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
        color_blend_state.attachmentCount = 1;
        color_blend_state.pAttachments = blend_attachment_state.as_ptr();
        let mut viewport_state = vk::VkPipelineViewportStateCreateInfo::default();
        viewport_state.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
        viewport_state.viewportCount = 1;
        viewport_state.scissorCount = 1;
        let dynamic_state_enables = [
            vk::VkDynamicState::VK_DYNAMIC_STATE_VIEWPORT,
            vk::VkDynamicState::VK_DYNAMIC_STATE_SCISSOR,
        ];
        let mut dynamic_state = vk::VkPipelineDynamicStateCreateInfo::default();
        dynamic_state.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
        dynamic_state.pDynamicStates = dynamic_state_enables.as_ptr();
        dynamic_state.dynamicStateCount = dynamic_state_enables.len() as u32;
        let mut depth_stencil_state = vk::VkPipelineDepthStencilStateCreateInfo::default();
        depth_stencil_state.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
        depth_stencil_state.depthTestEnable = 1;
        depth_stencil_state.depthWriteEnable = 1;
        depth_stencil_state.depthCompareOp = vk::VkCompareOp::VK_COMPARE_OP_LESS_OR_EQUAL;
        depth_stencil_state.depthBoundsTestEnable = 0;
        depth_stencil_state.back.failOp = vk::VkStencilOp::VK_STENCIL_OP_KEEP;
        depth_stencil_state.back.passOp = vk::VkStencilOp::VK_STENCIL_OP_KEEP;
        depth_stencil_state.back.compareOp = vk::VkCompareOp::VK_COMPARE_OP_ALWAYS;
        depth_stencil_state.stencilTestEnable = 0;
        depth_stencil_state.front = depth_stencil_state.back;
        let mut multisample_state = vk::VkPipelineMultisampleStateCreateInfo::default();
        multisample_state.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
        multisample_state.rasterizationSamples = vk::VkSampleCountFlagBits::VK_SAMPLE_COUNT_1_BIT;
        let mut vertex_input_binding = vk::VkVertexInputBindingDescription::default();
        vertex_input_binding.stride = 0;
        vertex_input_binding.inputRate = vk::VkVertexInputRate::VK_VERTEX_INPUT_RATE_VERTEX;
        let mut vertex_attributes =
            vec![vk::VkVertexInputAttributeDescription::default(); vertex_attrs.len()];
        for i in 0..vertex_attrs.len() {
            vertex_attributes[i].location = i as u32;
            vertex_attributes[i].offset = vertex_input_binding.stride;
            vertex_attributes[i].format = match vertex_attrs[i].clone() {
                VertexAttribute::Vec3F32 => {
                    vertex_input_binding.stride += 12;
                    vk::VkFormat::VK_FORMAT_R32G32B32_SFLOAT
                }
                VertexAttribute::Vec2F32 => {
                    vertex_input_binding.stride += 8;
                    vk::VkFormat::VK_FORMAT_R32G32_SFLOAT
                }
            }
        }
        let mut vertex_input_state = vk::VkPipelineVertexInputStateCreateInfo::default();
        vertex_input_state.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
        vertex_input_state.vertexBindingDescriptionCount = 1;
        vertex_input_state.pVertexBindingDescriptions = &vertex_input_binding;
        vertex_input_state.vertexAttributeDescriptionCount = vertex_attributes.len() as u32;
        vertex_input_state.pVertexAttributeDescriptions = vertex_attributes.as_ptr();
        let stage_name = CString::new("main").unwrap();
        let stages_count = shader.borrow().get_stages_count();
        let mut shader_stages = vec![vk::VkPipelineShaderStageCreateInfo::default(); stages_count];
        for i in 0..stages_count {
            shader_stages[i].sType =
                vk::VkStructureType::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
            shader_stages[i].stage = match i {
                0 => vk::VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT,
                1 => vk::VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT,
                n @ _ => {
                    logf!("Stage {} is not implemented yet!", n);
                }
            };
            shader_stages[i].module = shader.borrow().get_stage(i).module;
            shader_stages[i].pName = stage_name.as_ptr();
        }
        let mut pipeline_create_info = vk::VkGraphicsPipelineCreateInfo::default();
        pipeline_create_info.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
        pipeline_create_info.layout = layout.vk_data;
        pipeline_create_info.renderPass = render_pass.vk_data;
        pipeline_create_info.stageCount = shader_stages.len() as u32;
        pipeline_create_info.pStages = shader_stages.as_ptr();
        pipeline_create_info.pVertexInputState = &vertex_input_state;
        pipeline_create_info.pInputAssemblyState = &input_assembly_state;
        pipeline_create_info.pRasterizationState = &rasterization_state;
        pipeline_create_info.pColorBlendState = &color_blend_state;
        pipeline_create_info.pMultisampleState = &multisample_state;
        pipeline_create_info.pViewportState = &viewport_state;
        pipeline_create_info.pDepthStencilState = &depth_stencil_state;
        pipeline_create_info.renderPass = render_pass.vk_data;
        pipeline_create_info.pDynamicState = &dynamic_state;
        let mut vk_data = 0 as vk::VkPipeline;
        vulkan_check!(vk::vkCreateGraphicsPipelines(
            pipeline_cache.logical_device.vk_data,
            pipeline_cache.vk_data,
            1,
            &pipeline_create_info,
            null(),
            &mut vk_data,
        ));
        Pipeline {
            cache: pipeline_cache.clone(),
            descriptor_set: descriptor_set,
            layout: layout,
            shader: shader,
            render_pass: render_pass.clone(),
            vk_data: vk_data,
        }
    }

    pub fn get_shader(&self) -> &Arc<DebugCell<Shader>> {
        &self.shader
    }
}

impl Drop for Pipeline {
    fn drop(&mut self) {
        unsafe {
            vk::vkDestroyPipeline(self.layout.logical_device.vk_data, self.vk_data, null());
        }
    }
}

pub struct Manager {
    pub cache: Arc<Cache>,
    pub cached: Cacher<ShaderId, Pipeline>,
    pub descriptor_manager: Arc<DebugCell<DescriptorManager>>,
    pub render_pass: Arc<RenderPass>,
    pub shader_manager: Arc<DebugCell<ShaderManager>>,
}

impl Manager {
    pub fn new<CoreApp>(
        engine: &Engine<CoreApp>
    ) -> Self 
    where
        CoreApp: CoreAppTrait {
        let device = engine.logical_device.as_ref().unwrap().clone();
        Manager {
            render_pass: engine.render_pass.as_ref().unwrap().clone(),
            cache: Arc::new(Cache::new(device.clone())),
            descriptor_manager: Arc::new(DebugCell::new(DescriptorManager::new(
                engine.buffer_manager.as_ref().unwrap().clone()))),
            cached: Cacher::new(),
            shader_manager: engine.os_app.asset_manager.shader_manager.clone(),
        }
    }

    pub fn get<'a>(&'a mut self, id: ShaderId) -> Arc<DebugCell<Pipeline>> {
        let self_ptr: &'static usize = unsafe { transmute(&self) };
        let self2 = *self_ptr;
        self.cached.get(id, &|| { 
            let self2: &'a mut Manager = unsafe { transmute(self2) };
            self2.create_pipeline(id) 
        })
    }

    fn create_pipeline(&mut self, id: ShaderId) -> Arc<DebugCell<Pipeline>> {
        Arc::new(DebugCell::new(Pipeline::new(self, id)))
    }
}