Compilation
========================================================================================

NanoGUI uses a CMake build system to ensure portability. All dependencies are
cloned and compiled in one batch, which should generally reduce the amount of
configuration effort to zero. Assuming that NanoGUI was cloned into the current
working directory, the following commands need to be executed:

.. code-block:: bash

   # enter the top-level NanoGUI directory
   $ cd nanogui

   # make a build directory and enter that
   $ mkdir build
   $ cd build

   # generate your Makefile
   $ cmake ..

   # now that you have a Makefile, use that to build
   $ make -j 4

For Windows, the process is nearly the same:

.. code-block:: bash

   # enter the top-level NanoGUI directory
   $ cd nanogui

   # make a build directory and enter that
   $ mkdir build
   $ cd build

   # Specify VS Version AND 64bit, otherwise it defaults to 32.
   # The version number and year may be different for you, Win64
   # can be appended to any of them.  Execute `cmake -G` to get
   # a listing of the available generators.
   #
   # 32 bit Windows builds are /not/ supported
   $ cmake -G "Visual Studio 14 2015 Win64" ..

   # Either open the .sln with Visual Studio, or run
   $ cmake --build . --config Release

Default Configurations
----------------------------------------------------------------------------------------

By default, NanoGUI will

+---------------------------------+---------------------------+
| Impact / effect                 | CMake Option              |
+=================================+===========================+
| Build the example programs.     | ``NANOGUI_BUILD_EXAMPLE`` |
+---------------------------------+---------------------------+
| Build as a *shared* library.    | ``NANOGUI_BUILD_SHARED``  |
+---------------------------------+---------------------------+
| Build the Python plugins.       | ``NANOGUI_BUILD_PYTHON``  |
+---------------------------------+---------------------------+
| Use GLAD if on Windows.         | ``NANOGUI_USE_GLAD``      |
+---------------------------------+---------------------------+
| Generate an ``install`` target. | ``NANOGUI_INSTALL``       |
+---------------------------------+---------------------------+

Users developing projects that reference NanoGUI as a ``git submodule`` (this
is **strongly** encouraged) can set up the parent project's CMake configuration
file as follows (this assumes that ``nanogui`` lives in the directory
``ext/nanogui`` relative to the parent project):

.. code-block:: cmake

    # Disable building extras we won't need (pure C++ project)
    set(NANOGUI_BUILD_EXAMPLE OFF CACHE BOOL " " FORCE)
    set(NANOGUI_BUILD_PYTHON  OFF CACHE BOOL " " FORCE)
    set(NANOGUI_INSTALL       OFF CACHE BOOL " " FORCE)

    # Add the configurations from nanogui
    add_subdirectory(ext/nanogui)

    # For reliability of parallel build, make the NanoGUI targets dependencies
    set_property(TARGET glfw glfw_objects nanogui PROPERTY FOLDER "dependencies")

Required Variables Exposed
----------------------------------------------------------------------------------------

Due to the nature of building an OpenGL application for different platforms, three
variables are populated to allow for easy incorporation with your CMake build.  After
you have executed ``add_subdirectory`` as shown above, you will need to add the
following (assuming the target you are building is called ``myTarget``):

.. code-block:: cmake

   # Various preprocessor definitions have been generated by NanoGUI
   add_definitions(${NANOGUI_EXTRA_DEFS})

   # On top of adding the path to nanogui/include, you may need extras
   include_directories(${NANOGUI_EXTRA_INCS})

   # Compile a target using NanoGUI
   add_executable(myTarget myTarget.cpp)

   # Lastly, additional libraries may have been built for you.  In addition to linking
   # against NanoGUI, we need to link against those as well.
   target_link_libraries(myTarget nanogui ${NANOGUI_EXTRA_LIBS})

Advanced Compilation Details
----------------------------------------------------------------------------------------

NanoGUI and Python
****************************************************************************************

