/* This file was generated by scramble.py. */
#include "lids.h"
#include "scramble.h"
void black_out_not_circle(Image *image, int x, int y, int r)
{
    int w = image->w;
    int h = image->h;
    int sum = 0, n = 0;
    for (int j = 0; j < h; j++)
    {
        for (int i = 0; i < w ; i++)
        {
            int dx = i - x;
            int dy = j - y;
            int d = sqrt(dx * dx + dy * dy);
            if (d <= r)
            {
                int c = image->data.b[i + j * w];
                sum += c;
                n++;
            }
        }
    }
    sum /= n;
    for (int j = 0; j < h; j++)
    {
        for (int i = 0; i < w ; i++)
        {
            int dx = i - x;
            int dy = j - y;
            int d = sqrt(dx * dx + dy * dy);
            if (d > r)
            {
                image->data.b[i + j * w] = sum;
            }
        }
    }
}
void fix_crop_border(Image *image, int l, int t, int r, int b)
{
    /* 
     * Color outside areas of image with average color of inside area. */
    if (l > 0)
    {
        l = 0;
    }
    if (t > 0)
    {
        t = 0;
    }
    if (r > 0)
    {
        r = 0;
    }
    if (b > 0)
    {
        b = 0;
    }
    int w = image->w;
    int h = image->h;
    l = -l;
    t = -t;
    r = w + r - 1;
    b = h + b - 1;
    int sum = 0, n = 0;
    for (int j = t; j <= b; j++)
    {
        for (int i = l; i <= r ; i++)
        {
            int c = image->data.b[i + j * w];
            sum += c;
            n++;
        }
    }
    sum /= n;
    for (int j = 0; j < h; j++)
    {
        for (int i = 0; i < w ; i++)
        {
            if (j < t || j > b || i < l || i > r)
            {
                image->data.b[i + j * w] = sum;
            }
        }
    }
}
void mask_crop_border(Image *image, int l, int t, int r, int b)
{
    /* 
     * Fill in the mask for parts of the iris being clipped off. */
    if (l > 0)
    {
        l = 0;
    }
    if (t > 0)
    {
        t = 0;
    }
    if (r > 0)
    {
        r = 0;
    }
    if (b > 0)
    {
        b = 0;
    }
    int w = image->w;
    int h = image->h;
    l = -l;
    t = -t;
    r = w + r - 1;
    b = h + b - 1;
    for (int j = 0; j < h; j++)
    {
        for (int i = 0; i < w ; i++)
        {
            if (j < t || j > b || i < l || i > r)
            {
                image->data.b[i + j * w] = 255;
            }
        }
    }
}
int scan_edge(Image *image, int x, int y, int dx, int dy, int n)
{
    /* 
     * Starting at the given location, created a mask from edges. */
    int w = image->w;
    int i = x;
    int firstval = -1;
    for (int t = 0; t < n; t++)
    {
        int j = y;
        while (1)
        {
            int c = image->data.b[i + j * w];
            if (c > 0)
            {
                firstval = j;
                goto got_firstval;
            }
            j += dy;
            if (j == -1 || j == image->h)
            {
                break;
            }
        }
        i += dx;
    }
    got_firstval:;
    if (firstval == -1)
    {
        return 0;
    }
    i = x;
    int bval = -1;
    for (int t = 0; t < n; t++)
    {
        int j = y;
        int pc = 0;
        while (1)
        {
            int c = image->data.b[i + j * w];
            if (j == bval)
            {
                pc = 128;
            }
            if (c > 0)
            {
                pc = 255;
                firstval = j;
                if (bval == -1 || j * dy < bval * dy)
                {
                    bval = j;
                }
            }
            image->data.b[i + j * w] = pc;
            j += dy;
            if (j == -1 || j == image->h)
            /* We reached the border without masking anything? */
            {
                if (pc == 0)
                {
                    for (j = firstval; j != -1 && j != image->h; j += dy)
                    {
                        image->data.b[i + j * w] = 192;
                    }
                }
                break;
                /* bval += dy */
            }
        }
        i += dx;
    }
    return 0;
}
Image * mask_lids(Image const *orig_image, char const *what, int px, int py, int pr, int ix, int iy, int ir)
{
    /* 
     * px, py, pr: Pupil position and radius
     * ix, iy, ir: Iris position and radius
     * 
     * This creates a black&white image, where black pixels are considered iris
     * texture and all other pixels are considered belonging to lids.
     * 
     * Right now, this is a somewhat over-zealous algorithm, often cutting away
     * more than needed, especially in the presence of eyelashes. */
    int ox = ix - ir;
    int oy = iy - ir;
    Image *image = image_copy_crop(orig_image, ox, oy, ir * 2 + 1, ir * 2 + 1);
    int w = image->w;
    int h = image->h;
    fix_crop_border(image, ox, oy, orig_image->w - w - ox, orig_image->h - h - oy);
    ix -= ox;
    iy -= oy;
    px -= ox;
    py -= oy;
    int min_r = pr * 1.5;
    /* Blackout the pupil */
    black_out_circle(image, px, py, pr, min_r);
    /* Blackout anything outside the iris */
    /* black_out_not_circle(image, ix, iy, ir) */
    if (hasword(what, "lids"))
    {
        char name[MAX_PATH];
        get_image_name(orig_image, "lids", name);
        save_tiff_luminance(name, image);
    }
    Image *edges = canny(image, 3, 15, 0, 1, "");
    /* black_out_not_circle(edges, ix, iy, ir - 4) # cover up for blackened circle */
    threshold_below(edges, 6, 0);
    threshold_above(edges, 7, 255);
    remove_streaks(edges, "", 30, 30, 0, 1, 1, 1, 1, 100, 1, False);
    if (hasword(what, "lidscanny"))
    {
        char name[MAX_PATH];
        get_image_name(orig_image, "lidscanny", name);
        save_tiff_luminance(name, edges);
    }
    scan_edge(edges, 0, iy, 1, -1, ir + 1);
    scan_edge(edges, edges->w - 1, iy, -1, -1, ir);
    scan_edge(edges, 0, iy, 1, 1, ir + 1);
    scan_edge(edges, edges->w - 1, iy, -1, 1, ir);
    mask_crop_border(edges, ox, oy, orig_image->w - w - ox, orig_image->h - h - oy);
    if (hasword(what, "lidsmask"))
    {
        char name[MAX_PATH];
        get_image_name(orig_image, "lidsmask", name);
        save_tiff_luminance(name, edges);
    }
    return edges;
}
Image * generate_mask(Image *eye, int px, int py, int pr, int ix, int iy, int ir, int tw, int th)
{
    Image *mask = image_new_undef_b(tw, th);
    mask->name = strdup(eye->name);
    double angle = 0, da = 2 * pi / tw;
    for (int i = 0; i < tw; i++)
    {
        double c = cos(angle);
        double s = -sin(angle);
        double sx = px + 0.5 + c * pr;
        double sy = py + 0.5 + s * pr;
        double ex = ix + 0.5 + c * ir;
        double ey = iy + 0.5 + s * ir;
        for (int j = 0; j < th; j++)
        {
            int x = sx + (ex - sx) * j / th;
            int y = sy + (ey - sy) * j / th;
            mask->data.b[i + j * tw] = eye->data.b[x + y * eye->w];
        }
        angle += da;
    }
    return mask;
}
#define addbit { if (x) code[codepos] |= 1 << bitpos; bitpos++; if (bitpos == 32) { codepos++; bitpos = 0; } }
uint32_t * generate_mask_code(Image *mask, int thick, int count)
{
    /* 
     * Bits are added to the code starting to the left and with the lowest bit in
     * a byte.
     * We duplicate each row, as the actual bitcode has two rows for each signal.
     * The count parameters specifies how many stripes to use, thick is how thick
     * one stripe is in pixels. We consider a bit mask as soon as a single input
     * pixel was even slightly masked (the mask is 255 levels grayscale, from
     * 0 = unmasked to 255 = completely masked). */
    uint32_t *code = ALLOCATE0(2 * count * mask->w / thick);
    int codepos = 0;
    int bitpos = 0;
    for (int j = 0; j < count * thick; j += thick)
    {
        for (int l = 0; l < 2; l++)
        {
            for (int i = 0; i < mask->w; i++)
            {
                int x = 0;
                for (int k = 0; k < thick; k++)
                {
                    B c = mask->data.b[i + mask->rowbytes * (j + k)];
                    x += c;
                }
                addbit;
            }
        }
    }
    assert(codepos == count * 2 * 512 / 32);
    return code;
}
Image * generate_empty_mask(int w, int h)
{
    Image *mask = image_new_undef_b(w, h);
    for (int i = 0; i < mask->w; i++)
    {
        for (int j = 0; j < mask->h; j++)
        {
            mask->data.b[j * mask->rowbytes + i] = 0;
        }
    }
    return mask;
}
/* This file was generated by scramble.py. */
