/**************************************************************************
 *{@C
 *      Copyright:      1988-2023 Paul Obermeier (obermeier@poSoft.de)
 *
 *      Module:         ImageProcessing
 *      Filename:       IP_State.c
 *
 *      Author:         Paul Obermeier
 *
 *      Description:    Functions to change the state of the image processing
 *                      module.
 *
 *      Additional documentation:
 *                      None.
 *
 *      Exported functions:
 *                      IP_SetFormat
 *                      IP_GetFormat
 *                      IP_SetCompression
 *                      IP_GetCompression
 *                      IP_SetDrawMask
 *                      IP_GetDrawMask
 *                      IP_SetDrawColor
 *                      IP_GetDrawColor
 *                      IP_SetDrawMode
 *                      IP_GetDrawMode
 *                      IP_SetColorCorrect
 *                      IP_GetColorCorrect
 *                      IP_SetNumThreads
 *                      IP_GetNumThreads
 *
 **************************************************************************/

#include <stdio.h>

#include "UT_Compat.h"
#include "UT_Const.h"
#include "UT_Macros.h"
#include "UT_Error.h"

#include "FF_Image.h"

#include "IP_Image.h"
#include "IP_ImagePrivate.h"

/* Current pixel data format */

FF_ImgFmtType IP_StateFormat[FF_NumImgChanTypes] = {
   FF_ImgFmtTypeNone,   /* FF_ImgChanTypeGray */
   FF_ImgFmtTypeUByte,  /* FF_ImgChanTypeRed */
   FF_ImgFmtTypeUByte,  /* FF_ImgChanTypeGreen */
   FF_ImgFmtTypeUByte,  /* FF_ImgChanTypeBlue */
   FF_ImgFmtTypeNone,   /* FF_ImgChanTypeMatte */
   FF_ImgFmtTypeNone,   /* FF_ImgChanTypeRedMatte */
   FF_ImgFmtTypeNone,   /* FF_ImgChanTypeGreenMatte */
   FF_ImgFmtTypeNone,   /* FF_ImgChanTypeBlueMatte */
   FF_ImgFmtTypeNone,   /* FF_ImgChanTypeHoriSnr */
   FF_ImgFmtTypeNone,   /* FF_ImgChanTypeVertSnr */
   FF_ImgFmtTypeNone,   /* FF_ImgChanTypeDepth */
   FF_ImgFmtTypeNone,   /* FF_ImgChanTypeTemperature */
   FF_ImgFmtTypeNone    /* FF_ImgChanTypeRadiance */
};

/* Current compression method */

FF_ImgComprType IP_StateCompression[FF_NumImgChanTypes] = {
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeGray */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeRed */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeGreen */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeBlue */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeMatte */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeRedMatte */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeGreenMatte */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeBlueMatte */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeHoriSnr */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeVertSnr */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeDepth */
    FF_ImgComprTypeNone,        /* FF_ImgChanTypeTemperature */
    FF_ImgComprTypeNone         /* FF_ImgChanTypeRadiance */
};

/* Current drawing mask */

UT_Bool IP_StateDrawMask[FF_NumImgChanTypes] = {
    UT_True,    /* FF_ImgChanTypeGray */
    UT_True,    /* FF_ImgChanTypeRed */
    UT_True,    /* FF_ImgChanTypeGreen */
    UT_True,    /* FF_ImgChanTypeBlue */
    UT_True,    /* FF_ImgChanTypeMatte */
    UT_True,    /* FF_ImgChanTypeRedMatte */
    UT_True,    /* FF_ImgChanTypeGreenMatte */
    UT_True,    /* FF_ImgChanTypeBlueMatte */
    UT_True,    /* FF_ImgChanTypeHoriSnr */
    UT_True,    /* FF_ImgChanTypeVertSnr */
    UT_True,    /* FF_ImgChanTypeDepth */
    UT_True,    /* FF_ImgChanTypeTemperature */
    UT_True     /* FF_ImgChanTypeRadiance */
};

/* Current drawing color, UByte version */

UInt8 IP_StateDrawColorUByte[FF_NumImgChanTypes] = {
    0,          /* FF_ImgChanTypeGray */
    0,          /* FF_ImgChanTypeRed */
    0,          /* FF_ImgChanTypeGreen */
    0,          /* FF_ImgChanTypeBlue */
    0,          /* FF_ImgChanTypeMatte */
    0,          /* FF_ImgChanTypeRedMatte */
    0,          /* FF_ImgChanTypeGreenMatte */
    0,          /* FF_ImgChanTypeBlueMatte */
    0,          /* FF_ImgChanTypeHoriSnr */
    0,          /* FF_ImgChanTypeVertSnr */
    0,          /* FF_ImgChanTypeDepth */
    0,          /* FF_ImgChanTypeTemperature */
    0           /* FF_ImgChanTypeRadiance */
};

