Beispiel #1
0
void Particle::init(){
  
  linkShader();
  
  initBuffers();
  
  GLuint gravity = glGetUniformLocation(program, "Gravity");
  GLuint plt = glGetUniformLocation(program, "ParticleLifetime");
  //GLuint ptex = glGetUniformLocation(program, "ParticleTex");
  
  glUniform1f(plt, 5.0f);
  //glUniform3f(gravity, 0.0f, -0.2f, 0.0f);
  
  angle = half_pi<float>();
  
  projection = mat4(1.0f);
  model = mat4(1.0f);
  view = lookAt(vec3(3.0f * cosf(angle), 1.5f, 3.0f * sinf(angle)), vec3(0.0f, 1.5f, 0.0f), vec3(0.0f, 1.0f, 0.0f));
  
  //  glUniform1f(gravity, 9.8);
  mat4 mvpMatrix(1.0f);
  
  starttimer = clock();
  
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
    void initShader(Vec3 &pos, Mat4 &perspective, Mat4 &cameraTranslation, Mat4 &cameraRotation, PhongMaterial &mat)
    {

      BasicShader::initShader();

      addVertexShader("../../shaders/light_shadow_v.glsl");
      addFragmentShader("../../shaders/light_shadow_f.glsl");

      linkShader();

      addUniform(std::string("transform"));
      addUniform(std::string("perspective"));
      addUniform(std::string("camera"));
      addUniform(std::string("cameraRotation"));
      addUniform(std::string("lightMatrix"));

      addUniform(std::string("specularIntensity"));
      addUniform(std::string("specularExponent"));

      addUniform(std::string("eyePos"));

      addUniform(std::string("dirLight.diffuseIntensity"));
      addUniform(std::string("dirLight.dir"));
      addUniform(std::string("dirLight.color"));
      addUniform(std::string("dirLight.ambientIntensity"));

      addUniform(std::string("pointLight.color"));
      addUniform(std::string("pointLight.ambientIntensity"));
      addUniform(std::string("pointLight.diffuseIntensity"));
      addUniform(std::string("pointLight.position"));

      addUniform(std::string("pointLight.att.constant"));
      addUniform(std::string("pointLight.att.linear"));
      addUniform(std::string("pointLight.att.exp"));

      addUniform(std::string("spotLight.color"));
      addUniform(std::string("spotLight.position"));
      addUniform(std::string("spotLight.dir"));
      addUniform(std::string("spotLight.ambientIntensity"));
      addUniform(std::string("spotLight.diffuseIntensity"));
      addUniform(std::string("spotLight.cutoff"));


      addUniform(std::string("spotLight.att.constant"));
      addUniform(std::string("spotLight.att.linear"));
      addUniform(std::string("spotLight.att.exp"));

      addUniform(std::string("sampler"));
      addUniform(std::string("samplerShadow"));

      material_ = &mat;

      perspective_ = &perspective;
      cameraTranslation_ = &cameraTranslation;
      cameraRotation_ = &cameraRotation;
      eyePos_ = pos;

    }
Beispiel #3
0
        void Shader::loadShader()
        {
            m_ShaderID = glCreateProgram();
            GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
            compileShader(m_VertexShaderPath, vertexShaderId);

            GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
            compileShader(m_FragmentShaderPath, fragmentShaderId);

            linkShader(m_ShaderID, vertexShaderId, fragmentShaderId);
        }
Beispiel #4
0
GLuint buildShader(const char *vert_src, const char *frag_src, const char *prepend_src)
{
    if (prepend_src) {
        vert_src = prependShader(vert_src, prepend_src);
        frag_src = prependShader(frag_src, prepend_src);
    }

    GLuint vert_shader = compileShader(GL_VERTEX_SHADER, vert_src);
    GLuint frag_shader = compileShader(GL_FRAGMENT_SHADER, frag_src);
    GLuint result = linkShader(vert_shader, frag_shader);
    glDetachShader(result, vert_shader);
    glDetachShader(result, frag_shader);
    glDeleteShader(vert_shader);
    glDeleteShader(frag_shader);

    if (prepend_src) {
        free((char*) vert_src);
        free((char*) frag_src);
    }
    return result;
}
Beispiel #5
0
GLuint loadShaders(
    const std::string& vertexFile,
    const std::string& fragmentFile)
{
    GLuint vertexId = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentId = glCreateShader(GL_FRAGMENT_SHADER);

    std::string vertexCode = readFile(vertexFile);
    std::string fragmentCode = readFile(fragmentFile);

    compileShader(vertexId, vertexCode);
    compileShader(fragmentId, fragmentCode);

    GLuint programId = 0;
    linkShader(vertexId, fragmentId, programId);

    glDeleteShader(vertexId);
    glDeleteShader(fragmentId);

    return programId;
}
SpriteBatcher::SpriteBatcher()
    : camera(NULL), vao(0), program(0), lastTexture(0), drawn(0)
{
    // Create shader program
    GLuint vertex = createShader(VERTEX_SRC, GL_VERTEX_SHADER);
    GLuint fragment = createShader(FRAGMENT_SRC, GL_FRAGMENT_SHADER);
    program = createShaderProgram(vertex, fragment);
    linkShader(program);
    validateShader(program);

    glDetachShader(program, vertex);
    glDeleteShader(vertex);
    glDetachShader(program, fragment);
    glDeleteShader(fragment);

    // Create vertex array and prepare buffers for being updated >= once per frame
    glGenVertexArrays(1, &vao);
    glGenBuffers(2, buffers);

    glBindVertexArray(vao);

    glBindBuffer(GL_ARRAY_BUFFER, buffers[VCTBO]);
    glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_DYNAMIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[EBO]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, NULL, GL_DYNAMIC_DRAW);
    
    // Attributes
    glBindBuffer(GL_ARRAY_BUFFER, buffers[VCTBO]);
    glEnableVertexAttribArray(0); // position
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1); // color
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(2 * sizeof(float)));
    glEnableVertexAttribArray(2); // texture coordinates
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));

    glBindVertexArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
