#include // must come before glfw3 #include #include #include #include #include #include "map/node.h" #include "map/square.h" #define MAP_HEIGHT 10 #define MAP_WIDTH 10 float camera_pos_x = 0.0f; float camera_pos_y = 0.0f; float camera_pos_z = 0.0f; float camera_yaw = 50.0f; // rotation around y-axis float camera_pitch = -50.0f; // rotation aroudn x-axis float camera_speed = 0.1f; float yaw_speed = 0.5f; float pitch_speed = 0.5f; bool draw_grid = true; bool debug_spin = false; bool DEBUG = false; void logger(const char* msg) { if (DEBUG) { printf("%s\n", msg); } } // Renderer void renderHeightMap(Square **squares) { logger("Init colors..."); float colors[4][3] = { {0.0f, 0.0f, 0.0f}, // init {0.2f, 0.7f, 0.2f}, // fairway green {0.0f, 0.5f, 0.0f}, // rough green {0.3f, 0.8f, 0.3f}, // green green }; float scale_factor = 1.0f; logger("Init perspective..."); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(-camera_pos_x, -camera_pos_y, -camera_pos_z); glRotatef(-camera_pitch, 1.0f, 0.0f, 0.0f); glRotatef(-camera_yaw, 0.0f, 1.0f, 0.0f); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-10.0, 10.0, -10.0, 10.0, -20.0, 20.0); logger("Init rendering..."); for (int x = 0; x < MAP_WIDTH - 1; x++) { for (int y = 0; y < MAP_HEIGHT - 1; y++) { // TODO: Fix color to fill full square as opposed to line float* color = colors[0]; if (squares[x][y].terrain == TERRAIN_FAIRWAY) { color = colors[1]; } if (squares[x][y].terrain == TERRAIN_ROUGH) { color = colors[2]; } if (squares[x][y].terrain == TERRAIN_GREEN) { color = colors[3]; } glColor3fv(color); glBegin(GL_QUADS); glVertex3f(x, squares[x][y].node_tl->elevation * scale_factor, y); glVertex3f(x + 1, squares[x][y].node_tr->elevation * scale_factor, y); glVertex3f(x + 1, squares[x][y].node_br->elevation * scale_factor, y + 1); glVertex3f(x, squares[x][y].node_bl->elevation * scale_factor, y + 1); glEnd(); } } // draw grid logger("Init grid..."); if (draw_grid) { glColor3f(0.0f, 0.0f, 0.0f); glLineWidth(3.0f); glBegin(GL_LINES); for (int x = 0; x <= MAP_WIDTH - 2; x++) { for (int y = 0; y < MAP_HEIGHT - 2; y++) { glVertex3f(x, squares[x][y].node_tl->elevation * scale_factor, y); glVertex3f(x, squares[x][y + 1].node_tl->elevation * scale_factor, y + 1); } } for (int y = 0; y <= MAP_HEIGHT - 2; y++) { for (int x = 0; x < MAP_WIDTH - 2; x++) { glVertex3f(x, squares[x][y].node_tl->elevation * scale_factor, y); glVertex3f(x + 1, squares[x + 1][y].node_tl->elevation * scale_factor, y); } } // TODO: Draw final column of grid manually } logger("Init end..."); glEnd(); } // Function to initialize nodes Node*** initialize_nodes(int X, int Y) { Node ***nodes = (Node ***)malloc(X * sizeof(Node **)); for (int i = 0; i < X; i++) { nodes[i] = (Node **)malloc(Y * sizeof(Node *)); for (int j = 0; j < Y; j++) { // Allocate memory for each Node nodes[i][j] = (Node *)malloc(sizeof(Node)); nodes[i][j]->x = i; nodes[i][j]->y = j; nodes[i][j]->elevation = 0.0f; } } return nodes; } // Function to initialize squares Square** initialize_squares(Node ***nodes, int X, int Y) { Square **squares = (Square **)malloc((X - 1) * sizeof(Square *)); for (int i = 0; i < X - 1; i++) { squares[i] = (Square *)malloc((Y - 1) * sizeof(Square)); for (int j = 0; j < Y - 1; j++) { // Assign pointers to nodes to create the Square squares[i][j].node_tl = nodes[i][j]; squares[i][j].node_tr = nodes[i+1][j]; squares[i][j].node_bl = nodes[i][j+1]; squares[i][j].node_br = nodes[i+1][j+1]; squares[i][j].terrain = TERRAIN_ROUGH; } } return squares; } // TODO: Move into dedicated cleaner header // Function to free memory allocated for nodes void free_nodes(Node ***nodes, int X, int Y) { for (int i = 0; i < X; i++) { for (int j = 0; j < Y; j++) { free(nodes[i][j]); } free(nodes[i]); } free(nodes); } // TODO: Move into dedicated cleaner header // Function to free memory allocated for squares void free_squares(Square **squares, int X) { for (int i = 0; i < X - 1; i++) { free(squares[i]); } free(squares); } // TODO: Move into controller struct, avoid key rollover void process_input(GLFWwindow* window, Square* square) { if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera_pos_y -= camera_speed; if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera_pos_y += camera_speed; if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera_pos_x -= camera_speed; if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera_pos_x += camera_speed; if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS) debug_spin = !debug_spin; if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS) draw_grid = !draw_grid; if (glfwGetKey(window, GLFW_KEY_G) == GLFW_PRESS) square->terrain = TERRAIN_GREEN; if (glfwGetKey(window, GLFW_KEY_H) == GLFW_PRESS) square->terrain = TERRAIN_FAIRWAY; if (glfwGetKey(window, GLFW_KEY_J) == GLFW_PRESS) square->terrain = TERRAIN_ROUGH; if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) camera_pitch += pitch_speed; if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) camera_pitch -= pitch_speed; if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) camera_yaw -= yaw_speed; if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) camera_yaw += yaw_speed; } int main(int argc, char *argv[]) { logger("Initializing window..."); GLFWwindow* window; // initiate glfw library if (!glfwInit()){ logger("Failed to initiate GLFW."); return -1; } // create glfw window logger("Creating window..."); GLFWmonitor* primary = glfwGetPrimaryMonitor(); const GLFWvidmode* mode = glfwGetVideoMode(primary); window = glfwCreateWindow(mode->width, mode->height, "raycaster", primary, NULL); if (!window){ logger("Failed to create GLFW window."); glfwTerminate(); return -1; } // make window current logger("Making window current..."); glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; GLenum err = glewInit(); if (err != GLEW_OK) { logger("GLEW init error"); return -1; } glEnable(GL_DEPTH_TEST); // init grid and squares logger("Initializing nodes..."); Node ***nodes = initialize_nodes(MAP_WIDTH, MAP_HEIGHT); logger("Initializing squares..."); Square **squares = initialize_squares(nodes, MAP_WIDTH, MAP_HEIGHT); // Debug stuff squares[1][1].node_tl->elevation = 5.0f; change_square_height(&squares[3][3], 5.0f); change_square_height(&squares[5][5], -5.0f); change_square_terrain(&squares[1][6], TERRAIN_FAIRWAY); change_square_terrain(&squares[1][5], TERRAIN_FAIRWAY); change_square_terrain(&squares[1][4], TERRAIN_FAIRWAY); change_square_terrain(&squares[1][3], TERRAIN_GREEN); while (!glfwWindowShouldClose(window)) { logger("Processing input..."); process_input(window, &squares[3][3]); logger("Entering main loop..."); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); logger("Rendering..."); renderHeightMap(squares); glfwSwapBuffers(window); // Swap buffers to display the rendered image if (debug_spin) { camera_yaw = camera_yaw + 0.1f; } // Poll for and process events, wait for events if none are pending glfwWaitEventsTimeout(0.01); // Add a slight delay to reduce CPU usage } logger("Terminating GLFW..."); glfwTerminate(); free_nodes(nodes, MAP_WIDTH, MAP_HEIGHT); free_squares(squares, MAP_WIDTH); return 0; }