# from std/os import splitPath
# {.passC:"-I" & currentSourcePath().splitPath.head .}
type const_cstring* {.importc:"const char*".} = cstring

const
  TINYEXR_SUCCESS* = (0)
  TINYEXR_ERROR_INVALID_MAGIC_NUMBER* = (-1)
  TINYEXR_ERROR_INVALID_EXR_VERSION* = (-2)
  TINYEXR_ERROR_INVALID_ARGUMENT* = (-3)
  TINYEXR_ERROR_INVALID_DATA* = (-4)
  TINYEXR_ERROR_INVALID_FILE* = (-5)
  TINYEXR_ERROR_INVALID_PARAMETER* = (-6)
  TINYEXR_ERROR_CANT_OPEN_FILE* = (-7)
  TINYEXR_ERROR_UNSUPPORTED_FORMAT* = (-8)
  TINYEXR_ERROR_INVALID_HEADER* = (-9)
  TINYEXR_ERROR_UNSUPPORTED_FEATURE* = (-10)
  TINYEXR_ERROR_CANT_WRITE_FILE* = (-11)
  TINYEXR_ERROR_SERIALIZATION_FAILED* = (-12)
  TINYEXR_ERROR_LAYER_NOT_FOUND* = (-13)
  TINYEXR_ERROR_DATA_TOO_LARGE* = (-14)

##  @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf }
##  pixel type: possible values are: UINT = 0 HALF = 1 FLOAT = 2

const
  TINYEXR_PIXELTYPE_UINT* = (0)
  TINYEXR_PIXELTYPE_HALF* = (1)
  TINYEXR_PIXELTYPE_FLOAT* = (2)
  TINYEXR_MAX_HEADER_ATTRIBUTES* = (1024)
  TINYEXR_MAX_CUSTOM_ATTRIBUTES* = (128)
  TINYEXR_COMPRESSIONTYPE_NONE* = (0)
  TINYEXR_COMPRESSIONTYPE_RLE* = (1)
  TINYEXR_COMPRESSIONTYPE_ZIPS* = (2)
  TINYEXR_COMPRESSIONTYPE_ZIP* = (3)
  TINYEXR_COMPRESSIONTYPE_PIZ* = (4)
  TINYEXR_COMPRESSIONTYPE_ZFP* = (128) ##  TinyEXR extension
  TINYEXR_ZFP_COMPRESSIONTYPE_RATE* = (0)
  TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION* = (1)
  TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY* = (2)
  TINYEXR_TILE_ONE_LEVEL* = (0)
  TINYEXR_TILE_MIPMAP_LEVELS* = (1)
  TINYEXR_TILE_RIPMAP_LEVELS* = (2)
  TINYEXR_TILE_ROUND_DOWN* = (0)
  TINYEXR_TILE_ROUND_UP* = (1)