Beispiel #7
0
    void initShader(Vec3 &pos, Mat4 &perspective, Mat4 &cameraTranslation, Mat4 &cameraRotation)
    {

      BasicShader::initShader();

      addVertexShader("../../shaders/simple_v.glsl");
      addFragmentShader("../../shaders/simple_f.glsl");

      linkShader();

      addUniform(std::string("transform"));
      addUniform(std::string("perspective"));
      addUniform(std::string("camera"));
      addUniform(std::string("cameraRotation"));

      //addUniform(std::string("model_col"));

      perspective_ = &perspective;
      cameraTranslation_ = &cameraTranslation;
      cameraRotation_ = &cameraRotation;
      eyePos_ = pos;

    }
void Shader::createShader(const std::string& shaderFile)
{
	_vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
	_fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

	std::string vertexShaderCode;
	std::ifstream vertexShaderStream(shaderFile+".vert", std::ios::in);
	if (vertexShaderStream.is_open())
	{
		std::string line = "";
		while (std::getline(vertexShaderStream, line))
			vertexShaderCode += "\n" + line;

		vertexShaderStream.close();
	}

	std::string fragmentShaderCode;
	std::ifstream fragmentShaderStream(shaderFile + ".frag", std::ios::in);
	if (fragmentShaderStream.is_open())
	{
		std::string line = "";
		while (std::getline(fragmentShaderStream, line))
			fragmentShaderCode += "\n" + line;

		fragmentShaderStream.close();
	}

	compileShader(vertexShaderCode, fragmentShaderCode);

	checkShaderError();

	linkShader();

	glDeleteShader(_vertexShaderID);
	glDeleteShader(_fragmentShaderID);
}
Beispiel #9
0
void Shader::loadGeometryShader(const std::string &shader) {
	mGeometryHandle = createSharedObjects(shader, GL_GEOMETRY_SHADER);
	linkShader(mGeometryHandle);
}
Beispiel #10
0
/**
 * @brief Loads a fragment shader
 *
 * @param fragmentShader
 *      Fragment program
 */
void Shader::loadFragmentShader(const std::string &fragmentShader) {
	mFragmentHandle = createSharedObjects(fragmentShader, GL_FRAGMENT_SHADER);
	linkShader(mFragmentHandle);
}
Beispiel #11
0
/**
 * @brief Loads a vertex shader
 *
 * @param vertexPath
 *      Vertex program
 *
 */
