> net#arf:$.a500.RiscOS+.doc.SprExtend


Author:  Neil Raine
Status:  Description of new interfaces provided by SpriteExtend in RISC OS+
History:
        20-Sep-89  0.01  First draft released.
        21-Sep-89  0.02  Updated to show list of possible errors
        21-Sep-89  0.03  Put in non-linear transformations error
        22-Sep-89  0.04  Specify exactly which points are mapped to which
GStark  29-Sep-89  0.05  Updated with information on accuracy and source rectangle clipping
GStark  28-Nov-89  0.06  Updated with specification for InsertDeleteRows,  and
                            InsertDeleteColumns.
GStark  03-Jan-90  0.07  Updated the text referring to the possible errors for transformation


Transformed sprite SWIs
-----------------------

        SWI OS_SpriteOp
        In:     R0 = 55 (SpriteReason_PlotMaskTransformed) (+ 0, 256 or 512)
                R0 = 56 (SpriteReason_PutSpriteTransformed) (+ 0, 256 or 512)
                R1 -> sprite area (if R0 > 255)
                R2 -> sprite name or header (depends on R0)
                R3 = flag word:
                        bit 0 set => R6 -> destination coords, else matrix
                        bit 1 set => R4 -> source rectangle inside sprite
                        bits 2..31 reserved (must be 0)
                R4 -> source rectangle coordinate block (if R3 bit 1 set):
                        R4!0,4 = x0, y0 one corner in sprite (pixels)
                        R4!8,12 = x1,y1 second corner in sprite (pixels)
                R5 = GCOL action (for PutSpriteTransformed)
                          +8 if mask is to be used
                R6 -> matrix (if R3 bit 0 clear):
                        R6!0,4,8,12,16,20 = matrix (as for Draw module)
                R6 -> destination coordinate block (if R3 bit 0 set):
                        R6!0,4 = X0,Y0 on screen (1/256th OS unit)
                        R6!8,12 = X1,Y1 on screen (1/256th OS unit)
                        R6!16,20 = X2,Y2 on screen (1/256th OS unit)
                        R6!24,28 = X3,Y3 on screen (1/256th OS unit)
                R7 -> translation table ( <= 0 => none)

The source coordinates are inclusive at the bottom-left, and exclusive at the
top-right.

When specifying a destination parallelogram, the source rectangle is mapped
onto the destination as follows:

        x0,y0   ->      X0,Y0
        x1,y0   ->      X1,Y1
        x1,y1   ->      X2,Y2
        x0,y1   ->      X3,Y3

In future it may be possible to set the destination to an arbitrary
quadrilateral, rather than a parallelogram.  In order to reserve this
possibility, the current version returns a user-intelligible (-ish) error if
the destination is not a parallelogram.

For PutSpriteTransformed, the sprite is plotted through its mask only
if (a) it has one, and (b) R5 bit 3 is set.  R5 is ignored for
PlotMaskTransformed.

The SWI returns an error if any of R3 bits 2..31 are set, to ensure
that these are left clear by software developers.

The SWI covers exactly those pixels on the screen that a call to
Draw_Fill would produce for a rectangle of the same size with the same
transformation matrix, where it is filling to half-way through the boundary.
                                                 
When plotting using a destination parallelogram, the source rectangle must
be entirely within the sprite. For plotting with a matrix, the source rectangle 
will be clipped to the sprite boundaries prior to transformation.

If the source rectangle (after clipping, if using a matrix) has no area, i.e.
x0=x1 OR y0=y1 then an error will be generated, as it is not possible to choose
a colour in which to fill the destination.
                                               
Note that the SWI does allow x0>x1 or y0>y1 or both. When plotting with a matrix
there is no difference between x0 and x1 swapped, or y0 and y1 swapped, but when
specifying a destination parallelogram the image will be reflected.

Due to the mechanism of the routine the accuracy is not absolute. The SWI will always
cover the same area as a Draw filled path, but not necessarily with the right source
pixel data from the sprite. The worst possible error (in a fraction of a source pixel)
at one end of the plotted area is given by <destination width or height>/65536.

The table beloe gives more information on the maximum errors attainable:    

   Destination size                     Worst possible error in source pixels
         5                                              0.0000763
         10                                             0.0001526
         50                                             0.0007629
        100                                             0.0015259
        500                                             0.0076294
       1000                                             0.0152588
       5000                                             0.0762939
      10000                                             0.1525879
[ The largest output possible is 32767 pixels ]
i.e. When plotting a sprite to a destination width of 5000 pixels, the worst error possible
in the position in the source rectangle of the final pixel plotted is about 1/13 of a source
pixel.

Note that if these errors (usually too small to notice) must be avoided then the sprite should
be plotted in parts - perhaps by dividing the plotting into four areas.

Errors:
        Attempt to set reserved flags
                Bits 2 to 31 of R0 must be zero in the current specification
        Source rectangle area zero
                The area of the source rectangle must be non-zero, so the sprite routines will
                have some valid colour(s) to plot the output rectangle in. If the area is zero,
                there would be no valid colour(s) with which to plot the output.
        Source rectangle not inside sprite
                The source rectangle must be totally inside the sprite
        SpriteExtend can only do linear transformations
                The current version of the transformation routines can only perform linear
                transformations, and not any arbitrary rotation.
                                                


InsertDeleteColumns - InsertDeleteRows
------------------------------------------------

        SWI OS_SpriteOp
        In:     R0 = 57 (SpriteReason_InsertDeleteRows) (+ 0, 256 or 512)
                R0 = 58 (SpriteReason_InsertDeleteColumns) (+ 0, 256 or 512)
                R1 -> sprite area (if R0 > 255)
                R2 -> sprite name or header (depends on R0)
                R3 = row/column to start deletion at or insert before
                R4 = number of rows/columns to insert (if +ve) or delete (if -ve).
        Out:
                All registers preserved

For insertion R4>0, and R3 specifies the row or column to insert before. Rows are
numbered from 0 at the bottom, and columns from 0 at the left. Thus inserting before
the first column, i.e. at the left-hand edge, is performed with R3=0. If there are
N rows and M columns in the sprite then R3 can be equal to N if inserting rows, in which
case the rows will be inserted at the top of the sprite. If inserting columns then
R3 can equal M at most, in which case columns will be inserted at the right-hand edge of
the sprite.
The inserted rows/columns will be set to colour 0. If the sprite has a mask then rows/columns
will be inserted into that as well, and the inserted area will be transparent.

For deletion R4<0, and R3 specifies the first row or column to be deleted. The rows/columns
from R3 to R3-R4-1 will be deleted, i.e. R4 = -number of rows to delete. An error will be given
if R3 or R4 are out of range for the sprite.

