So I have my code:
#include <iostream>
//GLEW
#define GLEW_STATIC
#include<glew.h>
//GLFW
#include <glfw3.h>
#include <SOIL.h>
#include "Shader.h"
// GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <vector>>
// Functions prototype
void key_callback(GLFWwindow *window, int key, int scancode, int action, int mode);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void checkMovement();
bool checkCollision(glm::vec3 &fruitPos, glm::vec3 &headPos);
void growSnake();
void update();
GLint bodyLength = 0;
// Window Dimensions
const GLuint screenWidth = 1000, screenHeight = 800;
bool keys[1024];
GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;
bool up = true;
bool left = false;
bool right = false;
bool down = false;
glm::vec3 cameraPos(0.0f, 0.0f, 6.0f);
GLfloat sensitivity = 0.1f;
glm::vec3 headPos(0.0f, 0.4f, 0.0f);
glm::vec3 fruitPos(1.0f, 1.0f, 0.0f);
glm::vec3 bodyPos[7];
//glm::vec3 pos(0.0f, 0.4f, 0.0f);
const GLfloat SNAKE_TIME_DURATION = 0.3f;
GLfloat next_snake_time = SNAKE_TIME_DURATION;
int main()
{
std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;
// GLFW init
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create a GLFWWindow object that we can use for GLFW's functions
GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "Snake OpenGL", nullptr, nullptr);
if (window == nullptr)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
}
glfwMakeContextCurrent(window);
// Set the required callback functions
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
glewInit();
// Initialize GLEW to setup the OpenGL Function pointers
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
int width, height;
glfwGetFramebufferSize(window, &width, &height);
// Define the viewport dimensions
glViewport(0, 0, screenWidth, screenHeight);
Shader headShader("headShader.vs", "headShader.frag");
Shader groundShader("headShader.vs", "groundShader.frag");
Shader fruitShader("headShader.vs", "fruitShader.frag");
Shader bodyShader("headShader.vs", "fruitShader.frag");
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f
};
GLuint indices[] = {
0, 1, 3,
1, 2, 3
};
GLuint headTexture, groundTexture;
GLuint VBO, HEAD, EBO, GROUND, FRUIT, BODY[7];
glGenVertexArrays(1, &HEAD);
glGenVertexArrays(1, &GROUND);
glGenVertexArrays(1, &FRUIT);
glGenVertexArrays(7, BODY);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// HEAD VAO
glBindVertexArray(HEAD);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Set the vertex attrib pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Set the texture attrib pointers
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// Head texture========================================
glGenTextures(1, &headTexture);
glBindTexture(GL_TEXTURE_2D, headTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture wrapping to GL_REPEAT
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int imgWidth, imgHeight;
unsigned char* image = SOIL_load_image("images/metal.png", &imgWidth, &imgHeight, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imgWidth, imgHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
//GROUND VAO============================================================
glBindVertexArray(GROUND);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Set the vertex attrib pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Set the texture attrib pointers
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
// Ground texture==================================================
glGenTextures(1, &groundTexture);
glBindTexture(GL_TEXTURE_2D, groundTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture wrapping to GL_REPEAT
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
image = SOIL_load_image("images/ground.jpg", &imgWidth, &imgHeight, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imgWidth, imgHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
// FRUIT VAO
glBindVertexArray(FRUIT);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Set the vertex attrib pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
for(int i = 0; i < 7; i++)
{
glBindVertexArray(BODY[i]);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Set the vertex attrib pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
}
// Game Loop
while (!glfwWindowShouldClose(window))
{
GLfloat currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
//Check if any events have been activated(key pressed, mouse moved etc.) and call corresponding response functions
glfwPollEvents();
GLfloat now = glfwGetTime();
if (now >= next_snake_time)
{
checkMovement();
next_snake_time = now + SNAKE_TIME_DURATION;
}
if (checkCollision(fruitPos, headPos))
{
growSnake();
update();
}
// Render
// Clear the color buffer
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Ground SHADER PROGRAM
groundShader.Use();
glm::mat4 model;
glm::mat4 view;
glm::mat4 proj;
view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
proj = glm::perspective(45.0f, (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
model = glm::translate(model, glm::vec3(0.0f, 0.0f, 3.0f));
model = glm::scale(model, glm::vec3(4.0f, 4.0f, 4.0f));
GLint modelLoc = glGetUniformLocation(headShader.Program, "model");
GLint viewLoc = glGetUniformLocation(headShader.Program, "view");
GLint projLoc = glGetUniformLocation(headShader.Program, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
glBindTexture(GL_TEXTURE_2D, groundTexture);
glUniform1i(glGetUniformLocation(groundShader.Program, "groundTexture"), 0);
glBindVertexArray(GROUND);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//FRUIT SHADER PROGRAM
fruitShader.Use();
model = glm::mat4();
model = glm::translate(model, glm::vec3(fruitPos.x, fruitPos.y, 0.0f));
model = glm::scale(model, glm::vec3(0.25f, 0.25f, 0.25f));
modelLoc = glGetUniformLocation(headShader.Program, "model");
viewLoc = glGetUniformLocation(headShader.Program, "view");
projLoc = glGetUniformLocation(headShader.Program, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
glBindVertexArray(FRUIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//HEAD SHADER PROGRAM
headShader.Use();
// MODEL MATRIX
model = glm::mat4();
model = glm::translate(model, glm::vec3(headPos.x, headPos.y, 0.0f));
model = glm::scale(model, glm::vec3(0.25f, 0.25f, 0.25f));
modelLoc = glGetUniformLocation(headShader.Program, "model");
viewLoc = glGetUniformLocation(headShader.Program, "view");
projLoc = glGetUniformLocation(headShader.Program, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
glBindTexture(GL_TEXTURE_2D, headTexture);
glUniform1i(glGetUniformLocation(headShader.Program, "ourTexture"), 0);
glBindVertexArray(HEAD);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// BODY SHADER PROGRAM
bodyShader.Use();
for(int i = 0; i < bodyLength; i++)
{
model = glm::mat4();
model = glm::translate(model, glm::vec3(bodyPos[i].x, bodyPos[i].y, 0.0f));
model = glm::scale(model, glm::vec3(0.25f, 0.25f, 0.25f));
modelLoc = glGetUniformLocation(bodyShader.Program, "model");
viewLoc = glGetUniformLocation(bodyShader.Program, "view");
projLoc = glGetUniformLocation(bodyShader.Program, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
glBindVertexArray(BODY[i]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
glfwSwapBuffers(window);
}
glDeleteVertexArrays(1, &HEAD);
glDeleteVertexArrays(1, &GROUND);
glDeleteVertexArrays(1, &FRUIT);
glDeleteVertexArrays(7, BODY);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glfwTerminate();
return 0;
}
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;
}
*/
if (key == GLFW_KEY_W && action == GLFW_PRESS)
{
up = true;
down = false;
left = false;
right = false;
}
if (key == GLFW_KEY_S && action == GLFW_PRESS)
{
up = false;
down = true;
left = false;
right = false;
}
if (key == GLFW_KEY_D && action == GLFW_PRESS)
{
up = false;
down = false;
left = false;
right = true;
}
if (key == GLFW_KEY_A && action == GLFW_PRESS)
{
up = false;
down = false;
left = true;
right = false;
}
}
void checkMovement()
{
if (up)
{
update();
headPos.y += sensitivity;
}
if (down)
{
update();
headPos.y -= sensitivity;
}
if (right)
{
update();
headPos.x += sensitivity;
}
if (left)
{
update();
headPos.x -= sensitivity;
}
std::cout << std::endl;
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
}
bool checkCollision(glm::vec3 &fruitPos, glm::vec3 &headPos)
{
if ((GLint)(headPos.x) == (GLint)(fruitPos.x) && (GLint)(headPos.y) == (GLint)(fruitPos.y))
{
// growSnake();
fruitPos.x++;
std::cout << "fruitPos.X: " << fruitPos.x << std::endl;
fruitPos.y++;
std::cout << "fruitPos.Y: " << fruitPos.y << std::endl;
std::cout << std::endl;
return true;
}
return false;
}
void growSnake()
{
bodyLength++;
}
void update()
{
for(int i = bodyLength - 1; i >= 0; i--)
{
if (i == 0)
{
bodyPos[i] = headPos;
}
else {
bodyPos[i] = bodyPos[i - 1];
}
}
}
How can I structure my code(the buffers, the rendering, the updating etc.) using classes ?Can somebody give me an advice ?
P.S; I'm beginner in OOP (I know the syntax, but I didn't practice working with classes, objects etc. so I need something easy).
Thank you!