// File: 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
movq %rsp, %rbp
subq $0x260, %rsp            # imm = 0x260
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movss %xmm0, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq -0x8(%rbp), %rax
movl (%rax), %eax
movq -0x8(%rbp), %rcx
imull 0x4(%rcx), %eax
movl %eax, -0x28(%rbp)
movq -0x8(%rbp), %rax
movl (%rax), %ecx
movq -0x18(%rbp), %rax
movl %ecx, (%rax)
movq -0x8(%rbp), %rax
movl 0x4(%rax), %ecx
movq -0x18(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x8(%rbp), %rax
movl (%rax), %ecx
movq -0x20(%rbp), %rax
movl %ecx, (%rax)
movq -0x8(%rbp), %rax
movl 0x4(%rax), %ecx
movq -0x20(%rbp), %rax
movl %ecx, 0x4(%rax)
movslq -0x28(%rbp), %rdi
callq 0x1150
movq %rax, %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x8(%rax)
movslq -0x28(%rbp), %rdi
callq 0x1150
movq %rax, %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x18(%rbp), %rax
cmpq $0x0, 0x8(%rax)
jne 0x14f4
movq 0x2b12(%rip), %rdi      # 0x3ff0
leaq 0xba8(%rip), %rsi       # 0x208d
callq 0x10d0
movl $0x1, %edi
callq 0x1110
movq -0x20(%rbp), %rax
cmpq $0x0, 0x8(%rax)
jne 0x1512
movq 0x2aea(%rip), %rdi      # 0x3ff0
leaq 0xb80(%rip), %rsi       # 0x208d
callq 0x10d0
movl $0x0, -0x24(%rbp)
cmpl $0x100, -0x24(%rbp)     # imm = 0x100
jge 0x1575
cvtsi2sdl -0x24(%rbp), %xmm0
movsd 0xae1(%rip), %xmm1      # 0x2010
divsd %xmm1, %xmm0
movss -0x10(%rbp), %xmm1
cvtss2sd %xmm1, %xmm2
movsd 0xad4(%rip), %xmm1      # 0x2018
divsd %xmm2, %xmm1
callq 0x11b0
movsd 0xabb(%rip), %xmm1      # 0x2010
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movb %al, %cl
movslq -0x24(%rbp), %rax
movb %cl, -0x250(%rbp,%rax)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x1519
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x40(%rbp)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x38(%rbp)
movl $0x0, -0x24(%rbp)
movl -0x24(%rbp), %eax
cmpl -0x28(%rbp), %eax
jge 0x15d1
movq -0x38(%rbp), %rax
movslq -0x24(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movb -0x250(%rbp,%rax), %dl
movq -0x48(%rbp), %rax
movslq -0x24(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x15a0
movl $0x100, %eax            # imm = 0x100
cltd
idivl -0xc(%rbp)
cvtsi2sd %eax, %xmm0
movsd 0xa22(%rip), %xmm1      # 0x2008
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, -0x254(%rbp)
xorl %eax, %eax
movl %eax, %edi
callq 0x10b0
movl %eax, %edi
callq 0x10c0
movl $0x0, -0x24(%rbp)
movl -0x24(%rbp), %eax
cmpl -0x28(%rbp), %eax
jge 0x1687
callq 0x1050
cltd
idivl -0x254(%rbp)
movl %edx, -0x258(%rbp)
movl -0x24(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
jne 0x1656
movq -0x48(%rbp), %rax
movslq -0x24(%rbp), %rcx
movzbl (%rax,%rcx), %edi
addl -0x258(%rbp), %edi
callq 0x1720
movb %al, %dl
movq -0x48(%rbp), %rax
movslq -0x24(%rbp), %rcx
movb %dl, (%rax,%rcx)
jmp 0x167a
movq -0x48(%rbp), %rax
movslq -0x24(%rbp), %rcx
movzbl (%rax,%rcx), %edi
subl -0x258(%rbp), %edi
callq 0x1720
movb %al, %dl
movq -0x48(%rbp), %rax
movslq -0x24(%rbp), %rcx
movb %dl, (%rax,%rcx)
jmp 0x167c
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x160b
movl $0x100, %eax            # imm = 0x100
cltd
idivl -0xc(%rbp)
movl %eax, -0x2c(%rbp)
movl $0x0, -0x24(%rbp)
cmpl $0x100, -0x24(%rbp)     # imm = 0x100
jge 0x16d6
movl -0x2c(%rbp), %eax
movl %eax, -0x25c(%rbp)
movl -0x24(%rbp), %eax
cltd
idivl -0x2c(%rbp)
movl %eax, %ecx
movl -0x25c(%rbp), %eax
imull %ecx, %eax
movb %al, %cl
movslq -0x24(%rbp), %rax
movb %cl, -0x150(%rbp,%rax)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x169a
movl $0x0, -0x24(%rbp)
movl -0x24(%rbp), %eax
cmpl -0x28(%rbp), %eax
jge 0x170e
movq -0x48(%rbp), %rax
movslq -0x24(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movb -0x150(%rbp,%rax), %dl
movq -0x40(%rbp), %rax
movslq -0x24(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x16dd
addq $0x260, %rsp            # imm = 0x260
popq %rbp
retq
nopw (%rax,%rax)