// File: /workspace/github_cpp_makefile_star2_O1/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x238, %rsp            # imm = 0x238
movq %rdx, %r15
movss %xmm0, 0x8(%rsp)
movl %esi, %ebx
movq %rdi, %r12
movl (%rdi), %r13d
movl 0x4(%rdi), %ebp
movl %r13d, %eax
imull %esi, %eax
movl %eax, (%rdx)
movl %ebp, %eax
imull %esi, %eax
movl %eax, 0x4(%rdx)
movl %esi, %ecx
imull %esi, %ecx
imull %eax, %ecx
imull (%rdi), %ecx
movslq %ecx, %rdi
callq 0x2160
movq %rax, 0x8(%r15)
testq %rax, %rax
je 0x27d1
movq %rax, %r14
imull %r13d, %ebp
movq 0x8(%r12), %rax
movq %rax, 0x20(%rsp)
xorps %xmm0, %xmm0
cvtss2sd 0x8(%rsp), %xmm0
movsd 0x9da(%rip), %xmm1      # 0x3008
divsd %xmm0, %xmm1
movsd %xmm1, 0x8(%rsp)
xorl %r13d, %r13d
xorps %xmm0, %xmm0
cvtsi2sd %r13d, %xmm0
movsd 0x9c5(%rip), %xmm1      # 0x3010
divsd %xmm1, %xmm0
movsd 0x8(%rsp), %xmm1
callq 0x21d0
mulsd 0x9ae(%rip), %xmm0      # 0x3010
cvttsd2si %xmm0, %eax
movb %al, 0x30(%rsp,%r13)
incq %r13
cmpq $0x100, %r13            # imm = 0x100
jne 0x263b
movl %ebp, %edi
testl %ebp, %ebp
movq 0x20(%rsp), %r8
jle 0x2699
xorl %eax, %eax
movzbl (%r8,%rax), %ecx
movb 0x30(%rsp,%rcx), %cl
movb %cl, (%r8,%rax)
incq %rax
cmpq %rax, %rdi
jne 0x2684
xorps %xmm0, %xmm0
cvtsi2sd %ebx, %xmm0
mulsd %xmm0, %xmm0
cvttsd2si %xmm0, %esi
xorl %ecx, %ecx
movl $0x100, %eax            # imm = 0x100
xorl %edx, %edx
idivl %esi
movl %eax, %esi
movl %ecx, %eax
cltd
idivl %esi
movb %al, 0x130(%rsp,%rcx)
incq %rcx
cmpq $0x100, %rcx            # imm = 0x100
jne 0x26b5
testl %ebp, %ebp
jle 0x26eb
xorl %eax, %eax
movzbl (%r8,%rax), %ecx
movb 0x130(%rsp,%rcx), %cl
movb %cl, (%r8,%rax)
incq %rax
cmpq %rax, %rdi
jne 0x26d3
movslq 0x4(%r12), %rax
movq %rax, 0x28(%rsp)
testq %rax, %rax
jle 0x27bf
movl (%r12), %ecx
movl (%r15), %edx
movl %ebx, %esi
movl 0x4(%r15), %eax
imull %ebx, %eax
movl %eax, 0x1c(%rsp)
leaq (,%rsi,4), %rax
leaq (%rax,%rax,2), %r8
movq $0x0, 0x8(%rsp)
movq $0x0, 0x10(%rsp)
testl %ecx, %ecx
jle 0x2799
movq 0x10(%rsp), %r15
imulq %rcx, %r15
addq 0x20(%rsp), %r15
movq 0x8(%rsp), %rax
xorl %r12d, %r12d
testl %ebx, %ebx
jle 0x278f
movl %eax, %ebp
leaq 0x919(%rip), %r10       # 0x3070
xorl %r13d, %r13d
movl %ebp, %edi
xorl %r9d, %r9d
movzbl (%r15,%r12), %r11d
cmpl %r11d, (%r10,%r9)
setl %r11b
negb %r11b
movslq %edi, %rdi
movb %r11b, (%r14,%rdi)
addq $0xc, %r9
incl %edi
cmpq %r9, %r8
jne 0x275f
incq %r13
addq $0x4, %r10
addl %edx, %ebp
cmpq %rsi, %r13
jne 0x275a
incq %r12
addl %ebx, %eax
cmpq %rcx, %r12
jne 0x274a
movq 0x10(%rsp), %rdi
incq %rdi
movq 0x8(%rsp), %rax
addl 0x1c(%rsp), %eax
movq %rax, 0x8(%rsp)
movq %rdi, 0x10(%rsp)
cmpq 0x28(%rsp), %rdi
jne 0x2730
addq $0x238, %rsp            # imm = 0x238
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x2818(%rip), %rdi      # 0x4ff0
leaq 0x87d(%rip), %rsi       # 0x305c
callq 0x20e0
movl $0x1, %edi
callq 0x2120
nop