#include "Models.hpp"

using namespace render::vk;

std::unique_ptr<Shape> Shape::Create(const std::vector<glm::vec3>& vertices) {
    vk::Buffer::info tmp;
    data_view view(vertices);
    auto mem = createBuffer(view.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, view, tmp);
    return std::unique_ptr<Shape>(new Shape(tmp.ref, std::move(mem), vertices.size()));
}

std::unique_ptr<ColoredShape> ColoredShape::Create(const std::vector<glm::vec3>& vert, const std::vector<glm::vec4>& cols) {
    assert(vert.size() == cols.size());
    std::vector<Vertex> vertices;
    vertices.reserve(vert.size());
    for (size_t i = 0; i < vert.size(); i++) {
        vertices.push_back(Vertex{vert.at(i), cols.at(i)});
    }

    vk::Buffer::info tmp;
    data_view view(vertices);
    auto mem = createBuffer(view.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, view, tmp);
    return std::unique_ptr<ColoredShape>(new ColoredShape(vertices.size(), tmp.ref, std::move(mem)));
}

std::unique_ptr<Model> Model::Create(const Data& data) {
    std::vector<vk::Buffer::info> tmp;
    data_view vertices(data.vertices);
    data_view indices(data.indices);
    auto mem = createBuffers({{vertices.size, Usage::VERTEX, vertices}, {indices.size, Usage::INDEX, indices}}, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, tmp);
    return std::unique_ptr<Model>(new Model(data.indices.size(), tmp.at(0).ref, tmp.at(1).ref, std::move(mem)));
}
std::unique_ptr<LodModel> LodModel::Create(const LodData& data) {
    std::vector<vk::Buffer::info> tmp;
    data_view vertices(data.first.vertices);
    data_view indices(data.first.indices);
    auto mem = createBuffers({{vertices.size, Usage::VERTEX, vertices}, {indices.size, Usage::INDEX, indices}}, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, tmp);
    return std::unique_ptr<LodModel>(new LodModel(data.first.indices.size(), data.second, tmp.at(0).ref, tmp.at(1).ref, std::move(mem)));
}

std::unique_ptr<render::Model> createModelVk(const Model::Data& data) {
    return Model::Create(data);
}
void Model::MakeDefault() {
    render::Model::createFunc = createModelVk;
}

std::unique_ptr<render::LodModel> createLodModelVk(const LodModel::LodData& data) {
    return LodModel::Create(data);
}
void LodModel::MakeDefault() {
    render::LodModel::createFunc = createLodModelVk;
}