// File: /workspace/github_cpp_makefile_star2_O3/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 $0x118, %rsp            # imm = 0x118
movq %rcx, %r12
movss %xmm0, -0x30(%rbp)
movl %esi, -0x38(%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 0x2bbc
movq %rax, %rbx
movq 0x8(%r15), %r12
xorps %xmm0, %xmm0
cvtss2sd -0x30(%rbp), %xmm0
movsd 0x945(%rip), %xmm1      # 0x3008
divsd %xmm0, %xmm1
movsd %xmm1, -0x30(%rbp)
xorl %r14d, %r14d
xorps %xmm0, %xmm0
cvtsi2sd %r14d, %xmm0
movsd 0x931(%rip), %xmm1      # 0x3010
divsd %xmm1, %xmm0
movsd -0x30(%rbp), %xmm1
callq 0x21d0
mulsd 0x91b(%rip), %xmm0      # 0x3010
cvttsd2si %xmm0, %eax
movb %al, -0x140(%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 -0x140(%rbp,%rdx), %dl
movb %dl, (%r12,%rcx)
incq %rcx
cmpq %rcx, %rax
jne 0x2717
movq %rsp, %rax
movl 0x4(%r15), %edx
movslq (%r15), %r15
movl %r15d, %esi
cmpl $0x0, -0x38(%rbp)
movq %rax, -0x40(%rbp)
je 0x29fd
leal 0x4(%rsi), %eax
leaq (%rax,%rax), %r14
movq %rsp, %rcx
leaq 0xf(,%rax,4), %r8
andq $-0x10, %r8
movq %rcx, %rdi
subq %r8, %rdi
movq %rdi, %rsp
negq %r8
xorl %r11d, %r11d
movl %r11d, (%rcx,%r8)
movw %r11w, 0x6(%rdi,%r15,2)
leal 0x2(%rsi), %r10d
movslq %r10d, %rcx
movw %r11w, (%rdi,%rcx,2)
leaq (%rdi,%rax,2), %r8
movl %r11d, (%r8)
movw %r11w, 0x6(%r8,%r15,2)
movw %r11w, (%r8,%rcx,2)
leaq (%rdi,%rax,4), %r9
movl %r11d, (%r9)
movq %r15, -0x30(%rbp)
movw %r11w, 0x6(%r9,%r15,2)
movw %r11w, (%r9,%rcx,2)
testl %esi, %esi
jle 0x27dd
leaq (%r12,%rsi), %rcx
leaq (%r14,%rdi), %r11
addq $0x4, %r11
xorl %r15d, %r15d
movzbl (%r12,%r15), %r13d
movw %r13w, 0x4(%rdi,%r15,2)
movzbl (%rcx,%r15), %r13d
movw %r13w, (%r11,%r15,2)
incq %r15
cmpq %r15, %rsi
jne 0x27c0
testl %edx, %edx
movq -0x30(%rbp), %r13
jle 0x2ba9
movl %r10d, %r10d
leaq (%rdi,%rax,4), %r11
addq $0x8, %r11
addq %rdi, %r14
addq $0x8, %r14
addq $-0x2, %r10
xorl %r15d, %r15d
movq 0x816(%rip), %xmm0      # 0x3020
movapd 0x81e(%rip), %xmm1      # 0x3030
movq %rdx, -0x38(%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 0x2856
cmpl $0x1, %eax
jne 0x2875
testl %esi, %esi
jle 0x29e9
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
movw %cx, 0x4(%rdi,%rax,2)
incq %rax
cmpq %rax, %rsi
jne 0x2842
jmp 0x2892
testl %esi, %esi
jle 0x29e9
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
movw %cx, 0x4(%r8,%rax,2)
incq %rax
cmpq %rax, %rsi
jne 0x2860
jmp 0x2892
testl %esi, %esi
jle 0x29e9
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
movw %cx, 0x4(%r9,%rax,2)
incq %rax
cmpq %rax, %rsi
jne 0x287f
testl %esi, %esi
jle 0x29e1
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
movd %ecx, %xmm2
pshufd $0x50, %xmm2, %xmm2     # xmm2 = xmm2[0,0,1,1]
pmaddwd %xmm0, %xmm2
cvtdq2pd %xmm2, %xmm2
divpd %xmm1, %xmm2
movd 0x6(%rdi,%rax,2), %xmm3
pshuflw $0x60, %xmm3, %xmm3     # xmm3 = xmm3[0,0,2,1,4,5,6,7]
psrad $0x10, %xmm3
cvtdq2pd %xmm3, %xmm3
addpd %xmm2, %xmm3
cvttpd2dq %xmm3, %xmm3
pshuflw $0xe8, %xmm3, %xmm3     # xmm3 = xmm3[0,2,2,3,4,5,6,7]
movd %xmm3, 0x6(%rdi,%rax,2)
leal (%rcx,%rcx,2), %edx
xorps %xmm4, %xmm4
cvtsi2sd %edx, %xmm4
movswl (%r14,%rax,2), %edx
xorps %xmm5, %xmm5
cvtsi2sd %edx, %xmm5
movq -0x8(%r14,%rax,2), %xmm3
punpcklwd %xmm3, %xmm3    # xmm3 = xmm3[0,0,1,1,2,2,3,3]
psrad $0x10, %xmm3
pshufd $0xee, %xmm3, %xmm6     # xmm6 = xmm3[2,3,2,3]
cvtdq2pd %xmm6, %xmm6
cvtdq2pd %xmm3, %xmm7
xorps %xmm3, %xmm3
cvtsi2sd %ecx, %xmm3
unpcklpd %xmm4, %xmm3            # xmm3 = xmm3[0],xmm4[0]
divpd %xmm1, %xmm3
movapd %xmm3, %xmm4
unpckhpd %xmm3, %xmm4            # xmm4 = xmm4[1],xmm3[1]
movapd %xmm3, %xmm8
unpckhpd %xmm2, %xmm8            # xmm8 = xmm8[1],xmm2[1]
addpd %xmm7, %xmm8
addpd %xmm2, %xmm6
cvttpd2dq %xmm8, %xmm7
cvttpd2dq %xmm6, %xmm6
unpcklpd %xmm6, %xmm7            # xmm7 = xmm7[0],xmm6[0]
packssdw %xmm7, %xmm7
movq %xmm7, -0x8(%r14,%rax,2)
addsd %xmm5, %xmm4
cvttsd2si %xmm4, %ecx
movw %cx, (%r14,%rax,2)
movq -0x8(%r11,%rax,2), %xmm4
punpcklwd %xmm4, %xmm4    # xmm4 = xmm4[0,0,1,1,2,2,3,3]
psrad $0x10, %xmm4
cvtdq2pd %xmm4, %xmm5
pshufd $0xee, %xmm4, %xmm4     # xmm4 = xmm4[2,3,2,3]
cvtdq2pd %xmm4, %xmm4
unpckhpd %xmm3, %xmm2            # xmm2 = xmm2[1],xmm3[1]
addpd %xmm4, %xmm2
addpd %xmm3, %xmm5
cvttpd2dq %xmm5, %xmm4
cvttpd2dq %xmm2, %xmm2
unpcklpd %xmm2, %xmm4            # xmm4 = xmm4[0],xmm2[0]
packssdw %xmm4, %xmm4
movq %xmm4, -0x8(%r11,%rax,2)
movswl (%r11,%rax,2), %ecx
xorps %xmm2, %xmm2
cvtsi2sd %ecx, %xmm2
addsd %xmm3, %xmm2
cvttsd2si %xmm2, %ecx
movb %r13b, (%rbx,%rax)
movw %cx, (%r11,%rax,2)
incq %rax
cmpq %rax, %r10
jne 0x289c
addq %rax, %rbx
movq -0x38(%rbp), %rdx
movq -0x30(%rbp), %r13
incq %r15
addq %r13, %r12
cmpq %rdx, %r15
jne 0x2816
jmp 0x2ba9
leal 0x2(%rsi), %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)
leal 0x1(%r15), %ecx
movslq %ecx, %r8
movw %r9w, (%rdi,%r8,2)
leaq (%rdi,%rax,2), %r10
movw %r9w, (%r10)
movw %r9w, (%r10,%r8,2)
testl %r15d, %r15d
jle 0x2a57
xorl %r8d, %r8d
movzbl (%r12,%r8), %r9d
movw %r9w, 0x2(%rdi,%r8,2)
incq %r8
cmpq %r8, %rsi
jne 0x2a44
testl %edx, %edx
jle 0x2ba9
movl %ecx, %r8d
leaq (%rdi,%rax,2), %r9
addq $0x2, %r9
decq %r8
xorl %r10d, %r10d
movsd 0x5a0(%rip), %xmm0      # 0x3018
movq 0x5c0(%rip), %xmm1      # 0x3040
movapd 0x5c8(%rip), %xmm2      # 0x3050
testb $0x1, %r10b
jne 0x2aad
testl %r15d, %r15d
jle 0x2b9a
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
movw %cx, (%r9,%rax,2)
incq %rax
cmpq %rax, %rsi
jne 0x2a99
jmp 0x2ac9
testl %esi, %esi
jle 0x2b9a
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
movw %cx, 0x2(%rdi,%rax,2)
incq %rax
cmpq %rax, %rsi
jne 0x2ab7
testl %esi, %esi
jle 0x2b9a
xorl %eax, %eax
cmpw $0x7f, 0x2(%rdi,%rax,2)
setge %r11b
negb %r11b
movzwl 0x2(%rdi,%rax,2), %ecx
movzbl %r11b, %r14d
subl %r14d, %ecx
movswl %cx, %ecx
leal (,%rcx,8), %r14d
subl %ecx, %r14d
xorps %xmm3, %xmm3
cvtsi2sd %r14d, %xmm3
movswl 0x4(%rdi,%rax,2), %r14d
xorps %xmm4, %xmm4
cvtsi2sd %r14d, %xmm4
mulsd %xmm0, %xmm3
addsd %xmm3, %xmm4
cvttsd2si %xmm4, %r14d
movw %r14w, 0x4(%rdi,%rax,2)
movd %ecx, %xmm3
pshufd $0x50, %xmm3, %xmm3     # xmm3 = xmm3[0,0,1,1]
pmaddwd %xmm1, %xmm3
cvtdq2pd %xmm3, %xmm3
movd -0x2(%r9,%rax,2), %xmm4
pshuflw $0x60, %xmm4, %xmm4     # xmm4 = xmm4[0,0,2,1,4,5,6,7]
psrad $0x10, %xmm4
cvtdq2pd %xmm4, %xmm4
mulpd %xmm2, %xmm3
addpd %xmm3, %xmm4
cvttpd2dq %xmm4, %xmm3
pshuflw $0xe8, %xmm3, %xmm3     # xmm3 = xmm3[0,2,2,3,4,5,6,7]
xorps %xmm4, %xmm4
cvtsi2sd %ecx, %xmm4
movd %xmm3, -0x2(%r9,%rax,2)
movswl 0x2(%r9,%rax,2), %ecx
xorps %xmm3, %xmm3
cvtsi2sd %ecx, %xmm3
mulsd %xmm0, %xmm4
addsd %xmm4, %xmm3
cvttsd2si %xmm3, %ecx
movb %r11b, (%rbx,%rax)
movw %cx, 0x2(%r9,%rax,2)
incq %rax
cmpq %rax, %r8
jne 0x2ad3
addq %rax, %rbx
incq %r10
addq %r15, %r12
cmpq %rdx, %r10
jne 0x2a88
movq -0x40(%rbp), %rsp
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x242d(%rip), %rdi      # 0x4ff0
leaq 0x4c8(%rip), %rsi       # 0x3092
callq 0x20e0
movl $0x1, %edi
callq 0x2120
nopl (%rax)