/******************************************************************************
 * Copyright 2018 NVIDIA Corporation. All rights reserved.
 *****************************************************************************/
/// \file
/// \brief Multi-view functionality

#ifndef NVIDIA_INDEX_IVIEWPORT_H
#define NVIDIA_INDEX_IVIEWPORT_H

#include <mi/dice.h>

namespace nv
{
namespace index
{

/// A viewport defines a two-dimensional area of a canvas where the
/// scene from a given DiCE scope should be rendered. Creating
/// multiple views allows to render the same scene or multiple scenes
/// with modifications side-by-side to one canvas.
///
/// Without the multi-view functionality, NVIDIA IndeX implicitly
/// uses a viewport that covers the entire canvas (\c IIndex_canvas)
/// and uses the global DiCE scope.
///
/// The DiCE scoping mechanism makes it possible to define multiple
/// versions of the same basic scene with different scene elements,
/// while sharing those scene elements that are the same in all
/// scopes. A simple example is setting a different camera for each
/// viewport while keeping the same scene. This is achieved by first
/// calling \c mi::neuraylib::IDice_transaction::localize() on the
/// \c ICamera and then modifying the camera separately for each
/// viewport scope. See the DiCE documentation for more details
/// about the scoping mechanism.
///
/// \note When creating new scene elements in a local scope, take
/// care that they are not accessed from other scopes, where they
/// are not visible and where an invalid tag access error would
/// happen.
///
/// As a best practice, it is advisable to create the basic scene in
/// the global scope, create multiple specialized versions of it in
/// local scopes and then assign the local scopes to viewports.
/// Scene changes that should be visible on all viewports can then
/// simply be made in the global scope. Note that the global scope
/// is not actually rendered in this scenario, only the local scopes
/// that inherit from it.
///
/// To support efficient handling of large distributed data, NVIDIA
/// IndeX makes some restrictions on how multiple scene scopes can
/// be defined:
///
/// - The scene in all viewport scopes must contain the same
///   distributed data scene elements (i.e. \c IRegular_volume, \c
///   IRegular_heightfield) and a warning will be printed during
///   rendering when such a scene element is missing from one
///   viewport scope. The scene elements may still be localized and
///   therefore differ between viewports, so it is possible to
///   enable a volume in some of the viewports but disable it in
///   others.
///
/// - Results of \c IDistributed_compute_technique will only be
///   shared between viewports when the compute technique is not
///   localized.
///
/// - When using \c Distributed_compute_technique to create volume
///   data, all viewports must use the same compute technique.
///   Otherwise data may be recomputed constantly.
///
/// - When the height values inside a heightfield are modified by an
///   \c IDistributed_compute_algorithm so that the bounding box of
///   the \c IRegular_heightfield changes, then the heightfield must
///   not be localized in any viewport scope.
///
/// - Volume slices, i.e. \c ISection_scene_element and \c
///   IVertical_profile_scene_element, have to be added to their
///   parent \c IRegular_volume in global scope.
///
/// @ingroup nv_index_rendering
///
class IViewport : public mi::base::Interface_declare<0x3dd9ae6f, 0x819d, 0x4c9c, 0xbb, 0x72, 0x7f,
                    0x5a, 0x8c, 0x49, 0xc7, 0x01>
{
public:
  /// Sets the DiCE scope that should be used for this viewport.
  ///
  /// \param[in] scope DiCE scope, this class takes ownership.
  virtual void set_scope(mi::neuraylib::IScope* scope) = 0;

  /// Returns the DiCE scope of this viewport.
  ///
  /// \return DiCE scope.
  virtual mi::neuraylib::IScope* get_scope() const = 0;

  /// Sets the anchor point of the viewport window on the
  /// \c IIndex_canvas.
  ///
  /// \param[in] anchor_position Lower left position of viewport window in pixels
  virtual void set_position(const mi::math::Vector_struct<mi::Sint32, 2>& anchor_position) = 0;

  /// Returns the anchor point of the viewport window on the
  /// \c IIndex_canvas in pixel
  ///
  /// \return Anchor point position
  virtual mi::math::Vector_struct<mi::Sint32, 2> get_position() const = 0;

  /// Sets the window size (resolution).
  ///
  /// \param[in] resolution Window resolution in pixels
  virtual void set_size(const mi::math::Vector_struct<mi::Sint32, 2>& resolution) = 0;

  /// Return the window size (resolution).
  ///
  /// \return Window resolution in pixels
  virtual mi::math::Vector_struct<mi::Sint32, 2> get_size() const = 0;
};

/// Defines a list of viewports that will be rendered onto a canvas.
///
/// This list is passed to the multi-view version of \c
/// IIndex_rendering::render() as well as \c
/// IIndex_scene_query::pick(). The order of the viewports in the
/// list defines the rendering order.
///
/// For testing and debugging the multi-view support, extra \em
/// advisory log output can be enabled.
///
/// @ingroup nv_index_rendering
///
class IViewport_list : public mi::base::Interface_declare<0xbd7cbc5a, 0x4628, 0x47ea, 0x94, 0x9d,
                         0x64, 0x3c, 0x34, 0xa3, 0xc6, 0x8e>
{
public:
  /// Returns the number of viewports contained in the list.
  ///
  /// \return Number of viewports
  virtual mi::Size size() const = 0;

  /// Returns the viewport at the given position in the viewport list.
  ///
  /// \param[in] index Position in the list.
  /// \return Selected viewport, or 0 when \c index is invalid
  virtual nv::index::IViewport* get(mi::Size index) const = 0;

  /// Appends a viewport to the end of the viewport list.
  ///
  /// This class takes ownership of the viewport.
  ///
  /// \param[in] viewport Viewport to append, this class takes ownership.
  virtual void append(nv::index::IViewport* viewport) = 0;

  /// Inserts a viewport into the viewport list at the given position.
  ///
  /// \param[in] index    Position in the list.
  /// \param[in] viewport Viewport to insert, this class takes ownership.
  /// \return true on success, false when \c index is invalid
  virtual bool insert(mi::Size index, nv::index::IViewport* viewport) = 0;

  /// Removes the viewport at the given position from the viewport
  /// list.
  ///
  /// \param[in] index Position in the list.
  /// \return true on success, or false when the element was not found
  virtual bool remove(mi::Size index) = 0;

  /// Removes all viewports from the list.
  virtual void clear() = 0;

  /// Enables or disables the advisory output.
  ///
  /// When the advisory is enabled, extra debug messages related
  /// to multi-view support will be printed to the log.
  ///
  /// The advisory output is disabled by default.
  ///
  /// \param[in] enable   Advisory output state
  virtual void set_advisory_enabled(bool enable) = 0;

  /// Returns whether if the advisory output is enabled.
  ///
  /// \return \c true when advisory is enabled
  virtual bool get_advisory_enabled() const = 0;
};
}
} // namespace index / nv

#endif // NVIDIA_INDEX_IVIEWPORT_H
