/* test shit */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>

#include <math.h>

#include <SDL_image.h>

#define MAXWIDTH 512
#define MAXHEIGHT 512

#define true 1
#define false 0

int WIDTH, HEIGHT;

static inline float get(float *src, int x, int y)
{
    return src[y * WIDTH + x];
}

static inline void put(float *src, int x, int y, float p)
{
    src[y * WIDTH + x] = p;
}

static float *new(void)
{
    return malloc(WIDTH * HEIGHT * sizeof(float));
}

static float *copy(float *src)
{
    float *dest = malloc(WIDTH * HEIGHT * sizeof(float));
    memcpy(dest, src, WIDTH * HEIGHT * sizeof(float)); 
    return dest;
}

#define N 5
#define NN ((N * 2 + 1))

static void makegauss(float mat[NN][NN], float sigma, float dx, float dy)
{
    float t = 0;
    int i, j;

    sigma = 2. * sigma * sigma;

    for(j = 0; j < NN; j++)
        for(i = 0; i < NN; i++)
        {
            float a = (float)(i - N) + dx;
            float b = (float)(j - N) + dy;
            mat[i][j] = pow(M_E, - (a * a + b * b) / sigma);
            t += mat[i][j];
        }

    for(j = 0; j < NN; j++)
        for(i = 0; i < NN; i++)
            mat[i][j] /= t;
}

static float *gauss(float *src, float mat[NN][NN])
{
    float *dest = new();
    int x, y, i, j;

    for(y = N; y < HEIGHT - N; y++)
        for(x = N; x < WIDTH - N; x++)
        {
            float p = 0;

            for(j = 0; j < NN; j++)
                for(i = 0; i < NN; i++)
                    p += get(src, x + i - N, y + j - N) * mat[i][j];

            put(dest, x, y, p);
        }

    return dest;
}

static float *fullgauss(float *src, float mat[NN][NN])
{
    float *dest = new();
    int x, y, i, j;

    for(y = 0; y < HEIGHT; y++)
        for(x = 0; x < WIDTH; x++)
        {
            float p = 0;

            for(j = 0; j < NN; j++)
                for(i = 0; i < NN; i++)
                    if(x + i >= N && x + i < WIDTH + N
                       && y + j >= N && y + j < HEIGHT + N)
                        p += get(src, x + i - N, y + j - N) * mat[i][j];

            put(dest, x, y, p);
        }

    return dest;
}

static float fulldist(float *p1, float *p2)
{
    float error = 0.;
    int x, y;

    for(y = 0; y < HEIGHT; y++)
        for(x = 0; x < WIDTH; x++)
        {
            float t = get(p1, x, y) - get(p2, x, y);
            error += t * t;
        }

    return error / (WIDTH * HEIGHT);
}

static float dist(float *p1, float *p2)
{
    float error = 0.;
    int x, y;

    for(y = N; y < HEIGHT - N; y++)
        for(x = N; x < WIDTH - N; x++)
        {
            float t = get(p1, x, y) - get(p2, x, y);
            error += t * t;
        }

    return error / ((WIDTH - N) * (HEIGHT - N));
}

static float *load(char *name)
{
    SDL_Surface *tmp, *surface;
    uint32_t *pixels;
    float *floats;
    int x, y;

    tmp = IMG_Load(name);
    if(!tmp)
        return NULL;

    WIDTH = tmp->w > MAXWIDTH ? MAXWIDTH : tmp->w;
    HEIGHT = tmp->h > MAXHEIGHT ? MAXHEIGHT : tmp->h;
    floats = malloc(WIDTH * HEIGHT * sizeof(float));
    if(!floats)
        return NULL;

    surface = SDL_CreateRGBSurface(SDL_SWSURFACE, WIDTH, HEIGHT, 32,
                                   0xff0000, 0xff00, 0xff, 0x0);
    pixels = (uint32_t *)surface->pixels;
    SDL_BlitSurface(tmp, NULL, surface, NULL);
    SDL_FreeSurface(tmp);

    for(y = 0; y < HEIGHT; y++)
        for(x = 0; x < WIDTH; x++)
        {
            int green = (pixels[y * surface->pitch / 4 + x] >> 8) & 0xff;
            put(floats, x, y, (float)green / 0xff);
        }

    return floats;
}

