├── 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 |
--------------------------------------------------------------------------------