/* nanogui/common.h -- common definitions used by NanoGUI NanoGUI was developed by Wenzel Jakob . 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. */ /** \file */ #pragma once #include #include #include #include /* Set to 1 to draw boxes around widgets */ //#define NANOGUI_SHOW_WIDGET_BOUNDS 1 #if !defined(NAMESPACE_BEGIN) || defined(DOXYGEN_DOCUMENTATION_BUILD) /** * \brief Convenience macro for namespace declarations * * The macro ``NAMESPACE_BEGIN(nanogui)`` will expand to ``namespace * nanogui {``. This is done to hide the namespace scope from editors and * C++ code formatting tools that may otherwise indent the entire file. * The corresponding ``NAMESPACE_END`` macro also lists the namespace * name for improved readability. * * \param name * The name of the namespace scope to open */ #define NAMESPACE_BEGIN(name) namespace name { #endif #if !defined(NAMESPACE_END) || defined(DOXYGEN_DOCUMENTATION_BUILD) /** * \brief Convenience macro for namespace declarations * * Closes a namespace (counterpart to ``NAMESPACE_BEGIN``) * ``NAMESPACE_END(nanogui)`` will expand to only ``}``. * * \param name * The name of the namespace scope to close */ #define NAMESPACE_END(name) } #endif #if defined(NANOGUI_SHARED) # if defined(_WIN32) # if defined(NANOGUI_BUILD) # define NANOGUI_EXPORT __declspec(dllexport) # else # define NANOGUI_EXPORT __declspec(dllimport) # endif # elif defined(NANOGUI_BUILD) # define NANOGUI_EXPORT __attribute__ ((visibility("default"))) # else # define NANOGUI_EXPORT # endif #else /** * If the build flag ``NANOGUI_SHARED`` is defined, this directive will expand * to be the platform specific shared library import / export command depending * on the compilation stage. If undefined, it expands to nothing. **Do not** * define this directive on your own. */ # define NANOGUI_EXPORT #endif /* Force usage of discrete GPU on laptops (macro must be invoked in main application) */ #if defined(_WIN32) #define NANOGUI_FORCE_DISCRETE_GPU() \ extern "C" { \ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; \ __declspec(dllexport) int NvOptimusEnablement = 1; \ } #else /** * On Windows, exports ``AmdPowerXpressRequestHighPerformance`` and * ``NvOptimusEnablement`` as ``1``. */ #define NANOGUI_FORCE_DISCRETE_GPU() #endif #if defined(_WIN32) #if defined(NANOGUI_BUILD) /* Quench a few warnings on when compiling NanoGUI on Windows */ #pragma warning(disable : 4127) // warning C4127: conditional expression is constant #pragma warning(disable : 4244) // warning C4244: conversion from X to Y, possible loss of data #endif #pragma warning(disable : 4251) // warning C4251: class X needs to have dll-interface to be used by clients of class Y #pragma warning(disable : 4714) // warning C4714: function X marked as __forceinline not inlined #endif // These will produce broken links in the docs build #ifndef DOXYGEN_SHOULD_SKIP_THIS struct NVGcontext { /* Opaque handle type, never de-referenced within NanoGUI */ }; struct GLFWwindow { /* Opaque handle type, never de-referenced within NanoGUI */ }; struct NVGcolor; struct NVGglyphPosition; struct GLFWcursor; #endif // DOXYGEN_SHOULD_SKIP_THIS // Define command key for windows/mac/linux #ifdef __APPLE__ /// If on OSX, maps to ``GLFW_MOD_SUPER``. Otherwise, maps to ``GLFW_MOD_CONTROL``. #define SYSTEM_COMMAND_MOD GLFW_MOD_SUPER #else /// If on OSX, maps to ``GLFW_MOD_SUPER``. Otherwise, maps to ``GLFW_MOD_CONTROL``. #define SYSTEM_COMMAND_MOD GLFW_MOD_CONTROL #endif NAMESPACE_BEGIN(nanogui) /// Cursor shapes available to use in GLFW. enum class Cursor { Arrow = 0, IBeam, Crosshair, Hand, HResize, VResize, /// Not a cursor --- should always be last: enables a loop over the cursor types. CursorCount }; /* Import some common Eigen types */ using Eigen::Vector2f; using Eigen::Vector3f; using Eigen::Vector4f; using Eigen::Vector2i; using Eigen::Vector3i; using Eigen::Vector4i; using Eigen::Matrix3f; using Eigen::Matrix4f; using Eigen::VectorXf; using Eigen::MatrixXf; /** * Convenience typedef for things like index buffers. You would use it the same * as ``Eigen::MatrixXf``, only it is storing ``uint32_t`` instead of ``float``. */ typedef Eigen::Matrix MatrixXu; /** * \class Color common.h nanogui/common.h * * \brief Stores an RGBA floating point color value. * * This class simply wraps around an ``Eigen::Vector4f``, providing some convenient * methods and terminology for thinking of it as a color. The data operates in the * same way as ``Eigen::Vector4f``, and the following values are identical: * * \rst * +---------+-------------+-----------------------+-------------+ * | Channel | Array Index | Eigen::Vector4f Value | Color Value | * +=========+=============+=======================+=============+ * | Red | ``0`` | x() | r() | * +---------+-------------+-----------------------+-------------+ * | Green | ``1`` | y() | g() | * +---------+-------------+-----------------------+-------------+ * | Blue | ``2`` | z() | b() | * +---------+-------------+-----------------------+-------------+ * | Alpha | ``3`` | w() | w() | * +---------+-------------+-----------------------+-------------+ * * .. note:: * The method for the alpha component is **always** ``w()``. * \endrst * * You can and should still use the various convenience methods such as ``any()``, * ``all()``, ``head()``, etc provided by Eigen. */ class Color : public Eigen::Vector4f { typedef Eigen::Vector4f Base; public: /// Default constructor: represents black (``r, g, b, a = 0``) Color() : Color(0, 0, 0, 0) {} /** * Makes an exact copy of the data represented by the input parameter. * * \param color * The four dimensional float vector being copied. */ Color(const Eigen::Vector4f &color) : Eigen::Vector4f(color) { } /** * Copies (x, y, z) from the input vector, and uses the value specified by * the ``alpha`` parameter for this Color object's alpha component. * * \param color * The three dimensional float vector being copied. * * \param alpha * The value to set this object's alpha component to. */ Color(const Eigen::Vector3f &color, float alpha) : Color(color(0), color(1), color(2), alpha) { } /** * Copies (x, y, z) from the input vector, casted as floats first and then * divided by ``255.0``, and uses the value specified by the ``alpha`` * parameter, casted to a float and divided by ``255.0`` as well, for this * Color object's alpha component. * * \param color * The three dimensional integer vector being copied, will be divided by ``255.0``. * * \param alpha * The value to set this object's alpha component to, will be divided by ``255.0``. */ Color(const Eigen::Vector3i &color, int alpha) : Color(color.cast() / 255.f, alpha / 255.f) { } /** * Copies (x, y, z) from the input vector, and sets the alpha of this color * to be ``1.0``. * * \param color * The three dimensional float vector being copied. */ Color(const Eigen::Vector3f &color) : Color(color, 1.0f) {} /** * Copies (x, y, z) from the input vector, casting to floats and dividing by * ``255.0``. The alpha of this color will be set to ``1.0``. * * \param color * The three dimensional integer vector being copied, will be divided by ``255.0``. */ Color(const Eigen::Vector3i &color) : Color((Vector3f)(color.cast() / 255.f)) { } /** * Copies (x, y, z, w) from the input vector, casting to floats and dividing * by ``255.0``. * * \param color * The three dimensional integer vector being copied, will be divided by ``255.0``. */ Color(const Eigen::Vector4i &color) : Color((Vector4f)(color.cast() / 255.f)) { } /** * Creates the Color ``(intensity, intensity, intensity, alpha)``. * * \param intensity * The value to be used for red, green, and blue. * * \param alpha * The alpha component of the color. */ Color(float intensity, float alpha) : Color(Vector3f::Constant(intensity), alpha) { } /** * Creates the Color ``(intensity, intensity, intensity, alpha) / 255.0``. * Values are casted to floats before division. * * \param intensity * The value to be used for red, green, and blue, will be divided by ``255.0``. * * \param alpha * The alpha component of the color, will be divided by ``255.0``. */ Color(int intensity, int alpha) : Color(Vector3i::Constant(intensity), alpha) { } /** * Explicit constructor: creates the Color ``(r, g, b, a)``. * * \param r * The red component of the color. * * \param g * The green component of the color. * * \param b * The blue component of the color. * * \param a * The alpha component of the color. */ Color(float r, float g, float b, float a) : Color(Vector4f(r, g, b, a)) { } /** * Explicit constructor: creates the Color ``(r, g, b, a) / 255.0``. * Values are casted to floats before division. * * \param r * The red component of the color, will be divided by ``255.0``. * * \param g * The green component of the color, will be divided by ``255.0``. * * \param b * The blue component of the color, will be divided by ``255.0``. * * \param a * The alpha component of the color, will be divided by ``255.0``. */ Color(int r, int g, int b, int a) : Color(Vector4i(r, g, b, a)) { } /// Construct a color vector from MatrixBase (needed to play nice with Eigen) template Color(const Eigen::MatrixBase& p) : Base(p) { } /// Assign a color vector from MatrixBase (needed to play nice with Eigen) template Color &operator=(const Eigen::MatrixBase& p) { this->Base::operator=(p); return *this; } /// Return a reference to the red channel float &r() { return x(); } /// Return a reference to the red channel (const version) const float &r() const { return x(); } /// Return a reference to the green channel float &g() { return y(); } /// Return a reference to the green channel (const version) const float &g() const { return y(); } /// Return a reference to the blue channel float &b() { return z(); } /// Return a reference to the blue channel (const version) const float &b() const { return z(); } /** * Computes the luminance as ``l = 0.299r + 0.587g + 0.144b + 0.0a``. If * the luminance is less than 0.5, white is returned. If the luminance is * greater than or equal to 0.5, black is returned. Both returns will have * an alpha component of 1.0. */ Color contrastingColor() const { float luminance = cwiseProduct(Color(0.299f, 0.587f, 0.144f, 0.f)).sum(); return Color(luminance < 0.5f ? 1.f : 0.f, 1.f); } /// Allows for conversion between this Color and NanoVG's representation. inline operator const NVGcolor &() const; }; // skip the forward declarations for the docs #ifndef DOXYGEN_SHOULD_SKIP_THIS /* Forward declarations */ template class ref; class AdvancedGridLayout; class BoxLayout; class Button; class CheckBox; class ColorWheel; class ColorPicker; class ComboBox; class GLFramebuffer; class GLShader; class GridLayout; class GroupLayout; class ImagePanel; class ImageView; class Label; class Layout; class MessageDialog; class Object; class Popup; class PopupButton; class ProgressBar; class Screen; class Serializer; class Slider; class StackedWidget; class TabHeader; class TabWidget; class TextBox; class Theme; class ToolButton; class VScrollPanel; class Widget; class Window; #endif // DOXYGEN_SHOULD_SKIP_THIS /** * Static initialization; should be called once before invoking **any** NanoGUI * functions **if** you are having NanoGUI manage OpenGL / GLFW. This method * is effectively a wrapper call to ``glfwInit()``, so if you are managing * OpenGL / GLFW on your own *do not call this method*. * * \rst * Refer to :ref:`nanogui_example_3` for how you might go about managing OpenGL * and GLFW on your own, while still using NanoGUI's classes. * \endrst */ extern NANOGUI_EXPORT void init(); /// Static shutdown; should be called before the application terminates. extern NANOGUI_EXPORT void shutdown(); /** * \brief Enter the application main loop * * \param refresh * NanoGUI issues a redraw call whenever an keyboard/mouse/.. event is * received. In the absence of any external events, it enforces a redraw * once every ``refresh`` milliseconds. To disable the refresh timer, * specify a negative value here. * * \param detach * This pararameter only exists in the Python bindings. When the active * \c Screen instance is provided via the \c detach parameter, the * ``mainloop()`` function becomes non-blocking and returns * immediately (in this case, the main loop runs in parallel on a newly * created thread). This feature is convenient for prototyping user * interfaces on an interactive Python command prompt. When * ``detach != None``, the function returns an opaque handle that * will release any resources allocated by the created thread when the * handle's ``join()`` method is invoked (or when it is garbage * collected). * * \remark * Unfortunately, Mac OS X strictly requires all event processing to take * place on the application's main thread, which is fundamentally * incompatible with this type of approach. Thus, NanoGUI relies on a * rather crazy workaround on Mac OS (kudos to Dmitriy Morozov): * ``mainloop()`` launches a new thread as before but then uses * libcoro to swap the thread execution environment (stack, registers, ..) * with the main thread. This means that the main application thread is * hijacked and processes events in the main loop to satisfy the * requirements on Mac OS, while the thread that actually returns from this * function is the newly created one (paradoxical, as that may seem). * Deleting or ``join()``ing the returned handle causes application to * wait for the termination of the main loop and then swap the two thread * environments back into their initial configuration. */ extern NANOGUI_EXPORT void mainloop(int refresh = 50); /// Request the application main loop to terminate (e.g. if you detached mainloop). extern NANOGUI_EXPORT void leave(); /** * \brief Open a native file open/save dialog. * * \param filetypes * Pairs of permissible formats with descriptions like * ``("png", "Portable Network Graphics")``. * * \param save * Set to ``true`` if you would like subsequent file dialogs to open * at whatever folder they were in when they close this one. */ extern NANOGUI_EXPORT std::string file_dialog(const std::vector> &filetypes, bool save); #if defined(__APPLE__) || defined(DOXYGEN_DOCUMENTATION_BUILD) /** * \brief Move to the application bundle's parent directory * * This is function is convenient when deploying .app bundles on OSX. It * adjusts the file path to the parent directory containing the bundle. */ extern NANOGUI_EXPORT void chdir_to_bundle_parent(); #endif /** * \brief Convert a single UTF32 character code to UTF8. * * \rst * NanoGUI uses this to convert the icon character codes * defined in :ref:`file_include_nanogui_entypo.h`. * \endrst * * \param c * The UTF32 character to be converted. */ extern NANOGUI_EXPORT std::array utf8(int c); /// Load a directory of PNG images and upload them to the GPU (suitable for use with ImagePanel) extern NANOGUI_EXPORT std::vector> loadImageDirectory(NVGcontext *ctx, const std::string &path); /// Convenience function for instanting a PNG icon from the application's data segment (via bin2c) #define nvgImageIcon(ctx, name) nanogui::__nanogui_get_image(ctx, #name, name##_png, name##_png_size) /// Helper function used by nvgImageIcon extern NANOGUI_EXPORT int __nanogui_get_image(NVGcontext *ctx, const std::string &name, uint8_t *data, uint32_t size); NAMESPACE_END(nanogui)