static void save(float *src, char *name)
{
    SDL_Surface *surface;
    uint32_t *pixels;
    int x, y;

    surface = SDL_CreateRGBSurface(SDL_SWSURFACE, WIDTH, HEIGHT, 32,
                                   0xff0000, 0xff00, 0xff, 0x0);
    pixels = (uint32_t *)surface->pixels;

    for(y = 0; y < HEIGHT; y++)
    for(x = 0; x < WIDTH; x++)
    {
        float p = 255 * get(src, x, y);
        uint32_t i = p < 0 ? 0 : p > 255 ? 255 : p;
        pixels[surface->pitch / 4 * y + x] = (i << 16) | (i << 8) | i;
    }

    SDL_SaveBMP(surface, name);
}

static float *ostromoukhov(float *src)
{
    static int const table[][3] =
    {
         {13, 0, 5}, {13, 0, 5}, {21, 0, 10}, {7, 0, 4},
         {8, 0, 5}, {47, 3, 28}, {23, 3, 13}, {15, 3, 8},
         {22, 6, 11}, {43, 15, 20}, {7, 3, 3}, {501, 224, 211},
         {249, 116, 103}, {165, 80, 67}, {123, 62, 49}, {489, 256, 191},
         {81, 44, 31}, {483, 272, 181}, {60, 35, 22}, {53, 32, 19},
         {237, 148, 83}, {471, 304, 161}, {3, 2, 1}, {481, 314, 185},
         {354, 226, 155}, {1389, 866, 685}, {227, 138, 125}, {267, 158, 163},
         {327, 188, 220}, {61, 34, 45}, {627, 338, 505}, {1227, 638, 1075},
         {20, 10, 19}, {1937, 1000, 1767}, {977, 520, 855}, {657, 360, 551},
         {71, 40, 57}, {2005, 1160, 1539}, {337, 200, 247}, {2039, 1240, 1425},
         {257, 160, 171}, {691, 440, 437}, {1045, 680, 627}, {301, 200, 171},
         {177, 120, 95}, {2141, 1480, 1083}, {1079, 760, 513}, {725, 520, 323},
         {137, 100, 57}, {2209, 1640, 855}, {53, 40, 19}, {2243, 1720, 741},
         {565, 440, 171}, {759, 600, 209}, {1147, 920, 285}, {2311, 1880, 513},
         {97, 80, 19}, {335, 280, 57}, {1181, 1000, 171}, {793, 680, 95},
         {599, 520, 57}, {2413, 2120, 171}, {405, 360, 19}, {2447, 2200, 57},
         {11, 10, 0}, {158, 151, 3}, {178, 179, 7}, {1030, 1091, 63},
         {248, 277, 21}, {318, 375, 35}, {458, 571, 63}, {878, 1159, 147},
         {5, 7, 1}, {172, 181, 37}, {97, 76, 22}, {72, 41, 17},
         {119, 47, 29}, {4, 1, 1}, {4, 1, 1}, {4, 1, 1},
         {4, 1, 1}, {4, 1, 1}, {4, 1, 1}, {4, 1, 1},
         {4, 1, 1}, {4, 1, 1}, {65, 18, 17}, {95, 29, 26},
         {185, 62, 53}, {30, 11, 9}, {35, 14, 11}, {85, 37, 28},
         {55, 26, 19}, {80, 41, 29}, {155, 86, 59}, {5, 3, 2},
         {5, 3, 2}, {5, 3, 2}, {5, 3, 2}, {5, 3, 2},
         {5, 3, 2}, {5, 3, 2}, {5, 3, 2}, {5, 3, 2},
         {5, 3, 2}, {5, 3, 2}, {5, 3, 2}, {5, 3, 2},
         {305, 176, 119}, {155, 86, 59}, {105, 56, 39}, {80, 41, 29},
         {65, 32, 23}, {55, 26, 19}, {335, 152, 113}, {85, 37, 28},
         {115, 48, 37}, {35, 14, 11}, {355, 136, 109}, {30, 11, 9},
         {365, 128, 107}, {185, 62, 53}, {25, 8, 7}, {95, 29, 26},
         {385, 112, 103}, {65, 18, 17}, {395, 104, 101}, {4, 1, 1}
    };

    float *dest = new();
    float *tmp = copy(src);
    int x, y;

    for(y = 0; y < HEIGHT; y++)
    {
        for(x = 0; x < WIDTH; x++)
        {
            int x1 = (y & 1) ? WIDTH - 1 - x + 1 : x - 1;
            int x2 = (y & 1) ? WIDTH - 1 - x : x;
            int x3 = (y & 1) ? WIDTH - 1 - x - 1 : x + 1;

            float p = get(tmp, x2, y);
            float q = p > 0.5 ? 1. : 0.;
            float error = (p - q);
            int i = p * 255.9999;

            put(dest, x2, y, q);

            if(i > 127)
                i = 255 - i;
            if(i < 0)
                i = 0;

            error /= table[i][0] + table[i][1] + table[i][2];

            if(x < WIDTH - 1)
                put(tmp, x3, y, get(tmp, x3, y) + error * table[i][0]);
            if(y < HEIGHT - 1)
            {
                if(x > 0)
                    put(tmp, x1, y + 1,
                        get(tmp, x1, y + 1) + error * table[i][1]);
                put(tmp, x2, y + 1, get(tmp, x2, y + 1) + error * table[i][2]);
            }
        }
    }

    free(tmp);

    return dest;
}

