GNU Info

Info Node: (xaos.info)filters

(xaos.info)filters


Next: algorithm Prev: xthreads Up: Hacker
Enter node , (file) or (file)node

Filters
=======

   This is a brief description of filter system used internally by XaoS.
Filters in XaoS provides an object oriented interface to every part of
XaoS engine. Main filters are: User interface implemented in ui_helper.c
and zooming engine implemented in zoom.c. Filters are connected into an
queue - at the beggining there is just two filters here(zoom and ui)
but later additional filters should be inserted into the middle of queue
like an stereogram generation etc. The queue supports operations like
remove filter, add filter and initialize.

   In the caluclation every filter should use data caluclated by filter
lower in the queue. Data are stored into image. So for example
stereogram filter should use fractal generated by zooming engine and
create an stereogram.

   This makes XaoS's code more flexible and makes easy future
enhancements like different zooming engine, image rotation, other
special effects, plug-ins and some other funny stuff since interface of
each such part is well defined and each filter has quite good control
over his childs.  So stereogram filter should change palette, force
zooming engine to change depth, width and height of calchlated image to
fit his needs and so on.

   This document describes mainly creating of filter like stereogram
generator i.e. filter placed into middle of queue since I don't expect
there will be many people creating "terminal" filters (zooming
engines/user interface layer) note that different user interface is
possible since user interface layer is not the real user interface just
set of high level functions that should be called by main application
like set_view. So in case you want to use XaoS as an calculation engine
in your program this document is probably not for you.

   Each filter is defined by filter_action structures as follows:
     struct filteraction {
       char *name;
       char *shortname;
       int flags;
       struct filter *(*getinstance)(struct filteraction *a);
       void (*destroyinstance)(struct filter *f);
       int (*doit)(struct filter *f,int flags,int time);
       int (*requirement)(struct filter *f,struct requirements *r);
       int (*initialize)(struct filter *f,struct initdata *i);
       void (*convertup)(struct filter *f,int *x,int *y);
       void (*convertdown)(struct filter *f,int *x,int *y);
       void (*removefilter)(struct filter *f);
     };
   This structure describes static filter's parameters (like its name)
and basic set of methods required for communication with resto of XaoS.
The name field describes filter's name like "An random dot stereogram
generator". Name is displayed by ugly interface in filter's menu. So it
is expected to be descrptive and shorter than 30 characters. The short
name is one word long name for filter like "stereogram". This name is
used by save files, possibly by command line parameters. Simply
everywhere where user should need to write it and writing long
descriptive name should be just wasting of time and disk space.

   Flags field is kept for future enhancements and is expected to be 0
for now.

Creating / destroing of instance
--------------------------------

   Functions getinstance and destroyinstance are equvivalents to
constructor and desctructor in OOP. Getinstance is expected to create
and fill following structure:

     struct filter {
       struct filter *next,*previous;
       struct queue *queue;
       struct filteraction *action;
       struct image *image,*childimage;
       struct requirements req;
       struct fractal_context *fractalc;
       void *data;
       char *name;
       int flags;
       void (*wait_function) (struct filter *f);
       /*stuff for wait_function*/
       int pos,max,incalculation,readyforinterrupt,interrupt;
       char *pass;
     };
   Altrought this structure seems to be long and complex, most of
fileds are unused at this time and rest of them are filled
automatically by function:

 - Function: struct filter *createfilter (struct filteraction *FA);
     That should be used to create instance. Only possibly interesting
     field is data. It's pointer reserved for filter's internal use. So
     it should be pointer to filter's internal variables if required.
     Following is example implementation of getinstance with allocating
     of such additional structure. In case nothing similiar is required
     you should use dirrectly createfilter at getinstance's place.

     static struct filter *getinstance(struct filteraction *a)
     {
           struct filter *f = createfilter(a);    /*create filter structure*/
           struct stereogramdata *i=calloc(sizeof(*i),1);
                                                  /*allocate internal variables*/
           /*initialize your variables here*/
           f->data=i;                             /*add pointer to internal data*/
           return (f);
     }

   The destroyinstance is expected to free memory used by filter
structure and all internal data of filter. To free filter structure use
normal free(filter); So implementation of suchfunction should look like:
     static void destroyinstance(struct filter *f)
     {
          destroyinheredimage(f);
          free(f->data);
          free(f);
     }
   The meaning of destroyinheredimage will be described later.

Initialization
--------------

   During initialization phaste each filter says to his parrent what
kind of images it supports (this should depend on images supported by
his child), parent chooses best supported image format for his purposes
and gives it to the child. Initialization is done in two pases.

   First pass start by lowest filter in the queue and each filter
passes to his parrents requirement structure.

   Second pass starts by the highest filter and each filter passes to
