///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
// 
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// *       Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// *       Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// *       Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////


#ifndef INCLUDED_IMF_ENVMAP_H
#define INCLUDED_IMF_ENVMAP_H

//-----------------------------------------------------------------------------
//
//	Environment maps
//
//	Environment maps define a mapping from 3D directions to 2D
//	pixel space locations.  Environment maps are typically used
//	in 3D rendering, for effects such as quickly approximating
//	how shiny surfaces reflect their environment.
//
//	Environment maps can be stored in scanline-based or in tiled
//	OpenEXR files.  The fact that an image is an environment map
//	is indicated by the presence of an EnvmapAttribute whose name
//	is "envmap". (Convenience functions to access this attribute
//	are defined in header file ImfStandardAttributes.h.)
//	The attribute's value defines the mapping from 3D directions
//	to 2D pixel space locations.
//
//	This header file defines the set of possible EnvmapAttribute
//	values.
//
//	For each possible EnvmapAttribute value, this header file also
//	defines a set of convienience functions to convert between 3D
//	directions and 2D pixel locations.
//
//	Most of the convenience functions defined below require a
//	dataWindow parameter.  For scanline-based images, and for
//	tiled images with level mode ONE_LEVEL, the dataWindow
//	parameter should be set to the image's data window, as
//	defined in the image header.  For tiled images with level
//	mode MIPMAP_LEVELS or RIPMAP_LEVELS, the data window of the
//	image level that is being accessed should be used instead.
//	(See the dataWindowForLevel() methods in ImfTiledInputFile.h
//	and ImfTiledOutputFile.h.)
//
//-----------------------------------------------------------------------------

#include <ImathBox.h>

namespace Imf {

//--------------------------------
// Supported environment map types
//--------------------------------

enum Envmap
{
    ENVMAP_LATLONG = 0,		// Latitude-longitude environment map
    ENVMAP_CUBE = 1,		// Cube map

    NUM_ENVMAPTYPES		// Number of different environment map types
};


//-------------------------------------------------------------------------
// Latitude-Longitude Map:
//
// The environment is projected onto the image using polar coordinates
// (latitude and longitude).  A pixel's x coordinate corresponds to
// its longitude, and the y coordinate corresponds to its latitude.
// Pixel (dataWindow.min.x, dataWindow.min.y) has latitude +pi/2 and
// longitude +pi; pixel (dataWindow.max.x, dataWindow.max.y) has
// latitude -pi/2 and longitude -pi.
//
// In 3D space, latitudes -pi/2 and +pi/2 correspond to the negative and
// positive y direction.  Latitude 0, longitude 0 points into positive
// z direction; and latitude 0, longitude pi/2 points into positive x
// direction.
//
// The size of the data window should be 2*N by N pixels (width by height),
// where N can be any integer greater than 0.
//-------------------------------------------------------------------------

namespace LatLongMap
{
    //----------------------------------------------------
    // Convert a 3D direction to a 2D vector whose x and y
    // components represent the corresponding latitude
    // and longitude.
    //----------------------------------------------------

    Imath::V2f		latLong (const Imath::V3f &direction);


    //--------------------------------------------------------
    // Convert the position of a pixel to a 2D vector whose
    // x and y components represent the corresponding latitude
    // and longitude.
    //--------------------------------------------------------

    Imath::V2f		latLong (const Imath::Box2i &dataWindow,
				 const Imath::V2f &pixelPosition);


    //-------------------------------------------------------------
    // Convert a 2D vector, whose x and y components represent
    // longitude and latitude, into a corresponding pixel position.
    //-------------------------------------------------------------

    Imath::V2f		pixelPosition (const Imath::Box2i &dataWindow,
				       const Imath::V2f &latLong);


    //-----------------------------------------------------
    // Convert a 3D direction vector into a corresponding
    // pixel position.  pixelPosition(dw,dir) is equivalent
    // to pixelPosition(dw,latLong(dw,dir)).
    //-----------------------------------------------------

    Imath::V2f		pixelPosition (const Imath::Box2i &dataWindow,
				       const Imath::V3f &direction);


    //--------------------------------------------------------
    // Convert the position of a pixel in a latitude-longitude
    // map into a corresponding 3D direction.
    //--------------------------------------------------------

