-
Notifications
You must be signed in to change notification settings - Fork 605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix screen for applications that want to manage their own glfw and not rely on nanogui #91
Changes from 8 commits
972c471
3f11784
f925cdc
435c91b
20d8559
641c8f0
5584b32
efe7ef2
f0a1c74
b304307
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/* | ||
src/example3.cpp -- C++ version of an example application that shows | ||
how to use nanogui in an application with an already created and managed | ||
glfw context. | ||
|
||
NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>. | ||
The widget drawing code is based on the NanoVG demo application | ||
by Mikko Mononen. | ||
|
||
All rights reserved. Use of this source code is governed by a | ||
BSD-style license that can be found in the LICENSE.txt file. | ||
*/ | ||
|
||
// GLFW | ||
#include <GLFW/glfw3.h> | ||
|
||
#include <nanogui/nanogui.h> | ||
#include <iostream> | ||
|
||
using namespace nanogui; | ||
|
||
enum test_enum { | ||
Item1 = 0, | ||
Item2, | ||
Item3 | ||
}; | ||
|
||
bool bvar = true; | ||
int ivar = 12345678; | ||
double dvar = 3.1415926; | ||
float fvar = (float)dvar; | ||
std::string strval = "A string"; | ||
test_enum enumval = Item2; | ||
Color colval(0.5f, 0.5f, 0.7f, 1.f); | ||
|
||
Screen *screen = nullptr; | ||
|
||
int main(int /* argc */, char ** /* argv */) { | ||
|
||
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); | ||
|
||
// Create a GLFWwindow object | ||
GLFWwindow* window = glfwCreateWindow(800, 800, "example3", nullptr, nullptr); | ||
if (window == nullptr) { | ||
std::cout << "Failed to create GLFW window" << std::endl; | ||
glfwTerminate(); | ||
return -1; | ||
} | ||
glfwMakeContextCurrent(window); | ||
|
||
int width, height; | ||
glfwGetFramebufferSize(window, &width, &height); | ||
glViewport(0, 0, width, height); | ||
glfwSwapInterval(0); | ||
glfwSwapBuffers(window); | ||
|
||
// Create a nanogui screen and pass the glfw pointer to initialize | ||
screen = new Screen(); | ||
screen->initialize(window, true); | ||
|
||
// Create nanogui gui | ||
bool enabled = true; | ||
FormHelper *gui = new FormHelper(screen); | ||
ref<Window> nanoguiWindow = gui->addWindow(Eigen::Vector2i(10, 10), "Form helper example"); | ||
gui->addGroup("Basic types"); | ||
gui->addVariable("bool", bvar)->setTooltip("Test tooltip."); | ||
gui->addVariable("string", strval); | ||
|
||
gui->addGroup("Validating fields"); | ||
gui->addVariable("int", ivar)->setSpinnable(true); | ||
gui->addVariable("float", fvar)->setTooltip("Test."); | ||
gui->addVariable("double", dvar)->setSpinnable(true); | ||
|
||
gui->addGroup("Complex types"); | ||
gui->addVariable("Enumeration", enumval, enabled)->setItems({ "Item 1", "Item 2", "Item 3" }); | ||
gui->addVariable("Color", colval); | ||
|
||
gui->addGroup("Other widgets"); | ||
gui->addButton("A button", []() { std::cout << "Button pressed." << std::endl; })->setTooltip("Testing a much longer tooltip, that will wrap around to new lines multiple times.");; | ||
|
||
screen->setVisible(true); | ||
screen->performLayout(); | ||
nanoguiWindow->center(); | ||
|
||
|
||
glfwSetCursorPosCallback(window, | ||
[](GLFWwindow *w, double x, double y) { | ||
screen->cursorPosCallbackEvent(x, y); | ||
} | ||
); | ||
|
||
glfwSetMouseButtonCallback(window, | ||
[](GLFWwindow *w, int button, int action, int modifiers) { | ||
screen->mouseButtonCallbackEvent(button, action, modifiers); | ||
} | ||
); | ||
|
||
glfwSetKeyCallback(window, | ||
[](GLFWwindow *w, int key, int scancode, int action, int mods) { | ||
screen->keyCallbackEvent(key, scancode, action, mods); | ||
} | ||
); | ||
|
||
glfwSetCharCallback(window, | ||
[](GLFWwindow *w, unsigned int codepoint) { | ||
screen->charCallbackEvent(codepoint); | ||
} | ||
); | ||
|
||
glfwSetDropCallback(window, | ||
[](GLFWwindow *w, int count, const char **filenames) { | ||
screen->dropCallbackEvent(count, filenames); | ||
} | ||
); | ||
|
||
glfwSetScrollCallback(window, | ||
[](GLFWwindow *w, double x, double y) { | ||
screen->scrollCallbackEvent(x, y); | ||
} | ||
); | ||
|
||
glfwSetFramebufferSizeCallback(window, | ||
[](GLFWwindow* w, int width, int height) { | ||
screen->resizeCallbackEvent(width, height); | ||
} | ||
); | ||
|
||
// Game loop | ||
while (!glfwWindowShouldClose(window)) { | ||
// Check if any events have been activated (key pressed, mouse moved etc.) and call corresponding response functions | ||
glfwPollEvents(); | ||
|
||
glClearColor(0.2f, 0.25f, 0.3f, 1.0f); | ||
glClear(GL_COLOR_BUFFER_BIT); | ||
|
||
// Draw nanogui | ||
screen->drawContents(); | ||
screen->drawWidgets(); | ||
|
||
glfwSwapBuffers(window); | ||
} | ||
|
||
// Terminate GLFW, clearing any resources allocated by GLFW. | ||
glfwTerminate(); | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,7 +73,7 @@ static float get_pixel_ratio(GLFWwindow *window) { | |
Screen::Screen() | ||
: Widget(nullptr), mGLFWWindow(nullptr), mNVGContext(nullptr), | ||
mCursor(Cursor::Arrow), mBackground(0.3f, 0.3f, 0.32f), | ||
mShutdownGLFWOnDestruct(false), mFullscreen(false) { | ||
mShutdownGLFWOnDestruct(false), mFullscreen(false), mOwningGLFWContext(false) { | ||
memset(mCursors, 0, sizeof(GLFWcursor *) * (int) Cursor::CursorCount); | ||
} | ||
|
||
|
@@ -83,7 +83,7 @@ Screen::Screen(const Vector2i &size, const std::string &caption, bool resizable, | |
unsigned int glMajor, unsigned int glMinor) | ||
: Widget(nullptr), mGLFWWindow(nullptr), mNVGContext(nullptr), | ||
mCursor(Cursor::Arrow), mBackground(0.3f, 0.3f, 0.32f), mCaption(caption), | ||
mShutdownGLFWOnDestruct(false), mFullscreen(fullscreen) { | ||
mShutdownGLFWOnDestruct(false), mFullscreen(fullscreen), mOwningGLFWContext(true) { | ||
memset(mCursors, 0, sizeof(GLFWcursor *) * (int) Cursor::CursorCount); | ||
|
||
/* Request a forward compatible OpenGL glMajor.glMinor core profile context. | ||
|
@@ -252,6 +252,15 @@ void Screen::initialize(GLFWwindow *window, bool shutdownGLFWOnDestruct) { | |
glfwSetWindowSize(window, mSize.x() * mPixelRatio, mSize.y() * mPixelRatio); | ||
#endif | ||
|
||
#if defined(NANOGUI_GLAD) | ||
if (!gladInitialized) { | ||
gladInitialized = true; | ||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) | ||
throw std::runtime_error("Could not initialize GLAD!"); | ||
glGetError(); // pull and ignore unhandled errors like GL_INVALID_ENUM | ||
} | ||
#endif | ||
|
||
/* Detect framebuffer properties and set up compatible NanoVG context */ | ||
GLint nStencilBits = 0, nSamples = 0; | ||
glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, | ||
|
@@ -300,10 +309,12 @@ void Screen::setVisible(bool visible) { | |
if (mVisible != visible) { | ||
mVisible = visible; | ||
|
||
if (visible) | ||
glfwShowWindow(mGLFWWindow); | ||
else | ||
glfwHideWindow(mGLFWWindow); | ||
if (mOwningGLFWContext) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why disable setVisible() for non-owned GLFW context? I think it would be quite reasonable to leave this on. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I am managing my own GLFW and windowing code, and just using a pointer to a 'screen' object for my GUI, having the whole window hidden just because I call: screen->setVisible(false) is misleading, what if I just want to hide the GUI alone, but keep my true window visible? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, |
||
if (visible) | ||
glfwShowWindow(mGLFWWindow); | ||
else | ||
glfwHideWindow(mGLFWWindow); | ||
} | ||
} | ||
} | ||
|
||
|
@@ -368,20 +379,27 @@ void Screen::drawWidgets() { | |
float bounds[4]; | ||
nvgFontFace(mNVGContext, "sans"); | ||
nvgFontSize(mNVGContext, 15.0f); | ||
nvgTextAlign(mNVGContext, NVG_ALIGN_CENTER | NVG_ALIGN_TOP); | ||
nvgTextAlign(mNVGContext, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); | ||
nvgTextLineHeight(mNVGContext, 1.1f); | ||
Vector2i pos = widget->absolutePosition() + | ||
Vector2i(widget->width() / 2, widget->height() + 10); | ||
|
||
nvgTextBoxBounds(mNVGContext, pos.x(), pos.y(), tooltipWidth, | ||
widget->tooltip().c_str(), nullptr, bounds); | ||
nvgTextBounds(mNVGContext, pos.x(), pos.y(), | ||
widget->tooltip().c_str(), nullptr, bounds); | ||
int h = (bounds[2] - bounds[0]) / 2; | ||
if (h > tooltipWidth / 2) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Super-minor: brace should be on previous line. |
||
nvgTextAlign(mNVGContext, NVG_ALIGN_CENTER | NVG_ALIGN_TOP); | ||
nvgTextBoxBounds(mNVGContext, pos.x(), pos.y(), tooltipWidth, | ||
widget->tooltip().c_str(), nullptr, bounds); | ||
|
||
h = (bounds[2] - bounds[0]) / 2; | ||
} | ||
nvgGlobalAlpha(mNVGContext, | ||
std::min(1.0, 2 * (elapsed - 0.5f)) * 0.8); | ||
|
||
nvgBeginPath(mNVGContext); | ||
nvgFillColor(mNVGContext, Color(0, 255)); | ||
int h = (bounds[2] - bounds[0]) / 2; | ||
nvgRoundedRect(mNVGContext, bounds[0] - 4 - h, bounds[1] - 4, | ||
(int) (bounds[2] - bounds[0]) + 8, | ||
(int) (bounds[3] - bounds[1]) + 8, 3); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super-minor: lambda function body and the following brace should be indented by another 4 spaces here and below.