//===============================================================================
// Copyright (c) 2014-2016  Advanced Micro Devices, Inc. All rights reserved.
//===============================================================================
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// 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 Software.
//
// THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////////

#pragma once

//#ifndef _BC6H_DEFINITIONS_H_
//#define _BC6H_DEFINITIONS_H_

#include "hdr_encode.h"


#include <cstdint>
#include <cstdlib>
#include <cstring>

using CMP_HALF = uint16_t; // ?

typedef std::uint8_t BYTE;
typedef std::uint32_t DWORD;

#define TRUE 1
#define FALSE 0

#define BC6H_NUM_BLOCK_TYPES            14
#define BC6H_MAX_PARTITIONS             32
#define BC6H_MAX_SUBSETS                2
#define BC6H_MAX_SUBSET_SIZE            16
#define BC6H_COMPRESSED_BLOCK_SIZE      16
#define BC6H_MAX_PARTITIONS_TABLE       (1+64+64)
#define BC6H_MAX_INDEX_BITS             4        // Maximum number of index bits: This should be set to 3
#define NCHANNELS                       3
#define NINDICES                        16
#define MAXENDPOINTS                    2
#define F16NEGPREC_LIMIT_VAL            -2048.0f //f16 negative precision limit value
#define F16MAX                          0x7bff
#define F16S_MASK                       0x8000   // f16 sign mask
#define F16EM_MASK                      0x7fff   // f16 exp & mantissa mask
#define U16MAX                          0xffff
#define S16MIN                          (-0x8000)
#define S16MAX                          0x7fff
#define INT16_MASK                      0xffff
#define BC6H_WEIGHT_MAX                 64       // scale from 0 to 64
#define BC6H_WEIGHT_SHIFT               6        // Using shift operator (Multipler or divider by 64)
#define BC6H_WEIGHT_ROUND               32       // take care of round up errors
#define BC6H_OFFSET_MAG                 31       // This offsets the colors from the actual line by a factor mag/32 or mag/64
#define MAX_TWOREGION_MODES             10
#define MAX_BC6H_MODES                  14
#define MAX_BC6H_PARTITIONS             32
#define HIGH_INDEX_BIT                  4
#define ONE_REGION_INDEX_OFFSET         65        // bit location to start saving color index values for single region shape
#define TWO_REGION_INDEX_OFFSET         82        // bit location to start saving color index values for two region shapes
#define MIN_MODE_FOR_ONE_REGION         11        // Two regions shapes use modes 1..9 and single use 11..14
#define R_0(ep)                         (ep)[0][0][i]
#define R_1(ep)                         (ep)[0][1][i]
#define R_2(ep)                         (ep)[1][0][i]
#define R_3(ep)                         (ep)[1][1][i]
#define MASK(n)                         ((1<<(n))-1)
#define SIGN_EXTEND(w,tbits)            ((((signed(w))&(1<<((tbits)-1)))?((~0)<<(tbits)):0)|(signed(w)))
#define REGION(x,y,si)                  shapes[((si)&3)*4+((si)>>2)*64+(x)+(y)*16]
#define BC6H_NREGIONS                   2                 // shapes for two regions

// this might get optimized away
inline bool cmp_isnan(float v) { return v != v; }

typedef unsigned int uint;
typedef enum _BC6H_COMPONENT {
    BC6H_COMP_RED   = 0,
    BC6H_COMP_GREEN = 1,
    BC6H_COMP_BLUE =  2,
    BC6H_COMP_ALPHA = 3
} BC6H_COMPONENT;

enum {
    BC6_ONE = 0,
    BC6_TWO
};

enum {
    C_RED = 0,
    C_GREEN,
    C_BLUE
};

enum {
    UNSIGNED_F16 = 1,
    SIGNED_F16     = 2
};

enum EField {
    NA, // N/A
    M,  // Mode
    D,  // Shape
    RW,
    RX,
    RY,
    RZ,
    GW,
    GX,
    GY,
    GZ,
    BW,
    BX,
    BY,
    BZ,
};

struct EndPointPair {
    int A;
    int B;
};


struct BC6H_Vec3 {
    int x,y,z;
};