type
  EXRVersion* {.pure, bycopy.} = object
    version*: cint
    ##  this must be 2
    ##  tile format image;
    ##  not zero for only a single-part "normal" tiled file (according to spec.)
    tiled*: cint
    long_name*: cint
    ##  long name attribute
    ##  deep image(EXR 2.0);
    ##  for a multi-part file, indicates that at least one part is of type deep* (according to spec.)
    non_image*: cint
    multipart*: cint
    ##  multi-part(EXR 2.0)

  EXRAttribute* {.pure, bycopy.} = object
    name*: array[256, char]
    ##  name and type are up to 255 chars long.
    `type`*: array[256, char]
    value*: ptr uint8
    ##  uint8_t*
    size*: cint
    pad0*: cint

  EXRChannelInfo* {.pure, bycopy.} = object
    name*: array[256, char]
    ##  less than 255 bytes long
    pixel_type*: cint
    x_sampling*: cint
    y_sampling*: cint
    p_linear*: uint8
    pad*: array[3, uint8]

  EXRTile* {.pure, bycopy.} = object
    offset_x*: cint
    offset_y*: cint
    level_x*: cint
    level_y*: cint
    width*: cint
    ##  actual width in a tile.
    height*: cint
    ##  actual height int a tile.
    images*: ptr ptr uint8
    ##  image[channels][pixels]

  EXRBox2i* {.pure, bycopy.} = object
    min_x*: cint
    min_y*: cint
    max_x*: cint
    max_y*: cint

  EXRHeader* {.pure, bycopy.} = object
    pixel_aspect_ratio*: cfloat
    line_order*: cint
    data_window*: EXRBox2i
    display_window*: EXRBox2i
    screen_window_center*: array[2, cfloat]
    screen_window_width*: cfloat
    chunk_count*: cint
    ##  Properties for tiled format(`tiledesc`).
    tiled*: cint
    tile_size_x*: cint
    tile_size_y*: cint
    tile_level_mode*: cint
    tile_rounding_mode*: cint
    long_name*: cint
    ##  for a single-part file, agree with the version field bit 11
    ##  for a multi-part file, it is consistent with the type of part
    non_image*: cint
    multipart*: cint
    header_len*: cuint
    ##  Custom attributes(exludes required attributes(e.g. `channels`,
    ##  `compression`, etc)
    num_custom_attributes*: cint
    custom_attributes*: ptr EXRAttribute
    ##  array of EXRAttribute. size =
    ##  `num_custom_attributes`.
    channels*: ptr EXRChannelInfo
    ##  [num_channels]
    pixel_types*: ptr cint
    ##  Loaded pixel type(TINYEXR_PIXELTYPE_*) of `images` for
    ##  each channel. This is overwritten with `requested_pixel_types` when
    ##  loading.
    num_channels*: cint
    compression_type*: cint
    ##  compression type(TINYEXR_COMPRESSIONTYPE_*)
    requested_pixel_types*: ptr cint
    ##  Filled initially by
    ##  ParseEXRHeaderFrom(Meomory|File), then users
    ##  can edit it(only valid for HALF pixel type
    ##  channel)
    ##  name attribute required for multipart files;
    ##  must be unique and non empty (according to spec.);
    ##  use EXRSetNameAttr for setting value;
    ##  max 255 character allowed - excluding terminating zero
    name*: array[256, char]

  EXRMultiPartHeader* {.pure, bycopy.} = object
    num_headers*: cint
    headers*: ptr EXRHeader

  EXRImage* {.pure, bycopy.} = object
    tiles*: ptr EXRTile
    ##  Tiled pixel data. The application must reconstruct image
    ##  from tiles manually. NULL if scanline format.
    next_level*: ptr EXRImage
    ##  NULL if scanline format or image is the last level.
    level_x*: cint
    ##  x level index
    level_y*: cint
    ##  y level index
    images*: ptr ptr uint8
    ##  image[channels][pixels]. NULL if tiled format.
    width*: cint
    height*: cint
    num_channels*: cint
    ##  Properties for tile format.
    num_tiles*: cint

  EXRMultiPartImage* {.pure, bycopy.} = object
    num_images*: cint
    images*: ptr EXRImage

  DeepImage* {.pure, bycopy.} = object
    channel_names*: cstringArray
    image*: ptr ptr ptr cfloat
    ##  image[channels][scanlines][samples]
    offset_table*: ptr ptr cint
    ##  offset_table[scanline][offsets]
    num_channels*: cint
    width*: cint
    height*: cint
    pad0*: cint


##  @deprecated { For backward compatibility. Not recommended to use. }
##  Loads single-frame OpenEXR image. Assume EXR image contains A(single channel
##  alpha) or RGB(A) channels.
##  Application must free image data as returned by `out_rgba`
##  Result image format is: float x RGBA x width x hight
##  Returns negative value and may set error string in `err` when there's an
##  error

