	

    MAIN.CPP
     
     
     
    //Some Windows Headers (For Time, IO, etc.)
    #include <windows.h>
    #include <mmsystem.h>
    #include <GL/glew.h>
    #include <GL/freeglut.h>
    #include <iostream>
    #include "maths_funcs.h"
    #include "mesh.h"
     
    // Assimp includes
     
    #include <assimp/cimport.h> // C importer
    #include <assimp/scene.h> // collects data
    #include <assimp/postprocess.h> // various extra operations
    #include <stdio.h>
    #include <math.h>
    #include <vector> // STL dynamic memory.
     
     
    /*----------------------------------------------------------------------------
                       MESH TO LOAD
      ----------------------------------------------------------------------------*/
    // this mesh is a dae file format but you should be able to use any other format too, obj is typically what is used
    // put the mesh in your project directory, or provide a filepath for it here
    #define MESHNAME1 "monkeyhead.dae"
    #define MESHNAME2 "chair.obj"
    /*----------------------------------------------------------------------------
      ----------------------------------------------------------------------------*/
     
    std::vector<float> g_vp, g_vn, g_vt;
    int g_point_count = 0;
     
     
    // Macro for indexing vertex buffer
    #define BUFFER_OFFSET(i) ((char *)NULL + (i))
     
    using namespace std;
    GLuint shaderProgramID;
     
     
    unsigned int mesh_vao = 0;
    int width = 800;
    int height = 600;
     
    GLfloat xpos = 0.0f;
    GLfloat ypos = 0.0f;
    GLfloat zpos = -5.0f;
    GLuint loc1, loc2, loc3;
    GLfloat rotate_y = 0.0f;
     
    mat4 model = identity_mat4 ();
     
    mesh chair, monkey;
     
     
     
     
     
     
    /*
    #pragma region MESH LOADING
    /*----------------------------------------------------------------------------
                       MESH LOADING FUNCTION
      ----------------------------------------------------------------------------
     
    bool load_mesh (const char* file_name) {
      const aiScene* scene = aiImportFile (file_name, aiProcess_Triangulate); // TRIANGLES!
      if (!scene) {
        fprintf (stderr, "ERROR: reading mesh %s\n", file_name);
        return false;
      }
      printf ("  %i animations\n", scene->mNumAnimations);
      printf ("  %i cameras\n", scene->mNumCameras);
      printf ("  %i lights\n", scene->mNumLights);
      printf ("  %i materials\n", scene->mNumMaterials);
      printf ("  %i meshes\n", scene->mNumMeshes);
      printf ("  %i textures\n", scene->mNumTextures);
     
      for (unsigned int m_i = 0; m_i < scene->mNumMeshes; m_i++) {
        const aiMesh* mesh = scene->mMeshes[m_i];
        printf ("    %i vertices in mesh\n", mesh->mNumVertices);
        g_point_count += mesh->mNumVertices;
        for (unsigned int v_i = 0; v_i < mesh->mNumVertices; v_i++) {
          if (mesh->HasPositions ()) {
            const aiVector3D* vp = &(mesh->mVertices[v_i]);
            //printf ("      vp %i (%f,%f,%f)\n", v_i, vp->x, vp->y, vp->z);
            g_vp.push_back (vp->x);
            g_vp.push_back (vp->y);
            g_vp.push_back (vp->z);
          }
          if (mesh->HasNormals ()) {
            const aiVector3D* vn = &(mesh->mNormals[v_i]);
            //printf ("      vn %i (%f,%f,%f)\n", v_i, vn->x, vn->y, vn->z);
            g_vn.push_back (vn->x);
            g_vn.push_back (vn->y);
            g_vn.push_back (vn->z);
          }
          if (mesh->HasTextureCoords (0)) {
            const aiVector3D* vt = &(mesh->mTextureCoords[0][v_i]);
            //printf ("      vt %i (%f,%f)\n", v_i, vt->x, vt->y);
            g_vt.push_back (vt->x);
            g_vt.push_back (vt->y);
          }
          if (mesh->HasTangentsAndBitangents ()) {
            // NB: could store/print tangents here
          }
        }
      }
     
      aiReleaseImport (scene);
      return true;
    }
     
    #pragma endregion MESH LOADING
     
    */
     
    // Shader Functions- click on + to expand
    #pragma region SHADER_FUNCTIONS
     
    // Create a NULL-terminated string by reading the provided file
    char* readShaderSource(const char* shaderFile) {  
        FILE* fp = fopen(shaderFile, "rb"); //!->Why does binary flag "RB" work and not "R"... wierd msvc thing?
     
        if ( fp == NULL ) { return NULL; }
     
        fseek(fp, 0L, SEEK_END);
        long size = ftell(fp);
     
        fseek(fp, 0L, SEEK_SET);
        char* buf = new char[size + 1];
        fread(buf, 1, size, fp);
        buf[size] = '\0';
     
        fclose(fp);
     
        return buf;
    }
     
     
    static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType)
    {
            // create a shader object
        GLuint ShaderObj = glCreateShader(ShaderType);
     
        if (ShaderObj == 0) {
            fprintf(stderr, "Error creating shader type %d\n", ShaderType);
            exit(0);
        }
            const char* pShaderSource = readShaderSource( pShaderText);
     
            // Bind the source code to the shader, this happens before compilation
            glShaderSource(ShaderObj, 1, (const GLchar**)&pShaderSource, NULL);
            // compile the shader and check for errors
        glCompileShader(ShaderObj);
        GLint success;
            // check for shader related errors using glGetShaderiv
        glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success);
        if (!success) {
            GLchar InfoLog[1024];
            glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog);
            fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog);
            exit(1);
        }
            // Attach the compiled shader object to the program object
        glAttachShader(ShaderProgram, ShaderObj);
    }
     
    GLuint CompileShaders()
    {
            //Start the process of setting up our shaders by creating a program ID
            //Note: we will link all the shaders together into this ID
        shaderProgramID = glCreateProgram();
        if (shaderProgramID == 0) {
            fprintf(stderr, "Error creating shader program\n");
            exit(1);
        }
     
            // Create two shader objects, one for the vertex, and one for the fragment shader
        AddShader(shaderProgramID, "../Shaders/simpleVertexShader.txt", GL_VERTEX_SHADER);
        AddShader(shaderProgramID, "../Shaders/simpleFragmentShader.txt", GL_FRAGMENT_SHADER);
     
        GLint Success = 0;
        GLchar ErrorLog[1024] = { 0 };
            // After compiling all shader objects and attaching them to the program, we can finally link it
        glLinkProgram(shaderProgramID);
            // check for program related errors using glGetProgramiv
        glGetProgramiv(shaderProgramID, GL_LINK_STATUS, &Success);
            if (Success == 0) {
                    glGetProgramInfoLog(shaderProgramID, sizeof(ErrorLog), NULL, ErrorLog);
                    fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog);
            exit(1);
            }
     
            // program has been successfully linked but needs to be validated to check whether the program can execute given the current pipeline state
        glValidateProgram(shaderProgramID);
            // check for program related errors using glGetProgramiv
        glGetProgramiv(shaderProgramID, GL_VALIDATE_STATUS, &Success);
        if (!Success) {
            glGetProgramInfoLog(shaderProgramID, sizeof(ErrorLog), NULL, ErrorLog);
            fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog);
            exit(1);
        }
            // Finally, use the linked shader program
            // Note: this program will stay in effect for all draw calls until you replace it with another or explicitly disable its use
        glUseProgram(shaderProgramID);
            return shaderProgramID;
    }
    #pragma endregion SHADER_FUNCTIONS
     
    // VBO Functions - click on + to expand
    #pragma region VBO_FUNCTIONS
     
    /*
    void generateObjectBufferMesh() {
    /*----------------------------------------------------------------------------
                       LOAD MESH HERE AND COPY INTO BUFFERS
      ----------------------------------------------------------------------------
     
            //Note: you may get an error "vector subscript out of range" if you are using this code for a mesh that doesnt have positions and normals
            //Might be an idea to do a check for that before generating and binding the buffer.
     
            //load_mesh (MESH_NAME1);
            //int variable = g_point_count;
            load_mesh (MESH_NAME2);
     
            unsigned int vp_vbo = 0;
            loc1 = glGetAttribLocation(shaderProgramID, "vertex_position");
            loc2 = glGetAttribLocation(shaderProgramID, "vertex_normal");
            loc3 = glGetAttribLocation(shaderProgramID, "vertex_texture");
     
            glGenBuffers (1, &vp_vbo);
            glBindBuffer (GL_ARRAY_BUFFER, vp_vbo);
            glBufferData (GL_ARRAY_BUFFER, g_point_count * 3 * sizeof (float), &g_vp[0], GL_STATIC_DRAW);
            unsigned int vn_vbo = 0;
            glGenBuffers (1, &vn_vbo);
            glBindBuffer (GL_ARRAY_BUFFER, vn_vbo);
            glBufferData (GL_ARRAY_BUFFER, g_point_count * 3 * sizeof (float), &g_vn[0], GL_STATIC_DRAW);
     
    //      This is for texture coordinates which you don't currently need, so I have commented it out
    //      unsigned int vt_vbo = 0;
    //      glGenBuffers (1, &vt_vbo);
    //      glBindBuffer (GL_ARRAY_BUFFER, vt_vbo);
    //      glBufferData (GL_ARRAY_BUFFER, g_point_count * 2 * sizeof (float), &g_vt[0], GL_STATIC_DRAW);
           
            unsigned int vao = 0;
            glBindVertexArray (vao);
     
            glEnableVertexAttribArray (loc1);
            glBindBuffer (GL_ARRAY_BUFFER, vp_vbo);
            glVertexAttribPointer (loc1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
            glEnableVertexAttribArray (loc2);
            glBindBuffer (GL_ARRAY_BUFFER, vn_vbo);
            glVertexAttribPointer (loc2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
     
    //      This is for texture coordinates which you don't currently need, so I have commented it out
    //      glEnableVertexAttribArray (loc3);
    //      glBindBuffer (GL_ARRAY_BUFFER, vt_vbo);
    //      glVertexAttribPointer (loc3, 2, GL_FLOAT, GL_FALSE, 0, NULL);
           
    }
     
     
    #pragma endregion VBO_FUNCTIONS
     
    */
     
     
    void display(){
     
            // tell GL to only draw onto a pixel if the shape is closer to the viewer
            glEnable (GL_DEPTH_TEST); // enable depth-testing
            glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
            glClearColor (0.5f, 0.5f, 0.5f, 1.0f);
            glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glUseProgram (shaderProgramID);
     
     
            //Declare your uniform variables that will be used in your shader
            int matrix_location = glGetUniformLocation (shaderProgramID, "model");
            int view_mat_location = glGetUniformLocation (shaderProgramID, "view");
            int proj_mat_location = glGetUniformLocation (shaderProgramID, "proj");
     
            monkey.view = identity_mat4();
            monkey.persp_proj = perspective(45.0, (float)width/(float)height, 0.1, 100.0);
            monkey.view = translate (monkey.view, vec3 (xpos, ypos, zpos));
           
     
            /*
            // Root of the Hierarchy
            mat4 view = identity_mat4 ();
            mat4 persp_proj = perspective(45.0, (float)width/(float)height, 0.1, 100.0);
           
            model = rotate_y_deg (model, rotate_y);
            view = translate (view, vec3 (xpos, ypos, zpos));
     
            // update uniforms & draw
            glUniformMatrix4fv (proj_mat_location, 1, GL_FALSE, persp_proj.m);
            glUniformMatrix4fv (view_mat_location, 1, GL_FALSE, view.m);
            glUniformMatrix4fv (matrix_location, 1, GL_FALSE, model.m);
            */
     
           
        glutSwapBuffers();
    }
     
     
    void updateScene() {   
     
            // Placeholder code, if you want to work with framerate
            // Wait until at least 16ms passed since start of last frame (Effectively caps framerate at ~60fps)
            static DWORD  last_time = 0;
            DWORD  curr_time = timeGetTime();
            float  delta = (curr_time - last_time) * 0.001f;
            if (delta > 0.03f)
                    delta = 0.03f;
            last_time = curr_time;
     
            // rotate the model slowly around the y axis
            //rotate_y+=0.0002f;
            // Draw the next frame
            glutPostRedisplay();
    }
     
     
    void init()
    {
            // Set up the shaders
            GLuint shaderProgramID = CompileShaders();
            // load mesh into a vertex buffer array
            monkey.generateObjectBufferMesh(shaderProgramID, MESHNAME1);
            chair.generateObjectBufferMesh(shaderProgramID, MESHNAME2);
           
    }
     
     
    void scale1()
    {
            mat4 scalar = identity_mat4();
            scalar = scale(scalar, vec3(0.8, 0.8, 0.8));
            model = model * scalar;
    }
     
    void scale2()
    {
            mat4 scalar = identity_mat4();
            scalar = scale(scalar, vec3(1.2, 1.2, 1.2));
            model = model * scalar;
    }
     
    // Placeholder code for the keypress
    void keypress(unsigned char key, int x, int y) {
     
            switch (key)
            {
            case 'w':
                    ypos += 0.1;
                    break;
            case 'a':
                    xpos -= 0.1;
                    break;
            case 's':
                    ypos -= 0.1;
                    break;
            case 'd':
                    xpos += 0.1;
                    break;
            case '1':
                    scale1();
                    break;
            case '2':
                    scale2();
                    break;
            }
     
    }
     
    int main(int argc, char** argv){
     
            // Set up the window
            glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
        glutInitWindowSize(width, height);
        glutCreateWindow("Hello Triangle");
     
            // Tell glut where the display function is
            glutDisplayFunc(display);
            glutIdleFunc(updateScene);
            glutKeyboardFunc(keypress);
     
             // A call to glewInit() must be done after glut is initialized!
        GLenum res = glewInit();
            // Check for any errors
        if (res != GLEW_OK) {
          fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
          return 1;
        }
            // Set up your objects and shaders
            init();
            // Begin infinite event loop
            glutMainLoop();
        return 0;
    }
     
     
     
     
     
     
    MESH.CPP
     
     
     
     
     
    //Some Windows Headers (For Time, IO, etc.)
    #include <windows.h>
    #include <mmsystem.h>
    #include <GL/glew.h>
    #include <GL/freeglut.h>
    #include <iostream>
    #include "maths_funcs.h"
    #include "mesh.h"
     
    // Assimp includes
     
    #include <assimp/cimport.h> // C importer
    #include <assimp/scene.h> // collects data
    #include <assimp/postprocess.h> // various extra operations
    #include <stdio.h>
    #include <math.h>
    #include <vector> // STL dynamic memory.
     
    unsigned int vp_vbo = 0;
    unsigned int vn_vbo = 0;
     
     
     
    //loadmesh, genertateobjectbufferMesh, draw
     
    bool mesh::load_mesh (const char* file_name) {
      const aiScene* scene = aiImportFile (file_name, aiProcess_Triangulate); // TRIANGLES!
      if (!scene) {
        fprintf (stderr, "ERROR: reading mesh %s\n", file_name);
        return false;
      }
      printf ("  %i animations\n", scene->mNumAnimations);
      printf ("  %i cameras\n", scene->mNumCameras);
      printf ("  %i lights\n", scene->mNumLights);
      printf ("  %i materials\n", scene->mNumMaterials);
      printf ("  %i meshes\n", scene->mNumMeshes);
      printf ("  %i textures\n", scene->mNumTextures);
     
      g_point_count = 0;
     
      for (unsigned int m_i = 0; m_i < scene->mNumMeshes; m_i++) {
        const aiMesh* mesh = scene->mMeshes[m_i];
        printf ("    %i vertices in mesh\n", mesh->mNumVertices);
        g_point_count += mesh->mNumVertices;
        for (unsigned int v_i = 0; v_i < mesh->mNumVertices; v_i++) {
          if (mesh->HasPositions ()) {
            const aiVector3D* vp = &(mesh->mVertices[v_i]);
            //printf ("      vp %i (%f,%f,%f)\n", v_i, vp->x, vp->y, vp->z);
            g_vp.push_back (vp->x);
            g_vp.push_back (vp->y);
            g_vp.push_back (vp->z);
          }
          if (mesh->HasNormals ()) {
            const aiVector3D* vn = &(mesh->mNormals[v_i]);
            //printf ("      vn %i (%f,%f,%f)\n", v_i, vn->x, vn->y, vn->z);
            g_vn.push_back (vn->x);
            g_vn.push_back (vn->y);
            g_vn.push_back (vn->z);
          }
          if (mesh->HasTextureCoords (0)) {
            const aiVector3D* vt = &(mesh->mTextureCoords[0][v_i]);
            //printf ("      vt %i (%f,%f)\n", v_i, vt->x, vt->y);
            g_vt.push_back (vt->x);
            g_vt.push_back (vt->y);
          }
          if (mesh->HasTangentsAndBitangents ()) {
            // NB: could store/print tangents here
          }
        }
      }
     
      aiReleaseImport (scene);
      return true;
    }
     
    void mesh::generateObjectBufferMesh(GLuint shaderProgramID, const char* file_name) {
    /*----------------------------------------------------------------------------
                       LOAD MESH HERE AND COPY INTO BUFFERS
      ----------------------------------------------------------------------------*/
     
            //Note: you may get an error "vector subscript out of range" if you are using this code for a mesh that doesnt have positions and normals
            //Might be an idea to do a check for that before generating and binding the buffer.
     
            //load_mesh (MESH_NAME1);
            //int variable = g_point_count;
            load_mesh (file_name);
     
           
            loc1 = glGetAttribLocation(shaderProgramID, "vertex_position");
            loc2 = glGetAttribLocation(shaderProgramID, "vertex_normal");
            loc3 = glGetAttribLocation(shaderProgramID, "vertex_texture");
     
            glGenBuffers (1, &vp_vbo);
            glBindBuffer (GL_ARRAY_BUFFER, vp_vbo);
            glBufferData (GL_ARRAY_BUFFER, g_point_count * 3 * sizeof (float), &g_vp[0], GL_STATIC_DRAW);
            glGenBuffers (1, &vn_vbo);
            glBindBuffer (GL_ARRAY_BUFFER, vn_vbo);
            glBufferData (GL_ARRAY_BUFFER, g_point_count * 3 * sizeof (float), &g_vn[0], GL_STATIC_DRAW);
     
    //      This is for texture coordinates which you don't currently need, so I have commented it out
    //      unsigned int vt_vbo = 0;
    //      glGenBuffers (1, &vt_vbo);
    //      glBindBuffer (GL_ARRAY_BUFFER, vt_vbo);
    //      glBufferData (GL_ARRAY_BUFFER, g_point_count * 2 * sizeof (float), &g_vt[0], GL_STATIC_DRAW);
           
            unsigned int vao = 0;
            glBindVertexArray (vao);
     
    //      This is for texture coordinates which you don't currently need, so I have commented it out
    //      glEnableVertexAttribArray (loc3);
    //      glBindBuffer (GL_ARRAY_BUFFER, vt_vbo);
    //      glVertexAttribPointer (loc3, 2, GL_FLOAT, GL_FALSE, 0, NULL);
           
    }
     
    void mesh::draw(int width, int heigth, int matrix_location, int view_mat_location, int proj_mat_location)
    {
            glEnableVertexAttribArray (loc1);
            glBindBuffer (GL_ARRAY_BUFFER, vp_vbo);
            glVertexAttribPointer (loc1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
            glEnableVertexAttribArray (loc2);
            glBindBuffer (GL_ARRAY_BUFFER, vn_vbo);
            glVertexAttribPointer (loc2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
     
            glUniformMatrix4fv (proj_mat_location, 1, GL_FALSE, persp_proj.m);
            glUniformMatrix4fv (view_mat_location, 1, GL_FALSE, view.m);
            glUniformMatrix4fv (matrix_location, 1, GL_FALSE, model.m);
     
            glDrawArrays (GL_TRIANGLES, 0, g_point_count);
    }