struct BC6H_Vec3f {
    float x, y, z;
};

struct UShortVec3 {
    unsigned short x,y,z;
};


struct ModePartitions {
    int nbits;              // Number of bits
    int prec[3];            // precission of the Qunatized RGB endpoints
    int transformed;        // if 0, deltas are unsigned and no transform; otherwise, signed and transformed
    int modebits;           // number of mode bits
    int IndexPrec;          // Index Precision
    int mode;               // Mode value to save
    int lowestPrec;         // Step size of each precesion incriment
};

static ModePartitions ModePartition[MAX_BC6H_MODES +1] = {
    {0,    {0,0,0},        0,    0,    0,    0,     0  },// Mode = Invaild
    
    // Two region Partition
    {10,   {5,5,5},        1,    2,    3,    0x00,  31 },  // Mode = 1
    {7,    {6,6,6},        1,    2,    3,    0x01,  248},  // Mode = 2
    {11,   {5,4,4},        1,    5,    3,    0x02,  15 },  // Mode = 3
    {11,   {4,5,4},        1,    5,    3,    0x06,  15 },  // Mode = 4
    {11,   {4,4,5},        1,    5,    3,    0x0a,  15 },  // Mode = 5
    {9,    {5,5,5},        1,    5,    3,    0x0e,  62 },  // Mode = 6
    {8,    {6,5,5},        1,    5,    3,    0x12,  124},  // Mode = 7
    {8,    {5,6,5},        1,    5,    3,    0x16,  124},  // Mode = 8
    {8,    {5,5,6},        1,    5,    3,    0x1a,  124},  // Mode = 9
    {6,    {6,6,6},        0,    5,    3,    0x1e,  496},  // Mode = 10
            
    // One region Partition
    {10,   {10,10,10},     0,    5,    4,    0x03,  31 },  // Mode = 11
    {11,   {9,9,9},        1,    5,    4,    0x07,  15 },  // Mode = 12
    {12,   {8,8,8},        1,    5,    4,    0x0b,  7  },  // Mode = 13
    {16,   {4,4,4},        1,    5,    4,    0x0f,  1  }  // Mode = 14
};


//  Shape, Fixup Index locations for region 1's (subset = 2)
// locations accroding to BC6H documentation on a 4x4 block
//        15,15,15, 15,
//        15,15,15, 15,
//        15,15,15, 15,
//        15,15,15, 15,
//        15, 2, 8,  2,
//         2, 8, 8, 15,
//         2, 8, 2,  2,
//         8, 8, 2,  2,
//
// The Region2FixUps are for our index[subset = 2][16][3] locations
// indexed by shape region 2
static const int g_Region2FixUp[32] = {
    7, 3, 11, 7,
    3, 11, 9, 5,
    2, 12, 7, 3,
    11, 7, 11, 3,
    7, 1, 0, 1,
    0, 1, 0, 7,
    0, 1, 1, 0,
    4, 4, 1, 0,
};

// Indexed by all shape regions
// Partition Set Fixups for region 1 note region 0 is always at 0
// that means normally we use 3 bits to define an index value
// if its at the fix up location then its one bit less
static const int g_indexfixups[32] = {
    15,15,15,15,
    15,15,15,15,
    15,15,15,15,
    15,15,15,15,
    15, 2, 8, 2,
    2, 8, 8,15,
    2, 8, 2, 2,
    8, 8, 2, 2,
};


//------------------------------------------------------------------------------


