From d89807981bc715912fa619f0a8311edf9de71c1e Mon Sep 17 00:00:00 2001 From: Erik Cowley Date: Mon, 9 Oct 2023 20:54:01 -0400 Subject: [PATCH] Rename snowland to ghostland --- .gitignore | 1 + ghostland.cpp | 578 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 579 insertions(+) create mode 100644 ghostland.cpp diff --git a/.gitignore b/.gitignore index b4fea81..0d7cb03 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ go.work *.o *.swp +ghostland # you can download these from the internet stb_image.c diff --git a/ghostland.cpp b/ghostland.cpp new file mode 100644 index 0000000..7dbf40e --- /dev/null +++ b/ghostland.cpp @@ -0,0 +1,578 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "shader_m.h" + +#include +#include +#include +#include + +#include "collisions.h" + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void mouse_callback(GLFWwindow* window, double xpos, double ypos); +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +void processInput(GLFWwindow *window); +int createShader(const char *filename, int shadertype); + +// settings +const unsigned int WINDOWWIDTH = 1600; +const unsigned int WINDOWHEIGHT = 900; + +// camera +glm::vec3 player_pos = glm::vec3(0.0f, 0.0f, 3.0f); +glm::vec3 camera_front = glm::vec3(0.0f, 0.0f, -1.0f); +glm::vec3 camera_up = glm::vec3(0.0f, 1.0f, 0.0f); +glm::vec3 light_pos = glm::vec3(0.0f, 0.0f, 0.0f); + +bool first_mouse = true; +float yaw = 0.0f; +float pitch = 0.0f; +float lastX = WINDOWWIDTH / 2.0; +float lastY = WINDOWHEIGHT / 2.0; +float fov = 60.0f; + +float timed = 0.0f; +float last_frame = 0.0f; + +float camera_speed = 10.0f; + +const char *projectionC = "projection"; +const char *viewC = "view"; +const char *modelC = "model"; + +const char *objectcolorC = "objectcolor"; +const char *viewposC = "viewPos"; +const char *shininessC = "material.shininess"; +const char *colorC = "material.color"; +const char *lightposC = "light.position"; +const char *directionC = "light.direction"; +const char *largecutoffC = "light.largecutoff"; +const char *smallcutoffC = "light.smallcutoff"; +const char *ambientC = "light.ambient"; +const char *diffuseC = "light.diffuse"; +const char *specularC = "light.specular"; + + +int num_walls; +float *wall_vertices; + +int trailmax = 1800; + +glm::vec3 getNormalFromIndex(int ix) { + return glm::vec3( + wall_vertices[ix * 6 * 6 + 3], + wall_vertices[ix * 6 * 6 + 4], + wall_vertices[ix * 6 * 6 + 5] + ); +} + +glm::vec3 getVec3FromIndices(int ix, int jx) { + return glm::vec3( + wall_vertices[ix * 6 * 6 + jx * 6], + wall_vertices[ix * 6 * 6 + jx * 6 + 1], + wall_vertices[ix * 6 * 6 + jx * 6 + 2] + ); +} + +glm::vec3 checkIntersection(glm::vec3 movement) { + + glm::vec3 vec_start, vec_stop, p1, p2, p3, res; + int gotX = 0, gotZ = 0; + vec_start = player_pos; + vec_stop = vec_start + movement * 20.0f; + res.x = movement.x; + res.y = movement.y; + res.z = movement.z; + + for (int ix = 0; ix < num_walls; ix++) { + glm::vec3 norm = getNormalFromIndex(ix); + if (gotX && gotZ) { + break; + } + if (!gotX) { + if ((movement.x > 0 && norm.x < 0) || (movement.x < 0 && norm.x > 0)) { + p1 = getVec3FromIndices(ix, 1); + p2 = getVec3FromIndices(ix, 0); + p3 = getVec3FromIndices(ix, 2); + if (getIntersection(vec_start, vec_stop, p1, p2, p3)) { + gotX = 1; + res.x = -movement.x; + } + } + } + if (!gotZ) { + if ((movement.z > 0 && norm.z < 0) || (movement.z < 0 && norm.z > 0)) { + p1 = getVec3FromIndices(ix, 1); + p2 = getVec3FromIndices(ix, 0); + p3 = getVec3FromIndices(ix, 2); + if (getIntersection(vec_start, vec_stop, p1, p2, p3)) { + gotZ = 1; + res.z = -movement.z; + } + } + } + } + + return res; + +} + +int main() +{ + + int success; + + FILE *fp = fopen("maze.txt", "r"); + float fakeyaw; + if (fscanf(fp, "%f %f %f %f\n", &player_pos.x, &player_pos.y, &player_pos.z, &fakeyaw) == EOF) { + printf("1st fscanf failed.\n"); + return -1; + } + if (fscanf(fp, "%d\n", &num_walls) == EOF) { + printf("2nd fscanf failed.\n"); + return -1; + } + // num surfaces * 6 (vertices per point) * 6 (floats per point) + int num_wall_vertices = num_walls * 6 * 6; + wall_vertices = (float *)calloc(sizeof(float), num_wall_vertices); + // read walls + for (int i = 0; i < num_walls; i++) { + for (int j = 0; j < 6; j++) { + int vix = i*6*6 + j*6; + if (fscanf( + fp, + "%f %f %f %f %f %f\n", + &wall_vertices[vix], + &wall_vertices[vix+1], + &wall_vertices[vix+2], + &wall_vertices[vix+3], + &wall_vertices[vix+4], + &wall_vertices[vix+5] + ) == EOF) { + printf("3rd fscanf failed.\n"); + return -1; + } + } + if (fscanf(fp, "\n") == EOF) { + printf("4th fscanf failed.\n"); + return -1; + } + } + + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + GLFWwindow* window = glfwCreateWindow(WINDOWWIDTH, WINDOWHEIGHT, "Ghostland!", NULL, NULL); + if (window == NULL) + { + printf("Failed to create GLFW window.\n"); + glfwTerminate(); + return -1; + } + glfwMakeContextCurrent(window); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetCursorPosCallback(window, mouse_callback); + glfwSetScrollCallback(window, scroll_callback); + + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + printf("Failed to initialize GLAD.\n"); + return -1; + } + + glEnable(GL_DEPTH_TEST); + + int vertex_shader = createShader("vertexshader.txt", GL_VERTEX_SHADER); + if (vertex_shader < 0) { + return -1; + } + int fragment_shader = createShader("fragmentshader.txt", GL_FRAGMENT_SHADER); + if (fragment_shader < 0) { + return -1; + } + + int wall_program = glCreateProgram(); + glAttachShader(wall_program, vertex_shader); + glAttachShader(wall_program, fragment_shader); + glLinkProgram(wall_program); + glGetProgramiv(wall_program, GL_LINK_STATUS, &success); + if (!success) { + char infoLog[1024]; + glGetProgramInfoLog(wall_program, 1024, NULL, infoLog); + printf("Shader wall_program link error: %s\n", infoLog); + glfwTerminate(); + return -1; + } + + int floor_program = glCreateProgram(); + glAttachShader(floor_program, vertex_shader); + glAttachShader(floor_program, fragment_shader); + glLinkProgram(floor_program); + glGetProgramiv(floor_program, GL_LINK_STATUS, &success); + if (!success) { + char infoLog[1024]; + glGetProgramInfoLog(floor_program, 1024, NULL, infoLog); + printf("Shader floor_program link error: %s\n", infoLog); + glfwTerminate(); + return -1; + } + + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + + // read floor + float *floor_vertices = (float *)calloc(sizeof(float), 6*6); + for (int j = 0; j < 6; j++) { + int vix = j*6; + if (fscanf( + fp, + "%f %f %f %f %f %f\n", + &floor_vertices[vix], + &floor_vertices[vix+1], + &floor_vertices[vix+2], + &floor_vertices[vix+3], + &floor_vertices[vix+4], + &floor_vertices[vix+5] + ) == EOF) { + printf("floor fscanf failed.\n"); + return -1; + } + } + fclose(fp); + + // do stuff for walls + unsigned int wallsVBO, wallsVAO; + glGenVertexArrays(1, &wallsVAO); + glGenBuffers(1, &wallsVBO); + + glBindVertexArray(wallsVAO); + + glBindBuffer(GL_ARRAY_BUFFER, wallsVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * num_wall_vertices, wall_vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + // normal attribute + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + // do stuff for floor + unsigned int floorVBO, floorVAO; + glGenVertexArrays(1, &floorVAO); + glGenBuffers(1, &floorVBO); + + glBindVertexArray(floorVAO); + + glBindBuffer(GL_ARRAY_BUFFER, floorVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 6 * 1, floor_vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + // normal attribute + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + // do stuff for trail + float trail_vertices[] = { + 0.25f, 0.0f, 0.0f, + -0.25f, 0.0f, 0.5f, + -0.25f, 0.0f, -0.5f, + + -0.25f, 0.0f, 0.1f, + -0.25f, 0.0f, -0.1f, + -0.75f, 0.0f, 0.1f, + + -0.75f, 0.0f, 0.1f, + -0.75f, 0.0f, -0.1f, + -0.25f, 0.0f, -0.1f, + }; + + unsigned int trailVBO, trailVAO; + glGenVertexArrays(1, &trailVAO); + glGenBuffers(1, &trailVBO); + + glBindVertexArray(trailVAO); + + glBindBuffer(GL_ARRAY_BUFFER, trailVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * 3 * 3, trail_vertices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + glEnableVertexAttribArray(0); + + int trail_shader = createShader("trailshader.txt", GL_VERTEX_SHADER); + if (trail_shader < 0) { + return -1; + } + int trailfrag_shader = createShader("trailfragshader.txt", GL_FRAGMENT_SHADER); + if (trailfrag_shader < 0) { + return -1; + } + + int trail_program = glCreateProgram(); + glAttachShader(trail_program, trail_shader); + glAttachShader(trail_program, trailfrag_shader); + glLinkProgram(trail_program); + glGetProgramiv(trail_program, GL_LINK_STATUS, &success); + if (!success) { + char infoLog[1024]; + glGetProgramInfoLog(wall_program, 1024, NULL, infoLog); + printf("Shader trail_program link error: %s\n", infoLog); + glfwTerminate(); + return -1; + } + + glm::vec3 *trail_positions = (glm::vec3 *)calloc(sizeof(glm::vec3), trailmax); + float *trail_angles = (float *)calloc(sizeof(float), trailmax); + int trail_ix = 0; + int trail_sz = 0; + + int time_sec = 0, num_frames = 0; + glm::vec3 wall_color = glm::vec3(0.61f, 0.6f, 0.59f); + float wall_shininess = 6.5; + glm::vec3 floor_color = glm::vec3(0.11f, 0.1f, 0.09f); + float floor_shininess = 3.25; + glm::vec3 ambient = glm::vec3(0.007f, 0.006f, 0.005f); + glm::vec3 diffuse = glm::vec3(0.61f, 0.60f, 0.59f); + glm::vec3 specular = glm::vec3(0.11f, 0.10f, 0.09f); + + float largecutoff = glm::cos(glm::radians(30.0f)); + float smallcutoff = glm::cos(glm::radians(7.5f)); + + while (!glfwWindowShouldClose(window)) + { + float current_frame = static_cast(glfwGetTime()); + int current_frameI = (int)current_frame; + if (current_frameI != time_sec) { + printf("FPS: %d\n", num_frames); + time_sec = current_frameI; + num_frames = 0; + trail_positions[trail_ix].x = player_pos.x; + trail_positions[trail_ix].y = 6.5; + trail_positions[trail_ix].z = player_pos.z; + trail_angles[trail_ix] = yaw; + printf("Recorded trail %d: (%f, %f, %f) %f\n", trail_ix, trail_positions[trail_ix].x, trail_positions[trail_ix].y, trail_positions[trail_ix].z, yaw); + trail_ix = (trail_ix + 1) % trailmax; + if (trail_sz < trailmax) { + trail_sz++; + } + } else { + num_frames++; + } + timed = current_frame - last_frame; + last_frame = current_frame; + + processInput(window); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glUseProgram(wall_program); + + glm::mat4 projection = glm::perspective(glm::radians(fov), (float)WINDOWWIDTH / (float)WINDOWHEIGHT, 0.1f, 256.0f); + glUniformMatrix4fv(glGetUniformLocation(wall_program, projectionC), 1, GL_FALSE, &projection[0][0]); + + glm::mat4 view = glm::lookAt(player_pos, player_pos + camera_front, camera_up); + glUniformMatrix4fv(glGetUniformLocation(wall_program, viewC), 1, GL_FALSE, &view[0][0]); + + glm::mat4 model = glm::mat4(1.0f); + glUniformMatrix4fv(glGetUniformLocation(wall_program, modelC), 1, GL_FALSE, &model[0][0]); + + // light position + light_pos.x = player_pos.x + 0.5 * cos(glm::radians(yaw + 45.0f)) * cos(glm::radians(pitch)); + light_pos.y = player_pos.y + 0.5 * sin(glm::radians(pitch)); + light_pos.z = player_pos.z + 0.5 * sin(glm::radians(yaw + 45.0f)) * cos(glm::radians(pitch)); + + // fragment requirements + glUniform3fv(glGetUniformLocation(wall_program, viewposC), 1, &player_pos[0]); + glUniform1f(glGetUniformLocation(wall_program, shininessC), wall_shininess); + glUniform3fv(glGetUniformLocation(wall_program, colorC), 1, &wall_color[0]); + glUniform3fv(glGetUniformLocation(wall_program, lightposC), 1, &light_pos[0]); + glUniform3fv(glGetUniformLocation(wall_program, directionC), 1, &camera_front[0]); + glUniform1f(glGetUniformLocation(wall_program, largecutoffC), largecutoff); + glUniform1f(glGetUniformLocation(wall_program, smallcutoffC), smallcutoff); + glUniform3fv(glGetUniformLocation(wall_program, ambientC), 1, &ambient[0]); + glUniform3fv(glGetUniformLocation(wall_program, diffuseC), 1, &diffuse[0]); + glUniform3fv(glGetUniformLocation(wall_program, specularC), 1, &specular[0]); + + glBindVertexArray(wallsVAO); + glDrawArrays(GL_TRIANGLES, 0, num_wall_vertices); + + glUseProgram(floor_program); + + glUniformMatrix4fv(glGetUniformLocation(floor_program, projectionC), 1, GL_FALSE, &projection[0][0]); + glUniformMatrix4fv(glGetUniformLocation(floor_program, viewC), 1, GL_FALSE, &view[0][0]); + glUniformMatrix4fv(glGetUniformLocation(floor_program, modelC), 1, GL_FALSE, &model[0][0]); + glUniform3fv(glGetUniformLocation(floor_program, viewposC), 1, &player_pos[0]); + + // fragment requirements + glUniform3fv(glGetUniformLocation(floor_program, viewposC), 1, &player_pos[0]); + glUniform1f(glGetUniformLocation(floor_program, shininessC), floor_shininess); + glUniform3fv(glGetUniformLocation(floor_program, colorC), 1, &floor_color[0]); + glUniform3fv(glGetUniformLocation(floor_program, lightposC), 1, &light_pos[0]); + glUniform3fv(glGetUniformLocation(floor_program, directionC), 1, &camera_front[0]); + glUniform1f(glGetUniformLocation(floor_program, largecutoffC), largecutoff); + glUniform1f(glGetUniformLocation(floor_program, smallcutoffC), smallcutoff); + glUniform3fv(glGetUniformLocation(floor_program, ambientC), 1, &ambient[0]); + glUniform3fv(glGetUniformLocation(floor_program, diffuseC), 1, &diffuse[0]); + glUniform3fv(glGetUniformLocation(floor_program, specularC), 1, &specular[0]); + + glBindVertexArray(floorVAO); + glDrawArrays(GL_TRIANGLES, 0, 6 * 6 * 1); + + glUseProgram(trail_program); + + glUniformMatrix4fv(glGetUniformLocation(trail_program, projectionC), 1, GL_FALSE, &projection[0][0]); + glUniformMatrix4fv(glGetUniformLocation(trail_program, viewC), 1, GL_FALSE, &view[0][0]); + glm::vec3 trail_color = glm::vec3(1.0f, 0.0f, 0.0f); + glUniform3fv(glGetUniformLocation(trail_program, objectcolorC), 1, &trail_color[0]); + + for (int i = 0; i < trail_sz; i++) { + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, trail_positions[i]); + model = glm::rotate(model, glm::radians(trail_angles[i]), glm::vec3(0.0f, -1.0f, 0.0f)); + glUniformMatrix4fv(glGetUniformLocation(trail_program, modelC), 1, GL_FALSE, &model[0][0]); + glBindVertexArray(trailVAO); + + glDrawArrays(GL_TRIANGLES, 0, 3 * 3 * 3); + } + + glfwSwapBuffers(window); + glfwPollEvents(); + + } + + glDeleteVertexArrays(1, &wallsVAO); + glDeleteBuffers(1, &wallsVBO); + + glDeleteVertexArrays(1, &floorVAO); + glDeleteBuffers(1, &floorVBO); + + glfwTerminate(); + return 0; +} + +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); + + float camera_speed_adjusted = static_cast(camera_speed * timed); + glm::vec3 movement; + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { + movement = glm::vec3(camera_front.x, 0.0, camera_front.z); + } else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { + movement = glm::vec3(-camera_front.x, 0.0, -camera_front.z); + } else if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { + glm::vec3 right = glm::cross(camera_front, camera_up); + movement = glm::vec3(-right.x, 0.0, -right.z); + } else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { + glm::vec3 right = glm::cross(camera_front, camera_up); + movement = glm::vec3(right.x, 0.0, right.z); + } else { + return; + } + movement = glm::normalize(movement) * camera_speed_adjusted; + movement = checkIntersection(movement); + player_pos += movement; +} + +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +void mouse_callback(GLFWwindow* window, double xpos_in, double ypos_in) +{ + float xpos = static_cast(xpos_in); + float ypos = static_cast(ypos_in); + + if (first_mouse) + { + lastX = xpos; + lastY = ypos; + first_mouse = false; + } + + float xoffset = xpos - lastX; + float yoffset = lastY - ypos; + lastX = xpos; + lastY = ypos; + + float sensitivity = 0.1f; + xoffset *= sensitivity; + yoffset *= sensitivity; + + yaw += xoffset; + pitch += yoffset; + + if (pitch > 89.0f) + pitch = 89.0f; + if (pitch < -89.0f) + pitch = -89.0f; + + glm::vec3 front; + front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch)); + front.y = sin(glm::radians(pitch)); + front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch)); + camera_front = glm::normalize(front); + +} + +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) +{ + fov -= (float)yoffset; + if (fov < 1.0f) + fov = 1.0f; + if (fov > 90.0f) + fov = 90.0f; +} + +int createShader(const char *filename, int shadertype) { + FILE* fp = fopen(filename, "r"); + if (!fp) { + printf("failed to open vertex shader!\n"); + return -1; + } + fseek(fp, 0L, SEEK_END); + unsigned int buffer_sz = ftell(fp); + rewind(fp); + + char *buffer = (char *)calloc(sizeof(char), buffer_sz + 1); + if (fread(buffer, buffer_sz, 1, fp) != 1) { + printf("failed to read vertex shader!\n"); + return -1; + } + fclose(fp); + + int shader = glCreateShader(shadertype); + glShaderSource(shader, 1, &buffer, NULL); + free(buffer); + glCompileShader(shader); + int success; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + char info_log[1024]; + glGetShaderInfoLog(shader, 1024, NULL, info_log); + printf("Shader compile error for %s: %s\n", filename, info_log); + glfwTerminate(); + return -1; + } + return shader; +}