├── lib └── libglsl.so ├── glslutil ├── ShaderIF.o ├── libglsl.so ├── Makefile ├── MakefileMac ├── ShaderIF.h └── ShaderIF.c++ ├── smiley_version1.png ├── smiley_version2.png ├── project1 ├── shaders │ ├── project1.fsh │ └── project1.vsh ├── Project1_SampleData.txt ├── Makefile ├── ModelView.h ├── main.c++ └── ModelView.c++ ├── README.md └── mvcutil ├── GLFWController.h ├── Controller.h ├── GLFWController.c++ └── Controller.c++ /lib/libglsl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/opengl-two-smiley-faces/master/lib/libglsl.so -------------------------------------------------------------------------------- /glslutil/ShaderIF.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/opengl-two-smiley-faces/master/glslutil/ShaderIF.o -------------------------------------------------------------------------------- /glslutil/libglsl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/opengl-two-smiley-faces/master/glslutil/libglsl.so -------------------------------------------------------------------------------- /smiley_version1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/opengl-two-smiley-faces/master/smiley_version1.png -------------------------------------------------------------------------------- /smiley_version2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/opengl-two-smiley-faces/master/smiley_version2.png -------------------------------------------------------------------------------- /project1/shaders/project1.fsh: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | // Complete the placeholder implementation here... 4 | uniform vec3 color; 5 | out vec4 fragmentColor; 6 | 7 | void main() 8 | { 9 | fragmentColor = vec4(color, 1.0); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /project1/Project1_SampleData.txt: -------------------------------------------------------------------------------- 1 | 6 50 2 | 0 0 20 0 20 40 -20 40 -20 0 0 0 3 | 3 10 5 15 6.5 17.5 8 15 4 | 3 10 5 15 6.5 16.5 8 15 5 | 3 10 -5 15 -6.5 17.5 -8 15 6 | 3 10 -5 15 -6.5 16.5 -8 15 7 | 3 10 -2 11 0 9 2 11 8 | 4 60 9 | -6 6 -3 2 3 2 6 6 10 | 4 60 11 | -6 6 -3 0.5 3 0.5 6 6 -------------------------------------------------------------------------------- /glslutil/Makefile: -------------------------------------------------------------------------------- 1 | CPP = g++ -std=c++11 2 | C_FLAGS = -fPIC -O -c -DGL_GLEXT_PROTOTYPES 3 | 4 | LINK = g++ -fPIC 5 | 6 | OBJS = ShaderIF.o 7 | 8 | libglsl.so: $(OBJS) 9 | $(LINK) -shared -o libglsl.so $(OBJS) 10 | cp libglsl.so ../lib/ 11 | 12 | ShaderIF.o: ShaderIF.h ShaderIF.c++ 13 | $(CPP) $(C_FLAGS) ShaderIF.c++ 14 | -------------------------------------------------------------------------------- /glslutil/MakefileMac: -------------------------------------------------------------------------------- 1 | CPP = g++ -std=c++11 2 | C_FLAGS = -I/usr/local/include -fPIC -g -c -DGLFW_INCLUDE_GLEXT -DGLFW_INCLUDE_GLCOREARB -DGL_SILENCE_DEPRECATION 3 | 4 | LINK = g++ -fPIC 5 | 6 | OBJS = ShaderIF.o 7 | 8 | libglsl.so: $(OBJS) 9 | $(LINK) -shared -o libglsl.so $(OBJS) -framework OpenGL 10 | cp libglsl.so ../lib/ 11 | 12 | ShaderIF.o: ShaderIF.h ShaderIF.c++ 13 | $(CPP) $(C_FLAGS) ShaderIF.c++ 14 | -------------------------------------------------------------------------------- /project1/shaders/project1.vsh: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | // Complete the placeholder implementation here 4 | in vec2 mcPosition; // vertex position 5 | uniform vec4 scaleTrans; // for mapping coordinates into Logical Device Space 6 | 7 | void main() 8 | { 9 | // ldsX = sx * mcX + tx 10 | float ldsX = scaleTrans[0]*mcPosition.x + scaleTrans[1]; 11 | 12 | // ldsY = sy * mcY + ty 13 | float ldsY = scaleTrans[2]*mcPosition.y + scaleTrans[3]; 14 | 15 | gl_Position = vec4(ldsX, ldsY, 0, 1); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenGL Two Smiley Faces 2 | 3 | This is my first OpenGL project. When the program runs, you will be able to switch between two different views to see two different versions of a smiley face. 4 | 5 | ## How to Run Program in Terminal 6 | 7 | 1. Clone or download the repo 8 | 2. Inside project1 folder, run `make` command 9 | 3. Type `./main Project1_SampleData.txt` 10 | 4. Press `n` to view n points and `m` to view m points 11 | 12 | ## What it Looks Like 13 | 14 | Here are the two smiley faces you can view. Press `n` to view the first one and `m` to view the second one. 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /project1/Makefile: -------------------------------------------------------------------------------- 1 | CPP = g++ -std=c++11 2 | INC = -I../glslutil -I../mvcutil -I/usr/local/include -I. 3 | 4 | # >>> FOR LINUX, uncomment next few lines; comment out the MAC ones. 5 | C_FLAGS = -fPIC -g -c $(INC) -DGL_GLEXT_PROTOTYPES 6 | GL_LIB_LOC = -L/usr/lib/nvidia-375 7 | GL_LIBRARIES = $(GL_LIB_LOC) -lglfw -lGLU -lGL 8 | MAKE = make 9 | # >>> FOR MAC, uncomment next few lines; comment out previous linux ones. 10 | # C_FLAGS = -fPIC -g -c $(INC) -DGLFW_INCLUDE_GLEXT -DGLFW_INCLUDE_GLCOREARB -DGL_SILENCE_DEPRECATION 11 | # GL_LIBRARIES = -L/usr/local/lib -lglfw -framework OpenGL 12 | # MAKE = make -f MakefileMac 13 | # >>> END: FOR LINUX - FOR MAC 14 | 15 | LINK = g++ -fPIC -g 16 | LOCAL_UTIL_LIBRARIES = ../lib/libglsl.so 17 | 18 | OBJS = main.o ModelView.o Controller.o GLFWController.o 19 | 20 | main: $(OBJS) $(LOCAL_UTIL_LIBRARIES) 21 | $(LINK) -o main $(OBJS) $(LOCAL_UTIL_LIBRARIES) $(GL_LIBRARIES) 22 | 23 | ../lib/libglsl.so: ../glslutil/ShaderIF.h ../glslutil/ShaderIF.c++ 24 | (cd ../glslutil; $(MAKE)) 25 | 26 | main.o: main.c++ 27 | $(CPP) $(C_FLAGS) main.c++ 28 | ModelView.o: ModelView.h ModelView.c++ 29 | $(CPP) $(C_FLAGS) ModelView.c++ 30 | Controller.o: ../mvcutil/Controller.h ../mvcutil/Controller.c++ 31 | $(CPP) $(C_FLAGS) -DGLFW_INCLUDE_GLU ../mvcutil/Controller.c++ 32 | GLFWController.o: ../mvcutil/GLFWController.h ../mvcutil/GLFWController.c++ 33 | $(CPP) $(C_FLAGS) ../mvcutil/GLFWController.c++ 34 | -------------------------------------------------------------------------------- /mvcutil/GLFWController.h: -------------------------------------------------------------------------------- 1 | // GLFWController.h - A concrete Controller subclass using the GLFW window interface 2 | 3 | #ifndef GLFWCONTROLLER_H 4 | #define GLFWCONTROLLER_H 5 | 6 | #include "GLFW/glfw3.h" 7 | 8 | #include "Controller.h" 9 | 10 | class GLFWController : public Controller 11 | { 12 | public: 13 | GLFWController(const std::string& windowTitle, int rcFlags = 0); 14 | virtual ~GLFWController(); 15 | 16 | void run(); 17 | void setRunWaitsForAnEvent(bool b) { runWaitsForAnEvent = b;} 18 | void setWindowTitle(const std::string& title); 19 | 20 | protected: 21 | GLFWController(const GLFWController& c) : Controller(c) {} 22 | 23 | virtual void handleDisplay(); 24 | void initializeCallbacksForRC(); 25 | void prepareWindow() const; 26 | void reportWindowInterfaceVersion(std::ostream& os) const; 27 | void swapBuffers() const { glfwSwapBuffers(theWindow); } 28 | 29 | GLFWwindow* theWindow; 30 | private: 31 | bool returnFromRun, runWaitsForAnEvent; 32 | int lastPixelPosX, lastPixelPosY; 33 | 34 | void createWindowAndRC(const std::string& windowTitle, int rcFlags); 35 | 36 | static int numGLFWControllers; 37 | 38 | static void charCB(GLFWwindow* window, unsigned int theChar); 39 | static void keyboardCB(GLFWwindow* window, int key, int scanCode, int action, int mods); 40 | static void mouseMotionCB(GLFWwindow* window, double x, double y); 41 | static void reshapeCB(GLFWwindow* window, int width, int height); 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /mvcutil/Controller.h: -------------------------------------------------------------------------------- 1 | // Controller.h - An Abstract base Class for a Controller (in Model-View-Controller sense) 2 | 3 | #ifndef CONTROLLER_H 4 | #define CONTROLLER_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class ModelView; 12 | 13 | class Controller 14 | { 15 | public: 16 | Controller(); 17 | virtual ~Controller(); 18 | 19 | void addModel(ModelView* m); 20 | void getOverallMCBoundingBox(double* xyzLimits) const; 21 | double getViewportAspectRatio() const; // height/width 22 | virtual void redraw() {} // to force a display update 23 | void reportVersions(std::ostream& os) const; 24 | virtual void run() = 0; 25 | virtual void setWindowTitle(const std::string& title) = 0; 26 | 27 | static bool checkForErrors(std::ostream& os, const std::string& context); 28 | static Controller* getCurrentController() { return curController; } 29 | static void setNewWindowSize(int width, int height); 30 | 31 | protected: 32 | Controller(const Controller& c) {} 33 | std::vector models; 34 | 35 | // Virtual methods for event handling (any can be overridden) 36 | // --> Keyboard-related event handling 37 | virtual void handleAsciiChar(unsigned char theChar, int x, int y); 38 | 39 | // --> Window-related event handling 40 | virtual void handleReshape(int width, int height); 41 | 42 | // --> Miscellaneous 43 | virtual void endProgram() { exit(0); } 44 | void pixelPointToLDSPoint(int x, int y, double& ldsX, double& ldsY); 45 | void pixelVectorToLDSVector(int dx, int dy, double& ldsDX, double& ldsDY); 46 | virtual void renderAllModels(); 47 | virtual void reportWindowInterfaceVersion(std::ostream& os) const = 0; 48 | virtual void swapBuffers() const = 0; 49 | 50 | // Data the Controller uses to track the overall MC box bounding all models. 51 | double overallMCBoundingBox[6]; 52 | int glClearFlags; 53 | 54 | static Controller* curController; 55 | static int newWindowWidth, newWindowHeight; 56 | static std::string titleString(const std::string& str); 57 | 58 | private: 59 | void updateMCBoundingBox(ModelView* m); 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /glslutil/ShaderIF.h: -------------------------------------------------------------------------------- 1 | // ShaderIF.h: Basic interface to read, compile, and link GLSL Shader programs 2 | 3 | #ifndef SHADERIF_H 4 | #define SHADERIF_H 5 | 6 | #ifdef __APPLE_CC__ 7 | #include "GLFW/glfw3.h" 8 | #else 9 | #include 10 | #endif 11 | 12 | #include 13 | 14 | class ShaderIF 15 | { 16 | public: 17 | struct ShaderSpec 18 | { 19 | std::string fName; 20 | GLenum sType; 21 | }; 22 | // Creating and managing shader programs: 23 | // Create an instance with one of the following two constructors 24 | // and use the getShaderPgmID() method to get the shader program ID. 25 | // For example: 26 | // ShaderIF* sIF = new ShaderIF("MyShader.vsh", "MyShader.fsh"); 27 | // int pgmId = sIF->getShaderPgmID(); 28 | // Implementation note for android deviecs: note that the Rendering 29 | // Context (including, but not limited to GLSL shader programs) is 30 | // sometimes destroyed while your program is running, most notably 31 | // whenever the device is rotated, the "home" key pressed, etc. When 32 | // this happens, you must be prepared to recognize that the shader 33 | // program must be recreated. 34 | ShaderIF(const std::string& vShader, const std::string& fShader); 35 | ShaderIF(const ShaderSpec* shaders, int nShaders); 36 | virtual ~ShaderIF(); 37 | int getShaderPgmID() const { return shaderPgm; } 38 | 39 | // Lookup routines for per-vertex and per-primitive (uniform) variables: 40 | GLint ppuExists(const std::string& name); // per-primitive (uniform) 41 | GLint ppuLoc(const std::string& name); // per-primitive (uniform) 42 | GLint pvaExists(const std::string& name); // per-vertex attribute 43 | GLint pvaLoc(const std::string& name); // per-vertex attribute 44 | private: 45 | struct Shader 46 | { 47 | std::string fName; 48 | GLenum sType; 49 | std::string source; 50 | int pgmID; 51 | 52 | Shader(): fName(""), sType(0), source(""), pgmID(0) {} 53 | }; 54 | void destroy(); 55 | void initShaders(); 56 | 57 | static bool readShaderSource(Shader& shader); 58 | 59 | int shaderPgm; 60 | int numShaderComponents; 61 | Shader* shaders; 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /project1/ModelView.h: -------------------------------------------------------------------------------- 1 | // ModelView.h - a basic combined Model and View for OpenGL 2 | 3 | #ifndef MODELVIEW_H 4 | #define MODELVIEW_H 5 | 6 | #include "ShaderIF.h" 7 | 8 | #include 9 | 10 | #ifdef __APPLE_CC__ 11 | #include "GLFW/glfw3.h" 12 | #else 13 | #include 14 | #endif 15 | 16 | // for interfacing to common GLSL data types 17 | typedef float vec2[2]; 18 | typedef float vec3[3]; 19 | 20 | class ModelView 21 | { 22 | public: 23 | ModelView(ShaderIF* sIF, vec2* nVertexPositions, int nPoints, int mPoints, vec2* mVertexPositions); 24 | virtual ~ModelView(); 25 | 26 | // xyzLimits: {mcXmin, mcXmax, mcYmin, mcYmax, mcZmin, mcZmax} 27 | void getMCBoundingBox(double* xyzLimits) const; 28 | bool handleCommand(unsigned char anASCIIChar, double ldsX, double ldsY); 29 | void render() const; 30 | 31 | // viewing controls common to 2D and 3D 32 | static void setAspectRatioPreservationEnabled(bool b) 33 | { aspectRatioPreservationEnabled = b; } 34 | static void setMCRegionOfInterest(double xyz[6]); 35 | 36 | private: 37 | GLuint vao[2]; 38 | GLuint vbo[2]; 39 | int nTotalPoints; 40 | int mTotalPoints; 41 | float xmin, xmax, ymin, ymax; 42 | vec3 nColor; 43 | vec3 mColor; 44 | 45 | ShaderIF* shaderIF; 46 | 47 | void deleteObject(); 48 | 49 | void initModelGeometry(vec2* nVertexPositions, vec2* mVertexPositions); 50 | 51 | // Routines for computing parameters necessary to map from arbitrary 52 | // model coordinate ranges into OpenGL's -1..+1 Logical Device Space. 53 | // 1. linearMap determines the scale and translate parameters needed in 54 | // order to map a value, f (fromMin <= f <= fromMax) to its corresponding 55 | // value, t (toMin <= t <= toMax). Specifically: t = scale*f + trans. 56 | static void linearMap(double fromMin, double fromMax, 57 | double toMin, double toMax, double& scale, double& trans); 58 | // 2. matchAspectRatio modifies (xmin,xmax) OR (ymin,ymax) to center that 59 | // region in an expanded window that matches the given aspect ratio. 60 | static void matchAspectRatio(double& xmin, double& xmax, 61 | double& ymin, double& ymax, double vAR); 62 | // 3. compute2DScaleTrans uses the current model coordinate region of 63 | // interest - modified as necessary to preserve aspect ratios - and 64 | // then passes the modified limits to linearMap to compute the scale 65 | // and translation needed to map MC to LDS. 66 | // (The scales and translationes are returned in float[] because 67 | // glUniform currently allows only float[].) 68 | static void compute2DScaleTrans(float* scaleTrans); 69 | 70 | static double mcRegionOfInterest[6]; 71 | static bool aspectRatioPreservationEnabled; 72 | }; 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /project1/main.c++: -------------------------------------------------------------------------------- 1 | // main.c++ 2 | 3 | #include "GLFWController.h" 4 | #include "ModelView.h" 5 | #include 6 | #include 7 | 8 | void createScene(GLFWController& c, ShaderIF* sIF, float xValues[], float yValues[], int totalNPoints, int totalMPoints) 9 | { 10 | float dt = 1.0 / (totalMPoints - 1); 11 | vec2 nVertexPositions[totalNPoints]; 12 | vec2 buf[totalNPoints]; 13 | vec2* mVertexPositions = new vec2[totalMPoints]; 14 | float t; 15 | 16 | for (int i = 0; i < totalNPoints; i++) 17 | { 18 | nVertexPositions[i][0] = xValues[i]; 19 | nVertexPositions[i][1] = yValues[i]; 20 | } 21 | 22 | for (int i = 0; i < totalMPoints; i++) 23 | { 24 | for (int a = 0; a < totalNPoints; a++) 25 | { 26 | buf[a][0] = nVertexPositions[a][0]; 27 | buf[a][1] = nVertexPositions[a][1]; 28 | } 29 | 30 | t = i * dt; 31 | for (int j = 0; j <= totalNPoints - 2; j++) 32 | { 33 | for (int k = 0; k <= totalNPoints - j - 2; k++) 34 | { 35 | buf[k][0] = (1 - t) * buf[k][0] + t * buf[k + 1][0]; 36 | buf[k][1] = (1 - t) * buf[k][1] + t * buf[k + 1][1]; 37 | } 38 | } 39 | // i-th point for the VBO is now in buf[0] 40 | mVertexPositions[i][0] = buf[0][0]; 41 | mVertexPositions[i][1] = buf[0][1]; 42 | } 43 | 44 | c.addModel(new ModelView(sIF, nVertexPositions, totalNPoints, totalMPoints, mVertexPositions)); 45 | } 46 | 47 | int main(int argc, char* argv[]) 48 | { 49 | GLFWController c(argv[0]); 50 | c.reportVersions(std::cout); 51 | 52 | ShaderIF* sIF = new ShaderIF("shaders/project1.vsh", "shaders/project1.fsh"); 53 | 54 | int totalNPoints = 0; 55 | int totalMPoints = 0; 56 | 57 | std::ifstream userFileChoice; 58 | std::string fileName = argv[1]; 59 | userFileChoice.open(fileName); 60 | if(!userFileChoice.is_open()) 61 | { 62 | std::cout << "Failed to open file. File was not found.\n"; 63 | exit(1); 64 | } 65 | while (!userFileChoice.eof()) 66 | { 67 | userFileChoice >> totalNPoints; 68 | userFileChoice >> totalMPoints; 69 | float xValues[totalNPoints]; 70 | float yValues[totalNPoints]; 71 | 72 | for (int i = 0; i < totalNPoints; i++) 73 | { 74 | userFileChoice >> xValues[i]; 75 | userFileChoice >> yValues[i]; 76 | } 77 | 78 | createScene(c, sIF, xValues, yValues, totalNPoints, totalMPoints); 79 | } 80 | 81 | // initialize 2D viewing information: 82 | // Get the overall scene bounding box in Model Coordinates: 83 | double xyz[6]; // xyz limits, even though this is 2D 84 | c.getOverallMCBoundingBox(xyz); 85 | std::cout << "Bounding box: " << xyz[0] << " <= x <= " << xyz[1] << '\n'; 86 | std::cout << " " << xyz[2] << " <= y <= " << xyz[3] << '\n'; 87 | std::cout << " " << xyz[4] << " <= z <= " << xyz[5] << "\n\n"; 88 | // Tell class ModelView we initially want to see the whole scene: 89 | ModelView::setMCRegionOfInterest(xyz); 90 | 91 | glClearColor(1.0, 1.0, 1.0, 1.0); 92 | c.run(); 93 | 94 | delete sIF; 95 | userFileChoice.close(); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /mvcutil/GLFWController.c++: -------------------------------------------------------------------------------- 1 | // GLFWController.c++: a basic GLFWController (in Model-View-GLFWController sense) 2 | 3 | #include 4 | 5 | #include "GLFWController.h" 6 | #include "ModelView.h" 7 | 8 | int GLFWController::numGLFWControllers = 0; 9 | 10 | GLFWController::GLFWController(const std::string& windowTitle, int rcFlags) : 11 | theWindow(nullptr), 12 | returnFromRun(false), runWaitsForAnEvent(true), 13 | lastPixelPosX(0), lastPixelPosY(0) 14 | { 15 | if (numGLFWControllers++ == 0) 16 | glfwInit(); 17 | 18 | // First create the window and its Rendering Context (RC) 19 | createWindowAndRC(windowTitle, rcFlags); 20 | } 21 | 22 | GLFWController::~GLFWController() 23 | { 24 | if (theWindow != nullptr) 25 | glfwDestroyWindow(theWindow); 26 | 27 | if (--numGLFWControllers == 0) 28 | glfwTerminate(); 29 | } 30 | 31 | void GLFWController::charCB(GLFWwindow* window, unsigned int theChar) 32 | { 33 | if (theChar < 128) 34 | { 35 | GLFWController* c = dynamic_cast(curController); 36 | c->handleAsciiChar( 37 | static_cast(theChar), c->lastPixelPosX, c->lastPixelPosY); 38 | } 39 | } 40 | 41 | void GLFWController::createWindowAndRC(const std::string& windowTitle, int rcFlags) 42 | { 43 | // The following calls enforce use of only non-deprecated functionality. 44 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 45 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 46 | 47 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); 48 | int minor = 8; // Start AT LEAST one greater than where you really want to start 49 | while ((theWindow == nullptr) && (minor > 0)) 50 | { 51 | minor--; 52 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor); 53 | theWindow = glfwCreateWindow(newWindowWidth, newWindowHeight, titleString(windowTitle).c_str(), nullptr, nullptr); 54 | } 55 | if (theWindow == nullptr) 56 | { 57 | std::cerr << "\n**** COULD NOT CREATE A 4.x RENDERING CONTEXT ****\n\n"; 58 | return; 59 | } 60 | 61 | glfwMakeContextCurrent(theWindow); 62 | initializeCallbacksForRC(); 63 | } 64 | 65 | void GLFWController::handleDisplay() 66 | { 67 | prepareWindow(); 68 | // clear the frame buffer 69 | glClear(glClearFlags); 70 | 71 | renderAllModels(); 72 | 73 | glfwSwapBuffers(theWindow); 74 | 75 | checkForErrors(std::cout, "GLFWController::handleDisplay"); 76 | } 77 | 78 | void GLFWController::initializeCallbacksForRC() 79 | { 80 | glfwSetWindowSizeCallback(theWindow, reshapeCB); 81 | glfwSetCharCallback(theWindow, charCB); 82 | glfwSetKeyCallback(theWindow, keyboardCB); 83 | glfwSetCursorPosCallback(theWindow, mouseMotionCB); 84 | } 85 | 86 | void GLFWController::keyboardCB(GLFWwindow* window, int key, int scanCode, int action, int mods) 87 | { 88 | if (curController != nullptr) 89 | { 90 | GLFWController* theC = dynamic_cast(curController); 91 | if ((key == GLFW_KEY_ESCAPE) && (action != GLFW_PRESS)) 92 | theC->handleAsciiChar(27, theC->lastPixelPosX, theC->lastPixelPosY); 93 | } 94 | } 95 | 96 | void GLFWController::mouseMotionCB(GLFWwindow* window, double x, double y) 97 | { 98 | if (curController != nullptr) 99 | { 100 | GLFWController* c = dynamic_cast(curController); 101 | c->lastPixelPosX = static_cast(x + 0.5); 102 | c->lastPixelPosY = static_cast(y + 0.5); 103 | } 104 | } 105 | 106 | void GLFWController::prepareWindow() const 107 | { 108 | #ifdef __APPLE__ 109 | if (theWindow == nullptr) 110 | return; 111 | glfwMakeContextCurrent(theWindow); 112 | int width, height; 113 | glfwGetFramebufferSize(theWindow, &width, &height); 114 | glViewport(0, 0, width, height); 115 | #endif 116 | } 117 | 118 | void GLFWController::reportWindowInterfaceVersion(std::ostream& os) const 119 | { 120 | os << " GLFW: " << glfwGetVersionString() << '\n'; 121 | } 122 | 123 | void GLFWController::reshapeCB(GLFWwindow* window, int width, int height) 124 | { 125 | dynamic_cast(curController)->handleReshape(width, height); 126 | } 127 | 128 | void GLFWController::run() 129 | { 130 | if (theWindow == nullptr) 131 | return; 132 | while (!glfwWindowShouldClose(theWindow) && !returnFromRun) 133 | { 134 | if (runWaitsForAnEvent) 135 | glfwWaitEvents(); 136 | else 137 | glfwPollEvents(); 138 | handleDisplay(); 139 | } 140 | glfwDestroyWindow(theWindow); 141 | theWindow = nullptr; 142 | } 143 | 144 | void GLFWController::setWindowTitle(const std::string& title) 145 | { 146 | if (theWindow != nullptr) 147 | glfwSetWindowTitle(theWindow, title.c_str()); 148 | } 149 | -------------------------------------------------------------------------------- /glslutil/ShaderIF.c++: -------------------------------------------------------------------------------- 1 | // ShaderIF.c++: Basic interface to read, compile, and link GLSL Shader programs 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "ShaderIF.h" 9 | 10 | ShaderIF::ShaderIF(const std::string& vShader, const std::string& fShader) : 11 | shaderPgm(0), numShaderComponents(2) // just a vertex & fragment shader 12 | { 13 | shaders = new Shader[numShaderComponents]; 14 | shaders[0].fName = vShader; 15 | shaders[0].sType = GL_VERTEX_SHADER; 16 | shaders[1].fName = fShader; 17 | shaders[1].sType = GL_FRAGMENT_SHADER; 18 | initShaders(); 19 | } 20 | 21 | ShaderIF::ShaderIF(const ShaderSpec* shaders, int nShaders) : 22 | shaderPgm(0), numShaderComponents(nShaders) 23 | { 24 | this->shaders = new Shader[numShaderComponents]; 25 | for (int i=0 ; ishaders[i].fName = shaders[i].fName; 28 | this->shaders[i].sType = shaders[i].sType; 29 | } 30 | initShaders(); 31 | } 32 | 33 | ShaderIF::~ShaderIF() 34 | { 35 | if (shaders != nullptr) 36 | { 37 | destroy(); 38 | delete [] shaders; 39 | shaders = nullptr; 40 | } 41 | } 42 | 43 | void ShaderIF::destroy() 44 | { 45 | for (int si=0 ; si 0) 49 | { 50 | if (glIsShader(sPgmID)) 51 | glDeleteShader(sPgmID); 52 | shaders[si].pgmID = 0; 53 | } 54 | } 55 | if (shaderPgm > 0) 56 | { 57 | if (glIsProgram(shaderPgm)) 58 | glDeleteProgram(shaderPgm); 59 | } 60 | shaderPgm = 0; 61 | numShaderComponents = 0; 62 | } 63 | 64 | void ShaderIF::initShaders() 65 | { 66 | for (int i = 0; i < numShaderComponents; i++ ) 67 | { 68 | if (!readShaderSource(shaders[i])) 69 | return; 70 | 71 | shaders[i].pgmID = glCreateShader(shaders[i].sType); 72 | const char* src = shaders[i].source.c_str(); 73 | glShaderSource(shaders[i].pgmID, 1, &src, nullptr); 74 | glCompileShader(shaders[i].pgmID); 75 | 76 | GLint compiled; 77 | glGetShaderiv(shaders[i].pgmID, GL_COMPILE_STATUS, &compiled ); 78 | if ( !compiled ) 79 | { 80 | std::cerr << shaders[i].fName << " failed to compile:" << std::endl; 81 | GLint logSize; 82 | glGetShaderiv(shaders[i].pgmID, GL_INFO_LOG_LENGTH, &logSize ); 83 | if (logSize <= 0) 84 | std::cerr << "No log information available (" << logSize << ")\n"; 85 | else 86 | { 87 | try 88 | { 89 | char* logMsg = new char[logSize]; 90 | glGetShaderInfoLog(shaders[i].pgmID, logSize, nullptr, logMsg ); 91 | std::cerr << "ERROR LOG: '" << logMsg << "'\n"; 92 | delete [] logMsg; 93 | } 94 | catch (std::bad_alloc bae) 95 | { 96 | std::cerr << "Could not allocate error log buffer of size: " << logSize << std::endl; 97 | } 98 | } 99 | destroy(); 100 | return; 101 | } 102 | } 103 | 104 | shaderPgm = glCreateProgram(); 105 | for (int i=0 ; i 7 | #include 8 | #endif 9 | 10 | #include "Controller.h" 11 | #include "ModelView.h" 12 | 13 | Controller* Controller::curController = nullptr; 14 | int Controller::newWindowWidth = 512; 15 | int Controller::newWindowHeight = 512; 16 | 17 | Controller::Controller() : glClearFlags(GL_COLOR_BUFFER_BIT) 18 | { 19 | Controller::curController = this; 20 | 21 | // indicate we do not yet have any models by setting min to +1 and max to -1: 22 | overallMCBoundingBox[0] = overallMCBoundingBox[2] = overallMCBoundingBox[4] = 1.0; 23 | overallMCBoundingBox[1] = overallMCBoundingBox[3] = overallMCBoundingBox[5] = -1.0; 24 | } 25 | 26 | Controller::~Controller() 27 | { 28 | if (this == curController) 29 | curController = nullptr; 30 | } 31 | 32 | void Controller::addModel(ModelView* m) 33 | { 34 | if (m == nullptr) 35 | return; 36 | models.push_back(m); 37 | updateMCBoundingBox(m); 38 | } 39 | 40 | bool Controller::checkForErrors(std::ostream& os, const std::string& context) 41 | // CLASS METHOD 42 | { 43 | bool hadError = false; 44 | GLenum e = glGetError(); 45 | while (e != GL_NO_ERROR) 46 | { 47 | os << "CheckForErrors (context: " << context 48 | #ifdef __APPLE__ 49 | << "): " << static_cast(e) << std::endl; 50 | #else 51 | << "): " << static_cast(gluErrorString(e)) << std::endl; 52 | #endif 53 | e = glGetError(); 54 | hadError = true; 55 | } 56 | return hadError; 57 | } 58 | 59 | void Controller::getOverallMCBoundingBox(double xyzLimits[]) const 60 | { 61 | for (int i=0 ; i<6 ; i++) 62 | xyzLimits[i] = overallMCBoundingBox[i]; 63 | } 64 | 65 | double Controller::getViewportAspectRatio() const 66 | { 67 | int vp[4]; 68 | glGetIntegerv(GL_VIEWPORT, vp); 69 | return static_cast(vp[3]) / static_cast(vp[2]); 70 | } 71 | 72 | void Controller::handleAsciiChar(unsigned char theChar, int x, int y) 73 | { 74 | const unsigned char ESC = 27; 75 | if (theChar == ESC) 76 | endProgram(); 77 | else 78 | { 79 | // No other character is currently handled by the Controller, so we 80 | // just send the event information to the model. 81 | 82 | double ldsX, ldsY; // only coord system known to both Controller and ModelView 83 | pixelPointToLDSPoint(x, y, ldsX, ldsY); 84 | 85 | // Pass the event to each registered ModelView, stopping if and when 86 | // an instance tells us not to pass it to any others. 87 | for (std::vector::iterator it=models.begin() ; ithandleCommand(theChar, ldsX, ldsY)) 89 | break; 90 | 91 | redraw(); 92 | } 93 | } 94 | 95 | void Controller::handleReshape(int width, int height) 96 | { 97 | glViewport(0, 0, width, height); 98 | redraw(); 99 | } 100 | 101 | void Controller::pixelPointToLDSPoint(int xIn, int yIn, double& ldsX, double& ldsY) 102 | { 103 | int vp[4]; 104 | glGetIntegerv(GL_VIEWPORT, vp); 105 | double x = xIn - vp[0]; 106 | ldsX = 2.0 * x / static_cast(vp[2]) - 1.0; 107 | // The window managers report pixel coordinates assuming y=0 is at the top 108 | // of the window. The main OpenGL API assumes y=0 is at the bottom, hence: 109 | double y = (vp[3] - yIn) - vp[1]; 110 | ldsY = 2.0 * y / static_cast(vp[3]) - 1.0; 111 | } 112 | 113 | void Controller::pixelVectorToLDSVector(int dxIn, int dyIn, double& ldsDX, double& ldsDY) 114 | { 115 | int vp[4]; 116 | glGetIntegerv(GL_VIEWPORT, vp); 117 | ldsDX = 2.0 * static_cast(dxIn) / static_cast(vp[2]); 118 | // The window managers delta y is positive going down the screen; In LDS space, 119 | // delta y is positive going up the screen. Hence the leading "-": 120 | ldsDY = -2.0 * static_cast(dyIn) / static_cast(vp[3]); 121 | } 122 | 123 | void Controller::renderAllModels() 124 | { 125 | // draw the collection of models 126 | for (std::vector::iterator it=models.begin() ; itrender(); 128 | } 129 | 130 | void Controller::reportVersions(std::ostream& os) const 131 | { 132 | const char* glVer = reinterpret_cast(glGetString(GL_VERSION)); 133 | const char* glslVer = reinterpret_cast 134 | (glGetString(GL_SHADING_LANGUAGE_VERSION)); 135 | // glGetString can return nullptr if no rendering context has been created 136 | os << "VERSIONS: GL: "; 137 | if (glVer == nullptr) 138 | os << "nullptr (has RC been created?)\n"; 139 | else 140 | os << glVer << '\n'; 141 | os << " GLSL: "; 142 | if (glslVer == nullptr) 143 | os << "nullptr (has RC been created?)\n"; 144 | else 145 | os << glslVer << '\n'; 146 | reportWindowInterfaceVersion(os); 147 | } 148 | 149 | void Controller::setNewWindowSize(int width, int height) 150 | { 151 | newWindowWidth = width; newWindowHeight = height; 152 | } 153 | 154 | std::string Controller::titleString(const std::string& str) 155 | { 156 | int lastSlash = str.length() - 1; 157 | while (lastSlash > 0) 158 | { 159 | if (str[lastSlash] == '/') 160 | return str.substr(lastSlash+1); 161 | lastSlash--; 162 | } 163 | // No slashes - just return original string 164 | return str; 165 | } 166 | 167 | void Controller::updateMCBoundingBox(ModelView* m) 168 | { 169 | if (m == nullptr) 170 | return; 171 | if (overallMCBoundingBox[0] <= overallMCBoundingBox[1]) 172 | { 173 | // bounding box already initialized; just update it: 174 | double xyz[6]; 175 | m->getMCBoundingBox(xyz); 176 | if (xyz[0] > xyz[1]) 177 | // This model does not want to be included in BBs 178 | return; 179 | for (int i=0 ; i<5 ; i+=2) 180 | { 181 | if (xyz[i] < overallMCBoundingBox[i]) 182 | overallMCBoundingBox[i] = xyz[i]; 183 | if (xyz[i+1] > overallMCBoundingBox[i+1]) 184 | overallMCBoundingBox[i+1] = xyz[i+1]; 185 | } 186 | } 187 | else // use this model to initialize the bounding box 188 | m->getMCBoundingBox(overallMCBoundingBox); 189 | } 190 | -------------------------------------------------------------------------------- /project1/ModelView.c++: -------------------------------------------------------------------------------- 1 | // ModelView.c++ - a basic combined Model and View for OpenGL 2 | 3 | #include 4 | 5 | #include "ModelView.h" 6 | #include "Controller.h" 7 | #include "ShaderIF.h" 8 | 9 | double ModelView::mcRegionOfInterest[6] = { -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 }; 10 | bool ModelView::aspectRatioPreservationEnabled = true; 11 | 12 | ModelView::ModelView(ShaderIF* sIF, vec2* triangleVertices, int nPoints, int mPoints, vec2* mVertexPositions) : shaderIF(sIF) 13 | { 14 | nTotalPoints = nPoints; 15 | mTotalPoints = mPoints; 16 | initModelGeometry(triangleVertices, mVertexPositions); 17 | } 18 | 19 | ModelView::~ModelView() 20 | { 21 | deleteObject(); 22 | } 23 | 24 | void ModelView::deleteObject() 25 | { 26 | if (vao[0] > 0) // not already deleted 27 | { 28 | glDeleteBuffers(1, vbo); 29 | glDeleteVertexArrays(1, vao); 30 | vao[0] = vbo[0] = 0; 31 | } 32 | } 33 | 34 | void ModelView::compute2DScaleTrans(float* scaleTransF) 35 | { 36 | double xmin = mcRegionOfInterest[0]; 37 | double xmax = mcRegionOfInterest[1]; 38 | double ymin = mcRegionOfInterest[2]; 39 | double ymax = mcRegionOfInterest[3]; 40 | 41 | if (aspectRatioPreservationEnabled) 42 | { 43 | // preserve aspect ratio. Make "region of interest" wider or taller to 44 | // match the Controller's viewport aspect ratio. 45 | double vAR = Controller::getCurrentController()->getViewportAspectRatio(); 46 | matchAspectRatio(xmin, xmax, ymin, ymax, vAR); 47 | } 48 | 49 | // We are only concerned with the xy extents for now, hence we will 50 | // ignore mcRegionOfInterest[4] and mcRegionOfInterest[5]. 51 | // Map the overall limits to the -1..+1 range expected by the OpenGL engine 52 | double scaleTrans[4]; 53 | linearMap(xmin, xmax, -1.0, 1.0, scaleTrans[0], scaleTrans[1]); 54 | linearMap(ymin, ymax, -1.0, 1.0, scaleTrans[2], scaleTrans[3]); 55 | for (int i=0 ; i<4 ; i++) 56 | scaleTransF[i] = static_cast(scaleTrans[i]); 57 | } 58 | 59 | // xyzLimits: {mcXmin, mcXmax, mcYmin, mcYmax, mcZmin, mcZmax} 60 | void ModelView::getMCBoundingBox(double* xyzLimits) const 61 | { 62 | xyzLimits[0] = xmin; 63 | xyzLimits[1] = xmax; 64 | xyzLimits[2] = ymin; 65 | xyzLimits[3] = ymax; 66 | xyzLimits[4] = -1.0; // [4] and [5] are 67 | xyzLimits[5] = 1.0; // (zmin, zmax) but really it's 0..0 68 | } 69 | 70 | bool toggle = true; 71 | 72 | bool ModelView::handleCommand(unsigned char anASCIIChar, double ldsX, double ldsY) 73 | { 74 | if (anASCIIChar == 'n') 75 | { 76 | toggle = true; 77 | } 78 | else if (anASCIIChar == 'm') 79 | { 80 | toggle = false; 81 | } 82 | return true; // not intended for me; tell Controller to keep trying 83 | } 84 | 85 | void ModelView::initModelGeometry(vec2* nVertexPositions, vec2* mVertexPositions) 86 | { 87 | // set color for n 88 | nColor[0] = 1; nColor[1] = 0.5; nColor[2] = 0.2; 89 | 90 | // set color for m 91 | mColor[0] = 0.4; mColor[1] = 0.9; mColor[2] = 0.7; 92 | 93 | // create VAOs and VBOs 94 | glGenVertexArrays(2, vao); 95 | glGenBuffers(2, vbo); 96 | 97 | // initialize these for n 98 | glBindVertexArray(vao[0]); 99 | glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); 100 | 101 | // allocate space and send data to GPU for n 102 | int numBytesInBuffer = nTotalPoints * sizeof(vec2); 103 | glBufferData(GL_ARRAY_BUFFER, numBytesInBuffer, nVertexPositions, GL_STATIC_DRAW); 104 | glVertexAttribPointer(shaderIF->pvaLoc("mcPosition"), 2, GL_FLOAT, GL_FALSE, 0, 0); 105 | glEnableVertexAttribArray(shaderIF->pvaLoc("mcPosition")); 106 | 107 | // initialize these for m 108 | glBindVertexArray(vao[1]); 109 | glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); 110 | 111 | // allocate space and send data to GPU for m 112 | int numBytesInBufferM = mTotalPoints * sizeof(vec2); 113 | glBufferData(GL_ARRAY_BUFFER, numBytesInBufferM, mVertexPositions, GL_STATIC_DRAW); 114 | glVertexAttribPointer(shaderIF->pvaLoc("mcPosition"), 2, GL_FLOAT, GL_FALSE, 0, 0); 115 | glEnableVertexAttribArray(shaderIF->pvaLoc("mcPosition")); 116 | 117 | // determine and remember min/max coordinates 118 | xmin = xmax = nVertexPositions[0][0]; 119 | ymin = ymax = nVertexPositions[0][1]; 120 | 121 | for (int i = 0; i < nTotalPoints; i++) 122 | { 123 | if (nVertexPositions[i][0] < xmin) 124 | { 125 | xmin = nVertexPositions[i][0]; 126 | } 127 | else if (nVertexPositions[i][0] > xmax) 128 | { 129 | xmax = nVertexPositions[i][0]; 130 | } 131 | 132 | if (nVertexPositions[i][1] < ymin) 133 | { 134 | ymin = nVertexPositions[i][1]; 135 | } 136 | else if (nVertexPositions[i][1] > ymax) 137 | { 138 | ymax = nVertexPositions[i][1]; 139 | } 140 | } 141 | 142 | for (int i = 0; i < mTotalPoints; i++) 143 | { 144 | if (mVertexPositions[i][0] < xmin) 145 | { 146 | xmin = mVertexPositions[i][0]; 147 | } 148 | else if (mVertexPositions[i][0] > xmax) 149 | { 150 | xmax = mVertexPositions[i][0]; 151 | } 152 | 153 | if (mVertexPositions[i][1] < ymin) 154 | { 155 | ymin = mVertexPositions[i][1]; 156 | } 157 | else if (mVertexPositions[i][1] > ymax) 158 | { 159 | ymax = mVertexPositions[i][1]; 160 | } 161 | } 162 | } 163 | 164 | // linearMap determines the scale and translate parameters needed in 165 | // order to map a value, f (fromMin <= f <= fromMax) to its corresponding 166 | // value, t (toMin <= t <= toMax). Specifically: t = scale*f + trans. 167 | void ModelView::linearMap(double fromMin, double fromMax, double toMin, double toMax, 168 | double& scale, double& trans) // CLASS METHOD 169 | { 170 | scale = (toMax - toMin) / (fromMax - fromMin); 171 | trans = toMin - scale*fromMin; 172 | } 173 | 174 | void ModelView::matchAspectRatio(double& xmin, double& xmax, 175 | double& ymin, double& ymax, double vAR) 176 | { 177 | double wHeight = ymax - ymin; 178 | double wWidth = xmax - xmin; 179 | double wAR = wHeight / wWidth; 180 | if (wAR > vAR) 181 | { 182 | // make window wider 183 | wWidth = wHeight / vAR; 184 | double xmid = 0.5 * (xmin + xmax); 185 | xmin = xmid - 0.5*wWidth; 186 | xmax = xmid + 0.5*wWidth; 187 | } 188 | else 189 | { 190 | // make window taller 191 | wHeight = wWidth * vAR; 192 | double ymid = 0.5 * (ymin + ymax); 193 | ymin = ymid - 0.5*wHeight; 194 | ymax = ymid + 0.5*wHeight; 195 | } 196 | } 197 | 198 | void ModelView::render() const 199 | { 200 | // save the current GLSL program in use 201 | GLint pgm; 202 | glGetIntegerv(GL_CURRENT_PROGRAM, &pgm); 203 | 204 | // draw the triangles using our vertex and fragment shaders 205 | glUseProgram(shaderIF->getShaderPgmID()); 206 | 207 | // set scaleTrans (and all other needed) uniform(s) 208 | float scaleTrans[4]; 209 | compute2DScaleTrans(scaleTrans); 210 | glUniform4fv(shaderIF->ppuLoc("scaleTrans"), 1, scaleTrans); 211 | 212 | // make require primitive call(s) 213 | if (toggle == true) 214 | { 215 | glUniform3fv(shaderIF->ppuLoc("color"), 1, nColor); // establish the color for n 216 | glBindVertexArray(vao[0]); 217 | glDrawArrays(GL_LINE_STRIP, 0, nTotalPoints); 218 | } 219 | else 220 | { 221 | glUniform3fv(shaderIF->ppuLoc("color"), 1, mColor); // establish the color for m 222 | glBindVertexArray(vao[1]); 223 | glDrawArrays(GL_LINE_STRIP, 0, mTotalPoints); 224 | } 225 | 226 | // restore the previous program 227 | glUseProgram(pgm); 228 | } 229 | 230 | void ModelView::setMCRegionOfInterest(double xyz[6]) 231 | { 232 | for (int i=0 ; i<6 ; i++) 233 | mcRegionOfInterest[i] = xyz[i]; 234 | } 235 | --------------------------------------------------------------------------------