/*============================================================================================================
MODE FORMAT TABLE:

Mode    Partition Indices    Partition    Color Endpoints                        Mode Bits            Dec value
1        46 bits                5 bits        75 bits (10.555, 10.555, 10.555)   2 bits (00)           0
2        46 bits                5 bits        75 bits (7666, 7666, 7666)         2 bits (01)           1
3        46 bits                5 bits        72 bits (11.555, 11.444, 11.444)   5 bits (00010)        2
4        46 bits                5 bits        72 bits (11.444, 11.555, 11.444)   5 bits (00110)        6
5        46 bits                5 bits        72 bits (11.444, 11.444, 11.555)   5 bits (01010)        10
6        46 bits                5 bits        72 bits (9555, 9555, 9555)         5 bits (01110)        14
7        46 bits                5 bits        72 bits (8666, 8555, 8555)         5 bits (10010)        18
8        46 bits                5 bits        72 bits (8555, 8666, 8555)         5 bits (10110)        22
9        46 bits                5 bits        72 bits (8555, 8555, 8666)         5 bits (11010)        26
10       46 bits                5 bits        72 bits (6666, 6666, 6666)         5 bits (11110)        30
11       63 bits                0 bits        60 bits (10.10, 10.10, 10.10)      5 bits (00011)        3
12       63 bits                0 bits        60 bits (11.9, 11.9, 11.9)         5 bits (00111)        7
13       63 bits                0 bits        60 bits (12.8, 12.8, 12.8)         5 bits (01011)        11
14       63 bits                0 bits        60 bits (16.4, 16.4, 16.4)         5 bits (01111)        15
============================================================================================================*/

struct END_Points {
    int A[NCHANNELS];
    int B[NCHANNELS];
};

struct AMD_BC6H_Format {
    unsigned short region;             // one or two
    unsigned short m_mode;             // m
    int d_shape_index;                 // d
    int rw;                            // endpt[0].A[0]
    int rx;                            // endpt[0].B[0]
    int ry;                            // endpt[1].A[0]
    int rz;                            // endpt[1].B[0]
    int gw;                            // endpt[0].A[1]
    int gx;                            // endpt[0].B[1]
    int gy;                            // endpt[1].A[1]
    int gz;                            // endpt[1].B[1]
    int bw;                            // endpt[0].A[2]
    int bx;                            // endpt[0].B[2]
    int by;                            // endpt[1].A[2]
    int bz;                            // endpt[1].B[2]

    union {
        std::uint8_t indices[4][4];            // Indices data after header block
        std::uint8_t indices16[16];
    };

    float         din[MAX_SUBSET_SIZE][MAX_DIMENSION_BIG];   // Original data input
    END_Points    EC[MAXENDPOINTS];    // compressed endpoints expressed as endpt[0].A[] and endpt[1].B[]
    END_Points    E[MAXENDPOINTS];     // decompressed endpoints
    bool          issigned;            // Format is 16 bit signed floating point
    bool          istransformed;       // region two: all modes = true except mode=10
    short         wBits;               // number of bits for the root endpoint
    short         tBits[NCHANNELS];    // number of bits used for the transformed endpoints
    int           format;              // floating point format are we using for decompression
    BC6H_Vec3      Palete[2][16];
    BC6H_Vec3f     Paletef[2][16];

    int           index;               // for debugging
    float         fEndPoints[MAX_SUBSETS][MAX_END_POINTS][MAX_DIMENSION_BIG];
    float         cur_best_fEndPoints[MAX_SUBSETS][MAX_END_POINTS][MAX_DIMENSION_BIG];
    int           shape_indices[MAX_SUBSETS][MAX_SUBSET_SIZE];
    int           cur_best_shape_indices[MAX_SUBSETS][MAX_SUBSET_SIZE];
    int           entryCount[MAX_SUBSETS];
    int           cur_best_entryCount[MAX_SUBSETS];
    float         partition[MAX_SUBSETS][MAX_SUBSET_SIZE][MAX_DIMENSION_BIG];
    float         cur_best_partition[MAX_SUBSETS][MAX_SUBSET_SIZE][MAX_DIMENSION_BIG];
    bool          optimized;           // were end points optimized during final encoding
};

//extern unsigned short    g_BC6H_FORMAT;

#ifndef DEFINE_BC6H_PARTITIONS
extern uint8_t   BC6_PARTITIONS[MAX_SUBSETS][MAX_PARTITIONS][MAX_SUBSET_SIZE];