/* Current drawing color, Float32 version */

Float32 IP_StateDrawColorFloat[FF_NumImgChanTypes] = {
    0.0,        /* FF_ImgChanTypeGray */
    0.0,        /* FF_ImgChanTypeRed */
    0.0,        /* FF_ImgChanTypeGreen */
    0.0,        /* FF_ImgChanTypeBlue */
    0.0,        /* FF_ImgChanTypeMatte */
    0.0,        /* FF_ImgChanTypeRedMatte */
    0.0,        /* FF_ImgChanTypeGreenMatte */
    0.0,        /* FF_ImgChanTypeBlueMatte */
    0.0,        /* FF_ImgChanTypeHoriSnr */
    0.0,        /* FF_ImgChanTypeVertSnr */
    0.0,        /* FF_ImgChanTypeDepth */
    0.0,        /* FF_ImgChanTypeTemperature */
    0.0         /* FF_ImgChanTypeRadiance */
};

/* Current drawing mode */

IP_DrawModeType IP_StateDrawMode[FF_NumImgChanTypes] = {
    IP_DrawModeReplace,         /* FF_ImgChanTypeGray */
    IP_DrawModeReplace,         /* FF_ImgChanTypeRed */
    IP_DrawModeReplace,         /* FF_ImgChanTypeGreen */
    IP_DrawModeReplace,         /* FF_ImgChanTypeBlue */
    IP_DrawModeReplace,         /* FF_ImgChanTypeMatte */
    IP_DrawModeReplace,         /* FF_ImgChanTypeRedMatte */
    IP_DrawModeReplace,         /* FF_ImgChanTypeGreenMatte */
    IP_DrawModeReplace,         /* FF_ImgChanTypeBlueMatte */
    IP_DrawModeReplace,         /* FF_ImgChanTypeHoriSnr */
    IP_DrawModeReplace,         /* FF_ImgChanTypeVertSnr */
    IP_DrawModeReplace,         /* FF_ImgChanTypeDepth */
    IP_DrawModeReplace,         /* FF_ImgChanTypeTemperature */
    IP_DrawModeReplace          /* FF_ImgChanTypeRadiance */
};

/* Current gamma factor */

Float32 IP_StateGamma = 2.0;

/* Current monitor primary red, green and blue, and monitor white point */

CIE_hue IP_StateHueRed =        {0.670f, 0.330f};
CIE_hue IP_StateHueGreen =      {0.210f, 0.710f};
CIE_hue IP_StateHueBlue =       {0.140f, 0.080f};
CIE_hue IP_StateHueWhite =      {0.313f, 0.329f};

/* Current number of threads used for image processing */

Int32 IP_StateNumThreads = 1;

/* Current scale factor of vector text */

Int32 IP_TextScale = 1;

/***************************************************************************
 *[@e
 *      Name:           IP_SetFormat
 *
 *      Usage:          Set the current pixel data format.
 *
 *      Synopsis:       UT_Bool IP_SetFormat 
 *                              (const FF_ImgFmtType fmt[])
 *
 *      Description:    IP_SetFormat defines the current pixel data
 *                      format for all channels, i.e. the format to be used for
 *                      the different channels when a new image is created.
 *                      When memory is allocated for channel number "i" of an
 *                      image, pixel data format fmt[i] is used.
 *
 *                      By default, the current pixel data format is
 *                      FF_ImgFmtTypeNone for all channels except for
 *                      FF_ImgChanTypeRed, FF_ImgChanTypeGreen and 
 *                      FF_ImgChanTypeBlue, for which 
 *                      the default is FF_ImgFmtTypeUByte.
 *
 *      Return value:   IP_SetFormat returns UT_True if it was successful,
 *                      else UT_False.
 *
 *      See also:       IP_GetFormat
 *
 ***************************************************************************/

UT_Bool IP_SetFormat (const FF_ImgFmtType fmt[])
{
    Int32 i;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        if (fmt[i] < 0 || fmt[i] >= FF_NumImgFmtTypes) {
            UT_ErrSetNum (UT_ErrParamInvalid, str_pixformat);
            return UT_False;
        }
    }
    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        IP_StateFormat[i] = fmt[i];
    }
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           IP_GetFormat
 *
 *      Usage:          Get the current pixel data format.
 *
 *      Synopsis:       void IP_GetFormat (FF_ImgFmtType fmt[])
 *
 *      Description:    IP_GetFormat returns the current pixel data format
 *                      in "fmt".
 *
 *      Return value:   None.
 *
 *      See also:       IP_SetFormat
 *
 ***************************************************************************/

