/* Copyright (c) 2009 The Khronos Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and/or associated documentation files (the
 * "Materials"), to deal in the Materials without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Materials, and to
 * permit persons to whom the Materials are furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Materials.
 *
 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
 */

#ifndef OWFIMAGE_H_
#define OWFIMAGE_H_

#include "owftypes.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef void*   OWF_DISPCTX;


#undef USE_FLOAT_PIXEL

/*
 * This is and always should be the only place where USE_FLOAT_PIXEL is 
 * defined so if #define USE_FLOAT_PIXEL is absent in owfimage.h then it
 * can be assumed it is not defined elsewhere. 
 */ 
//#define USE_FLOAT_PIXEL

/* --
* internal pixel format
*/
#ifdef USE_FLOAT_PIXEL
#define OWF_IMAGE_INTERNAL_PIXEL_IS_FLOAT

typedef OWFfloat            OWFsubpixel; /* subpixel representation */

#define OWF_RED_MIN_VALUE   0.0f
#define OWF_RED_MAX_VALUE   1.0f
#define OWF_GREEN_MIN_VALUE 0.0f
#define OWF_GREEN_MAX_VALUE 1.0f
#define OWF_BLUE_MIN_VALUE  0.0f
#define OWF_BLUE_MAX_VALUE  1.0f
#define OWF_ALPHA_MIN_VALUE 0.0f
#define OWF_ALPHA_MAX_VALUE 1.0f

#define OWF_FULLY_OPAQUE        OWF_ALPHA_MAX_VALUE
#define OWF_FULLY_TRANSPARENT   OWF_ALPHA_MIN_VALUE

#define OWF_BYTE_MAX_VALUE  255.0f
#define OWF_BILINEAR_ROUNDING_VALUE 0.0f
#define OWF_BLEND_ROUNDING_VALUE 0.0f
#define OWF_PREMUL_ROUNDING_FACTOR  0.0f
#define OWF_SOURCE_CONVERSION_ROUNDING_VALUE 0.0f

#else
#undef OWF_IMAGE_INTERNAL_PIXEL_IS_FLOAT

typedef OWFuint8            OWFsubpixel; /* subpixel representation */

#define OWF_RED_MIN_VALUE         0
#define OWF_RED_MAX_VALUE       255
#define OWF_GREEN_MIN_VALUE       0
#define OWF_GREEN_MAX_VALUE     255
#define OWF_BLUE_MIN_VALUE        0
#define OWF_BLUE_MAX_VALUE      255
#define OWF_ALPHA_MIN_VALUE       0
#define OWF_ALPHA_MAX_VALUE     255
#define OWF_FULLY_OPAQUE        OWF_ALPHA_MAX_VALUE
#define OWF_FULLY_TRANSPARENT   OWF_ALPHA_MIN_VALUE

#define OWF_BYTE_MAX_VALUE      255

#define OWF_BILINEAR_ROUNDING_VALUE 0.5f
#define OWF_SOURCE_CONVERSION_ROUNDING_VALUE 0.5f
#define OWF_BLEND_ROUNDING_VALUE (OWF_ALPHA_MAX_VALUE/2)
#define OWF_PREMUL_ROUNDING_FACTOR (OWF_ALPHA_MAX_VALUE/2)

#endif

/*
 * Byte order of different color formats
 * these are used when converting from/to
 * internal format
 */

#define ARGB8888_ALPHA_MASK         0xFF000000
#define ARGB8888_RED_MASK           0x00FF0000
#define ARGB8888_GREEN_MASK         0x0000FF00
#define ARGB8888_BLUE_MASK          0x000000FF
#define ARGB8888_ALPHA_SHIFT        24
#define ARGB8888_RED_SHIFT          16
#define ARGB8888_GREEN_SHIFT        8
#define ARGB8888_BLUE_SHIFT         0

#define RGB565_ALPHA_MASK   0xFFFF
#define RGB565_RED_MASK     0xF800
#define RGB565_GREEN_MASK   0x07E0
#define RGB565_BLUE_MASK    0x001F

