├── demo.png ├── lib └── libglsl.so ├── glslutil ├── ShaderIF.o ├── libglsl.so ├── Makefile ├── MakefileMac ├── ShaderIF.h └── ShaderIF.c++ ├── fancytrees ├── shaders │ ├── fancytree.vsh │ └── fancytree.fsh ├── Makefile ├── ModelView.h ├── main.c++ └── ModelView.c++ ├── README.md └── mvcutil ├── GLFWController.h ├── Controller.h ├── GLFWController.c++ └── Controller.c++ /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/opengl-fancy-trees/master/demo.png -------------------------------------------------------------------------------- /lib/libglsl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/opengl-fancy-trees/master/lib/libglsl.so -------------------------------------------------------------------------------- /glslutil/ShaderIF.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/opengl-fancy-trees/master/glslutil/ShaderIF.o -------------------------------------------------------------------------------- /glslutil/libglsl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CompSciLauren/opengl-fancy-trees/master/glslutil/libglsl.so -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /fancytrees/shaders/fancytree.vsh: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | in vec2 mcPosition; 4 | in float vertexFraction; 5 | in vec3 vertexColor; 6 | 7 | uniform vec4 scaleTrans; 8 | out PVA 9 | { 10 | vec3 color; 11 | float fraction; 12 | } pvaOut; 13 | 14 | void main() 15 | { 16 | pvaOut.color = vertexColor; 17 | pvaOut.fraction = vertexFraction; 18 | float ldsX = scaleTrans[0]*mcPosition.x + scaleTrans[1]; 19 | float ldsY = scaleTrans[2]*mcPosition.y + scaleTrans[3]; 20 | gl_Position = vec4(ldsX, ldsY, 0, 1); 21 | } 22 | -------------------------------------------------------------------------------- /fancytrees/shaders/fancytree.fsh: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | in PVA 4 | { 5 | vec3 color; 6 | float fraction; 7 | } pvaIn; 8 | 9 | // colorMode: 10 | // 0 ==> use interpolated vertex color (colorToFS) 11 | // 1 ==> use interpolated height fraction 12 | // 2 ==> use product of two 13 | // 3 ==> hard-wired constant darkish magenta 14 | uniform int colorMode; 15 | 16 | out vec4 fragmentColor; 17 | 18 | void main() 19 | { 20 | if (colorMode == 0) 21 | fragmentColor = vec4(pvaIn.color,1.0); 22 | else if (colorMode == 1) 23 | fragmentColor = vec4(pvaIn.fraction, pvaIn.fraction, pvaIn.fraction, 1.0); 24 | else if (colorMode == 2) 25 | fragmentColor = vec4(pvaIn.fraction*pvaIn.color, 1.0); 26 | else // colorMode == 3 27 | fragmentColor = vec4(0.6, 0.0, 0.6, 1.0); 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenGL Fancy Trees 2 | 3 | > A beginner example project that displays and interacts with fancy trees. 4 | 5 | ## How to Run Program in Terminal 6 | 7 | 1. Clone or download the repo 8 | 2. Inside fancytrees folder, run `make` command 9 | 3. Type `./main` 10 | 11 | ## What it Looks Like 12 | 13 | If you choose the twoTriangles\_V1 program, you should see an image of three fancy trees. To cycle through different colors/patterns, press '1' repeatedly for the left tree, press '2' repeatedly for the middle tree, and press '0' repeatedly for the right tree. Press '3' repeatedly to cycle through different colors/patterns for the border surrounding the trees. 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/SampleProgramSet1/SampleProgramSet1.html "KU EECS 672 public class website"). 21 | 22 | -------------------------------------------------------------------------------- /fancytrees/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 | -------------------------------------------------------------------------------- /fancytrees/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 | typedef float vec2[2]; 17 | typedef float vec3[3]; 18 | 19 | class ModelView 20 | { 21 | public: 22 | ModelView(ShaderIF* sIF, vec2* coords, vec3* colors, 23 | float* fractions, int nVertices); 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 | ShaderIF* shaderIF; 38 | GLuint vao[1]; 39 | GLuint vbo[3]; // 0: colors; 1: fractions; 2: coordinates 40 | int colorMode; // how is color determined for this set of triangles 41 | int numVertices; 42 | int serialNumber; 43 | float xmin, xmax, ymin, ymax; 44 | 45 | // Routines for computing parameters necessary to map from arbitrary 46 | // model coordinate ranges into OpenGL's -1..+1 Logical Device Space. 47 | // 1. linearMap determines the scale and translate parameters needed in 48 | // order to map a value, f (fromMin <= f <= fromMax) to its corresponding 49 | // value, t (toMin <= t <= toMax). Specifically: t = scale*f + trans. 50 | static void linearMap(double fromMin, double fromMax, 51 | double toMin, double toMax, double& scale, double& trans); 52 | // 2. matchAspectRatio modifies (xmin,xmax) OR (ymin,ymax) to center that 53 | // region in an expanded window that matches the given aspect ratio. 54 | static void matchAspectRatio(double& xmin, double& xmax, 55 | double& ymin, double& ymax, double vAR); 56 | // 3. compute2DScaleTrans uses the current model coordinate region of 57 | // interest - modified as necessary to preserve aspect ratios - and 58 | // then passes the modified limits to linearMap to compute the scale 59 | // and translation needed to map MC to LDS. 60 | // (The scales and translationes are returned in float[] because 61 | // glUniform currently allows only float[].) 62 | static void compute2DScaleTrans(float* scaleTrans); 63 | 64 | static double mcRegionOfInterest[6]; 65 | static bool aspectRatioPreservationEnabled; 66 | 67 | static int numInstances; // we associate a "serial number" with each instance 68 | 69 | void initModelGeometry(vec2* coords, vec3* colors, float* fractions); 70 | }; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /fancytrees/main.c++: -------------------------------------------------------------------------------- 1 | // main.c++: An OpenGL program that draws three colored triangles 2 | 3 | #include "GLFWController.h" 4 | #include "ModelView.h" 5 | 6 | void makeFrame(Controller& c, ShaderIF* sIF, float halfWidth) 7 | { 8 | float frameWidth = 0.125; 9 | float fs = (1.0 + frameWidth) * halfWidth; // "frame start" 10 | float fe = (1.0 + 2.0*frameWidth) * halfWidth; // "frame end" 11 | vec2 frameCoords[] = 12 | { 13 | { -fe, -fe }, { -fs, -fs }, { fe, -fe }, { fs, -fs }, 14 | { fe, fe }, { fs, fs }, { -fe, fe }, { -fs, fs }, 15 | { -fe, -fe }, { -fs, -fs } 16 | }; 17 | 18 | float g = 0.5; 19 | vec3 frameColors[] = 20 | { 21 | { 0.0, 0.0, 0.0 },{ g, g, g },{ 0.0, 0.0, 0.0 },{ g, g, g }, 22 | { 0.0, 0.0, 0.0 },{ g, g, g },{ 0.0, 0.0, 0.0 },{ g, g, g }, 23 | { 0.0, 0.0, 0.0 },{ g, g, g } 24 | }; 25 | 26 | float outer = 1.0, inner = 0.0; 27 | float frameFraction[] = 28 | { 29 | outer, inner, outer, inner, outer, 30 | inner, outer, inner, outer, inner 31 | }; 32 | 33 | c.addModel( new ModelView(sIF, frameCoords, frameColors, frameFraction, 10) ); 34 | } 35 | 36 | void makeTree(Controller& c, ShaderIF* sIF, float xs, float ys, float outer[], float inner[]) 37 | { 38 | // define per-vertex colors 39 | // (Whether these will actually be used depends on the current "colorMode".) 40 | vec3 vertexColors[20] = 41 | { 42 | // bottom four: black trunk 43 | { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, 44 | { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } 45 | }; 46 | // alternate outer and inner for the rest 47 | for (int i=4 ; i<20 ; i+=4) 48 | { 49 | for (int j=0 ; j<3 ; j++) 50 | { 51 | vertexColors[i ][j] = outer[j]; 52 | vertexColors[i+1][j] = outer[j]; 53 | vertexColors[i+2][j] = inner[j]; 54 | vertexColors[i+3][j] = inner[j]; 55 | } 56 | }; 57 | 58 | // define vertex coordinates 59 | vec2 vertexPositions[] = 60 | { 61 | {-2, 0}, {2, 0}, {-2, 4}, {2, 4}, {-10, 6}, {10, 6}, {-4, 9}, {4, 9}, {-7, 11}, {7, 11}, 62 | {-2, 13}, {2, 13}, {-4, 14}, {4, 14}, {-1, 16}, {1, 16}, {-2, 17}, {2, 17}, 63 | { -0.2, 19}, {0.2, 19} 64 | }; 65 | 66 | float heightFractions[20]; 67 | 68 | for (int i=0 ; i<20 ; i++) 69 | { 70 | heightFractions[i] = vertexPositions[i][1] / 19.0; 71 | vertexPositions[i][0] += xs; 72 | vertexPositions[i][1] += ys; 73 | } 74 | 75 | c.addModel( new ModelView(sIF, vertexPositions, vertexColors, heightFractions, 20) ); 76 | } 77 | 78 | void createScene(GLFWController& c, ShaderIF* sIF) 79 | { 80 | float outer0[] = { 0.0, 1.0, 0.0 }; 81 | float inner0[] = { 1.0, 0.0, 0.0 }; 82 | makeTree(c, sIF, 7, -3, outer0, inner0); 83 | float outer1[] = { 0.0, 1.0, 0.0 }; 84 | float inner1[] = { 0.0, 0.2, 0.0 }; 85 | makeTree(c, sIF, -9.5, -8, outer1, inner1); 86 | float outer2[] = { 0.0, 0.0, 1.0 }; 87 | float inner2[] = { 0.0, 0.0, 0.3 }; 88 | makeTree(c, sIF, 0, -10, outer2, inner2); 89 | makeFrame(c, sIF, 18); 90 | } 91 | 92 | int main(int argc, char* argv[]) 93 | { 94 | GLFWController c(argv[0]); 95 | c.reportVersions(std::cout); 96 | 97 | ShaderIF* sIF = new ShaderIF("shaders/fancytree.vsh", "shaders/fancytree.fsh"); 98 | 99 | createScene(c, sIF); 100 | 101 | glClearColor(1.0, 1.0, 1.0, 1.0); 102 | 103 | double xyz[6]; // xyz limits, even though this is 2D 104 | c.getOverallMCBoundingBox(xyz); 105 | std::cout << "Bounding box: " << xyz[0] << " <= x <= " << xyz[1] << '\n'; 106 | std::cout << " " << xyz[2] << " <= y <= " << xyz[3] << '\n'; 107 | std::cout << " " << xyz[4] << " <= z <= " << xyz[5] << "\n\n"; 108 | ModelView::setMCRegionOfInterest(xyz); 109 | 110 | c.run(); 111 | 112 | delete sIF; 113 | 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /fancytrees/ModelView.c++: -------------------------------------------------------------------------------- 1 | // ModelView.c++ - a basic combined Model and View for OpenGL 2 | 3 | #include 4 | 5 | #include "Controller.h" 6 | #include "ModelView.h" 7 | 8 | // Current MC Region of interest 9 | double ModelView::mcRegionOfInterest[6] = { -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 }; 10 | bool ModelView::aspectRatioPreservationEnabled = true; 11 | 12 | int ModelView::numInstances = 0; 13 | 14 | ModelView::ModelView(ShaderIF* sIF, vec2* coords, vec3* colors, 15 | float* fractions, int nVertices) : 16 | shaderIF(sIF), colorMode(0), numVertices(nVertices), 17 | serialNumber(numInstances) 18 | { 19 | numInstances++; 20 | initModelGeometry(coords, colors, fractions); 21 | } 22 | 23 | ModelView::~ModelView() 24 | { 25 | glDeleteBuffers(3, vbo); 26 | glDeleteVertexArrays(1, vao); 27 | } 28 | 29 | void ModelView::compute2DScaleTrans(float* scaleTransF) // CLASS METHOD 30 | { 31 | double xmin = mcRegionOfInterest[0]; 32 | double xmax = mcRegionOfInterest[1]; 33 | double ymin = mcRegionOfInterest[2]; 34 | double ymax = mcRegionOfInterest[3]; 35 | 36 | if (aspectRatioPreservationEnabled) 37 | { 38 | // preserve aspect ratio. Make "region of interest" wider or taller to 39 | // match the Controller's viewport aspect ratio. 40 | double vAR = Controller::getCurrentController()->getViewportAspectRatio(); 41 | matchAspectRatio(xmin, xmax, ymin, ymax, vAR); 42 | } 43 | 44 | double scaleTrans[4]; 45 | linearMap(xmin, xmax, -1.0, 1.0, scaleTrans[0], scaleTrans[1]); 46 | linearMap(ymin, ymax, -1.0, 1.0, scaleTrans[2], scaleTrans[3]); 47 | for (int i=0 ; i<4 ; i++) 48 | scaleTransF[i] = static_cast(scaleTrans[i]); 49 | } 50 | 51 | // xyzLimits: {mcXmin, mcXmax, mcYmin, mcYmax, mcZmin, mcZmax} 52 | void ModelView::getMCBoundingBox(double* xyzLimits) const 53 | { 54 | xyzLimits[0] = xmin; xyzLimits[1] = xmax; 55 | xyzLimits[2] = ymin; xyzLimits[3] = ymax; 56 | xyzLimits[4] = -1.0; xyzLimits[5] = 1.0; // (zmin, zmax) (really 0..0) 57 | } 58 | 59 | bool ModelView::handleCommand(unsigned char anASCIIChar, double ldsX, double ldsY) 60 | { 61 | if ((anASCIIChar >= '0') && (anASCIIChar <= '9')) 62 | { 63 | int which = static_cast(anASCIIChar) - static_cast('0'); 64 | if (which == serialNumber) // was this message intended for me??? 65 | { 66 | // Yes, it is intended for me. Process and then tell Controller 67 | // stop sending this event to other ModelView instances: 68 | colorMode = (colorMode + 1) % 4; // cycle among 0, 1, 2, 3 69 | return false; // tell Controller to stop send this event 70 | } 71 | } 72 | return true; // not intended for me; tell Controller to keep trying. 73 | } 74 | 75 | void ModelView::initModelGeometry(vec2* coords, vec3* colors, float* fractions) 76 | { 77 | glGenVertexArrays(1, vao); 78 | glBindVertexArray(vao[0]); 79 | 80 | // create three per-vertex attribute buffers for the set of triangles 81 | // [0] - color buffer; [1] - fraction; [2] - vertex coordinate buffer 82 | glGenBuffers(3, vbo); 83 | 84 | // Allocate space for and copy CPU color information to GPU 85 | glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); 86 | int numBytesColors = numVertices * sizeof(vec3); 87 | glBufferData(GL_ARRAY_BUFFER, numBytesColors, colors, GL_STATIC_DRAW); 88 | glVertexAttribPointer(shaderIF->pvaLoc("vertexColor"), 3, GL_FLOAT, GL_FALSE, 0, 0); 89 | glEnableVertexAttribArray(shaderIF->pvaLoc("vertexColor")); 90 | 91 | // Allocate space for and copy CPU fraction information to GPU 92 | glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); 93 | int numBytesCodeData = numVertices * sizeof(float); 94 | glBufferData(GL_ARRAY_BUFFER, numBytesCodeData, fractions, GL_STATIC_DRAW); 95 | glVertexAttribPointer(shaderIF->pvaLoc("vertexFraction"), 1, GL_FLOAT, GL_FALSE, 0, 0); 96 | glEnableVertexAttribArray(shaderIF->pvaLoc("vertexFraction")); 97 | 98 | // Allocate space for and copy CPU coordinate data to GPU 99 | glBindBuffer(GL_ARRAY_BUFFER, vbo[2]); 100 | int numBytesCoordinateData = numVertices * sizeof(vec2); 101 | glBufferData(GL_ARRAY_BUFFER, numBytesCoordinateData, coords, GL_STATIC_DRAW); 102 | glVertexAttribPointer(shaderIF->pvaLoc("mcPosition"), 2, GL_FLOAT, GL_FALSE, 0, 0); 103 | glEnableVertexAttribArray(shaderIF->pvaLoc("mcPosition")); 104 | 105 | // make note of the min/max coordinates 106 | xmin = xmax = coords[0][0]; 107 | ymin = ymax = coords[0][1]; 108 | for (int i=1 ; i xmax) 113 | xmax = coords[i][0]; 114 | if (coords[i][1] < ymin) 115 | ymin = coords[i][1]; 116 | else if (coords[i][1] > ymax) 117 | ymax = coords[i][1]; 118 | } 119 | 120 | // REMEMBER: 121 | // All three array buffers here - along with their memory layout information and 122 | // enable statuses - will be reestablished in ModelView::render with the single 123 | // call to glBindVertexArray(vao[0]). 124 | } 125 | 126 | // linearMap determines the scale and translate parameters needed in 127 | // order to map a value, f (fromMin <= f <= fromMax) to its corresponding 128 | // value, t (toMin <= t <= toMax). Specifically: t = scale*f + trans. 129 | void ModelView::linearMap(double fromMin, double fromMax, double toMin, double toMax, 130 | double& scale, double& trans) // CLASS METHOD 131 | { 132 | scale = (toMax - toMin) / (fromMax - fromMin); 133 | trans = toMin - scale*fromMin; 134 | } 135 | 136 | void ModelView::matchAspectRatio(double& xmin, double& xmax, 137 | double& ymin, double& ymax, double vAR) 138 | { 139 | double wHeight = ymax - ymin; 140 | double wWidth = xmax - xmin; 141 | double wAR = wHeight / wWidth; 142 | if (wAR > vAR) 143 | { 144 | // make window wider 145 | wWidth = wHeight / vAR; 146 | double xmid = 0.5 * (xmin + xmax); 147 | xmin = xmid - 0.5*wWidth; 148 | xmax = xmid + 0.5*wWidth; 149 | } 150 | else 151 | { 152 | // make window taller 153 | wHeight = wWidth * vAR; 154 | double ymid = 0.5 * (ymin + ymax); 155 | ymin = ymid - 0.5*wHeight; 156 | ymax = ymid + 0.5*wHeight; 157 | } 158 | } 159 | 160 | void ModelView::render() const 161 | { 162 | // save the current GLSL program in use 163 | GLint pgm; 164 | glGetIntegerv(GL_CURRENT_PROGRAM, &pgm); 165 | // draw the triangles using our vertex and fragment shaders 166 | glUseProgram(shaderIF->getShaderPgmID()); 167 | 168 | // define the mapping from MC to -1..+1 Logical Device Space: 169 | float scaleTrans[4]; 170 | compute2DScaleTrans(scaleTrans); 171 | glUniform4fv(shaderIF->ppuLoc("scaleTrans"), 1, scaleTrans); 172 | 173 | glBindVertexArray(vao[0]); // reestablishes all buffer settings as noted above 174 | 175 | glUniform1i(shaderIF->ppuLoc("colorMode"), colorMode); 176 | glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices); 177 | 178 | // restore the previous program 179 | glUseProgram(pgm); 180 | } 181 | 182 | void ModelView::setMCRegionOfInterest(double xyz[6]) 183 | { 184 | for (int i=0 ; i<6 ; i++) 185 | mcRegionOfInterest[i] = xyz[i]; 186 | } 187 | --------------------------------------------------------------------------------