child an image and some other stuff. Then caluclation should begin.

   Queue needs to be reinicialized after creating, resizing,
adding/removing of filter and similiar operations.

   First pass is implemented using require function. This function is
expected to take care at child's requirements it received as parameter,
fill requirements structure and call require function of his parent
filter.
     struct requirements {
       int nimages;
       int supportedmask;
       int flags;
     };
   The nimages field should be set to 1 or 2. In case it is 2, parent
filter must pass image with two buffers. Note that in case it is 1,
parent should pass image with two buffers too.

   Supported mask is mask of supported image types by filter. Image
types are following:
`C256'
     An normal 8bpp image with palette

`REALCOLOR'
     An 16bpp image with 5 bits for red, 5 bits for green and 5 bits
     for blue

`HICOLOR'
     An 16bpp image but with 6 bits for green

`TRUECOLOR24'
     An 24bpp truecolor image with 8bits for each color.

`TRUECOLOR'
     An 32bpp truecolor image with 8bits for each color.

`LARGEITER'
     An 16bpp image but w/o colors. It is expected to hold number of
     iterations   it should be also tought as 16bpp grayscale image

`SMALLITER'
     Similiar to `LARGEITER' but 8bpp

   In case you don't wory about palettes, allocations of colors and you
do just some operation with bitmap, so you wory just abour depth of
image you should use mask of following: `MASK1BPP' for 8 bit images,
`MASK2BPP' for 16bit and so on.

   The latest field of requirements structure is flags. It mask from
following constants:

`IMAGEDATA'
     in case your filter requires data from previous frame untouched.
     In case   this is not set, filters should reuse your image and
     change it. But some   filters like and motion blur or zooming
     engine requires data from previous   frame to construct new, so
     this flag should be set there is no more flags supported at the
moment. Function require should also save child's require structure
into filter->req for later use by initialize pass. So you should look
like:
     static int requirement(struct filter *f,struct requirements *r)
     {
       f->req=*r;    /*Save an child's requirements*/
       r->nimages=1; /*Just one image is required*/
       r->flags&=~IMAGEDATA;/*unset the imagedata field*/
       r->supportedmask=C256|TRUECOLOR|HICOLOR|REALCOLOR;
                     /*mask of all supported image types*/
       return (f->next->action->requirement(f->next, r));
                     /*call parent*/
     }
   Next pass is main initialization. It goes in oposite order(from
parent to child) and child's inhers some stuff from parent like images
etc...  The initialize structure receives an initdata structure:
     struct initdata {
       void (*wait_function) (struct filter *f);
       struct image *image;
       struct fractal_context *fractalc;
       int flags;
     };
   an wait_function is function called by filter during calculation that
lets the parent filters(usually user interface layer) to inform user
how calculation continues. Image is an image expected to be filled by
image in calculation phaste. Fractalc is pointer to structure that will
contain information about fractal during calculation(like formula type
etc...) Flags is mask of following constants:
`DATALOST'
     this is set in case, that data in image was lost(image was cleared
     or  resized or freshly allocated). Filters that uses data from
     previous frames  should take care to this flag. Zooming engine for
     example recalculates  whole image since pixels from previous frame
     was lost.   Note that data should be lost also in case, filter
     receives different  image that in previous initialization since
     some filter behind was  removed.  An inhering process is done
