# We need this for the extern "C", not for exposing symbols
{.passC:"-DASTCENC_DYNAMIC_LIBRARY".}

{.compile:"astc-encoder/Source/astcenc_averages_and_directions.cpp",
compile:"astc-encoder/Source/astcenc_block_sizes.cpp",
compile:"astc-encoder/Source/astcenc_color_quantize.cpp",
compile:"astc-encoder/Source/astcenc_color_unquantize.cpp",
compile:"astc-encoder/Source/astcenc_compress_symbolic.cpp",
compile:"astc-encoder/Source/astcenc_compute_variance.cpp",
compile:"astc-encoder/Source/astcenc_decompress_symbolic.cpp",
compile:"astc-encoder/Source/astcenc_diagnostic_trace.cpp",
compile:"astc-encoder/Source/astcenc_entry.cpp",
compile:"astc-encoder/Source/astcenc_find_best_partitioning.cpp",
compile:"astc-encoder/Source/astcenc_ideal_endpoints_and_weights.cpp",
compile:"astc-encoder/Source/astcenc_image.cpp",
compile:"astc-encoder/Source/astcenc_integer_sequence.cpp",
compile:"astc-encoder/Source/astcenc_mathlib.cpp",
compile:"astc-encoder/Source/astcenc_mathlib_softfloat.cpp",
compile:"astc-encoder/Source/astcenc_partition_tables.cpp",
compile:"astc-encoder/Source/astcenc_percentile_tables.cpp",
compile:"astc-encoder/Source/astcenc_pick_best_endpoint_format.cpp",
compile:"astc-encoder/Source/astcenc_quantization.cpp",
compile:"astc-encoder/Source/astcenc_symbolic_physical.cpp",
compile:"astc-encoder/Source/astcenc_weight_align.cpp",
compile:"astc-encoder/Source/astcenc_weight_quant_xfer_tables.cpp".}

type AstcencContext* = object

type AstcencError* {.size:4.} = enum
    ASTCENC_SUCCESS = 0, ASTCENC_ERR_OUT_OF_MEM, ASTCENC_ERR_BAD_CPU_FLOAT,
    ASTCENC_ERR_BAD_PARAM, ASTCENC_ERR_BAD_BLOCK_SIZE, ASTCENC_ERR_BAD_PROFILE,
    ASTCENC_ERR_BAD_QUALITY, ASTCENC_ERR_BAD_SWIZZLE, ASTCENC_ERR_BAD_FLAGS,
    ASTCENC_ERR_BAD_CONTEXT, ASTCENC_ERR_NOT_IMPLEMENTED,
    ASTCENC_ERR_BAD_DECODE_MODE, ASTCENC_ERR_DTRACE_FAILURE

template astc_assert*(err: AstcencError) =
    assert err == ASTCENC_SUCCESS, "ASTC error: " & $err

type AstcencProfile* {.size:4.} = enum
    ASTCENC_PRF_LDR_SRGB = 0, ASTCENC_PRF_LDR, ASTCENC_PRF_HDR_RGB_LDR_A,
    ASTCENC_PRF_HDR

let ASTCENC_PRE_FASTEST*: float32 = 0.0f
let ASTCENC_PRE_FAST*: float32 = 10.0f
let ASTCENC_PRE_MEDIUM*: float32 = 60.0f
let ASTCENC_PRE_THOROUGH*: float32 = 98.0f
let ASTCENC_PRE_VERYTHOROUGH*: float32 = 99.0f
let ASTCENC_PRE_EXHAUSTIVE*: float32 = 100.0f

type AstcencSwz* {.size:4.} = enum
    SWZ_R = 0, SWZ_G = 1, SWZ_B = 2, SWZ_A = 3,
    SWZ_0 = 4, SWZ_1 = 5, SWZ_Z = 6

type AstcencSwizzle* {.bycopy.} = object
    r*: AstcencSwz
    g*: AstcencSwz
    b*: AstcencSwz
    a*: AstcencSwz

type AstcencType* {.size:4.} = enum
    ASTCENC_TYPE_U8 = 0, ASTCENC_TYPE_F16 = 1, ASTCENC_TYPE_F32 = 2

type AstcencProgressCallback* = proc(p: float32) {.cdecl.}

