Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/doc/xaosdev.info
diff options
context:
space:
mode:
Diffstat (limited to 'doc/xaosdev.info')
-rw-r--r--doc/xaosdev.info2862
1 files changed, 2862 insertions, 0 deletions
diff --git a/doc/xaosdev.info b/doc/xaosdev.info
new file mode 100644
index 0000000..57b5d82
--- /dev/null
+++ b/doc/xaosdev.info
@@ -0,0 +1,2862 @@
+This is Info file xaosdev.info, produced by Makeinfo version 1.68 from
+the input file xaosdev.texinfo.
+
+INFO-DIR-SECTION Graphics
+START-INFO-DIR-ENTRY
+* XaoS: (xaosdev). The fast real-time interactive fractal zoomer
+ (developers documentation
+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: xaosdev.info, Node: Top, Prev: (dir), Up: (dir)
+
+XaoS 3.1
+********
+
+ An real-time interactive fractal zoomer
+ Hacker's guide
+ May 14, 1998
+
+ This manual contains documentation for those who are interested in
+studying and improving XaoS sources or using them in other programs.
+It includes description of algorithm and documentation of those parts
+of XaoS I think they should be useful for someone.
+
+* Menu:
+
+* design:: Overview of the XaoS design
+* driver:: Driver API description
+* gui-driver:: Writing user interface driver
+* eui:: Writing an external user interface
+* ui-helper:: UI helper library
+* xthreads:: XaoS thread library
+* filters:: Filters
+* algorithm:: Algorithm description
+* timerlib:: The timer library
+* registry:: XaoS function registry
+* index:: Function command and variable index
+
+
+File: xaosdev.info, Node: design, Next: driver, Prev: Top, Up: Top
+
+Overview of the XaoS design
+***************************
+
+ Whole sources of XaoS are designed into several "libraries" (some of
+them are not really libraries, but added into other's, but should be
+separated easily).
+
+ Understanding to the main philosophy should help you to navigate in
+the sources. I also expect that many of the lower level stuff should
+be useful in the other projects, since it is designed to be fairly
+generic.
+
+ So here is an overview from the lowest level stuff to the highest.
+
+Palette and image library
+=========================
+
+ Sources are in directory `src/filter'. The aim of palette library is
+to provide relatively abstract interface to the various visuals and
+hide differences in the hardware and driver implementation. Fixedcolor,
+pseudocolor, grayscale and truecolor visuals should be handled in the
+almost same way.
+
+ It provides the structure `palette', which contains actual palette.
+You might allocate new colors here (you give RGB value and
+corresponding pixel is returned), interpolate colors where possible,
+cycle colors and so on. Every palette also consist from the two
+parts--the preallocated color cells and the actual palette. This lets
+for example to GUI possibility to allocate statically colors for its
+texts and dialogs, while rest of palette is under control of different
+parts of XaoS.
+
+ This library also contain set of functions to allocate different
+palettes used by other parts. I expected that different parts of XaoS
+should use same palette. Nothing similar happened yet, but functions
+are kept here.
+
+ The image library is built at the top of palette library. It extends
+functionality for handling actual image data. Each image is represented
+by one or two frame-buffers (it is useful for double-buffering). One
+frame-buffer is called current and other old. They should be flipped by
+special function. Program can draw into both of them.
+
+ Frame-buffers are hold as the set of pointers to the scan-lines.
+This brings better flexibility, because tricks like sub-windows, or
+flipped bitmaps are possible. Also speeds up, since you should avoid
+one multiplication.
+
+ The last significant information image structure hold is of course
+bpp depth. It is counted in bytes, and should be 0-4. Where 0 is used
+for 1bit bitmaps.
+
+Filter library
+==============
+
+ Source are available in `src/filter'. This library controls the
+process of creation of the image. It handles an queue of the filters,
+where each filter should modify the image. There are two special filter
+at the beginning and end of queue. The first filter is usually the
+actual fractal engine which creates image, while the terminal filter is
+usually user interface helper library.
+
+Xthread library
+===============
+
+ This library provides interface to various multi-threading libraries
+(currently the BeOS, plan9 and POSIX implementations are available). It
+allows to run various function paraelly and some synchronization
+primitives (semaphores). It is simple, but has all the functionality
+required for the XaoS engine.
+
+Fractal library
+===============
+
+ Source are available in `src/engine/', headers in `fractal.h'. This
+library contains the actual fractal calculation routines. It operates
+with fractal context, which contains informations like current formula,
+seed for julia, palette etc.
+
+ Functions for calculating the various fractal types and various
+coloring modes are available here.
+
+Zooming engine and other filters.
+=================================
+
+ Source are available in `src/engine/'. This is the actual zooming
+engine filter. It is done in fairly independent way at fractal library,
+so it should be possibly used for zooming other stuff. (it was already
+used for zooming large scale images containing maps of Hungary).
+
+ All other filter has their special file, where is implementation and
+structure containing all functions exported from the filter to user
+interface. They are registered in the file `ui_helper'. One other
+terminal filter is implemented--Julia morpher. Other filters adds
+special effects (such as motion blur), or does conversions (such as
+rotation, dithering etc.)
+
+Timer library
+=============
+
+ This library provides many of very useful timing primitives. Such as
+timers, etc. Currently it is used by some other programs too.
+
+xio library
+===========
+
+ This library aims to provide united interface to file-system. Some
+strange systems (such as MacOS) has file-system API done in much
+different way than in UNIX. They don't have names in string, and uses
+special structures etc.
+
+xshl library
+============
+
+ Xshl stands for XaoS simple hypertext library. It contains fairly
+universal engine parsing an xshl language. It is similar to HTML with
+some additions and many restrictions. It should render this texts for
+the proportional/non-proportional fonts and various sizes.
+
+help library
+============
+
+ it is built at the top of xshl and xio libraries. It should read
+help files, wick contains an chapters. Parse chapter with given keyword
+etc.
+
+xmenu library
+=============
+
+ This is the XaoS function registry. All functions from UI-Helper
+library are registered in the registry. From this registry the menus,
+dialogs, command line options and scripting language are built.
+
+Catalog library
+===============
+
+ This is library for handling an message catalogs. It should read
+catalog and convert the keyword into actual message.
+
+PNG library
+===========
+
+ This library provides the function for saving an image from Image
+library to the file (in PNG format). Other formats should be added as
+well if required.
+
+UI-helper library
+=================
+
+ This library controls all the low-level stuff and provides an high
+level interface to it. It has functions for playing animations,
+zooming/UN-zooming and such. It heavily uses all the described
+libraries. It don't implement functions for handling menus and such,
+but makes great help for such implementations, because of the function
+registry database.
+
+Ugly interface
+==============
+
+ This is currently the only real user interface for XaoS (there is
+also an second, wich is used for rendering animations, but it is not
+user interface, how users expect it). It is built at the top of
+UI-helper library and provides functions for drawing menus, dialogs and
+such. It has drivers for many platforms, and it should be easily
+ported to the others.
+
+ In the future, it should be quite easily to extended to let drivers
+specify their own menu/dialog handling code, so it should be possible
+to give it an "native" look of given platform.
+
+ It has also an function, where an GUI drawing routines are disabled.
+Function registry database is transfered trough pipe to external
+program, wick should build the menus and act as external user
+interface. It then back sends an commands in the scripting language
+representing things, that user done. So it is an another way, how to
+give native look to ugly interface.
+
+ Ugly interface has also one serious limitation--for the historical
+reasons it is coded to handle just one window (rest of XaoS probably
+can do multiple windows--untested). So in windowed environments it is
+impossible to open multiple menus with fractals. At the other hand,
+this limitation is not so important, once external GUI enter the role.
+They should just start multiple XaoS engines. This will bring extra
+robustness, multitasking and some other advantages, so it is the
+proffered way. Thats why I don't plan to remove this limitation yet.
+
+
+File: xaosdev.info, Node: driver, Next: gui-driver, Prev: design, Up: Top
+
+Driver API description
+**********************
+
+ To port successfully 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...), has serious problems. They
+ generate incorrect code or crash during compilation. I highly
+ recommend to use GNU C compiler. Even some versions of GNU C has
+ problems. Please read `compilers.txt' for more information.
+
+ * Fast way to avoid division by zero/overflow and other floating
+ point exception. XaoS is carefully 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 platforms provide way to switch
+ coprocessor into mode, where 1/0 is evaluated into Inf etc. If
+ there is no such way, try to use some kind of signal handler that
+ will ignore such exceptions.
+
+ The "normal" solution--add ifs to avoid division by zero is almost
+ impossible. The division is quite easy to check. But other
+ cases--overflows are much worse. So I don't think it is possible
+ to avoid all crashes just by adding ifs.
+
+ XaoS don't depend at IEEE arithmetic. Result in such cases should
+ me mostly undefined. XaoS usually works well with compiler's
+ switches for inexact math enabled (such as `-ffast-math' in GNU).
+ But no guarantees. For example at Alphas this is not true--since
+ they usually generates exceptions then. Also `-mno-ieee-fp' at
+ Intel don't work. This is due to gcc bug. Gcc in some cases reverse
+ the condition when this switch is enabled. I've made patch to fix this
+ problem and hope that it will get to egcs or gcc soon.
+
+ * Text or graphics output device. If you have only text output
+ device, you may use AA driver, which renders fractals into high
+ quality ASCII art. In this case you might skip this chapter,
+ download AA-lib (http://www.ta.jcu.cz/aa) and read porting chapter
+ of AAlib manual. Graphics device must one of:
+
+ * 8bits per pixel with user definable palette `C256', static
+ palette `FIXEDCOLOR', or static grayscale `GRAYSCALE'
+
+ * 16bits per pixel with arbitrary bits per each color
+ `TRUECOLOR'
+
+ * 24bits per pixel with 8 bits per each color, arbitrary order
+ `TRUECOLOR24'
+
+ * 32bits per pixel with arbitrary order of colors, where each
+ colors fit to exactly one byte `TRUECOLOR'
+
+ * 1bits per pixel bitmap with both orders (Least or Most
+ significant bit first)
+
+ Please contact me if you have different kind of device. Some modes
+ (like miss-ordered truecolor modes) should be added really easily
+ if required. Note that mono/4/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
+ converter. (For bitmap there already exists--see `dither.c'.
+
+ * Some way to save images. By default XaoS uses `pnglib', which is
+ ported to many platforms, but there is still many others. If your
+ system has some standard image format, which is easier to handle
+ than `.png', contact me and I will show you, how to add such
+ support to XaoS (see `png.c').
+
+ * Stdio compatible library (this is problem at Mac or BeOS). XaoS
+ has the abstract layer at the top of stdio, so it should use other
+ input/output libraries too. You might write just another
+ implementation if it's library called `xio'. See `xio.h'.
+
+ 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 (*mousetype) (int type); /*Change mouse cursor*/
+ void (*flush) (void); /*Flush current state to screen*/
+ int textwidth; /*width of text*/
+ int textheight; /*height of text*/
+ struct params *params; /*command line parameters*/
+ int flags;
+ float width,height;
+ int maxwidth,maxheight;
+ int imagetype;
+ int palettestart,paletteend,maxentries;
+ int rmask, gmask, bmask;
+ struct gui_driver gui_driver;
+ };
+
+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 came. This is useful on multi-tasked os
+ where xaos does not eats unnecesaru CPU.
+
+ *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. For special keys use
+ `UIKEY_UP', `UIKEY_DOWN', etc. See `ui.h' for complete lists
+ of this constants.
+
+ 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 position x/y. This function is a bit
+ archaistic (XaoS now uses in the most cases its own functions
+ drawing directly to the buffer), but in some
+ cases--initialization messages or calculation, functions are
+ unusable, so we still need this primitive. In the `C256' mode
+ you might rely, that first allocated color is always black and
+ second is white.
+
+ - 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 scan-line
+ size in bytes(usually width) and 0 if fail. This is useful 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: 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.
+
+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.
+
+RMASK, GMASK, BMASK
+ This fields are used in truecolor modes to specify, where each
+ color is defined
+
+MAXENTRIES;
+ Number of allocatable entries. Normally should be
+ PALETTESTART-PALETTEEND
+
+IMAGETYPE
+ defines type of image. Should be one of following values:
+ `UI_C256'
+ classical 256 color with palette scheme used by most older
+ graphics adapters. You should use it also for
+ static-color schemes but they are not supported well in
+ current version.
+
+ `UI_TRUECOLOR'
+ 32bpp truecolor mode
+
+ `UI_TRUECOLOR24'
+ 24bpp truecolor mode.
+
+ `UI_TRUECOLOR16'
+ 16bpp truecolor mode
+
+ 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.
+
+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 beginning
+
+MAXWIDTH,MAXHEIGHT
+ see FLAGS. May be set to 0,0 for the beginning
+
+FLAGS
+ This variable says more about your driver. You may start with
+ value 0. But for final version it is recommended to read
+ following chapter carefully.
+
+ Flags are uppercase constants and should be set by following way:
+
+ `ASYNC_PALETTE | RANDOM_PALETTE_SIZE'
+
+ 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 applications 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 allays same
+ number of colors is available.
+
+ `UPDATE_AFTER_RESIZE'
+ recalculate and redraw screen even if its size is not changed.
+ In case that resize procedure destroys data in buffers
+
+ `RESIZE_COMMAND'
+ Some drivers (mainly the fullscreen ones) may in the function
+ `get_size' ask user for the size and color depth. It
+ should be nice to let user change this parameter at
+ runtime. I.E force XaoS to reinitialize his images. This is
+ done by `ui_resize' call. This call in windowed drivers
+ is called by the external event. But in fullscreen
+ drivers you need key/menu item for this. You might add
+ this function directly into XaoS's function registry (see
+ for example the GGI driver)--it is usefull mainly when you
+ want to make some size selection dialog in the standard
+ way, or let XaoS add his default one. And this is done by
+ this flag. See for example SVGAlib or DOG driver.
+ Screen/window size informations:
+
+ Xaos needs to know exact size of displayed images. This is required
+ for random dot stereo-grams 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 prefer 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 environments
+ 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.
+
+GUI_DRIVER
+ See next section for description.
+
+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 platform.
+
+ Please let me know if you want to start code some driver.
+
+
+File: xaosdev.info, Node: gui-driver, Next: eui, Prev: driver, Up: Top
+
+Writting GUI driver
+*******************
+
+ XaoS have builtin GUI. Many operating systems have native gui
+toolkits and XaoS default GUI might look strange there. To avoid this
+problem, you might write external gui program (see eui section) or
+write mappings of XaoS GUI functions. The advantage of external gui
+process in multitasking. XaoS is not thread safe and GUI must be
+synchronous with calculation. Also ugly interface code currently don't
+support multiple windows (this should be solved in future). This
+solution is suitable mainly for those systems, where cooperation of two
+programs sharing one window should be problem (like on Windows).
+
+ To write gui driver you need to fill following structure:
+ struct gui_driver
+ {
+ void (*setrootmenu)(struct uih_context *c, char *name);
+ void (*enabledisable)(struct uih_context *c, char *name);
+ void (*menu)(struct uih_context *c, char *name);
+ void (*dialog)(struct uih_context *c, char *name);
+ void (*help)(struct uih_context *c, char *name);
+ };
+
+ All function have `uih_context' parameter. You don't need to worry
+about it's contents. Just pass it to the called functions that require
+it. This parameter is for multiple window support, that is not
+implemented yet.
+
+ The `setrootmenu' function expected to draw root menu according to
+the menu called `name'. To get menu fields you might use following
+piece of code:
+ #include <ui.h>
+ #include <xmenu.h>
+
+ ....
+
+ int i;
+ menuitem *item;
+ for (i = 0; (item = menu_item (name, i)) != NULL; i++)
+ {
+ if (item->type == MENU_SUBMENU) {
+ /* This field is submenu. You might call here
+ function to construct submenu. item->shortname contains
+ name for submenu */
+ }
+ /* add menu field here.
+
+ You might check flags here:
+ item->flags&MENUFLAG_CHECKBOX
+ field have beckbox
+ item->flags&MENUFLAG_RADIO
+ field is part of radio button group. In current implementation
+ there is one radio button group per menu.
+
+ in both cases you might call: menu_enabled(uih, item) to see
+ if item is checked or not.
+
+ item->name contains field's text
+
+ item->key contains hotkey (one letter string in current
+ implementation)
+ }
+ Once field is selected, call function `ui_menuactivate(item, NULL)'
+where `item' is pointer to `menuitem' record of selected field.
+
+ Function `enabledisable' is called when checkbox or radiobutton
+state is changed. The `name' parameter match to `item->shortname' of
+changed field. So you need to browse all created menus, compare
+`item->shortname' and in case it match, call `menu_enabled' to obtain
+new state. For radiobuttons only enable events are noticed. Your code
+is expected to automatically disable all other radiobuttons in the same
+submenu.
+
+ function `menu' works in similar way to `setrootmenu' but displays
+popup menu.
+
+ Function `dialog' is called for dialogs. The function should look
+like:
+ menuitem *item = menu_findcommand(name);
+ menudialog *dialog = menu_getdialog(uih, item);
+ int i;
+ for(i=0; dialog[i].question; i++)
+ {
+ /* Construct dialog, where left side contains labels with
+ dialog[i].question. Right side contains input entities based on the
+ dialog[i].type. Dialog[i].type is one of the following:
+
+ DIALOG_INT: integer value input. The default value is: dialog[i].defint
+ DIALOG_FLOAT: floating point input value (long double, where availble
+ exact). Default value is dialog: dialog[i].deffloat
+ DIALOG_COORD: complex value floating point input (two floats), default
+ values are dialog[i].deffloat and dialog[i].deffloat2
+ DIALOG_STRING: string input. default value is dialog[i].defstr
+ DIALOG_IFILE: input file
+ DIALOG_OFILE: output file
+ default mask is dialog[i].defstr
+ DIALOG_CHOICE: choice between various strings.
+ retype dialog[i].defstr to char ** to get pointer to NULL terminated
+ array of the choices.
+ }
+ Once dialog is filled by user, gui_driver is expected to allocate
+array of union `dialogparam' `dialogparam':
+ dialogparam *p = calloc (sizeof (*p), nitems);
+ fill selected values. `p[i].dint' is used to pass integer value, or
+number of DIALOG_CHOICE selection, `p[i].number' is used for floating
+point number, `p[i].dstring' for strings and filenames,
+`p[i].dcoord[0]' and `p[i].dcoord[1]' for complex values.
+
+ The string values are expected to be in separate malloced chunks.
+Once array is filled, call `ui_menuactivate(item, p)'.
+
+ The function `help' is used to display help about given topic. To
+implement it you might eighter convert XaoS help file to some native
+format, or use xshl library to render help page for you. To render xshl
+page use:
+ #include <xshl.h>
+ xshl_line *lines;
+ int getwidth (void *data, int flags, char *text)
+ {
+ return width of text with given flags
+ flags is mask of the following:
+ XSHL_BIG - large text
+ XSHL_EMPH - emphatized text
+ XSHL_MONOSPACE - monospaced text (typewriter)
+ XSHL_LINK - line (should be underlined or so)
+ XSHL_WHITE
+ XSHL_RED
+ XSHL_BLACK - color of text (not very meaningfull here)
+ XSHL_RIGHTALIGN
+ XSHL_CENTERALIGN - alignment of the text
+
+ }
+ lines = help_make (name, getwidth, textheight, largetextheight);
+ if (lines == NULL)
+ lines = help_make ("main", getwidth, textheight, largetextheight);
+ Now you might use `lines' to draw the help. It is pointer to the
+arraw of structures:
+ struct xshl_line {
+ int y;
+ struct xshl_item *first;
+ };
+ `y' is possition of the line from beggining of text and first is
+pointer to the blocks of texts on the line. Last line contains NULL
+pointer in the first section.
+
+ `first' is linked list of the structures:
+ struct xshl_item {
+ struct xshl_context c;
+ char *text;
+ int x;
+ int width;
+ struct xshl_item *next;
+ };
+
+ you might draw text `text' on the possition `x' (and `y' from the
+line record) using style described by `xshl_context':
+ struct xshl_context {
+ int flags;
+ char *linktext;
+ };
+ `flags' have same meaning as in `getwidth' section. `linktext' is
+name of the next help page in case field have XSHL_LINK atribute.
+
+ As an example of `gui_driver' see win32 driver code.
+
+
+File: xaosdev.info, Node: eui, Next: ui-helper, Prev: gui-driver, Up: Top
+
+Writting an external user interface
+***********************************
+
+ This part describes, how to make an external user interface--it is
+the separate program, which makes an window with all menus and dialogs.
+It uses XaoS engine for calculating the fractal as separate process.
+This design brings many advantages--the external GUI implementation
+should have an "native look" for given platform and should contain many
+extensions, such as multiple windows etc. Also all calculation are done
+in the multitasking and user interface is usable even when engine is
+busy.
+
+ The X window provides a way, when program draws into other's
+window--"master" program creates window and sub-window, where he wants
+to have fractal, then calls engine with `-windowid' NUMBER_OF_WINDOW
+parameters. It instead of creating new window uses specified window.
+Most famous example of such cooperation is probably
+ghostscript/ghostview.
+
+ Other windowed environments probably provides similar way for
+cooperation. At others it should be implemented using shared memory, so
+it should work at most platforms, I expect.
+
+ Of course, you might also design UI as separate button box in
+another window, like most of animation players, or Imagemagick have. In
+fact external GUI should be very similar to Imagemagick style.
+
+basic concept
+=============
+
+ The UI implementation has function to disable it's GUI functions.
+Because of the function registry, all it's menus and dialogs are
+described in the fairly simple database. This database is mapped also
+to the scripting language similar to scheme. So the external UI
+implementation just translate the actions into this scripting language
+and sends it trough pipe.
+
+ This commands should be created automatically from the database, as
+well as menus and dialogs, so UI don't need to have special code for
+various XaoS features. At the beginning it should use XaoS' command
+`(print_menus)' to force him to send information about database, then
+build menus using this information.
+
+ For this you need just some equivalent to UNIX pipes, so again I
+expect it is doable at most platforms.
+
+starting XaoS as slave process
+==============================
+
+ One of the first thinks, engine needs to do is to initialize XaoS in
+right mode to work as slave process. For this you need to do several
+thinks:
+
+ * Open the pipe
+
+ * Disable builtin GUI
+
+ * Read menu hierarchy (this is optional--GUI can also have all menus
+ coded into it. But it is not recommended, since it will make
+ problems with future adding new features)
+
+ Opening pipe is done via `-pipe' option. It takes one parameter,
+which is name of FIFO you want use. If you specify "`-'", XaoS will
+read input from stdin.
+
+ To disable XaoS GUI use option `-nogui'. This will disable all menus,
+dialogs and help text.
+
+ To read menu hiearchy just add `-print_menus' parameter and then
+parse XaoS's output. This will print the whole hierarchy. In case you
+are building menus at the time, they are selected, you might prefer
+usage of the command `print_menu'. It prints just one menu without it's
+sub-menus, so it's output should be directly used for building it. It
+takes one string parameter, which is name of menu you want to print. To
+print root menu use `"root"'. Option should look like this:
+`-print_menu root'.
+
+ Under X Window you need also specify the `-windowid'. Also the
+`-shared' is quite recommended. Otherwise in pseudocolor visuals XaoS
+will create it's own colormap, wich will most probably collide with
+UI's colormap and XaoS or UI will have false colors. If you have any
+idea, how to avoid this, let me know.
+
+ You might also let user to specify some extra parameters from the
+command line. You should simple add the to the end of command line. The
+`-nogui' and `-print_menus' commands must be first for the simple
+reason: XaoS parses it's command line in the early initialization
+stages. Some commands (like `-print_menus') should be processed at this
+time, while others (like `-loadpos' needs to have working engine. This
+commands are queued and processed later, once engine is initialized.
+In case some such command is before `-print_menus' XaoS will decide to
+keep same order of commands, so it will queue `-print_menus' too. This
+will case, that menus will be printed much later and startup will be
+slower.
+
+ So the proper calling sequence for the user interface under X should
+look like:
+
+ xaos -nogui -print_menus -windowid <id> -share -pipe - [OTHER OPTIONS]
+
+Parsing the menu structure
+==========================
+
+ The structure is printed menu by menu. Each menu contains an header,
+some entries and `endmenu'. Whole listing from `print_menus' is
+terminated by `endmenus'.
+
+ The header starts with `menu' and then contains an identifier of menu
+and full name. Such as:
+
+ menu "fractal" "Fractal"
+
+ Then each entry has its own line. It starts by type, which should be
+`submenu' or `menuentry'.
+
+ `submenu' has similar format to header--fullname of menu and
+identifier.
+
+ `menuentry' adds next few fields. It has an type of entry, which
+should be `normal', `radio' or `checkbox'. `radio' and `checkbox' are
+followed by `on' or `off' specifying whether it is enabled or disabled.
+The radio-buttons don't have explicit information about groups they
+belongs to. For now I just expect, that each menu contains just one
+such group, so it is clear.
+
+ Then set of flags should follow. Currently two flags are defined.
+`dialog', wich specifies, that function has dialog, and
+`dialogatdisable'. By default, dialog for check-boxed functions are
+displayed just in case they are enabled. The second flag reverses this
+behaviour. It is now used for `mandlebrot' function, which behaves in
+this style. When you disable it, user is prompted for the Julia seed.
+
+ So specification should look like this:
+
+ menu fractal "Fractal"
+ submenu "formulae" "mformula"
+ submenu "Incoloring mode" "mincoloring"
+ submenu "Outcoloring mode" "moutcoloring"
+ submenu "Plane" "mplane"
+ submenu "Palette" "palette"
+ menuentry "Mandelbrot mode" "uimandelbrot" checkbox off dialogatdisable dialog
+ menuentry "Perturbation" "uiperturbation" checkbox off dialog
+ menuentry "View" "uiview" normal dialog
+ menuentry "Reset to defaults" "initstate" normal
+ endmenu
+
+Activating functions and dialogs
+================================
+
+ Once the menu structure is built and user selects some item, it
+should be activated. It is done by simple command: `(NAME)'. Once "`)'"
+is sent, command is executed by XaoS.
+
+ Check-boxed functions has one extra parameter--`#t' to enable them
+and `#f' to disable. So if you want enable item `autopilot' send:
+`autopilot #t'
+
+ Radio-buttons don't have any such special parameter--because
+disabling radio-button is nonsense.
+
+ In case, item has flag dialog enabled, engine expects that UI will
+make dialog first, ask user of values and then call function with
+parameters. UI needs first to know, what parameters function expect.
+It is done by sending command `(print_dialog "NAME")'. XaoS replies
+with dialog specification very similar to menu specification.
+
+ It has header `dialog' followed by the name of function. Then one
+dialog entry per line is sent. it is started by `dialogentry' followed
+by question UI should display. The is type, which should be one of the
+following:
+`integer'
+ Integer number such as `123'
+
+`float'
+ Floating point number such as `123.123'
+
+`string'
+ String such as `"ahoj"'
+
+`keyword'
+ String such as `'ahoj'. The keywords are mostly similar to string,
+ except they can not contain space. They are used for example for
+ specifying formula type. Strings are used for printing texts etc.
+
+`inputfile'
+
+`outputfile'
+ Here UI should display file selection dialogs. With `outputfile'
+ it is also good idea to check, whether file exist and in this case
+ make some overwriting dialog too.
+
+`onoff'
+ Boolean value (`#f', or `#t')
+
+`complex'
+ Complex value--two floating point numbers such as `123.123 123.123'
+
+`choice'
+ Choice between some keywords. Those keywords are send after
+ `choice' in enclosed the `{' `}'. Last information at the line is
+the default value in the same format as examples above. For files, the
+default value is in format `"[PREFIX]*[EXTENSION]"'.
+
+ Some examples:
+
+ customdialog "uiview"
+ dialogentry "center:" complex 0.000000 0.000000
+ dialogentry "Radius:" float 0.000000
+ dialogentry "Angle:" float 0.000000
+ enddialog
+
+ dialog "load"
+ dialogentry "Filename:" inputfile "fract*.xpf"
+ enddialog
+
+ customdialog "color"
+ dialogentry "Color" choice {white black red }white
+ enddialog
+
+ To activate function, send command which contain function name,
+possible `#t'/`#f' in check-boxes and parameters in the same order as
+in dialog, same format as in examples, separated by the space. Such as:
+
+ (uiview 0 0 0.5 0)
+ (load "text.xpf")
+ (color 'white)
+
+Synchronization
+===============
+
+ In some cases, XaoS can change radio-box and check-box values. (like
+when user pressed a key, or loaded some file). So all changes are sent
+to GUI, wich should inform about this. They are sent to standard output
+in following format:
+
+ checkbox "name" on/off
+ radio "name" on/off
+
+ So your GUI should parse this and change it's menus when necessary.
+
+ Also XaoS's menus can contain more distinct trees. In some cases
+(like when animation replay is active) root of menu structure should
+change. The XaoS sends command:
+
+ root "name"
+
+ Also user can press keys, which normally displayed menus, dialogs or
+help. Then XaoS sends commands:
+
+ menu "name"
+ dialog "name"
+ help "topic"
+
+ All this commands should be taken into account by GUI, or should be
+ignored.
+
+help
+====
+
+ XaoS's help is in the simple hypertext language. In order to
+simplify it's parsing I've made an xshl and help libraries. So making
+of help window should be quite easy. Just call help function:
+
+ - Function: struct xshl_line *help_make (char *COMMAND, int GETWIDTH
+ (void *, int FLAGS, char *TEXT), int WIDTH, int SMALLHEIGHT,
+ int BIGHEIGHT);
+ and you will receive of listings of text with positions, where to
+print into window.
+
+ `command' parameter is topic of help. `getwidth' function is
+function, wich returns width of given text. `width' is width of window,
+`smallheight' is height of small font and `bigheight' is height of big
+font.
+
+ Please ask me for more details if necessary.
+
+ And thats all. Good luck with coding.
+
+
+File: xaosdev.info, Node: ui-helper, Next: xthreads, Prev: eui, Up: Top
+
+UI-helper library
+*****************
+
+ UI helper library takes care to all XaoS' engine functions and
+features and gives the higher level API, which is quite easy to
+understand. If you want to write completely new user interface
+(replacement for the ugly interface--not just new bindings for native
+menus or external user interfaces) or you want to use XaoS engine in
+your program as an library, you will probably want to use this library.
+
+ It's API has many calls and features. This section gives just brief
+overview of it's calls. Please ask me about details.
+
+initialization
+==============
+
+ To initialize ui helper library, you need to prepare an palette and
+image. Palette is created using palette library calls `createpalette'.
+Creating truecolor palette should look like this:
+
+ struct palette *pal = createpalette (0, 0, TRUECOLOR, 0, 0, NULL,
+ NULL, NULL, NULL);
+
+ For details about creating palettes see `ui.c' or ask me.
+
+ To create image call:
+
+ struct *image img = create_image_mem (width, height, 2, pal,
+ pixelwidth, pixelheight);
+
+ This creates image in the memory. If you want to create it in your
+own buffers, you might use `create_image_cont' or `create_image' calls.
+Again see `ui.c'.
+
+ Then it is time to fire up main library:
+
+ struct uih_context *uih = uih_mkcontext (0, img, passfunc,
+ NULL, NULL);
+
+ The `passfunc' is called when engine is calculating. It might process
+events and display process information. It should look like this:
+
+ static int
+ ui_passfunc (struct uih_context *c, int display, char *text, float percent)
+ {
+ /*process events */
+ if (uih->display)
+ {
+ uih_drawwindows (uih);
+ /*display */
+ }
+ if (display)
+ {
+ if (percent)
+ sprintf (str, "%s %3.2f%% ", text, (double) percent);
+ else
+ sprintf (str, "%s ", text);
+ /*display it */
+ }
+ }
+ It might set `uih->interrupt', if it wants to interrupt current
+calculation.
+
+ You also might load the catalog file in order to make tutorials
+working:
+
+ uih_loadcatalog (uih, "english");
+
+ Since this ui_helper library is fully functional and you might enter
+the main loop.
+
+main loop
+=========
+
+ UI helper library does an timing primitives. So it expect an
+standard form of the main loop. It asks the program to display changed
+image when necessary. Library also use timerlib for it's timing. So
+read section about this library, since you might use it for your
+purposes too.
+
+ Main loop should look like this:
+
+ while (1)
+ {
+ if (uih->display)
+ {
+ uih_prepare_image (uih);
+ uih_drawwindows(uih);
+ /*display current image buffer*/
+ }
+ uih_update (uih, mousex, mousey, buttons);
+ if ((time = tl_process_group (syncgroup, NULL)) != -1 &&
+ !uih->inanimation) {
+ /*relax given time in usec - wait of events etc..*/
+ }
+ /*and repeat*/
+ }
+
+calling functions
+=================
+
+ UI helper library has many functions declared in `ui_helper.h' for
+various actions. There is too much of them to describe, but their names
+are quite informative, so I hope you will not have problems.
+
+ You might also use XaoS function registry, which does all this stuff
+for you. You will just draw menus and dialogs based at this registry
+and automatically all features will be available. So if you are writing
+an ordinary user interface, this is the preffered way.
+
+ Note that `ui_helper' library is not reentrant, so you can't call
+most of this function from the `passfunc'. If you are using registry,
+activating function handles this automatically and queues functions
+when necessary. To process them you need to flush queue in the main
+loop as follows:
+
+ static void
+ processbuffer (void)
+ {
+ menuitem *item;
+ dialogparam *d;
+ if (uih->incalculation)
+ return;
+ while ((item = menu_delqueue (&d)) != NULL)
+ {
+ menu_menuactivate (item, d);
+ }
+ }
+
+closing library
+===============
+
+ This is done using:
+
+ uih_freecontext (uih);
+
+ One implementation of user interface at the top is ugly interface.
+See dirrectory `src/ui'. Another, much simpler is `render.c', which does
+animation rendering.
+
+
+File: xaosdev.info, Node: xthreads, Next: filters, Prev: ui-helper, Up: Top
+
+XaoS thread library
+*******************
+
+ This description should be useful for those, who want to port XaoS
+into multiprocessor platforms and those, who want to implement some
+filter or other relatively computational expensive code. Note that
+thread library should be mapped into nothread calls, in case host does
+not allows multi-threading or it is not SMP architecture (since this
+library is used only to distribute calculation 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--auto-detection or number of threads users wants. In case threads
+ is set to 1, threading library is disabled and following functions
+ are mapped into those nothread_ equivalents defined in `xthread.h'.
+
+ Note that threads are not identical--there is main thread (one
+ that called xth_init) that communicates with drivers, controls
+ calculation 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 UN-initialize 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 parameters: 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 immediately 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 similar 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 spin-locks are maybe better than
+ Dijskra semaphores. 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 mechanism is used by calculation 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 calculation routines in case queue is empty. This happens in
+ case of 50 threads but happens rarely at two or eight threads
+ according to my tests.
+
+ - Function: void xth_wakeall (int N)
+ Similar to wakeup but wake up all threads.
+
+
+File: xaosdev.info, Node: filters, Next: algorithm, Prev: xthreads, Up: Top
+
+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 beginning there is just two filters here(zoom and ui) but
+later additional filters should be inserted into the middle of queue
+like an stereo-gram generation etc. The queue supports operations like
+remove filter, add filter and initialize.
+
+ In the calculation every filter should use data calculated by filter
+lower in the queue. Data are stored into image. So for example
+stereo-gram filter should use fractal generated by zooming engine and
+create an stereo-gram.
+
+ 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 child. So stereo-gram filter should change palette, force
+zooming engine to change depth, width and height of calculated image to
+fit his needs and so on.
+
+ This document describes mainly creating of filter like stereo-gram
+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 stereo-gram
+generator". Name is displayed by ugly interface in filter's menu. So it
+is expected to be descriptive 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 / destroying of instance
+=================================
+
+ Functions getinstance and destroyinstance are equivalents to
+constructor and destructor 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
+fields 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 get-instance with
+ allocating of such additional structure. In case nothing similar
+ is required you should use directly 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 such function 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 parent 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 parents requirement structure.
+
+ Second pass starts by the highest filter and each filter passes to
+child an image and some other stuff. Then calculation should begin.
+
+ Queue needs to be reinitialized after creating, resizing,
+adding/removing of filter and similar 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
+
+`TRUECOLOR24'
+ An 24bpp truecolor image with 8bits for each color.
+
+`TRUECOLOR16'
+ An 16bpp truecolor image
+
+`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'
+ Similar to `LARGEITER' but 8bpp
+
+ In case you don't worry about palettes, allocations of colors and
+you do just some operation with bitmap, so you worry just about 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 opposite order(from
+parent to child) and child's infers 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 recommended to use same image or at least same memory for
+ data when passing to child. But this is not allays possible.
+ Following function implements heuristic 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 your 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 filters (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 mechanism you also must call
+destroyinheredimage in destroyinstance function and updateinheredimage
+at the beginning 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
+behaviors--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 function does
+nothing.
+
+Caluclation
+===========
+
+ Main calculation is done using doit function. It is expected to call
+child's calculation function when required and apply filter at output.
+It receives flags. Only flag in `INTERRUPTIBLE' for now. It is mainly
+for zooming 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 calculate 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 beginnings 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 writing 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 position in fractal and back. Convertup is function that
+receives coordinates in child'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: xaosdev.info, Node: algorithm, Next: timerlib, Prev: filters, Up: Top
+
+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 flicker a bit and why points do not blink
+randomly as in recalculated 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 recalculated 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 described 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 necessary 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 there is not good approximation 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 surprisingly simple algorithm that solves all these problems. First I
+decided to define exactly what is best approximation. This should be
+done by defining a price for every approximation and choose the
+approximation with the lowest price. Prices are defined as such:
+
+ Approximating 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 approximations for row/column 2 I may
+use previous one: Try new position n. Calculate the price and add the
+best approximation for the previous (row/column 1) one that uses a new
+position lower than n(prohibits doubling or swapping). This should 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 approximation. 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 occasionally 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 neighbors. 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 ideal positions should cause
+miss-ordered 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 beginning 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 recalculated--like tables for calculating price from
+distance. Also dividing main loops into many specialized parts and
+avoiding filing unnecessary 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 acquired 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 actually 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 calculation 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
+calculates iterations 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 recalculated slowly to get exact
+values. This helps 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 an without periodicity checks. In most cases it uses
+nonperiodicity checking version. Periodicity check version is used just
+in case, some inside set pixel has been found during solid guessing
+paste around. This is done mainly because periodicity checking version
+of loop is significantly 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 choose between 5FPS and 15FPS. This caused
+that images are calculated 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 oscillating.
+
+ 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 supports 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
+proceeded 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 discussion about current
+implementation. Only problem of current implementation I see is
+possibility, that calculation is divided into too many parts (realloc
+tables, move points, calculate, symmetries, dynamic resolution) and
+tasks needs to synchronize between each part. So this should be too
+slow at real SMP box.
+
+
+File: xaosdev.info, Node: timerlib, Next: registry, Prev: algorithm, Up: Top
+
+The timer library
+*****************
+
+ Timer library is library I did for timing in XaoS. But I found it
+useful 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 application (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 calculate step
+ for badies, move badies for set step, display and again. This way
+ fixes problem with speed. But moving badies just for calculated
+ 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 enough to make game smooth
+ but low enough to do whole internal loop in time. So internal loop
+ should look like: read user input, move badies, display, measure
+ 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 method, 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 calculate 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 comfortable
+ 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 application for example should want
+to move one set of badies at one framerate and other at different
+framerate. This requires two such timings. 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 timing, how easy to use it is, speed, portability and to
+minimalize inexpected situations (like race conditions in asynchronous
+interrupts and so on)
+
+The name of game
+================
+
+ Timer library operates with "timers". They should be created, you
+should measure time since last reset, pause them or set "handler" and
+"interval". But handler is not activated at given interval yet. Since
+timer library is not asynchronous, you must activate them.
+
+ For activating is used "groups". You should process 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 frequency. 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 asynchronously like from interrupt. It is not recommended 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 useful, 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 frequency 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
+useful. 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 calculation 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 useful for
+example when you want precalculate animation at given framerate.
+
+ To control group of timers, you might create "emulators". It is just
+another time controlled by you. It is useful in cases you want to
+emulate fixed framerate (for animation rendering) or such.
+
+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. Similar 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.
+
+Emulator functions
+==================
+
+ - Function: struct timeemulator *tl_create_emulator (void);
+ This function creates new emulator--you need to create one first
+ before emulating.
+
+ - Function: void tl_free_emulator (struct timeemulator *T);
+ Destroy emulator's data
+
+ - Function: void tl_elpased (struct timeemulator *T, int ELPASED);
+ Move emulated time.
+
+ - Function: void tl_emulate_timer (struct timer *T, struct
+ timeemulator *E);
+ Set timer to the emulated mode. Since now all time is controled by
+ emulator E. All other behavior of timer keeps unchanged.
+
+ - Function: void tl_unemulate_timer (struct timer *T);
+ Disable emulated mode for the timer.
+
+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);
+ }
+
+
+File: xaosdev.info, Node: registry, Next: index, Prev: timerlib, Up: Top
+
+XaoS function registry
+**********************
+
+ XaoS has an ui helper library, which provides functionality provided
+by user interface. All it's useful functions are registered into
+central registry. This registry is used to generate menus and dialogs
+as well as command line options or scripting language. So it is very
+significant think in XaoS design.
+
+ Not only those who want hack XaoS ui-helper layer needs to know
+this, but also authors of drivers should use this to add new driver
+depended functions into XaoS's menu. Also external user interface is
+based at this. Main idea behind external user interfaces (currently
+one for TCL/Tk and Gtk is under development) is following: XaoS
+transfers it's registry to interface (using simple description
+language). User interface starts XaoS in it's window and builds menus
+and dialogs based at this registry. Then once user select some
+function, it creates an command for scripting language and sends it back
+to XaoS' engine.
+
+ So knowledge of this part is essential for many developers. Please
+take care for this part.
+
+ The implementation of registry is in file `xmenu.c', header is
+`xmenu.h'. Mainly for historical reasons it speaks about menus and
+dialogs. (It was designed for the GUI at the beginning) I am keeping
+this terminology, since it is quite clean and easy to understand
+instead of talking in some cryptic abstract term.
+
+Function description
+====================
+
+ To add function into database, you need write it's description into
+menuitem structure. It has following prototype:
+
+ typedef struct menuitem
+ {
+ char *menuname;
+ char *key;
+ char *name;
+ char *shortname;
+ int type;
+ int flags;
+ void (*function) ();
+ int iparam;
+ void *pparam;
+ int (*control) (struct uih_context *);
+ menudialog *(*dialog) (struct uih_context *);
+ }
+ menuitem;
+
+ - Variable: menuname
+ Name of menu (or category) function belongs in. The root of all
+ categories is called `"root"'. XaoS alternativly uses an
+ `"animroot"' when animation replay is active. If you are adding an
+ function, it is better to add it into some subcategory like as
+ `"ui"' (it will be placed into UI menu then) or create an new
+ category for your functions if needed. It will appear as submenu
+ in main menu in the UI.
+
+ - Variable: key
+ Ascii code of hotkey to activate this function. Use `NULL' if none.
+
+ - Variable: name
+ Longer name of functions used in the menu entry, or `xaos --help'
+ listing
+
+ - Variable: shortname
+ One-word name of function used in command language and references
+ to function.
+
+ - Variable: type
+ type of function--this is not return type. Type should be one of
+ following constants:
+ `MENU_SUBMENU'
+ An submenu. This is not real function, but name for submenu.
+ You might fill the KEY, NAME, SHORTNAME functions. An name
+ of this new submenu is placed in the field PPARAM.
+
+ `MENU_NOPARAM'
+ An normal function without any parameters. When actived,
+ function FUNCTION with just an pointer to `uih_context'
+ will be called.
+
+ `MENU_INT'
+ This should be used to simplify entering of more similar
+ functions (handled by just one universal function in the c
+ code). This function is handled in same way as
+ `MENU_NOPARAM', but also in one integer parameters taken
+ from `iparam' is passed.
+
+ `MENU_STRING'
+ Similar to `MENU_INT' but uses string instead of integer.
+
+ `MENU_DIALOG'
+ If you function needs some paramters, use dialog structure to
+ describe them. In scripting language your function will
+ have parameters then, in user interface dialog will be
+ displayed. PPARAM must then point to array of dialog
+ entries. Witting them will be described later. If your
+ function has just one parameter described in dialog
+ structure, it will be called in normal c way--if you want
+ string parameter, one pointer pointing to string (in
+ addition to `uih_context') will be passed to the functions.
+
+ In case of multiple parameters are requested, it is
+ impossible to call function in c way without special
+ wrapper for each such case. So it will receive pointer to
+ array of `dialogparam' unions, wich contains one entry for
+ each parameter. `dialogparam' is declared as follows:
+ typedef union
+ {
+ char *dstring;
+ int dint;
+ number_t number;
+ number_t dcoord[2];
+ xio_path dpath;
+ void *dummy;
+ }
+ dialogparam;
+
+ `MENU_CDIALOG'
+ In some cases, it is useful to add some context specific
+ default values to the dialog structure. In this case you
+ might use this type instead. In this case function DIALOG
+ is called first, and it is expected to return pointer to
+ correct dialog structure. Dialog structure must lie in
+ static storage (since it is not freed) and always must have
+ the same fields, just differ in the default values.
+ Also this function must work correctly even in the case
+ pointer to `uih_context' is `NULL', since it is often
+ called in the initialization stages (parameter parsing
+ etc.)
+
+ - Variable: flags
+ Flags are used to set additional information about function:
+ `MENUFLAG_CHECKBOX'
+ Some features act like check-box--i.e. by one calling of
+ function they are enabled, second call disables this. In menu
+ it is useful to add an check-box for this function indicating
+ whether feature is on or off.
+
+ And thats exactly what this flag does :). You need also
+ define the function CONTROL wich return's `1' when enabled
+ and `0' when disabled. In order to let external GUI's work
+ correctly you need also call `uih_updatemenus("name")' every
+ time state of this function changes.
+
+ In the scripting language this adds an first parameter, wich
+ if `#t' or `#f'. Engine then calls function just when it is
+ necessary. For `#t' dialog is requested, with `#f' function
+ is called just as `NOPARAM'. I.e. dialog is displayed just
+ when enabling feature.
+
+ `MENUFLAG_DIALOGATDISABLE'
+ In checkbox display dialog when this feature is disabled
+ instead when enabled.
+
+ `MENUFLAG_RADIO'
+ Other features act like radio-button. Control function in
+ this case receives same parameter as defined for `MENU_INT'
+ or `MENU_STRING' types and is expected to return `1' when
+ enabled. You also need to call `uih_updatemenus' when
+ changed. No special parameter is added in the scripting
+ language.
+
+ `MENUFLAG_INTERRUPT'
+ Interrupt current calculation when this function called (it
+ is used by functions with causes recalculation of screen)
+
+ `MENUFLAG_INCALC'
+ By default XaoS queues functions and calls later when they
+ are activated in caluclation. This flag disables this feature.
+
+ `MENUFLAG_ATSTARTUP'
+ By default XaoS queues functions and calls later when they
+ are activated as command line parameters (in time engine is
+ not fully initialized yet). This flag disables this feature.
+
+ `MENUFLAG_NOMENU'
+ Function will not be visible in the menu
+
+ `MENUFLAG_NOPLAY'
+ Function will not be available as command in scripts
+
+ `MENUFLAG_NOOPTION'
+ Function will not be available as command line option
+
+Initializing menuitem structure as static variable
+==================================================
+
+ In most case menuitems should be wrote as static variables. Because
+contents of this structure should change in future, please use one of
+macros defined in `xmenu.h'. They provides cleaner and easier to extend
+way to define this entries.
+
+ For example to define `MENU_NOPARAM' function use following macro:
+
+ - Function: MENUNOP (MENUNAME, KEY, NAME, SHORTNAME, FLAGS, FUNCTION)
+ Similar macros exist for the other types too. They ends for `CB' or
+`RB' for check-boxed or radio-boxes functions. See `menu.c' for large
+example of definitions. They should look like this:
+
+ static menuitem menuitems[] = /*XaoS menu specifications */
+ {
+ SUBMENU ("", NULL, "Root menu", "root"),
+ SUBMENU ("", NULL, "Replay only commands", "plc"),
+ MENUNOP ("comm", NULL, "print menus specifications of all menus",
+ "print_menus", MENUFLAG_NOMENU|MENUFLAG_NOPLAY|MENUFLAG_ATSTARTUP,
+ uih_printallmenus),
+ ...
+
+Dialog description
+==================
+
+ Dialog description is similar to menuitem. It is array of following
+structures:
+ typedef struct dialog
+ {
+ char *question;
+ int type;
+ int defint;
+ char *defstr;
+ number_t deffloat;
+ number_t deffloat2;
+ }
+ menudialog;
+ It is terminated by QUESTION pointer set to `NULL'.
+
+ The QUESTION contains string ui should display when is asking for
+this field.
+
+ TYPE should be one of following values: `DIALOG_INT',
+`DIALOG_FLOAT', `DIALOG_STRING', `DIALOG_KEYSTRING' (the difference
+between string and keystring is, that in scripting language string is
+passed as `"hello"', but keystring is passed as scheme keyword as
+`'hello'), `DIALOG_IFILE' (input file), `DIALOG_OFILE', `DIALOG_CHOICE'
+(choice between different keystrings), `DIALOG_ONOFF' (boolean
+parameter), `DIALOG_COORD' (two floats--complex number)
+
+ Set to corresponding DEF* field for default value. In case of files
+use string in the format `"[PREFIX]*[EXTENSION]"'. For type
+`DIALOG_CHOICE' set DEFSTR to pointer to array of strings terminated by
+`NULL' entry.
+
+ To write dialog structures again use macros defined in `xmenu.h'
+like:
+ DIALOGSTR(question,default)
+ The definition should look like:
+
+ static menudialog uih_viewdialog[] =
+ {
+ DIALOGCOORD ("center:", 0, 0),
+ DIALOGFLOAT ("Radius:", 1),
+ DIALOGFLOAT ("Angle:", 0),
+ {NULL}
+ };
+
+Modifying registry
+==================
+
+ - Function: void menu_add (menuitem *ITEM, int N);
+ Add array of N items to the database.
+
+ - Function: void menu_delete (menuitem *ITEMS, int N);
+ Remove array of N items from database.
+
+Querying registry
+=================
+
+ - Function: menuitem* menu_findkey (char *KEY, char *ROOT);
+ Find item for given key. ROOT is menu where to start (submenus are
+ searched recursively)
+
+ - Function: menuitem* menu_findcommand (char *NAME);
+ Find item for given short name
+
+ - Function: char* menu_fullname (char *MENU);
+ Long name for the short name of menu
+
+ - Function: menuitem* menu_item (char *MENU, int N);
+ Nth entry of the MENU. Return `NULL' if no more entries available.
+
+ - Function: int menu_enabled (menuitem *ITEM, struct uih_context *C);
+ Check whether given item is activated (for check-boxed and
+ radio-boxed functions)
+
+ - Function: int menu_havedialog (menuitem *ITEM, struct uih_context
+ *C);
+ Does this function have dialog?
+
+ - Function: menu_getdialog (CONTEXT, M)
+ Macro returns pointer to dialog structure. (function must have it,
+ otherwise garbage is returned).
+
+ - Function: int menu_available (menuitem *ITEM, char *ROOT);
+ Check whether item is available as one of entries of ROOT (or it's
+ submenus)
+
+
+File: xaosdev.info, Node: index, Prev: registry, Up: Top
+
+Index of functions, variables, types and constants
+**************************************************
+
+* Menu:
+
+* alloc_buffers: driver.
+* ANIMATION: filters.
+* C256 <1>: filters.
+* C256: driver.
+* CHANGED: filters.
+* createfilter: filters.
+* display: driver.
+* ethreads: xthreads.
+* filter: filters.
+* filteraction: filters.
+* FIXEDCOLOR <1>: filters.
+* FIXEDCOLOR: driver.
+* flip_buffer: driver.
+* flush: driver.
+* free_buffers: driver.
+* FULLSCREEN: driver.
+* getinstance: filters.
+* getsize: driver.
+* GRAYSCALE <1>: filters.
+* GRAYSCALE: driver.
+* image <1>: filters.
+* image: design.
+* INEXACT: filters.
+* inherimage: filters.
+* inhermisc: filters.
+* init: driver.
+* initdata: filters.
+* MASK1BPP: filters.
+* MAXCONDS: xthreads.
+* MAXSEMAPHORS: xthreads.
+* menu_add: registry.
+* menu_available: registry.
+* MENU_CDIALOG: registry.
+* menu_delete: registry.
+* MENU_DIALOG: registry.
+* menu_enabled: registry.
+* menu_findcommand: registry.
+* menu_findkey: registry.
+* menu_fullname: registry.
+* menu_getdialog: registry.
+* menu_havedialog: registry.
+* MENU_INT: registry.
+* menu_item: registry.
+* MENU_NOPARAM: registry.
+* MENU_STRING: registry.
+* MENU_SUBMENU: registry.
+* menudialog: registry.
+* MENUFLAG_ATSTARTUP: registry.
+* MENUFLAG_CHECKBOX: registry.
+* MENUFLAG_DIALOGATDISABLE: registry.
+* MENUFLAG_INCALC: registry.
+* MENUFLAG_INTERRUPT: registry.
+* MENUFLAG_NOMENU: registry.
+* MENUFLAG_NOOPTION: registry.
+* MENUFLAG_NOPLAY: registry.
+* MENUFLAG_RADIO: registry.
+* menuitem: registry.
+* MENUNOP: registry.
+* mousetype: driver.
+* nthreads: xthreads.
+* P_FLOAT: driver.
+* P_NUMBER: driver.
+* P_STRING: driver.
+* P_SWITCH: driver.
+* palette: design.
+* params: driver.
+* PIXELSIZE: driver.
+* print: driver.
+* processevents: driver.
+* RANDOM_PALETTE_SIZE: driver.
+* requirements: filters.
+* RESIZE_COMMAND: driver.
+* RESOLUTION: driver.
+* SCREENSIZE: driver.
+* set_color: driver.
+* set_range: driver.
+* timeemulator: timerlib.
+* tl_add_timer: timerlib.
+* tl_create_group: timerlib.
+* tl_create_timer: timerlib.
+* tl_elpased: timerlib.
+* tl_emulate_timer: timerlib.
+* tl_free_emulator: timerlib.
+* tl_free_group: timerlib.
+* tl_free_timer: timerlib.
+* tl_lookup_timer: timerlib.
+* tl_process_group: timerlib.
+* tl_reset_timer: timerlib.
+* tl_resume_timer: timerlib.
+* tl_set_handler: timerlib.
+* tl_set_interval: timerlib.
+* tl_set_multihandler: timerlib.
+* tl_sleep: timerlib.
+* tl_slowdown_timer: timerlib.
+* tl_stop_timer: timerlib.
+* tl_unemulate_timer: timerlib.
+* tl_update_time: timerlib.
+* TRUECOLOR <1>: filters.
+* TRUECOLOR: driver.
+* TRUECOLOR24 <1>: filters.
+* TRUECOLOR24: driver.
+* TRUECOLOR32 <1>: filters.
+* TRUECOLOR32: driver.
+* UI_C256: driver.
+* ui_driver: driver.
+* UI_FIXEDCOLOR: driver.
+* UI_GRAYSCALE: driver.
+* UI_TRUECOLOR: driver.
+* UI_TRUECOLOR24: driver.
+* UI_TRUECOLOR32: driver.
+* uninit: driver.
+* UPDATE_AFTER_RESIZE: driver.
+* xshl_line: eui.
+* xth_bgjob: xthreads.
+* xth_function: xthreads.
+* xth_init: xthreads.
+* xth_lock: xthreads.
+* xth_nthread: xthreads.
+* xth_sleep: xthreads.
+* xth_sync: xthreads.
+* xth_uninit: xthreads.
+* xth_unlock: xthreads.
+* xth_wakeall: xthreads.
+* xth_wakeup: xthreads.
+
+
+
+Tag Table:
+Node: Top501
+Node: design1475
+Node: driver9067
+Node: gui-driver25868
+Node: eui32613
+Node: ui-helper43320
+Node: xthreads47876
+Node: filters52923
+Node: algorithm69506
+Node: timerlib89511
+Node: registry99566
+Node: index111446
+
+End Tag Table