
 Video filters
 =============
 This document describes how to write a video filter for CineWorks.


 Glossary
 --------
 Filter                 A video effect
 Filter window          The window displaying the filters applied to a clip
 Filter library         The window displaying all available filters
 Filter list            A list of the filters being applied to a clip
 Local parameters       Filter-parameters specific for a clip
 Global parameters      Filter-parameters for all clips



 Filter file format
 ==================
 Filters reside in the directories <CineWorks$Dir>.Filters0 - Filters3. A
maximum of 300 filters can be loaded at once.
 A filter can either be stored as a single file (filetype &FFD) or as a
directory holding (at least) a file called Filter (filetype &FFD). If the
directory is an application directory (the name start with a !) the file
!Run inside the directory will be *Run'ed (if present). Likewise, the file
!Sprites will be *IconSprite'ed.

 A filter file has the following header:

 Word
  0       ID
  1       Offset to filter icon block or 0
  2       Offset to init code or 0
  3       Offset to kill code or 0
  4       Offset to add code or 0
  5       Offset to remove code or 0
  6       Offset to setup code or 0
  7       Offset to start code or 0
  8       Offset to filter code
  9       Offset to end code or 0
  10      Offset to filter preview code or 0
  11      Offset to info code or 0
  12      Offset to save code or 0
  13      Offset to load code or 0
  14      Offset to filter info
  15      0
  16      0
  17      0
  18      0
  19      Workspace required (in bytes) or 0 (1024 bytes) or < 0 (none)

 All offsets are relative to the start of the file.
 The filters are loaded to the RMA and allocated the amount of workspace
specified in word 19 of the header.

 Although a filter may provide any level of complex user-configuration, it is
still very easy to write a simple filter. Basically, all that is required is
a header (20 word) of which only 3 words have to be <> 0 and the code which
manipulates the frame in one way or another.


 ID
 --
 The ID is purely for identifying a filter, the bits have no meaning for
CineWorks.

 Bit 31 set: The ID has not been registered with Oregan.

 The following IDs are reserved:

 &00000000
 &FFFFFFFF
 &44534Fxx (<xx>"OSD") (Oregan Software Developments)
 &504248xx (<xx>"HBP") (Henrik Bjerregaard Pedersen)
 &5743xxxx (<xxxx>"CW") (CineWorks)

 Third party developers should contact Oregan for an allocation of an ID.
 ID are allocated in chunks of 256, so that the bottom 8 bits of the ID are
free for the developer to change.


 Filter icon block
 -----------------
 This is a icon block (32 bytes) (see SWI Wimp_CreateIcon).
 This entry can be 0, in which case CineWorks will create a default icon
using a default sprite and the name of the filter.
 The icon should be 200x160 OS units, text-sprite (or optionally sprite-only)
like the filer icons. The coordinates are altered by CineWorks before the icon
is created. The text should not be more than 12 chars.
 The filter should either *IconSprites the necessary sprites when starting, or
it should supply the sprite in a spritearea within the filter. If the sprite
is *IconSprite'ed, it is suggested that the name be 'cwf_xxxxxxxx'.
 The sprite should be max 100x50 pixels, MODE 27.

 It is suggested that this block is used for the icon:

 Word   Contents        Meaning
 0      0               min x of icon bounding box (unused)
 1      0               min y of icon bounding box (unused)
 2      0               max x of icon bounding box (unused)
 3      0               max y of icon bounding box (unused)
 4      &1700A10B       icon flags
 5      <text>          pointer to text (within the filter)
 6      <valid>         pointer to validation string (eg. 'Scwf_rgbyuv')
 7      <n>             length of text buffer (usually <= 13)

 The icon is read AFTER the init code is called, so the init code should
insert the pointers to the text and validation strings.


 Init code
 ---------
 This is called after the filter has been loaded.
 This entry can be 0.

 On entry
 R0  =>  Movie definition
 R1  =>  Base of machinecode routines (the core)
 R2  =>  Various variables
 R5  =>  Private (global) workspace for the filter (1024 bytes)

 The pointers in R0-R2 are only passed this once.
 The pointers remain the same all the time, but the contents may change.

 On exit
 R0  =   0 (if initialised OK)  or
 R0  =>  error block


 Kill code
 ---------
 This is called when CineWorks exits
 This entry can be 0.

 On entry
 R5  =>  Private (global) workspace for the filter (1024 bytes)

 On exit
 -

 Add filter code
 ---------------
 This is called when the filter is added to a clip.
 This entry can be 0.

 On entry
 R0  =>  Clip
 R1  =   Clip number on track
 R2  =   Track number
 R5  =>  Private (global) workspace for the filter

 On exit
 R0  =   Value to pass to remove/setup/start/filter/end/save/load code in R5
         (ie. the private word) or
        -1 (filter could not be applied)

 If this entry in the header is 0, the private word will be set to 0.
 This entry is also called when CineWorks loads a file, that is, when a clip
to which this filter is applied is loaded. Thus this code should not do
anything that requires user interaction.


 Remove filter code
 ------------------
 This is called when the filter is removed from a clip.
 This entry can be 0.

 On entry
 R5  =>  Private (global) workspace for the filter
 R6  =   Private word

 On exit
 -

 Filter setup code
 -----------------
 This is called when the user wants to setup the filters local parameters,