/* Dither using error diffusion and Floyd-Steinberg-like coefficients:
         X a b
     c d e f g
     h i j k l
*/
static float *ed(float *src, int serpentine,
                 int a, int b, int c, int d, int e, int f,
                 int g, int h, int i, int j, int k, int l)
{
    float *dest = new();
    float *tmp = copy(src);
    int x, y, n;

    n = a + b + c + d + e + f + g + h + i + j + k + l;

    for(y = 0; y < HEIGHT; y++)
    {
        int swap = serpentine && (y & 1);

        for(x = 0; x < WIDTH; x++)
        {
            int x0 = swap ? WIDTH - 1 - x + 2 : x - 2;
            int x1 = swap ? WIDTH - 1 - x + 1 : x - 1;
            int x2 = swap ? WIDTH - 1 - x     : x;
            int x3 = swap ? WIDTH - 1 - x - 1 : x + 1;
            int x4 = swap ? WIDTH - 1 - x - 2 : x + 2;

            float p = get(tmp, x2, y);
            float q = p > 0.5 ? 1. : 0.;
            float error = (p - q) / n;

            put(dest, x2, y, q);

            if(x < WIDTH - 1)
                put(tmp, x3, y, get(tmp, x3, y) + error * a);
            if(x < WIDTH - 2)
                put(tmp, x4, y, get(tmp, x4, y) + error * b);
            if(y < HEIGHT - 1)
            {
                if(x > 0)
                {
                    put(tmp, x1, y + 1,
                        get(tmp, x1, y + 1) + error * d);
                    if(x > 1)
                        put(tmp, x0, y + 1,
                            get(tmp, x0, y + 1) + error * c);
                }
                put(tmp, x2, y + 1, get(tmp, x2, y + 1) + error * e);
                if(x < WIDTH - 1)
                {
                    put(tmp, x3, y + 1,
                        get(tmp, x3, y + 1) + error * f);
                    if(x < WIDTH - 2)
                        put(tmp, x4, y + 1,
                            get(tmp, x4, y + 1) + error * g);
                }
            }
            if(y < HEIGHT - 2)
            {
                if(x > 0)
                {
                    put(tmp, x1, y + 2,
                        get(tmp, x1, y + 2) + error * h);
                    if(x > 1)
                        put(tmp, x0, y + 2,
                            get(tmp, x0, y + 2) + error * i);
                }
                put(tmp, x2, y + 2, get(tmp, x2, y + 2) + error * j);
                if(x < WIDTH - 1)
                {
                    put(tmp, x3, y + 2,
                        get(tmp, x3, y + 2) + error * k);
                    if(x < WIDTH - 2)
                        put(tmp, x4, y + 2,
                            get(tmp, x4, y + 2) + error * l);
                }
            }
        }
    }

    free(tmp);

    return dest;
}

