#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <algorithm>
class Camera{
// euler Angles
float yaw;
float pitch;
glm::vec3 forward;
glm::vec3 up;
glm::vec3 right;
glm::vec3 WorldUp;
glm::mat4 proj;
glm::vec3 location;
void updateCameraVectors()
{
// calculate the new Front vector
forward.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
forward.y = sin(glm::radians(pitch));
forward.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
forward = glm::normalize(forward);
// also re-calculate the Right and Up vector
right = glm::normalize(glm::cross(forward, WorldUp)); // normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
up = glm::normalize(glm::cross(right, forward));
}
public:
Camera() {}
Camera(float screenWidth, float screenHeight, float fov = 100.0f, float near = 0.1f, float far = 10'000.0f)
{
SetProjection(screenWidth, screenWidth, fov, near, far);
location = glm::vec3(0.0f);
WorldUp = glm::vec3(0, 1, 0);
yaw = -90;
pitch = 0;
updateCameraVectors();
}
void Move(glm::vec3 deltaLocation) {
location += deltaLocation.x * right;
location += deltaLocation.y * up;
location += deltaLocation.z * -forward;
}
void Rotate(glm::vec3 deltaRotation) {
yaw += -deltaRotation.y;
pitch += deltaRotation.x;
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
// update Front, Right and Up Vectors using the updated Euler angles
updateCameraVectors();
}
void SetProjection(float screenWidth, float screenHeight, float fov, float near = 0.1f, float far = 10'000.0f) {
proj = glm::perspective(glm::degrees(10.0f), screenWidth / screenHeight, near, far);
}
glm::mat4 GetCameraMatrix() {
return proj * glm::lookAt(location, location + forward*100.0f, glm::vec3(0, 1, 0));
}
};
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <string>
#include <iostream>
#include <vector>
#include "Shader.h"
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "Actor.h"
#include "Camera.h"
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
void drawActor(Actor& actor, VertexBuffer& vb, IndexBuffer& ib);
void processInput(GLFWwindow* window);
void size_callback(GLFWwindow* window, int width, int height);
void cursor_enter_callback(GLFWwindow* window, int entered);
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);
GLFWwindow* create_GLFWwindow(float width, float height, std::string title);
void init_glad();
Camera camera;
Shader shader;
float SCR_WIDTH = 640, SCR_HEIGHT = 480;
std::string SCR_TITLE = "My 3D App";
glm::mat4 proj, view, model;
float currentFrame, lastFrame, deltaTime;
int main() {
GLFWwindow* window = create_GLFWwindow(SCR_WIDTH, SCR_HEIGHT, SCR_TITLE);
init_glad();
shader.Compile();
shader.Bind();
// |>----------<>----------<>----------<>----------<>----------<|
// |> DEFINE VERTICES <|
// |>----------<>----------<>----------<>----------<>----------<|
std::vector<Actor> actors;
for(int i =0;i<10;i++)
for (int j = 0; j < 10; j++) {
Actor actor(50);
actor.setLocation(200 * i, 100 * j, 0);
actors.push_back(actor);
}
unsigned int layout[]{ 3, GL_FLOAT,2,GL_FLOAT };
VertexArray va; va.Bind();
VertexBuffer vb;// (actor1.getPoints().data(), sizeof(float) * actor1.getPoints().size());
IndexBuffer ib;// (actor1.getIndicies().data(), sizeof(unsigned int) * actor1.getIndicies().size());
vb.setLayout(layout,sizeof(layout));
va.Unbind();
// |>----------<>----------<>----------<>----------<>----------<|
// |> TEXTURE <|
// |>----------<>----------<>----------<>----------<>----------<|
// load and create a texture
unsigned int texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
// The FileSystem::getPath(...) is part of the GitHub repository so we can find files on any IDE/platform; replace it with your own image path.
unsigned char* data = stbi_load("res/horse-face.png", &width, &height, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
shader.SetUniform1i("texture1", 0);
// enable blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// |>----------<>----------<>----------<>----------<>----------<|
// |> CAMERA <|
// |>----------<>----------<>----------<>----------<>----------<|
camera = Camera(35, SCR_WIDTH, SCR_HEIGHT);
// |>----------<>----------<>----------<>----------<>----------<|
// |> ImGUI <|
// |>----------<>----------<>----------<>----------<>----------<|
ImGui::CreateContext();
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 440");
//ImGui variables:
//bool show_demo_window = true;
//bool show_another_window = false;
float clear_color[]{ 0.45f, 0.55f, 0.60f, 1.00f };
// |>----------<>----------<>----------<>----------<>----------<|
// |> RENDER LOOP <|
// |>----------<>----------<>----------<>----------<>----------<|
glEnable(GL_DEPTH_TEST);
va.Bind();
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
while (!glfwWindowShouldClose(window)) {
// per-frame time logic
// --------------------
float currentFrame = static_cast<float>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
processInput(window);
// clear
glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
for(auto& i :actors)
drawActor(i,vb,ib);
// render imgui
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("test");
ImGui::ColorEdit4("bg color", clear_color);
ImGui::End();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
glfwPollEvents();
}
}
void drawActor(Actor& actor, VertexBuffer& vb, IndexBuffer& ib) {
vb.SetBufferData(actor.getPoints().data(), sizeof(float) * actor.getPoints().size());
ib.SetBufferData(actor.getIndicies().data(), sizeof(unsigned int) * actor.getIndicies().size());
model = actor.modelMatrix();
glm::mat4 mvp = camera.GetCameraMatrix() * model;
shader.setUniformMat4f("u_MVP", mvp);
glDrawElements(GL_TRIANGLES, actor.getIndicies().size(), GL_UNSIGNED_INT, 0);
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
//if (key == GLFW_KEY_RIGHT && action == GLFW_PRESS);
if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
if (GLFW_CURSOR_DISABLED == glfwGetInputMode(window, GLFW_CURSOR))
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
else
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
void processInput(GLFWwindow* window){
float cameraSpeed = static_cast<float>(250 * deltaTime);
glm::vec3 deltaLocation = glm::vec3(0.0f);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
deltaLocation += glm::vec3(0, 0, -1); // to forward
else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
deltaLocation += glm::vec3(0, 0, 1); // to backward
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
deltaLocation += glm::vec3(1, 0, 0); // to right
else if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
deltaLocation += glm::vec3(-1, 0, 0); // to left
if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
deltaLocation += glm::vec3(0, 1, 0); // to up
else if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
deltaLocation += glm::vec3(0, -1, 0); // to down
camera.Move(deltaLocation * cameraSpeed);
glm::mat4 mvp = camera.GetCameraMatrix() * model;
shader.setUniformMat4f("u_MVP", mvp);
}
void size_callback(GLFWwindow* window, int width, int height) {
//std::cout << "New width: " << width << "\theight: " << height << std::endl;
//camera.SetProjection(width, height,10);
//glm::mat4 mvp = camera.GetCameraMatrix() * model;
//shader.setUniformMat4f("u_MVP", mvp);
//glViewport(0, 0, width, height);
}
GLFWwindow* create_GLFWwindow(float width, float height, std::string title){
// |>----------<>----------<>----------<>----------<>----------<|
// |> CREATE GLFW WINDOW <|
// |>----------<>----------<>----------<>----------<>----------<|
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWmonitor* MyMonitor = glfwGetPrimaryMonitor(); // The primary monitor.. Later Occulus?..
const GLFWvidmode* mode = glfwGetVideoMode(MyMonitor);
SCR_WIDTH = mode->width;
SCR_HEIGHT = mode->height;
std::cout << "Monitor width: " << SCR_WIDTH << "\theight: " << SCR_HEIGHT << std::endl;
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, title.c_str(), glfwGetPrimaryMonitor(), NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
//return EXIT_FAILURE;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glfwSetFramebufferSizeCallback(window, size_callback); // we bind callback to our size_callback func.
glfwSetCursorPosCallback(window, cursor_position_callback);
glfwSetCursorEnterCallback(window, cursor_enter_callback);
glfwSetKeyCallback(window, key_callback);
//https://www.glfw.org/docs/3.3/input_guide.html#cursor_standard
//glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
return window;
}
// |>----------<>----------<>----------<>----------<>----------<|
// |> MOUSE <|
// |>----------<>----------<>----------<>----------<>----------<|
static double lastX = 0, lastY = 0;
void cursor_enter_callback(GLFWwindow* window, int entered){
if (entered){
glfwGetCursorPos(window, &lastX, &lastY);
}
else{
// The cursor left the content area of the window
}
}
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) {
if (GLFW_CURSOR_NORMAL == glfwGetInputMode(window, GLFW_CURSOR))
return;
//std::cout << lastX-xpos << "-" << lastY-ypos << std::endl;
double mouseSensitivity = 0.2;
double deltaX = (lastX - xpos) * mouseSensitivity;
double deltaY = (lastY - ypos) * mouseSensitivity;
camera.Rotate(glm::vec3(deltaY, deltaX, 0));
lastX = xpos;
lastY = ypos;
//static double lastX, lastY;
}
void init_glad(){
// |>----------<>----------<>----------<>----------<>----------<|
// |> LOAD OPENGL FUNCTION POINTERS <|
// |>----------<>----------<>----------<>----------<>----------<|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
exit(EXIT_FAILURE);
}
}
Leave a Reply