(ie. when the user double clicks SELECT on the filter icon in a filter window).
 This entry can be 0.

 On entry
 R5  =>  Private (global) workspace for the filter
 R6  =   Private word


 Filter start code
 -----------------
 This is called before CineWorks starts rendering a movie.
 This entry can be 0.

 On entry
 R0  =   Size X (in pixels) of the movie
 R1  =   Size Y (in pixels) of the movie
 R5  =>  Private (global) workspace for the filter
 R6  =   Private word

 On exit
 -

 Filter code
 -----------
 This is called for each frame in the clip the filter is applied to.

 On entry
 R0  =>  Frame data
 R1  =   Position in clip (0 to <number of frames in clip))
 R2  =   Size X (in pixels) of the movie
 R3  =   Size Y (in pixels) of the movie
 R4  =>  Sprite area ('work' is the output sprite, 'mask2' is the mask (4bpp))
 R5  =>  Private (global) workspace for the filter
 R6  =   Private word

 On exit
 -
 There's no guarentee that this code will be called between the calls to the
filter start code and the filter end code.
 The filter code is called after keying, colour control and the build-in
video effects have been applied, but before transitions are applied.
 Very ugly effects may appear if you apply a filter to a clip with a path.


 Filter end code
 ---------------
 This is called when CineWorks has rendered the last frame in the movie.
 This entry can be 0.

 On entry
 R5  =>  Private (global) workspace for the filter
 R6  =   Private word

 On exit
 -

 Filter preview code
 -------------------
 This is called when the user wants to preview the filter.
 This entry can be 0.

 On entry
 R0  =>  Frame data
 R1  =   Position in clip (0-100)
 R2  =   Size X (in pixels) of the movie
 R3  =   Size Y (in pixels) of the movie
 R4  =>  Sprite area ('work' is the output sprite)
 R5  =>  Private (global) workspace for the filter
 R6  =   Private word

 On exit
 -

 Notice: Contrary to when rendering the movie, the start and end entry points
are not called before and after calling the preview code.
 Usually, the preview code will be asked to apply the filter to a thumbnail,
that is, to a 64x48 pixels frame.


 Info code
 ---------
 This is called when the user wants to setup the filter's global parameters
(ie. when the user double clicks SELECT on the filter icon in the filter
library.
 This entry can be 0.

 On entry
 R5  =>  Private (global) workspace for the filter.

 On exit
 -

 Save code
 ---------
 This is called when CineWorks saves the definition of a clip to which the
filter has been applied.
 This entry can be 0.

 On entry
 R1  =   File handle
 R5  =>  Private (global) workspace for the filter
 R6  =   Private word

 On exit
 R0  =  Number of bytes written (must be a multiple of 4 and >= 0).
 The file pointer MUST have been incremented by exactly the number of bytes
that have been written.
 CineWorks itself only saves the ID of the filter.


 Load code
 ---------
 This is called when CineWorks loads a file holding data saved by the save
code (see above).
 This entry can be 0.

 On entry
 R0  =   Size of data
 R1  =   File handle
 R5  =>  Private (global) workspace for the filter
 R6  =   Private word (usually 0)

 The file pointer is set to point to the first byte written by the save code.
 The code is only called if R0 > 0.

 On exit
 R0  =  New private word.


 Filter info
 -----------
 This word holds the offset from the start of the filter header to a structure
holding various information about the filter. This is displayed when the user
double clicks ADJUST on the filter in the filter library.
 The first 32 bytes holds the name of the filter (max 31 chars, ctrl-char
terminated).
 The next 32 bytes holds the version and date (max 31 chars, ctrl-char
terminated).
 The next 32 bytes holds the name of author/copyright holder (max 31 chars,
ctrl-char terminated).


 Workspace
 ---------
 This word indicates how much workspace the filter requires initially.
 If this is < 0 , nothing is allocated. 0 is assumed to mean 'default' which
is 1024 bytes. Before the filter init code is called, CineWorks replaces this
word with a pointer to the workspace (undefined if no workspace was allocated).
 If the workspace is larger than 255 bytes, the path to the filter on the
harddisc will be inserted in the start of the workspace.
 Usually will R5 hold a pointer to the filter workspace when any of the
routines in the filter is called, but if no workspace is allocated, R5 will be
undefined.


 Notes
 =====
 A filter should preferably allow to be applied to multiple clips, or indeed
to be applied more than once to a clip. In other words, the filter should be
're-entrant'. This can be achieved by using the private word to hold whatever
clip-specific data the filter needs to hold.
 CineWorks assumes that the filter is re-entrant, so it is up to the filter
to say stop (by returning an error on exit from the add filter code) if it
is applied more times than it (the filter) allows.
 Usually, the filter will allocate (see Heap_AllocateBlock) an appropiate
amount of workspace each time the 'add filter' code is called, and return the
anchor of the workspace as the private word.
 Alternatively (and faster but less fleksible) the filter can allocate
workspace once and for all, and then let the private word be a pointer to an
area within this workspace. This will usually allow the filter to be applied
to only a limited number of clips, and may use more memory than needed;
however, due to limitations in the heap manager, this is actually the
recommended way to allocate workspace for multiple instantiations of a filter.
A filter may assume that it won't be applied to more than 10-20 clips.

 The filter may not call the heap manager while rendering is in progress.
 If it suddenly needs extra workspace it should get this from the RMA.

