This is Info file xaos.info, produced by Makeinfo version 1.67 from the
input file xaos.texinfo.

INFO-DIR-SECTION Graphics
START-INFO-DIR-ENTRY
* XaoS: (xaos).                 The fast realtime interactive fractal zoomer
END-INFO-DIR-ENTRY

   (C) 1997 Jan Hubicka

   Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.


File: xaos.info,  Node: Top,  Next: Overview,  Prev: (dir),  Up: (dir)

XaoS 3.0
********

                                 An realtime interactive fractal zoomer
                                                            Mar 2, 1997

* Menu:

* Overview::		What does this software do then ?
* User::		User's guide
* Hacker::		Hacker's guide


File: xaos.info,  Node: Overview,  Next: User,  Prev: Top,  Up: Top

Overview
********

* Menu:

* Why?::		Why yet another fractal generator?
* What?::		What does this software do then?
* History::		How this all started?


File: xaos.info,  Node: Why?,  Next: What?,  Prev: Overview,  Up: Overview

Why yet another fractal generator?
==================================

   We decided to make XaoS, because all fractal browsers we know needs
long time to calculate every image. You may browse nice images
generated by them but real impression from fractal--they self
similarity and possible infinite zooming into nice part of fractals can
be seen only in animation. There are many programs available that makes
nice animations but they takes long time to calculate and lots of space
on disc. Most of animations are quite ugly because their authors can't
see it without many hours of calculations.

   Natural question is: it is possible to generate such animation in
realtime? Ansver was negative for many years, since Mandelbrot set is
very computational expensive. Thinks are changing. Today's computer are
fast enought to calculate aprox. 1000 pixels per frame. It is enought
for very low resolution animation (30x30). Several programs doing that
are available. But 30x30 animation still looks quite ugly. To make
animation nice you need at least 320x200 pixels. And thats 65 times
more!  One possibility is wait until computers will be fast enought, but
it should take many years and then 320x200 animations will be obsolette
and everyone will want 1024x768 resolution instead.

   We found special algorithm that saves up to 99.98% of calculations
during zooming by reusing pixels already caluclated in previous frames.
There were some programs doing similiar trick before but we don't know
about any able to do zooming interactivly in same or higher speed than
XaoS does. Many other tricks was later implemented into XaoS to
archieve higher framerate.  Now XaoS does up to 120 frames per second
at 120Mhz pentium in fullscreen 320x200 animation and calculates at the
avearge 160 (0.24%) pixels per frame.  This makes XaoS fast enought to
archeieve primary goal--realtime animation, but there is still many
places for improvement, since more complex fractals, higher
resolutions, or slower computers still brings many problems.


File: xaos.info,  Node: What?,  Next: History,  Prev: Why?,  Up: Overview

What does this software do then ?
=================================

   XaoS is an realtime interactive fractal zoomer. This means that it
lets you zoom smoothly into place you choose without many hours of
calculation required by most of other fractal generators. It now has
also many other features, like 9 different fractal types, autopilot,
special coloring modes, support for various bit depths (8bpp,
truecolor, hicolor and realcolor), random palette generation, color
cycling etc...


File: xaos.info,  Node: History,  Prev: What?,  Up: Overview

How this all started
====================

   This section is still under development. Sorry :)


File: xaos.info,  Node: User,  Next: Hacker,  Prev: Overview,  Up: Top

User's guide
************

   This charapter contains documentation for XaoS's users. It contains
maninly thinks that are too long to describe in help or tutorials. So
it is targeted for advanced users.

* Menu:

* format::		XaoS's file format description


File: xaos.info,  Node: format,  Prev: User,  Up: User

XaoS's file format description?
===============================

   This section describes format used by XaoS for animations,
confiugration files and saved possitions. All these files have common
format, designed to be easily readable, to allow manual editing of
files and converting them into another program.

   I also taken a care to make it easily extensible for future versions
of XaoS so I hope there will not be many incompatibilities between
various XaoS's versions.

   File is simple set of commands executed seqentially. XaoS does not
provide any varibles/cycles as usual scrippting languages but possible
future extension to scheme should be easy since format uses scheme-like
syntax.  Syntax of every command is:

     (command_name <PARAM1> <PARAM2>...)

   Where parameters are optional and separated by whitespace (arbitary
number of spaces, tabs and enters). Parameters should have following
types:

`integer'
     number w/o decimal point (`123')

`float'
     floating point number in decimal notation with optional exponent
     (`1.23E2')

