// File: /workspace/github_cpp_makefile_star2_O1/brianwu02[P]ImageProcessing/error_diffusion.cpp
// Function: error_diffusion(imageS*, int, int, float, imageS*)
void error_diffusion(imageP I1, int mtd, int serpentine, float gamma, imageP I2) {
    int i, total, threshold;
    unsigned char *in;
    unsigned char *out;
    unsigned char gammaCorrectionLUT[256];
    unsigned char thresholdingLUT[256];

    total = I1->width * I1->height;
    I2->width = I1->width;
    I2->height = I1->height;

    I2->image = (unsigned char *) malloc(total);

    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++) {
        gammaCorrectionLUT[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] = gammaCorrectionLUT[in[i]];
    }

    // create thresholding scale
    threshold = 255 / 2;
    
    // create circular buffer. this one here is only 2 'widths' long.

    int h = I1->height;
    int w = I1->width;

    // mtd=0; manually copy row 0 to the circular buffer. Floyd-Steinberg Algorithm
    if (mtd == 0) {
        short buf[1][w+2];

        //short bufer[10];
        //short *buf1 = bufer;

        // pad the buffer
        buf[0][0] = 0;
        buf[0][(w+2) -1] = 0;
        buf[1][0] = 0;
        buf[1][(w+2) -1] = 0;

        for (int i = 0; i < w; i++) {
            buf[0][i+1] = in[i];
        }
        
        for (int y=0; y<h; y++) {
            // manually copy row 1 in to the circular buffer.
            if ((y % 2) == 0) {
                // if y is even, copy to buf[1]
                for (int i = 0; i < w; i++) {
                    buf[1][i+1] = in[y*w+i];
                }
            } else {
                // if y is odd, copy to buf[0]
                for (int i = 0; i < w; i++) {
                    buf[0][i+1] = in[y*w+i];
                }
            }
            
            int p = 1;

            for (int x=0; x<w; x++) {

                *out = (buf[0][p] < threshold) ? 0 : 255;
                short e = (buf[0][p] - *out);
                
                buf[0][p+1] += (e*7/16.0);
                buf[1][p-1] += (e*3/16.0); // error to SW
                buf[1][p] += (e*5/16.0);   // error to S
                buf[1][p+1] += (e*1/16.0); // error to SE
                p++;
                out++;
            }
        }
    } else {
        short buf[2][w+4];

        // pad the buffer, 2 deep.
        buf[0][0] = 0;
        buf[0][1] = 0;
        buf[0][(w+4) -1] = 0;
        buf[0][(w+4) -2] = 0;

        buf[1][0] = 0;
        buf[1][1] = 0;
        buf[1][(w+4) -1] = 0;
        buf[1][(w+4) -2] = 0;

        buf[2][0] = 0;
        buf[2][1] = 0;
        buf[2][(w+4) -1] = 0;
        buf[2][(w+4) -2] = 0;

        // mtd=1; for Jarvis-Judice-Ninke Error diffusion algorithm, need buffers.
        for (int i = 0; i < w; i++) {
            buf[0][i+2] = in[i];
            buf[1][i+2] = in[i+w];
        }
        // circular buffer logic.
        for (int y=0; y<h; y++) {
            if ((y % 3) == 0) {
                for (int i = 0; i < w; i++) {
                    buf[2][i+2] = in[y*w+i];
                }
            }
            if ((y % 3) == 1) {
                for (int i = 0; i < w; i++) {
                   buf[0][i+2] = in[y*w+i];
                }
            }
            if ((y % 3) == 2) {
                for (int i = 0; i < w; i++) {
                    buf[1][i+2] = in[y*w+i];
                }
            }

            int p = 2;
            for (int x=0; x<w; x++) {
                *out = (buf[0][p] < threshold) ? 0 : 255;
                //cout << (int) buf[0][p] << endl;
                short e = (buf[0][p] - *out);

                buf[0][p+1] += (e*7/48.0);
                buf[0][p+2] += (e*5/48.0);
                buf[1][p-2] += (e*3/48.0);
                buf[1][p-1] += (e*5/48.0);
                buf[1][p] += (e*7/48.0);
                buf[1][p+1] += (e*5/48.0);
                buf[1][p+2] += (e*3/48.0);

                buf[2][p-2] += (e*1/48.0);
                buf[2][p-1] += (e*3/48.0);
                buf[2][p] += (e*5/48.0);
                buf[2][p+1] += (e*3/48.0);
                buf[2][p+2] += (e*1/48.0);

                p++;
                out++;
            }
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x128, %rsp            # imm = 0x128
movq %rcx, %r12
movss %xmm0, -0x30(%rbp)
movl %esi, -0x34(%rbp)
movq %rdi, %r15
movl (%rdi), %eax
movl 0x4(%rdi), %r13d
movl %eax, (%rcx)
movl %r13d, 0x4(%rcx)
imull %eax, %r13d
movslq %r13d, %rdi
callq 0x2160
movq %rax, 0x8(%r12)
testq %rax, %rax
je 0x2c26
movq %rax, %rbx
movq 0x8(%r15), %r12
xorps %xmm0, %xmm0
cvtss2sd -0x30(%rbp), %xmm0
movsd 0x1945(%rip), %xmm1     # 0x4008
divsd %xmm0, %xmm1
movsd %xmm1, -0x30(%rbp)
xorl %r14d, %r14d
xorps %xmm0, %xmm0
cvtsi2sd %r14d, %xmm0
movsd 0x1931(%rip), %xmm1     # 0x4010
divsd %xmm1, %xmm0
movsd -0x30(%rbp), %xmm1
callq 0x21d0
mulsd 0x191b(%rip), %xmm0     # 0x4010
cvttsd2si %xmm0, %eax
movb %al, -0x150(%rbp,%r14)
incq %r14
cmpq $0x100, %r14            # imm = 0x100
jne 0x26cf
testl %r13d, %r13d
jle 0x272f
movl %r13d, %eax
xorl %ecx, %ecx
movzbl (%r12,%rcx), %edx
movb -0x150(%rbp,%rdx), %dl
movb %dl, (%r12,%rcx)
incq %rcx
cmpq %rcx, %rax
jne 0x2717
movq %rsp, %rax
movl 0x4(%r15), %edx
movslq (%r15), %r13
movl %r13d, %esi
cmpl $0x0, -0x34(%rbp)
movq %rax, -0x40(%rbp)
je 0x2a64
leal 0x4(%rsi), %eax
leaq (%rax,%rax), %rcx
movq %rsp, %r8
leaq 0xf(,%rax,4), %r9
andq $-0x10, %r9
movq %r8, %rdi
subq %r9, %rdi
movq %rdi, %rsp
negq %r9
xorl %r10d, %r10d
movl %r10d, (%r8,%r9)
movw %r10w, 0x6(%rdi,%r13,2)
movw %r10w, 0x4(%rdi,%r13,2)
leaq (%rdi,%rax,2), %r8
movl %r10d, (%r8)
movw %r10w, 0x6(%r8,%r13,2)
movw %r10w, 0x4(%r8,%r13,2)
leaq (%rdi,%rax,4), %r9
movl %r10d, (%r9)
movw %r10w, 0x6(%r9,%r13,2)
movw %r10w, 0x4(%r9,%r13,2)
testl %r13d, %r13d
jle 0x27d6
leaq (%r12,%rsi), %r10
leaq (%rcx,%rdi), %r11
addq $0x4, %r11
xorl %r14d, %r14d
movzbl (%r12,%r14), %r15d
movw %r15w, 0x4(%rdi,%r14,2)
movzbl (%r10,%r14), %r15d
movw %r15w, (%r11,%r14,2)
incq %r14
cmpq %r14, %rsi
jne 0x27b9
testl %edx, %edx
jle 0x2c13
leal 0x2(%r13), %r10d
leaq (%rdi,%rax,4), %r11
addq $0x8, %r11
leaq (%rcx,%rdi), %r14
addq $0x8, %r14
addq $-0x2, %r10
xorl %r15d, %r15d
movsd 0x1817(%rip), %xmm0     # 0x4018
movq %r13, -0x30(%rbp)
movq %rdx, -0x48(%rbp)
movl %r15d, %eax
movl $0xaaaaaaab, %ecx       # imm = 0xAAAAAAAB
imulq %rcx, %rax
shrq $0x21, %rax
leal (%rax,%rax,2), %ecx
movl %r15d, %eax
subl %ecx, %eax
cmpl $0x2, %eax
je 0x2881
cmpl $0x1, %eax
je 0x2852
testl %esi, %esi
jle 0x2844
xorl %ecx, %ecx
movzbl (%r12,%rcx), %r13d
movw %r13w, 0x4(%r9,%rcx,2)
incq %rcx
cmpq %rcx, %rsi
jne 0x2831
cmpl $0x2, %eax
movq -0x30(%rbp), %r13
je 0x2881
cmpl $0x1, %eax
jne 0x289b
testl %esi, %esi
jle 0x286b
xorl %ecx, %ecx
movzbl (%r12,%rcx), %r13d
movw %r13w, 0x4(%rdi,%rcx,2)
incq %rcx
cmpq %rcx, %rsi
jne 0x2858
movq -0x30(%rbp), %r13
testl %r13d, %r13d
setle %cl
cmpl $0x2, %eax
setne %al
orb %cl, %al
je 0x2886
jmp 0x289b
testl %r13d, %r13d
jle 0x289b
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
movw %cx, 0x4(%r8,%rax,2)
incq %rax
cmpq %rax, %rsi
jne 0x2888
testl %r13d, %r13d
jle 0x2a50
xorl %eax, %eax
cmpw $0x7f, 0x4(%rdi,%rax,2)
setge %r13b
negb %r13b
movzwl 0x4(%rdi,%rax,2), %ecx
movzbl %r13b, %edx
subl %edx, %ecx
movswl %cx, %ecx
leal (,%rcx,8), %edx
subl %ecx, %edx
xorps %xmm3, %xmm3
cvtsi2sd %edx, %xmm3
divsd %xmm0, %xmm3
movswl 0x6(%rdi,%rax,2), %edx
xorps %xmm1, %xmm1
cvtsi2sd %edx, %xmm1
addsd %xmm3, %xmm1
cvttsd2si %xmm1, %edx
movw %dx, 0x6(%rdi,%rax,2)
leal (%rcx,%rcx,4), %edx
xorps %xmm1, %xmm1
cvtsi2sd %edx, %xmm1
divsd %xmm0, %xmm1
movswl 0x8(%rdi,%rax,2), %edx
xorps %xmm4, %xmm4
cvtsi2sd %edx, %xmm4
addsd %xmm1, %xmm4
leal (%rcx,%rcx,2), %edx
cvtsi2sd %edx, %xmm2
cvttsd2si %xmm4, %edx
movw %dx, 0x8(%rdi,%rax,2)
movswl -0x8(%r14,%rax,2), %edx
xorps %xmm4, %xmm4
cvtsi2sd %edx, %xmm4
divsd %xmm0, %xmm2
addsd %xmm2, %xmm4
cvttsd2si %xmm4, %edx
movw %dx, -0x8(%r14,%rax,2)
movswl -0x6(%r14,%rax,2), %edx
xorps %xmm4, %xmm4
cvtsi2sd %edx, %xmm4
addsd %xmm1, %xmm4
cvttsd2si %xmm4, %edx
movw %dx, -0x6(%r14,%rax,2)
movswl -0x4(%r14,%rax,2), %edx
xorps %xmm4, %xmm4
cvtsi2sd %edx, %xmm4
addsd %xmm3, %xmm4
cvttsd2si %xmm4, %edx
movw %dx, -0x4(%r14,%rax,2)
movswl -0x2(%r14,%rax,2), %edx
xorps %xmm3, %xmm3
cvtsi2sd %edx, %xmm3
addsd %xmm1, %xmm3
cvttsd2si %xmm3, %edx
movw %dx, -0x2(%r14,%rax,2)
movswl (%r14,%rax,2), %edx
xorps %xmm4, %xmm4
cvtsi2sd %edx, %xmm4
addsd %xmm2, %xmm4
xorps %xmm3, %xmm3
cvtsi2sd %ecx, %xmm3
cvttsd2si %xmm4, %ecx
movw %cx, (%r14,%rax,2)
movswl -0x8(%r11,%rax,2), %ecx
xorps %xmm4, %xmm4
cvtsi2sd %ecx, %xmm4
divsd %xmm0, %xmm3
addsd %xmm3, %xmm4
cvttsd2si %xmm4, %ecx
movw %cx, -0x8(%r11,%rax,2)
movswl -0x6(%r11,%rax,2), %ecx
xorps %xmm4, %xmm4
cvtsi2sd %ecx, %xmm4
addsd %xmm2, %xmm4
cvttsd2si %xmm4, %ecx
movw %cx, -0x6(%r11,%rax,2)
movswl -0x4(%r11,%rax,2), %ecx
xorps %xmm4, %xmm4
cvtsi2sd %ecx, %xmm4
addsd %xmm1, %xmm4
cvttsd2si %xmm4, %ecx
movw %cx, -0x4(%r11,%rax,2)
movswl -0x2(%r11,%rax,2), %ecx
xorps %xmm1, %xmm1
cvtsi2sd %ecx, %xmm1
addsd %xmm2, %xmm1
cvttsd2si %xmm1, %ecx
movw %cx, -0x2(%r11,%rax,2)
movswl (%r11,%rax,2), %ecx
xorps %xmm1, %xmm1
cvtsi2sd %ecx, %xmm1
addsd %xmm3, %xmm1
cvttsd2si %xmm1, %ecx
movb %r13b, (%rbx,%rax)
movw %cx, (%r11,%rax,2)
incq %rax
cmpq %rax, %r10
jne 0x28a6
addq %rax, %rbx
movq -0x48(%rbp), %rdx
movq -0x30(%rbp), %r13
incq %r15
addq %r13, %r12
cmpq %rdx, %r15
jne 0x2809
jmp 0x2c13
leal 0x2(%r13), %eax
movq %rsp, %rcx
leaq 0xf(,%rax,2), %r8
andq $-0x10, %r8
movq %rcx, %rdi
subq %r8, %rdi
movq %rdi, %rsp
negq %r8
xorl %r9d, %r9d
movw %r9w, (%rcx,%r8)
movw %r9w, 0x2(%rdi,%r13,2)
leaq (%rdi,%rax,2), %rcx
movw %r9w, (%rcx)
movw %r9w, 0x2(%rcx,%r13,2)
testl %esi, %esi
jle 0x2ab8
xorl %ecx, %ecx
movzbl (%r12,%rcx), %r8d
movw %r8w, 0x2(%rdi,%rcx,2)
incq %rcx
cmpq %rcx, %rsi
jne 0x2aa5
testl %edx, %edx
jle 0x2c13
leal 0x1(%rsi), %r8d
movslq %esi, %r9
leaq (%rdi,%rax,2), %r10
addq $0x2, %r10
decq %r8
xorl %r11d, %r11d
movsd 0x1543(%rip), %xmm0     # 0x4020
testb $0x1, %r11b
jne 0x2afe
testl %r13d, %r13d
jle 0x2b17
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
movw %cx, (%r10,%rax,2)
incq %rax
cmpq %rax, %rsi
jne 0x2aea
jmp 0x2b17
testl %r13d, %r13d
jle 0x2b17
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
movw %cx, 0x2(%rdi,%rax,2)
incq %rax
cmpq %rax, %rsi
jne 0x2b05
testl %esi, %esi
jle 0x2c04
xorl %eax, %eax
cmpw $0x7f, 0x2(%rdi,%rax,2)
setge %cl
negb %cl
movzwl 0x2(%rdi,%rax,2), %r14d
movzbl %cl, %r15d
subl %r15d, %r14d
movswl %r14w, %r14d
leal (,%r14,8), %r15d
subl %r14d, %r15d
xorps %xmm1, %xmm1
cvtsi2sd %r15d, %xmm1
movswl 0x4(%rdi,%rax,2), %r15d
xorps %xmm2, %xmm2
cvtsi2sd %r15d, %xmm2
mulsd %xmm0, %xmm1
addsd %xmm1, %xmm2
cvttsd2si %xmm2, %r15d
movw %r15w, 0x4(%rdi,%rax,2)
leal (%r14,%r14,2), %r15d
xorps %xmm1, %xmm1
cvtsi2sd %r15d, %xmm1
mulsd %xmm0, %xmm1
movswl -0x2(%r10,%rax,2), %r15d
xorps %xmm2, %xmm2
cvtsi2sd %r15d, %xmm2
addsd %xmm1, %xmm2
cvttsd2si %xmm2, %r15d
movw %r15w, -0x2(%r10,%rax,2)
leal (%r14,%r14,4), %r15d
xorps %xmm1, %xmm1
cvtsi2sd %r15d, %xmm1
movswl (%r10,%rax,2), %r15d
xorps %xmm2, %xmm2
cvtsi2sd %r15d, %xmm2
mulsd %xmm0, %xmm1
addsd %xmm1, %xmm2
xorps %xmm1, %xmm1
cvtsi2sd %r14d, %xmm1
cvttsd2si %xmm2, %r14d
movw %r14w, (%r10,%rax,2)
movswl 0x2(%r10,%rax,2), %r14d
xorps %xmm2, %xmm2
cvtsi2sd %r14d, %xmm2
mulsd %xmm0, %xmm1
addsd %xmm1, %xmm2
cvttsd2si %xmm2, %r14d
movb %cl, (%rbx,%rax)
movw %r14w, 0x2(%r10,%rax,2)
incq %rax
cmpq %rax, %r8
jne 0x2b21
addq %rax, %rbx
incq %r11
addq %r9, %r12
cmpq %rdx, %r11
jne 0x2add
movq -0x40(%rbp), %rsp
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x33c3(%rip), %rdi      # 0x5ff0
leaq 0x1426(%rip), %rsi      # 0x405a
callq 0x20e0
movl $0x1, %edi
callq 0x2120
nop