#ifndef UNSUPPORTED
static void convert_3d(struct filter *f, int *x1, int *y1)
{
    struct threeddata *data = (struct threeddata *) f->data;
    int y;
    int x = *x1;
    unsigned int inp;
    unsigned int height = data->height;
    register const spixel_t *input;
    if (x >= f->childimage->width - 5 || x < 0
	|| *y1 > f->childimage->height) {
	*x1 += *y1 / 2;
	return;
    }
    if (x < 0)
	x = 0;
    for (y = f->childimage->height - 3; y >= 0; y--) {
	int d;
	input = ((spixel_t *) f->childimage->currlines[y] + y / 2);
	inp = (input[x] + input[x + 1] + input[x + 2] +
	       input[x + 3] + input[x + 4] + input[x + 5]);
	input = ((spixel_t *) f->childimage->currlines[y + 1] + y / 2);
	inp += (input[x] + input[x + 1] + input[x + 2] +
		input[x + 3] + input[x + 4] + input[x + 5]);
	input = ((spixel_t *) f->childimage->currlines[y + 2] + y / 2);
	inp += (input[x] + input[x + 1] + input[x + 2] +
		input[x + 3] + input[x + 4] + input[x + 5]);
	d = y - (inp / 16 > height ? height : inp / 16);
	if (d <= *y1) {
	    *y1 = y;
	    *x1 = x + y / 2;
	    return;
	}
    }
    *x1 += *y1 / 2;
    return;
}

static void convertup_3d(struct filter *f, int *x1, int *y1)
{
    struct threeddata *data = (struct threeddata *) f->data;
    int y = *y1;
    int x = *x1;
    unsigned int inp;
    unsigned int height = data->height;
    register const spixel_t *input;
    if (x >= f->childimage->width - 5)
	x = f->childimage->width - 6;
    if (y >= f->childimage->height - 3)
	y = f->childimage->height - 3;
    if (x < 0)
	x = 0;
    if (y < 0)
	y = 0;
    input = ((spixel_t *) f->childimage->currlines[y] + y / 2);
    inp = (input[x] + input[x + 1] + input[x + 2] +
	   input[x + 3] + input[x + 4] + input[x + 5]);
    input = ((spixel_t *) f->childimage->currlines[y + 1] + y / 2);
    inp += (input[x] + input[x + 1] + input[x + 2] +
	    input[x + 3] + input[x + 4] + input[x + 5]);
    input = ((spixel_t *) f->childimage->currlines[y + 2] + y / 2);
    inp += (input[x] + input[x + 1] + input[x + 2] +
	    input[x + 3] + input[x + 4] + input[x + 5]);
    *x1 -= *y1 / 2;
    *y1 = y - (inp / 16 > height ? height : inp / 16);
}

static void do_3d(void *dataptr, struct taskinfo *task, int r1, int r2)
{
    struct filter *RESTRICT f = (struct filter *) dataptr;
    unsigned int y;
    int maxinp = 0;
    unsigned int x;
    unsigned int end;
    unsigned int sum;
    spixel_t const *RESTRICT input;
    unsigned int *RESTRICT lengths;
    unsigned int *RESTRICT sums;
    unsigned int *RESTRICT relsums;
    struct threeddata *data = (struct threeddata *) f->data;


    /* Copy to local variables to improve cse and memory references.  */
    unsigned int height = data->height;
    unsigned int stereogrammode = data->stereogrammode;
    unsigned int colheight = data->colheight;
    unsigned int midcolor = data->midcolor;
    unsigned int darkcolor = data->darkcolor;
    const unsigned int *RESTRICT pixels = data->pixels;
    cpixel_t *RESTRICT * RESTRICT currlines =
	(cpixel_t * RESTRICT * RESTRICT) f->image->currlines;
    struct inp {
	int max;
	unsigned int down;
    } *inpdata;

#ifdef HAVE_ALLOCA1
    lengths =
	(unsigned int *) alloca(sizeof(unsigned int) * f->image->width);
    inpdata =
	(struct inp *) alloca(sizeof(struct inp) * (f->image->width + 2));
    sums =
	(unsigned int *) alloca(sizeof(unsigned int) *
				(f->image->width + 2) * 2);
#else
    lengths =
	(unsigned int *) malloc(sizeof(unsigned int) * f->image->width);
    inpdata =
	(struct inp *) malloc(sizeof(struct inp) * (f->image->width + 2));
    sums =
	(unsigned int *) malloc(sizeof(unsigned int) *
				(f->image->width + 2) * 2);
#endif
    for (x = 0; x < (unsigned int) f->image->width; x++)
	lengths[x] = f->image->height - 1,
	    sums[x * 2 + 0] = 0, sums[x * 2 + 1] = 0, inpdata[x].max = 0;
    sums[x * 2 + 0] = 0, sums[x * 2 + 1] = 0, inpdata[x].max = 0;
    inpdata[x + 1].max = 0;
    end = r2;
    for (y = f->childimage->height - 2; y > 0;) {
	y--;
	input = ((spixel_t *) f->childimage->currlines[y] + y / 2);
	x = r1;
	relsums = sums + (y & 1);

	/* Fix boundary cases.  */
	/*relsums[0] = relsums[1];
	   relsums[end*2-1] = relsums[end*2-2]; */
	inpdata[end + 1] = inpdata[end] = inpdata[end - 1];
	sum =
	    input[x] + input[x + 1] + input[x + 2] + input[x + 3] +
	    input[x + 4] + input[x + 5];

	while (x < end) {
	    unsigned int inp;
	    unsigned int d;

	    /* Average pixel values of 5*3 square to get nicer shapes.  */
	    sum += input[x + 6] - input[x];
	    inp = sum + sums[x * 2 + 1] + sums[x * 2];
	    relsums[x * 2] = sum;
	    inpdata[x].down = inp;

	    /* Calculate shades.  */
	    maxinp = inpdata[x + 2].max;
	    if ((int) inp > maxinp)
		inpdata[x].max = inp - 32;
	    else
		inpdata[x].max = maxinp - 32;

	    /* caluclate top of mountain.  */
	    d = inp / 16;
	    d = y - (d > height ? height : d);

	    /* Underflow */
	    if (d > 65535U)
		d = 0;
	    if (d < lengths[x]) {
		int y1;
		unsigned int color;
		if (stereogrammode)
		    color = pixels[y];
		else if (inp / 16 > height)
		    /*Red thinks on the top.  */
		    color =
			pixels[inp / 16 >=
			       colheight ? colheight : inp / 16];
		else {
		    int c;
		    /* Simple shading model.  
		       Depends only on the preceding voxel.  */

		    c = ((int) inpdata[x + 2].down - (int) inp) / 8;

		    /* Get shades.  */
		    color =
			((int) inp > maxinp ? midcolor : darkcolor) - c;
		    color =
			pixels[color <
			       65535 ? (color <
					height ? color : height) : 0];
		}
		for (y1 = lengths[x]; y1 >= (int) d; y1--) {
		    p_setp(currlines[y1], x, color);
		}
		lengths[x] = d;
	    }
	    x++;
	}
    }
#ifndef HAVE_ALLOCA1
    free(lengths);
    free(inpdata);
    free(sums);
#endif
}
#endif
#undef do_3d
#undef convert_3d
#undef convertup_3d
