summaryrefslogtreecommitdiffstats
path: root/dev/MinGfx/src/graphics_app.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dev/MinGfx/src/graphics_app.cc')
-rw-r--r--dev/MinGfx/src/graphics_app.cc467
1 files changed, 467 insertions, 0 deletions
diff --git a/dev/MinGfx/src/graphics_app.cc b/dev/MinGfx/src/graphics_app.cc
new file mode 100644
index 0000000..57405f5
--- /dev/null
+++ b/dev/MinGfx/src/graphics_app.cc
@@ -0,0 +1,467 @@
+/*
+ Copyright (c) 2017,2018 Regents of the University of Minnesota.
+ All Rights Reserved.
+ See corresponding header file for details.
+ */
+
+#include "graphics_app.h"
+
+
+namespace mingfx {
+
+
+
+GraphicsApp::GraphicsApp(int width, int height, const std::string &caption) :
+ graphicsInitialized_(false), width_(width), height_(height), caption_(caption), lastDrawT_(0.0),
+ leftDown_(false), middleDown_(false), rightDown_(false), screen_(NULL), window_(NULL)
+{
+}
+
+GraphicsApp::~GraphicsApp() {
+}
+
+void GraphicsApp::InitGraphicsContext() {
+
+ glfwInit();
+
+ glfwSetTime(0);
+
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+
+ glfwWindowHint(GLFW_SAMPLES, 0);
+ glfwWindowHint(GLFW_RED_BITS, 8);
+ glfwWindowHint(GLFW_GREEN_BITS, 8);
+ glfwWindowHint(GLFW_BLUE_BITS, 8);
+ glfwWindowHint(GLFW_ALPHA_BITS, 8);
+ glfwWindowHint(GLFW_STENCIL_BITS, 8);
+ glfwWindowHint(GLFW_DEPTH_BITS, 24);
+ glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
+
+
+ // on OSX, glfwCreateWindow bombs if we pass caption_.c_str() in for the 3rd
+ // parameter perhaps because it's const. so, copying to a tmp char array here.
+ char *title = new char[caption_.size() + 1];
+ for (int i = 0; i < caption_.size(); i++) {
+ title[i] = caption_[i];
+ }
+ title[caption_.size()] = '\0';
+ std::cout << caption_ << std::endl;
+
+ // Create a GLFWwindow object
+ window_ = glfwCreateWindow(width_, height_, title, NULL, NULL);
+ if (window_ == nullptr) {
+ std::cerr << "Failed to create GLFW window" << std::endl;
+ glfwTerminate();
+ exit(-1);
+ }
+ glfwMakeContextCurrent(window_);
+ glfwSetWindowUserPointer(window_, this);
+
+ // cleanup tmp title hack
+ delete [] title;
+
+
+#if defined(NANOGUI_GLAD)
+ if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
+ throw std::runtime_error("Could not initialize GLAD!");
+ glGetError(); // pull and ignore unhandled errors like GL_INVALID_ENUM
+#endif
+
+ glClearColor(0.2f, 0.25f, 0.3f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Create a nanogui screen and pass the glfw pointer to initialize
+ screen_ = new nanogui::Screen();
+ screen_->initialize(window_, true);
+
+ glfwGetFramebufferSize(window_, &width_, &height_);
+ glViewport(0, 0, width_, height_);
+ glfwSwapInterval(0);
+ glfwSwapBuffers(window_);
+
+ screen_->setVisible(true);
+ screen_->performLayout();
+
+ glfwSetCursorPosCallback(window_,
+ [](GLFWwindow *window, double x, double y) {
+ GraphicsApp *app = (GraphicsApp*)glfwGetWindowUserPointer(window);
+ app->cursor_pos_glfw_cb(x, y);
+ }
+ );
+
+ glfwSetMouseButtonCallback(window_,
+ [](GLFWwindow *window, int button, int action, int modifiers) {
+ GraphicsApp *app = (GraphicsApp*)glfwGetWindowUserPointer(window);
+ app->mouse_button_glfw_cb(button, action, modifiers);
+ }
+ );
+
+ glfwSetKeyCallback(window_,
+ [](GLFWwindow *window, int key, int scancode, int action, int mods) {
+ GraphicsApp *app = (GraphicsApp*)glfwGetWindowUserPointer(window);
+ app->key_glfw_cb(key, scancode, action, mods);
+ }
+ );
+
+ glfwSetCharCallback(window_,
+ [](GLFWwindow *window, unsigned int codepoint) {
+ GraphicsApp *app = (GraphicsApp*)glfwGetWindowUserPointer(window);
+ app->char_glfw_cb(codepoint);
+ }
+ );
+
+ glfwSetDropCallback(window_,
+ [](GLFWwindow *window, int count, const char **filenames) {
+ GraphicsApp *app = (GraphicsApp*)glfwGetWindowUserPointer(window);
+ app->drop_glfw_cb(count, filenames);
+ }
+ );
+
+ glfwSetScrollCallback(window_,
+ [](GLFWwindow *window, double x, double y) {
+ GraphicsApp *app = (GraphicsApp*)glfwGetWindowUserPointer(window);
+ app->scroll_glfw_cb(x, y);
+ }
+ );
+
+ glfwSetFramebufferSizeCallback(window_,
+ [](GLFWwindow *window, int width, int height) {
+ GraphicsApp *app = (GraphicsApp*)glfwGetWindowUserPointer(window);
+ app->resize_glfw_cb(width, height);
+ }
+ );
+
+ graphicsInitialized_ = true;
+ }
+
+
+
+void GraphicsApp::Run() {
+
+ if (!graphicsInitialized_) {
+ InitGraphicsContext();
+ }
+
+ InitNanoGUI();
+
+ InitOpenGL();
+
+ // Main program loop
+ glfwSetTime(0.0);
+ while (!glfwWindowShouldClose(window_)) {
+
+ // Poll for new user input events and call callbacks
+ glfwPollEvents();
+
+ // Update the simulation, i.e., perform all non-graphics updates that
+ // should happen each frame.
+ double now = glfwGetTime();
+ UpdateSimulation(now-lastDrawT_);
+ lastDrawT_ = now;
+
+ // Clear is handled in this mainloop so that drawing works even for
+ // users who do not want to fill in DrawUsingOpenGL()
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+ // NanoGUI sets these to something other than the OpenGL defaults, which
+ // screws up most OpenGL programs, so we need to reset them each frame here.
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glEnable(GL_DEPTH_TEST);
+
+ // Users may fill this in to do raw OpenGL rendering
+ DrawUsingOpenGL();
+
+ // This renders the nanogui widgets created on screen_
+ screen_->drawContents();
+ screen_->drawWidgets();
+
+ // Users may fill this in to do additional 2D rendering with the NanoVG library
+ DrawUsingNanoVG(screen_->nvgContext());
+
+ glfwSwapBuffers(window_);
+ }
+
+ glfwTerminate();
+}
+
+
+
+bool GraphicsApp::cursor_pos_glfw_cb(double x, double y) {
+
+ if (screen_->cursorPosCallbackEvent(x,y)) {
+ // event was handled by nanogui
+ lastMouse_ = Point2((float)x, (float)y);
+ return true;
+ }
+ else {
+ Point2 cur((float)x, (float)y);
+ Vector2 delta = cur - lastMouse_;
+
+ // if no buttons are down, generate a mouse move event
+ if (!leftDown_ && !middleDown_ && !rightDown_) {
+ mouse_move(cur, delta);
+ }
+
+ // if a button is down, generate a corresponding mouse drag event
+ if (leftDown_) {
+ left_mouse_drag(cur, delta);
+ }
+ if (middleDown_) {
+ middle_mouse_drag(cur, delta);
+ }
+ if (rightDown_) {
+ right_mouse_drag(cur, delta);
+ }
+
+ lastMouse_ = cur;
+ return false;
+ }
+}
+
+bool GraphicsApp::mouse_button_glfw_cb(int button, int action, int modifiers) {
+ if (screen_->mouseButtonCallbackEvent(button, action, modifiers)) {
+ return true;
+ }
+ else if (button == GLFW_MOUSE_BUTTON_LEFT) {
+ double x,y;
+ glfwGetCursorPos(window_, &x, &y);
+ if (action == 1) {
+ left_mouse_down(Point2((float)x, (float)y));
+ leftDown_ = true;
+ }
+ else {
+ left_mouse_up(Point2((float)x, (float)y));
+ leftDown_ = false;
+ }
+ return true;
+ }
+ else if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
+ double x,y;
+ glfwGetCursorPos(window_, &x, &y);
+ if (action == 1) {
+ middle_mouse_down(Point2((float)x, (float)y));
+ middleDown_ = true;
+ }
+ else {
+ middle_mouse_up(Point2((float)x, (float)y));
+ middleDown_ = false;
+ }
+ return true;
+ }
+ else if (button == GLFW_MOUSE_BUTTON_RIGHT) {
+ double x,y;
+ glfwGetCursorPos(window_, &x, &y);
+ if (action == 1) {
+ right_mouse_down(Point2((float)x, (float)y));
+ rightDown_ = true;
+ }
+ else {
+ right_mouse_up(Point2((float)x, (float)y));
+ rightDown_ = false;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool GraphicsApp::key_glfw_cb(int key, int scancode, int action, int modifiers) {
+ if (screen_->keyCallbackEvent(key, scancode, action, modifiers)) {
+ return true;
+ }
+ else {
+ if (glfwGetKeyName(key, scancode) != NULL) {
+ if (action == GLFW_PRESS) {
+ key_down(glfwGetKeyName(key, scancode), modifiers);
+ }
+ else if (action == GLFW_REPEAT) {
+ key_repeat(glfwGetKeyName(key, scancode), modifiers);
+ }
+ else {
+ key_up(glfwGetKeyName(key, scancode), modifiers);
+ }
+ return true;
+ }
+ else {
+ if (action == GLFW_PRESS) {
+ special_key_down(key, scancode, modifiers);
+ }
+ else if (action == GLFW_REPEAT) {
+ special_key_repeat(key, scancode, modifiers);
+ }
+ else {
+ special_key_up(key, scancode, modifiers);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool GraphicsApp::char_glfw_cb(unsigned int codepoint) {
+ if (screen_->charCallbackEvent(codepoint)) {
+ return true;
+ }
+ else {
+ // TODO: could add another virtual function to GraphicsApp to
+ // respond to this if needed
+ }
+ return false;
+}
+
+
+bool GraphicsApp::drop_glfw_cb(int count, const char **filenames) {
+ if (screen_->dropCallbackEvent(count, filenames)) {
+ return true;
+ }
+ else {
+ // TODO: could add another virtual function to GraphicsApp to
+ // respond to this if needed
+ }
+ return false;
+}
+
+
+bool GraphicsApp::scroll_glfw_cb(double x, double y) {
+ if (screen_->scrollCallbackEvent(x,y)) {
+ return true;
+ }
+ else {
+ // TODO: could add another virtual function to GraphicsApp to
+ // respond to this if needed
+ }
+ return false;
+}
+
+
+bool GraphicsApp::resize_glfw_cb(int width, int height) {
+ if (screen_->resizeCallbackEvent(width, height)) {
+ return true;
+ }
+ else {
+ // the width and height reported here are the new framebuffer size
+ // we will query/save/report the new window size instead
+ width_ = window_width();
+ height_ = window_height();
+ OnWindowResize(width_, height_);
+ }
+ return false;
+}
+
+
+bool GraphicsApp::IsKeyDown(int key) {
+ return (glfwGetKey(window_, key) == GLFW_PRESS);
+}
+
+bool GraphicsApp::IsLeftMouseDown() {
+ return (glfwGetMouseButton(window_, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+}
+
+
+bool GraphicsApp::IsMiddleMouseDown() {
+ return (glfwGetMouseButton(window_, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+}
+
+
+bool GraphicsApp::IsRightMouseDown() {
+ return (glfwGetMouseButton(window_, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+}
+
+
+
+float GraphicsApp::aspect_ratio() {
+ int width, height;
+ glfwGetFramebufferSize(window_, &width, &height);
+ return (float)width/(float)height;
+}
+
+int GraphicsApp::window_width() {
+ int width, height;
+ glfwGetWindowSize(window_, &width, &height);
+ return width;
+}
+
+int GraphicsApp::framebuffer_width() {
+ int width, height;
+ glfwGetFramebufferSize(window_, &width, &height);
+ return width;
+}
+
+int GraphicsApp::window_height() {
+ int width, height;
+ glfwGetWindowSize(window_, &width, &height);
+ return height;
+}
+
+int GraphicsApp::framebuffer_height() {
+ int width, height;
+ glfwGetFramebufferSize(window_, &width, &height);
+ return height;
+}
+
+Point2 GraphicsApp::PixelsToNormalizedDeviceCoords(const Point2 &pointInPixels) {
+ float x = (pointInPixels[0] / window_width()) * 2.0f - 1.0f;
+ float y = (1.0f - (pointInPixels[1] / window_height())) * 2.0f - 1.0f;
+ return Point2(x,y);
+}
+
+Point2 GraphicsApp::NormalizedDeviceCoordsToPixels(const Point2 &pointInNDC) {
+ float x = 0.5f * (pointInNDC[0] + 1.0f) * window_width();
+ float y = (1.0f - (0.5f * (pointInNDC[1] + 1.0f))) * window_height();
+ return Point2(x,y);
+}
+
+Vector2 GraphicsApp::PixelsToNormalizedDeviceCoords(const Vector2 &vectorInPixels) {
+ float x = (2.0f/window_width()) * vectorInPixels[0];
+ float y = (-2.0f/window_height()) * vectorInPixels[1];
+ return Vector2(x,y);
+}
+
+Vector2 GraphicsApp::NormalizedDeviceCoordsToPixels(const Vector2 &vectorInNDC) {
+ float x = (window_width()/2.0f) * vectorInNDC[0];
+ float y = (-window_height()/2.0f) * vectorInNDC[1];
+ return Vector2(x,y);
+}
+
+float GraphicsApp::ReadZValueAtPixel(const Point2 &pointInPixels, unsigned int whichBuffer) {
+ // scale screen points to framebuffer size, since they are not the same on retina displays
+ float x01 = pointInPixels[0] / window_width();
+ float y01 = pointInPixels[1] / window_height();
+ y01 = 1.0f - y01;
+
+ float x = x01 * (float)framebuffer_width();
+ float y = y01 * (float)framebuffer_height();
+
+ float z;
+ glReadPixels((int)x, (int)y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
+ return z;
+}
+
+
+nanogui::Screen* GraphicsApp::screen() {
+ return screen_;
+}
+
+GLFWwindow* GraphicsApp::window() {
+ return window_;
+}
+
+
+void GraphicsApp::ResizeWindow(int new_width, int new_height) {
+ glfwSetWindowSize(window_, new_width, new_height);
+ width_ = new_width;
+ height_ = new_height;
+ OnWindowResize(new_width, new_height);
+}
+
+
+
+
+
+} // end namespace