/* XXX */
static float *dbs(float *src, float *orig, float sigma, float dx, float dy)
{
    float mat[NN][NN];
    float *dest, *tmp, *tmp2;
    float error;

    makegauss(mat, sigma, 0., 0.);
    tmp = fullgauss(src, mat);

    makegauss(mat, sigma, dx, dy);
    dest = copy(orig);
    tmp2 = fullgauss(dest, mat);

    error = dist(tmp, tmp2);

    for(;;)
    {
        int changes = 0;
        int x, y, i, j, n;

        for(y = 0; y < HEIGHT; y++)
        for(x = 0; x < WIDTH; x++)
        {
            float d, d2, e, best = 0.;
            int opx = -1, opy = -1;

            d = get(dest, x, y);

            /* Compute the effect of a toggle */
            e = 0.;
            for(j = -N; j < N + 1; j++)
            {
                if(y + j < 0 || y + j >= HEIGHT)
                    continue;

                for(i = -N; i < N + 1; i++)
                {
                    float m, p, q1, q2;

                    if(x + i < 0 || x + i >= WIDTH)
                        continue;
                    
                    m = mat[i + N][j + N];
                    p = get(tmp, x + i, y + j);
                    q1 = get(tmp2, x + i, y + j);
                    q2 = q1 - m * d + m * (1. - d);
                    e += (q1 - p) * (q1 - p) - (q2 - p) * (q2 - p);
                }
            }
            if(e > best)
            {
                best = e;
                opx = opy = 0;
            }

            /* Compute the effect of swaps */
            for(n = 0; n < 8; n++)
            {
                static int const step[] =
                    { 0, 1, 0, -1, -1, 0, 1, 0, -1, -1, -1, 1, 1, -1, 1, 1 };
                int idx = step[n * 2], idy = step[n * 2 + 1];
                if(y + idy < 0 || y + idy >= HEIGHT
                     || x + idx < 0 || x + idx >= WIDTH)
                    continue;
                d2 = get(dest, x + idx, y + idy);
                if(d2 == d)
                    continue;
                e = 0.;
                for(j = -N; j < N + 1; j++)
                {
                    if(y + j < 0 || y + j >= HEIGHT)
                        continue;
                    if(j - idy + N < 0 || j - idy + N >= NN)
                        continue;
                    for(i = -N; i < N + 1; i++)
                    {
                        float ma, mb, p, q1, q2;
                        if(x + i < 0 || x + i >= WIDTH)
                            continue;
                        if(i - idx + N < 0 || i - idx + N >= NN)
                            continue;
                        ma = mat[i + N][j + N];
                        mb = mat[i - idx + N][j - idy + N];
                        p = get(tmp, x + i, y + j);
                        q1 = get(tmp2, x + i, y + j);
                        q2 = q1 - ma * d + ma * d2 - mb * d2 + mb * d;
                        e += (q1 - p) * (q1 - p) - (q2 - p) * (q2 - p);
                    }
                }
                if(e > best)
                {
                    best = e;
                    opx = idx;
                    opy = idy;
                }
            }

            /* Apply the change if interesting */
            if(best <= 0.)
                continue;
            if(opx || opy)
            {
                d2 = get(dest, x + opx, y + opy);
                put(dest, x + opx, y + opy, d);
            }
            else
                d2 = 1. - d;
            put(dest, x, y, d2);
            for(j = -N; j < N + 1; j++)
            for(i = -N; i < N + 1; i++)
            {
                float m = mat[i + N][j + N];
                if(y + j >= 0 && y + j < HEIGHT
                    && x + i >= 0 && x + i < WIDTH)
                {
                    float t = get(tmp2, x + i, y + j);
                    put(tmp2, x + i, y + j, t + m * (d2 - d));
                }
                if((opx || opy) && y + opy + j >= 0 && y + opy + j < HEIGHT
                                && x + opx + i >= 0 && x + opx + i < WIDTH)
                {
                    float t = get(tmp2, x + opx + i, y + opy + j);
                    put(tmp2, x + opx + i, y + opy + j, t + m * (d - d2));
                }
            }

            changes++;
        }

        fprintf(stderr, "did %i changes\n", changes);

        if(changes == 0)
            break;
    }

    free(tmp);
    free(tmp2);

    return dest;
}