    Imath::V3f		direction (const Imath::Box2i &dataWindow,
				   const Imath::V2f &pixelPosition);
}


//--------------------------------------------------------------
// Cube Map:
//
// The environment is projected onto the six faces of an
// axis-aligned cube.  The cube's faces are then arranged
// in a 2D image as shown below.
//
//          2-----------3
//         /           /|
//        /           / |       Y
//       /           /  |       |
//      6-----------7   |       |
//      |           |   |       |
//      |           |   |       |
//      |   0       |   1       *------- X
//      |           |  /       /
//      |           | /       /
//      |           |/       /
//      4-----------5       Z
// 
//   dataWindow.min
//        /
//       / 
//      +-----------+
//      |3    Y    7|
//      |     |     |
//      |     |     |
//      |  ---+---Z |  +X face
//      |     |     |
//      |     |     |
//      |1         5|
//      +-----------+
//      |6    Y    2|
//      |     |     |
//      |     |     |
//      | Z---+---  |  -X face
//      |     |     |
//      |     |     |
//      |4         0|
//      +-----------+
//      |6    Z    7|
//      |     |     |
//      |     |     |
//      |  ---+---X |  +Y face
//      |     |     |
//      |     |     |
//      |2         3|
//      +-----------+
//      |0         1|
//      |     |     |
//      |     |     |
//      |  ---+---X |  -Y face
//      |     |     |
//      |     |     |
//      |4    Z    5|
//      +-----------+
//      |7    Y    6|
//      |     |     |
//      |     |     |
//      | X---+---  |  +Z face
//      |     |     |
//      |     |     |
//      |5         4|
//      +-----------+
//      |2    Y    3|
//      |     |     |
//      |     |     |
//      |  ---+---X |  -Z face
//      |     |     |
//      |     |     |
//      |0         1|
//      +-----------+
//                 /
//                /
//          dataWindow.max
//
// The size of the data window should be N by 6*N pixels
// (width by height), where N can be any integer greater
// than 0.
// 
//--------------------------------------------------------------

//------------------------------------
// Names for the six faces of the cube
//------------------------------------

enum CubeMapFace
{
    CUBEFACE_POS_X,	// +X face
    CUBEFACE_NEG_X,	// -X face
    CUBEFACE_POS_Y,	// +Y face
    CUBEFACE_NEG_Y,	// -Y face
    CUBEFACE_POS_Z,	// +Z face
    CUBEFACE_NEG_Z,	// -Z face
};

namespace CubeMap
{
    //---------------------------------------------
    // Width and height of a cube's face, in pixels
    //---------------------------------------------

    int			sizeOfFace (const Imath::Box2i &dataWindow);


    //------------------------------------------
    // Compute the region in the environment map
    // that is covered by the specified face.
    //------------------------------------------

    Imath::Box2i	dataWindowForFace (CubeMapFace face,
					   const Imath::Box2i &dataWindow);


    //----------------------------------------------------
    // Convert the coordinates of a pixel within a face
    // [in the range from (0,0) to (s-1,s-1), where
    // s == sizeOfFace(dataWindow)] to pixel coordinates
    // in the environment map.
    //----------------------------------------------------

    Imath::V2f		pixelPosition (CubeMapFace face,
				       const Imath::Box2i &dataWindow,
				       Imath::V2f positionInFace);


    //--------------------------------------------------------------
    // Convert a 3D direction into a cube face, and a pixel position
    // within that face.
    //
    // If you have a 3D direction, dir, the following code fragment
    // finds the position, pos, of the corresponding pixel in an
    // environment map with data window dw:
    //
    // CubeMapFace f;
    // V2f pif, pos;
    //
    // faceAndPixelPosition (dir, dw, f, pif);
    // pos = pixelPosition (f, dw, pif);
    //
    //--------------------------------------------------------------

    void		faceAndPixelPosition (const Imath::V3f &direction,
					      const Imath::Box2i &dataWindow,
					      CubeMapFace &face,
					      Imath::V2f &positionInFace);

   
    // --------------------------------------------------------
    // Given a cube face and a pixel position within that face,
    // compute the corresponding 3D direction.
    // --------------------------------------------------------

    Imath::V3f		direction (CubeMapFace face,
				   const Imath::Box2i &dataWindow,
				   const Imath::V2f &positionInFace);
}


} // namespace Imf

#endif