Although it is |year|, you may still for example wish to build the Python bindings for
Python 2.7.  The variable you would set **before** ``add_subdirectory`` is
``NANOGUI_PYTHON_VERSION``.  For example,

.. code-block:: cmake

   set(NANOGUI_PYTHON_VERSION "2.7")
   # can also use minor versions
   set(NANOGUI_PYTHON_VERSION "3.6.2")


NanoGUI and Eigen
****************************************************************************************

NanoGUI uses Eigen_ internally for various vector types.  Eigen is an advanced header
only template library, which NanoGUI vendors in the ``ext`` folder.  It is important to
understand the implication of Eigen being header only: **only one version of Eigen can
be included**.

There is a CMake bypass variable available in NanoGUI: ``NANOGUI_EIGEN_INCLUDE_DIR``.
You would set this variable **before** ``add_subdirectory``.  Since you will want to
provide the same kind of bypass for users of your library, the following snippet is a
good starting point.  For this example code:

1. The parent CMake project is called ``myproj``.  A good CMake practice to adopt is to
   prefix your project's name to any variables you intend to expose.  This allows parent
   projects to know where the variable came from, and avoids name collisions.
2. First ``find_package`` is used to try and find Eigen.  The philosophy is that the
   user is responsible for ensuring that the version of Eigen they want to use will be
   found.
3. Since NanoGUI needs to remain self-contained, the side-effect is that even if the
   user does *not* have Eigen installed, you can fallback and use the one vendored with
   NanoGUI.
4. The following directory structure:

   .. code-block:: none

      myproj/
          CMakeLists.txt         <- Where this example code is
          ext/
              nanogui/
                  CMakeLists.txt <- NanoGUI's build system
                  ext/
                      eigen/     <- NanoGUI's internal copy of Eigen


.. code-block:: cmake

   # `if NOT` is what enables the same bypass for your project
   if(NOT MYPROJ_EIGEN3_INCLUDE_DIR)
     # Grab or find the Eigen3 include directory.
     find_package(Eigen3 QUIET)
     if(EIGEN3_INCLUDE_DIR)
       set(MYPROJ_EIGEN3_INCLUDE_DIR ${EIGEN3_INCLUDE_DIR})
     else()
       # use the internal NanoGUI copy of Eigen
       set(MYPROJ_EIGEN3_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/nanogui/ext/eigen)
     endif()
   endif()

   message(STATUS "Using Eigen3 from directory: ${MYPROJ_EIGEN3_INCLUDE_DIR}")
   set(NANOGUI_EIGEN_INCLUDE_DIR ${EIGEN3_INCLUDE_DIR} CACHE BOOL " " FORCE)
   # set any other NanoGUI specific variables you need (shown in above sections)
   add_subdirectory(ext/nanogui)

   # include it for your project as well (or append to a list
   # and include that list later, depending on your setup)
   include_directories(${MYPROJ_EIGEN3_INCLUDE_DIR})

.. _Eigen: https://eigen.tuxfamily.org/dox/

NanoGUI, GLFW, and Other Projects
****************************************************************************************

Suppose you want to use NanoGUI as your GUI toolkit, but you also have another library
you want to use that depends on ``glfw``.  Call the second library Foo.  Generally
speaking, it is unlikely that library Foo will provide you with mechanisms to explicitly
specify where ``glfw`` comes from.  You could try to work on a patch with the developers
of library Foo to allow this to be overridden, but you may need to maintain your own
fork of library Foo.  There is just as much justification to allow the bypass as there
is to not want it in a build system.

Since NanoGUI merges the ``glfw`` objects into the library being built, you can actually
just specify ``nanogui`` as the ``glfw`` dependency directly.  So lets suppose that
library Foo was looking for ``glfw`` like this:

.. code-block:: cmake

   find_package(GLFW3)
   if(GLFW3_FOUND)
     include_directories(${GLFW3_INCLUDE_DIRS})
     target_link_libraries(foo ${GLFW3_LIBRARIES})
   endif()

