// File: /workspace/github_cpp_makefile_star2_O2/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, %r15
movq %rdx, %r14
movss %xmm0, 0x8(%rsp)
movl %esi, %ebx
movq %rdi, %r12
movl (%rdi), %eax
movl 0x4(%rdi), %ecx
movl %eax, (%rdx)
movl %ecx, 0x4(%rdx)
movl %eax, (%r15)
movl %ecx, 0x4(%r15)
movl %ecx, %ebp
imull %eax, %ebp
movslq %ebp, %r13
movq %r13, %rdi
callq 0x1130
movq %rax, 0x8(%r15)
movq %r13, %rdi
callq 0x1130
movq %rax, 0x8(%r14)
testq %rax, %rax
je 0x1561
cmpq $0x0, 0x8(%r15)
jne 0x1426
movq 0x2bd6(%rip), %rdi      # 0x3ff0
leaq 0xc69(%rip), %rsi       # 0x208a
callq 0x10c0
cvtss2sd 0x8(%rsp), %xmm0
movsd 0xbd4(%rip), %xmm1      # 0x2008
divsd %xmm0, %xmm1
movsd %xmm1, 0x8(%rsp)
xorl %r13d, %r13d
cmpq $0x100, %r13            # imm = 0x100
je 0x147c
cvtsi2sd %r13d, %xmm0
movsd 0xbb9(%rip), %xmm1      # 0x2010
divsd %xmm1, %xmm0
movsd 0x8(%rsp), %xmm1
callq 0x1190
mulsd 0xba2(%rip), %xmm0      # 0x2010
cvttsd2si %xmm0, %eax
movb %al, 0x10(%rsp,%r13)
incq %r13
jmp 0x1441
movq 0x8(%r15), %r15
movq 0x8(%r14), %r14
movq 0x8(%r12), %rax
xorl %ecx, %ecx
testl %ebp, %ebp
cmovlel %ecx, %ebp
cmpq %rcx, %rbp
je 0x14a6
movzbl (%rax,%rcx), %edx
movb 0x10(%rsp,%rdx), %dl
movb %dl, (%r15,%rcx)
incq %rcx
jmp 0x1490
xorl %r12d, %r12d
movl $0x100, %eax            # imm = 0x100
xorl %edx, %edx
idivl %ebx
movl %eax, %ebx
cvtsi2sd %eax, %xmm0
mulsd 0xb58(%rip), %xmm0      # 0x2018
cvttsd2si %xmm0, %r13d
xorl %edi, %edi
callq 0x10a0
movl %eax, %edi
callq 0x10b0
cmpq %r12, %rbp
je 0x1510
callq 0x1050
cltd
idivl %r13d
movl %edx, %eax
negl %eax
testb $0x1, %r12b
movzbl (%r15,%r12), %ecx
cmovel %edx, %eax
addl %ecx, %eax
testl %eax, %eax
jg 0x14f9
xorl %eax, %eax
movl $0xff, %ecx
cmpl %ecx, %eax
jl 0x1507
movl $0xff, %eax
movb %al, (%r15,%r12)
incq %r12
jmp 0x14d3
xorl %ecx, %ecx
cmpq $0x100, %rcx            # imm = 0x100
je 0x1533
movl %ecx, %eax
cltd
idivl %ebx
negb %dl
movzbl %dl, %eax
addl %ecx, %eax
movb %al, 0x110(%rsp,%rcx)
incq %rcx
jmp 0x1512
xorl %eax, %eax
cmpq %rax, %rbp
je 0x154f
movzbl (%r15,%rax), %ecx
movb 0x110(%rsp,%rcx), %cl
movb %cl, (%r14,%rax)
incq %rax
jmp 0x1535
addq $0x218, %rsp            # imm = 0x218
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x2a88(%rip), %rdi      # 0x3ff0
leaq 0xb1b(%rip), %rsi       # 0x208a
callq 0x10c0
pushq $0x1
popq %rdi
callq 0x10f0