static void study(float *src, float *dest, float sigma, float precision)
{
#   define Z 3
    float mat[NN][NN];
    float *tmp, *tmp2;
    float e0, best, fx = -1., fy = -1., step = 2.;
    int dx, dy;

    makegauss(mat, sigma, 0., 0.);
    tmp = gauss(src, mat);
    tmp2 = gauss(dest, mat);

    e0 = dist(tmp, tmp2);
    free(tmp2);

    while(step > precision)
    {
        float bfx = 0., bfy = 0., e;

        best = 9999.;

        for(dy = 0; dy <= Z; dy++)
            for(dx = 0; dx <= Z; dx++)
            {
                makegauss(mat, sigma, fx + step * dx / Z, fy + step * dy / Z);
                tmp2 = gauss(dest, mat);
                e = dist(tmp, tmp2);
                free(tmp2);
                if(e < best)
                {
                    best = e;
                    bfx = fx + step * dx / Z;
                    bfy = fy + step * dy / Z;
                }
            }

        fx = bfx - step / Z;
        fy = bfy - step / Z;
        step = step * 2 / Z;
    }

    free(tmp);

    printf("%g -> %g for %g %g\n", 1000 * e0, 1000 * best, fx, fy);
    fflush(stdout);
}

static float *merge(float *im1, float *im2, float t)
{
    float *dest = new();
    int x, y;

    for(y = 0; y < HEIGHT; y++)
    for(x = 0; x < WIDTH; x++)
        put(dest, x, y, t * get(im1, x, y) + (1. - t) * get(im2, x, y));

    return dest;
}