/* These are used when converting from RGB565 to ARGB8888. */
#define RGB565_ALPHA_SHIFT  16
#define RGB565_RED_SHIFT    11
#define RGB565_GREEN_SHIFT  5

/* subpixels per pixel */
#define OWF_PIXEL_SIZE      4

/* subpixel in bytes */
#define OWF_SUBPIXEL_SIZE   sizeof(OWFsubpixel)
#define OWF_BYTES_PER_PIXEL (OWF_PIXEL_SIZE * OWF_SUBPIXEL_SIZE)

#pragma pack(push, 1)
typedef union {
    struct {
        OWFsubpixel         blue;
        OWFsubpixel         green;
        OWFsubpixel         red;
        OWFsubpixel         alpha;
    } color;
    OWFsubpixel             subpixel[OWF_PIXEL_SIZE];
    OWFuint8                pixelbytes[OWF_BYTES_PER_PIXEL];
} OWFpixel;
#pragma pack(pop)

/* -- */

/* filters used in OWF_Image_Stretch */
typedef enum {
    OWF_FILTER_POINT_SAMPLING,  /* nearest pixel */
    OWF_FILTER_BILINEAR        /* nearest 4 */
} OWF_FILTERING;

typedef struct {
    OWFint                  width;
    OWFint                  height;
    OWFint                  stride; /* number of bytes per line */
    OWFint                  pixelSize; /* pixel size in bytes */
    OWF_IMAGE_FORMAT        format;
    OWFboolean              foreign;
    OWFint                  dataMax; /* data buffer max size */
    void*                   data;
} OWF_IMAGE;

/* This typedef denotes an owned OWF_IMAGE, as opposed to a temporary association.
 * Owned instances must be destroyed when the containing object is destroyed.
 */
typedef OWF_IMAGE* OWF_IMAGE_INST;

typedef enum {
    OWF_FLIP_NONE,
    OWF_FLIP_VERTICALLY     = 1,
    OWF_FLIP_HORIZONTALLY   = 2
} OWF_FLIP_DIRECTION;

typedef enum {
    OWF_ROTATION_0          = 0,
    OWF_ROTATION_90         = 90,
    OWF_ROTATION_180        = 180,
    OWF_ROTATION_270        = 270
} OWF_ROTATION;

typedef enum {
    OWF_TRANSPARENCY_NONE,
    OWF_TRANSPARENCY_GLOBAL_ALPHA   = (1 << 0),
    OWF_TRANSPARENCY_SOURCE_ALPHA   = (1 << 1),
    OWF_TRANSPARENCY_MASK           = (1 << 2),
    OWF_TRANSPARENCY_COLOR_KEY      = (1 << 3)
} OWF_TRANSPARENCY;

typedef struct _OWF_BLEND_INFO {
    struct {
        OWF_IMAGE*          image;
        OWF_RECTANGLE*      rectangle;
    } destination;

    struct {
        OWF_IMAGE*          image;
        OWF_RECTANGLE*      rectangle;
    } source;

    OWF_IMAGE*              mask;
    OWFsubpixel             globalAlpha;
    OWFboolean              destinationFullyOpaque;
    OWFpixel*               tsColor;
} OWF_BLEND_INFO;


/*!---------------------------------------------------------------------------
 *  \brief Initialize image object
 *
 *  \param image            Image object to initialize
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_Init(OWF_IMAGE* image);

/*!---------------------------------------------------------------------------
 *  \brief Creates new reference counted image object
 *
 *  \param width            Image width (in pixels)
 *  \param height           Image height (in pixels)
 *  \param format           Image format (\see OWF_IMAGE_FORMAT)
 *  \param buffer           Pointer to image pixel data. If NULL, then a new
 *                          buffer is allocated for storing image pixel data.
 *                          Allocated buffer is owned by the image. If non-NULL,
 *                          then the image will be a "foreign" one, that doesn't
 *                          own the pixel data but merely uses it.
 *  \param minimumStride    Minimum number of bytes per scanline (may be zero)
 *
 *
 *  \return New image object or NULL if error occured.
 *----------------------------------------------------------------------------*/