void IP_GetFormat (FF_ImgFmtType fmt[])
{
    Int32 i;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        fmt[i] = IP_StateFormat[i];
    }
    return;
}

/***************************************************************************
 *[@e
 *      Name:           IP_SetCompression
 *
 *      Usage:          Set the current compression method.
 *
 *      Synopsis:       UT_Bool IP_SetCompression
 *                              (const FF_ImgComprType cmp[])
 *
 *      Description:    IP_SetCompression defines the current compression
 *                      method for all channels, i.e. the compression method
 *                      to be used when an image is written to a file:
 *                      Cmp[i] is the compression method to be applied to
 *                      channel number "i".
 *
 *                      By default, the current compression method is
 *                      FF_ImgComprTypeNone for all channels.
 *
 *      Return value:   IP_SetCompression returns UT_True if it was successful,
 *                      else UT_False.
 *
 *      See also:       IP_GetCompression
 *
 ***************************************************************************/

UT_Bool IP_SetCompression (const FF_ImgComprType cmp[])
{
    Int32 i;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        if (cmp[i] < 0 || cmp[i] >= FF_NumImgComprTypes) {
            UT_ErrSetNum (UT_ErrParamInvalid, str_compression);
            return UT_False;
        }
    }
    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        IP_StateCompression[i] = cmp[i];
    }
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           IP_GetCompression
 *
 *      Usage:          Get the current compression method.
 *
 *      Synopsis:       void IP_GetCompression (FF_ImgComprType cmp[])
 *
 *      Description:    IP_GetCompression returns the current compression
 *                      method in "cmp".
 *
 *      Return value:   None.
 *
 *      See also:       IP_SetCompression
 *
 ***************************************************************************/

void IP_GetCompression (FF_ImgComprType cmp[])
{
    Int32 i;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        cmp[i] = IP_StateCompression[i];
    }
    return;
}

/***************************************************************************
 *[@e
 *      Name:           IP_SetDrawMask
 *
 *      Usage:          Set the current drawing mask.
 *
 *      Synopsis:       UT_Bool IP_SetDrawMask (const UT_Bool msk[])
 *
 *      Description:    IP_SetDrawMask defines the current drawing mask, i.e.
 *                      the mask selecting which channels will be affected by
 *                      functions drawing into an image:
 *                      Drawing into channel number "i" is allowed only if
 *                      msk[i] is UT_True.
 *
 *                      By default, the current drawing mask is "UT_True" for
 *                      all channels.
 *
 *      Return value:   IP_SetDrawMask returns UT_True if it was successful,
 *                      else UT_False.
 *
 *      See also:       IP_GetDrawMask
 *
 ***************************************************************************/

UT_Bool IP_SetDrawMask (const UT_Bool msk[])
{
    Int32 i;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        IP_StateDrawMask[i] = !!msk[i];
    }
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           IP_GetDrawMask
 *
 *      Usage:          Get the current drawing mask.
 *
 *      Synopsis:       void IP_GetDrawMask (UT_Bool msk[])
 *
 *      Description:    IP_GetDrawMask returns the current drawing mask
 *                      in "msk".
 *
 *      Return value:   None.
 *
 *      See also:       IP_SetDrawMask
 *
 ***************************************************************************/

void IP_GetDrawMask (UT_Bool msk[])
{
    Int32 i;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        msk[i] = IP_StateDrawMask[i];
    }
    return;
}

/***************************************************************************
 *[@e
 *      Name:           IP_SetDrawColor
 *
 *      Usage:          Set the current drawing color.
 *
 *      Synopsis:       UT_Bool IP_SetDrawColor (const Float32 clr[])
 *
 *      Description:    IP_SetDrawColor defines the current drawing color for
 *                      all channels, i.e. the color used when drawing into an
 *                      image takes place: The current drawing color for
 *                      channel number "i" is set to clr[i].
 *                      Drawing colors should be in the range from 0.0 to 1.0
 *                      for all channels except FF_ImgChanTypeHoriSnr,
 *                      FF_ImgChanTypeVertSnr, FF_ImgChanTypeDepth,
 *                      FF_ImgChanTypeTemperature and FF_ImgChanTypeRadiance.
 *                      For FF_ImgChanTypeHoriSnr and FF_ImgChanTypeVertSnr,
 *                      drawing "colors" must be in the range from -1.0 to +1.0.
 *                      For FF_ImgChanTypeDepth, drawing "colors" must be 
 *                      greater than 0.0, as depth information is stored as the
 *                      reciprocal value.
 *
 *                      By default, the current drawing color is 0.0 for all
 *                      channels.
 *
 *      Return value:   IP_SetDrawColor returns UT_True if it was successful,
 *                      else UT_False.
 *
 *      See also:       IP_GetDrawColor
 *
 ***************************************************************************/

