• -OPENGL5 Model Import & Scene Graph & Blend Opacity-


    ASSIMP构建大纲:

    因为递归的原因有必要把大纲还原,类似katana和maya大纲一样

    以maya为例:(输出的时候别导出obj,fbx可以保护层级,abc也可以,但是现在assimp不支持,回头可以用abc api 搞一个)

    所以我在函数原型加入一个pwd

    void processNode(aiNode * node, const aiScene* scene,string pwd);
    #include <iostream>
    #include <assimp/Importer.hpp>
    #include <assimp/scene.h>
    #include <assimp/postprocess.h>
    #include <string>
    using namespace std;
    
    void processNode(aiNode * node, const aiScene* scene, string pwd);
    int main(){
        Assimp::Importer import;
        string path = "maya.fbx";
        const aiScene * scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
        if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
        {
            cout << "ERROR::ASSIMP::" << import.GetErrorString() << endl;
    
        }
    
        string directory = path.substr(0, path.find_last_of('/'));
        cout << directory << endl;
    
        // Get Root Node
        aiNode * node = scene->mRootNode;
        processNode(node,scene,"/");
    
    
    
    
    
        return 0;
    }
    
    void processNode(aiNode * node, const aiScene* scene,string pwd){
    
        cout << ">>LOOP At Node:" << pwd <<" WORLD MATRIX:" << endl;
        aiMatrix4x4 mat =  node->mTransformation;
        cout << "{
    ";
        cout << "	" <<mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << endl;
        cout << "	" <<mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << endl;
        cout << "	" <<mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << endl;
        cout << "	" <<mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4 << endl;
        cout << "}
    ";
    
        for(unsigned int i = 0; i < node->mNumMeshes; i++)
        {
            aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
    
            // mesh points
            cout <<">>Num points:" <<mesh->mNumVertices<< endl;
    
            // Dump materials infos
            aiMaterial *mat = scene->mMaterials[mesh->mMaterialIndex];
            cout << ">>Get Mesh Name: "<<mesh->mName.C_Str()<< " <->  MaterialName: " << mat->GetName().C_Str()  << endl;
            cout << ">>start dumping the texture:
    ";
            cout << "{
    ";
            for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_DIFFUSE); i++)
            {
                aiString str;
                mat->GetTexture(aiTextureType_DIFFUSE, i, &str);
                cout << "	diffuseTexture: "<<str.C_Str() << endl;
            }
            for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_NORMALS); i++)
            {
                aiString str;
                mat->GetTexture(aiTextureType_NORMALS, i, &str);
                cout << "	NormalTexture: "<<str.C_Str() << endl;
            }
            for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_AMBIENT); i++)
            {
                aiString str;
                mat->GetTexture(aiTextureType_AMBIENT, i, &str);
                cout << "	AmbientTexture: "<<str.C_Str() << endl;
            }
            for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_OPACITY); i++)
            {
                aiString str;
                mat->GetTexture(aiTextureType_OPACITY, i, &str);
                cout << "	OpacityTexture: "<<str.C_Str() << endl;
            }
            for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_SPECULAR); i++)
            {
                aiString str;
                mat->GetTexture(aiTextureType_SPECULAR, i, &str);
                cout << "	SpecularTexture: "<<str.C_Str() << endl;
            }
            for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_HEIGHT); i++)
            {
                aiString str;
                mat->GetTexture(aiTextureType_HEIGHT, i, &str);
                cout << "	HeightTexture: "<<str.C_Str() << endl;
            }
            for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_UNKNOWN); i++)
            {
                aiString str;
                mat->GetTexture(aiTextureType_HEIGHT, i, &str);
                cout << "	UnkownTexture: "<<str.C_Str() << endl;
            }
            cout << "}
    ";
    
        }
    
        for(unsigned int i = 0; i < node->mNumChildren; i++)
        {
    
            string pathName =  pwd + node->mChildren[i]->mName.C_Str();
            pathName += "/";
            processNode(node->mChildren[i], scene,pathName);
        }
    
    
        cout << "
    ";
    
    }
    main.cpp

    DUMP:

    maya.fbx
    >>LOOP At Node:/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 0
        0 0 1 0
        0 0 0 1
    }
    >>LOOP At Node:/Geometry/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 0
        0 0 1 0
        0 0 0 1
    }
    >>LOOP At Node:/Geometry/part1/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 0
        0 0 1 0
        0 0 0 1
    }
    >>LOOP At Node:/Geometry/part1/pSphere1/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 0
        0 0 1 0
        0 0 0 1
    }
    >>Num points:1560
    >>Get Mesh Name: pSphere1 <->  MaterialName: lambert1
    >>start dumping the texture:
    {
    }
    
    >>LOOP At Node:/Geometry/part1/pSphere2/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 2.17013
        0 0 1 0
        0 0 0 1
    }
    >>Num points:1560
    >>Get Mesh Name: pSphere2 <->  MaterialName: lambert1
    >>start dumping the texture:
    {
    }
    
    >>LOOP At Node:/Geometry/part1/pSphere3/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 4.34026
        0 0 1 0
        0 0 0 1
    }
    >>Num points:1560
    >>Get Mesh Name: pSphere3 <->  MaterialName: lambert1
    >>start dumping the texture:
    {
    }
    
    >>LOOP At Node:/Geometry/part1/pSphere4/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 6.51039
        0 0 1 0
        0 0 0 1
    }
    >>Num points:1560
    >>Get Mesh Name: pSphere4 <->  MaterialName: lambert1
    >>start dumping the texture:
    {
    }
    
    
    >>LOOP At Node:/Geometry/part2/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 0
        0 0 1 0
        0 0 0 1
    }
    >>LOOP At Node:/Geometry/part2/pSphere5/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 8.68052
        0 0 1 0
        0 0 0 1
    }
    >>Num points:1560
    >>Get Mesh Name: pSphere5 <->  MaterialName: lambert1
    >>start dumping the texture:
    {
    }
    
    >>LOOP At Node:/Geometry/part2/pSphere6/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 10.8507
        0 0 1 0
        0 0 0 1
    }
    >>Num points:1560
    >>Get Mesh Name: pSphere6 <->  MaterialName: lambert1
    >>start dumping the texture:
    {
    }
    
    >>LOOP At Node:/Geometry/part2/pSphere7/ WORLD MATRIX:
    {
        1 0 0 0
        0 1 0 13.0208
        0 0 1 0
        0 0 0 1
    }
    >>Num points:1560
    >>Get Mesh Name: pSphere7 <->  MaterialName: lambert1
    >>start dumping the texture:
    {
    }

    额外的我定义了我的场景描述,已经修改的跪下了,每次写代码遍历场景,发现特么的完全不科学。

    json用的https://github.com/nlohmann/json

    CP19会实现场景分析,加载场景。CP18修改了一些系统内部逻辑设计。

    {
        "name": "simple",
        "project_dir": "D:/plugin_dev/opengl/CP_18/Triangle/build/scene",
        "models": [
            "model/nanosuit.obj"
        ],
        "mats": {
            "glass": {
                "shader_define": {
                    "___comment___": "type=0 is file shader; type=1 use inline color ; type=2 use inline texture; type=3 use our json code shader,this may be use in our ui ",
                    "code_type": 0,
                    "frag_code": "",
                    "vert_code": ""
                },
                "params_define": {
                    "diffuse": "model/glass_dif.png"
                }
            },
            "leg": {
                "shader_define": {
                    "code_type": 0,
                    "frag_code": "",
                    "vert_code": ""
                },
                "params_define": {
                    "diffuse": "model/leg_dif.png",
                    "specular": "model/leg_showroom_spec.png"
                }
            },
            "hand": {
                "shader_define": {
                    "code_type": 0,
                    "frag_code": "",
                    "vert_code": ""
                },
                "params_define": {
                    "diffuse": "model/hand_dif.png",
                    "specular": "model/hand_showroom_spec.png"
                }
            },
            "body": {
                "shader_define": {
                    "code_type": 0,
                    "frag_code": "",
                    "vert_code": ""
                },
                "params_define": {
                    "diffuse": "model/mat2_diffuse.png",
                    "specular": "model/mat2_specular.png"
                }
            },
            "helmet": {
                "shader_define": {
                    "code_type": 0,
                    "frag_code": "",
                    "vert_code": ""
                },
                "params_define": {
                    "diffuse": "model/helmet_diff.png",
                    "specular": "model/helmet_showroom_spec.png"
                }
            },
            "arms": {
                "shader_define": {
                    "code_type": 0,
                    "frag_code": "",
                    "vert_code": ""
                },
                "params_define": {
                    "diffuse": "model/arm_dif.png",
                    "specular": "model/arm_showroom_spec.png"
                }
            }
        },
      
        "assignMaterial": {
            "/Visor": "glass",
            "/Lights": "glass",
            "/Legs": "leg",
            "/hands": "hand",
            "/Arms": "arms",
            "/Helmet": "helmet",
            "/Body": "body"
        }
    }
    #include <iostream>
    #include <json.hpp>
    #include <fstream>
    using namespace std;
    using json = nlohmann::json;
    int main()
    {
        ifstream  in("scene.json");
        json j;
        in >> j;
        cout << "scene name:" << j.at("name") << endl;
        cout << "project dir" << j.at("project_dir") <<endl;
    
        for(auto &m: j["models"]){
            cout << "load model:" << m.get<string>() <<endl;
        }
    
        cout << "
    Parse Materials:
    ";
        // read "mats"
        json mats = j["mats"];
    
        for(auto &mat: mats.items()){
            json matNameObject = mat.key(); // json mat name
            json matContentObject = mat.value();  // json shader content define
            cout << "Inspect mat:" << matNameObject <<endl;
    
            json shaderDefineObject =  matContentObject["shader_define"];
            json paramDefineObject = matContentObject["params_define"];
    
            //cout << shaderDefineObject <<endl;
            //cout << paramDefineObject << endl;
    
            for(auto &params: paramDefineObject.items())
            {
                json paramNameObject = params.key();
                json valueObject = params.value(); // may be relative texture path , or shader value
                string pname = paramNameObject.get<string>();
                if(pname == "diffuse"){
                    cout << "diffuse: " << valueObject <<endl;
                }
                if(pname == "specular"){
                    cout << "specular: " << valueObject <<endl;
                }
            }
            cout << "
    ";
    
        }
    
        return 0;
    }
    cpp场景分析

    Log:

    21:36:39: Starting D:plugin_devopenglJSON_CP_01JSON_Scene_ParseJSON_Scene_Parse.exe ...
    scene name:"simple"
    project dir"D:/plugin_dev/opengl/CP_18/Triangle/build/scene"
    load model:model/nanosuit.obj
    
    Parse Materials:
    Inspect mat:"arms"
    diffuse: "model/arm_dif.png"
    specular: "model/arm_showroom_spec.png"
    
    Inspect mat:"body"
    diffuse: "model/mat2_diffuse.png"
    specular: "model/mat2_specular.png"
    
    Inspect mat:"glass"
    diffuse: "model/glass_dif.png"
    
    Inspect mat:"hand"
    diffuse: "model/hand_dif.png"
    specular: "model/hand_showroom_spec.png"
    
    Inspect mat:"helmet"
    diffuse: "model/helmet_diff.png"
    specular: "model/helmet_showroom_spec.png"
    
    Inspect mat:"leg"
    diffuse: "model/leg_dif.png"
    specular: "model/leg_showroom_spec.png"
    
    21:36:39: D:plugin_devopenglJSON_CP_01JSON_Scene_ParseJSON_Scene_Parse.exe exited with code 0

    CP18:

    locations debug;

    //
    // Created by admin on 2020/2/21.
    //
    
    #ifndef TRIANGLE_ALG_MODELDELEGATE_H
    #define TRIANGLE_ALG_MODELDELEGATE_H
    #include <string>
    #include <vector>
    #include "ALG_MeshDelegate.h"
    #include "ALG_LoadShader.h"
    #include <assimp/Importer.hpp>
    #include <assimp/scene.h>
    #include <assimp/postprocess.h>
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    
    
    namespace AlgebraMaster
    {
    using namespace std;
    
    
    // helper method for exchange aiMatrix to glm matrix
    void exchange_matrix_data(glm::mat4 &DesMatrix,const aiMatrix4x4 & srcAssimpMat);
    
    // ----------------------- SCENE LOCATION --------------------------------
    struct SceneLocation{
        // function
        SceneLocation();
        ~SceneLocation();
    
        // vars
        string pwd;
        glm::mat4 worldTransform;
        string type; // group or Mesh
        Mesh *mesh;
    };
    
    SceneLocation::SceneLocation():pwd(""),worldTransform(1.0f),type("group"),mesh(nullptr){
    }
    SceneLocation::~SceneLocation() {
        if(mesh)
            delete mesh;
    }
    
    // ----------------------- SCENE LOCATION --------------------------------
    
    
    
    
    // ----------------------- SCENE Model --------------------------------
    class Model{
    public:
        //* Read Mesh from path */
        Model() = default;
        explicit Model(const string& path);
        ~Model();
    
        void readMesh(const string& path);
        //* overwrite all mesh material */
        void assignMaterial(const LoadShader &shader);
        //* paint mesh in opengl */
        void draw();
        //* get the locations */
        vector<SceneLocation*> getLocations();
    
        // use default shader
        inline void useSimpleShader(){
            cout << "Model Used basic shader that should call useSimpleShaderMatrix() in render loop !
    ";
            for(auto &loc :locations){
                loc->mesh->shader.asSimpleShader();
            }
        }
        inline void useSimpleShaderMatrix(glm::mat4 &proj, glm::mat4 &view, glm::mat4 &model){
            for(auto &loc :locations){
                loc->mesh->shader.use();
                loc->mesh->shader.setMat4("projection", proj);
                loc->mesh->shader.setMat4("view", view);
                loc->mesh->shader.setMat4("model", model);
    
            }
        }
        inline void debugLocations(){
            cout << "debug locations:
    ";
            cout << "{
    ";
            for(auto&loc : locations){
                cout <<"	SceneGraph:" <<loc->pwd <<"	Type:" <<loc->type << endl;
            }
            cout << "}
    ";
        }
    
    
    
    private:
    
        // vars
        vector<SceneLocation*> locations;
        string directory; // the mesh location at filesystem path
    
    
        // functions from assimp to our struct
        void processNode(aiNode *assimpNode,const aiScene* assimpScene, string pwd);
        Mesh* processMesh(aiMesh *assimpMesh, const aiScene *assimpScene);
    
    };
    
    
    
    // constructor
    Model::Model(const string &path) {
        readMesh(path);
    }
    Model::~Model() {
        for(auto & location : locations){
            delete location;
        }
        locations.clear();
    }
    
    vector<SceneLocation *> Model::getLocations() {
        return this->locations;
    }
    
    void Model::draw(){
        for_each(locations.begin(),locations.end(),[](SceneLocation* l){l->mesh->draw();});
    }
    void Model::assignMaterial(const LoadShader &shader) {
        for(auto & location : locations){
            location->mesh->assignMaterial(shader);
        }
    }
    
    void Model::readMesh(const string &path)
    {
        Assimp::Importer import;
        const aiScene * scene = import.ReadFile(path.c_str(),
                aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
        // check error
        if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){
            cout << "ERROR::ASSIMP:: " << import.GetErrorString() << endl;
            return ;
        }
        // retrieve the directory path of the filepath
        directory = path.substr(0, path.find_last_of('/'));
    
        // process ASSIMP's root node recursively
        processNode(scene->mRootNode, scene,"/");
    
    }
    
    void Model::processNode(aiNode *assimpNode, const aiScene *assimpScene, string pwd) {
        // process each mesh located at the current node
        aiMatrix4x4 mat =  assimpNode->mTransformation;
        auto *location = new SceneLocation;
        location->pwd = pwd;
        if (assimpNode->mNumMeshes<=0)
            location->type = "group";
        else
            location->type = "mesh";
        location->pwd = pwd;
        exchange_matrix_data(location->worldTransform,mat);
    
        // loop this node's meshs
        for(unsigned int i = 0; i < assimpNode->mNumMeshes; i++)
        {
            // the node object only contains indices to index the actual objects in the scene.
            // the scene contains all the data, node is just to keep stuff organized (like relations between nodes).
            aiMesh* assimpMesh = assimpScene->mMeshes[assimpNode->mMeshes[i]];
            Mesh* mesh = processMesh(assimpMesh,assimpScene);
            location->mesh = mesh;
            this->locations.emplace_back(location);
        }
        // after we've processed all of the meshes (if any) we then recursively process each of the children nodes
        for(unsigned int i = 0; i < assimpNode->mNumChildren; i++)
        {
            string pathName =  pwd + assimpNode->mChildren[i]->mName.C_Str();
            pathName += "/";
            processNode(assimpNode->mChildren[i], assimpScene,pathName);
        }
    
    }
    Mesh* Model::processMesh(aiMesh *assimpMesh, const aiScene *assimpScene)
    {
        // our mesh interface pointer
        Mesh *mesh = new Mesh;
        // construct mesh data from assimpMesh
        for(unsigned int i =0; i <assimpMesh->mNumVertices;i++){
            Vertex vertex;
            vertex.position.x= assimpMesh->mVertices[i].x;
            vertex.position.y= assimpMesh->mVertices[i].y;
            vertex.position.z= assimpMesh->mVertices[i].z;
            vertex.normal.x = assimpMesh->mNormals[i].x;
            vertex.normal.y = assimpMesh->mNormals[i].y;
            vertex.normal.z = assimpMesh->mNormals[i].z;
            // tex
            if(assimpMesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
            {
                // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
                // use models where a vertex can have multiple texture coordinates so we always take the first set (0).
                vertex.texCoords.x = assimpMesh->mTextureCoords[0][i].x;
                vertex.texCoords.y = assimpMesh->mTextureCoords[0][i].y;
            }
            else{
                vertex.texCoords.x = 0.0f;
                vertex.texCoords.y = 0.0f;
            }
            // tangent
            vertex.tangent.x = assimpMesh->mTangents[i].x;
            vertex.tangent.y = assimpMesh->mTangents[i].y;
            vertex.tangent.z = assimpMesh->mTangents[i].z;
            // bitangent
            vertex.biTangent.x = assimpMesh->mBitangents[i].x;
            vertex.biTangent.y = assimpMesh->mBitangents[i].y;
            vertex.biTangent.z = assimpMesh->mBitangents[i].z;
            mesh->vertices.emplace_back(vertex);
        }
        // indices
        for(int i=0; i<assimpMesh->mNumFaces; i++){
            aiFace face = assimpMesh->mFaces[i];
            for(int j=0;j<face.mNumIndices;j++){
                mesh->indices.emplace_back(face.mIndices[j]);
            }
        }
        mesh->setupMesh();
        return mesh;
    
    }
    // ----------------------- SCENE Model --------------------------------
    
    
    
    
    // ---- Helper
    void exchange_matrix_data(glm::mat4 &DesMatrix,const aiMatrix4x4 & srcAssimpMat){
    
        DesMatrix[0].x = srcAssimpMat.a1;
        DesMatrix[0].y = srcAssimpMat.a2;
        DesMatrix[0].z = srcAssimpMat.a3;
        DesMatrix[0].w = srcAssimpMat.a4;
    
        DesMatrix[1].x = srcAssimpMat.b1;
        DesMatrix[1].y = srcAssimpMat.b2;
        DesMatrix[1].z = srcAssimpMat.b3;
        DesMatrix[1].w = srcAssimpMat.b4;
    
        DesMatrix[2].x = srcAssimpMat.c1;
        DesMatrix[2].y = srcAssimpMat.c2;
        DesMatrix[2].z = srcAssimpMat.c3;
        DesMatrix[2].w = srcAssimpMat.c4;
    
        DesMatrix[3].x = srcAssimpMat.d1;
        DesMatrix[3].y = srcAssimpMat.d2;
        DesMatrix[3].z = srcAssimpMat.d3;
        DesMatrix[3].w = srcAssimpMat.d4;
    }
    
    
    } // end of namespace
    
    #endif //TRIANGLE_ALG_MODELDELEGATE_H
    ALG_ModelDelegate.h
    #ifndef LOADSHADER_H
    #define LOADSHADER_H
    
    
    #include <GL/glew.h>
    
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <sstream>
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    
    
    
    
    namespace AlgebraMaster{
    
    
    using namespace std;
    // Shaders
    
    
    
    struct LoadShader
    {
        enum ShaderIOType{FILE,INLINE_DEFAULT_PROJECTION };
        void compileShaderProgram(){
            // create shader program and check it
            GLint success;
            GLchar infoLog[512];
            shaderProgram = glCreateProgram();
            glAttachShader(shaderProgram,vertexShader);
            glAttachShader(shaderProgram,fragmentShader);
            glLinkProgram(shaderProgram );
            glGetProgramiv( shaderProgram, GL_LINK_STATUS, &success );  // Get Link Status
            if (!success)
            {
                glGetProgramInfoLog( shaderProgram, 512, NULL, infoLog );
                std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED
    " << infoLog << std::endl;
            }
            // Delete the shaders as they're linked into our program now and no longer necessery
            glDeleteShader( vertexShader );
            glDeleteShader( fragmentShader );
        }
        void compileVertexShader(string code){
            vertexShader = glCreateShader( GL_VERTEX_SHADER );
    
            const char * src = code.c_str();
            glShaderSource( vertexShader, 1, &(src), NULL );
    
            glCompileShader( vertexShader );
            GLint success;
            GLchar infoLog[512];
    
            glGetShaderiv( vertexShader, GL_COMPILE_STATUS, &success );
            if ( !success )
            {
                glGetShaderInfoLog( vertexShader, 512, NULL, infoLog );
                std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED
    " << infoLog << std::endl;
            }
        }
    
        void compileFragmentShader(string code){
            const char * src = code.c_str();
            GLint success;
            GLchar infoLog[512];
            fragmentShader = glCreateShader( GL_FRAGMENT_SHADER );
            glShaderSource( fragmentShader, 1, &src, NULL );
            glCompileShader( fragmentShader );
            glGetShaderiv( fragmentShader, GL_COMPILE_STATUS, &success ); // Get Compile status
            if ( !success )
            {
                glGetShaderInfoLog( fragmentShader, 512, NULL, infoLog );
                std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
    " << infoLog << std::endl;
            }
        }
    
    
    
        LoadShader(){
    
        }
        void asSimpleShader()
        {
            const char* vertexShaderSource = "#version 450 core
    "
                                             "layout (location = 0) in vec4 v_position;
    "
                                             "layout ( location = 1 ) in vec3 v_normal;
    "
                                             "layout ( location = 2 ) in vec2 v_texCoord;
    "
                                             "out vec4 myColor;
    "
                                             "uniform mat4 model;
    "
                                             "uniform mat4 view;
    "
                                             "uniform mat4 projection;
    "
                                             "void main()
    "
                                             "{
    "
                                             "gl_Position = projection *   view * model * v_position;
    "
                                             "myColor = vec4(v_normal , 1);
    "
                                             "}";
    
    
    
            const char* fragmentShaderSource = "#version 450 core
    "
                                               "out vec4 fColor;
    "
                                               "in vec4 myColor;
    "
                                               "void main()
    "
                                               "{
    "
                                               "fColor = myColor;
    "
                                               "}
    ";
    
    
    
    
            shaderIOType = INLINE_DEFAULT_PROJECTION;
            compileVertexShader(vertexShaderSource);
            compileFragmentShader(fragmentShaderSource);
            compileShaderProgram();
        }
    
    
        void setShaderName(const string &name){
            shaderName = name;
        }
    
        LoadShader(const char*vertPath, const char* fragPath){
            load(vertPath,fragPath);
            shaderIOType = FILE;
        }
    
        string _readFile(const char *path){
            ifstream stream;
            stringstream ss;
            stream.exceptions(ifstream::badbit);
            try
            {
                stream.open(path);    // open file
                ss << stream.rdbuf(); // get strings from file
            } catch (ifstream::failure e)
            {
                cout << "ERROR::OPEN FILE:" << path << endl;
            }
            // close file handle
            stream.close();
    
            // get str() from stringstream
            string shaderCode = ss.str();
            return shaderCode;
        }
    
        void _loadVertexShader(const char *path){
    
            // read shader code
            auto handle = _readFile(path);
            const char * shaderCode = handle.c_str();
            compileVertexShader(shaderCode);
    
        }
    
        void _loadFragmentShader(const char *path){
            // read shader code
            auto handle = _readFile(path);
            const char * shaderCode = handle.c_str();
            compileFragmentShader(shaderCode);
        }
    
        void load(const char* vertShaderPath, const char* fragShaderPath){
            shaderIOType = FILE;
            _loadVertexShader(vertShaderPath);
            _loadFragmentShader(fragShaderPath);
            // create shader program and check it
            compileShaderProgram();
        }
    
        void use(){
            glUseProgram(shaderProgram);
        }
    
        void setBool(const char *name, bool value) const
        {
            glUniform1i(glGetUniformLocation(shaderProgram, name), (int)value);
        }
        void setInt(const char *name, int value) const
        {
            glUniform1i(glGetUniformLocation(shaderProgram,name), value);
        }
        // ------------------------------------------------------------------------
        void setFloat(const char *name, float value) const
        {
            glUniform1f(glGetUniformLocation(shaderProgram, name), value);
        }
        // ------------------------------------------------------------------------
        void setVec2(const char *name, const glm::vec2 &value) const
        {
            glUniform2fv(glGetUniformLocation(shaderProgram,name), 1, &value[0]);
        }
    
        void setVec2(const char *name, float x, float y) const
        {
            glUniform2f(glGetUniformLocation(shaderProgram,name), x, y);
        }
        // ------------------------------------------------------------------------
        void setVec3(const char *name, const glm::vec3 &value) const
        {
            glUniform3fv(glGetUniformLocation(shaderProgram,name), 1, &value[0]);
        }
        void setVec3(const char *name, float x, float y, float z) const
        {
            glUniform3f(glGetUniformLocation(shaderProgram,name), x, y, z);
        }
        // ------------------------------------------------------------------------
        void setVec4(const char *name, const glm::vec4 &value) const
        {
            glUniform4fv(glGetUniformLocation(shaderProgram,name), 1, &value[0]);
        }
        void setVec4(const char *name, float x, float y, float z, float w)
        {
            glUniform4f(glGetUniformLocation(shaderProgram,name), x, y, z, w);
        }
    
        void setMat2(const char*name, const glm::mat2 &mat) const
        {
            glUniformMatrix2fv(glGetUniformLocation(shaderProgram, name), 1, GL_FALSE,glm::value_ptr(mat));
        }
    
        void setMat3(const char*name, const glm::mat3 &mat){
            GLuint location = glGetUniformLocation(shaderProgram, name);
            glUniformMatrix3fv(location,1, GL_FALSE, &mat[0][0]);
        }
    
        void setMat4(const char *name , const glm::mat4 &mat){
            GLuint location = glGetUniformLocation(shaderProgram, name);
            glUniformMatrix4fv(location,1, GL_FALSE, glm::value_ptr(mat));
        }
    
        GLuint shaderProgram;
        GLuint vertexShader;
        GLuint fragmentShader;
        ShaderIOType shaderIOType;
        string shaderName;
    };
    
    
    
    }
    
    
    #endif // LOADSHADER_H
    ALG_LoadShader.h
    #ifndef WINDOW_H
    #define WINDOW_H
    
    
    #define GLEW_STATIC
    #include <GL/glew.h>
    
    #undef GLFW_DLL
    #include <GLFW/glfw3.h>
    
    
    
    
    
    class FrameWindow
    {
    public:
        FrameWindow(int width,int height,const char*title="OpenGL");
        virtual ~FrameWindow();
        GLFWwindow *getWindow();
    private:
         GLFWwindow *window;
         int w;
         int h;
    };
    
    FrameWindow::FrameWindow(int width,int height,const char*title){
        w = width;
        h = height;
        glewInit();
        glfwInit();
        window = glfwCreateWindow(width,height,title,NULL,NULL);
        glfwMakeContextCurrent(window);
    
    
    }
    FrameWindow::~FrameWindow(){
        glfwDestroyWindow(window);
        glfwTerminate();
    }
    GLFWwindow * FrameWindow::getWindow(){
        return window;
    }
    
    #endif // WINDOW_H
    ALG_FrameWindow.h
    #ifndef MESH_H
    #define MESH_H
    
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    #include <string>
    #include <vector>
    #include "ALG_LoadShader.h"
    #include <GL/glew.h>
    namespace AlgebraMaster
    {
    
    using namespace std;
    
    
    
    struct Vertex{
        glm::vec3 position;
        glm::vec3 normal;
        glm::vec2 texCoords;
        glm::vec3 tangent;
        glm::vec3 biTangent;
    };
    struct Texture{
        // Reference houdini principledshader
        enum Type {
            BASECOLOR_MAP, SPECULAR_MAP, EMISSION_MAP,
            BUMP_MAP, NORMAL_MAP, IOR_MAP,
            OPACITY_MAP, DISPLACE_MAP,
            CHAN_TEX0,CHAN_TEX1,CHAN_TEX2,CHAN_TEX3,
            CHAN_TEX4,CHAN_TEX5,CHAN_TEX6,CHAN_TEX7,
            CHAN_TEX8,CHAN_TEX9_CHAN_TEX10
        };
        unsigned int id;
        string path;
        Type texType;
    };
    
    struct Mesh
    {
    public:
        Mesh()= default;
        //* constructor */
        Mesh(const vector<Vertex> &vts,
                const vector<unsigned int>ids,
                const vector<Texture> &texs);
        // rendering data
        vector<Vertex> vertices;
        vector<unsigned int> indices;
        vector<Texture> textures;
        // ogl
        unsigned int VAO,VBO,EBO; // vertex array buffer
    
        //* this method need called manually */
        void setupMesh();
    
        // ogl draw
        void draw();
    
        // shader
        LoadShader shader;
    
        // get mat from outside
        void assignMaterial(const LoadShader & rhs_shader);
    
    };
    
    
    Mesh::Mesh(const vector<Vertex> &vts,
               const vector<unsigned int>ids,
               const vector<Texture> &texs):vertices(vts),indices(ids),textures(texs){
    
    }
    
    void Mesh::assignMaterial(const LoadShader &rhs_shader) {
        shader.fragmentShader = rhs_shader.fragmentShader;
        shader.vertexShader = rhs_shader.vertexShader;
        shader.shaderProgram = rhs_shader.shaderProgram;
    }
    
    // opengl draw the mesh
    void Mesh::draw() {
        this->shader.use();
        string mat_prefix = "material.";
        for(int i=0;i<textures.size();i++){
            glActiveTexture(GL_TEXTURE0 + i);
            switch (this->textures[i].texType)
            {
                case Texture::BASECOLOR_MAP:{
                    string texchanName = mat_prefix + "diffuse_map";
                    shader.setInt(texchanName.c_str(),i);
                    break;
                }
                case Texture::SPECULAR_MAP:{
                    string texchanName = mat_prefix + "specular_map";
                    shader.setInt(texchanName.c_str(),i);
                    break;
                }
                case Texture::EMISSION_MAP:{
                    string texchanName = mat_prefix + "emission_map";
                    shader.setInt(texchanName.c_str(),i);
                    break;
                }
                case Texture::BUMP_MAP:{
                    string texchanName = mat_prefix + "bump_map";
                    shader.setInt(texchanName.c_str(),i);
                    break;
                }
                case Texture::NORMAL_MAP:{
                    string texchanName = mat_prefix + "normal_map";
                    shader.setInt(texchanName.c_str(),i);
                    break;
                }
                case Texture::IOR_MAP:{
                    string texchanName = mat_prefix + "ior_map";
                    shader.setInt(texchanName.c_str(),i);
                    break;
                }
                case Texture::OPACITY_MAP:{
                    string texchanName = mat_prefix + "opacity_map";
                    shader.setInt(texchanName.c_str(),i);
                    break;
                }
                case Texture::DISPLACE_MAP:{
                    string texchanName = mat_prefix + "displace_map";
                    shader.setInt(texchanName.c_str(),i);
                    break;
                }
                default:
                    break;
    
            } // end of switch
            glBindTexture(GL_TEXTURE_2D, textures[i].id); // bind current id
    
        } // end of for each textures
    
    
        // draw mesh
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
    
        // always good practice to set everything back to defaults once configured.
        glActiveTexture(GL_TEXTURE0);
    }
    
    // init our mesh data
    void Mesh::setupMesh() {
        glCreateVertexArrays(1,&VAO);           // vertex array object
        glCreateBuffers(1,&VBO);                // vertex buffer object
        glCreateBuffers(1,&EBO);                // vertex element array buffer object
        glBindVertexArray(VAO);                 // bind vertex array
        glBindBuffer(GL_ARRAY_BUFFER,VBO);      // bind vertex buffer
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
    
        // vertex attributes
        // position
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
        // normal
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 3*sizeof(float)) );
        //tex
        glEnableVertexAttribArray(2);
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 6*sizeof(float)) );
        //tangent
        glEnableVertexAttribArray(3);
        glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 8*sizeof(float)) );
        // bitangent
        glEnableVertexAttribArray(4);
        glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 11*sizeof(float)) );
    
        glBindVertexArray(0);
    }
    
    } // end of namespace
    
    #endif // MESH_H
    ALG_MeshDelegate.h
    #ifndef LOADTEXTURE_H
    #define LOADTEXTURE_H
    #include <GL/glew.h>
    
    // IMP the stb image loader
    #define STB_IMAGE_IMPLEMENTATION
    #include <stb_image.h>
    #include <iostream>
    using namespace std;
    
    namespace AlgebraMaster
    {
    
    
    
    class LoadTexture
    {
    public:
        LoadTexture()=default;
        LoadTexture(const char *fileName);
        void load(const char *fileName);
        virtual ~LoadTexture();
        inline GLuint getTextureID(){return textureID;}
        inline GLuint getImageFormat(){return format;}
    private:
        GLuint textureID;
        GLenum format;
    };
    
    void LoadTexture::load(const char *fileName)
    {
        glGenTextures(1, &textureID);
        int width, height, nrComponents;
        unsigned char *data = stbi_load(fileName, &width, &height, &nrComponents, 0);
        if (data)
        {
            if (nrComponents == 1)
                format = GL_RED;
            else if (nrComponents == 3)
                format = GL_RGB;
            else if (nrComponents == 4)
                format = GL_RGBA;
    
            glBindTexture(GL_TEXTURE_2D, textureID);
            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
            glGenerateMipmap(GL_TEXTURE_2D);
    
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    
            stbi_image_free(data);
        }
        else
        {
            std::cout << "Texture failed to load at path: " << fileName << std::endl;
            stbi_image_free(data);
        }
    
    }
    
    LoadTexture::LoadTexture(const char *fileName){
        load(fileName);
    }
    LoadTexture::~LoadTexture(){}
    
    }
    #endif // LOADTEXTURE_H
    ALG_LoadTexture.h
    #ifndef GLFWCAMERA_H
    #define GLFWCAMERA_H
    
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    
    namespace AlgebraMaster{
    
    
    
    class GLFWCamera{
    public:
        GLFWCamera();
        ~GLFWCamera(){}
        enum CAMERA_MOVEMENT{
            FORWARD,     // Camera move to front   ->  key:W
            BACKWARD,    // Camera move to back    ->  key:S
            LEFT,        // Camera move to left    ->  key:A
            RIGHT        // Camera move to right   ->  key:D
        };
    
    public:
        glm::vec3 pos;   // camera world space
        glm::vec3 front;
        glm::vec3 up;
    
        // Euler Angles
       float yaw;
       float pitch;
    
    
       // Camera options
       float movementSpeed;
       float mouseSensitivity;
       float fov;
    
       void processFov(float yoffset){
           if(fov >= 1.0f && fov <= 45.0f){
               fov -= yoffset;
           }
           if(fov <=1.0f){
               fov = 1.0f;
           }
           if(fov >= 45.0f){
               fov = 45.0f;
           }
       }
    
       // build the matrix for lookAt
       glm::mat4 GetViewMatrix(){
           return glm::lookAt(pos , pos + front , up);
       }
    
       // process -Rotate the view-
       void processMouseMove(float xoffset, float yoffset);
    
    
       // process -W S A D-
       void processKeyboardMove(float delta, CAMERA_MOVEMENT moveDir);
    
    
    
       void updateFront(){
           glm::vec3 tempfront;
           tempfront.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
           tempfront.y = sin(glm::radians(pitch));
           tempfront.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
           this->front = glm::normalize(tempfront);
       }
    
    
    };
    
    GLFWCamera::GLFWCamera(){
        pos = glm::vec3(0.0f,0.0f,3.0f);
        up = glm::vec3(0.0f,1.0f,0.0f);
        front = glm::vec3(0.0f,0.0f,-1.0f);
        yaw = -90.0f;
        pitch = 0.0f;
        fov = 45.0f;
        movementSpeed = 4.5f;
        mouseSensitivity = 0.1f;
    }
    
    void GLFWCamera::processMouseMove(float xoffset, float yoffset)
    {
    
        xoffset *= mouseSensitivity;
        yoffset *= mouseSensitivity;
    
        yaw += xoffset;
        pitch += yoffset;
    
        // make sure that when pitch is out of bounds, screen doesn't get flipped
        if (pitch > 89.0f)
            pitch = 89.0f;
        if (pitch < -89.0f)
            pitch = -89.0f;
        this->updateFront();
    }
    
    void GLFWCamera::processKeyboardMove(float delta, CAMERA_MOVEMENT moveDir)
    {
        float vel = movementSpeed * delta;
        switch (moveDir)
        {
        case FORWARD:
            {
                pos += vel * front;
                break;
            }
        case BACKWARD:
            {
                pos -= vel * front;
                break;
            }
        case LEFT:
            {
                pos -= glm::normalize(glm::cross(front, up)) * vel;
                break;
            }
        case RIGHT:
            {
                pos += glm::normalize(glm::cross(front, up)) * vel;
            }
        default:
            break;
        }
    }
    
    }
    #endif // GLFWCAMERA_H
    ALG_GLFWCamera.h
    #define GLEW_STATIC
    // GLEW
    #include <GL/glew.h>
    #include <cstdlib>
    #undef GLFW_DLL
    // GLFW
    #include <GLFW/glfw3.h>
    #include <iostream>
    #include "ALG_LoadShader.h"
    #include "ALG_LoadTexture.h"
    #include "ALG_GLFWCamera.h"
    #include "ALG_FrameWindow.h"
    #include "ALG_ModelDelegate.h"
    #include <cmath>
    
    
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    using namespace AlgebraMaster;
    
    
    const unsigned int SRC_WIDTH = 1400;
    const unsigned int SRC_HEIGHT = 720;
    
    
    static GLuint cubeVAO,VBO;
    static GLuint lightVAO;  //VBO stays the same; the vertices are the same for the light object which is also a 3D cube
    
    
    static LoadShader SurfaceShader;
    
    void init();
    void display();
    
    
    void processInput(GLFWwindow *window);
    void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize
    void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse
    void scroll_callback(GLFWwindow *window, double xoffset, double yoffset);
    
    
    // camera
    static GLFWCamera *camera;
    static float lastX =  float(SRC_WIDTH) / 2.0f;
    static float lastY =  float(SRC_HEIGHT) / 2.0f;
    static bool firstMouse = true;
    static bool firstMiddowMouse = true;
    // timing
    static float deltaTime = 0.0f;    // time between current frame and last frame
    static float lastFrame = 0.0f;
    
    // light define
    static glm::vec3 lightPos(0.0f, 4.0f,-2.0f);
    
    
    Model nanosuit_model;
    void init(){
    
        camera = new GLFWCamera;
        camera->pos.y = 10.0f;
        camera->pos.z = 25.0f;
        // GL depth zbuffer
        glEnable(GL_DEPTH_TEST);
        //SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag");
        nanosuit_model.readMesh("scene/model/nanosuit.obj");
        nanosuit_model.useSimpleShader();
        nanosuit_model.debugLocations();
        //nanosuit_model.assignMaterial(SurfaceShader);
    }
    
    // ----------- Render Loop ----------
    void display(){
        // per-frame time logic
                // --------------------
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        // object .vert settings
        glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f,  1000.0f);
        glm::mat4 view = camera->GetViewMatrix();
        // object world transformation
        glm::mat4 model = glm::mat4(1.0f);
        nanosuit_model.useSimpleShaderMatrix(projection,view,model);
    
    
    
        //SurfaceShader.setMat4("projection", projection);
        //SurfaceShader.setMat4("view", view);
        //SurfaceShader.setMat4("model", model);
    
    
        nanosuit_model.draw();
    
    
    }
    
    
    int main()
    {
        glfwInit();
        FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT);
        glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback);
        glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback);
        glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback);
        init();
        // RENDER--------------
        while(!glfwWindowShouldClose(FrameWindow.getWindow())){
            processInput(FrameWindow.getWindow());
            display();
            glfwSwapBuffers(FrameWindow.getWindow());
            glfwPollEvents();
        }
        delete camera;
        return 0;
    }
    
    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);
    }
    
    void processInput(GLFWwindow *window)
    {
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, true);
        if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD);
        if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD);
        if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT);
        if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT);
    }
    
    // ROTATE VIEW DIR
    void mouse_callback(GLFWwindow* window, double xpos, double ypos){
    
        int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE);
        int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT);
        int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT);
        // set up the camera view
        if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS)
        {
            if (firstMouse){
                lastX = xpos;
                lastY = ypos;
                firstMouse = false;
            }
            float xoffset = xpos - lastX;
            float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
            lastX = xpos;
            lastY = ypos;
            camera->processMouseMove(xoffset,yoffset);
        }
        if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){
            firstMouse = true;
        }
    
    
        // Move Camera Position
        if( middow_mouse_state == GLFW_PRESS) {
    
            if (firstMiddowMouse){
                lastX = xpos;
                lastY = ypos;
                firstMiddowMouse = false;
            }
            float xoffset = xpos - lastX;
            float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
            lastX = xpos;
            lastY = ypos;
            camera->pos.x += xoffset*0.01f;
            camera->pos.y += yoffset*0.01f;
    
        }
        if ( middow_mouse_state == GLFW_RELEASE){
            firstMiddowMouse = true;
        }
    
    }
    
    void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){
        camera->processFov(yoffset);
    }
    main.cpp
    cmake_minimum_required(VERSION 3.5)
    
    project(Triangle)
    
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    # OPENGL
    find_package(OpenGL REQUIRED)
    include_directories(${OpenGL_INCLUDE_DIRS})
    link_directories(${OpenGL_LIBRARY_DIRS})
    add_definitions(${OpenGL_DEFINITIONS})
    
    if(NOT OPENGL_FOUND)
        message(ERROR " OPENGL not found!")
    endif(NOT OPENGL_FOUND)
    
    # GLEW
    set(GLEW_HOME D:/plugin_dev/libs/glew-2.1.0)
    include_directories(${GLEW_HOME}/include)
    link_directories(${GLEW_HOME}/lib/Release/x64)
    
    # GLFW
    set(GLFW_HOME D:/plugin_dev/libs/glfw-3.3.1.bin.WIN64)
    include_directories(${GLFW_HOME}/include/)
    link_directories(${GLFW_HOME}/lib-vc2019)
    
    # STB
    include_directories(D:/plugin_dev/libs/stb)
    
    # GLM
    include_directories(D:/plugin_dev/libs/GLM_include)
    
    # Assimp
    include_directories(D:/plugin_dev/libs/assimp-5.0.1_bin/win_vs2019/include)
    
    if(CMAKE_BUILD_TYPE STREQUAL Debug)
        message(">> Cmake will use debug mode to link debug lib")
        link_directories(D:/plugin_dev/libs/assimp-5.0.1_bin/win_vs2019/Debug) # we first link the debug
        link_libraries(assimp-vc142-mtd)
    else()
        link_directories(D:/plugin_dev/libs/assimp-5.0.1_bin/win_vs2019/Release) # we first link the debug
        link_libraries(assimp-vc142-mt)
    endif()
    
    
    #json
    include_directories(D:/plugin_dev/libs/nlohmann)
    
    # output excutable dir
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build)
    
    
    # SRC FILE
    FILE(
        GLOB
        SRC
        *.cpp *.h
        )
    
    add_executable(Triangle ${SRC} ALG_SceneDelegate.h)
    target_link_libraries(Triangle glew32s.lib glfw3 opengl32 )
    CMakeLists

    CP19:

    只做了个描述diffuse贴图的,其他的通道跟灯光有关系,普通的烂灯光,烂材质懒的写。

    {
      "name": "simple",
      "project_dir": "D:/plugin_dev/opengl/CP_19/Triangle/build/scene",
      "models": [
        "model/nanosuit.obj"
      ],
      "mats": {
        "glass": {
          "shader_define": {
            "___comment___1": "type=0 is default no texture shader; ",
            "___comment___2": "type=1 use inline texture; ",
            "___comment___3": "type=2 use our json code shader,this may be use in our ui  ",
            "___comment___4": "type=3 from file",
            "vert_file": "",
            "frag_file": "",
            "code_type": 1,
            "frag_code": "",
            "vert_code": ""
          },
          "params_define": {
            "diffuse": "model/glass_dif.png"
          }
        },
        "leg": {
          "shader_define": {
            "code_type": 1,
            "vert_file": "",
            "frag_file": "",
            "frag_code": "",
            "vert_code": ""
          },
          "params_define": {
            "diffuse": "model/leg_dif.png",
            "specular": "model/leg_showroom_spec.png"
          }
        },
        "hand": {
          "shader_define": {
            "code_type": 1,
            "vert_file": "",
            "frag_file": "",
            "frag_code": "",
            "vert_code": ""
          },
          "params_define": {
            "diffuse": "model/hand_dif.png",
            "specular": "model/hand_showroom_spec.png"
          }
        },
        "body": {
          "shader_define": {
            "code_type": 1,
            "vert_file": "",
            "frag_file": "",
            "frag_code": "",
            "vert_code": ""
          },
          "params_define": {
            "diffuse": "model/mat2_diffuse.png",
            "specular": "model/mat2_specular.png"
          }
        },
        "helmet": {
          "shader_define": {
            "code_type": 1,
            "vert_file": "",
            "frag_file": "",
            "frag_code": "",
            "vert_code": ""
          },
          "params_define": {
            "diffuse": "model/helmet_diff.png",
            "specular": "model/helmet_showroom_spec.png"
          }
        },
        "arms": {
          "shader_define": {
            "code_type": 1,
            "vert_file": "",
            "frag_file": "",
            "frag_code": "",
            "vert_code": ""
          },
          "params_define": {
            "diffuse": "model/arm_dif.png",
            "specular": "model/arm_showroom_spec.png"
          }
        }
      },
    
      "assignMaterial": {
        "/Visor": "glass",
        "/Lights": "glass",
        "/Legs": "leg",
        "/hands": "hand",
        "/Arms": "arms",
        "/Helmet": "helmet",
        "/Body": "body"
      },
    
    
      "lights": {
        "lgt1":
        {
          "shader_define":
          {
            "lightType": "pointLight",
            "code_type": 1,
            "vert_file": "",
            "frag_file": "",
            "frag_code": "",
            "vert_code": ""
          },
          "params_define":
          {
            "pos" : [0.0, 10.0, 0.0],
            "sensitive" : 1.0,
            "color": [1.0, 0.0, 0.0]
          }
        },
        "lgt2":
        {
          "shader_define":
          {
            "lightType": "pointLight",
            "vert_file": "",
            "frag_file": "",
            "code_type": 1,
            "frag_code": "",
            "vert_code": ""
          },
          "params_define":
          {
            "pos" : [0.0, 10.0, 0.0],
            "sensitive" : 1.0,
            "color": [1.0, 0.0, 0.0]
          }
        },
        "lgt3":
        {
          "shader_define":
          {
            "lightType": "dirLight",
            "code_type": 1,
            "frag_code": "",
            "vert_code": ""
          },
          "params_define":
          {
            "pos" : [0.0, 10.0, 0.0],
            "sensitive" : 1.0,
            "color": [1.0, 0.0, 0.0],
            "dir": [1.0, -1.0, 0.0]
          }
        }
    
      },
    
      "assignLights":{
        "/lights/light1": "lgt1",
        "/lights/light2": "lgt2",
        "/lights/light3": "lgt3"
      }
    
    }
    scene.json
    #define GLEW_STATIC
    // GLEW
    #include <GL/glew.h>
    #include <cstdlib>
    #undef GLFW_DLL
    // GLFW
    #include <GLFW/glfw3.h>
    #include <iostream>
    #include "ALG_LoadShader.h"
    #include "ALG_LoadTexture.h"
    #include "ALG_GLFWCamera.h"
    #include "ALG_FrameWindow.h"
    #include "ALG_ModelDelegate.h"
    #include "ALG_SceneDelegate.h"
    #include "ALG_DrawGrid.h"
    #include <cmath>
    
    
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    using namespace AlgebraMaster;
    
    
    const unsigned int SRC_WIDTH = 1400;
    const unsigned int SRC_HEIGHT = 720;
    
    
    static GLuint cubeVAO,VBO;
    static GLuint lightVAO;  //VBO stays the same; the vertices are the same for the light object which is also a 3D cube
    
    
    static LoadShader SurfaceShader;
    
    void init();
    void display();
    
    
    void processInput(GLFWwindow *window);
    void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize
    void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse
    void scroll_callback(GLFWwindow *window, double xoffset, double yoffset);
    
    
    // camera
    static GLFWCamera *camera;
    static float lastX =  float(SRC_WIDTH) / 2.0f;
    static float lastY =  float(SRC_HEIGHT) / 2.0f;
    static bool firstMouse = true;
    static bool firstMiddowMouse = true;
    // timing
    static float deltaTime = 0.0f;    // time between current frame and last frame
    static float lastFrame = 0.0f;
    
    // light define
    static glm::vec3 lightPos(0.0f, 4.0f,-2.0f);
    
    static Scene scene;
    static DrawGrid grid;
    void init(){
    
    
    
        camera = new GLFWCamera;
        camera->pos.y = 5.0f;
        camera->pos.z = 25.0f;
        // GL depth zbuffer
        glEnable(GL_DEPTH_TEST);
    
    
        //SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag");
    
    
        scene.read("scene/scene.json");
        scene.parseInitialize();
        scene.parseModel();
        scene.parseMats();
        scene.parseAssignMats();
    
        grid.initialize();
    }
    
    // ----------- Render Loop ----------
    void display(){
    
        // per-frame time logic
                // --------------------
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
    
    
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        // object .vert settings
        glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f,  1000.0f);
        glm::mat4 view = camera->GetViewMatrix();
        // object world transformation
        glm::mat4 model = glm::mat4(1.0f);
    
    
        scene.setMatrix(projection,view,model);
        //SurfaceShader.setMatrix(model,view,projection);
        //scene.assignMaterial(SurfaceShader);
    
        scene.draw();
    
    
        grid.draw(projection,view);
    
    }
    
    
    int main()
    {
        glfwInit();
        FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT);
        glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback);
        glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback);
        glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback);
        init();
        // RENDER--------------
        while(!glfwWindowShouldClose(FrameWindow.getWindow())){
            processInput(FrameWindow.getWindow());
            display();
            glfwSwapBuffers(FrameWindow.getWindow());
            glfwPollEvents();
        }
        delete camera;
        return 0;
    }
    
    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);
    }
    
    void processInput(GLFWwindow *window)
    {
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, true);
        if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD);
        if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD);
        if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT);
        if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT);
    }
    
    // ROTATE VIEW DIR
    void mouse_callback(GLFWwindow* window, double xpos, double ypos){
    
        int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE);
        int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT);
        int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT);
        // set up the camera view
        if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS)
        {
            if (firstMouse){
                lastX = xpos;
                lastY = ypos;
                firstMouse = false;
            }
            float xoffset = xpos - lastX;
            float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
            lastX = xpos;
            lastY = ypos;
            camera->processMouseMove(xoffset,yoffset);
        }
        if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){
            firstMouse = true;
        }
    
    
        // Move Camera Position
        if( middow_mouse_state == GLFW_PRESS) {
    
            if (firstMiddowMouse){
                lastX = xpos;
                lastY = ypos;
                firstMiddowMouse = false;
            }
            float xoffset = xpos - lastX;
            float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
            lastX = xpos;
            lastY = ypos;
            camera->pos.x += xoffset*0.01f;
            camera->pos.y += yoffset*0.01f;
    
        }
        if ( middow_mouse_state == GLFW_RELEASE){
            firstMiddowMouse = true;
        }
    
    }
    
    void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){
        camera->processFov(yoffset);
    }
    main.cpp

    其他的代码可以看下面CP20。

    CP20:

    透明,透明只跟绘制顺序相关。

    比如这个我先绘制我的网格,然后绘制我的立方体,最后对透明物体排序。

     然后开启这些脑残特性,

     // GL depth zbuffer
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    #version 450 core
    // Final Color To export
    out vec4 FragColor;
    
    // from vert shader
    in vec3 f_Normal;
    in vec2 f_TexCoord;
    in vec3 f_Pos; // fragment position
    
    
    uniform sampler2D diffuse_map;
    
    
    void main()
    {
        vec4 df = texture(diffuse_map, f_TexCoord);
        FragColor = df;
    }
    SurfaceShader.frag
    #version 450 core
    // INCOMING DATA
    layout ( location = 0 ) in vec4 v_position; //  pos
    //layout ( location = 1 ) in vec3 v_normal;   //  norm
    layout ( location = 1 ) in vec2 v_texCoord; //  st
    
    // define out data
    out vec2 f_TexCoord;
    // normal at world matrix, we direct from C++ calcalation
    out vec3 f_Normal;  // to world matrix : mat3( transpose(inverse(model)) ) * v_normal;
    out vec3 f_Pos;
    
    
    // INCOMING THE MATRIX FROM CLIENT to transform the gl point position
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;
    
    
    
    
    
    void main(){
        // Transform the world matrix to view matrix
        gl_Position = projection *   view * model * v_position;
    
        //f_Normal = mat3(transpose(inverse(model))) * v_normal;  // f_Normal at world matrix
        f_TexCoord = v_texCoord;          // out TexCoord
        f_Pos = vec3(model *v_position);  // out fragment position
    }
    SurfaceShader.vert
    //
    // Created by admin on 2020/2/27.
    //
    
    #ifndef TRIANGLE_OGLHELPER_H
    #define TRIANGLE_OGLHELPER_H
    #define GLEW_STATIC
    #include <GL/glew.h>
    
    void CreateGeometryBuffer(unsigned int &VAO, unsigned int &VBO);
    
    
    void CreateGeometryBuffer(unsigned int &VAO, unsigned int &VBO){
    
        glCreateVertexArrays(1, &VAO);
        glCreateBuffers(1,&VBO);
        glBindVertexArray(VAO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
    
    }
    
    
    
    
    
    
    
    #endif //TRIANGLE_OGLHELPER_H
    OGLHelper.h
    //
    // Created by admin on 2020/2/25.
    //
    
    #ifndef TRIANGLE_ALG_VERTEX_H
    #define TRIANGLE_ALG_VERTEX_H
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    
    namespace AlgebraMaster {
        using namespace std;
        struct Vertex {
            glm::vec3 position;
            glm::vec3 normal;
            glm::vec2 texCoords;
            glm::vec3 tangent;
            glm::vec3 biTangent;
        };
    }
    
    #endif //TRIANGLE_ALG_VERTEX_H
    ALG_Vertex.h
    //
    // Created by admin on 2020/2/25.
    //
    
    #ifndef TRIANGLE_ALG_TEXTURE_H
    #define TRIANGLE_ALG_TEXTURE_H
    
    #include <iostream>
    namespace AlgebraMaster{
    
    using namespace std;
    struct Texture{
        // Reference houdini principledshader
        enum Type {
            BASECOLOR_MAP, SPECULAR_MAP, EMISSION_MAP,
            BUMP_MAP, NORMAL_MAP, IOR_MAP,
            OPACITY_MAP, DISPLACE_MAP,
            CHAN_TEX0,CHAN_TEX1,CHAN_TEX2,CHAN_TEX3,
            CHAN_TEX4,CHAN_TEX5,CHAN_TEX6,CHAN_TEX7,
            CHAN_TEX8,CHAN_TEX9_CHAN_TEX10
        };
        unsigned int id;             // glBindTexture(GL_TEXTURE_2D,id);
        unsigned int textureUnitID;  // for shaderMethod set the texture unit: gluniformli(location, texture_unit)
        string path;                 // ralative path
        Type texType;                // type
        unsigned int texChannel;     // glActiveTexture(texChannel);
    };
    
    }
    
    #endif //TRIANGLE_ALG_TEXTURE_H
    ALG_Texture.h
    //
    // Created by Admin on 2020/2/23.
    //
    
    #ifndef TRIANGLE_ALG_SCENEDELEGATE_H
    #define TRIANGLE_ALG_SCENEDELEGATE_H
    #include <iostream>
    #include <json.hpp>
    #include <string>
    #include <fstream>
    #include <iomanip>
    #include <vector>
    #include "ALG_LoadShader.h"
    #include "ALG_ModelDelegate.h"
    #include "ALG_LoadTexture.h"
    #include "ALG_MeshDelegate.h" // texture struct
    
    
    namespace AlgebraMaster{
    // namespace
    using namespace std;
    using json = nlohmann::json;
    //
    
    bool checkJsonError(json &j,string msg);
    bool checkJsonError(json &j,string msg)
    {
        if (j.is_null()) {
            cout << "ERROR JSON:" << msg<<endl;
            return true;
        }
        return false;
    }
    
    
    
    template <typename T>
    void FreeSTLMemory(T & container);
    
    template <typename T>
    void FreeSTLMemory(T & container){
        // release mats mem
        for(auto &c: container){
            delete c;
        }
        container.clear();
    }
    
    
    Texture *CreateTexture(const LoadTexture &textureLoader,
                               const string &relativeTexturePath,
                               Texture::Type type,
                               unsigned int textureChannel,
                               unsigned int textureUnitID);
    
    Texture *CreateTexture(const LoadTexture &textureLoader,
                           const string &relativeTexturePath,
                           Texture::Type type,
                           unsigned int textureChannel,
                           unsigned int textureUnitID)
    {
        // create texture object
        auto *texture = new Texture;                // Create our texture object
        texture->id = textureLoader.getTextureID(); // Assign GL_TextureID to our texture object
        texture->texType = type;  // set texture type
        texture->path = relativeTexturePath;            // set texture path is relative
        texture->texChannel = textureChannel;
        texture->textureUnitID = textureUnitID;   //current unique texture unit
        return texture;
    }
    
    
    
    //* scene description from json object/
    class Scene{
    public:
        Scene();
        virtual ~Scene();
        void read(const string &path);
        void save(const string &path)const;
        virtual void draw();
        string getSceneName()const;
        void setSceneName(const string &name);
        Texture * getTextureByPath(const string &path){
            for(auto &t: allTextures){
                if(t->path == path)return t;
            }
            return nullptr;
        }
    
    
        vector<LoadShader *> allShaders;
        vector<Texture*> allTextures; // all texture from json file , this index will as GL_activeTexture(TEXTURE0+i)
        LoadShader* getShaderByName(const string &name){
            for(auto &m : allShaders){
                if(m->shaderName == name)
                    return m;
            }
            return nullptr;
        }
        void debugShaders(){
            for(auto &s: allShaders){
                cout <<"Scene::debugShaders debug shader pool have:" << s->shaderName <<endl;
            }
        }
        void parseInitialize();
        // read mesh
        void parseModel();
        void parseMats();
        void parseAssignMats();
        void setMatrix(glm::mat4 &proj , glm::mat4 & view , glm::mat4 model = glm::mat4(1.0f));
        //override all model mats
        void assignMaterial(LoadShader &shader){
            for(auto &m : allModels){
                m->assignMaterial(shader);
            }
        }
    
    
    private:
        // * scene description json obj */
        json j;
        vector<Model*> allModels;
    
    
        // proj
        string project_dir;
        //
        bool textureIsLoaded(const string &texturePath);
    
    public:
        static int currentActiveTextureChannel;
        static int currentTextureLoaderIndex;
    };
    int Scene::currentActiveTextureChannel = GL_TEXTURE0;
    int Scene::currentTextureLoaderIndex = 0;
    
    // ------------------ DEFINE FUNCTION --------------------------
    Scene::Scene(){
    
    }
    Scene::~Scene() {
        // release mats mem
    
        cout << "---------------Memory Release----------------------
    ";
        cout << "free model's mem 
    ";
        FreeSTLMemory(allModels);
        //
        cout << "free all textures mem 
    ";
        FreeSTLMemory(allTextures);
        //
        cout << "free all shaders mem 
    ";
        FreeSTLMemory(allShaders);
        cout << "---------------Memory Release----------------------
    ";
    }
    
    bool Scene::textureIsLoaded(const string &texturePath) {
        bool isLoaded = false;
        for(auto &tex: allTextures){
            if (tex->path == texturePath){
                isLoaded = true;
            }
        }
        return isLoaded;
    }
    
    void Scene::setMatrix(glm::mat4 &proj , glm::mat4 &view , glm::mat4 model)
    {
        for(auto &mod :allModels){
            for(auto &loc: mod->getLocations()) {
                loc->mesh->shader.setMatrix(model, view, proj);
            }
        }
    }
    
    
    
    // Read File
    void Scene::read(const string &path) {
        ifstream  in(path.c_str());
        in >> j;
    }
    
    // Write File
    void Scene::save(const string &path) const{
        // write prettified JSON to another file
        ofstream o(path.c_str());
        o << setw(4) << j << std::endl;
    }
    
    
    string Scene::getSceneName() const {
        auto name = j["name"];
        if( name){
            return name;
        }
        return "ERROR SCENE NAME";
    }
    void Scene::setSceneName(const string &name)  {
        j["name"] = name;
    }
    
    void Scene::draw() {
        for(auto &m : allModels){
            m->draw();
        }
    }
    
    void Scene::parseInitialize()
    {
        string temp_proj_dir = j["project_dir"];
        temp_proj_dir += "/";
        project_dir = temp_proj_dir;
    
    }
    
    void Scene::parseModel() {
        cout << j["models"] <<endl;
        for(string path :j["models"]){
            auto *model = new Model;
            string absPath = project_dir + path;
            cout << "Scene Parse Read mesh:" << absPath <<endl;
            model->readMesh(absPath);
            this->allModels.emplace_back(model);
        }
    }
    
    void Scene::parseMats() {
        json mats = j["mats"];
        for (auto& mat : mats.items())
        {
            json matNameObject = mat.key(); // json mat name
            json matContentObject = mat.value();  // json tex
    
    
            json shaderDefineObject =  matContentObject["shader_define"];
            json codeTypeObject = shaderDefineObject["code_type"];
            json fragCodeObject = shaderDefineObject["frag_code"];
            json vertCodeObject = shaderDefineObject["vert_code"];
    
    
            auto *shader = new LoadShader;
            bool jsonIsError = false;   // if is error , create default mat
            jsonIsError = checkJsonError(shaderDefineObject,"Can not find key ->shader_define  ,create default color shader");
            if(jsonIsError)
            {
                shader->asSimpleShader();
                return;
            }
            jsonIsError = checkJsonError(codeTypeObject,"Can not find key ->code_type  ,create default color shader");
            if(jsonIsError){
                shader->asSimpleShader();
                return;
            }
            jsonIsError = checkJsonError(fragCodeObject,"Can not find key ->frag_code  ,create default color shader");
            if(jsonIsError){
                shader->asSimpleShader();
                return;
            }
            jsonIsError = checkJsonError(vertCodeObject,"Can not find key ->vert_code  ,create default color shader");
            if(jsonIsError){
                shader->asSimpleShader();
                return;
            }
    
    
            // JSON shader_define values
            string std_strMatName = matNameObject.get<string>(); // mat name
            int codeType = codeTypeObject.get<int>();
            string fragCode = fragCodeObject.get<string>();
            string vertCode = vertCodeObject.get<string>();
    
            cout << "system create mat:" << std_strMatName << " codeType:" <<codeType <<endl;
    
            switch (codeType)
            {
                case 0:
                {
                    shader->asSimpleShader();
                    shader->shaderName = std_strMatName;
                    break;
                }
                case 1:
                {
                    shader->asSimpleTextureShader();
                    shader->shaderName = std_strMatName;
                    break;
                }
                case 2:
                {
                    shader->fromSrc(vertCode,fragCode);
                    shader->shaderName = std_strMatName;
                    break;
                }
                default:
                    // create in line shader
                    shader->asSimpleShader();
                    shader->shaderName = std_strMatName;
                    break;
            }
    
            // shader param define
            json paramDefineObject = matContentObject["params_define"];
            for(auto &params: paramDefineObject.items())
            {
                json paramNameObject = params.key();
                json valueObject = params.value(); // may be relative texture path , or shader value
    
                string paramName = paramNameObject.get<string>();
                if(paramName == "diffuse")
                {
                    string texRelativePath = valueObject.get<string>();
                    string texAbsPath = project_dir + texRelativePath;
                    // create texture loader
                    LoadTexture textureLoader;
                    textureLoader.load(texAbsPath.c_str());
                    // if texture load error, pass this loading
                    if (!textureLoader.loadStatus)
                        continue;
    
                    // if this texture have loaded
                    if (textureIsLoaded(texRelativePath))
                    {
                        shader->textures.emplace_back(getTextureByPath(texRelativePath)); // make connection with pair shader
                        continue;
                    }
                    unsigned int texChannel = Scene::currentActiveTextureChannel;
                    unsigned int textureUnitID = Scene::currentTextureLoaderIndex;   //current unique texture unit
                    Texture *tex = CreateTexture(textureLoader,texRelativePath,
                                                 Texture::BASECOLOR_MAP,
                                                 texChannel,
                                                 textureUnitID);
                    cout << "OPENGL->register <diffuse> texture:" << texRelativePath <<" ID:"<<tex->id<< " channel:"<<tex->texChannel<< " unit:"<<tex->textureUnitID <<endl;
                    Scene::currentTextureLoaderIndex+=1;
                    Scene::currentActiveTextureChannel+=1;
                    allTextures.emplace_back(tex);
                    shader->textures.emplace_back(tex);// make connection with pair shader
                }
    
                if(paramName == "specular")
                {
                    string texRelativePath = valueObject.get<string>();
                    string texAbsPath = project_dir + texRelativePath;
    
                    // create texture loader
                    LoadTexture textureLoader;
                    textureLoader.load(texAbsPath.c_str());
                    // if texture load error, pass this loading
                    if (!textureLoader.loadStatus)
                        continue;
    
                    // if this texture have loaded
                    if (textureIsLoaded(texRelativePath)){
                        shader->textures.emplace_back(getTextureByPath(texRelativePath)); // make connection with pair shader
                        continue;
                    }
                    unsigned int texChannel = Scene::currentActiveTextureChannel;
                    unsigned int textureUnitID = Scene::currentTextureLoaderIndex;   //current unique texture unit
    
    
                    Texture *tex = CreateTexture(textureLoader,texRelativePath,
                                                 Texture::SPECULAR_MAP,
                                                 texChannel,
                                                 textureUnitID);
                    cout << "OPENGL->register <specular> texture:" << texRelativePath <<" ID:"<<tex->id<< " channel:"<<tex->texChannel<< " unit:"<<tex->textureUnitID <<endl;
                    Scene::currentTextureLoaderIndex+=1;
                    Scene::currentActiveTextureChannel+=1;
    
                    allTextures.emplace_back(tex);
                    shader->textures.emplace_back(tex);// make connection with pair shader
                }
    
            } // end of mat param settings
    
            allShaders.emplace_back(shader); // place shader in our container
    
        }//end of loop material
    }
    
    void Scene::parseAssignMats() {
    
        // loop all model
        json matTree = j["assignMaterial"];
        for(auto &tree: matTree.items()){
            json locationPWDObject = tree.key();
            json locationMatNameObject = tree.value();
    
            string locationPWD = locationPWDObject.get<string>();
            string locationMatName = locationMatNameObject.get<string>();
            LoadShader *shader = getShaderByName(locationMatName);
            if (!shader){
                cout << "ERROR Try to assign:"<< locationPWD <<",But can not find material in material pool:" << locationMatName <<endl;
                continue;
            }
    
    
            // loop all model, find the location
            for(auto &model: allModels){
                SceneLocation *loc = model->getLocationByPath(locationPWD);
                loc->mesh->assignMaterial(*shader);
                cout << "!!!!!!!!!!!!!!!!!!!!!assign:" << shader->shaderName << " to:" << loc->pwd <<endl;
            }
        }
    }
    
    }// end of namespace
    #endif //TRIANGLE_ALG_SCENEDELEGATE_H
    ALG_SceneDelegate.h
    //
    // Created by admin on 2020/2/21.
    //
    
    #ifndef TRIANGLE_ALG_MODELDELEGATE_H
    #define TRIANGLE_ALG_MODELDELEGATE_H
    #include <string>
    #include <vector>
    #include "ALG_MeshDelegate.h"
    #include "ALG_LoadShader.h"
    #include <assimp/Importer.hpp>
    #include <assimp/scene.h>
    #include <assimp/postprocess.h>
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    
    
    namespace AlgebraMaster
    {
    using namespace std;
    
    
    // helper method for exchange aiMatrix to glm matrix
    void exchange_matrix_data(glm::mat4 &DesMatrix,const aiMatrix4x4 & srcAssimpMat);
    
    // ----------------------- SCENE LOCATION --------------------------------
    struct SceneLocation{
        // function
        SceneLocation();
        ~SceneLocation();
    
        // vars
        string pwd;
        glm::mat4 worldTransform;
        string type; // group or Mesh
        Mesh *mesh;
    };
    
    SceneLocation::SceneLocation():pwd(""),worldTransform(1.0f),type("group"),mesh(nullptr){
    }
    SceneLocation::~SceneLocation() {
        if(mesh)
            delete mesh;
    }
    
    // ----------------------- SCENE LOCATION --------------------------------
    
    
    
    
    // ----------------------- SCENE Model --------------------------------
    class Model{
    public:
        //* Read Mesh from path */
        Model() = default;
        explicit Model(const string& path);
        ~Model();
    
        void readMesh(const string& path);
        //* overwrite all mesh material */
        void assignMaterial(LoadShader &shader);
        //* paint mesh in opengl */
        void draw();
        //* get the locations */
        vector<SceneLocation*> &getLocations();
    
        //* get location by name /
        SceneLocation * getLocationByPath(const string &path);
    
        // use default shader
        inline void useSimpleShader(){
            cout << "Model Used basic shader that should call useSimpleShaderMatrix() in render loop !
    ";
            for(auto &loc :locations){
                loc->mesh->shader.asSimpleShader();
            }
        }
        inline void useSimpleShaderMatrix(glm::mat4 &proj, glm::mat4 &view, glm::mat4 &model){
            for(auto &loc :locations){
                loc->mesh->shader.use();
                loc->mesh->shader.setMat4("projection", proj);
                loc->mesh->shader.setMat4("view", view);
                loc->mesh->shader.setMat4("model", model);
    
            }
        }
        inline void debugLocations(){
            cout << "debug locations:
    ";
            cout << "{
    ";
            for(auto&loc : locations){
                cout <<"	SceneGraph:" <<loc->pwd <<"	Type:" <<loc->type << endl;
            }
            cout << "}
    ";
        }
    
    
    
    private:
    
        // vars
        vector<SceneLocation*> locations;
        string directory; // the mesh location at filesystem path
    
    
        // functions from assimp to our struct
        void processNode(aiNode *assimpNode,const aiScene* assimpScene, string pwd);
        Mesh* processMesh(aiMesh *assimpMesh, const aiScene *assimpScene);
    
    };
    
    
    
    // constructor
    Model::Model(const string &path) {
        readMesh(path);
    }
    Model::~Model() {
        for(auto & location : locations){
            delete location;
        }
        locations.clear();
    }
    
    vector<SceneLocation *> &Model::getLocations() {
        return this->locations;
    }
    
    SceneLocation * Model::getLocationByPath(const string &path){
        for(auto &loc: this->locations){
            if(loc->pwd == path)return loc;
        }
        return nullptr;
    }
    
    void Model::draw(){
        for(auto &loc: locations){
            loc->mesh->draw();
        }
    }
    void Model::assignMaterial(LoadShader &shader) {
        for(auto & location : locations){
            location->mesh->assignMaterial(shader);
        }
    }
    
    void Model::readMesh(const string &path)
    {
        Assimp::Importer import;
        const aiScene * scene = import.ReadFile(path.c_str(),
                aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
        // check error
        if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){
            cout << "ERROR::ASSIMP:: " << import.GetErrorString() << endl;
            return ;
        }
        // retrieve the directory path of the filepath
        directory = path.substr(0, path.find_last_of('/'));
    
        // process ASSIMP's root node recursively
        processNode(scene->mRootNode, scene,"/");
    
        // fix location pwd end with '/', we should remove it
        for(auto &loc : locations){
            string pwd = loc->pwd;
            if (pwd[pwd.length()-1] == '/'){
                loc->pwd = string(pwd.begin(),pwd.end()-1);
            }
        }
    }
    
    void Model::processNode(aiNode *assimpNode, const aiScene *assimpScene, string pwd) {
        // process each mesh located at the current node
        aiMatrix4x4 mat =  assimpNode->mTransformation;
        auto *location = new SceneLocation;
        location->pwd = pwd;
        if (assimpNode->mNumMeshes<=0)
            location->type = "group";
        else
            location->type = "mesh";
        location->pwd = pwd;
        exchange_matrix_data(location->worldTransform,mat);
    
        // loop this node's meshs
        for(unsigned int i = 0; i < assimpNode->mNumMeshes; i++)
        {
            // the node object only contains indices to index the actual objects in the scene.
            // the scene contains all the data, node is just to keep stuff organized (like relations between nodes).
            aiMesh* assimpMesh = assimpScene->mMeshes[assimpNode->mMeshes[i]];
            Mesh* mesh = processMesh(assimpMesh,assimpScene);
            location->mesh = mesh;
            this->locations.emplace_back(location);
        }
        // after we've processed all of the meshes (if any) we then recursively process each of the children nodes
        for(unsigned int i = 0; i < assimpNode->mNumChildren; i++)
        {
            string pathName =  pwd + assimpNode->mChildren[i]->mName.C_Str();
            pathName += "/";
            processNode(assimpNode->mChildren[i], assimpScene,pathName);
        }
    
    }
    Mesh* Model::processMesh(aiMesh *assimpMesh, const aiScene *assimpScene)
    {
        // our mesh interface pointer
        Mesh *mesh = new Mesh;
        // construct mesh data from assimpMesh
        for(unsigned int i =0; i <assimpMesh->mNumVertices;i++){
            Vertex vertex;
            vertex.position.x= assimpMesh->mVertices[i].x;
            vertex.position.y= assimpMesh->mVertices[i].y;
            vertex.position.z= assimpMesh->mVertices[i].z;
            vertex.normal.x = assimpMesh->mNormals[i].x;
            vertex.normal.y = assimpMesh->mNormals[i].y;
            vertex.normal.z = assimpMesh->mNormals[i].z;
            // tex
            if(assimpMesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
            {
                // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
                // use allModels where a vertex can have multiple texture coordinates so we always take the first set (0).
                vertex.texCoords.x = assimpMesh->mTextureCoords[0][i].x;
                vertex.texCoords.y = assimpMesh->mTextureCoords[0][i].y;
            }
            else{
                vertex.texCoords.x = 0.0f;
                vertex.texCoords.y = 0.0f;
            }
            // tangent
            vertex.tangent.x = assimpMesh->mTangents[i].x;
            vertex.tangent.y = assimpMesh->mTangents[i].y;
            vertex.tangent.z = assimpMesh->mTangents[i].z;
            // bitangent
            vertex.biTangent.x = assimpMesh->mBitangents[i].x;
            vertex.biTangent.y = assimpMesh->mBitangents[i].y;
            vertex.biTangent.z = assimpMesh->mBitangents[i].z;
            mesh->vertices.emplace_back(vertex);
        }
        // indices
        for(int i=0; i<assimpMesh->mNumFaces; i++){
            aiFace face = assimpMesh->mFaces[i];
            for(int j=0;j<face.mNumIndices;j++){
                mesh->indices.emplace_back(face.mIndices[j]);
            }
        }
        mesh->setupMesh();
        return mesh;
    
    }
    // ----------------------- SCENE Model --------------------------------
    
    
    
    
    // ---- Helper
    void exchange_matrix_data(glm::mat4 &DesMatrix,const aiMatrix4x4 & srcAssimpMat){
    
        DesMatrix[0].x = srcAssimpMat.a1;
        DesMatrix[0].y = srcAssimpMat.a2;
        DesMatrix[0].z = srcAssimpMat.a3;
        DesMatrix[0].w = srcAssimpMat.a4;
    
        DesMatrix[1].x = srcAssimpMat.b1;
        DesMatrix[1].y = srcAssimpMat.b2;
        DesMatrix[1].z = srcAssimpMat.b3;
        DesMatrix[1].w = srcAssimpMat.b4;
    
        DesMatrix[2].x = srcAssimpMat.c1;
        DesMatrix[2].y = srcAssimpMat.c2;
        DesMatrix[2].z = srcAssimpMat.c3;
        DesMatrix[2].w = srcAssimpMat.c4;
    
        DesMatrix[3].x = srcAssimpMat.d1;
        DesMatrix[3].y = srcAssimpMat.d2;
        DesMatrix[3].z = srcAssimpMat.d3;
        DesMatrix[3].w = srcAssimpMat.d4;
    }
    
    
    } // end of namespace
    
    #endif //TRIANGLE_ALG_MODELDELEGATE_H
    ALG_ModelDelegate.h
    #ifndef MESH_H
    #define MESH_H
    
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    #include <string>
    #include <vector>
    #include "ALG_LoadShader.h"
    #include <GL/glew.h>
    #include "ALG_TextureDelegate.h"
    #include "ALG_Vertex.h"
    namespace AlgebraMaster
    {
    
    using namespace std;
    
    
    
    
    struct Mesh
    {
    public:
        Mesh()= default;
        //* constructor */
        Mesh(const vector<Vertex> &vts,
                const vector<unsigned int>ids);
    
    // rendering data
        vector<Vertex> vertices;
        vector<unsigned int> indices;
    
        // ogl
        unsigned int VAO,VBO,EBO; // vertex array buffer
    
        //* this method need called manually */
        virtual void setupMesh();
    
        // ogl draw
        virtual void draw();
    
        // shader
        LoadShader shader;
    
        // get mat from outside
        void assignMaterial(const LoadShader & rhs_shader);
    
    };
    
    
    Mesh::Mesh(const vector<Vertex> &vts,
               const vector<unsigned int>ids):vertices(vts),indices(ids){
    
    }
    
    void Mesh::assignMaterial(const LoadShader &rhs_shader) {
        shader.fragmentShader = rhs_shader.fragmentShader;
        shader.vertexShader = rhs_shader.vertexShader;
        shader.shaderProgram = rhs_shader.shaderProgram;
        shader.projection = rhs_shader.projection;
        shader.view = rhs_shader.view;
        shader.model = rhs_shader.model;
        shader.textures = rhs_shader.textures;
    }
    
    // opengl draw the mesh
    void Mesh::draw() {
        this->shader.use();
        shader.setMatrix(shader.model,shader.view,shader.projection);
    
        string mat_prefix = "material.";
        for(auto &tex: shader.textures)
        {
            glActiveTexture(tex->texChannel);
            switch (tex->texType)
            {
                case Texture::BASECOLOR_MAP:{
                    string texchanName = mat_prefix + "diffuse_map";
                    shader.setInt(texchanName.c_str(),tex->textureUnitID);
                    break;
                }
                case Texture::SPECULAR_MAP:{
                    string texchanName = mat_prefix + "specular_map";
                    shader.setInt(texchanName.c_str(),tex->textureUnitID);
                    break;
                }
                case Texture::EMISSION_MAP:{
                    string texchanName = mat_prefix + "emission_map";
                    shader.setInt(texchanName.c_str(),tex->textureUnitID);
                    break;
                }
                case Texture::BUMP_MAP:{
                    string texchanName = mat_prefix + "bump_map";
                    shader.setInt(texchanName.c_str(),tex->textureUnitID);
                    break;
                }
                case Texture::NORMAL_MAP:{
                    string texchanName = mat_prefix + "normal_map";
                    shader.setInt(texchanName.c_str(),tex->textureUnitID);
                    break;
                }
                case Texture::IOR_MAP:{
                    string texchanName = mat_prefix + "ior_map";
                    shader.setInt(texchanName.c_str(),tex->textureUnitID);
                    break;
                }
                case Texture::OPACITY_MAP:{
                    string texchanName = mat_prefix + "opacity_map";
                    shader.setInt(texchanName.c_str(),tex->textureUnitID);
                    break;
                }
                case Texture::DISPLACE_MAP:{
                    string texchanName = mat_prefix + "displace_map";
                    shader.setInt(texchanName.c_str(),tex->textureUnitID);
                    break;
                }
                default:
                    break;
    
            } // end of switch
            glBindTexture(GL_TEXTURE_2D, tex->id); // bind current id
    
        } // end of for each textures
    
    
        // draw mesh
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
    
        // always good practice to set everything back to defaults once configured.
        glActiveTexture(GL_TEXTURE0);
    }
    
    // init our mesh data
    void Mesh::setupMesh() {
        glCreateVertexArrays(1,&VAO);           // vertex array object
        glCreateBuffers(1,&VBO);                // vertex buffer object
        glCreateBuffers(1,&EBO);                // vertex element array buffer object
        glBindVertexArray(VAO);                 // bind vertex array
    
        glBindBuffer(GL_ARRAY_BUFFER,VBO);      // bind vertex buffer
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
    
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
    
        // vertex attributes
        // position
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
        // normal
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 3*sizeof(float)) );
        //tex
        glEnableVertexAttribArray(2);
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 6*sizeof(float)) );
        //tangent
        glEnableVertexAttribArray(3);
        glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 8*sizeof(float)) );
        // bitangent
        glEnableVertexAttribArray(4);
        glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 11*sizeof(float)) );
    
        glBindVertexArray(0);
    }
    
    } // end of namespace
    
    #endif // MESH_H
    ALG_MeshDelegate.h
    #ifndef LOADTEXTURE_H
    #define LOADTEXTURE_H
    #include <GL/glew.h>
    
    // IMP the stb image loader
    #define STB_IMAGE_IMPLEMENTATION
    #include <stb_image.h>
    #include <iostream>
    using namespace std;
    
    namespace AlgebraMaster
    {
    
    
    
    class LoadTexture
    {
    public:
        LoadTexture();
        LoadTexture(const char *fileName);
        void load(const char *fileName);
        virtual ~LoadTexture();
        inline GLuint getTextureID()const{return textureID;}
        inline GLuint getImageFormat()const{return format;}
        GLuint textureID;
        GLenum format;
        bool loadStatus;
    };
    
    LoadTexture::LoadTexture() {
        loadStatus = false;
    }
    
    
    void LoadTexture::load(const char *fileName)
    {
        glGenTextures(1, &textureID);
        int width, height, nrComponents;
        unsigned char *data = stbi_load(fileName, &width, &height, &nrComponents, 0);
        if (data)
        {
            if (nrComponents == 1)
                format = GL_RED;
            else if (nrComponents == 3)
                format = GL_RGB;
            else if (nrComponents == 4)
                format = GL_RGBA;
    
            glBindTexture(GL_TEXTURE_2D, textureID);
            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
            glGenerateMipmap(GL_TEXTURE_2D);
    
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    
            stbi_image_free(data);
            loadStatus = true;
        }
        else
        {
            loadStatus = false;
            std::cout << "Texture failed to load at path: " << fileName << std::endl;
            stbi_image_free(data);
        }
    
    }
    
    LoadTexture::LoadTexture(const char *fileName){
        loadStatus = false;
        load(fileName);
    }
    LoadTexture::~LoadTexture(){}
    
    }
    #endif // LOADTEXTURE_H
    ALG_LoadTexture.h
    #ifndef LOADSHADER_H
    #define LOADSHADER_H
    
    
    #include <GL/glew.h>
    
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <sstream>
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    #include <vector>
    #include "ALG_TextureDelegate.h"
    
    namespace AlgebraMaster
    {
    
    using namespace std;
    // Shaders
    
    const char* vertexShaderSource = "#version 450 core
    "
                                     "layout (location = 0) in vec4 v_position;
    "
                                     "layout ( location = 1 ) in vec3 v_normal;
    "
                                     "layout ( location = 2 ) in vec2 v_texCoord;
    "
                                     "out vec2 myTexCoord;
    "
                                     "uniform mat4 model;
    "
                                     "uniform mat4 view;
    "
                                     "uniform mat4 projection;
    "
                                     "void main()
    "
                                     "{
    "
                                     "gl_Position = projection *   view * model * v_position;
    "
                                     "myTexCoord = v_texCoord;
    "
                                     "}";
    
    
    
    const char* fragmentShaderSource = "#version 450 core
    "
                                       "out vec4 fColor;
    "
                                       "void main()
    "
                                       "{
    "
                                       "fColor = vec4(0.5f, 0.5f, 0.5f , 1.0f);
    "
                                       "}
    ";
    
    // this have texture
    const char* fragmentShaderSource2 = "#version 450 core
    "
                                        "out vec4 fColor;
    "
                                        "in vec2 myTexCoord;
    "
                                        "struct Material
    "
                                        "{
    "
                                        "float Kd;        // diffuse mult
    "
                                        "float kS;        // specular mult
    "
                                        "float shininess; // phong pow(,shine)
    "
                                        "sampler2D diffuse_map;
    "
                                        "sampler2D specular_map;
    "
                                        "sampler2D emission_map;
    "
                                        "};
    "
                                        "uniform Material material;
    "
                                        "void main()
    "
                                        "{
    "
                                        "vec4 df_tex=texture(material.diffuse_map, myTexCoord);
    ;"
                                        "fColor = vec4(df_tex.r,df_tex.g,df_tex.b,1.0f) ;
    "
                                        "}
    ";
    
    struct LoadShader
    {
        enum ShaderIOType{FILE,INLINE_DEFAULT_PROJECTION,INLINE_TEXTURE_PROJECTION};
        void compileShaderProgram(){
            // create shader program and check it
            GLint success;
            GLchar infoLog[512];
            shaderProgram = glCreateProgram();
            glAttachShader(shaderProgram,vertexShader);
            glAttachShader(shaderProgram,fragmentShader);
            glLinkProgram(shaderProgram );
            glGetProgramiv( shaderProgram, GL_LINK_STATUS, &success );  // Get Link Status
            if (!success)
            {
                glGetProgramInfoLog( shaderProgram, 512, NULL, infoLog );
                std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED
    " << infoLog << std::endl;
            }
            // Delete the allShaders as they're linked into our program now and no longer necessery
            glDeleteShader( vertexShader );
            glDeleteShader( fragmentShader );
        }
        void compileVertexShader(string code){
            vertexShader = glCreateShader( GL_VERTEX_SHADER );
    
            const char * src = code.c_str();
            glShaderSource( vertexShader, 1, &(src), NULL );
    
            glCompileShader( vertexShader );
            GLint success;
            GLchar infoLog[512];
    
            glGetShaderiv( vertexShader, GL_COMPILE_STATUS, &success );
            if ( !success )
            {
                glGetShaderInfoLog( vertexShader, 512, NULL, infoLog );
                std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED
    " << infoLog << std::endl;
            }
        }
        void compileFragmentShader(string code){
            const char * src = code.c_str();
            GLint success;
            GLchar infoLog[512];
            fragmentShader = glCreateShader( GL_FRAGMENT_SHADER );
            glShaderSource( fragmentShader, 1, &src, NULL );
            glCompileShader( fragmentShader );
            glGetShaderiv( fragmentShader, GL_COMPILE_STATUS, &success ); // Get Compile status
            if ( !success )
            {
                glGetShaderInfoLog( fragmentShader, 512, NULL, infoLog );
                std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
    " << infoLog << std::endl;
            }
        }
    
        void fromSrc(const string &vertCode, const string &fragCode){
            compileVertexShader(vertCode);
            compileFragmentShader(fragCode);
            compileShaderProgram();
        }
    
        LoadShader(){
    
        }
        ~LoadShader(){
    
        }
    
        void asSimpleTextureShader(){
            shaderName = "simpleTex";
            shaderIOType = INLINE_TEXTURE_PROJECTION;
            compileVertexShader(vertexShaderSource);
            compileFragmentShader(fragmentShaderSource2);
            compileShaderProgram();
        }
    
    
        void asSimpleShader()
        {
            shaderName = "simpleCol";
            shaderIOType = INLINE_DEFAULT_PROJECTION;
            compileVertexShader(vertexShaderSource);
            compileFragmentShader(fragmentShaderSource);
            compileShaderProgram();
        }
    
    
        void setShaderName(const string &name){
            shaderName = name;
        }
    
        LoadShader(const char*vertPath, const char* fragPath){
            load(vertPath,fragPath);
            shaderIOType = FILE;
        }
    
        string _readFile(const char *path){
            ifstream stream;
            stringstream ss;
            stream.exceptions(ifstream::badbit);
            try
            {
                stream.open(path);    // open file
                ss << stream.rdbuf(); // get strings from file
            } catch (ifstream::failure e)
            {
                cout << "ERROR::OPEN FILE:" << path << endl;
            }
            // close file handle
            stream.close();
    
            // get str() from stringstream
            string shaderCode = ss.str();
            return shaderCode;
        }
    
        void _loadVertexShader(const char *path){
    
            // read shader code
            auto handle = _readFile(path);
            const char * shaderCode = handle.c_str();
            compileVertexShader(shaderCode);
    
        }
    
        void _loadFragmentShader(const char *path){
            // read shader code
            auto handle = _readFile(path);
            const char * shaderCode = handle.c_str();
            compileFragmentShader(shaderCode);
        }
    
        void load(const char* vertShaderPath, const char* fragShaderPath){
            shaderIOType = FILE;
            _loadVertexShader(vertShaderPath);
            _loadFragmentShader(fragShaderPath);
            // create shader program and check it
            compileShaderProgram();
        }
    
        void use(){
            glUseProgram(shaderProgram);
        }
    
        void setBool(const char *name, bool value) const
        {
            glUniform1i(glGetUniformLocation(shaderProgram, name), (int)value);
        }
        void setInt(const char *name, int value) const
        {
            glUniform1i(glGetUniformLocation(shaderProgram,name), value);
        }
        // ------------------------------------------------------------------------
        void setFloat(const char *name, float value) const
        {
            glUniform1f(glGetUniformLocation(shaderProgram, name), value);
        }
        // ------------------------------------------------------------------------
        void setVec2(const char *name, const glm::vec2 &value) const
        {
            glUniform2fv(glGetUniformLocation(shaderProgram,name), 1, &value[0]);
        }
    
        void setVec2(const char *name, float x, float y) const
        {
            glUniform2f(glGetUniformLocation(shaderProgram,name), x, y);
        }
        // ------------------------------------------------------------------------
        void setVec3(const char *name, const glm::vec3 &value) const
        {
            glUniform3fv(glGetUniformLocation(shaderProgram,name), 1, &value[0]);
        }
        void setVec3(const char *name, float x, float y, float z) const
        {
            glUniform3f(glGetUniformLocation(shaderProgram,name), x, y, z);
        }
        // ------------------------------------------------------------------------
        void setVec4(const char *name, const glm::vec4 &value) const
        {
            glUniform4fv(glGetUniformLocation(shaderProgram,name), 1, &value[0]);
        }
        void setVec4(const char *name, float x, float y, float z, float w)
        {
            glUniform4f(glGetUniformLocation(shaderProgram,name), x, y, z, w);
        }
    
        void setMat2(const char*name, const glm::mat2 &mat) const
        {
            glUniformMatrix2fv(glGetUniformLocation(shaderProgram, name), 1, GL_FALSE,glm::value_ptr(mat));
        }
    
        void setMat3(const char*name, const glm::mat3 &mat){
            GLuint location = glGetUniformLocation(shaderProgram, name);
            glUniformMatrix3fv(location,1, GL_FALSE, &mat[0][0]);
        }
    
        void setMat4(const char *name , const glm::mat4 &mat){
            GLuint location = glGetUniformLocation(shaderProgram, name);
            glUniformMatrix4fv(location,1, GL_FALSE, glm::value_ptr(mat));
        }
    
        GLuint shaderProgram;
        GLuint vertexShader;
        GLuint fragmentShader;
        ShaderIOType shaderIOType;
        string shaderName;
        vector <Texture*> textures;   // do not release this memory, scene will manipulate this mem
    
        glm::mat4 model;
        glm::mat4 view;
        glm::mat4 projection;
    
        void setMatrix(const glm::mat4 &matModel , const glm::mat4 &matView , const glm::mat4 &matProjection){
            model = matModel;
            view = matView;
            projection = matProjection;
    
            setMat4("projection", projection);
            setMat4("view", view);
            setMat4("model", model);
        }
    };
    
    }
    
    
    #endif // LOADSHADER_H
    ALG_LoadShader.h
    //
    // Created by admin on 2020/2/25.
    //
    #define GLEW_STATIC
    // GLEW
    #include <GL/glew.h>
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    #include <GL/glew.h>
    #include "ALG_MathFunction.h"
    #include "ALG_LoadShader.h"
    namespace AlgebraMaster{
    
    // x line
    static float points[] = {
            -10.0f,0.0f,0.0f,
            10.0f,0.0f,0.0f
    };
    
    
    class DrawGrid{
    public:
        void initialize();
        void draw(glm::mat4 &proj, glm::mat4 &view);
        // members
        GLuint VAO,VBO;
        LoadShader shader;
    };
    
    void DrawGrid::initialize() {
    
        glCreateVertexArrays(1, &VAO);
        glCreateBuffers(1,&VBO);
        glBindVertexArray(VAO);
    
        glBindBuffer(GL_ARRAY_BUFFER,VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
    
        // position
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    
        shader.asSimpleShader();
    }
    
    void DrawGrid::draw(glm::mat4 &proj, glm::mat4 &view) {
        glEnable(GL_LINE_SMOOTH);
        shader.use();
        shader.setMat4("projection",proj);
        shader.setMat4("view",view);
        glLineWidth(1.0f);
        glBindVertexArray(VAO);
    
        // Draw X line
        glm::mat4 model(1.0f);
        shader.setMat4("model",model);
        glDrawArrays(GL_LINES,0, 2);
    
    
        // Draw Z line
        glm::mat4 rot(1.0f);
        rot = glm::rotate(rot,glm::radians(90.0f),glm::vec3(0.0f, 1.0f, 0.0f ) );
        shader.setMat4("model",rot);
        glDrawArrays(GL_LINES,0, 2);
    
    
        // offset line on x
    
    
    
    
        //  Z positive dir
        for(int i=1;i<11;i++){
            // offset line on z
            glm::mat4 model(1.0f);
            glBindVertexArray(VAO);
            model = glm::translate(model,glm::vec3(0.0f, 0.0f, i ) );
            shader.setMat4("model",model);
            glDrawArrays(GL_LINES,0, 2);
    
        }
        // Z negative dir
        for(int i=1;i<11;i++){
            // offset line on z
            glm::mat4 model(1.0f);
            glBindVertexArray(VAO);
            model = glm::translate(model,glm::vec3(0.0f, 0.0f, -i ) );
            shader.setMat4("model",model);
            glDrawArrays(GL_LINES,0, 2);
            // offset line on x
        }
    
        // X positive dir
        for(int i=1;i<11;i++){
            glBindVertexArray(VAO);
            // offset line on x
            glm::mat4 rot(1.0f);
            rot = glm::rotate(rot,glm::radians(90.0f),glm::vec3(0.0f, 1.0f, 0.0f ) );
    
            glm::mat4 trans(1.0f);
            trans = glm::translate(trans,glm::vec3(i,0.0f,0.0f));
    
            shader.setMat4("model",trans*rot);
            glDrawArrays(GL_LINES,0, 2);
            // offset line on x
        }
    
        // X negative dir
        for(int i=1;i<11;i++){
            // offset line on x
            glm::mat4 rot(1.0f);
            rot = glm::rotate(rot,glm::radians(90.0f),glm::vec3(0.0f, 1.0f, 0.0f ) );
            glm::mat4 trans(1.0f);
            trans = glm::translate(trans,glm::vec3(-i,0.0f,0.0f));
            shader.setMat4("model",trans*rot);
            glDrawArrays(GL_LINES,0, 2);
    
            // offset line on x
        }
    
        glDisable(GL_LINE_SMOOTH);
    }
    }// end of namespace
    
    
    
    
    
    
    #ifndef TRIANGLE_ALG_DRAWGRID_H
    #define TRIANGLE_ALG_DRAWGRID_H
    
    
    
    
    
    #endif //TRIANGLE_ALG_DRAWGRID_H
    ALG_DrawGrid.h
    #ifndef WINDOW_H
    #define WINDOW_H
    #undef GLFW_DLL
    #include <GLFW/glfw3.h>
    
    #define GLEW_STATIC
    #include <GL/glew.h>
    
    
    namespace AlgebraMaster{
    
    
    class FrameWindow
    {
    public:
        FrameWindow(int width,int height,const char*title="日格朗拉Never Fake");
        virtual ~FrameWindow();
        GLFWwindow *getWindow();
    private:
         GLFWwindow *window;
         int w;
         int h;
    };
    
    FrameWindow::FrameWindow(int width,int height,const char*title){
        w = width;
        h = height;
        glfwInit();
        window = glfwCreateWindow(width,height,title,NULL,NULL);
        glfwMakeContextCurrent(window);
        glewInit();
    
    }
    FrameWindow::~FrameWindow(){
        glfwDestroyWindow(window);
        glfwTerminate();
    }
    GLFWwindow * FrameWindow::getWindow(){
        return window;
    }
    }
    #endif // WINDOW_H
    ALG_FrameWindow.h
    #ifndef GLFWCAMERA_H
    #define GLFWCAMERA_H
    
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    
    namespace AlgebraMaster{
    
    
    
    class GLFWCamera{
    public:
        GLFWCamera();
        ~GLFWCamera(){}
        enum CAMERA_MOVEMENT{
            FORWARD,     // Camera move to front   ->  key:W
            BACKWARD,    // Camera move to back    ->  key:S
            LEFT,        // Camera move to left    ->  key:A
            RIGHT        // Camera move to right   ->  key:D
        };
    
    public:
        glm::vec3 pos;   // camera world space
        glm::vec3 front;
        glm::vec3 up;
    
        // Euler Angles
       float yaw;
       float pitch;
    
    
       // Camera options
       float movementSpeed;
       float mouseSensitivity;
       float fov;
    
       void processFov(float yoffset){
           if(fov >= 1.0f && fov <= 45.0f){
               fov -= yoffset;
           }
           if(fov <=1.0f){
               fov = 1.0f;
           }
           if(fov >= 45.0f){
               fov = 45.0f;
           }
       }
    
       // build the matrix for lookAt
       glm::mat4 GetViewMatrix(){
           return glm::lookAt(pos , pos + front , up);
       }
    
       // process -Rotate the view-
       void processMouseMove(float xoffset, float yoffset);
    
    
       // process -W S A D-
       void processKeyboardMove(float delta, CAMERA_MOVEMENT moveDir);
    
    
    
       void updateFront(){
           glm::vec3 tempfront;
           tempfront.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
           tempfront.y = sin(glm::radians(pitch));
           tempfront.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
           this->front = glm::normalize(tempfront);
       }
    
    
    };
    
    GLFWCamera::GLFWCamera(){
        pos = glm::vec3(0.0f,0.0f,3.0f);
        up = glm::vec3(0.0f,1.0f,0.0f);
        front = glm::vec3(0.0f,0.0f,-1.0f);
        yaw = -90.0f;
        pitch = 0.0f;
        fov = 45.0f;
        movementSpeed = 4.5f;
        mouseSensitivity = 0.1f;
    }
    
    void GLFWCamera::processMouseMove(float xoffset, float yoffset)
    {
    
        xoffset *= mouseSensitivity;
        yoffset *= mouseSensitivity;
    
        yaw += xoffset;
        pitch += yoffset;
    
        // make sure that when pitch is out of bounds, screen doesn't get flipped
        if (pitch > 89.0f)
            pitch = 89.0f;
        if (pitch < -89.0f)
            pitch = -89.0f;
        this->updateFront();
    }
    
    void GLFWCamera::processKeyboardMove(float delta, CAMERA_MOVEMENT moveDir)
    {
        float vel = movementSpeed * delta;
        switch (moveDir)
        {
        case FORWARD:
            {
                pos += vel * front;
                break;
            }
        case BACKWARD:
            {
                pos -= vel * front;
                break;
            }
        case LEFT:
            {
                pos -= glm::normalize(glm::cross(front, up)) * vel;
                break;
            }
        case RIGHT:
            {
                pos += glm::normalize(glm::cross(front, up)) * vel;
            }
        default:
            break;
        }
    }
    
    }
    #endif // GLFWCAMERA_H
    ALG_GLFWCamera.h
    #define GLEW_STATIC
    // GLEW
    #include <GL/glew.h>
    #include <cstdlib>
    #undef GLFW_DLL
    // GLFW
    #include <GLFW/glfw3.h>
    #include <iostream>
    #include "ALG_LoadShader.h"
    #include "ALG_LoadTexture.h"
    #include "ALG_GLFWCamera.h"
    #include "ALG_FrameWindow.h"
    #include "ALG_ModelDelegate.h"
    #include "ALG_SceneDelegate.h"
    #include "ALG_DrawGrid.h"
    #include <cmath>
    #include "OGLHelper.h"
    
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    #include <map>
    using namespace AlgebraMaster;
    
    
    const unsigned int SRC_WIDTH = 1400;
    const unsigned int SRC_HEIGHT = 720;
    
    
    
    static LoadShader SurfaceShader;
    
    void init();
    void display();
    
    
    void processInput(GLFWwindow *window);
    void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize
    void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse
    void scroll_callback(GLFWwindow *window, double xoffset, double yoffset);
    
    
    // camera
    static GLFWCamera *camera;
    static float lastX =  float(SRC_WIDTH) / 2.0f;
    static float lastY =  float(SRC_HEIGHT) / 2.0f;
    static bool firstMouse = true;
    static bool firstMiddowMouse = true;
    // timing
    static float deltaTime = 0.0f;    // time between current frame and last frame
    static float lastFrame = 0.0f;
    
    // light define
    static glm::vec3 lightPos(0.0f, 4.0f,-2.0f);
    
    
    
    // Geometry
    
    static DrawGrid grid;
    
    static float cubeVertices[] = {
        // positions          // texture Coords
               -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
                0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
                0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
                0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
               -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
               -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
    
               -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
                0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
                0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
                0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
               -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
               -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    
               -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
               -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
               -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
               -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
               -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
               -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    
                0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
                0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
                0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
                0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
                0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
                0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    
               -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
                0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
                0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
                0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
               -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
               -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    
               -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
                0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
                0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
                0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
               -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
               -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
    };
    
    
    
    static float planeVertices[] = {
            // positions          // texture Coords
            5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
            -5.0f, -0.5f,  5.0f,  0.0f, 0.0f,
            -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
    
            5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
            -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
            5.0f, -0.5f, -5.0f,  2.0f, 2.0f
    };
    static float transparentVertices[] = {
            // positions         // texture Coords (swapped y coordinates because texture is flipped upside down)
            0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
            0.0f, -0.5f,  0.0f,  0.0f,  1.0f,
            1.0f, -0.5f,  0.0f,  1.0f,  1.0f,
    
            0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
            1.0f, -0.5f,  0.0f,  1.0f,  1.0f,
            1.0f,  0.5f,  0.0f,  1.0f,  0.0f
    };
    
    static vector<glm::vec3> windows
    {
        glm::vec3(-1.5f, 0.0f, -0.48f),
        glm::vec3( 1.5f, 0.0f, 0.51f),
        glm::vec3( 0.0f, 0.0f, 0.7f),
        glm::vec3(-0.3f, 0.0f, -2.3f),
        glm::vec3( 0.5f, 0.0f, -0.6f)
    };
    
    
    
    // cube vao vbo
    static unsigned int cubeVAO,cubeVBO;
    static unsigned int planeVAO,planeVBO;
    static unsigned int transparentVAO,transparentVBO;
    static LoadTexture texture1;
    static LoadTexture texture2;
    static LoadTexture texture3;
    
    void init(){
        camera = new GLFWCamera;
        camera->pos.y = 1.0f;
        camera->pos.z = 4.0f;
        // GL depth zbuffer
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
        SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag");
    
    
        glGenVertexArrays(1, &cubeVAO);
        glGenBuffers(1, &cubeVBO);
        glBindVertexArray(cubeVAO);
        glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    
    
        CreateGeometryBuffer(planeVAO, planeVBO);
        glBufferData(GL_ARRAY_BUFFER,sizeof(planeVertices),&planeVertices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    
    
        CreateGeometryBuffer(transparentVAO, transparentVBO);
        glBufferData(GL_ARRAY_BUFFER,sizeof(transparentVertices),&transparentVertices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    
    
        glBindVertexArray(0);
    
        cout << "cube VAO:" << cubeVAO <<endl;
        texture1.load("texture/marble.jpg");
        texture2.load("texture/metal.png");
        texture3.load("texture/window.png");
    
    
    
    
        grid.initialize();
    
    }
    
    // ----------- Render Loop ----------
    void display(){
    
    
        // per-frame time logic
                // --------------------
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
    
    
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        // object .vert settings
        glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f,  1000.0f);
        glm::mat4 view = camera->GetViewMatrix();
        // object world transformation
        glm::mat4 model = glm::mat4(1.0f);
    
        grid.draw(projection,view);
        // render cube
        SurfaceShader.setInt("diffuse_map", 1);
        SurfaceShader.use();
        SurfaceShader.setMat4("projection", projection);
        SurfaceShader.setMat4("view", view);
        model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
        SurfaceShader.setMat4("model", model);
    
    
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D,texture1.textureID);
        glBindVertexArray(cubeVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
        SurfaceShader.setMat4("model", model);
        glDrawArrays(GL_TRIANGLES, 0, 36);
    
    
    
        // floor
        glBindVertexArray(planeVAO);
        glBindTexture(GL_TEXTURE_2D, texture2.getTextureID());
        model = glm::mat4(1.0f);
        SurfaceShader.setMat4("model", model);
        glDrawArrays(GL_TRIANGLES, 0, 6);
    
        std::map<float, glm::vec3> sorted;
        for (unsigned int i = 0; i < windows.size(); i++)
        {
            float distance = glm::length(camera->pos - windows[i]);  // cal distance between camera and window position
            sorted[distance] = windows[i];
        }
        // windows (from furthest to nearest)
        glBindVertexArray(transparentVAO);
        glBindTexture(GL_TEXTURE_2D, texture3.getTextureID());
        for (std::map<float, glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it)
        {
           model = glm::mat4(1.0f);
           model = glm::translate(model, it->second);
           SurfaceShader.setMat4("model", model);
           glDrawArrays(GL_TRIANGLES, 0, 6);
        }
    
    
    
    
    }
    
    
    int main()
    {
        glfwInit();
        FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT);
        glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback);
        glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback);
        glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback);
        init();
        // RENDER--------------
        while(!glfwWindowShouldClose(FrameWindow.getWindow())){
            processInput(FrameWindow.getWindow());
            display();
            glfwSwapBuffers(FrameWindow.getWindow());
            glfwPollEvents();
        }
        delete camera;
        return 0;
    }
    
    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);
    }
    
    void processInput(GLFWwindow *window)
    {
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, true);
        if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD);
        if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD);
        if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT);
        if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
            camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT);
    }
    
    // ROTATE VIEW DIR
    void mouse_callback(GLFWwindow* window, double xpos, double ypos){
    
        int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE);
        int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT);
        int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT);
        // set up the camera view
        if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS)
        {
            if (firstMouse){
                lastX = xpos;
                lastY = ypos;
                firstMouse = false;
            }
            float xoffset = xpos - lastX;
            float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
            lastX = xpos;
            lastY = ypos;
            camera->processMouseMove(xoffset,yoffset);
        }
        if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){
            firstMouse = true;
        }
    
    
        // Move Camera Position
        if( middow_mouse_state == GLFW_PRESS) {
    
            if (firstMiddowMouse){
                lastX = xpos;
                lastY = ypos;
                firstMiddowMouse = false;
            }
            float xoffset = xpos - lastX;
            float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
            lastX = xpos;
            lastY = ypos;
            camera->pos.x += xoffset*0.01f;
            camera->pos.y += yoffset*0.01f;
    
        }
        if ( middow_mouse_state == GLFW_RELEASE){
            firstMiddowMouse = true;
        }
    
    }
    
    void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){
        camera->processFov(yoffset);
    }
    main.cpp

    面剔除:

    比较简单:

    默认glEnable(GL_CULL_FACE); 是剔除后面

    剔除front-face

    glEnable(GL_CULL_FACE);

    glFrontFace(GL_CW);  把顺时针的排序定为frontface,实际上默认这个CW应该是背面,CCW才是前面。现在相当于把真正的<前面>和<后面>调换顺序了。

    glCullFace(GL_BACK);  现在裁剪后面,其实在目前情况下是 前面,视窗上看相当于把前面裁剪了

       

    也可以这样剔除front-face:默认情况下,逆时针的排序代表front-face

  • 相关阅读:
    html问题记录20180529
    html问题记录20180518
    html问题记录20180515
    Redis持久化--AOF
    Redis持久化--RDB
    Redis事件模型
    两个字符串的编辑距离-动态规划方法
    Reactor事件模型在Redis中的应用
    事件驱动模式--Reactor
    IO多路复用--总结
  • 原文地址:https://www.cnblogs.com/gearslogy/p/12350580.html
Copyright © 2020-2023  润新知