proc LoadEXR*(out_rgba: var ptr UncheckedArray[cfloat]; width: var cint; height: var cint;
             filename: cstring; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Loads single-frame OpenEXR image by specifying layer name. Assume EXR image
##  contains A(single channel alpha) or RGB(A) channels. Application must free
##  image data as returned by `out_rgba` Result image format is: float x RGBA x
##  width x hight Returns negative value and may set error string in `err` when
##  there's an error When the specified layer name is not found in the EXR file,
##  the function will return `TINYEXR_ERROR_LAYER_NOT_FOUND`.

proc LoadEXRWithLayer*(out_rgba: var ptr UncheckedArray[cfloat]; width: var cint; height: var cint;
                      filename: cstring; layer_name: cstring; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##
##  Get layer infos from EXR file.
##
##  @param[out] layer_names List of layer names. Application must free memory
##  after using this.
##  @param[out] num_layers The number of layers
##  @param[out] err Error string(will be filled when the function returns error
##  code). Free it using FreeEXRErrorMessage after using this value.
##
##  @return TINYEXR_SUCCEES upon success.
##

proc EXRLayers*(filename: cstring; layer_names: ptr cstringArray;
               num_layers: ptr cint; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  @deprecated
##  Simple wrapper API for ParseEXRHeaderFromFile.
##  checking given file is a EXR file(by just look up header)
##  @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for
##  others

proc IsEXR*(filename: cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Simple wrapper API for ParseEXRHeaderFromMemory.
##  Check if given data is a EXR image(by just looking up a header section)
##  @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for
##  others

proc IsEXRFromMemory*(memory: pointer; size: csize_t): cint {.cdecl, importc, raises: [], gcsafe.}
##  @deprecated
##  Saves single-frame OpenEXR image to a buffer. Assume EXR image contains RGB(A) channels.
##  components must be 1(Grayscale), 3(RGB) or 4(RGBA).
##  Input image format is: `float x width x height`, or `float x RGB(A) x width x
##  hight`
##  Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero
##  value.
##  Save image as fp32(FLOAT) format when `save_as_fp16` is 0.
##  Use ZIP compression by default.
##  `buffer` is the pointer to write EXR data.
##  Memory for `buffer` is allocated internally in SaveEXRToMemory.
##  Returns the data size of EXR file when the value is positive(up to 2GB EXR data).
##  Returns negative value and may set error string in `err` when there's an
##  error

proc SaveEXRToMemory*(data: ptr cfloat; width: cint; height: cint; components: cint;
                     save_as_fp16: cint; buffer: ptr ptr uint8; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  @deprecated { Not recommended, but handy to use. }
##  Saves single-frame OpenEXR image to a buffer. Assume EXR image contains RGB(A) channels.
##  components must be 1(Grayscale), 3(RGB) or 4(RGBA).
##  Input image format is: `float x width x height`, or `float x RGB(A) x width x
##  hight`
##  Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero
##  value.
##  Save image as fp32(FLOAT) format when `save_as_fp16` is 0.
##  Use ZIP compression by default.
##  Returns TINYEXR_SUCCEES(0) when success.
##  Returns negative value and may set error string in `err` when there's an
##  error

proc SaveEXR*(data: ptr cfloat; width: cint; height: cint; components: cint;
             save_as_fp16: cint; filename: cstring; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Returns the number of resolution levels of the image (including the base)

proc EXRNumLevels*(exr_image: var EXRImage): cint {.cdecl, importc, raises: [], gcsafe.}
##  Initialize EXRHeader struct

proc InitEXRHeader*(exr_header: var EXRHeader) {.cdecl, importc, raises: [], gcsafe.}
##  Set name attribute of EXRHeader struct (it makes a copy)

proc EXRSetNameAttr*(exr_header: var EXRHeader; name: cstring) {.cdecl, importc, raises: [], gcsafe.}
##  Initialize EXRImage struct

proc InitEXRImage*(exr_image: var EXRImage) {.cdecl, importc, raises: [], gcsafe.}
##  Frees internal data of EXRHeader struct

proc FreeEXRHeader*(exr_header: var EXRHeader): cint {.cdecl, importc, raises: [], gcsafe.}
##  Frees internal data of EXRImage struct

proc FreeEXRImage*(exr_image: var EXRImage): cint {.cdecl, importc, raises: [], gcsafe.}
##  Frees error message

proc FreeEXRErrorMessage*(msg: cstring) {.cdecl, importc, raises: [], gcsafe.}
##  Parse EXR version header of a file.

proc ParseEXRVersionFromFile*(version: var EXRVersion; filename: cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Parse EXR version header from memory-mapped EXR data.

proc ParseEXRVersionFromMemory*(version: var EXRVersion; memory: pointer;
                               size: csize_t): cint {.cdecl, importc, raises: [], gcsafe.}
##  Parse single-part OpenEXR header from a file and initialize `EXRHeader`.
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc ParseEXRHeaderFromFile*(header: var EXRHeader; version: var EXRVersion;
                            filename: cstring; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Parse single-part OpenEXR header from a memory and initialize `EXRHeader`.
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc ParseEXRHeaderFromMemory*(header: var EXRHeader; version: var EXRVersion;
                              memory: pointer; size: csize_t; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*`
##  array.
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc ParseEXRMultipartHeaderFromFile*(headers: var ptr ptr EXRHeader;
                                     num_headers: var cint;
                                     version: var EXRVersion; filename: cstring;
                                     err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*`
##  array
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc ParseEXRMultipartHeaderFromMemory*(headers: var ptr ptr EXRHeader;
                                       num_headers: var cint;
                                       version: var EXRVersion; memory: pointer;
                                       size: csize_t; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Loads single-part OpenEXR image from a file.
##  Application must setup `ParseEXRHeaderFromFile` before calling this function.
##  Application can free EXRImage using `FreeEXRImage`
##  Returns negative value and may set error string in `err` when there's an
##  error
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc LoadEXRImageFromFile*(image: var EXRImage; header: var EXRHeader;
                          filename: cstring; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Loads single-part OpenEXR image from a memory.
##  Application must setup `EXRHeader` with
##  `ParseEXRHeaderFromMemory` before calling this function.
##  Application can free EXRImage using `FreeEXRImage`
##  Returns negative value and may set error string in `err` when there's an
##  error
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc LoadEXRImageFromMemory*(image: var EXRImage; header: var EXRHeader;
                            memory: pointer; size: csize_t; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Loads multi-part OpenEXR image from a file.
##  Application must setup `ParseEXRMultipartHeaderFromFile` before calling this
##  function.
##  Application can free EXRImage using `FreeEXRImage`
##  Returns negative value and may set error string in `err` when there's an
##  error
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc LoadEXRMultipartImageFromFile*(images: var EXRImage;
                                   headers: var ptr EXRHeader; num_parts: cuint;
                                   filename: cstring; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Loads multi-part OpenEXR image from a memory.
##  Application must setup `EXRHeader*` array with
##  `ParseEXRMultipartHeaderFromMemory` before calling this function.
##  Application can free EXRImage using `FreeEXRImage`
##  Returns negative value and may set error string in `err` when there's an
##  error
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc LoadEXRMultipartImageFromMemory*(images: var EXRImage;
                                     headers: var ptr EXRHeader; num_parts: cuint;
                                     memory: pointer; size: csize_t;
                                     err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Saves multi-channel, single-frame OpenEXR image to a file.
##  Returns negative value and may set error string in `err` when there's an
##  error
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc SaveEXRImageToFile*(image: var EXRImage; exr_header: var EXRHeader;
                        filename: cstring; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Saves multi-channel, single-frame OpenEXR image to a memory.
##  Image is compressed using EXRImage.compression value.
##  Return the number of bytes if success.
##  Return zero and will set error string in `err` when there's an
##  error.
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc SaveEXRImageToMemory*(image: var EXRImage; exr_header: var EXRHeader;
                          memory: var ptr uint8; err: var const_cstring): csize_t {.cdecl, importc, raises: [], gcsafe.}
##  Saves multi-channel, multi-frame OpenEXR image to a memory.
##  Image is compressed using EXRImage.compression value.
##  File global attributes (eg. display_window) must be set in the first header.
##  Returns negative value and may set error string in `err` when there's an
##  error
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc SaveEXRMultipartImageToFile*(images: var EXRImage;
                                 exr_headers: var ptr EXRHeader; num_parts: cuint;
                                 filename: cstring; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  Saves multi-channel, multi-frame OpenEXR image to a memory.
##  Image is compressed using EXRImage.compression value.
##  File global attributes (eg. display_window) must be set in the first header.
##  Return the number of bytes if success.
##  Return zero and will set error string in `err` when there's an
##  error.
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc SaveEXRMultipartImageToMemory*(images: var EXRImage;
                                   exr_headers: var ptr EXRHeader; num_parts: cuint;
                                   memory: var ptr uint8; err: var const_cstring): csize_t {.cdecl, importc, raises: [], gcsafe.}
##  Loads single-frame OpenEXR deep image.
##  Application must free memory of variables in DeepImage(image, offset_table)
##  Returns negative value and may set error string in `err` when there's an
##  error
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc LoadDeepEXR*(out_image: var DeepImage; filename: cstring; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}
##  NOT YET IMPLEMENTED:
##  Saves single-frame OpenEXR deep image.
##  Returns negative value and may set error string in `err` when there's an
##  error
##  extern int SaveDeepEXR(const DeepImage *in_image, const char *filename,
##                        const char **err);
##  NOT YET IMPLEMENTED:
##  Loads multi-part OpenEXR deep image.
##  Application must free memory of variables in DeepImage(image, offset_table)
##  extern int LoadMultiPartDeepEXR(DeepImage **out_image, int num_parts, const
##  char *filename,
##                        const char **err);
##  For emscripten.
##  Loads single-frame OpenEXR image from memory. Assume EXR image contains
##  RGB(A) channels.
##  Returns negative value and may set error string in `err` when there's an
##  error
##  When there was an error message, Application must free `err` with
##  FreeEXRErrorMessage()

proc LoadEXRFromMemory*(out_rgba: var ptr UncheckedArray[cfloat]; width: var cint; height: var cint;
                       memory: pointer; size: csize_t; err: var const_cstring): cint {.cdecl, importc, raises: [], gcsafe.}