OWF_PUBLIC OWF_IMAGE*
OWF_Image_Create(OWFint width,
                 OWFint height,
                 const OWF_IMAGE_FORMAT* format,
                 void* buffer,
                 OWFint minimumStride);

/*!---------------------------------------------------------------------------
 *  \brief Destroy image object. Rather than actually destroying the image
 *  immediately, this decrements image's reference count by one and once the
 *  counter reaches zero, the actual deletion will occur.
 *
 *  \param image            Image to destroy
 *----------------------------------------------------------------------------*/
OWF_PUBLIC void
OWF_Image_Destroy(OWF_IMAGE* image);

/*!---------------------------------------------------------------------------
 *  \brief Create a pixel-perfect copy (clone) of the image. The copy will be
 *  totally independent from the original image, i.e. doesn't share pixel
 *  buffers or anything.
 *
 *  \param image            Image to copy
 *
 *  \param Copy of the image or NULL if error occured.
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWF_IMAGE*
OWF_Image_Copy(const OWF_IMAGE* image);

/*!---------------------------------------------------------------------------
 *  \brief Set image size. This doesn't modify the pixel data in anyway,
 *  merely just changes the image header. Mostly used for (recycling) foreign
 *  images that point to external pixel buffers.
 *
 *  If the new pixel count (width * height) exceeds
 *  current values, the pixel buffer will NOT be resized, but the call will FAIL.
 *
 *  \param image            Image to resize
 *  \param width            New width of the image
 *  \param height           New height of the image
 *
 *
 *  \return Boolean value indicating success of the operation. In case of
 *  failure, no modifications are done to original image.
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFboolean
OWF_Image_SetSize(OWF_IMAGE* image,
                  OWFint width,
                  OWFint height);

/*!---------------------------------------------------------------------------
 *  \brief Set internal mode flags. This doesn't modify the pixel data in anyway,
 *  merely just changes the image header. Mostly used for (recycling) foreign
 *  images that point to external pixel buffers.
 *
 *
 *  \param image            Image to resize
 *  \param premultiply      Image data is premultiplied
 *  \param linear           Image colour data is linear
 *
 *
 *  \return Boolean value indicating success of the operation. In case of
 *  failure, no modifications are done to original image.
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_SetFlags(OWF_IMAGE* image,
                  OWFboolean premultiply,
                  OWFboolean linear);

/*!---------------------------------------------------------------------------
 *  \brief Set the pixel buffer to an alternate location.
 *  All other parameters remain the same.
 *
 *  \param image            Image to resize
 *  \param buffer           Image data source to start using
 *
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_SetPixelBuffer(OWF_IMAGE* image,      void* buffer);


/*!---------------------------------------------------------------------------
 *  \brief Blit (1:1 copy) pixels from image to another w/ clipping.
 *
 *  \param dst              Destination image
 *  \param dstRect          Destination rectangle
 *  \param src              Source image
 *  \param srcRect          Source rectangle
 *
 *  \return Boolean value indicating whether pixels were copied or not. If not,
 *  it means that either of the rectangles is outside its respective image's
 *  bounds.
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFboolean
OWF_Image_Blit(OWF_IMAGE* dst,
               OWF_RECTANGLE const* dstRect,
               OWF_IMAGE const* src,
               OWF_RECTANGLE const* srcRect);

/*!---------------------------------------------------------------------------
 *  \brief Stretch-blit (scaled copy) pixels from image to another w/ clipping.
 *
 *  \param dst              Destination image
 *  \param dstRect          Destination rectangle
 *  \param src              Source image
 *  \param srcRect          Source rectangle
 *
 *  \return Boolean value indicating whether pixels were copied or not. If not,
 *  it means that either of the rectangles is outside its respective image's
 *  bounds.
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFboolean
OWF_Image_Stretch(OWF_IMAGE* dst,
                  OWF_RECTANGLE* dstRect,
                  OWF_IMAGE* src,
                  OWFfloat* srcRect,
                  OWF_FILTERING filter);

/*!---------------------------------------------------------------------------
 *  \brief Multiply pixels' alpha value into rgb-color components.
 *  Multiplies only if image source image is non-premultiplied.
 *  \param image            Image to convert to pre-multiplied domain.
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_PremultiplyAlpha(OWF_IMAGE* image);

/*!---------------------------------------------------------------------------
 *  \brief Divide pixels' rgb-color components by its alpha value.
 *
 *  \param image            Image to convert to nonpre-multiplied domain.
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_UnpremultiplyAlpha(OWF_IMAGE* image);

/*!---------------------------------------------------------------------------
 *  \brief Linearizes image pixel data
 *
 *  \param image            Image to convert to linear domain
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_LinearizeData(OWF_IMAGE* image);

/*!---------------------------------------------------------------------------
 *  \brief Non-linearizes image pixel data
 *
 *  \param image            Image to convert to non-linear domain
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_NonLinearizeData(OWF_IMAGE* image);

/*!---------------------------------------------------------------------------
 *  \brief Apply gamma correction to image pixel values
 *
 *  \param image            Image to operate on
 *  \param gamma            Gamma value
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_Gamma(OWF_IMAGE* image, OWFfloat gamma);

/*!---------------------------------------------------------------------------
 *  \brief Flip (mirror) image about one or both of its center axes.
 *
 *  \param image            Image to flip
 *  \param dir              Flip direction. Valid values are
 *                          OWF_FLIP_NONE, OWF_FLIP_HORIZONTALLY,
 *                          OWF_FLIP_VERTICALLY or any bitwise-or combination
 *                          of the former.
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_Flip(OWF_IMAGE* image,
               OWF_FLIP_DIRECTION dir);

/*!---------------------------------------------------------------------------
 *  \brief Rotate image n*90 degrees about its center
 *
 *  \param dst              Result (rotated) image.
 *  \param src              Source image.
 *  \param rotation         Rotation angle (OWF_ROTATION_0, OWF_ROTATION_90,
 *                          OWF_ROTATION_180, or OWF_ROTATION_270)
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_Rotate(OWF_IMAGE* dst,
                 OWF_IMAGE* src,
                 OWF_ROTATION rotation);

/*!---------------------------------------------------------------------------
 *  \brief
 *
 *  \param
 *
 *  \return
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_Blend(OWF_BLEND_INFO* blend,
                OWF_TRANSPARENCY transparency);

/*!---------------------------------------------------------------------------
 *  \brief
 *
 *  \param
 *
 *  \return
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_Clear(OWF_IMAGE* image,
                OWFsubpixel red,
                OWFsubpixel green,
                OWFsubpixel blue,
                OWFsubpixel alpha);

/*!---------------------------------------------------------------------------
 *  \brief Convert image data from internal color format to destination format
 *
 *  \param dst
 *  \param src
 *
 *  \return
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFboolean
OWF_Image_DestinationFormatConversion(OWF_IMAGE* dst,
                                      OWF_IMAGE* src);
/*!---------------------------------------------------------------------------
 *  \brief Test whether it will be possible to convert to destination format.
 *  Note, no IMAGE object yet extists. This is effectively a "static" member method.
 *  \param format proposed destination format
 *
 *  \return boolean true if image lib can convert image data from internal color format 
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFboolean
OWF_Image_IsValidDestinationFormat(OWF_IMAGE_FORMAT* format);

/*!---------------------------------------------------------------------------
*  \brief Convert image data from source format to internal format
 *
 *  \param src
 *  \param dst
 *
 *  \return
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFboolean
OWF_Image_SourceFormatConversion(OWF_IMAGE* dst,
                                 OWF_IMAGE* src);

/*!---------------------------------------------------------------------------
 *  \brief
 *
 *  \param
 *
 *  \return
 *----------------------------------------------------------------------------*/
