354 lines
11 KiB
C++
354 lines
11 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <vector>
|
|
|
|
#include <GL/glew.h>
|
|
#include <GLFW/glfw3.h>
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
#include <glm/trigonometric.hpp>
|
|
|
|
#include <backends/imgui_impl_glfw.h>
|
|
#include <backends/imgui_impl_opengl3.h>
|
|
#include <imgui.h>
|
|
|
|
#include <SOIL2.h>
|
|
#include <assimp/DefaultLogger.hpp>
|
|
#include <assimp/Importer.hpp>
|
|
#include <assimp/Logger.hpp>
|
|
#include <assimp/postprocess.h>
|
|
#include <assimp/scene.h>
|
|
|
|
extern "C" {
|
|
#include "shader.h"
|
|
}
|
|
|
|
#define WIDTH 1024
|
|
#define HEIGHT 768
|
|
|
|
static void glfwErrorCallback(int e, const char *description) {
|
|
fprintf(stderr, "GLFW Error %d: %s", e, description);
|
|
}
|
|
|
|
bool loadModel(const char *path, std::vector<unsigned short> &indices,
|
|
std::vector<glm::vec3> &vertices, std::vector<glm::vec2> &uvs,
|
|
std::vector<glm::vec3> &normals) {
|
|
Assimp::Importer importer;
|
|
|
|
const aiScene *scene = importer.ReadFile(
|
|
path, aiProcess_Triangulate | aiProcess_JoinIdenticalVertices |
|
|
aiProcess_SortByPType);
|
|
if (!scene) {
|
|
fprintf(stderr, "%s\n", importer.GetErrorString());
|
|
return false;
|
|
}
|
|
const aiMesh *mesh = scene->mMeshes[0];
|
|
|
|
vertices.reserve(mesh->mNumVertices);
|
|
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
|
|
aiVector3D pos = mesh->mVertices[i];
|
|
vertices.push_back(glm::vec3(pos.x, pos.y, pos.z));
|
|
}
|
|
|
|
uvs.reserve(mesh->mNumVertices);
|
|
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
|
|
aiVector3D UVW = mesh->mTextureCoords[0][i]; // Multiple UVs? Prepsterous!
|
|
uvs.push_back(glm::vec2(UVW.x, UVW.y));
|
|
}
|
|
|
|
normals.reserve(mesh->mNumVertices);
|
|
for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
|
|
indices.push_back(mesh->mFaces[i].mIndices[0]);
|
|
indices.push_back(mesh->mFaces[i].mIndices[1]);
|
|
indices.push_back(mesh->mFaces[i].mIndices[2]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int initWindow() {
|
|
glfwSetErrorCallback(glfwErrorCallback);
|
|
|
|
glewExperimental = true;
|
|
if (!glfwInit()) {
|
|
fprintf(stderr, "GLFW went shitty time\n");
|
|
return 1;
|
|
}
|
|
|
|
glfwWindowHint(GLFW_SAMPLES, 4); // 4x Antialiasing
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Loser MacOS is broken
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // New GL
|
|
|
|
GLFWwindow *window;
|
|
window = glfwCreateWindow(WIDTH, HEIGHT, "Fred", NULL, NULL);
|
|
if (window == NULL) {
|
|
fprintf(stderr, "Failed to open window.\n");
|
|
glfwTerminate();
|
|
return 1;
|
|
}
|
|
|
|
glfwMakeContextCurrent(window);
|
|
glfwSwapInterval(1);
|
|
int code;
|
|
if ((code = glewInit()) != GLEW_OK) {
|
|
fprintf(stderr, "Failed to init GLEW: %s\n", glewGetErrorString(code));
|
|
return 1;
|
|
}
|
|
|
|
IMGUI_CHECKVERSION();
|
|
ImGui::CreateContext();
|
|
ImGuiIO &io = ImGui::GetIO();
|
|
(void)io;
|
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
|
|
|
ImGui::StyleColorsDark();
|
|
|
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
|
ImGui_ImplOpenGL3_Init("#version 330");
|
|
|
|
std::vector<unsigned short> indices;
|
|
std::vector<glm::vec3> indexed_vertices;
|
|
std::vector<glm::vec2> indexed_uvs;
|
|
std::vector<glm::vec3> indexed_normals;
|
|
if (!loadModel("../models/model.obj", indices, indexed_vertices, indexed_uvs,
|
|
indexed_normals)) {
|
|
return 0;
|
|
}
|
|
|
|
GLuint vertexArrayID;
|
|
glGenVertexArrays(1, &vertexArrayID);
|
|
glBindVertexArray(vertexArrayID);
|
|
|
|
GLuint vertexBuffer;
|
|
glGenBuffers(1, &vertexBuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
|
|
glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(glm::vec3),
|
|
&indexed_vertices[0], GL_STATIC_DRAW);
|
|
|
|
GLuint uvBuffer;
|
|
glGenBuffers(1, &uvBuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
|
|
glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(glm::vec2),
|
|
&indexed_uvs[0], GL_STATIC_DRAW);
|
|
|
|
GLuint normalBuffer;
|
|
glGenBuffers(1, &normalBuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
|
|
glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(glm::vec3),
|
|
&indexed_normals[0], GL_STATIC_DRAW);
|
|
|
|
GLuint elementBuffer;
|
|
glGenBuffers(1, &elementBuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, elementBuffer);
|
|
glBufferData(GL_ARRAY_BUFFER, indices.size() * sizeof(unsigned short),
|
|
&indices[0], GL_STATIC_DRAW);
|
|
|
|
GLuint texture = SOIL_load_OGL_texture(
|
|
"../textures/results/texture_BMP_DXT5_3.DDS", SOIL_LOAD_AUTO,
|
|
SOIL_CREATE_NEW_ID,
|
|
SOIL_FLAG_MIPMAPS | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
|
|
if (texture == 0) {
|
|
printf("Texture failed to load\n");
|
|
return 0;
|
|
}
|
|
|
|
GLuint programID =
|
|
loadShaders("../shaders/shader.vert", "../shaders/shader.frag");
|
|
|
|
// I love glm
|
|
// Projection matrix, 45deg FOV, 4:3 Aspect Ratio, Planes: 0.1units ->
|
|
// 100units
|
|
glm::mat4 projection = glm::perspective(
|
|
glm::radians(45.0f), (float)WIDTH / (float)HEIGHT, 0.1f, 100.0f);
|
|
|
|
// Camera matrix
|
|
glm::mat4 view =
|
|
glm::lookAt(glm::vec3(4, 3, 3), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
|
|
|
|
glm::mat4 model = glm::mat4(1.0f);
|
|
|
|
// Model view projection, the combination of the three vectors
|
|
glm::mat4 mvp = projection * view * model;
|
|
|
|
GLuint matrixID = glGetUniformLocation(programID, "MVP");
|
|
|
|
glEnable(GL_DEPTH_TEST); // Turn on the Z-buffer
|
|
glDepthFunc(GL_LESS); // Accept only the closest fragments
|
|
|
|
glEnable(GL_CULL_FACE); // Backface culling
|
|
|
|
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
|
|
|
// Define camera stuff
|
|
glm::vec3 position = {4, 3, 3};
|
|
float horizontalAngle = 3.14F; // Toward -Z, in Rads
|
|
float verticalAngle = 0.0f; // On the horizon
|
|
float initialFOV = 60.0f;
|
|
|
|
float speed = 3.0f;
|
|
float mouseSpeed = 0.005f;
|
|
|
|
double xpos, ypos;
|
|
|
|
double lastTime = 0;
|
|
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
|
|
glfwWindowShouldClose(window) == 0) {
|
|
// Clear this mf
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glUseProgram(programID);
|
|
|
|
// ImGui
|
|
// if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) {
|
|
// ImGui_ImplGlfw_Sleep(10);
|
|
// continue; // No rendering while minimized
|
|
// }
|
|
|
|
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
|
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
|
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
ImGui_ImplGlfw_NewFrame();
|
|
|
|
ImGui::NewFrame();
|
|
|
|
// ImGui::ShowDemoWindow();
|
|
ImGui::Begin("DEBUG INFO");
|
|
ImGui::Text("MVP:");
|
|
if (ImGui::BeginTable("mvp", 4)) {
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[0][0]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[0][1]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[0][2]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[0][3]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[1][0]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[1][1]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[1][2]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[1][3]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[2][0]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[2][1]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[2][2]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[2][3]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[3][0]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[3][1]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[3][2]);
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%f", mvp[3][3]);
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
ImGui::End();
|
|
|
|
// Compute a Fresh Super Sigma MVP
|
|
// What would an input system be without delta time
|
|
double currentTime = glfwGetTime();
|
|
float deltaTime = (float)(currentTime - lastTime);
|
|
|
|
glfwGetCursorPos(window, &xpos, &ypos);
|
|
glfwSetCursorPos(window, (float)(WIDTH) / 2, (float)(HEIGHT) / 2);
|
|
|
|
horizontalAngle +=
|
|
mouseSpeed * deltaTime * (float)((float)(WIDTH) / 2 - xpos);
|
|
verticalAngle +=
|
|
mouseSpeed * deltaTime * (float)((float)(HEIGHT) / 2 - ypos);
|
|
glm::vec3 direction(cos(verticalAngle) * sin(horizontalAngle),
|
|
sin(verticalAngle),
|
|
cos(verticalAngle) * cos(horizontalAngle));
|
|
glm::vec3 right(sin(horizontalAngle - 3.14f / 2.0f), 0,
|
|
cos(horizontalAngle - 3.14f / 2.0f));
|
|
glm::vec3 up = glm::cross(right, direction);
|
|
|
|
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
|
|
position += direction * deltaTime * speed;
|
|
}
|
|
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
|
|
position -= direction * deltaTime * speed;
|
|
}
|
|
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
|
|
position += right * deltaTime * speed;
|
|
}
|
|
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
|
|
position -= right * deltaTime * speed;
|
|
}
|
|
|
|
// float FOV = initialFOV;
|
|
// Disabled because unchanged
|
|
// glm_perspective(glm_rad(FOV), 4.0f/ 3.0f, 0.1f, 100.0f, projection);
|
|
glm::mat4 view = glm::lookAt(position, position + direction, up);
|
|
mvp = projection * view * model;
|
|
|
|
// Send mega sigma MVP to the vertex shader (transformations for the win)
|
|
glUniformMatrix4fv(matrixID, 1, GL_FALSE, &mvp[0][0]);
|
|
|
|
// DRAWING HAPPENS HERE
|
|
// Vertex Data
|
|
glEnableVertexAttribArray(0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
|
|
|
|
// UV Data
|
|
glEnableVertexAttribArray(1);
|
|
glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
|
|
|
|
// Normal Data
|
|
glEnableVertexAttribArray(2);
|
|
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
|
|
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
|
|
|
|
// Index buffer
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
|
|
|
|
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, (void *)0);
|
|
|
|
glDisableVertexAttribArray(0);
|
|
glDisableVertexAttribArray(1);
|
|
glDisableVertexAttribArray(2);
|
|
|
|
ImGui::Render();
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
|
|
// Swap buffers
|
|
glfwSwapBuffers(window);
|
|
glfwPollEvents();
|
|
|
|
lastTime = currentTime; // Count total frame time
|
|
}
|
|
|
|
ImGui_ImplOpenGL3_Shutdown();
|
|
ImGui_ImplGlfw_Shutdown();
|
|
ImGui::DestroyContext();
|
|
|
|
glDeleteBuffers(1, &vertexBuffer);
|
|
glDeleteBuffers(1, &uvBuffer);
|
|
glDeleteBuffers(1, &normalBuffer);
|
|
glDeleteBuffers(1, &elementBuffer);
|
|
glDeleteProgram(programID);
|
|
glDeleteTextures(1, &texture);
|
|
glDeleteVertexArrays(1, &vertexArrayID);
|
|
|
|
glfwDestroyWindow(window);
|
|
glfwTerminate();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main() { return initWindow(); }
|