// File: /workspace/github_cpp_makefile_star2_O2/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 $0x248, %rsp            # imm = 0x248
movq %rdx, %r15
movss %xmm0, 0x10(%rsp)
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, 0xc(%rsp)
movl %esi, %ecx
imull %esi, %ecx
imull %eax, %ecx
imull (%rdi), %ecx
movslq %ecx, %rdi
callq 0x1100
movq %rax, 0x8(%r15)
testq %rax, %rax
je 0x15fc
movq %rax, %r14
imull %r13d, %ebp
movq 0x8(%r12), %rax
movq %rax, 0x18(%rsp)
cvtss2sd 0x10(%rsp), %xmm0
movsd 0xbb3(%rip), %xmm1      # 0x2008
divsd %xmm0, %xmm1
movsd %xmm1, 0x10(%rsp)
xorl %r13d, %r13d
cmpq $0x100, %r13            # imm = 0x100
je 0x149d
cvtsi2sd %r13d, %xmm0
movsd 0xb98(%rip), %xmm1      # 0x2010
divsd %xmm1, %xmm0
movsd 0x10(%rsp), %xmm1
callq 0x1160
mulsd 0xb81(%rip), %xmm0      # 0x2010
cvttsd2si %xmm0, %eax
movb %al, 0x40(%rsp,%r13)
incq %r13
jmp 0x1462
xorl %eax, %eax
testl %ebp, %ebp
cmovlel %eax, %ebp
movq 0x18(%rsp), %rdx
cmpq %rax, %rbp
je 0x14be
movzbl (%rdx,%rax), %ecx
movb 0x40(%rsp,%rcx), %cl
movb %cl, (%rdx,%rax)
incq %rax
jmp 0x14a9
cvtsi2sdl 0xc(%rsp), %xmm0
mulsd %xmm0, %xmm0
cvttsd2si %xmm0, %esi
xorl %ecx, %ecx
movl $0x100, %eax            # imm = 0x100
xorl %edx, %edx
idivl %esi
movl %eax, %esi
cmpq $0x100, %rcx            # imm = 0x100
je 0x14f3
movl %ecx, %eax
cltd
idivl %esi
movb %al, 0x140(%rsp,%rcx)
incq %rcx
jmp 0x14d9
xorl %eax, %eax
movq 0x18(%rsp), %rdx
cmpq %rax, %rbp
je 0x1512
movzbl (%rdx,%rax), %ecx
movb 0x140(%rsp,%rcx), %cl
movb %cl, (%rdx,%rax)
incq %rax
jmp 0x14fa
movslq (%r12), %rax
movl 0x4(%r12), %esi
movl (%r15), %edx
xorl %r10d, %r10d
movl 0xc(%rsp), %ecx
testl %ecx, %ecx
movl $0x0, %edi
cmovgl %ecx, %edi
testl %eax, %eax
movl $0x0, %r8d
movq %rax, 0x28(%rsp)
cmovgl %eax, %r8d
testl %esi, %esi
cmovlel %r10d, %esi
movq %rsi, 0x30(%rsp)
movl %ecx, %eax
imulq $0xc, %rax, %r9
movl 0x4(%r15), %eax
imull %ecx, %eax
movl %eax, 0x24(%rsp)
leaq 0xb0d(%rip), %rcx       # 0x2070
xorl %r12d, %r12d
cmpq 0x30(%rsp), %r12
je 0x15ea
movq %r12, 0x38(%rsp)
imulq 0x28(%rsp), %r12
addq 0x18(%rsp), %r12
movq %r10, 0x10(%rsp)
xorl %eax, %eax
cmpq %r8, %rax
je 0x15d3
movq %rcx, %r11
movl %r10d, %ebp
xorl %r13d, %r13d
cmpq %rdi, %r13
je 0x15c9
movl %ebp, %esi
xorl %r15d, %r15d
cmpq %r15, %r9
je 0x15be
movzbl (%r12,%rax), %ebx
cmpl %ebx, (%r11,%r15)
setl %bl
negb %bl
movslq %esi, %rsi
movb %bl, (%r14,%rsi)
addq $0xc, %r15
incl %esi
jmp 0x159c
incq %r13
addl %edx, %ebp
addq $0x4, %r11
jmp 0x1592
incq %rax
addl 0xc(%rsp), %r10d
jmp 0x1584
movq 0x38(%rsp), %r12
incq %r12
movq 0x10(%rsp), %r10
addl 0x24(%rsp), %r10d
jmp 0x1566
addq $0x248, %rsp            # imm = 0x248
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x29ed(%rip), %rdi      # 0x3ff0
leaq 0xa52(%rip), %rsi       # 0x205c
callq 0x1090
pushq $0x1
popq %rdi
callq 0x10c0
nop