UT_Bool IP_SetDrawColor (const Float32 clr[])
{
    Int32 i, iclr;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        iclr = (Int32)(clr[i] * 255.0 + 0.5);
        IP_StateDrawColorUByte[i] = UT_MAX (0, UT_MIN (iclr, 255));
        IP_StateDrawColorFloat[i] = clr[i];
    }
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           IP_GetDrawColor
 *
 *      Usage:          Get the current drawing color.
 *
 *      Synopsis:       void IP_GetDrawColor (Float32 clr[])
 *
 *      Description:    IP_GetDrawColor returns the current drawing color
 *                      in "clr".
 *
 *      Return value:   None.
 *
 *      See also:       IP_SetDrawColor
 *
 ***************************************************************************/

void IP_GetDrawColor (Float32 clr[])
{
    Int32 i;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        clr[i] = IP_StateDrawColorFloat[i];
    }
    return;
}

/***************************************************************************
 *[@e
 *      Name:           IP_SetDrawMode
 *
 *      Usage:          Set the current drawing mode.
 *
 *      Synopsis:       UT_Bool IP_SetDrawMode 
 *                              (const IP_DrawModeType dm[])
 *
 *      Description:    IP_SetDrawMode defines the current drawing mode for
 *                      all channels, i.e. how the current drawing color is
 *                      combined with the orignal color of pixels when drawing
 *                      into an image takes place: Dm[i] is the current drawing
 *                      mode for channel number "i".
 *
 *                      By default, the current drawing mode is
 *                      IP_DrawModeReplace for all channels.
 *
 *      Return value:   IP_SetDrawMode returns UT_True if it was successful,
 *                      else UT_False.
 *
 *      See also:       IP_GetDrawMode
 *
 ***************************************************************************/

UT_Bool IP_SetDrawMode (const IP_DrawModeType dm[])
{
    Int32 i;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        if (dm[i] < 0 || dm[i] >= IP_NumDrawModeTypes) {
            UT_ErrSetNum (UT_ErrParamInvalid, str_drawmode);
            return UT_False;
        }
    }
    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        IP_StateDrawMode[i] = dm[i];
    }
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           IP_GetDrawMode
 *
 *      Usage:          Get the current drawing mode.
 *
 *      Synopsis:       void IP_GetDrawMode (IP_DrawModeType dm[])
 *
 *      Description:    IP_GetDrawMode returns the current drawing mode in "dm".
 *
 *      Return value:   None.
 *
 *      See also:       IP_SetDrawMode
 *
 ***************************************************************************/

void IP_GetDrawMode (IP_DrawModeType dm[])
{
    Int32 i;

    for (i = 0; i < FF_NumImgChanTypes; ++i) {
        dm[i] = IP_StateDrawMode[i];
    }
    return;
}

/***************************************************************************
 *[@e
 *      Name:           IP_SetColorCorrect
 *
 *      Usage:          Set the current color correction parameters.
 *
 *      Synopsis:       UT_Bool IP_SetColorCorrect
 *                              (Float32 gamma,
 *                              const CIE_hue *red,
 *                              const CIE_hue *green,
 *                              const CIE_hue *blue,
 *                              const CIE_hue *white)
 *
 *      Description:    IP_SetColorCorrect defines the current gamma and color
 *                      correction parameters, i.e. parameters written into
 *                      the header of any newly created images.
 *
 *                      The parameters and their default values are:
 *
 *                      gamma   2.0             Gamma factor of the frame
 *                                              buffer / monitor combination
 *                                              which will be used to display
 *                                              images
 *
 *                      red     (0.670, 0.330)  The location of the monitor's
 *                                              pure red in the CIE x-y color
 *                                              diagram; default is NTSC
 *                                              standard primary red.
 *
 *                      green   (0.210, 0.710)  The location of the monitor's
 *                                              pure green; default is NTSC
 *                                              standard primary green.
 *
 *                      blue    (0.140, 0.080)  The location of the monitor's
 *                                              pure blue; default is NTSC
 *                                              standard primary blue.
 *
 *                      white   (0.313, 0.329)  The location of the monitor's
 *                                              white point; default is CIE
 *                                              illuminant D6500, i.e. the
 *                                              color of a black body at a
 *                                              temperature of 6500 Kelvin.
 *
 *      Return value:   IP_SetColorCorrect returns UT_True if it was successful,
 *                      else UT_False.
 *
 *      See also:       IP_GetColorCorrect
 *
 ***************************************************************************/

