/* An edge detection filter.
 * This is very simple filter - it initializes smalliter image and then
 * does an simple edge detection algo on it.
 */
#include <config.h>
#ifndef _plan9_
#ifndef NO_MALLOC_H
#include <malloc.h>
#endif
#include <stdio.h>		/*for NULL */
#else
#include <u.h>
#include <libc.h>
#include <stdio.h>
#endif
#define SLARGEITER
#include <xthread.h>
#include <filter.h>

#define spixel_t pixel8_t
#include <c256.h>
#define do_edge do_edge8
#include "edge2d.c"

#undef spixel_t
#define spixel_t pixel16_t
#include <truecolor.h>
#define do_edge do_edge32
#include "edge2d.c"

#include <true24.h>
#define do_edge do_edge24
#include "edge2d.c"

#include <hicolor.h>
#define do_edge do_edge16
#include "edge2d.c"

static int requirement(struct filter *f, struct requirements *r)
{
    f->req = *r;
    r->nimages = 1;
    r->flags &= ~IMAGEDATA;
    r->supportedmask = MASK1BPP | MASK2BPP | MASK3BPP | MASK4BPP;
    return (f->next->action->requirement(f->next, r));
}

static int initialize(struct filter *f, struct initdata *i)
{
    inhermisc(f, i);
    /*in/out coloring modes looks better in iter modes. This also saves some
       memory in truecolor. */
    if (f->data != NULL)
	destroypalette((struct palette *) f->data);
    f->data =
	createpalette(0, 65536,
		      i->image->bytesperpixel <= 1 ? SMALLITER : LARGEITER,
		      0, 65536, NULL, NULL, NULL, NULL, NULL);
    if (!inherimage
	(f, i, TOUCHIMAGE | NEWIMAGE, 0, 0, (struct palette *) f->data, 0,
	 0))
	return 0;
    return (f->previous->action->initialize(f->previous, i));
}

static struct filter *getinstance(CONST struct filteraction *a)
{
    struct filter *f = createfilter(a);
    f->name = "Edge detection";
    return (f);
}

static void destroyinstance(struct filter *f)
{
    if (f->data != NULL)
	destroypalette((struct palette *) f->data);
    destroyinheredimage(f);
    free(f);
}

static int doit(struct filter *f, int flags, int time)
{
    int val;
    int size = f->childimage->palette->type == SMALLITER ? 253 : 65536;
    if (f->image->palette->size < size)
	size = f->image->palette->size;
    if (((struct palette *) f->data)->size != size)
	((struct palette *) f->data)->size =
	    size, ((struct palette *) f->data)->version++;
    updateinheredimage(f);
    val = f->previous->action->doit(f->previous, flags, time);
    drivercall(*f->image,
	       xth_function(do_edge8, f, f->image->height),
	       xth_function(do_edge16, f, f->image->height),
	       xth_function(do_edge24, f, f->image->height),
	       xth_function(do_edge32, f, f->image->height));
    xth_sync();
    return val;
}

CONST struct filteraction edge2_filter = {
    "Edge detection2",
    "edge2",
    0,
    getinstance,
    destroyinstance,
    doit,
    requirement,
    initialize,
    convertupgeneric,
    convertdowngeneric,
    NULL
};
