#include <cmath>
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "mgl/mgl.h"
#include "camera.h"
using namespace std;
GLFWwindow* window;
const GLuint WIDTH = 800, HEIGHT = 800;
const GLuint NUM_GROUND_LINES = 80;
glm::vec3 ground[NUM_GROUND_LINES*2*2];
glm::vec3 quad_data[342];
glm::vec3 strip_data[40];
glm::vec3 lightPos(0.0, 3.0, 0.0);
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
GLfloat square[] {
-0.5, -4.0, 0.5, 0.0, 1.0, 0.0,
0.5, -4.0, 0.5, 0.0, 1.0, 0.0,
-0.5, -4.0, -0.5, 0.0, 1.0, 0.0,
0.5, -4.0, -0.5, 0.0, 1.0, 0.0
};
GLuint program_sphere, program_ground, program_lamp;
GLuint vbo_sphere, vao_sphere;
GLuint vbo_sphere_normals, vao_sphere_normals;
GLuint vbo_poles, vao_poles;
GLuint vbo_ground, vao_ground;
GLuint index_buffer;
glm::vec3 cameraPos = glm::vec3(0.0, 0.0, 3.0);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
GLfloat yaw = -90.0f;
GLfloat pitch = 0.0f;
GLfloat lastX = WIDTH / 2.0;
GLfloat lastY = HEIGHT / 2.0;
GLfloat aspect = 45.0f;
GLfloat twist = 0;
GLfloat elevation = 0;
GLfloat azimuth = 0;
GLfloat deltaTime = 0.0f; // Time between current frame and last frame
GLfloat lastFrame = 0.0f;
bool firstMouse = true;
bool keys[1024];
const GLfloat X = .525731112119133606;
const GLfloat Z = .850650808352039932;
GLfloat vdata[12][3] {
{-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
{0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
{Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
};
GLuint tindices[20][3] = {
{0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
{8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11}
};
GLfloat ndata[60][3];
void init_sphere_normals()
{
for(int i=0; i<20; i++)
{
for(int j=0; j<3; j++)
{
for(int k=0; k<3; k++)
{
ndata[i*3+j][k] = vdata[tindices[i][j]][k];
}
}
}
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if (key >= 0 && key < 1024)
{
if (action == GLFW_PRESS)
{
keys[key] = true;
}
else if (action == GLFW_RELEASE)
keys[key] = false;
}
}
void do_movement()
{
// Camera controls
if (keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime);
if (keys[GLFW_KEY_S])
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (keys[GLFW_KEY_A])
camera.ProcessKeyboard(LEFT, deltaTime);
if (keys[GLFW_KEY_D])
camera.ProcessKeyboard(RIGHT, deltaTime);
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
GLfloat xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; // Reversed since y-coordinates go from bottom to left
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
if (aspect >= 1.0f && aspect <= 45.0f)
aspect -= yoffset;
if (aspect <= 1.0f)
aspect = 1.0f;
if (aspect >= 45.0f)
aspect = 45.0f;
}
void init_glfw()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Init GLFW
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, "Sphere", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glewExperimental = GL_TRUE;
glewInit();
// glfwSetCursorPosCallback(window, mouse_callback);
// glfwSetScrollCallback(window, scroll_callback);
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_callback);
// GLFW Options
// glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glViewport(0, 0, WIDTH, HEIGHT);
}
void init_sphere()
{
}
void init_poles()
{
int k = 0;
strip_data[k] = glm::vec3(0.0, 0.0, 1.0);
k++;
float sin80 = sin(glm::radians(80.0));
float cos80 = cos(glm::radians(80.0));
for(float theta = -180; theta <= 180.0; theta += 20.0)
{
float thetar = glm::radians(theta);
strip_data[k] = glm::vec3(sin(thetar)*cos80, cos(thetar)*cos80, sin80);
k++;
}
strip_data[k] = glm::vec3(0.0, 0.0, -1.0);
k++;
for(float theta = -180; theta <= 180; theta += 20.0)
{
float thetar = glm::radians(theta);
strip_data[k] = glm::vec3(sin(thetar)*cos80, cos(thetar)*cos80, sin80);
k++;
}
}
void init_ground()
{
GLfloat x = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
GLfloat z = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
for(int i=0; i<NUM_GROUND_LINES*2; i += 2)
{
GLfloat x = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(-x, -4.0, z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
z += 1.0;
}
for(int i=NUM_GROUND_LINES*2; i<NUM_GROUND_LINES*4; i += 2)
{
GLfloat z = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(x, -4.0, -z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
x += 1.0;
}
}
void init_checkerboard()
{
}
void init_opengl()
{
program_sphere = mgl::load_shaders("sphere.vert", "sphere.frag");
program_ground = mgl::load_shaders("ground.vert", "ground.frag");
program_lamp = mgl::load_shaders("lamp.vert", "lamp.frag");
init_sphere();
init_poles();
init_ground();
init_sphere_normals();
glEnable(GL_DEPTH_TEST);
//sphere VAO
glGenVertexArrays(1, &vao_sphere);
glGenBuffers(1, &vbo_sphere);
glBindVertexArray(vao_sphere);
glBindBuffer(GL_ARRAY_BUFFER, vbo_sphere);
glBufferData(GL_ARRAY_BUFFER, sizeof(vdata), vdata, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glGenBuffers(1, &index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(tindices), tindices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(ndata), ndata, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glBindVertexArray(0);
//ground VAO
glGenVertexArrays(1, &vao_ground);
glGenBuffers(1, &vbo_ground);
glBindVertexArray(vao_ground);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ground);
glBufferData(GL_ARRAY_BUFFER, sizeof(square), square, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}
int main()
{
init_glfw();
init_opengl();
while(!glfwWindowShouldClose(window))
{
GLfloat currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
glfwPollEvents();
do_movement();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 view;
glm::mat4 projection;
glm::mat4 model;
projection = glm::perspective(45.0f, (GLfloat)WIDTH/(GLfloat)HEIGHT, 0.1f, 100.0f);
glUseProgram(program_ground);
GLint projLoc = glGetUniformLocation(program_ground, "projection");
GLint viewLoc = glGetUniformLocation(program_ground, "view");
GLint modelLoc = glGetUniformLocation(program_ground, "model");
GLint groundColorLoc = glGetUniformLocation(program_ground, "groundColor");
// GLint lightColorLoc = glGetUniformLocation(program_ground, "lightColor");
GLint lightPosLoc = glGetUniformLocation(program_ground, "lightPos");
GLint viewPosLoc = glGetUniformLocation(program_ground, "viewPos");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
// glUniform3f(lightColorLoc, 1.0, 1.0, 1.0);
glUniform3f(viewPosLoc, camera.Position.x, camera.Position.y, camera.Position.z);
glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos.z);
view = camera.GetViewMatrix();
projection = glm::perspective(camera.Zoom, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glBindVertexArray(vao_ground);
bool white_square = false;
for(GLfloat z = -10.0; z <= 10.0; z += 1.0)
{
for(GLfloat x = -10.0; x <= 10.0; x += 1.0)
{
model = glm::mat4();
if(white_square)
glUniform3f(groundColorLoc, 1.0f, 1.0f, 1.0f);
else
glUniform3f(groundColorLoc, 1.0f, 0.0f, 0.0f);
model = glm::translate(model, glm::vec3(x, 0.0f, z));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
white_square = !white_square;
}
}
glBindVertexArray(0);
model = glm::mat4();
glUseProgram(program_sphere);
modelLoc = glGetUniformLocation(program_sphere, "model");
viewLoc = glGetUniformLocation(program_sphere, "view");
projLoc = glGetUniformLocation(program_sphere, "projection");
lightPosLoc = glGetUniformLocation(program_sphere, "lightPos");
viewPosLoc = glGetUniformLocation(program_sphere, "viewPos");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniform3f(viewPosLoc, camera.Position.x, camera.Position.y, camera.Position.z);
glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos.z);
glBindVertexArray(vao_sphere);
glDrawElements(GL_TRIANGLES, 60, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glUseProgram(program_lamp);
modelLoc = glGetUniformLocation(program_lamp, "model");
viewLoc = glGetUniformLocation(program_lamp, "view");
projLoc = glGetUniformLocation(program_lamp, "projection");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glfwSwapBuffers(window);
}
}