// glad and GLFW #include #include // glm math #include #include #include #include #include #include #include #include #define VERTEX_FILE "./shaders/vertex.glsl" #define FRAGMENT_FILE "./shaders/fragment.glsl" #define COMPUTE_FILE "./shaders/compute.glsl" const float SCR_WIDTH = 1200.0f; const float SCR_HEIGHT = 1200.0f; // Shader loader helper std::string loadShaderSource(const std::string& filepath) { std::ifstream file(filepath); if (!file.is_open()) { std::cerr << "Failed to open shader file: " << filepath << std::endl; return ""; } std::stringstream buffer; std::cout << "Loaded " << filepath << " successfully!\n"; buffer << file.rdbuf(); return buffer.str(); } GLuint compileShader(GLenum type, const std::string& source) { GLuint shader = glCreateShader(type); const char* src = source.c_str(); glShaderSource(shader, 1, &src, nullptr); glCompileShader(shader); int success; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { char infoLog[512]; glGetShaderInfoLog(shader, 512, nullptr, infoLog); std::cerr << "Shader compilation failed:\n" << infoLog << std::endl; exit(10); } return shader; } GLuint createShaderProgram(const std::string& vertexPath, const std::string& fragmentPath) { std::string vertexSrc = loadShaderSource(vertexPath); std::string fragmentSrc = loadShaderSource(fragmentPath); GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSrc); GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSrc); GLuint program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); glLinkProgram(program); int success; glGetProgramiv(program, GL_LINK_STATUS, &success); if (!success) { char infoLog[512]; glGetProgramInfoLog(program, 512, nullptr, infoLog); std::cerr << "Shader linking failed:\n" << infoLog << std::endl; exit(11); } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); return program; } GLuint createComputeProgram(const std::string& computePath) { std::string computeSrc = loadShaderSource(computePath); GLuint computeShader = compileShader(GL_COMPUTE_SHADER, computeSrc); GLuint program = glCreateProgram(); glAttachShader(program, computeShader); glLinkProgram(program); int success; glGetProgramiv(program, GL_LINK_STATUS, &success); if (!success) { char infoLog[512]; glGetProgramInfoLog(program, 512, nullptr, infoLog); std::cerr << "Compute shader linking failed:\n" << infoLog << std::endl;; } glDeleteShader(computeShader); return program; } int main() { // Initialize GLFW if (!glfwInit()) return -1; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // REQUIRED on macOS glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_SAMPLES, 16); // 16x MSAA GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenGL Template", nullptr, nullptr); if (!window) { glfwTerminate(); return -1; } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cerr << "Failed to initialize GLAD\n"; return -1; } glViewport(0, 0, (int)SCR_WIDTH, (int)SCR_HEIGHT); //DEBUG std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl; // ERROR: macOS does not support compute shaders in OpenGL < 4.3. // GLuint computeProgram = createComputeProgram(COMPUTE_FILE); // ----- Vertex Data ----- // Cube // Positions float vertices[] = { // positions -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f }; unsigned int indices[] = { 0, 1, 2, 2, 3, 0 }; GLuint VAO, VBO, EBO; glGenVertexArrays(1,&VAO); glGenBuffers(1,&VBO); glGenBuffers(1,&EBO); glBindVertexArray(VAO); 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); // position - VERTEX SHADER glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0); glEnableVertexAttribArray(0); // color - FRAGMENT SHADER glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)(3*sizeof(float))); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER,0); // glBindVertexArray(0); // Load shaders GLuint shaderProgram = createShaderProgram(VERTEX_FILE, FRAGMENT_FILE); // Check if shader program was created successfully if (shaderProgram == 0) { std::cerr << "Failed to create shader programs.\n"; return -1; } // Caulculate model, view, projection matrices glm::mat4 model = glm::mat4(1.0f); glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -1.0f)); glm::mat4 projection = glm::perspective(glm::radians(45.0f), SCR_WIDTH/SCR_HEIGHT, 0.1f, 100.0f); GLuint modelLoc = glGetUniformLocation(shaderProgram, "model"); GLuint viewLoc = glGetUniformLocation(shaderProgram, "view"); GLuint projLoc = glGetUniformLocation(shaderProgram, "projection"); glUseProgram(shaderProgram); 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(projection)); GLint resLoc = glGetUniformLocation(shaderProgram, "u_resolution"); glUniform2f(resLoc, SCR_WIDTH, SCR_HEIGHT); // hardcode for now GLint timeLoc = glGetUniformLocation(shaderProgram, "u_time"); GLint directionLoc = glGetUniformLocation(shaderProgram, "u_direction"); GLint oscilationLoc = glGetUniformLocation(shaderProgram, "u_oscilator"); glEnable(GL_MULTISAMPLE); float oscillation = 5.0f; // Render loop while (!glfwWindowShouldClose(window)) { static float direction = 1.0f; static int frameCount = 0; static unsigned char invert = 0; float timeValue = (float)glfwGetTime(); // Input glfwPollEvents(); if (frameCount++ % 24 == 0) { if (oscillation > 40) invert = 1; if (oscillation < 5) invert = 0; if (invert) oscillation -= 0.001; else oscillation += 0.001; // Debug std::cout << "Oscillation: " << oscillation << "\t"; std::cout << "Invert: " << invert << std::endl; direction = rand() % 50; // change direction every 300 frames } glUniform1f(timeLoc, timeValue); glUniform1f(directionLoc, direction); glUniform1f(oscilationLoc, oscillation); glClearColor(0.01f, 0.01f, 0.01f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); glUseProgram(shaderProgram); // Move WASD if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) view = glm::translate(view, glm::vec3(0.0f, 0.01f, 0.0f)); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) view = glm::translate(view, glm::vec3(0.0f, -0.01f, 0.0f)); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) view = glm::translate(view, glm::vec3(-0.01f, 0.0f, 0.0f)); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) view = glm::translate(view, glm::vec3(0.01f, 0.0f, 0.0f)); // QE rotate if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) view = glm::rotate(view, glm::radians(1.0f), glm::vec3(0.0f, 0.0f, 1.0f)); if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) view = glm::rotate(view, glm::radians(-1.0f), glm::vec3(0.0f, 0.0f, 1.0f)); glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glfwSwapBuffers(window); } glDeleteVertexArrays(1,&VAO); glDeleteBuffers(1,&VBO); glDeleteBuffers(1,&EBO); glDeleteProgram(shaderProgram); glfwDestroyWindow(window); glfwTerminate(); return 0; }