text: #include <cstdio>
  #include <cstdlib>
  #include <cstdint>
  #include "glad/glad.h"
  #include <GLFW/glfw3.h>
  
  #define WINDOW_WIDTH  1280
  #define WINDOW_HEIGHT  720
  
  void processInput(GLFWwindow *window)
  {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS ||
        glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
      glfwSetWindowShouldClose(window, true);
  
    /*
    static bool wireframe = false;
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
    {
      wireframe = !wireframe;
      glPolygonMode(GL_FRONT_AND_BACK, (wireframe ? GL_LINE : GL_FILL));
    }
    */
  }
  
  void framebuffer_size_callback(GLFWwindow* window, int width, int height)
  {
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
  }
  
  float vertices[] =
  {
     0.5f,  0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
    -0.5f, -0.5f, 0.0f,
    -0.5f,  0.5f, 0.0f
  };
  
  unsigned int indices[] =
  {
    0, 1, 3, 1, 2, 3
  };
  
  char* vertexShaderSource;
  char* fragmentShaderSource;
  
  void readShaders(void)
  {
    long length;
    FILE* file = fopen("./shaders/vertex.glsl", "r");
  
    if (file)
    {
      fseek(file, 0, SEEK_END);
      length = ftell(file);
      fseek(file, 0, SEEK_SET);
      vertexShaderSource = (char*)malloc(length+1);
      if (vertexShaderSource)
      {
        fread(vertexShaderSource, 1, length, file);
      }
      fclose(file);
      vertexShaderSource[length] = '\0';
    }
    else
    {
      perror("Vertex file???\n");
    }
  
    file = fopen("./shaders/fragment.glsl", "r");
  
    if (file)
    {
      fseek(file, 0, SEEK_END);
      length = ftell(file);
      fseek(file, 0, SEEK_SET);
      fragmentShaderSource = (char*)malloc(length+1);
      if (fragmentShaderSource)
      {
        fread(fragmentShaderSource, 1, length, file);
      }
      fclose(file);
      fragmentShaderSource[length] = '\0';
    }
    else
    {
      perror("fragment file???\n");
    }
  }
  
  
  int main()
  {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  
    GLFWwindow* window;
    window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Mooshy", NULL, NULL);
    if (!window)
    {
      printf("Failed to create OpenGL window!\n");
      glfwTerminate();
      return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
  
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
      printf("Failed to initialize GLAD!\n");
      glfwTerminate();
      return -1;
    }
  
    readShaders();
  
    int success;
    char log[512];
  
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
      glGetShaderInfoLog(vertexShader, 512, NULL, log);
      printf("Vertex compilation failed\n\n%s\n", log);
    }
  
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
      glGetShaderInfoLog(fragmentShader, 512, NULL, log);
      printf("fragment compilation failed\n\n%s\n", log);
    }
  
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
  
    free(vertexShaderSource);
    free(fragmentShaderSource);
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
  
    unsigned int VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
  
    glBindVertexArray(VAO);
  
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
  
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
  
    glBindVertexArray(0);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  
    while (!glfwWindowShouldClose(window))
    {
      processInput(window);
  
      glClearColor(0.2f, 0.3f, 0.8f, 0.8f);
      glClear(GL_COLOR_BUFFER_BIT);
  
      glUseProgram(shaderProgram);
      glBindVertexArray(VAO);
      glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
      // glBindVertexArray(0);
  
      glfwSwapBuffers(window);
      glfwPollEvents();
    }
  
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteProgram(shaderProgram);
  
    glfwTerminate();
    return 0;
  }
  