void Shader::loadVertexShader(const std::string &vertexShader) {
	mVertexHandle = createSharedObjects(vertexShader, GL_VERTEX_SHADER);
	linkShader(mVertexHandle);
}
Beispiel #12
0
int main(void)
{
    GLFWwindow* window;

    window = init("Transparency", 640, 480);
    if(!window)
    {
        return -1;
    }

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)640/(float)480, 0.1f, 1000.0f);
    glm::mat4 model1, model2, model3; // Cube 1 and 2 will be transparent, cube 3 not
    model1 = glm::translate(model1, glm::vec3(0.5f, 0.0f, -1.0f));
    model2 = glm::translate(model2, glm::vec3(0.0f, 0.5f, -2.0f));
    model3 = glm::translate(model3, glm::vec3(0.0f, 0.0f, -3.0f));
    glm::mat4 view;
    view = glm::translate(view, glm::vec3(0.0f, 0.0f, -4.0f));

    GLuint vertex = createShader(VERTEX_SRC, GL_VERTEX_SHADER);
    if(!vertex)
    {
        return -1;
    }
    GLuint fragment = createShader(FRAGMENT_SRC, GL_FRAGMENT_SHADER);
    if(!fragment)
    {
        return -1;
    }
    GLuint program = createShaderProgram(vertex, fragment);
    if(!program)
    {
        return -1;
    }
    bool result = linkShader(program);
    if(!result)
    {
        return -1;
    }
    result = validateShader(program);
    if(!result)
    {
        return -1;
    }
    glDetachShader(program, vertex);
    glDeleteShader(vertex);
    glDetachShader(program, fragment);
    glDeleteShader(fragment);

    glUseProgram(program);

    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    GLuint vbo;
    glGenBuffers(1, &vbo);

    float vertices[] =
    {
        // x   y      z     r     g     b     u     v
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
         0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    
        -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
         0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    
        -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        -0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
         0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
         0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
         0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    
        -0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
         0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f
    };

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0); // position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);
    glEnableVertexAttribArray(1); // color
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2); // texture coordinates
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));

    int w, h;
    GLuint textureTrans = loadImage("transparent.png", &w, &h, 0, true); // GL_TEXTURE0
    if(!textureTrans)
    {
        return -1;
    }
    GLuint textureOpaq = loadImage("opaque.png", &w, &h, 0, true); // GL_TEXTURE0
    if(!textureOpaq)
    {
        return -1;
    }
    glUniform1i(glGetUniformLocation(program, "tex"), 0); // GL_TEXTURE0

    GLint viewUL = glGetUniformLocation(program, "view");
    glUniformMatrix4fv(viewUL, 1, GL_FALSE, glm::value_ptr(view));
    GLint projUL = glGetUniformLocation(program, "projection");
    glUniformMatrix4fv(projUL, 1, GL_FALSE, glm::value_ptr(proj));
    GLint modelUL = glGetUniformLocation(program, "model");
    
    glClearColor(0.75f, 0.75f, 0.75f, 1.0f);

    while(!glfwWindowShouldClose(window))
    {
        // Clear (note the addition of GL_DEPTH_BUFFER_BIT)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // We have to sort the objects, rendering the backmost objects first
        // in this example, model1 is in front of model2, which is in front of model3
        // and model3 is the only one using the opaque texture
        // (This way we can avoid the sorting, making the example a bit easier to follow)
        glBindTexture(GL_TEXTURE_2D, textureOpaq);
        glUniformMatrix4fv(modelUL, 1, GL_FALSE, glm::value_ptr(model3));
        glDrawArrays(GL_TRIANGLES, 0, 36);

        glBindTexture(GL_TEXTURE_2D, textureTrans);
        glUniformMatrix4fv(modelUL, 1, GL_FALSE, glm::value_ptr(model2));
        glDrawArrays(GL_TRIANGLES, 0, 36);
        glUniformMatrix4fv(modelUL, 1, GL_FALSE, glm::value_ptr(model1));
        glDrawArrays(GL_TRIANGLES, 0, 36);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // Clean up
    glDeleteBuffers(1, &vbo);
    glDeleteVertexArrays(1, &vao);
    glDeleteTextures(1, &textureTrans);
    glDeleteTextures(1, &textureOpaq);

    glfwTerminate();
    return 0;
}
Beispiel #13
0
int main(void)
{
    GLFWwindow* window;
    window = init("Deferred Shading", WIDTH / 2, HEIGHT / 2);
    if(!window)
    {
        return -1;
    }

    glEnable(GL_DEPTH_TEST);

    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

    Camera camera(CAMERA_PERSPECTIVE, 45.0f, 0.1f, 1000.0f, (float)WIDTH, (float)HEIGHT);
    setCamera(&camera);

    GLuint geomProgram, lightProgram;
    {
        // Geometry pass program
        GLuint vertex = createShader(VERTEX_GEOM_SRC, GL_VERTEX_SHADER);
        GLuint fragment = createShader(FRAGMENT_GEOM_SRC, GL_FRAGMENT_SHADER);
        geomProgram = createShaderProgram(vertex, fragment);
        linkShader(geomProgram);
        validateShader(geomProgram);
        glDetachShader(geomProgram, vertex);
        glDeleteShader(vertex);
        glDetachShader(geomProgram, fragment);
        glDeleteShader(fragment);
    }
    {
        // Light pass program
        GLuint vertex = createShader(VERTEX_LIGHT_SRC, GL_VERTEX_SHADER);
        GLuint fragment = createShader(FRAGMENT_LIGHT_SRC, GL_FRAGMENT_SHADER);
        lightProgram = createShaderProgram(vertex, fragment);
        linkShader(lightProgram);
        validateShader(lightProgram);
        glDetachShader(lightProgram, vertex);
        glDeleteShader(vertex);
        glDetachShader(lightProgram, fragment);
        glDeleteShader(fragment);
    }

    // Create quad VAO
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    GLuint vbo;
    glGenBuffers(1, &vbo);

    float vertices[] =
    {
        // x   y       u     v
        -1.0f,  1.0f,  0.0f, 0.0f,
         1.0f,  1.0f,  1.0f, 0.0f,
         1.0f, -1.0f,  1.0f, 1.0f,
        -1.0f, -1.0f,  0.0f, 1.0f
    };

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    GLuint ebo;
    glGenBuffers(1, &ebo);

    GLuint indices[] =
    {
        0, 1, 2,
        2, 3, 0
    };

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    // Load the diffuse and specular texture
    // TODO: seperate specular texture
    glUseProgram(geomProgram);
    int w, h;
    GLuint textureDiff = loadImage("asteroid.png", &w, &h, 0, false); // GL_TEXTURE0
    if(!textureDiff)
    {
        return -1;
    }
    glUniform1i(glGetUniformLocation(geomProgram, "diffuse"), 0); // GL_TEXTURE0
    GLuint textureSpec = loadImage("asteroid.png", &w, &h, 1, false); // GL_TEXTURE1
    if(!textureSpec)
    {
        return -1;
    }
    glUniform1i(glGetUniformLocation(geomProgram, "specular"), 1); // GL_TEXTURE1

    Mesh mesh;
    if(!mesh.load("asteroid.obj"))
    {
        std::cerr << "Could not load mesh" << std::endl;
        return -1;
    }

    // Set random positions for the asteroids
    std::vector<glm::mat4> models;
    models.resize(NUM_ASTEROIDS);
    srand(SEED);
    for(int i = 0; i < NUM_ASTEROIDS; ++i)
    {
        glm::mat4 model;

        // Translate
        model = glm::translate(model, glm::vec3(rand() % 100 - 50.0f, rand() % 100 - 50.0f, rand() % 100));

        // Scale
        float scale = (rand() % 200) / 100.0f + 0.1f;
        model = glm::scale(model, glm::vec3(scale, scale, scale));

        // Rotate
        model = glm::rotate(model, glm::radians((float)(rand() % 100)), glm::vec3(1.0f, 1.0f, 1.0f));

        models[i] = model;
    }

    mesh.setInstances(NUM_ASTEROIDS, models);

    // Set positions and more for the lights
    PointLight lights[NUM_POINT_LIGHTS];
    for(int i = 0; i < NUM_POINT_LIGHTS; ++i)
    {
        float x, y, z;
        x = rand() % 100 - 50.0f;
        y = rand() % 100 - 50.0f;
        z = rand() % 100;

        float r, g, b; // For simplicity's sake, ambient, diffuse and specular colours are the same
        r = ((rand() % 10) / 20.0f) + 0.5;
        g = ((rand() % 10) / 20.0f) + 0.5;
        b = ((rand() % 10) / 20.0f) + 0.5;

        float con, lin, qua;
        con = 1.0f;
        lin = 0.09f;
        qua = 0.032f;

        lights[i].set(glm::vec3(x, y, z), glm::vec3(con, lin, qua), glm::vec3(r, g, b),
                glm::vec3(r, g, b), glm::vec3(r, g, b));
    }

    GBuffer gBuffer;

    glUseProgram(lightProgram);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, gBuffer.position);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, gBuffer.normal);
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, gBuffer.color);
    glUniform1i(glGetUniformLocation(lightProgram, "g_position"), 0);
    glUniform1i(glGetUniformLocation(lightProgram, "g_normal_spec_pow"), 1);
    glUniform1i(glGetUniformLocation(lightProgram, "g_albedo_spec"), 2);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    while(!glfwWindowShouldClose(window))
    {
        if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        {
            break;
        }

        updateCamera(WIDTH, HEIGHT, window);

        // GEOMETRY PASS
        glBindFramebuffer(GL_FRAMEBUFFER, gBuffer.buffer);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glm::mat4 proj = camera.getProjection();
        glm::mat4 view = camera.getView();
        glUseProgram(geomProgram);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textureDiff);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, textureSpec);
        glUniformMatrix4fv(glGetUniformLocation(geomProgram, "projection"), 1, GL_FALSE, glm::value_ptr(proj));
        glUniformMatrix4fv(glGetUniformLocation(geomProgram, "view"), 1, GL_FALSE, glm::value_ptr(view));
        glUniform1f(glGetUniformLocation(geomProgram, "specularPower"), 16.0f);
        mesh.render();
        
        // LIGHT PASS
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glUseProgram(lightProgram); 
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, gBuffer.position);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, gBuffer.normal);
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, gBuffer.color);
        glUniform3fv(glGetUniformLocation(lightProgram, "eye"), 1, glm::value_ptr(camera.getPosition()));
        for(int i = 0; i < NUM_POINT_LIGHTS; ++i)
        {
            lights[i].setUniforms(i, lightProgram);
        }
        glBindVertexArray(vao);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // Clean up
    glDeleteTextures(1, &textureDiff);
    glDeleteTextures(1, &textureSpec);
    glDeleteProgram(geomProgram);
    glDeleteProgram(lightProgram);
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ebo);

    glfwTerminate();
    return 0;
}
Beispiel #14
0
int main(void)
{
    GLFWwindow* window;

    // The OpenGL context creation code is in
    // ../common/util.cpp
    window = init("Hello Heightmap", 640, 480);
    if(!window)
    {
        return -1;
    }

    // Hide the cursor (escape will exit the application)
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

    // We will need to enable depth testing, so that OpenGL draws further
    // vertices first
    glEnable(GL_DEPTH_TEST);

    // Draw wireframe
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // Enable backface culling
    glEnable(GL_CULL_FACE); 
    glCullFace(GL_BACK);
    glFrontFace(GL_CCW); // front facing vertices are defined counter clock wise

    // Create the model matrix
    model = glm::mat4();
    // Rotate just a bit (the vector indicates the axes on which to rotate)
    model = glm::rotate(model, -glm::radians(35.0f), glm::vec3(0.0f, 1.0f, 1.0f));

    // Set the camera
    Camera camera(CAMERA_PERSPECTIVE, 45.0f, 0.1f, 1000.0f, 640.0f, 480.0f);
    camera.setPosition(0.0f, 0.0f, -3.0f);
    setCamera(&camera); // The camera updating is handled in ../common/util.cpp

    // Load the heightmap
    HeightMap map(20.0f);
    if(!map.load("heightmap.bmp"))
    {
        return -1;
    }
    const std::vector<float>& data = map.getData();
    int w = map.getWidth(), h = map.getHeight();
    std::vector<float> vertices;
    for(int i = 0; i < h; ++i)
    {
        for(int j = 0; j < w; ++j)
        {
            float x = (float)i;
            float z = (float)j;
            float height = data[i * w + j];

            vertices.push_back(x * SIZE);
            vertices.push_back(height);
            vertices.push_back(z * SIZE);
            // This is where you could add extra information,
            // like colour or texture coordinates.
            // You would have to change the vertex attribute pointer
            // code as well!
        }
    }
    std::vector<GLuint> indices;
    for(int i = 0; i < (h - 1); ++i)
    {
        for(int j = 0; j < (w - 1); ++j)
        {
            // We create six indices for each tile
            indices.push_back(i * w + j);
            indices.push_back((i + 1) * w + j);
            indices.push_back(i * w + j + 1);
            indices.push_back(i * w + j + 1);
            indices.push_back((i + 1) * w + j);
            indices.push_back((i + 1) * w + j + 1);
        }
    }

    // We start by creating a vertex and fragment shader
    // from the above strings
    GLuint vertex = createShader(VERTEX_SRC, GL_VERTEX_SHADER);
    if(!vertex)
    {
        return -1;
    }
    GLuint fragment = createShader(FRAGMENT_SRC, GL_FRAGMENT_SHADER);
    if(!fragment)
    {
        return -1;
    }
    // Now we must make a shader program: this program
    // contains both the vertex and the fragment shader
    GLuint program = createShaderProgram(vertex, fragment);
    if(!program)
    {
        return -1;
    }
    // We link the program, just like your C compiler links
    // .o files
    bool result = linkShader(program);
    if(!result)
    {
        return -1;
    }
    // We make sure the shader is validated
    result = validateShader(program);
    if(!result)
    {
        return -1;
    }
    // Detach and delete the shaders, because we no longer need them
    glDetachShader(program, vertex);
    glDeleteShader(vertex);
    glDetachShader(program, fragment);
    glDeleteShader(fragment);

    glUseProgram(program); // Set this as the current shader program

    // We now create the data to send to the GPU
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    GLuint vbo;
    glGenBuffers(1, &vbo);

    // Upload the vertices to the buffer
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), &vertices[0], GL_STATIC_DRAW);

    GLuint ebo;
    glGenBuffers(1, &ebo);

    // Upload the indices to the buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), &indices[0], GL_STATIC_DRAW);

    // Enable the vertex attributes and upload their data (see: layout(location=x))
    glEnableVertexAttribArray(0); // position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0);

    // We have now successfully created a drawable Vertex Array Object

    // Set the clear color to a light grey
    glClearColor(0.75f, 0.75f, 0.75f, 1.0f);

    while(!glfwWindowShouldClose(window))
    {
        if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        {
            break;
        }

        updateCamera(640, 480, window);

        // Clear (note the addition of GL_DEPTH_BUFFER_BIT)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Upload the MVP matrices
        GLint modelUL = glGetUniformLocation(program, "model");
        glUniformMatrix4fv(modelUL, 1, GL_FALSE, glm::value_ptr(model));
        GLint viewUL = glGetUniformLocation(program, "view");
        glUniformMatrix4fv(viewUL, 1, GL_FALSE, glm::value_ptr(camera.getView()));
        // This can be moved out of the loop because it rarely changes
        GLint projUL = glGetUniformLocation(program, "projection");
        glUniformMatrix4fv(projUL, 1, GL_FALSE, glm::value_ptr(camera.getProjection()));

        // The VAO is still bound so just draw the vertices
        glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);

        // Tip: if nothing is drawn, check the return value of glGetError and google it

        // Swap buffers to show current image on screen (for more information google 'backbuffer')
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // Clean up
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ebo);
    glDeleteVertexArrays(1, &vao);

    glfwTerminate();
    return 0;
}
Beispiel #15
0
int main(void)
{
    GLFWwindow* window = init("Morph Target Animation", 640, 480);
    if(!window)
    {
        return -1;
    }

    glEnable(GL_DEPTH_TEST);

    glm::mat4 proj = glm::perspective(glm::radians(45.0f), 640.0f / 480.0f, 0.1f, 1000.0f);
    glm::mat4 view = glm::translate(glm::mat4(), glm::vec3(0.0f, 0.0f, -4.0f));
    glm::mat4 model = glm::rotate(glm::mat4(), glm::radians(45.0f), glm::vec3(1.0f, 0.0f, 1.0f));

    // Load the shader
    GLuint program;
    {
        GLuint vertex = createShader(VERTEX_SRC, GL_VERTEX_SHADER);
        GLuint fragment = createShader(FRAGMENT_SRC, GL_FRAGMENT_SHADER);
        program = createShaderProgram(vertex, fragment);
        linkShader(program);
        validateShader(program);

        glDetachShader(program, vertex);
        glDeleteShader(vertex);
        glDetachShader(program, fragment);
        glDeleteShader(fragment);

        if(!program)
        {
            return -1;
        }
    }
    glUseProgram(program);

    float vertices1[] =
    {
        // x   y      z
        -0.5f, -0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
        -0.5f,  0.5f, -0.5f,
        -0.5f, -0.5f, -0.5f,
    
        -0.5f, -0.5f,  0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f,
        -0.5f, -0.5f,  0.5f,
    
        -0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f, -0.5f,
        -0.5f, -0.5f, -0.5f,
        -0.5f, -0.5f, -0.5f,
        -0.5f, -0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f,
    
         0.5f,  0.5f,  0.5f,
         0.5f,  0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
    
        -0.5f, -0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f, -0.5f,  0.5f,
        -0.5f, -0.5f,  0.5f,
        -0.5f, -0.5f, -0.5f,
    
        -0.5f,  0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
         0.5f,  0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f, -0.5f,
    };
    float vertices2[] =
    {
        // x   y      z     
        -1.0f, -1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,
         1.0f,  1.0f, -1.0f,
         1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f, -1.0f,
        -1.0f, -1.0f, -1.0f,
    
        -1.0f, -1.0f,  1.0f,
         1.0f, -1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f,
    
        -1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f, -1.0f,
        -1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,
    
         1.0f,  1.0f,  1.0f,
         1.0f,  1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,
         1.0f, -1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,
    
        -1.0f, -1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,
         1.0f, -1.0f,  1.0f,
         1.0f, -1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f,
        -1.0f, -1.0f, -1.0f,
    
        -1.0f,  1.0f, -1.0f,
         1.0f,  1.0f, -1.0f,
         1.0f,  1.0f,  1.0f,
         1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f, -1.0f,
    };

    // Create the vao and buffer objects
    GLuint vao;
    GLuint buffers[2];
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glGenBuffers(2, buffers);

    glBindBuffer(GL_ARRAY_BUFFER, buffers[CUR_POS_VBO]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

    glBindBuffer(GL_ARRAY_BUFFER, buffers[NEXT_POS_VBO]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, glm::value_ptr(proj));
    glUniformMatrix4fv(glGetUniformLocation(program, "view"), 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(glGetUniformLocation(program, "model"), 1, GL_FALSE, glm::value_ptr(model));

    glClearColor(0.75f, 0.75f, 0.75f, 1.0f);

    float timeSinceFrame = 0.0f;
    int currentFrame;
    glBindVertexArray(vao);
    while(!glfwWindowShouldClose(window))
    {
        // If the time for a frame has passed, we have to switch frames
        timeSinceFrame += glfwGetTime();
        if(timeSinceFrame >= FRAME_TIME)
        {
            if(currentFrame == 0)
            {
                currentFrame = 1;
            }
            else
            {
                currentFrame = 0;
            }
            timeSinceFrame = 0.0f;

            // Update the buffers
            glBindBuffer(GL_ARRAY_BUFFER, buffers[CUR_POS_VBO]);
            glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), 
                    currentFrame == 0 ? vertices1 : vertices2, GL_DYNAMIC_DRAW);
            glBindBuffer(GL_ARRAY_BUFFER, buffers[NEXT_POS_VBO]);
            glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1),
                    currentFrame == 0 ? vertices2 : vertices1, GL_DYNAMIC_DRAW);

            glBindBuffer(GL_ARRAY_BUFFER, 0);
        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUniform1f(glGetUniformLocation(program, "tween"), timeSinceFrame / FRAME_TIME);

        glDrawArrays(GL_TRIANGLES, 0, 36);

        glfwSetTime(0.0);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteBuffers(2, buffers);
    glDeleteVertexArrays(1, &vao);
    glDeleteProgram(program);

    glfwTerminate();
    return 0;
}
Beispiel #16
0
int main(void)
{
    GLFWwindow* window;

    window = init("Billboards", 640, 480);
    if(!window)
    {
        return -1;
    }

    glEnable(GL_DEPTH_TEST);

    Camera camera(CAMERA_PERSPECTIVE, 45.0f, 0.1f, 1000.0f, 640.0f, 480.0f);
    camera.setPosition(0.0f, 0.0f, -3.0f);
    setCamera(&camera); // The camera updating is handled in ../common/util.cpp

    glm::mat4 model;

    GLuint program;
    {
        GLuint vertex = createShader(VERTEX_SRC, GL_VERTEX_SHADER);
        GLuint fragment = createShader(FRAGMENT_SRC, GL_FRAGMENT_SHADER);
        program = createShaderProgram(vertex, fragment);
        linkShader(program);
        validateShader(program);
        glDetachShader(program, vertex);
        glDeleteShader(vertex);
        glDetachShader(program, fragment);
        glDeleteShader(fragment);
    }
    GLuint billboardProgram;
    {
        GLuint vertex = createShader(VERTEX_BB_SRC, GL_VERTEX_SHADER);
        GLuint fragment = createShader(FRAGMENT_BB_SRC, GL_FRAGMENT_SHADER);
        billboardProgram = createShaderProgram(vertex, fragment);
        linkShader(billboardProgram);
        validateShader(billboardProgram);
        glDetachShader(program, vertex);
        glDeleteShader(vertex);
        glDetachShader(program, fragment);
        glDeleteShader(fragment);
    }

    glUseProgram(program);

    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    GLuint vbo;
    glGenBuffers(1, &vbo);

    float vertices[] =
    {
        // x   y      z     r     g     b     u     v
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
         0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    
        -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
         0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    
        -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        -0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
         0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
         0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
    
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
         0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        -0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    
        -0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
         0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
         0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f
    };

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0); // position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);
    glEnableVertexAttribArray(1); // color
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2); // texture coordinates
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));

    float verts_bb[] =
    {
        -0.5f, -0.5f,
        0.5f,  -0.5f,
        -0.5f, 0.5f,
        0.5f, 0.5f
    };
    GLuint vbo_bb;
    glGenBuffers(1, &vbo_bb);
    GLuint vao_bb;
    glGenVertexArrays(1, &vao_bb);
    glBindVertexArray(vao_bb);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_bb);
    glBufferData(GL_ARRAY_BUFFER, sizeof(verts_bb), verts_bb, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glUseProgram(billboardProgram);
    glUniform3f(glGetUniformLocation(billboardProgram, "center"), 0.0f, 2.0f, 0.0f);
    glUniform2f(glGetUniformLocation(billboardProgram, "size"), 0.5f, 0.5f);

    int w, h;
    GLuint texture = loadImage("image.png", &w, &h, 0, false);
    glUniform1i(glGetUniformLocation(billboardProgram, "tex"), 0);
    glUseProgram(program);
    glUniform1i(glGetUniformLocation(program, "tex"), 0);
    
    glClearColor(0.75f, 0.75f, 0.75f, 1.0f);

    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

    while(!glfwWindowShouldClose(window))
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        updateCamera(640, 480, window);

        // Draw the cube
        glUseProgram(program);
        glBindVertexArray(vao);

        GLint modelUL = glGetUniformLocation(program, "model");
        glUniformMatrix4fv(modelUL, 1, GL_FALSE, glm::value_ptr(model));
        GLint viewUL = glGetUniformLocation(program, "view");
        glUniformMatrix4fv(viewUL, 1, GL_FALSE, glm::value_ptr(camera.getView()));
        GLint projUL = glGetUniformLocation(program, "projection");
        glUniformMatrix4fv(projUL, 1, GL_FALSE, glm::value_ptr(camera.getProjection()));

        glDrawArrays(GL_TRIANGLES, 0, 36);

        // Draw the billboard
        glBindVertexArray(vao_bb);
        glUseProgram(billboardProgram);

        viewUL = glGetUniformLocation(billboardProgram, "view");
        glUniformMatrix4fv(viewUL, 1, GL_FALSE, glm::value_ptr(camera.getView()));
        projUL = glGetUniformLocation(billboardProgram, "proj");
        glUniformMatrix4fv(projUL, 1, GL_FALSE, glm::value_ptr(camera.getProjection()));
        glUniform1i(glGetUniformLocation(billboardProgram, "fixedSize"), 0);
        glUniform3f(glGetUniformLocation(billboardProgram, "camRight"), camera.getRightVector().x, camera.getRightVector().y, camera.getRightVector().z);
        glUniform3f(glGetUniformLocation(billboardProgram, "camUp"), camera.getUpVector().x, camera.getUpVector().y, camera.getUpVector().z);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // Clean up
    glDeleteBuffers(1, &vbo);
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo_bb);
    glDeleteVertexArrays(1, &vao_bb);
    glDeleteProgram(program);
    glDeleteProgram(billboardProgram);
    glDeleteTextures(1, &texture);

    glfwTerminate();
    return 0;
}