`keyword'
     text started by apostroph `''. It is used to pass various string
     constants like formula name (`'mandel') Apostroph is required for
     scheme compatibility

`string'
     Text inside double quotes. The only parameter that should contain
     whitespaces

`boolean'
     `#t' for true or `#f' for false

   XaoS supports following functions: (functions with * invokes
recaluclation)

Control functions:
------------------

   XaoS command language lacks any control contstructions like loops,
if etc, since it is expected that scheme interpreter will be used in
case such thinks will be required.

 - Function: (LOAD STRING)
     This function loads and interprets file. It works in similiar way
     as include in C.

 - Function: (INITSTATE)
     This function reset XaoS state to default values from version 3.0.
     This command should be at the beggining of each animation file,
     since otherwise some stuff previously enabled by user should make
     inexpected effects.  State is not reseted by default before
     playing animation since it should make impossible to write macros.
     Current version IMO don't need them, but in future versions, where
     scheme programming language will be available this should be much
     more interesting subject.

Timming functions:
------------------

   This functions control animation replay speed.

 - Function: (USLEEP INTEGER)
     This function waits selected amount of time(in usec) until next
     commands are processed. Screen is recalculated and displayed at
     the begining of usleep when some (*) command were procesed in the
     last frame. Remaining time is spent by waiting or performing
     animation you entered by animation commands(see later)

 - Function: (WAIT)
     Waits until screen is animated (fractal is in calculation or some
     filters -- like motionblur does some animation. Do not call this
     function when zoom, or continuous rotation is active otherwise
     deadlock happends. It is recomended to call it, before text
     subtitles are displayed, since it looks ugly when they are
     displayed over blocky unfinished fractal. It may look well for you
     but ugly for others. Also you should call it after animation is
     performed and before switch to another fractal happeds, since
     switch to fractal involves calculation, screen is stopped for a
     while and unfinished fractal there looks ugly. You should also
     call it, when you want to do something as soon as possible.

 - Function: (TEXTSLEEP)
     This function is similiar to usleep, but should be used after text
     subtitle is displayed. Time to sleep is calculated from number of
     letters displayed and letters per second value. Letters per second
     value should be adjusted by users, so this provides mechanizm for
     finetuning speed of subtitles.


Fractal context functions:
--------------------------

   Fractal context contain informations about current fractal such as
formula, coloring modes etc.

 - Function: (FORMULA KEYWORD) (*)
     parameter keyword specifies formula you want to use. Following
     keywords are supported:mand, mand4, mand5, mand6, octo, newton,
     phoenix and newton The formula is switched and some other fractal
     context variables are switched to selected formula's defaults:
     julia/mandelbrot mode, current view.  Command works in same way as
     number key in ugly interface.

 - Function: (JULIA BOOLEAN) (*)
     Selects whether julia or mandelbrot version of fractal will be
     caluclated

 - Function: (JULIASEED FLOAT FLOAT) (* ONLY WHEN FAST JULIA MODE IS
          OFF)
     Selects julia seed (real and imaginary part)

 - Function: (PERTURBATION FLOAT FLOAT) (*)
     Selects perturbation value for mandelbrot version of set

 - Function: (PLANE INTEGER) (*)
     Selects plane number (same as in ugly interfact minus 1--starts
     with zero) I choosed numbering of planes instead of names because
     I was unable to find some nice, short and descriptive names for
     them.

 - Function: (INCOLORING INTEGER) (*)
     Selects inside coloring mode. Number works in same way as in plane
     command

 - Function: (OUTCOLORING INTEGER) (*)
     Same as incoloring but for outside coloring modes

 - Function: (INTCOLORING INTEGER) (*)
     Selects truecolor inside coloring mode. Number works in same way
     as in plane command. Has effect just wjem outcoloring mode is set
     to 10 (truecolor coloring)

 - Function: (OUTTCOLORING INTEGER) (*)
     Same as intcoloring but for outside coloring modes

 - Function: (MAXITER INTEGER) (*)
     Sets maximal number of iterations

 - Function: (RANGE INTEGER)
     Sets solid guessing range i.e how large rectangles will be filled
     by solid color when all four coners has same color.  0 disables
     this feature (increases precisity and slowes down)

 - Function: (PERIODICITY BOOLEAN)
     Enables/disables periodicity checking

Viewport functions:
-------------------

   Current viewport is part of fractal context, but I describe it here
separately to simplify orientation in this document. XaoS uses 4 numbers
to specify viewport--first two are real and imaginary coordinate of
center of view and next two are real and imaginary ranges. I decided to
use both ranges instead of "rectangular" view to allow specify viewport
more exactly to make animation nice even in unusual window dimensions.
Of course you should use both numbers equal. Viewport is before
calculation scalled according to current window dimension and smalles
possible viewport where image is correct(i.e not too wide/shrink)
containing whole selected viewport is displayed. So you should expect a
bit more stuff on the screen than you choosed.

 - Function: (ANGLE FLOAT) (* - JUST WHEN FASTROTATE MODE IS DISABLED)
     Set rotation angle in degrees

 - Function: (VIEW FLOAT FLOAT FLOAT FLOAT) (*)
     This function simply sets viewport.

 - Function: (ANIMATEVIEW FLOAT FLOAT FLOAT FLOAT) (*)
     This function is very similiar to previous one, except that it is
     expected that view will be changes just slightly so recaluclation
     with just ANIMATE priority (see fastmode command) is performed.

 - Function: (MOVEVIEW FLOAT FLOAT)
     This is animation function. For whole time selected by usleep after
     this frame will be spent by moving smoothly center of viewport to
     selected one

 - Function: (MORPHVIEW FLOAT FLOAT FLOAT FLOAT)
     This function is similiar to previous one except it allows also
     zooming/unzooming

 - Function: (FASTROTATE BOOLEAN)
     Enables/disables fast rotation mode. When fast rotation mode is on,
     XaoS is slower, but changing of angle does not require
     recaluclation.

 - Function: (MORPHANGLE FLOAT)
     This function smoothle morphes current angle to new one. Parameter
     is in degrees. Requires fastrotation mode enabled

 - Function: (AUTOROTATE BOOLEAN)
     Enables automatical continous rotation. Works just when fastrotate
     mode is enabled.

 - Function: (ROTATIONSPEED FLOAT)
     Adjust rotation speed. Parameter is in degrees per second.

 - Function: (ZOOMCENTER FLOAT FLOAT)
     This function sets center where you want to zoom/unzoom (where you
     pointed mouse in ugly interface). Parameters are not screen
     coordinates but coordinates in the fractal.

 - Function: (ZOOM)
     Starts zooing to point choosed by zoomcenter. This works in same
     way as button1 in the ugly interface. I don't recommend using this
     in manualy done scripts since it is not easy to expect result and
     result should differ slightly at different platforms/framerates.
     After zooming stops it is recommended use animateview to fix this
     possible error.  In manually writeln scripts I expect Zooming is
     performed until stop command is executed.

 - Function: (UNZOOM)
     Like zoom but starts unzooming

 - Function: (STOP)
     Stops zooming/unzoming (not imediately but after short time
     required for slowdown)

 - Function: (MAXSTEP FLOAT)
     Selects speed of zooming/unzooming. Step specifies how large
     amount of range will be taken away each 1/20 of second.  (0 means
     nothing, 1 means everything - this value is incorrect) Higher
     values means faster zooming

 - Function: (SPEEDUP FLOAT)
     When zooming/unzoming every 1/20 of second the speedup value is
     added to current step until maxstep is reeached. So this value
     selects speedup/slowdown of animation. Both this functions are
     more for internal use of XaoS then for manually wrote scripts.

Fast julia mode functions:
--------------------------

   Julia seed should be changed also using normal juliaseed function

 - Function: (FASTJULIA BOOLEAN) (* - JUST WITH #F)
     Enables/disables fast julia mode.

 - Function: (MORPHJULIA FLOAT FLOAT)
     Morphes seed from current one into new one linerary.

User interface functions:
-------------------------

 - Function: (FASTMODE KEYWORD)
     Image should be recalculated in two modes - fast mode, when after
     fixed amount of time caluclation is stopped and displayed with
     possibly lowered resolution and then resolution is slowly improved.
     Normal mode recaluclates image and displays it when finished. It
     also stops timming, so time spent by calclatig of image should
     differ in replay. (and next frames will not be replayed
     faster/slower to "get in time")

     By default new images are caluclated using normal mode but
     animation is caluclated using fast mode. You can change this
     behaviour by specifying:

    `never'
          Fast mode will be disabled

    `animation'
          The default behaviour

    `new'
          Use fast mode even for new images

 - Function: (FILTER KEYWORD BOOLEAN)
     Enables/disables selected filter. Keyword select filter and shoud
     be one of the following:
    `blur'
          motion blur filter

    `stereogram'
          random dot stereogram

    `interlace'
          interlace filter

    `truecolor'
          Truecolor emulator (recommended to enable in case your images
          rely on truecolor, smooth grades or palette size)

    `edge'
          wide edge detectio filter

    `edge2'
          Narrow edge detection filter

Palette functions
-----------------

   XaoS has small problems with restoring of palette. I had two goals in
save/replay mechanizm - to replay animations as exactly as possible and
to replay animation in highest possible quality (even higher then when
they was recorded). This two goals can not be solved in following
situation: XaoS uses palette as large as possible(approx 250 in 8bpp,
65536 in truecolor etc...). So when palette is saved in truecolor mode
and replayed in 8bpp it has to be shorter and when it is saved in 8bpp
and replayed in 65536 it is bigger. So do not rely on palette much.
First 200 entries should be OK but later ones should be different.
Another problem is color cycling.  Since on slower computers image
recaluclation takes longer time and color cycling is asymchronous
process, replay can not be exact.  So after you stop cycling, palette
should be shifted differently than when recorded. Please DO NOT RELY ON
ROTATED PALETTES.

   Following functions are provided:

 - Function: (DEFAULTPALETTE INTEGER) (* -- DO NOT RECALUCLATE IN MOST
          OF 8BPP MODES)
     Sets the default palette. The parameter says how much is palette
     shifted (by preious cycling). Should be 0 in the most cases.

 - Function: (PALETTE INTEGER INTEGER INTEGER)
     Generates random palette. First number specifies algorithm. It
     should be usefull for possible future improvements and must be 1
     for now.  Next parameter is random seed for palette. And the last
     one specifies shift like in (defaultpalette)

 - Function: (CYCLING BOOLEAN)
     Enables/disables color cycling. Note that on devices, where color
     cycling is impossible this command is ignored.

 - Function: (CYCLINGSPEED INTEGER)
     Sets cycling speed(how many shifts per second). Numbers lower than
     zero inverses direction of cycling

Text output functions
---------------------

   To make possible writting of commented tutorials XaoS has simple
text output functions too.

 - Function: (TEXT STRING)
     Displays text to the screen

 - Function: (TEXTPOSSITION HORIZONTAL VERTICAL)
     Lets you specify possition of displayed text. You may choose from 9
     possitions. HORIZONTAL parameter should be one of following
     keywords: `'left', `'center', `'right' and VERTICAL: `'top',
     `'middle', `'bottom'

 - Function: (MESSAGE STRING)
     Works in same way as `text' but uses string as index to message
     catalog, so it should be used for translatable tutorials.

 - Function: (LETTERSPERSEC INTEGER)
     Lets you adjust letters per second value used by textsleep. This
     is not recomended to use from animation since it should be best to
     let user tune it for himself. This function should be used in
     configuration file.

 - Function: (CLEARSCREEN)
     Clears screen...

 - Function: (DISPLAY)
     Displays fractal again. After text is displayed (or screen
     cleared), screen is not updated anymore to prevent overwriting of
     text. This is keept for compatibility with future version, where
     movement under text subtitles should be possible. You need to call
     `(display)' when you want to draw fractals again. It should be
     also used to clear subtitles (it redisplays screen with fractal)

   Example:

     ;configure everything for the first frame
     (palette 1 1163254293 0)	;custom palette
     (filter 'stereogram #f)		;no filters
     (filter 'interlace #f)
     (filter 'blur #f)
     (formula 'mandel)		;mandelbrot set
     (fastmode 'animation)		;default fast mode
     (fastjulia #f)			;normal mode
     (cycling #t)			;enable cycling
     (cyclingspeed 7)
     (maxiter 276)			;higher number o fiterations
     (outcoloring 0)			;no in/out coloring/plane
     (incoloring 0)
     (range 3)			;default range for solid guessing
     (plane 0)
     (usleep 1000000)		;second frame start here
     (moveview -1.8101154154614007889 -8.2687205907162041209E-05)
     				;just move the image
     (usleep 1000000)		;thirt frame
     (morphview -1.8101154154614007889 -8.2687205907162041209E-05
                 6.277210971069452361E-10 6.2772109785334669875E-10)
     				;10 seconds of zooming into selected rectanlge
     (usleep 100000000)

XaoS galerry
------------

   I plan to make XaoS galerry of animations and possition files at
XaoS homepage so please send me all your nice animations and images you
created using XaoS to `hubicka@paru.cas.cz'


File: xaos.info,  Node: Hacker,  Prev: User,  Up: Top

Hacker's guide
**************

   This charapter contains documentation for those who are interested in
improving, studying or using of XaoS sources in other programs.  It
includes documentation of those parts of XaoS I think they should be
usefull for someone.

* Menu:

* driver::		Driver API description
* xthreads::		XaoS thread library
* filters::		Filters
* algorithm::		Algorighm description
* timerlib::		The timer library


File: xaos.info,  Node: driver,  Next: xthreads,  Prev: Hacker,  Up: Hacker

Driver API description
======================

   To port sucessfully XaoS to some platform you need:

   * ANSI C compatible optimizing compiler. Note that optimizing
     compiler is really required, since XaoS is coded to be good target
     for optimizations and don't have any routines coded in assembly,
     so if you will use some bad compiler, you should receive more than
     ten times slower result. Also note that some compilers has serious
     problems with compiling XaoS -- like most of DOS compilers (Watcom
     C, Borland C, Microsoft C etc...), plan9 compiler also has serious
     problms with `formulas.c' . They generate incorrect code or crash
     during compilation. I highly recomend to use GNU C compiler.

   * Fast way to avoid division by zero/owerflow and other floating
     point exception. XaoS is curefully coded to not to crash in this
     case, but don't have any tests to avoid such situation and expect
     random result in such case.  Many plantforms provide way to switch
     coprocesor into mode, where 1/0 is evaulated into Inf etc. I there
     is no such way, try to use some kind of signal handler that will
     ignore such exceptions. This way should be slow, so if you really
     must use it, please contact me and we shall discuss speed
     issues/add some tests into most freqvent exceptions in XaoS. If
     your platform don't provide any such way, contact me too and I
     will have to introduce plenty of tests as ifdef, wich shlould
     greatly polute code and redce speed :(.

   * Text or graphics output device. If you have only text output
     device, you may use AA driver, wich renders fractals into high
     quality ASCII art. In this case you might skip this section,
     download AA-lib (http://www.ta.jcu.cz/aa) and read porting section
     of AAlib manual. Graphics device must one of:

        * 8bits per pixel with user definable palette `C256'

        * 8bits per pixel with static palette `FIXEDCOLOR'

        * 8bits per pixel with static grayscale `GRAYSCALE'

        * 16bits per pixel with 5 bits per each color, Red first, Green
          last `REALCOLOR'

        * 16bits per pixel with 5 bits per green and blue, 6 for green,
          red first `HICOLOR'

        * 24bits per pixel with 8 bits per each color, Red first
          `TRUECOLOR24'

        * 24bits per pixel with 8 bits per each color, Red first
          `TRUECOLOR24'

        * 32bits per pixel with highest 8 bit unused, otherwise like
          previous `TRUECOLOR'

        * 32bits per pixel with highest 8 bit unused, otherwise like
          previous at little edian machine `TRUECOLORMI'

        * 1bits per pixe, zero is black, most significant bit first,
          lines are aligned `MBITMAP'

        * 1bits per pixe, zero is black, most significant bit last,
          lines are aligned `LBITMAP'

        * 1bits per pixe, zero is white, most significant bit first,
          lines are aligned `MIBITMAP'

        * 1bits per pixe, zero is white, most significant bit last,
          lines are aligned `LIBITMAP'

     Please contact me if you have different kind of device. Some modes
     (like missordered truecolor modes) should be added really easily
     if required.  Note that mono/16 colors devices will be probably
     never supported internally by XaoS, since I expect they will be
     slower than 8bpp, so XaoS will internally work in 8bpp and then
     image should be converted. Contact me if you want to write such
     convertor.

   * Some way to save images. By default XaoS uses pnglib, wich is
     ported to many platforms, but there is still many other. If your
     system has some standard image format, wich is easier to handle
     than .png, contact me and I will show you, how to add such support
     to XaoS.

   * Stdio compatible library (this is problem at Mac or BeOS)

   Ugly interface is designed to make writing of new drivers as easy as
possible.  You need to write just few functions to fill following table:
(use file `ui_template' for starting of writing new driver from scrath)
     struct ui_driver {
       char *name;
       int (*init)(void);            /*initializing function. returns 0 if fail*/
       void (*getsize)(int *,int *);	/*get current size..in full-screen versions
                                       i.e svga and dos asks user for it*/
       void (*processevents)(int,int *,int *,int *,int *);
                                     /*processevents..calls ui_resize,ui_key
                                       also returns positions of mouse..
                                       waits for event if first parameter is
                                       1*/
       void (*getmouse)(int *,int *,int *);
                                     /*returns current mouse positions*/
       void (*uninit)();             /*called before exit*/
       int (*set_color)(int,int,int,int);
                                     /*alloc palette color and returns number*/
       int (*set_range)(ui_palette *palette,int start,int end)
                                     /*Set palette range*/
       void (*print)(int,int,char *);/*prints text*/
       void (*display)();            /*displays bitmap*/
       int (*alloc_buffers)(char **buffer1,char **buffer2);/*makes buffers*/
       void (*free_buffers)(char *buffer1,char *buffer2);/*frees buffers*/
       void (*flip_buffers)(void);   /*prints text*/
       void (*clrscr)(void);         /*Clear screen*/
       void (*mousetype) (int type); /*Change mouse cursor*/
       void (*driveropt) (void);     /*Driver depended actions*/
       void (*flush) (void);         /*Flush current state to screen*/
       int textwidth;                /*width of text*/
       int textheight;		/*height of text*/
       char **help;                  /*help text*/
       int helpsize;                 /*size of help in lines*/
       struct params *params;        /*command line parameters*/
       int flags;
       float width,height;
       int maxwidth,maxheight;
       int imagetype;
       int palettestart,paletteend,maxentries;
     };

Functions
---------

   Ui uses following functions to communicate with driver:

 - Function: init
     function that initializes driver and returns 1 if success and 0 if
     fail

 - Function: getsize (INT *WIDTH,INT *HEIGHT)
     returns size of screen(window) x and y

 - Function: processevents (INT WAIT, INT *X,INT *Y, INT *BUTTONMASK,
          INT &KEYS)
     gets new keyboard/mouse events. parameters:
    WAIT
          if 1 function can wait for next event otherwise just lookup if
                    something comed. This is usefull on multitasked os
          where xaos 	   does not eats unnecesaru cpi.

    *X,*Y
          here returns current positions of mouse

    *B
          returns mask of `BUTTON1',`BUTTON2',`BUTTON3' for mouse
          buttons

    *K
          returns mask for cursor keys
               `1'     left     `2'     right     `4'     up     `8'
               down             function also calls `ui_key'(ASCII
     character) and ui_resize if required

     note in case of problems freeing/allocating inside processevents
     you may     call `ui_call_resize' that calls resize later outside
     this function

 - Function: uninit
     Unitialises driver -- called before exit.

 - Function: set_range(UI_PALETTE *PALETTE, INT START, INT END)
     This is an preffered way to set palette (second way is `set_color')
     when `imagetype' is `UI_C256' (256 color with palette) one of this
     two functions is required. In truecolor modes they are unused. In
     case direct access to palette is possible at your platform, define
     this one. Function is expected to set all color cells between
     START to END to colors defined in PALETTE. `Ui_palette' is array
     of UI_RGB. `Palette[0]' is color for entry number START. `Ui_rgb'
     is an array of `char'.  `Palette[0][0]' is red field of entry
     number START, `Palette[0][1]' is green and `Palette[0][2]' is
     blue. `0' means black and `255' means full intensity. Use `NULL'
     if your driver don't support this call.

 - Function: set_color (INT R,INT G,INT B,INT INIT)
     This is an secondary way, that should be used at platforms w/o
     direct   palette access (like X11 or static color schemes). It
     receives RGB value   of color, and returns index of color cell
     with this color or -1 if no more   color cells available. An INIT
     parameter is set to 1, when first entry   of palette is allocated,
     `set_color' is expected to free all color   entries previously
     allocated. Use `NULL' if your driver don't support   this call

 - Function: print (INT `x',INT `y', CHAR *`text')
     prints text to screen at possition x/y

 - Function: display (VOID)
     displays current buffer to screen

 - Function: alloc_buffers (CHAR **BUFFER1,CHAR **BUFFER2)
     allocs two buffers that can hold screen size bitmap.    Also sets
     current buffer to buffer1. Since version 2.1 returns scanline
     size in bytes(usually width) and 0 if fail. This is usefull on
     systems, that   allocated bitmap bigger than
     window/screen(dividable by 4 or so)

 - Function: free_buffers(CHAR *BUFFER1,CHAR *BUFFER2)
     frees allocated buffers

 - Function: flip_buffer (VOID)
     flips buffers -- set current buffer to other one

 - Function: flush (VOID)
     This function should be used by drivers with buffered output to
     flush   output buffers. Other driver should set it to NULL.

 - Function: rotate_palette (INT DIRRECTION)
     function used for palette rotating. It is not required. Set to
     NULL if   it is unimplemented in your driver.

     When rotating is on this function is periodicaly called with
     direction   attribute. It must rotate all colors
     1-number_of_allocated direction steps   forward except first one.
     This should be implemented also using cmap array   in
     zoom_context that contains correct rgb values.

     So you may use ui_getcontext to get zoom_context and then   set
     context->numcolors colors in array cmap.

 - Function: mousetype (INT TYPE)
     This function is used to change mouse cursor. It receives
     following values:
    `NORMALMOUSE'
          This mouse is usually displayed at screen, when UI waits for
          user      commands

    `WAITMOUSE'
          This mouse is displayed when UI is busy(should be famous wait
          clocks)      or you may use mouse defined in ui_dos --
          mandelbrot set

    `REPLAYMOUSE'
          This mouse is displayed during replay. Should be none at
          fullscreen      drivers, since blinking mouse cursor during
          replay looks ugly. At      windowed system disabling mouse
          looks ugly, so it should be some funny      cursor.
     You should use NULL if your driver don't support this.

 - Function: clrscr (VOID)
     This function is

 - Function: driveropt (VOID)
     This is an optional function (should be set to NULL) that should
     be used for   various driver depended actions. You should use
     ui_menu call (see uinew.c   for examples of usage) to make some
     driver depended menu.

Other information
-----------------

   Also some additional variables are used to inform ui about driver.
All this values can be changed by init functions in case they are
unknown before.

TEXTHEIGHT,TEXTWIDTH
     width and height of your font

PALETTESTART,PALETTEEND
     First and last palette entry, that should be changed. This you
     should use   to avoid changing of entries reserved for window
     system, text, mouse etc.

MAXENTRIES;
     Number of allocatable entries. Normally should be
     PALETTESTART-PALETTEEND

IMAGETYPE
     defines type of image. Should be one of following values:
    `UI_C256'
          clasical 256 color with palette scheme used by most older
          graphics     adapters. You should use it also for staticcolor
          schemes but they are     not supported well in current
          version.

    `UI_TRUECOLOR'
          32bpp truecolor mode

    `UI_TRUECOLOR24'
          24bpp truecolor mode.

    `UI_HICOLOR'
          16bpp hicolor mode (65536 colors)

    `UI_REALCOLOR'
          16bpp realcolor mode (32768 colors)

   FOLLOWING PART IS NOT REQUIRED TO MAKE FIRST VERSION OF DRIVER
WORKING.  so you may skip to REGISTERING DRIVER for first read and
return here later.

HELP
     help text. This text is displayed at the end of ui' help. So you
     can put   your copyright there and additional informations about
     driver.

HELPSIZE
     number of lines of help

PARAMS
     Using this you may define command line options for you driver.

     They are defined using params structure like:
            static struct params params[]={
              {"-mode",P_NUMBER,&defmode,
                "Select graphics mode(same number as in interactive menu)"},
              {NULL,0,NULL,NULL}  /*this is MUST be last option field*/
            };

     every line is one parameters. List ends with `{NULL,0,NULL,NULL}'.
      First filed is option name.    Second field is type of parameter:
    `P_SWITCH'
          no parameter - variable is just set to 1 if option

    `P_NUMBER'
          integer number

    `P_STRING'
          string

    `P_FLOAT'
          floating point number (variable is float)     Third is
     pointer to variable that is changed if option is set.    It is for
     example `int*' for `P_NUMBER' or `P_SWITCH' and so on..    Last
     one is help text. Displayed by `ui -h'

WIDTH,HEIGHT
     see FLAGS. May be set to `0.0, 0.0' for the begining

MAXWIDTH,MAXHEIGHT
     see FLAGS. May be set to 0,0 for the begining

FLAGS
     This variable says more about your driver. You may start with
     value 0.    But for final version it is recomeded to read
     following section curefully.

     Flags are uppercase constants and should be set by following way:

     `ASYNC_PALETTE | PALETTE_ROTATION'

     following switches are supported:

    `RANDOM_PALETTE_SIZE'
          random size of palette. This is used in X where palette is
          shared between     programs. By default xaos allocates all
          available colors up to 256. This     is not very nice to
          other aplications in X. So randomsize causes that     just
          some random number of colors(between 8-256) are allocated.

          Also when this variable is off XaoS expects that allways same
          number of     colors is available.

    `UPDATE_AFTER_RESIZE'
          recalculate and redraw screen even if its size is not changed.
             In case that resize precodure destruys data in buffers
     Palette rotation options:

     Palette rotation should be implemented by various ways.      You
     may define following values to let xaos know about
     features/limitations     of your implementetion:

    `ROTATE_INSIDE_CALCULATION'
          call rotate routing inside calculation loop too?       (vbuff
          should include incorrect data)

    `PALETTE_REDISPLAYS'
          If you rotate_palette function displays buffers(like in
          truecolor modes. Set this to 1 and ui will handle this more
            effectivly)        Screen/window size informations

     Xaos needs to know exact size of displayed images. This is required
        for random dot stereograms and also for keeping fractals in
     their shape     (do not make them wide on 640x200 resolution etc.)
        So minimally one of the following values should be defined.
      (they are sorted in order I preffer them)
    `SCREENSIZE'
          values width/height specifies exact size of screen/window in
          centimeters

    `PIXELSIZE'
          values width/height specifies exact size of one pixel in
          centimeters      This is better for windowed enviroments
          where window size is often changed

    `FULLSCREEN'
          driver runs fullscreen. XaoS automatically uses default
          screen size      (29.0cm x 21.5cm)

    `RESOLUTION'
          driver does not know exact screen size. But knows resolution
          used.       (it is in variables width/height) XaoS
          automatically calculates      pixel width
          using:29.0cm/maxwidth      and height: 21.5/maxheight
     Of course default width and height can be changed by command line
     options.     You may also use combinations like:

    `SCREENSIZE | FULLSCREEN'
          the best for fullscreen drivers

    `PIXELSIZE | RESOLUTION'
          the best for windowed drivers

    `FULLSCREEN'
          for fullscreen drivers than have no idea about screen size...
                do not forget to set WIDTH, HEIGHT, MAXWIDTH,
     MAXHEIGHT fields if required.

Registering driver
------------------

   Than just register driver to `driver.c' and you may compile :) You
may use `ui_template.c' as driver template..

   You may also look at xthreads library description if you are porting
XaoS to some SMP platofrm.

   Please let me know if you want to start code some driver.


File: xaos.info,  Node: xthreads,  Next: filters,  Prev: driver,  Up: Hacker

XaoS thread library
===================

   This description should be usefull for those, who want to port XaoS
into multiprocessor platforms and those, who want to implement some
filter or other relativly computational expensive code. Note that thread
library should be mapped into nothread calls, in case host does not
allows multithreading or it is not SMP architecture (since this library
is used only to distribute calcualtion into other CPUs)

   XaoS thread library is simple map of few functions required by XaoS
to system library for threads.

   It has following variables:

 - Variable: ethreads
     This is set to 1 in case that threads are enabled

 - Variable: nthreads
     Number of threads

   It and following calls:

 - Function: void xth_init (int THREADS)
     This function initializes threading library (starts threads, sets
     ETHREAD to 1 and NTHREADS to n. THREADS parameter should be set to
     0 -- autodetection or number of threads users wants. In case
     threads is set to 1, threading library is disabled and following
     functions are mapped into ther nothread_ equivalents defined in
     `xthread.h'.

     Note that threads are not identical -- there is main thread (one
     that called xth_init) that comunicates with drivers, controls
     calcualtion etc. and other tasks that are waiting to orders from
     main task. They also can't use functions from xthread library.

 - Function: void xth_uninit (void)
     This function uninitializes thread library -- kills child threads,
     sets ETHREAD to 0 and NTHREADS to 1.

 - Function: void xth_function (xfunction *FUNCTION, void *data, int
          RANGE)
     This function is used in case, engine wants to perform some
     operation at image in parael. It is expected to wait until all
     threads are ready and start FUNCTION at all threads including
     control one with following paramters: DATA -- this parameter is
     same as DATA passed to xth_function, TASKINFO -- pointer to
     structure taskinfo, that is platform depended (defined in
     `xthread.h') but must have at least field `n', that holds number
     of thread (control thread has 0 and other numbers in range 1 -
     NTHREADS). Next two parameters is range of image, function is
     expected to do action. Xth_function is expected to divided RANGE
     into NTHREADS equal pieces and pass always start of piece and
     start of next piece (RANGE in case of last one). Function does not
     wait for other threads at the end and returns imediately to main
     thread after FUNCTION returns.

     This function is called approx 5-10 times per frame

 - Function: void xth_sync (void)
     This functions waits until all threads are ready for next order
     from main task.

     This function is called approx 5-10 times per frame

 - Function: void xth_bgjob (xfunction *FUNCTION, void *DATA)
     This function is expected to behave as follows: look if there is
     any thread waiting for orders, if so, ask him to call FUNCTION
     with similiar conventions as in xth_function except that range
     parameters are set to 0.  Otherwise it starts function in normally
     (at foreground).

     This function is called once per frame.

 - Function: void xth_nthread (struct taskinfo *S)
     This function should be used to determine number of current
     thread. Do not use `taskinfo->n' instead since in case threads are
     disabled, it should be defined to 0 and that allows optimizer to
     perform better optimizations.  This function should be called by
     all threads.

 - Function: void xth_lock (int N)

 - Function: void xth_unlock (int N)
     Lock/unlock lock number N. At least `MAXSEMAPHORS' locks must be
     available.

     Note that locks are used always for very short fragments of code
     so they needs to be fast. So spinlocks are maybe better than
     Dijskra semaphors.  Untested. They are called once per calculated
     line/row during zoom and once per approx 10 pixels during
     calculation of new image.

 - Function: void xth_sleep (int N, int L)
     It is expected to atomically unlock lock L and sleep in queue N.
     At least `MAXCONDS' queues must be available.  After it is waked
     up, lock L again. This mechanizm is used by calcualtion of new
     image algorithm, but it is designed to minimize its calls, so I
     expect they should be called once or twice.

 - Function: void xth_wakeup (int N)
     Wake up some thread from queue N. Lock used by sleep calls is
     locked in this cases. Function should also wake up all threads if
     such operation is not supported by host API. With luck, this
     function should not be called at all. It should be called by new
     image caluclation routines in case queue is empty. This happends
     in case of 50 threads but happeds rarely at two or eight threads
     according to my tests.

 - Function: void xth_wakeall (int N)
     Similiar to wakeup but wake up all threads.


File: xaos.info,  Node: filters,  Next: algorithm,  Prev: xthreads,  Up: Hacker

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!


File: xaos.info,  Node: algorithm,  Next: timerlib,  Prev: filters,  Up: Hacker

Algorithm description
=====================

   The main idea behind XaoS is that it is not required to calculate the
whole image every frame. Most pixels are already calculated in the
previous frames. You usually don't have exactly the pixels you want,
but all within a range lower than a step between pixels are acceptable.
That is why the image flickers a bit and why points do not blink
randomly as in precalculated animations.

   This document describes some of the most important algorithms in XaoS
   * Saving Previous Pixels

   * Approximation Algorithm

   * Moving Pixels to New Positions

   * Calculating New Pixels

   * Symmetry

   * Calculation of Mandelbrot Set

   * Dynamic Resolution

   * Autopilot

Saving Previous Pixels
----------------------

   Ideally, all precalculated points should be saved and used for
building successive frames. I could not figure out a practical way to
implement this. To save all frames for half an hour would require 24 Mb
of memory, and searching the saved frames would be more computationally
expensive than recalculating an entirely new frame.

   One way was later used by program Frang. It remembers all pixels as
x,y and value fields and when it builds new image, it draws all pixels
to it and then browses image and fills it by new pixels. Possibly some
rle cache should be used for calculated pixels. Frang actually uses
algorithm, that takes away pixels out of screen, so it behaves exactly
in same way as algorihm described here. At the other hand, this method
seems to require much more memory than XaoS algorithm and drawing
pixels/browsing image cost quite a lot, so algorithm descibed here
seems to be faster. Since it never requires examining of whole image
and new image is constructed using block move operations.

   For this reason only the last generated frame is used as reference.
This way the memory requirements are proportional to xsize * ysize. It
can be shown that this method is only about 2-5% slower during zooming.
Of course unzooming back to once browsed areas is much slower.

   Because only the previous frame is used, another optimization can be
performed: Imaginary and real parts of the calculated image are not
precise since they are the result of successive iterations of same
algorithm. In order to prevent errors from being distributed to the
following frames their exact coordinates need to be known.
Fortunately, it isn't neccassary to save their values since it is known
that all real components in a row and all imaginary components in a
column are equal. Thus, the only things that must be saved are the real
components for every row and the imaginary components for every column.

   This allows for a substantial speed-up in approximation because the
calculation requires less data. Of course, some rows and columns fall
out of the threshold and new ones need to be calculate to fill in the
gaps in the frame.

   Obviously, much less work is done. There are only xsize + ysize
calculations instead of xsize * ysize. So the main loop in XaoS looks
like this:
   * Make approximations for rows

   * Make approximations for columns

   * Move old pixels to their new positions

   * Calculate pixels for which there is no good approximation for
      their row

   * Calculate pixels for which ther is not good approcimation for
      their column but there is one for their row

Approximation Algorithm
-----------------------

Introduction to problem
-----------------------

   You can see that the approximation algorithm is central to the
implementation of XaoS. If the guess is incorrect the image will look
strange, boundaries will not be smooth and the zoom will flicker. On
the other hand, if it adds more new rows or columns than required,
zooming will become much slower. Also, in the instance of doubling
(i.e., using an old row or column more than once) the resolution will
lower. It is important to keep the increasing imaginary and real
components in the correct order. If a row and column of complex
coordinates follows one with higher coordinate values an improved
approximation can be attained by swapping their values.

   The algorithm needs to be relatively fast. It is only used for xsize
+ ysize values but if its speed is proportional to O(n^2), it can be
slower than a whole recalculation of the image. Speeds of O(n) or O(n *
log(n)) are acceptable.

Some simple algorithms to solve it
----------------------------------

   Initially, a very simple algorithm was used:

   Find the old row/column nearest the row/column that needs to be
regenerated. If the difference between them is less than one step
(step = (end - beginning) / resolution) then use it. Otherwise,
recalculate a new one.

   Finding the nearest row/column pair is very simple since it is always
greater or equal to the pair needing to be generated.

   Surprisingly, this simple algorithm has almost all the problems
described above. Doubling was fixed by lowering the limit to step / 2.
This cause a considerable slowdown so the limit was returned to step.
Instead, the algorithm was changed to search for only row/column pairs
that are greater than the previous frame's row/column pairs. This is
the algorithm that was used in version 1.0

   This algorithm still added to many new rows and columns and did not
generate smooth boundaries. For version 1.1 a heuristic was added that
preferred approximating rows/columns with lower values. This way it did
not occupy possible rows/columns for the next approximation. The result
was a speedup by a magnitude of four. In versions 1.1 to 2.0 many
improvements were made to the heuristic to give it added performance.
The following example tries to explain how complicated the problem is
(O is the old coordinates and X is the values to be approximated):
             X1        X2        X3        X4        X5        X6        X7
     O1 O2                    O3 O4 O5                   O6 O7 O8

   The normal algorithm will aproximate X1 by O2, X3 by O4 but nothing
more. For the algorithm with threshold step instead of step / 2:

       O2 to X1
       O3 to X2
       O4 to X3
       O5 to X4
       O6 to X5
       O8 to X6

   But this will fail with X7. The second algorithm which relies on
lower values will do the following:

       O1 to X1
       O3 to X2
       O4 to X3
       O5 to X4
       O6 to X5
       O7 to X6
       O8 to X7

   O1 to X1 is wrong. And there is many and many other situations that
may occur. But you may see that the normal algorithm will calculate 4
new rows/columns but the heuristic saves all of these calculations.

Current algorithms used
-----------------------

   In version 2.1 work on this heuristic was disabled after I discovered
a suprisingly simple algorithm that solves all these problems. First I
decided to define exactly what is best aproximation. This should be
done by defining a price for every aproximation and choose the
aproximation with the lowest price. Prices are defined as such:

   Aproximating row/column x by y costs dist(x, y) ^ 2.

   This prefers two smaller approximation errors before a single larger
error and describes my goal quite well.

   The cost for adding a new row/column specifies when it is better to
do a bad approximation and when to add a new row/column. I use (4 *
step) * (4 * step). This means that the approximation is acceptable when
dist(x, y) < 4 * step. Otherwise, adding a new row/column costs less.
Now the best approximation is known. All that is required is a fast
algorithm to do this. Surprisingly, this is possible in linear time
using a relatively simple dynamic algorithm. It uses approximations of
length < n to make a guess at the length of n. It can start by
approximating one row/column and then again for two, three up to
xsize/ysize rows/columns.

   The algorithm starts by calculating prices for all possible new
positions for old row/column 1. Because of the pricing there are
maximally 8 new positions. (Other ones must cost more than adding new
row/column). Of course it is possible that there are no new positions.

   For calculating the price of aproximations for row/column 2 I may use
previous one: Try new position n. Calculate the price and add the best
aproximation for the previous (row/column 1) one that uses a new
position lower than n(prohibits doubling or swapping). This shoud be
one of 8 positions or eventually adding of new one and not using
row/column 1 at all.

   The same method can be used for the rest of the rows/columns. At the
end the best price may be found for the last row/column and return by
the way it was calculated. (For this I need the saved "calculated
using" values.) At this step the best approximation has been determined.

   To fill the table, 9 * n steps are required and n steps to backtrack
best aproximation. The only problem is that this algorithm is still a
little slow (chiefly because of slow memory access on Intel
architectures). -But with some optimizing it works well.

   This algorithm is almost perfect except that it occaisonally adds new
rows/columns to the wrong locations. It does not prefer to add new
rows/columns into holes. But it does not seem that this is the real
problem. The last optimization made was based upon the face that added
rows/columns do not have the exact real and imaginary components
calculated by (beginning + x * step) but lies at the average of left
and right neighbours. This makes the boundaries smooth and distributes
coordinates better. It also has the added benefit of making the input
better for future approximations.

   Another danger during implementation if this algorithm is that
adding new rows/columns into their idead possitions should cause
missordered results, since some rows/columns should be off more that is
distance between them.  To avoid this, I use algorithm that always
examine start and end of block of new rows/columns and linearly
interpolates value between them. Special care needs to be at the blocks
that start at the begining or overs at the end.

   Implementation should be much faster using custom fixedpoint
routines -- first recalculate values that 0 means start of image and
65536 means end.  Than calculation is much cleaner. Values <0 and
>65536 are of screen, calculation is independent at scale and many
thinks should be precalculated -- like tables for calculating price
from distance.  Also dividing main loops into many specialized parts
and avoiding filing unnecesay parts of table helps. So current
algorithm in XaoS is about 5 or 6 times faster than first naive
implementation.

Moving Pixels to New Positions
------------------------------

   Since XaoS is using the approximation algorithm the following table
is filled for every row/column:
   * calculate

   * oldpoint

   * position     calculate is 1 if the current row/column is new and
needs to be calculated or 0 if no old pixels need to be moved. oldpoint
is a pointer to the old row/column that corresponds to the new one. This
pixel needs to be copied to the new location. position is the real and
imaginary components of the coordinates used for future approximations.
Because almost all points will be moved, the solution seems to be
simple: for every new point look at the row and column table; copy it
if required.

   There is the problem that this minimally needs three memory reads for
every pixel (read calculate, oldpoint and index of old point). This is
too slow, so a small optimization is performed. Instead rewriting the
piece of code in assembly, normal memcpy is used to move blocks of
pixels to their new locations. This minimizes the internal loop and
access can be done more quickly since memcpy is usually optimized for
each architecture.

   Using the row table, a list of blocks to move for every row is
created. With this new table all the pixels can be moved quickly. This
increased the speed of XaoS about four times and made this function so
fast that it is no longer a problem. (In fact, it takes much less
processing than all other parts of XaoS.)

Calculating New Pixels
----------------------

   The above optimizations make XaoS very fast, but another 30% increase
in speed is aquired by using a clever method for calculating the new
pixels. Many methods are known for saving calculations during the
generation of fractal images. The most powerful is boundary detection.
It relies on the fact that the Mandelbrot Set is connected with lakes.
You need only one pixel at the boundary, then traverse the whole set
and then fill the solid area inside. This method saves many
calculations but is too complex for adding just one line. Many claim
that it does not introduce any errors, but this is not true. It is
possible for a connected part of the lake to be so small that it is not
visible in smaller resolutions. In this case, boundary detection misses
the whole area. This algorithm is acutually used just for calculating
of new images (i.e. at the startup).

   XaoS uses modification of method known as solid guessing. The pixels
at the boundaries of a rectangle are calculated. If they are all the
same you may assume that this rectangle does not does not contain
anything and fill it.

   This algorithm is further modified to operate on added lines. For
this it is at least as good as boundary detection and produces more
tangible errors. When adding a single line, the upper and lower line
may be examined for the nearest three pixels. If they are all the same
then it is assumed that 9x9 pixels are the same. This disables all
calculations inside solid areas and calculates as many points as
boundary detection. The only possibility of creating a larger error
with this method as opposed to boundary detection is in the instance
that the shape of the set is so sharp that it does not set any of the
tested points but comes from the right (i.e., uncalculated) location.
This situation is not very common.

   Later, rules were added for new rows and columns that crossed each
other. In this instance you can test only four pixels. This situation
is very rare. It is hoped that it does not introduce many errors.

   If multiple blocks of new lines need to be calculated there are not
reference pixels to use for solid guessing. Interlacing does the trick.
By calculating the odd lines without any guessing, the guessing
algorithm is now possible for the remaining uncalculated lines. This
simple trick saves about 30% of the calculation of the main Mandelbrot
image.

   A similar approximation can also be done for the X coordinate. This
makes it possible to improve solid guessing at even pixels because all
surrounding pixels are available, further reducing errors.

Symmetry
--------

   Many fractals are horizontally or vertically symmetrical. This is
implemented in the approximation code. When there is no good
approximation available, try to mirror the opposite side if the line is
available.

   This method primarily speeds up the initial image.

Calculation of the Mandelbrot Set
---------------------------------

   Internal Mandelbrot caluclation loop is unrolled -- it calculates
first 8 iterations using normal method and then it expects that number
of iterations will be probably large so it switches into mode, where it
calcualtes iteratins in block of 8 with one bailout test at the end.
When bailout is received, saved values from previous iterations is
restored and last 8 iterations are recalcualted slowly to get exact
values. This leps a lot especially at pentium, where conditionals in
floating point code is slow.

   Another stuff is periodicity checking. XaoS has both version of
loops -- with ans without periodicity checks. In most cases it uses
nonperiodicity checking version. Periodicity check version is used just
in case, some inside set pixel has beed found during solid guessing
paste around. This is done mainly because periodicity checking verson
of loop is significnatly slower.

Dynamic Resolution
------------------

   The above optimizations often do not help enough and image
calculation is still too slow. One option was to reduce the framerate,
but a framerate lower than 5 frames per second is unbearable. Another
option is simply to calculate only the details that can be determined
within a time interval.

   Rows/columns not calculated are simple approximated by referencing
the nearest other row/column. The result is an image with larger pixels.
One problem is the fact that the order of calculating the rows/columns
is significant. Previous versions of XaoS simply calculated all rows
from top to bottom and then columns from left to right. Using the
dynamic resolution code with this algorithm would result in distorted
images. This was solved by adding priority to every row/column and
calculating the high priority row/column first. The algorithm for
adding these priorities is as follows:
   * Find middle row/column of uncalculated block. Priority is the size
        of the block (in floating point coordinates)

   * Start function for left block and right block

   This function produces quite good results. It tends to make same size
rectangles on the whole image and does not depend on resolution.

   Another interesting optimization is that during the zoom it is more
advantageous to calculate rows/columns in the center of the zoom
instead of the borders since these will be in the viewport longer and
the user is usually focusing on center of the zoom anyhow.

   This is done by simply adding to the calculated priority
normal_priority / (abs(newposition - oldposition) / step + 1). This
prefers rows/columns that do not move a great deal. Of course,
unzooming uses the formula reversed.

   The last variable to consider is the time interval for one frame.
Setting it too low makes the calculation slow. Setting it too high
makes the framerate too low. So the amount of time spent in other parts
of the program is calculated and multiplied by 5 to determine the
interval. If time is then lower than 15FPS, 15FPS is used instead,
since slower animations are unacceptable. At the other hand if it is
higher than 35FPS, it is set to 35FPS, since higher framerate is just
wasting of computer resources. When image is not animating, this values
is changed, so framerate is choosed between 5FPS and 15FPS. This caused
that images are calcualted quickly after zooms stops.

Autopilot
---------

   Another interesting algorithm controls the autopilot. It is actually
quite simple. Interesting parts are found at the boundaries of the set.
It randomly looks around and zooms to the first area containing both
outside and inside set points. Some fractals (such as the Newton) do
not have points inside the set at all. In this case it selects a point
where many (more than 2) different colors are around. (i.e., It zooms
into noisy areas.)

   In the instance that there are no such areas, the autopilot will
unzoom. Also detects oscilating.

   Current implementation also does detection of out of range numbers
and randomly choosed points are choosed near the old one, to avoid too
often changes of direction.

SMP support
-----------

   Since version 3.0 XaoS suports SMP. This is done using threads. Most
of XaoS routines should be threaded easily -- for example moveoldpoints
just divides image into n equal part and each part is proceded by one
processor.  Only unthreaded part is realloc table calculation routines.
I don't see any way to paraelize it except it calculates both - x and y
approximation at one time (using two processors).  Another interesting
algorithm to paraelize is boundary trace. See comments `btrace.c' for
discusion about current implementation.  Only problem of current
implementation I see is possibility, that calculation is divided into
too many parts (realloc tables, move points, calcualte, symetries,
dynamic resolution) and tasks needs to synchronize between each part.
So this should be too slow at real SMP box.


File: xaos.info,  Node: timerlib,  Prev: algorithm,  Up: Hacker

The timer library
=================

   Timer library is library I did for timming in XaoS. But I found it
usefull in many other programs (like demonstrations, games, animation
players and all other stuff that needs to be timed). So you should read
this description and possibly use it in your application and save some
coding time.

   There is many ways how to design of such timed aplicatioin (game)

  1. read user input, move badies, display and again this way has one
     disadvantage. Speed of game depends on speed of computer.  This
     was acceptable in old times where only processor was Z80 :) but now
     with wide variety of various hardwares such internal loop is
     unacceptable

  2. read user input, measure time since last loop and caluclate step
     for badies, move badies for set step, display and again.  This way
     fixes problem with speed. But moving badies just for caluclated
     step, that should differ a much is quite complex, usually
     introduces complex calculation, floating/fixedpoint math and other
     unnecesarry stuff that makes program long and introduces many bugs.

  3. Set the fixed framerate that is high enought to make game smooth
     but low enought to do whole internal loop in time. So internal
     loop should look like: read user input, move badies, display,
     meausre time spent in loop an sleep rest of time until next frame.
     This is quite popular scheme but has another disadvantage -- game
     can not be designed to use whole cpu power since on slower
     computers internal loop should take longer time that is reserved
     for one frame. Game will run slowly again.

  4. To take away disadvantage of previous methot, many games times just
     moving of badies and user input. Other stuff like displaying
     should be done in rest of time. In dos games moving and user input
     is often at asynchronous interrupt and drawing runs as main loop.
     This solves problem in case that drawing of game takes
     significantly longer time than moving of badies. This is quite
     usual so this scheme works well.

  5. previous scheme still has one problem -- since timer interrupt
     works asynchronously, there should happend many race condition, in
     case moving takes longer time than time reserved from frame,
     computer can crash. So this scheme should be enhanced into
     synchronous one with exactly same result but avoiding problem with
     race condition:

     read user input, measure time spent by loop and caluclate how many
     simulated frame interrupts activated since last activation, if
     zero sleep until simulated interrupt, move badies as many times as
     required, display

     this is an combination of 4 and 3 and seems to be most confortable
     way for writing games but since main loop is now quite complex
     many games don't do that.

  6. there is still one small problem. Method 5 expect that moving takes
     significantly lower time that displaying. This may not be truth.
     Simple work around is to write moving routine, that should move
     for x moves by faster way that calling move x times. This is often
     possible and makes easy extension to scheme 5. This scheme allows
     you to use very large maximal framerate (say 100FPS) and to have
     same results as method 2 (that is maximally exact method)

   As you can see, designing of main loop isn't so easy. This is just
very simple example. More advanced aplication for example should want
to move one set of badies at one framerate and other at different
framerate. This requires two such timmings. Another complication is
that there is many different ways to measure time exactly at different
platforms. Under linux you can measure using gettimeofday but under DOS
this is exact just to 1/18 of second and thats too low for smooth
animation and so on.

   Thats why I decided to design portable easy to use timer library,
that makes easy to implement all described method, combining of them
and much more.  During design I taken care at the following thinks:
quality of timming, how easy to use it is, speed, portability and to
minimalize inexpected situations (like race conditions in asynchronous
interrupts and so on)

What is what
------------

   Timer library operates with "timers". They should be created, you
should measuere time since last reset, pause them or set "handler" and
"interval".  But handler is not activat at gived interval yet. Since
timer library is not asynchronous, you must activate them.

   For activating is used "groups". You should provess group at some
place in your program. Then all timers in group are checked and their
handlers activated if required. When time spent since last activation
is higher than interval, handler is activated more times. Also interval
to next invocation is calculated to keep freqency.  Simple scheduling
is performed at handler -- handler is activated just once and then all
other timers are checked before it is activated again. You should also
define an multihandler -- handler that is activated just once and
receives argument how many intervals has left.

   There is two special groups -- `asyncgroup'. Timers in this group
are activated asynchornously like from interrupt. It is not recomended
to use it, since it brings many problems and usually isn't required.
Also it does not work at many platforms. `Syncgroup' is the default
group. Program is expected to process is quite often. In case you don't
need to use more groups, you should use this one.

   Time in timerlib is bit strange, since it does not flow continuously
but jumps. It is updated every time you call `tl_updatetime'. I used
this way in order to minimize context switches but later I found this
scheme very usefull, since you should lookup timer, do something and
then reset it and don't wory about time spend between lookup and reset
since it is 0 in case you did not called tl_updatetime. This helps to
keep freqency of timers exact w/o any errors caused by such situations.
At the other hand you need to call tl_updatetime at least once in your
main loop.

   Maybe you don't know why to create more groups, but I found it quite
usefull.  For example an autopilot in XaoS has such special group -- I
need to call it approx. every 1/20 of second but just at one place in
program. Invoking of autopilot when caluclation is active should
produce incorrect results, so I have special group for autopilot and
process just at one place where I am sure it is safe.

   Timers should be also emulated. You should stop them and then
control flow of time for given timer. This should be quite usefull for
example when you want precalculate animation at given framerate.

Time functions
--------------

 - Function: void tl_update_time (void)
     Update time used by timerlib. This must be called at least once in
     main loop otherwise time will not flow. See above.

 - Function: void tl_sleep (int TIME)
     Sleep given time. Similiar to usleep at POSIX.

Group functions
---------------

 - Function: tl_group *tl_create_group (void)
     Allocate and initialize group header. Returns NULL when malloc
     fails.

 - Function: void tl_free_group (tl_group *GROUP)
     Free memory storage used by group structure

 - Function: int tl_process_group (tl_group *GROUP, int *ACTIVATED)
     Process timers in group and activates their handlers. Returns time
     until next invocation. Main loop should sleep returned time then.
     An ACTIVATED parameter sould be `NULL'. If it is non `NULL',
     variable is set to number of activated handlers.

Timer functions
---------------

 - Function: tl_timer *tl_create_timer (void)
     Create timer structure.

 - Function: void tl_free_timer (tl_timer *TIMER)
     Free memory storage used by timer structure

 - Function: void tl_reset_timer (tl_timer *TIMER);
     Reset timer to current time. (time of last actication of
     `tl_update_time')

 - Function: int tl_lookup_timer (tl_timer *TIMER);
     Return time since last call of tl_reset_timer or last activation
     of handler.

 - Function: void tl_set_interval (tl_timer *TIMER, int INTERVAL);

 - Function: void tl_set_handler (tl_timer *TIMER, void (*HANDLER)
          (void *),void *userdata);

 - Function: void tl_set_multihandler (tl_timer *TIMER, void (*HANDLER)
          (void *,int),void *userdata);
     Handler, multihandler and interval control functions

 - Function: void tl_add_timer (tl_group *GROUP, tl_timer *TIMER)
     Add timer to given group. Timer should be added into just one
     group.

 - Function: void tl_stop_timer (tl_timer *TIMER)

 - Function: void tl_resume_timer (tl_timer *TIMER)
     Stop and resume timer.

 - Function: void tl_slowdown_timer (tl_timer *TIMER,int TIME)
     Time in timer is moved back for given time.

Example main loop
-----------------

     while(1)
     {
       time=tl_process_group(syncgroup,activated); /*Call game control functions*/
       update_keys();
       if(activated) /*something changed*/
         display();
       else tl_sleep(time);
     }



Tag Table:
Node: Top433
Node: Overview779
Node: Why?1003
Node: What?3115
Node: History3682
Node: User3843
Node: format4174
Node: Hacker19990
Node: driver20479
Node: xthreads37657
Node: filters42710
Node: algorithm59394
Node: timerlib79395

End Tag Table
