├── demo.png ├── hello.vsh ├── hello.fsh ├── ModelView.h ├── hello.c++ ├── README.md ├── GLFWController.h ├── Makefile ├── ModelView.c++ ├── ShaderIF.h ├── GLFWController.c++ └── ShaderIF.c++ /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/hello-opengl-mvc-framework/master/demo.png -------------------------------------------------------------------------------- /hello.vsh: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout (location = 0) in vec2 mcPosition; 4 | 5 | void main() 6 | { 7 | gl_Position = vec4(mcPosition, 0, 1); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /hello.fsh: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | // The first declaration of a variable with type "out vec4" will be 4 | // used in subsequent pipeline stages as the color for this fragment: 5 | out vec4 fragmentColor; 6 | 7 | void main() 8 | { 9 | fragmentColor = vec4(0.8, 0.8, 0.0, 1.0); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /ModelView.h: -------------------------------------------------------------------------------- 1 | // ModelView.h - a basic combined Model and View for OpenGL 2 | 3 | #ifndef MODELVIEW_H 4 | #define MODELVIEW_H 5 | 6 | #ifdef __APPLE_CC__ 7 | #include "GLFW/glfw3.h" 8 | #else 9 | #include 10 | #endif 11 | 12 | #include "ShaderIF.h" 13 | 14 | class ModelView 15 | { 16 | public: 17 | ModelView(ShaderIF* sIF); 18 | virtual ~ModelView(); 19 | 20 | void render() const; 21 | private: 22 | // This simple program requires 1 vertex array object & 1 vertex buffer object 23 | GLuint vao[1]; // "vao" = "vertex array object" 24 | GLuint vbo[1]; // "vbo" = "vertex buffer object" (holds per-vertex attribute data) 25 | 26 | ShaderIF* shaderIF; 27 | 28 | void initModelGeometry(); 29 | }; 30 | 31 | #endif 32 | 33 | -------------------------------------------------------------------------------- /hello.c++: -------------------------------------------------------------------------------- 1 | // hello.c++: A "Hello, OpenGL" program that draws a triangle 2 | // This version has been restructured from our "Basic" version 3 | // in order to make use of our MVC framework. 4 | 5 | #include "GLFWController.h" 6 | #include "ModelView.h" 7 | 8 | int main(int argc, char* argv[]) 9 | { 10 | GLFWController controller; // Step 1 11 | controller.reportVersions(std::cout); // (optional) 12 | ShaderIF* shaderIF = new ShaderIF("hello.vsh", "hello.fsh"); 13 | // Step 2 14 | ModelView* mv = new ModelView(shaderIF); // Step 3a 15 | controller.addModel( mv ); // Step 3b 16 | controller.run(); // Step 4 17 | 18 | delete shaderIF; 19 | 20 | return 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hello OpenGL MVC Framework 2 | 3 | > The [hello-opengl](https://github.com/CompSciLauren/hello-opengl "Hello OpenGL") beginner program but using a Model-View-Controller (MVC) framework. 4 | 5 | ## How to Run Program in Terminal 6 | 7 | 1. Clone or download the repo 8 | 2. Inside project folder, run `make` command 9 | 3. Type `./hello` 10 | 11 | ## What it Looks Like 12 | 13 | You should see an image of a yellow triangle with a black background. 14 | 15 | 16 | 17 | ## Credit 18 | 19 | This example program is from the 20 | [KU EECS 672 public class website](https://people.eecs.ku.edu/~jrmiller/Courses/OpenGL/HelloOpenGL/HelloOpenGLFramework/HelloOpenGLFramework.html "KU EECS 672 public class website"). 21 | -------------------------------------------------------------------------------- /GLFWController.h: -------------------------------------------------------------------------------- 1 | // GLFWController.h - a basic Controller (in Model-View-Controller sense) based 2 | // on the open-source GLFW toolkit. (http://www.glfw.org) 3 | 4 | #ifndef GLFWCONTROLLER_H 5 | #define GLFWCONTROLLER_H 6 | 7 | #include "GLFW/glfw3.h" 8 | 9 | #include 10 | #include 11 | 12 | class ModelView; 13 | 14 | class GLFWController 15 | { 16 | public: 17 | GLFWController(); 18 | virtual ~GLFWController(); 19 | 20 | void addModel(ModelView* m); 21 | void reportVersions(std::ostream& os) const; 22 | void run(); 23 | 24 | static bool checkForErrors(std::ostream& os, const std::string& context); 25 | protected: 26 | GLFWwindow* theWindow; 27 | private: 28 | // do not allow copies, including pass-by-value: 29 | GLFWController(const GLFWController& c) {} 30 | 31 | ModelView* model; 32 | 33 | void createWindowAndRC(const std::string& windowTitle); 34 | virtual void handleDisplay(); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CPP = g++ -std=c++11 2 | INC = -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 | 17 | OBJS = hello.o ModelView.o GLFWController.o ShaderIF.o 18 | 19 | hello: $(OBJS) 20 | $(LINK) -o hello $(OBJS) $(GL_LIBRARIES) 21 | 22 | hello.o: hello.c++ 23 | $(CPP) $(C_FLAGS) hello.c++ 24 | ModelView.o: ModelView.c++ 25 | $(CPP) $(C_FLAGS) ModelView.c++ 26 | GLFWController.o: GLFWController.c++ 27 | $(CPP) $(C_FLAGS) GLFWController.c++ 28 | ShaderIF.o: ShaderIF.h ShaderIF.c++ 29 | $(CPP) $(C_FLAGS) ShaderIF.c++ 30 | -------------------------------------------------------------------------------- /ModelView.c++: -------------------------------------------------------------------------------- 1 | // ModelView.c++ - a basic combined Model and View for OpenGL 2 | 3 | #include 4 | 5 | #include "ModelView.h" 6 | 7 | ModelView::ModelView(ShaderIF* sIF) : shaderIF(sIF) 8 | { 9 | initModelGeometry(); 10 | } 11 | 12 | ModelView::~ModelView() 13 | { 14 | glDeleteBuffers(1, vbo); 15 | glDeleteVertexArrays(1, vao); 16 | } 17 | 18 | void ModelView::initModelGeometry() 19 | { 20 | float triangleVertices[3][2] = 21 | { 22 | { -0.75, -0.75 }, { 0.75, -0.75 }, { 0.0, 0.75 } 23 | }; 24 | 25 | glGenVertexArrays(1, vao); // get a new, previously unused VAO name 26 | glBindVertexArray(vao[0]); // (initialize it and) make it active 27 | 28 | glGenBuffers(1, vbo); // get a new, previously unused VBO name 29 | glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // (initialize it and) make it active 30 | 31 | // Allocate space for AND copy the CPU data in "triangleVertices" to the VBO on the GPU: 32 | int numBytesInBuffer = 3 * 2 * sizeof(float); // 3 points; 2 coords each; float 33 | glBufferData(GL_ARRAY_BUFFER, numBytesInBuffer, triangleVertices, GL_STATIC_DRAW); 34 | 35 | int coordinateLocation = 0; // See "layout" in hello.vsh 36 | glVertexAttribPointer(coordinateLocation, 2, GL_FLOAT, GL_FALSE, 0, 0); 37 | glEnableVertexAttribArray(coordinateLocation); 38 | } 39 | 40 | void ModelView::render() const 41 | { 42 | // save the current GLSL program in use 43 | int savedPgm = 0; 44 | glGetIntegerv(GL_CURRENT_PROGRAM, &savedPgm); 45 | // place our vertex-fragment shader program in use 46 | glUseProgram(shaderIF->getShaderPgmID()); 47 | 48 | glBindVertexArray(vao[0]); 49 | glDrawArrays(GL_TRIANGLES, 0, 3); // start at 0 in buffer; process 3 vertices 50 | 51 | // restore the previous program 52 | glUseProgram(savedPgm); 53 | } 54 | 55 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /GLFWController.c++: -------------------------------------------------------------------------------- 1 | // GLFWController.c++ 2 | 3 | #include "GLFWController.h" 4 | #include "ModelView.h" 5 | 6 | GLFWController::GLFWController() : theWindow(nullptr), model(nullptr) 7 | { 8 | glfwInit(); 9 | 10 | // Before any OpenGL graphics calls can be made, we must create an 11 | // OpenGL Rendering Context (RC). There is one RC per window. 12 | createWindowAndRC("Hello, OpenGL"); 13 | } 14 | 15 | GLFWController::~GLFWController() 16 | { 17 | if (theWindow != nullptr) 18 | glfwDestroyWindow(theWindow); 19 | } 20 | 21 | void GLFWController::addModel(ModelView* m) 22 | { 23 | // for now, we just assume we only have one model: 24 | model = m; 25 | } 26 | 27 | bool GLFWController::checkForErrors(std::ostream& os, const std::string& context) 28 | // CLASS METHOD 29 | { 30 | bool hadError = false; 31 | GLenum e = glGetError(); 32 | while (e != GL_NO_ERROR) 33 | { 34 | os << "CheckForErrors (context: " << context 35 | << "): " << ((int)e) << std::endl; 36 | e = glGetError(); 37 | hadError = true; 38 | } 39 | return hadError; 40 | } 41 | 42 | void GLFWController::createWindowAndRC(const std::string& windowTitle) 43 | { 44 | // The following calls enforce use of only non-deprecated functionality. 45 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 46 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 47 | 48 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); 49 | int minor = 8; // Start AT LEAST one greater than where you really want to start 50 | while ((theWindow == nullptr) && (minor > 0)) 51 | { 52 | minor--; 53 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor); 54 | theWindow = glfwCreateWindow(400, 400, windowTitle.c_str(), nullptr, nullptr); 55 | } 56 | if (theWindow == nullptr) 57 | { 58 | std::cerr << "\n**** COULD NOT CREATE A 4.x RENDERING CONTEXT ****\n\n"; 59 | return; 60 | } 61 | glfwMakeContextCurrent(theWindow); 62 | } 63 | 64 | void GLFWController::handleDisplay() 65 | { 66 | // clear the frame buffer 67 | glClear(GL_COLOR_BUFFER_BIT); 68 | 69 | if (model != nullptr) 70 | model->render(); 71 | 72 | glfwSwapBuffers(theWindow); 73 | 74 | checkForErrors(std::cout, "GLFWController::handleDisplay"); 75 | } 76 | 77 | void GLFWController::reportVersions(std::ostream& os) const 78 | { 79 | const char* glVer = reinterpret_cast(glGetString(GL_VERSION)); 80 | const char* glslVer = reinterpret_cast 81 | (glGetString(GL_SHADING_LANGUAGE_VERSION)); 82 | // glGetString can return nullptr if no rendering context has been created 83 | os << "VERSIONS: GL: "; 84 | if (glVer == nullptr) 85 | os << "nullptr (has RC been created?)\n"; 86 | else 87 | os << glVer << '\n'; 88 | os << " GLSL: "; 89 | if (glslVer == nullptr) 90 | os << "nullptr (has RC been created?)\n"; 91 | else 92 | os << glslVer << '\n'; 93 | os << " GLFW: " << glfwGetVersionString() << '\n'; 94 | } 95 | 96 | void GLFWController::run() 97 | { 98 | while (!glfwWindowShouldClose(theWindow)) 99 | { 100 | glfwWaitEvents(); 101 | handleDisplay(); 102 | } 103 | glfwDestroyWindow(theWindow); 104 | theWindow = nullptr; 105 | } 106 | -------------------------------------------------------------------------------- /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