OWF_API_CALL void*
OWF_Image_AllocData(OWF_DISPCTX dc, OWFint width,
                    OWFint height,
                    OWF_PIXEL_FORMAT format);


/*!---------------------------------------------------------------------------
 *  \brief
 *
 *  \param
 *
 *  \return
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_FreeData(OWF_DISPCTX dc, void** buffer);

/*!---------------------------------------------------------------------------
 *  \brief
 *
 *  \param
 *
 *  \return
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFint
OWF_Image_GetFormatPixelSize(OWF_PIXEL_FORMAT format);


/*!---------------------------------------------------------------------------
 * \brief Return stride (aligned row size in bytes) calculated from image
 * width and pixelSize. If pixelSize is negative image width must be divisible
 * by pixelSize.
 *
 * \param width             Width of image
 * \param pixelSize         Size of single pixel in bytes. Negative size
 *                          means value is a divisor (i.e. 1/pixelSize)
 * \param padding           Number of bits each row is padded to.

 * \return Row size in bytes.
 *----------------------------------------------------------------------------*/
OWF_PUBLIC OWFint
OWF_Image_GetStride(OWFint width,
                    const OWF_IMAGE_FORMAT* format,OWFint minimumStride);

/*!---------------------------------------------------------------------------
 *  \brief
 *
 *  \param
 *
 *  \return
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFint
OWF_Image_GetFormatPadding(OWF_PIXEL_FORMAT format);

/*!---------------------------------------------------------------------------
 *  \brief Swap image width & height values in image header. Doesn't modify
 *  image pixel data.
 *
 *  \param image            Image to operate on.
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_SwapWidthAndHeight(OWF_IMAGE* image);

/*!---------------------------------------------------------------------------
 *  \brief Convert mask from external format to internal 8bpp format.
 *
 *  \param output           Result (converted) mask image
 *  \param input            Input mask image to convert.
 *
 *  \return Boolean value indicating operation success. OWF_FALSE means that
 *  input mask is either invalid or unsupported, or degenerate in some other
 *  fascinating way.
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFboolean
OWF_Image_ConvertMask(OWF_IMAGE* output,
                      OWF_IMAGE* input);

/*!---------------------------------------------------------------------------
 *  \brief Return pointer to given pixel in image.
 *
 *  \param image            Image
 *  \param x                X-coordinate of the pixel (0..width-1)
 *  \param y                Y-coordinate of the pixel (0..height-1)
 *
 *  The x & y coordinates will be clamped to [0..width-1, 0..height-1]
 *
 *  \return Pointer to given pixel
 *----------------------------------------------------------------------------*/
OWF_API_CALL OWFpixel*
OWF_Image_GetPixelPtr(OWF_IMAGE* image,
                      OWFint x,
                      OWFint y);

/*!---------------------------------------------------------------------------
 *  \brief Read single pixel from image
 *
 *  \param image Image
 *  \param x Pixel x coordinate
 *  \param y Pixel y coordinate
 *  \param pixel Where to store the pixel color value
 *
 *  Coordinates are clamped to region (0..width-1, 0..height-1)
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_GetPixel(OWF_IMAGE* image,
                   OWFint x,
                   OWFint y,
                   OWFpixel* pixel);

/*!---------------------------------------------------------------------------
 *  \brief Write a pixel into image
 *
 *  \param image Image
 *  \param x Pixel x coordinate
 *  \param y Pixel y coordinate
 *  \param pixel Color of the pixel
 *
 *  Coordinates are clamped to region (0..width-1, 0..height-1)
 *----------------------------------------------------------------------------*/
OWF_API_CALL void
OWF_Image_SetPixel(OWF_IMAGE* image,
                   OWFint x,
                   OWFint y,
                   OWFpixel const* pixel);

#ifdef __cplusplus
}
#endif

#endif