#else
uint8_t   BC6_PARTITIONS[MAX_SUBSETS][MAX_PARTITIONS][MAX_SUBSET_SIZE] = {
    // Single subset partitions for both BC6H abd BC7 up to 32 elements.
    {
        {
            0, 0, 0, 0,
            0, 0, 0, 0,
            0, 0, 0, 0,
            0, 0, 0, 0,
        },
    },

    {
        {
            // 0
            0,0,1,1,
            0,0,1,1,
            0,0,1,1,
            0,0,1,1
        },

        {
            // 1
            0,0,0,1,
            0,0,0,1,
            0,0,0,1,
            0,0,0,1
        },

        {
            // 2
            0,1,1,1,
            0,1,1,1,
            0,1,1,1,
            0,1,1,1
        },

        {
            // 3
            0,0,0,1,
            0,0,1,1,
            0,0,1,1,
            0,1,1,1
        },

        {
            // 4
            0,0,0,0,
            0,0,0,1,
            0,0,0,1,
            0,0,1,1
        },

        {
            // 5
            0,0,1,1,
            0,1,1,1,
            0,1,1,1,
            1,1,1,1
        },

        {
            // 6
            0,0,0,1,
            0,0,1,1,
            0,1,1,1,
            1,1,1,1
        },

        {
            // 7
            0,0,0,0,
            0,0,0,1,
            0,0,1,1,
            0,1,1,1
        },

        {
            // 8
            0,0,0,0,
            0,0,0,0,
            0,0,0,1,
            0,0,1,1
        },

        {
            // 9
            0,0,1,1,
            0,1,1,1,
            1,1,1,1,
            1,1,1,1
        },

        {
            // 10
            0,0,0,0,
            0,0,0,1,
            0,1,1,1,
            1,1,1,1
        },

        {
            // 11
            0,0,0,0,
            0,0,0,0,
            0,0,0,1,
            0,1,1,1
        },

        {
            // 12
            0,0,0,1,
            0,1,1,1,
            1,1,1,1,
            1,1,1,1
        },

        {
            // 13
            0,0,0,0,
            0,0,0,0,
            1,1,1,1,
            1,1,1,1
        },

        {
            // 14
            0,0,0,0,
            1,1,1,1,
            1,1,1,1,
            1,1,1,1
        },

        {
            // 15
            0,0,0,0,
            0,0,0,0,
            0,0,0,0,
            1,1,1,1
        },

        {
            // 16
            0,0,0,0,
            1,0,0,0,
            1,1,1,0,
            1,1,1,1
        },

        {
            // 17
            0,1,1,1,
            0,0,0,1,
            0,0,0,0,
            0,0,0,0
        },

        {
            // 18
            0,0,0,0,
            0,0,0,0,
            1,0,0,0,
            1,1,1,0
        },

        {
            // 19
            0,1,1,1,
            0,0,1,1,
            0,0,0,1,
            0,0,0,0
        },

        {
            // 20
            0,0,1,1,
            0,0,0,1,
            0,0,0,0,
            0,0,0,0
        },

        {
            // 21
            0,0,0,0,
            1,0,0,0,
            1,1,0,0,
            1,1,1,0
        },

        {
            // 22
            0,0,0,0,
            0,0,0,0,
            1,0,0,0,
            1,1,0,0
        },

        {
            // 23
            0,1,1,1,
            0,0,1,1,
            0,0,1,1,
            0,0,0,1
        },

        {
            // 24
            0,0,1,1,
            0,0,0,1,
            0,0,0,1,
            0,0,0,0
        },

        {
            // 25
            0,0,0,0,
            1,0,0,0,
            1,0,0,0,
            1,1,0,0
        },

        {
            // 26
            0,1,1,0,
            0,1,1,0,
            0,1,1,0,
            0,1,1,0
        },

        {
            // 27
            0,0,1,1,
            0,1,1,0,
            0,1,1,0,
            1,1,0,0
        },

        {
            // 28
            0,0,0,1,
            0,1,1,1,
            1,1,1,0,
            1,0,0,0
        },

        {
            // 29
            0,0,0,0,
            1,1,1,1,
            1,1,1,1,
            0,0,0,0
        },

        {
            // 30
            0,1,1,1,
            0,0,0,1,
            1,0,0,0,
            1,1,1,0
        },

        {
            // 31
            0,0,1,1,
            1,0,0,1,
            1,0,0,1,
            1,1,0,0
        },
    }
};
#endif

#define PARTITIONS  BC6_PARTITIONS

//#endif