UT_Bool IP_SetColorCorrect
        (Float32 gamma,
         const CIE_hue *red,
         const CIE_hue *green,
         const CIE_hue *blue,
         const CIE_hue *white)
{
    if (gamma < MINGAMMA || gamma > MAXGAMMA) {
         UT_ErrSetNum (UT_ErrParamRange, str_range_inclusive,
                       str_gamma, MINGAMMA, MAXGAMMA);
        return UT_False;
    }
    if ((red->x < 0.0) || (red->x > 1.0) ||
        (red->y < 0.0) || (red->y > 1.0) ||
        (green->x < 0.0) || (green->x > 1.0) ||
        (green->y < 0.0) || (green->y > 1.0) ||
        (blue->x < 0.0) || (blue->x > 1.0) ||
        (blue->y < 0.0) || (blue->y > 1.0) ||
        (white->x < 0.0) || (white->x > 1.0) ||
        (white->y < 0.0) || (white->y > 1.0)) {
        UT_ErrSetNum (UT_ErrParamRange, str_range_inclusive,
                     str_cie_hue, 0.0, 1.0);
        return UT_False;
    }
    IP_StateGamma = gamma;
    IP_StateHueRed = *red;
    IP_StateHueGreen = *green;
    IP_StateHueBlue = *blue;
    IP_StateHueWhite = *white;
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           IP_GetColorCorrect
 *
 *      Usage:          Get the current color correction parameters.
 *
 *      Synopsis:       void IP_GetColorCorrect
 *                              (Float32 *gamma,
 *                              CIE_hue *red,
 *                              CIE_hue *green,
 *                              CIE_hue *blue,
 *                              CIE_hue *white)
 *
 *      Description:    IP_GetColorCorrect returns the current gamma and color
 *                      correction parameters.
 *
 *      Return value:   None.
 *
 *      See also:       IP_SetColorCorrect
 *
 ***************************************************************************/

void IP_GetColorCorrect (Float32 *gamma, CIE_hue *red, CIE_hue *green,
                         CIE_hue *blue, CIE_hue *white)
{
    *gamma = IP_StateGamma;
    *red   = IP_StateHueRed;
    *green = IP_StateHueGreen;
    *blue  = IP_StateHueBlue;
    *white = IP_StateHueWhite;
    return;
}

/***************************************************************************
 *[@e
 *      Name:           IP_SetNumThreads
 *
 *      Usage:          Set the number of threads used for image processing.
 *
 *      Synopsis:       UT_Bool IP_SetNumThreads (Int32 n)
 *
 *      Description:    Some operating systems do not support the thread
 *                      concurrency mechanism on which the parallel image
 *                      operations are based. On these systems, all image
 *                      processing is done serially, regardless of the
 *                      number of processors specified with IP_SetNumThreads.
 *
 *      Return value:   IP_SetNumThreads attempts to allocate "n" threads
 *                      for parallel operations on images. "N" must not be
 *                      less than 1. IP_SetNumThreads returns UT_True if it is
 *                      successful, else UT_False.
 *
 *      See also:       IP_GetNumThreads
 *
 ***************************************************************************/

UT_Bool IP_SetNumThreads (Int32 n)
{
    if (n < 1) {
         UT_ErrSetNum (UT_ErrParamInvalid, str_inotless, str_numthread, 1);
        return UT_False;
    }
    IP_StateNumThreads = n;
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           IP_GetNumThreads
 *
 *      Usage:          Get the number of processors used for parallel processing.
 *
 *      Synopsis:       Int32  IP_GetNumThreads (void)
 *
 *      Description:    Some operating systems do not support the thread
 *                      concurrency mechanism on which the parallel image
 *                      operations are based. On these systems, all image
 *                      processing is done serially, regardless of the
 *                      number of processors specified with IP_SetNumThreads.
 *
 *      Return value:   IP_GetNumThreads returns the current number of
 *                      processors allocated for parallel processing.
 *
 *      See also:       IP_SetNumThreads
 *
 ***************************************************************************/
Int32 IP_GetNumThreads (void)
{
     return IP_StateNumThreads;
}
