text: #include <iostream>
  #include <cstring>
  #include <glm/mat4x4.hpp>
  #include <glm/gtx/transform.hpp>
  #include "VK_UniformBuffer.h"
  #include "VK_Context.h"
  #include "VK_Image.h"
  #include "VK_Texture.h"
  #include "VK_Pipeline.h"
  #include "VK_DynamicState.h"
  #include "VK_CommandPool.h"
  #include <fstream>
  
  using namespace std;
  
  const std::vector<float> vertices = {
      -0.5f, -0.5, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.05f, 0.0f,
          0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
          0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.5f,
          -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.5f, 1.5f
      };
  
  const std::vector<uint32_t> indices = {
      0, 1, 2, 2, 3, 0
  };
  
  VK_Context *context = nullptr;
  VK_Pipeline *pipeline = nullptr;
  
  uint32_t updateUniformBufferData(char *&data, uint32_t size)
  {
      glm::mat4 model = glm::identity<glm::mat4>();
      memcpy(data, &model[0][0], size);
      return sizeof(model);
  }
  
  void onFrameSizeChanged(int width, int height)
  {
      pipeline->getDynamicState()->applyDynamicViewport({0, 0, (float)width, (float)height, 0, 1});
  }
  
  int main()
  {
      VK_ContextConfig config;
      config.debug = true;
      config.name = "Texure";
  
      context = createVkContext(config);
      context->createWindow(480, 480, true);
      context->setOnFrameSizeChanged(onFrameSizeChanged);
  
      VK_Context::VK_Config vkConfig;
      context->initVulkanDevice(vkConfig);
  
      auto shaderSet = context->createShaderSet();
      shaderSet->addShader("../shader/texture/vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
      shaderSet->addShader("../shader/texture/frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
  
      shaderSet->appendVertexAttributeDescription(0, sizeof (float) * 3, VK_FORMAT_R32G32B32_SFLOAT, 0);
      shaderSet->appendVertexAttributeDescription(1, sizeof (float) * 4, VK_FORMAT_R32G32B32A32_SFLOAT,
              sizeof(float) * 3);
      shaderSet->appendVertexAttributeDescription(2, sizeof (float) * 2, VK_FORMAT_R32G32_SFLOAT,
              sizeof(float) * 7);
  
      shaderSet->appendVertexInputBindingDescription(9 * sizeof(float), 0, VK_VERTEX_INPUT_RATE_VERTEX);
  
      VkDescriptorSetLayoutBinding uniformBinding = VK_ShaderSet::createDescriptorSetLayoutBinding(0,
              VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT);
      shaderSet->addDescriptorSetLayoutBinding(uniformBinding);
  
      auto samplerBinding = VK_ShaderSet::createDescriptorSetLayoutBinding(1,
                            VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
                            VK_SHADER_STAGE_FRAGMENT_BIT);
      auto samplerCreateInfo  = VK_Sampler::createSamplerCreateInfo();
      auto samplerPtr = context->createSampler(samplerCreateInfo);
      VkSampler sampler = samplerPtr->getSampler();
      samplerBinding.pImmutableSamplers = &sampler;
  
      shaderSet->addDescriptorSetLayoutBinding(samplerBinding);
  
      if (!shaderSet->isValid()) {
          std::cerr << "invalid shaderSet" << std::endl;
          shaderSet->release();
          context->release();
          return -1;
      }
  
      auto ubo = shaderSet->addUniformBuffer(0, sizeof(float) * 16);
      ubo->setWriteDataCallback(updateUniformBufferData);
  
      auto image = context->createImage("../images/cat.png");
  
      auto imageViewCreateInfo = VK_ImageView::createImageViewCreateInfo(image->getImage(),
                                 VK_FORMAT_R8G8B8A8_SRGB);
      auto imageView = context->createImageView(imageViewCreateInfo);
      shaderSet->addImageView(imageView, 1);
  
      context->initVulkanContext();
      pipeline = context->createPipeline(shaderSet);
      pipeline->getDynamicState()->addDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
      pipeline->create();
      pipeline->getDynamicState()->applyDynamicViewport({0, 0, 480, 480, 0, 1});
  
      auto buffer = context->createVertexBuffer(vertices, 9, indices);
      pipeline->addRenderBuffer(buffer);
  
      context->createCommandBuffers();
  
      context->run();
      context->release();
  
      return 0;
  }
  