let ASTCENC_FLG_MAP_NORMAL*: uint32 = 1 shl 0
let ASTCENC_FLG_USE_DECODE_UNORM8*: uint32 = 1 shl 1
let ASTCENC_FLG_USE_ALPHA_WEIGHT*: uint32 = 1 shl 2
let ASTCENC_FLG_USE_PERCEPTUAL*: uint32 = 1 shl 3
let ASTCENC_FLG_DECOMPRESS_ONLY*: uint32 = 1 shl 4
let ASTCENC_FLG_SELF_DECOMPRESS_ONLY*: uint32 = 1 shl 5
let ASTCENC_FLG_MAP_RGBM*: uint32 = 1 shl 6
let ASTCENC_ALL_FLAGS*: uint32 = ASTCENC_FLG_MAP_NORMAL or ASTCENC_FLG_MAP_RGBM or
    ASTCENC_FLG_USE_ALPHA_WEIGHT or ASTCENC_FLG_USE_PERCEPTUAL or
    ASTCENC_FLG_USE_DECODE_UNORM8 or ASTCENC_FLG_DECOMPRESS_ONLY or
    ASTCENC_FLG_SELF_DECOMPRESS_ONLY

type AstcencConfig* {.bycopy.} = object
    profile*: AstcencProfile
    flags*: uint32
    block_x*: uint32
    block_y*: uint32
    block_z*: uint32
    cw_r_weight*: float32
    cw_g_weight*: float32
    cw_b_weight*: float32
    cw_a_weight*: float32
    a_scale_radius*: uint32
    rgbm_m_scale*: float32
    tune_partition_count_limit*: uint32
    tune_2partition_index_limit*: uint32
    tune_3partition_index_limit*: uint32
    tune_4partition_index_limit*: uint32
    tune_block_mode_limit*: uint32
    tune_refinement_limit*: uint32
    tune_candidate_limit*: uint32
    tune_2partitioning_candidate_limit*: uint32
    tune_3partitioning_candidate_limit*: uint32
    tune_4partitioning_candidate_limit*: uint32
    tune_db_limit*: float32
    tune_mse_overshoot*: float32
    tune_2partition_early_out_limit_factor*: float32
    tune_3partition_early_out_limit_factor*: float32
    tune_2plane_early_out_limit_correlation*: float32
    tune_search_mode0_enable*: float32
    progress_callback*: AstcencProgressCallback
    when defined(ASTCENC_DIAGNOSTICS):
        trace_file_path*: cstring

type AstcencImage* {.bycopy.} = object
    dim_x*: uint32
    dim_y*: uint32
    dim_z*: uint32
    data_type*: AstcencType
    data*: ptr pointer

type AstcencBlockInfo* {.bycopy.} = object
    profile*: AstcencProfile
    block_x*: uint32
    block_y*: uint32
    block_z*: uint32
    texel_count*: uint32
    is_error_block*: bool
    is_constant_block*: bool
    is_hdr_block*: bool
    is_dual_plane_block*: bool
    partition_count*: uint32
    partition_index*: uint32
    dual_plane_component*: uint32
    color_endpoint_modes*: array[4, uint32]
    color_level_count*: uint32
    weight_level_count*: uint32
    weight_x*: uint32
    weight_y*: uint32
    weight_z*: uint32
    color_endpoints*: array[4, array[2, array[4, float32]]]
    weight_values_plane1*: array[216, float32]
    weight_values_plane2*: array[216, float32]
    partition_assignment*: array[216, uint8]

proc astcenc_config_init*(profile: AstcencProfile; block_x: uint32; block_y: uint32;
                         block_z: uint32; quality: float32; flags: uint32;
                         config: ptr AstcencConfig): AstcencError {.cdecl,
    importc: "astcenc_config_init".}
proc astcenc_context_alloc*(config: ptr AstcencConfig; thread_count: uint32;
                           context: var ptr AstcencContext): AstcencError {.cdecl,
    importc: "astcenc_context_alloc".}
proc astcenc_compress_image*(context: ptr AstcencContext; image: ptr AstcencImage;
                            swizzle: ptr AstcencSwizzle; data_out: ptr uint8;
                            data_len: csize_t; thread_index: uint32): AstcencError {.
    cdecl, importc: "astcenc_compress_image".}
proc astcenc_compress_reset*(context: ptr AstcencContext): AstcencError {.cdecl,
    importc: "astcenc_compress_reset".}
proc astcenc_decompress_image*(context: ptr AstcencContext; data: ptr uint8;
                              data_len: csize_t; image_out: ptr AstcencImage;
                              swizzle: ptr AstcencSwizzle; thread_index: uint32): AstcencError {.
    cdecl, importc: "astcenc_decompress_image".}
proc astcenc_decompress_reset*(context: ptr AstcencContext): AstcencError {.cdecl,
    importc: "astcenc_decompress_reset".}
proc astcenc_context_free*(context: ptr AstcencContext) {.cdecl,
    importc: "astcenc_context_free".}
proc astcenc_get_block_info*(context: ptr AstcencContext; data: array[16, uint8];
                            info: ptr AstcencBlockInfo): AstcencError {.cdecl,
    importc: "astcenc_get_block_info".}
proc astcenc_get_error_string*(status: AstcencError): cstring {.cdecl,
    importc: "astcenc_get_error_string".}