You can cheat around this pretty easily.  For the modification to library Foo's build
system, all we do is wrap ``find_package``:

.. code-block:: diff

   + if(NOT GLFW3_FOUND)
       find_package(GLFW3)
   + endif()
     if(GLFW3_FOUND)
       include_directories(${GLFW3_INCLUDE_DIRS})
       target_link_libraries(foo ${GLFW3_LIBRARIES})
     endif()

Now that ``find_package`` will only execute if ``NOT GLFW3_FOUND``, in your build system
you make sure to set all three ``glfw`` variables (found, include, and libraries).  It
might look something like this:

.. code-block:: cmake

   # ... any other nanogui configs ...
   # same directory structure as Eigen example
   add_subdirectory(ext/nanogui)

   # nanogui needs to be added first so the 'nanogui' target is defined
   # and can be used in the generator expression for the libraries
   set(GLFW3_FOUND ON)
   set(GLFW3_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ext/nanogui/ext/glfw/include)
   set(GLFW3_LIBRARIES $<TARGET_FILE:nanogui>)

   add_subdirectory(ext/foo)

   # IMPORTANT! You need to force NanoGUI to build first
   # Assuming their library target is called 'foo'
   add_dependencies(foo nanogui)


Depending on what you need to do, the above may not be sufficient.  But it is at least
a starting point to being able to "share" NanoGUI as the vendor of ``glfw``.

.. _nanogui_including_custom_fonts:

Including Custom Fonts
****************************************************************************************

NanoGUI uses the Roboto_ font for text, and Entypo_ font for icons.  If you wish to add
your own custom font, all you need is a True Type file (a ``.ttf`` extension).  NanoGUI
will glob all fonts found in ``resources`` by expanding ``resources/*.ttf``.  So if you
had the directory structure

.. code-block:: none

   myproject/
       CMakeLists.txt      <- where this code is
       fonts/
           superfont.ttf
       ext/
           nanogui/
               resources/

You simply need to copy the ``superfont.ttf`` to NanoGUI's resources directory:

.. code-block:: cmake

   file(
     COPY ${CMAKE_CURRENT_SOURCE_DIR}/fonts/superfont.ttf
     DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/ext/nanogui/resources/superfont.ttf
   )

When you build the code, there should be a file ``nanogui_resources.h`` generated.  If
everything worked, your new font should have been included.

.. note::

   Since NanoGUI can support images as icons, you will want to make sure that the
   *codepoint* for any *icon* fonts you create is greater than ``1024``.  See
   :func:`nanogui::nvgIsImageIcon`.

.. tip::

   Some widgets allow you to set fonts directly, but if you want to apply the font
   globally, you should create a sub-class of :class:`nanogui::Theme` and explicitly
   call :func:`nanogui::Widget::setTheme` for each widget you create.

.. _Roboto: https://fonts.google.com/specimen/Roboto

.. _Entypo: http://www.entypo.com

.. _utf8: http://www.utf8-chartable.de/

.. _nanogui_compiling_the_docs:

Compiling the Documentation
----------------------------------------------------------------------------------------

The documentation system relies on 'Doxygen', 'Sphinx', 'Breathe', and
'Exhale'.  It uses the 'Read the Docs' theme for the layout of the generated
html.  So you will need to first

1. Install Doxygen for your operating system.  On Unix based systems, this
   should be available through your package manager (apt-get, brew, dnf, etc).

2. Install Sphinx, Breathe, Exhale, and the theme:

   .. code-block:: py

      pip3 install -r <path/to/nanogui>/docs/requirements.txt

Now that you have the relevant tools, you can build the documentation with

.. code-block:: bash

   # Enter the documentation directory
   $ cd <path/to/nanogui>/docs

   # Build the documentation
   $ make html

The output will be generated in ``_build``, the root html document is located
at ``_build/html/index.html``.

.. note::

   When building the documentation locally, there can be subtle differences in
   the rendered pages than what is hosted online.  You should largely be able
   to ignore this.
