// File: /workspace/github_cpp_makefile_star2_O3/brianwu02[P]ImageProcessing/unordered_dither.cpp
// Function: unordered_dither(imageS*, int, float, imageS*, imageS*)
void unordered_dither(imageP I1, int n, float gamma, imageP I2, imageP tmp_img) {
    int	 i, total, scale;
    uchar	*in, *out, *tmp_out, lut[256];
    uchar gamma_corrected_lut[256];

    // total number of pixels in image
    total = I1->width * I1->height;

    // init I2 dimensions and buffer
    I2->width  = I1->width;
    I2->height = I1->height;
    tmp_img->width = I1->width;
    tmp_img->height = I1->height;

    tmp_img->image = (uchar *) malloc(total);
    I2->image  = (uchar *) malloc(total);

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

    for (i = 0; i < 256; i++) {
    gamma_corrected_lut[i] = (int) (pow((double) i / 255.0 , (1.0 / gamma)) * 255.0);
    }
    tmp_out = tmp_img->image; // tmp output image buffer after gamma correction
    out = I2->image;    // output image buffer
    in  = I1->image;    // input  image buffer

    // this should produce gamma corrected image from look up table
    for (i=0; i<total; i++) tmp_out[i] = gamma_corrected_lut[ in[i] ];

    // create bias
    int bias = ((MXGRAY / n) * 0.5);

    // create a seed for rand() function
    srand(time(0));

    // apply random dither to Image
    for (i = 0; i < total; i++ ) {
        int randomized_bias = rand() % bias;
        // on even, add. bitwise faster than modulo. on odd, subtract
        if ((i & 1) == 0) {
            tmp_out[i] = clip_values(tmp_out[i] + randomized_bias);
        } else {
            tmp_out[i] = clip_values(tmp_out[i] - randomized_bias);
        }
    }

    scale = 256 / n;
    // init lookup table for quantization
    for(i=0; i<256 ; i++) {
        lut[i] = scale * (int) (i/scale);
    }
    
    // visit all input pixels and apply lut to threshold
    for(i=0; i<total; i++) out[i] = lut[tmp_out[i]];
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x218, %rsp            # imm = 0x218
movq %rcx, %r12
movq %rdx, %r15
movss %xmm0, 0x8(%rsp)
movl %esi, %ebx
movq %rdi, %r14
movl (%rdi), %eax
movl 0x4(%rdi), %ecx
movl %eax, (%rdx)
movl %ecx, 0x4(%rdx)
movl %eax, (%r12)
movl %ecx, 0x4(%r12)
movl %ecx, %ebp
imull %eax, %ebp
movslq %ebp, %r13
movq %r13, %rdi
callq 0x2180
movq %rax, 0x8(%r12)
movq %r13, %rdi
callq 0x2180
movq %rax, 0x8(%r15)
testq %rax, %rax
je 0x2602
cmpq $0x0, 0x8(%r12)
jne 0x24b8
movq 0x2b49(%rip), %rdi      # 0x4ff0
leaq 0xbdc(%rip), %rsi       # 0x308a
movl $0x14, %edx
callq 0x2120
xorps %xmm0, %xmm0
cvtss2sd 0x8(%rsp), %xmm0
movsd 0xb3f(%rip), %xmm1      # 0x3008
divsd %xmm0, %xmm1
movsd %xmm1, 0x8(%rsp)
xorl %r13d, %r13d
xorps %xmm0, %xmm0
cvtsi2sd %r13d, %xmm0
movsd 0xb2a(%rip), %xmm1      # 0x3010
divsd %xmm1, %xmm0
movsd 0x8(%rsp), %xmm1
callq 0x21e0
mulsd 0xb13(%rip), %xmm0      # 0x3010
cvttsd2si %xmm0, %eax
movb %al, 0x10(%rsp,%r13)
incq %r13
cmpq $0x100, %r13            # imm = 0x100
jne 0x24d6
movq 0x8(%r12), %r12
movq 0x8(%r15), %r15
movl %ebp, %r13d
testl %ebp, %ebp
jle 0x253c
movq 0x8(%r14), %rax
xorl %ecx, %ecx
movzbl (%rax,%rcx), %edx
movb 0x10(%rsp,%rdx), %dl
movb %dl, (%r12,%rcx)
incq %rcx
cmpq %rcx, %r13
jne 0x2528
movl $0x100, %eax            # imm = 0x100
xorl %edx, %edx
idivl %ebx
movl %eax, %ebx
xorl %edi, %edi
callq 0x20d0
movl %eax, %edi
callq 0x20e0
movl %ebp, 0x8(%rsp)
testl %ebp, %ebp
jle 0x25ae
xorps %xmm0, %xmm0
cvtsi2sd %ebx, %xmm0
mulsd 0xaac(%rip), %xmm0      # 0x3018
cvttsd2si %xmm0, %r14d
xorl %ebp, %ebp
callq 0x2060
cltd
idivl %r14d
movl %edx, %eax
negl %eax
testb $0x1, %bpl
movzbl (%r12,%rbp), %ecx
cmovel %edx, %eax
addl %ecx, %eax
testl %eax, %eax
jg 0x2594
xorl %eax, %eax
movl $0xff, %ecx
cmpl %ecx, %eax
jl 0x25a2
movl $0xff, %eax
movb %al, (%r12,%rbp)
incq %rbp
cmpq %rbp, %r13
jne 0x2573
xorl %ecx, %ecx
movl %ecx, %eax
cltd
idivl %ebx
negb %dl
movzbl %dl, %eax
addl %ecx, %eax
movb %al, 0x110(%rsp,%rcx)
incq %rcx
cmpq $0x100, %rcx            # imm = 0x100
jne 0x25b0
cmpl $0x0, 0x8(%rsp)
jle 0x25f0
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
movb 0x110(%rsp,%rcx), %cl
movb %cl, (%r15,%rax)
incq %rax
cmpq %rax, %r13
jne 0x25d8
addq $0x218, %rsp            # imm = 0x218
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x29e7(%rip), %rdi      # 0x4ff0
leaq 0xa7a(%rip), %rsi       # 0x308a
callq 0x2100
movl $0x1, %edi
callq 0x2140