diff --git a/assignment-2a/CMakeLists.txt b/assignment-2a/CMakeLists.txt index 6381383..a47137b 100755 --- a/assignment-2a/CMakeLists.txt +++ b/assignment-2a/CMakeLists.txt @@ -2,6 +2,12 @@ cmake_minimum_required (VERSION 3.1) set(CMAKE_CXX_STANDARD 17) +# Create a project called 'HW2a' +project(HW2a) + +# Define in the C++ code what the variable "SRC_DIR" should be equal to the current_path/src +add_definitions( -DSRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}/src" ) + # Generate the `compile_commands.json` file. set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") @@ -10,14 +16,6 @@ if(CMAKE_EXPORT_COMPILE_COMMANDS) ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) endif() -# Create a project called 'HW2a' -project(HW2a) - -# Define in the C++ code what the variable "SRC_DIR" should be equal to the current_path/src -add_definitions( -DSRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}/src" ) - -find_package(spdlog REQUIRED) - # Find OpenGL, and set link library names and include paths find_package(OpenGL REQUIRED) set(OPENGL_LIBRARIES ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY}) @@ -35,16 +33,15 @@ add_subdirectory(ext/glfw) # Make a list of all the source files set( SOURCES - ext/glad/src/glad.c - src/HW2a.cpp - src/controls.cpp - src/util.cpp + + ext/glad/src/glad.c ) # Make a list of all the header files (optional-- only necessary to make them appear in IDE) set( INCLUDES + src/ShaderStuff.hpp ) # Make a list of all of the directories to look in when doing #include "whatever.h" @@ -58,7 +55,6 @@ set( set( LIBS glfw - spdlog::spdlog ${OPENGL_LIBRARIES} ) @@ -74,8 +70,6 @@ include_directories(${INCLUDE_DIRS}) # Equivalent to the "-l" option for g++ target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBS}) -install(TARGETS ${PROJECT_NAME} DESTINATION bin) - # For Visual Studio only if (MSVC) # Do a parallel compilation of this project diff --git a/assignment-2a/src/HW2a.cpp b/assignment-2a/src/HW2a.cpp index 68f81db..a19e5f5 100755 --- a/assignment-2a/src/HW2a.cpp +++ b/assignment-2a/src/HW2a.cpp @@ -2,19 +2,21 @@ // Based on example code from: Interactive Computer Graphics: A Top-Down // Approach with Shader-Based OpenGL (6th Edition), by Ed Angel -#include -#include +#include "GLFW/glfw3.h" +#include "glad/glad.h" #include #include -#include #include #include #include -#include "shaders.h" +#define DEBUG_ON \ + 0 // repetitive of the debug flag in the shader loading code, included here + // for clarity only -#include "controls.h" -#include "util.h" +// This file contains the code that reads the shaders from their files and +// compiles them +#include "ShaderStuff.hpp" //---------------------------------------------------------------------------- @@ -36,44 +38,106 @@ GLint window_width = 500; GLint window_height = 500; GLdouble pi = 4.0 * atan(1.0); -bool is_dragging = false; -bool ctrl_pressed = false; -GLdouble drag_start_x, drag_start_y; - -double figure_x, figure_y, figure_z; - GLFWcursor *hand_cursor, *arrow_cursor; // some different cursors GLint NVERTICES = 9; // part of the hard-coded model +//---------------------------------------------------------------------------- +// function that is called whenever an error occurs +static void error_callback(int error, const char *description) { + fputs(description, stderr); // write the error description to stderr +} + +//---------------------------------------------------------------------------- +// function that is called whenever a keyboard event occurs; defines how +// keyboard input will be handled +static void key_callback(GLFWwindow *window, int key, int scancode, int action, + int mods) { + if (key == GLFW_KEY_ESCAPE && + action == GLFW_PRESS) // checks to see if the escape key was pressed + glfwSetWindowShouldClose(window, GL_TRUE); // closes the window +} + +//---------------------------------------------------------------------------- +// function that is called whenever a mouse or trackpad button press event +// occurs +static void mouse_button_callback(GLFWwindow *window, int button, int action, + int mods) { + glfwGetCursorPos(window, &mouse_x, &mouse_y); + + // Check which mouse button triggered the event, e.g. GLFW_MOUSE_BUTTON_LEFT, + // etc. and what the button action was, e.g. GLFW_PRESS, GLFW_RELEASE, etc. + // (Note that ordinary trackpad click = mouse left button) + // Also check if any modifier keys were active at the time of the button + // press, e.g. GLFW_MOD_ALT, etc. Take the appropriate action, which could + // (optionally) also include changing the cursor's appearance +} + +//---------------------------------------------------------------------------- +// function that is called whenever a cursor motion event occurs +static void cursor_pos_callback(GLFWwindow *window, double xpos, double ypos) { + + // determine the direction of the mouse or cursor motion + // update the current mouse or cursor location + // (necessary to quantify the amount and direction of cursor motion) + // take the appropriate action +} + +//---------------------------------------------------------------------------- + void init(void) { ColorType3D colors[NVERTICES]; FloatType2D vertices[NVERTICES]; GLuint vao[1], buffer, program, location1, location2; - // clang-format off // set up some hard-coded colors and geometry // this part can be customized to read in an object description from a file - colors[0].r = 1; colors[0].g = 1; colors[0].b = 1; // white - colors[1].r = 1; colors[1].g = 0; colors[1].b = 0; // red - colors[2].r = 1; colors[2].g = 0; colors[2].b = 0; // red - colors[3].r = 1; colors[3].g = 1; colors[3].b = 1; // white - colors[4].r = 0; colors[4].g = 0; colors[4].b = 1; // blue - colors[5].r = 0; colors[5].g = 0; colors[5].b = 1; // blue - colors[6].r = 1; colors[6].g = 1; colors[6].b = 1; // white - colors[7].r = 0; colors[7].g = 1; colors[7].b = 1; // cyan - colors[8].r = 0; colors[8].g = 1; colors[8].b = 1; // cyan + colors[0].r = 1; + colors[0].g = 1; + colors[0].b = 1; // white + colors[1].r = 1; + colors[1].g = 0; + colors[1].b = 0; // red + colors[2].r = 1; + colors[2].g = 0; + colors[2].b = 0; // red + colors[3].r = 1; + colors[3].g = 1; + colors[3].b = 1; // white + colors[4].r = 0; + colors[4].g = 0; + colors[4].b = 1; // blue + colors[5].r = 0; + colors[5].g = 0; + colors[5].b = 1; // blue + colors[6].r = 1; + colors[6].g = 1; + colors[6].b = 1; // white + colors[7].r = 0; + colors[7].g = 1; + colors[7].b = 1; // cyan + colors[8].r = 0; + colors[8].g = 1; + colors[8].b = 1; // cyan - vertices[0].x = 0; vertices[0].y = 0.25; // center - vertices[1].x = 0.25; vertices[1].y = 0.5; // upper right - vertices[2].x = -0.25; vertices[2].y = 0.5; // upper left - vertices[3].x = 0; vertices[3].y = 0.25; // center (again) - vertices[4].x = 0.25; vertices[4].y = -0.5; // low-lower right - vertices[5].x = 0.5; vertices[5].y = -0.25; // mid-lower right - vertices[6].x = 0; vertices[6].y = 0.25; // center (again) - vertices[7].x = -0.5; vertices[7].y = -0.25; // low-lower left - vertices[8].x = -0.25; vertices[8].y = -0.5; // mid-lower left - // clang-format on + vertices[0].x = 0; + vertices[0].y = 0.25; // center + vertices[1].x = 0.25; + vertices[1].y = 0.5; // upper right + vertices[2].x = -0.25; + vertices[2].y = 0.5; // upper left + vertices[3].x = 0; + vertices[3].y = 0.25; // center (again) + vertices[4].x = 0.25; + vertices[4].y = -0.5; // low-lower right + vertices[5].x = 0.5; + vertices[5].y = -0.25; // mid-lower right + vertices[6].x = 0; + vertices[6].y = 0.25; // center (again) + vertices[7].x = -0.5; + vertices[7].y = -0.25; // low-lower left + vertices[8].x = -0.25; + vertices[8].y = -0.5; // mid-lower left // Create and bind a vertex array object glGenVertexArrays(1, vao); @@ -89,13 +153,12 @@ void init(void) { glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colors), colors); // Define the names of the shader files - string shader_dir = env("SHADER_DIR").value_or(SRC_DIR); - string vshader = fmt::format("{}/vshader2a.glsl", shader_dir); - string fshader = fmt::format("{}/fshader2a.glsl", shader_dir); - spdlog::info("Shaders from: {}", shader_dir); + std::stringstream vshader, fshader; + vshader << SRC_DIR << "/vshader2a.glsl"; + fshader << SRC_DIR << "/fshader2a.glsl"; // Load the shaders and use the resulting shader program - program = InitShader(vshader.c_str(), fshader.c_str()); + program = InitShader(vshader.str().c_str(), fshader.str().c_str()); // Determine locations of the necessary attributes and matrices used in the // vertex shader @@ -121,7 +184,6 @@ void init(void) { //---------------------------------------------------------------------------- int main(int argc, char **argv) { - spdlog::set_level(spdlog::level::debug); int i; GLFWwindow *window; @@ -159,9 +221,9 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - // tells the system to wait for the rendered frame to finish updating - // before swapping buffers; can help to avoid tearing - glfwSwapInterval(1); + glfwSwapInterval( + 1); // tells the system to wait for the rendered frame to finish updating + // before swapping buffers; can help to avoid tearing // Define the keyboard callback function glfwSetKeyCallback(window, key_callback); @@ -171,7 +233,6 @@ int main(int argc, char **argv) { glfwSetCursorPosCallback(window, cursor_pos_callback); // Create the shaders and perform other one-time initializations - spdlog::info("Initializing..."); init(); // event loop @@ -188,23 +249,21 @@ int main(int argc, char **argv) { } // sanity check that your matrix contents are what you expect them to be - spdlog::debug("M = [{} {} {} {}\n" - " {} {} {} {}\n" - " {} {} {} {}\n" - " {} {} {} {}]\n", - M[0], M[4], M[8], M[12], M[1], M[5], M[9], M[13], M[2], M[6], - M[10], M[14], M[3], M[7], M[11], M[15]); + if (DEBUG_ON) + printf("M = [%f %f %f %f\n %f %f %f %f\n %f %f %f %f\n %f %f " + "%f %f]\n", + M[0], M[4], M[8], M[12], M[1], M[5], M[9], M[13], M[2], M[6], + M[10], M[14], M[3], M[7], M[11], M[15]); - // send the updated model transformation matrix to the GPU - glUniformMatrix4fv(m_location, 1, GL_FALSE, M); - - // draw a triangle between the first vertex and each - // successive vertex pair in the hard-coded model - glDrawArrays(GL_TRIANGLES, 0, NVERTICES); - - // ensure that all OpenGL calls have executed before swapping - // buffers - glFlush(); + glUniformMatrix4fv( + m_location, 1, GL_FALSE, + M); // send the updated model transformation matrix to the GPU + glDrawArrays( + GL_TRIANGLES, 0, + NVERTICES); // draw a triangle between the first vertex and each + // successive vertex pair in the hard-coded model + glFlush(); // ensure that all OpenGL calls have executed before swapping + // buffers glfwSwapBuffers(window); // swap buffers glfwWaitEvents(); // wait for a new event before re-drawing diff --git a/assignment-2a/src/ShaderStuff.hpp b/assignment-2a/src/ShaderStuff.hpp new file mode 100755 index 000000000..17ed123 --- /dev/null +++ b/assignment-2a/src/ShaderStuff.hpp @@ -0,0 +1,141 @@ +// Basic OpenGL program +// Based on example code from: Interactive Computer Graphics: A Top-Down Approach with Shader-Based OpenGL (6th Edition), by Ed Angel + +#ifndef SHADERSTUFF +#define SHADERSTUFF 1 + +#define DEBUG_ON 0 +#define BUFFER_OFFSET(bytes) ((GLvoid*) (bytes)) + +// Create a NULL-terminated string by reading the provided file +static char* +readShaderSource(const char* shaderFile) +{ + FILE *fp; + long length, count; + char *buffer; + // struct stat fileinfo; + + // open the file containing the text of the shader code + fp = fopen(shaderFile, "rb"); + + // check for errors in opening the file + if ( fp == NULL ) { + printf("can't open shader source file %s\n", shaderFile); + return NULL; + } + + // determine the file size + fseek(fp, 0, SEEK_END); // move position indicator to the end of the file; + length = ftell(fp); // return the value of the current position + if (DEBUG_ON) fprintf(stdout, "length in bytes of shader file: %ld\n", length); + + // allocate a buffer with the indicated number of bytes, plus one + buffer = new char[length + 1]; + + // read the appropriate number of bytes from the file + fseek(fp, 0, SEEK_SET); // move position indicator to the start of the file + count = fread(buffer, 1, length, fp); // read all of the bytes + if (DEBUG_ON) fprintf(stdout, "count of bytes successfully read: %ld\n", count); + + // append a NULL character to indicate the end of the string + buffer[count] = '\0'; //because on some systems, count != length + + // close the file + fclose(fp); + + // return the string + return buffer; +} + +// Create a GLSL program object from vertex and fragment shader files +GLuint +InitShader(const char* vShaderFileName, const char* fShaderFileName) +{ + GLuint vertex_shader, fragment_shader; + GLuint program; + + // check GLSL version + if (DEBUG_ON) printf("GLSL version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); + + // Create shader handlers + vertex_shader = glCreateShader(GL_VERTEX_SHADER); + fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + + // Read source code from file + std::string vs_text = readShaderSource(vShaderFileName); + std::string fs_text = readShaderSource(fShaderFileName); + + // error check + if ( vs_text == "" ) { + printf("Failed to read from vertex shader file %s\n", vShaderFileName); + exit( 1 ); + } else if (DEBUG_ON) { + printf("read shader code:\n%s\n", vs_text.c_str()); + } + if ( fs_text == "" ) { + printf("Failed to read from fragment shader file %s\n", fShaderFileName); + exit( 1 ); + } else if (DEBUG_ON) { + printf("read shader code:\n%s\n", fs_text.c_str()); + } + + // Set shader source + const char *vv = vs_text.c_str(); + const char *ff = fs_text.c_str(); + glShaderSource(vertex_shader, 1, &vv, NULL); + glShaderSource(fragment_shader, 1, &ff, NULL); + + // Compile shaders + glCompileShader(vertex_shader); + glCompileShader(fragment_shader); + + // Check for errors in compiling shaders + GLint compiled; + glGetShaderiv( vertex_shader, GL_COMPILE_STATUS, &compiled ); + if ( !compiled ) { + printf("vertex_shader failed to compile\n"); + if (DEBUG_ON) { + GLint logMaxSize, logLength; + glGetShaderiv( vertex_shader, GL_INFO_LOG_LENGTH, &logMaxSize ); + printf("printing error message of %d bytes\n", logMaxSize); + char* logMsg = new char[logMaxSize]; + glGetShaderInfoLog( vertex_shader, logMaxSize, &logLength, logMsg ); + printf("%d bytes retrieved\n", logLength); + printf("error message: %s\n", logMsg); + delete[] logMsg; + } + exit(1); + } + glGetShaderiv( fragment_shader, GL_COMPILE_STATUS, &compiled ); + if ( !compiled ) { + printf("fragment_shader failed to compile\n"); + if (DEBUG_ON) { + GLint logMaxSize, logLength; + glGetShaderiv( fragment_shader, GL_INFO_LOG_LENGTH, &logMaxSize ); + printf("printing error message of %d bytes\n", logMaxSize); + char* logMsg = new char[logMaxSize]; + glGetShaderInfoLog( fragment_shader, logMaxSize, &logLength, logMsg ); + printf("%d bytes retrieved\n", logLength); + printf("error message: %s\n", logMsg); + delete[] logMsg; + } + exit(1); + } + + // Create the program + program = glCreateProgram(); + + // Attach shaders to program + glAttachShader(program, vertex_shader); + glAttachShader(program, fragment_shader); + + // Link and set program to use + glLinkProgram(program); + glUseProgram(program); + + return program; +} + + +#endif diff --git a/assignment-2a/src/fshader2a.glsl b/assignment-2a/src/fshader2a.glsl index 75e4086..8b31a19 100755 --- a/assignment-2a/src/fshader2a.glsl +++ b/assignment-2a/src/fshader2a.glsl @@ -3,7 +3,7 @@ #version 150 in vec4 vcolor; out vec4 color; - -void main() { - color = vcolor; // set output color to interpolated color from vshader -} +void main() +{ + color = vcolor; // set output color to interpolated color from vshader +} \ No newline at end of file diff --git a/assignment-2a/src/state.cpp b/assignment-2a/src/state.cpp index e69de29..16863f0 100644 --- a/assignment-2a/src/state.cpp +++ b/assignment-2a/src/state.cpp @@ -0,0 +1,21 @@ +#include "state.h" + +void State::populate_matrix(GLfloat *matrix) { + // 0 1 2 3 + // 4 5 6 7 + // 8 9 10 11 + // 12 13 14 15 + + matrix[0] = this->x_scale; + matrix[5] = this->y_scale; + matrix[10] = 1.0; + matrix[15] = 1.0; + + /* + for (int i = 0; i < 16; i++) { + matrix[i] = (i % 5 == 0); + } + */ +} + +void State::start_dragging(pii at) { this->drag_start = at; } diff --git a/assignment-2a/src/state.h b/assignment-2a/src/state.h index 235c490..d699570 100644 --- a/assignment-2a/src/state.h +++ b/assignment-2a/src/state.h @@ -6,8 +6,12 @@ using namespace std; +#include "GLFW/glfw3.h" + typedef pair pii; +const double X_DELTA = 0.1, Y_DELTA = 0.1; + /// The state of the program struct State { pii mouse; @@ -18,6 +22,12 @@ struct State { /// Scaling factors double x_scale = 1.0; double y_scale = 1.0; + + void populate_matrix(GLfloat *matrix); + void start_dragging(pii at); + +private: + GLfloat M[16]; }; #endif diff --git a/assignment-2a/src/vshader2a.glsl b/assignment-2a/src/vshader2a.glsl index ee0ebc3..d49e2a0 100755 --- a/assignment-2a/src/vshader2a.glsl +++ b/assignment-2a/src/vshader2a.glsl @@ -6,7 +6,7 @@ in vec4 vertex_color; out vec4 vcolor; uniform mat4 M; -void main() { - gl_Position = M * vertex_position; // update vertex position using M - vcolor = vertex_color; // pass vertex color to fragment shader -} +void main() { + gl_Position = M*vertex_position; // update vertex position using M + vcolor = vertex_color; // pass vertex color to fragment shader +} \ No newline at end of file