int main(int argc, char *argv[])
{
    float mat0[NN][NN];
    float mat[NN][NN];
    float *src, *src2, *dest, *tmp, *tmp2;
    float sigma;
    int dx, dy, a, b, c, d, i;

    if(argc < 2)
        return 1;

    src = load(argv[1]);
    if(!src)
        return 2;

#if 0
    if(argc < 3)
        return 3;
    src2 = load(argv[2]);
    if(!src2)
        return 4;

    for(i = 0; i <= 100; i++)
    {
        tmp = merge(src, src2, (float)i / 100.);
        dest = ed(tmp, 7, 0, 1, 3, 5, 0, 0, 0, 0, 0, 0, 0);
        study(tmp, dest, 1.2, 0.001);
        free(dest);
        free(tmp);
    }
    free(src2);
    free(src);
#endif

#if 0
    tmp = ed(src, 7, 0, 0, 3, 5, 1, 0, 0, 0, 0, 0, 0);
    //dest = dbs(src, tmp, 0., 0.);
    dest = dbs(src, tmp, 0.20, 0.30);
    //dest = dbs(src, tmp, 0.158718, 0.283089);
    //dest = copy(tmp);
    free(tmp);
    study(src, dest, 1.2, 0.00001);
    save(dest, "output.bmp");
    free(dest);
#endif

#if 0
    //dest = ed(src, 5, 0, 0, 3, 5, 3, 0, 0, 0, 0, 0, 0);
    //dest = ed(src, false, 7, 0, 0, 3, 5, 1, 0, 0, 0, 0, 0, 0);
    //dest = ed(src, true, 7, 0, 0, 3, 5, 1, 0, 0, 0, 0, 0, 0);
    //dest = ed(src, true, 7, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0);
    //dest = ed(src, 7, 5, 3, 5, 7, 5, 3, 1, 3, 5, 3, 1);
    //dest = ed(src, 7, 0, 1, 3, 5, 0, 0, 0, 0, 0, 0, 0);
    //dest = ed(src, 7, 0, 1, 4, 4, 0, 0, 0, 0, 0, 0, 0);
    //dest = ed(src, 2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0);
    //dest = ed(src, 2911, 0, 1373, 3457, 2258, 0, 0, 0, 0, 0, 0, 0);
    dest = ostromoukhov(src);
    //dest = ed(src, 7, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0);
    //printf("%s: ", argv[1]);
    //study(src, dest, 1.2, 0.001);
    save(dest, "output.bmp");
    free(dest);
#endif

#if 0
#   define STEP 32
    dest = ed(src, 7, 0, 0, 3, 5, 1, 0, 0, 0, 0, 0, 0);
    makegauss(mat, 1.2, 0., 0.);
    tmp = gauss(src, mat);
    for(dy = 0; dy < STEP; dy++)
    {
        for(dx = 0; dx < STEP; dx++)
        {
            float fy = 2. / STEP * (dy - STEP / 2.);
            float fx = 2. / STEP * (dx - STEP / 2.);

            makegauss(mat, 1.2, fx, fy);
            tmp2 = gauss(dest, mat);
            printf("%g %g %g\n", fy, fx, 1000. * dist(tmp, tmp2));
            fflush(stdout);
            free(tmp2);
        }
        printf("\n");
    }

    save(dest, "output.bmp");
#endif

#if 0
    makegauss(mat0, 1.2, 0, 0);
    for(a = 0; a <= 16; a++)
    for(b = 0; b <= 16; b++)
    for(c = 0; c <= 16; c++)
    for(d = 0; d <= 16; d++)
    {
        float *tmp;
        if(a + b + c + d != 16)
            continue;
#if 0
        if(b > c) continue;
        if(d > c) continue;
        if(d > a) continue;
#endif
        printf("%02d %02d %02d %02d: ", a, b, c, d);
        dest = ed(src, true, a, 0, 0, b, c, d, 0, 0, 0, 0, 0, 0);
        //dest = ed(src, false, a, 0, 0, b, c, d, 0, 0, 0, 0, 0, 0);
        //study(src, dest, 1.2, 0.01);
        tmp = gauss(src, mat0);
        tmp2 = gauss(dest, mat0);
        printf("%.5g\n", 1000. * dist(tmp, tmp2));
        fflush(stdout);
        free(tmp);
        free(tmp2);
        free(dest);
    }
#endif

#if 0
    tmp = gauss(src, 0., 0.);
    for(a = 0; a < 16; a++)
    for(b = 0; b < 16; b++)
    for(c = 0; c < 16; c++)
    for(d = 0; d < 16; d++)
    {
        if(a + b + c + d != 16)
            continue;
        dest = ed(src, a, 0, 0, b, c, d, 0, 0, 0, 0, 0, 0);
        tmp2 = gauss(dest, 0., 0.);
        printf("%.5g: (%02d %02d %02d %02d)\n",
               1000. * dist(tmp, tmp2), a, b, c, d);
        free(dest);
        free(tmp2);
    }

    save(dest, "output.bmp");
#endif

#if 0
    printf("%s: ", argv[1]);
    makegauss(mat0, 1.2, 0, 0);
    tmp = gauss(src, mat0);

    dest = ed(src, false, 7, 0, 0, 3, 5, 1, 0, 0, 0, 0, 0, 0);
    tmp2 = gauss(dest, mat0);
    printf("%.5g ", 1000. * dist(tmp, tmp2));
    free(tmp2);
    makegauss(mat, 1.2, 0.16, 0.28);
    tmp2 = gauss(dest, mat);
    printf("%.5g ", 1000. * dist(tmp, tmp2));
    free(tmp2);
    free(dest);

    dest = ed(src, false, 7, 5, 3, 5, 7, 5, 3, 1, 3, 5, 3, 1);
    tmp2 = gauss(dest, mat0);
    printf("%.5g ", 1000. * dist(tmp, tmp2));
    free(tmp2);
    makegauss(mat, 1.2, 0.26, 0.76);
    tmp2 = gauss(dest, mat);
    printf("%.5g ", 1000. * dist(tmp, tmp2));
    free(tmp2);
    free(dest);

    dest = ostromoukhov(src);
    tmp2 = gauss(dest, mat0);
    printf("%.5g ", 1000. * dist(tmp, tmp2));
    free(tmp2);
    makegauss(mat, 1.2, 0.0, 0.19);
    tmp2 = gauss(dest, mat);
    printf("%.5g ", 1000. * dist(tmp, tmp2));
    free(tmp2);
    free(dest);

    dest = ed(src, true, 2911, 0, 0, 1373, 3457, 2258, 0, 0, 0, 0, 0, 0);
    tmp2 = gauss(dest, mat0);
    printf("%.5g ", 1000. * dist(tmp, tmp2));
    free(tmp2);
    makegauss(mat, 1.2, 0.0, 0.34);
    tmp2 = gauss(dest, mat);
    printf("%.5g ", 1000. * dist(tmp, tmp2));
    free(tmp2);
    free(dest);

    printf("\n");
#endif

#if 0
    printf("%s\n", argv[1]);

    dest = ed(src, false, 7, 0, 0, 3, 5, 1, 0, 0, 0, 0, 0, 0);
    study(src, dest, 1.2, 0.01);
    free(dest);

    dest = ed(src, false, 7, 5, 3, 5, 7, 5, 3, 1, 3, 5, 3, 1);
    study(src, dest, 1.2, 0.01);
    free(dest);

    dest = ostromoukhov(src);
    study(src, dest, 1.2, 0.01);
    free(dest);

    dest = ed(src, true, 2911, 0, 0, 1373, 3457, 2258, 0, 0, 0, 0, 0, 0);
    study(src, dest, 1.2, 0.01);
    free(dest);

    printf("\n");
#endif

#if 0
    //dest = ostromoukhov(src);
    //dest = ed(src, true, 7, 0, 0, 3, 5, 1, 0, 0, 0, 0, 0, 0);
    tmp = new();//ed(src, 7, 0, 0, 3, 5, 1, 0, 0, 0, 0, 0, 0);
    dest = dbs(src, tmp, 0., 0.);
    for(sigma = 0.8; sigma < 2; sigma *= 1.03)
    //for(sigma = 0.8; sigma < 2.; sigma *= 1.01)
    {
        printf("%g ", sigma);
        study(src, dest, sigma, 0.01);
    }
#endif

    tmp = new();
    a = 0;
    for(sigma = 0.8; sigma < 2; sigma *= 1.03)
    {
        char buf[1024];
        printf("%i: %g\n", a, sigma);
        dest = dbs(src, tmp, sigma, 0., 0.);
        sprintf(buf, "output-dbs-%i.bmp", a++);
        save(dest, buf);
    }

    return 0;
}