using function:

 - Function: void inhermisc (struct filter *F,struct initdata *I);
     This function sets fields in filter structure like as fractalc or
     wait_func.  Inhering of image is quite complex, since new image
     needs to be prepared for child. In order to save memory it is
     highly recomended to use same image or at least same memory for
     data when passing to child. But this is not allways possible.
     Following function implements heruistic to do this:

 - Function: int inherimage (struct filter *F,struct initdata *DATA,
          int FLAGS, int WIDTH, int HEIGHT, struct palette *PALETTE,
          float PIXELWIDTH, float PIXELHEIGHT)
     You should call this function in yout initialize pass. It fills
     image and childimage in filter structure, prepares initdata for
     child and creates image for child. Note that it should fail in
     some cases and return 0. In this case filter is expected to
     interrupt initialization and return 0 too.

     An FLAGS parameter is mask of following constants:
    `IMAGEDATA'
          in case your filter requires data from previous frame

    `TOUCHDATA'
          In case your filter touches data in output image. This is
          very usual but   there is some filtrs (like interlace or
          subwindow that don't)

    `NEWIMAGE'
          Set in case your filter can not deal with shared images
          (images that have   input data in same memory are as output)
     WIDTH and HEIGHT should be set to 0 in case you want same
     width/height as in parent image or width and height of image you
     want to pass to child.  PALETTE is palette of image you want to
     pass. Set to `NULL' if palette should be inhered from parent's
     image (usual).  PIXELWIDTH and PIXELHEIGHT specifies physical size
     of pixel in centimeters.  If set to 0 they are inhered from
     parent's image.

   In case you use inherimage mechanizm you also must call
destroyinheredimage in destroyinstance function and updateinheredimage
at the begining of calculate function.

   Example implementation:
     static int initialize(struct filter *f,struct initdata *i)
     {struct stereogramdata *s=f->data;
       inhermisc(f,i);
       if(!inherimage(f,i,TOUCHIMAGE,0,0,NULL,0,0) return 0;
       /*initialize here*/
       return(f->previous->action->initialize(f->previous,i));
     }
   Also note that fractal context hold pointer to fractal palette. In
case You don't change image palette everything is OK. But in case
child's image differs from parents image, there should be two
behaviours -- fractal's palette is child one (this should be common for
example in conversion filters ( 8bpp to truecolor etc)) or fractal's
palette is parent's one (like in edge detection filter). By default
fractal's palette is kept to parent's one.  This should be changed by
setfractalpalette call. It has two parameters -- filter structure and
palette. When you pass as palette child's palette, fractal's palette
will be changed to child. In case you pass NULL. Changing of palette
will be disabled (like in motion blur filter in 8bpp mode).  Note that
this is changed just in case you still have access to fractal palette.
Some parent should redirect palette before. Than this functio does
nothing.

Caluclation
-----------

   Main caluclation is done using doit function. It is expected to call
child's caluclation function when required and apply filter at output.
It receives flags. Only flag in `INTERRUPTIBLE' for now. It is mainly
for zooing engine so I do not describe it here. But filter is expected
to pass this flag to child. Next parameter is time in milliseconds that
expired since last doit call. It should be used to caluclate speed of
animation.

   Calculation loops returns flags. Flags is mask from following
constants:
`ANIMATION'
     in case filter performs some animation and expect that calculation
     will be  called again soon

`CHANGED'
     in case something changed in output image (usual)

`INEXACT'
     This is enabled by zooming engine in `INTERRUPTIBLE' mode in case
     that time  exceeded.

   An doit function changes image. Image structure contains following
fields significant for you:
`bytesperpixel'
     number of bytes per pixel (image depth)

`palette'
     palette of image.

`currlines'
     array of pointers to beginings of every scanline of image

`oldlines'
     array of pointers like currlines but for previous image in case
     doublebuffering is enabled

`nimages'
     set to 2 in case doublebuffering is active

`flipimage'
     pointer to function that flips oldlines and currlines.

   palette structure contains following significant fields:

`type'
     type of palette/image (`C256', `TRUECOLOR' etc...)

`size'
     number of allocated entries

`pixels'
     array of allocated entries. Conversion table from number of
     iteration  to pixel value.

`rgb'
     Rgb values for pixels (`NULL' for `TRUECOLOR', `HICOLOR' and
     similiar types)

   To make easier writting calculation loops for different depths
`pixel8_t', `pixel16_t' and `pixel32_t' are predefined. You also can
use include system as in edge detection filter, that lets you write
calculation loops just once and use cpixel_t and it will be compiled
for every bitmap depth.  See edge detection filter (engine/edge.c and
engine/edged.c) for implementation details.

Conversion
----------

   Convertup and convertdown functions are used for converting screen
coordinates to possition in fractal and back. Convertup is function
that receives coordinates in chield's image and is expected to convert
them into coordinates in parents image and call parent's convertup
function.

   Convertdown is reversed(from parent to child).

   In case coordinates respond 1:1 you should use convertupgeneric and
convertdowngeneric. In other case implementation should look like:

     static void convertup(struct filter *f,int *x,int *y)
     {
         *y*=2;
         *x*=2;
         if(f->next!=NULL) f->next->action->convertup(f->next,x,y);
     }
     static void convertdown(struct filter *f,int *x,int *y)
     {
         *y/=2;
         *x/=2;
         if(f->previous!=NULL) f->previous->action->convertdown(f->previous,x,y);
     }

Removing of filter
------------------

   Before filter is removed from queue, removefilter function is called.
It is expected to clean up thinks filter changed. Should be NULL in
most cases.

Registering of filter
---------------------

   Once filteraction structure is filled, filter is done and you should
try to enable it. To enable it in user interface you need to edit
ui/ui_helper.c, add filter into uih_filters structure and increase
uih_nfilters.  Note that order of filters in uih_filter is significant,
since same order is kept in filter queue, so you should specify if you
want to be called before/after filter xy.

   Then it is high time to start experimenting.

   Good luck!


automatically generated by info2www version 1.2.2.9