// File: brianwu02[P]ImageProcessing/halftone.cpp
// Function: halftone(imageS*, int, float, imageS*)
void halftone(imageP I1, int m, float gamma, imageP I2) {
    
    int i, total, new_total, scale;
    unsigned char *in, *out;
    unsigned char quant_lut[256], gamma_corrected_lut[256];

    // found at https://engineering.purdue.edu/~bouman/ece637/notes/pdf/Halftoning.pdf
    int clusterDotMatrix[8][8] = {
        {62, 57, 48, 36, 37, 49, 58, 63,},
        {56, 47, 35, 21, 22, 38, 50, 59,},
        {46, 34, 20, 10, 11, 23, 39, 51,},
        {33, 19,  9,  3,  0,  4, 12, 24,},
        {32, 18,  8,  2,  1,  5, 13, 25,},
        {45, 31, 17,  7,  6, 14, 26, 40,},
        {55, 44, 30, 16, 15, 27, 41, 52,},
        {61, 54, 43, 29, 28, 42, 53, 60}
    };

    int clusterDot[3][3] = {
        {6, 8, 4,},
        {1, 0, 3,},
        {5, 2, 7 }
    };

    int cluster[2][2] = {
        {1, 2},
        {3, 0}
    };

    total = I1->width * I1->height;

    I2->width = m * I1->width;
    I2->height = m * I1->height;

    new_total = (m * I1->width) * (m * I2->height);
    I2->image = (unsigned char *) malloc(new_total);

    //cout << (int) new_total << endl;

    out = I2->image;
    in = I1->image;

    if (I2->image == NULL) {
        cerr << "Not enough memory\n";
        exit(1);
    }

    // create gamma correction lookup table
    for (i=0; i<256; i++) {
        gamma_corrected_lut[i] = (int) (pow((double) i / 255.0, (1.0 / gamma)) * 255.0);
    }

    // gamma correct the input Image
    for (i=0; i<total; i++) {
        in[i] = gamma_corrected_lut[in[i]];
    }

    // define scale & create quantization lookup table 
    // where scale is broken up in to m grayscale values
    int n = pow(m, 2);
    scale = 256 / n;
    for (i=0; i<256; i++) {
        quant_lut[i] = (int) (scale * (i / scale)) / scale;
    }

    // visit all input pixels and apply quantization to m levels
    for (i=0; i<total; i++) {
        in[i] = quant_lut[in[i]];
    }

    int w = I1->width;
    int h = I1->height;
    int nw = I2->width;
    int nh = I2->height;
    
    // loop over the "large" pixels
    for (int y=0; y<h; y++) {
        for (int x=0; x<w; x++) {
            // this loop here happens height * width times, representing the "large" pixel
            for (int j=0; j<m; j++) {
                for (int i=0; i<m; i++) {
                    
                    // THIS TOOK WAY TOO DAMN LONG TO FIGURE OUT, BUT DAMN IT FELT GOOD!
                    out[(m*y*nh) + (j*nw) + i + (m*x)] = ((in[y*w+x] > clusterDot[i][j]) ? 255 : 0);

                    // the Henry Xue Formula right here.
                    //out[(i+(m*j*m) + m*(x+m*y*w))] = ((in[y*w+x] > clusterDot[i][j]) ? 255 : 0);
                }
            }
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x3b0, %rsp            # imm = 0x3B0
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movss %xmm0, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
leaq -0x340(%rbp), %rdi
leaq 0xb97(%rip), %rsi       # 0x2070
movl $0x100, %edx            # imm = 0x100
callq 0x1090
leaq -0x370(%rbp), %rdi
leaq 0xc7f(%rip), %rsi       # 0x2170
movl $0x24, %edx
callq 0x1090
movq 0xc9e(%rip), %rax       # 0x21a0
movq %rax, -0x380(%rbp)
movq 0xc98(%rip), %rax       # 0x21a8
movq %rax, -0x378(%rbp)
movq -0x8(%rbp), %rax
movl (%rax), %eax
movq -0x8(%rbp), %rcx
imull 0x4(%rcx), %eax
movl %eax, -0x20(%rbp)
movl -0xc(%rbp), %ecx
movq -0x8(%rbp), %rax
imull (%rax), %ecx
movq -0x18(%rbp), %rax
movl %ecx, (%rax)
movl -0xc(%rbp), %ecx
movq -0x8(%rbp), %rax
imull 0x4(%rax), %ecx
movq -0x18(%rbp), %rax
movl %ecx, 0x4(%rax)
movl -0xc(%rbp), %eax
movq -0x8(%rbp), %rcx
imull (%rcx), %eax
movl -0xc(%rbp), %ecx
movq -0x18(%rbp), %rdx
imull 0x4(%rdx), %ecx
imull %ecx, %eax
movl %eax, -0x24(%rbp)
movslq -0x24(%rbp), %rdi
callq 0x1130
movq %rax, %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x38(%rbp)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x18(%rbp), %rax
cmpq $0x0, 0x8(%rax)
jne 0x15b9
movq 0x2a4d(%rip), %rdi      # 0x3ff0
leaq 0xab2(%rip), %rsi       # 0x205c
callq 0x10b0
movl $0x1, %edi
callq 0x10f0
movl $0x0, -0x1c(%rbp)
cmpl $0x100, -0x1c(%rbp)     # imm = 0x100
jge 0x161c
cvtsi2sdl -0x1c(%rbp), %xmm0
movsd 0xa32(%rip), %xmm1      # 0x2008
divsd %xmm1, %xmm0
movss -0x10(%rbp), %xmm1
cvtss2sd %xmm1, %xmm2
movsd 0xa25(%rip), %xmm1      # 0x2010
divsd %xmm2, %xmm1
callq 0x1190
movsd 0xa0c(%rip), %xmm1      # 0x2008
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movb %al, %cl
movslq -0x1c(%rbp), %rax
movb %cl, -0x240(%rbp,%rax)
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
jmp 0x15c0
movl $0x0, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jge 0x1654
movq -0x30(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movb -0x240(%rbp,%rax), %dl
movq -0x30(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
jmp 0x1623
movl -0xc(%rbp), %edi
movl $0x2, %esi
callq 0x1880
cvttsd2si %xmm0, %eax
movl %eax, -0x384(%rbp)
movl $0x100, %eax            # imm = 0x100
cltd
idivl -0x384(%rbp)
movl %eax, -0x28(%rbp)
movl $0x0, -0x1c(%rbp)
cmpl $0x100, -0x1c(%rbp)     # imm = 0x100
jge 0x16c1
movl -0x28(%rbp), %eax
movl %eax, -0x3a8(%rbp)
movl -0x1c(%rbp), %eax
cltd
idivl -0x28(%rbp)
movl %eax, %ecx
movl -0x3a8(%rbp), %eax
imull %ecx, %eax
cltd
idivl -0x28(%rbp)
movb %al, %cl
movslq -0x1c(%rbp), %rax
movb %cl, -0x140(%rbp,%rax)
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
jmp 0x1681
movl $0x0, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jge 0x16f9
movq -0x30(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movb -0x140(%rbp,%rax), %dl
movq -0x30(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
jmp 0x16c8
movq -0x8(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x388(%rbp)
movq -0x8(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, -0x38c(%rbp)
movq -0x18(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x390(%rbp)
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, -0x394(%rbp)
movl $0x0, -0x398(%rbp)
movl -0x398(%rbp), %eax
cmpl -0x38c(%rbp), %eax
jge 0x1872
movl $0x0, -0x39c(%rbp)
movl -0x39c(%rbp), %eax
cmpl -0x388(%rbp), %eax
jge 0x185c
movl $0x0, -0x3a0(%rbp)
movl -0x3a0(%rbp), %eax
cmpl -0xc(%rbp), %eax
jge 0x1846
movl $0x0, -0x3a4(%rbp)
movl -0x3a4(%rbp), %eax
cmpl -0xc(%rbp), %eax
jge 0x1830
movq -0x30(%rbp), %rax
movl -0x398(%rbp), %ecx
imull -0x388(%rbp), %ecx
addl -0x39c(%rbp), %ecx
movslq %ecx, %rcx
movzbl (%rax,%rcx), %edx
movslq -0x3a4(%rbp), %rcx
leaq -0x370(%rbp), %rax
imulq $0xc, %rcx, %rcx
addq %rcx, %rax
movslq -0x3a0(%rbp), %rcx
movl (%rax,%rcx,4), %esi
xorl %eax, %eax
movl $0xff, %ecx
cmpl %esi, %edx
cmovgl %ecx, %eax
movb %al, %dl
movq -0x38(%rbp), %rax
movl -0xc(%rbp), %ecx
imull -0x398(%rbp), %ecx
imull -0x394(%rbp), %ecx
movl -0x3a0(%rbp), %esi
imull -0x390(%rbp), %esi
addl %esi, %ecx
addl -0x3a4(%rbp), %ecx
movl -0xc(%rbp), %esi
imull -0x39c(%rbp), %esi
addl %esi, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x3a4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3a4(%rbp)
jmp 0x1786
jmp 0x1832
movl -0x3a0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3a0(%rbp)
jmp 0x176d
jmp 0x1848
movl -0x39c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x39c(%rbp)
jmp 0x1751
jmp 0x185e
movl -0x398(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x398(%rbp)
jmp 0x1735
addq $0x3b0, %rsp            # imm = 0x3B0
popq %rbp
retq
nopl (%rax,%rax)