home *** CD-ROM | disk | FTP | other *** search
- Draw module specification
- =========================
-
- The current Draw module does not implement the floating point parts of this
- specification. Upgrading it to do so is a possible future development, but
- not a likely one.
-
-
- Path format
- ===========
-
- A path is a sequence of one or more of the following path elements, each of
- which is a sequence of words:
-
- 0 n = end of path, with n bytes remaining in buffer (n is
- only important for output buffers, and will not be
- read for input paths).
- 1 ptr = pointer to continuation of path.
- 2 x y = move to (x,y), starting new subpath. This subpath
- will affect winding numbers and so is filled
- normally.
- 3 x y = move to (x,y), starting new subpath. This subpath
- does not affect winding numbers when filling (used
- internally for thin-stroking paths). Note that any
- subpath started by this element will always be
- considered "closed" and so will never be closed by
- the "close open subpaths" operation.
- 4 = close current subpath with a gap (c.f. element type
- 7).
- 5 = close current subpath with a line (c.f. element type
- 8).
- 6 x1 y1 x2 y2 x3 y3 = Bezier curve to (x3,y3), with control points at
- (x1,y1) and (x2,y2);
- 7 x y = gap to (x,y), not starting new subpath - used
- internally for the gaps in non-thickened dashed
- lines.
- 8 x y = line to (x,y).
-
- Only the bottom byte of the element type (i.e. the first word in each of the
- sequences above) is significant: the remaining three bytes are free for use
- in any way a client of the Draw module sees fit. (On output to the input
- path, the Draw module will leave these three bytes unchanged; on output to a
- standard output path, the Draw module will store zeroes in these three
- bytes.)
-
- The element types noted as being used internally above can quite legitimately
- be used externally - the notes are simply to explain why these types exist at
- all.
-
- Note that there are order constraints on these elements - in particular,
- element types 4 to 8 may not be used when there is no current subpath,
- element types 2 and 3 start a new current subpath (ending any previous
- subpath), and element types 4 and 5 end the current subpath.
-
- Two lines, gaps or Bezier curves are considered to be adjacent if they both
- appear in the same subpath and one is defined immediately after the other, or
- if one of them is the first line, gap or Bezier curve of a subpath and the
- other closes that subpath (i.e. it is a path element type 4 or 5 and ends the
- subpath concerned). Adjacency of lines is used to decide whether to use a
- join to connect them when thickening a path.
-
- A subpath is called closed if it ends with a path element of type 4 or 5 (so
- that its last line, gap or Bezier curve is adjacent to its first one);
- otherwise, it is called open. Note that a subpath which happens to end at the
- same point that it started is not closed unless it actually ends with a type
- 4 or 5 path element: this can make a difference to whether its first and last
- line segments are connected with a join or with two caps when the path is
- thickened.
-
-
- The Draw module SWIs
- ====================
-
- All calls come in two versions, one a fixed point version and the other
- floating point. The former is faster but allows a smaller range of user
- co-ordinate systems and is sometimes less accurate.
-
- For the fixed point versions, all numbers that relate to distances in the
- co-ordinate space (e.g. co-ordinates, line widths, etc.) are expressed in
- user-defined units before transformation. When the transformed path is output
- to the screen (in particular, when Draw_Fill or Draw_Stroke is called), the
- units after transformation are 1/256 of an OS unit (i.e. approx. 1/(256*180)
- inch = 1/46080 inch = 1/640 point). The default flatness is 512 (2 OS units),
- which produces reasonable results when output is to the screen and the
- identity matrix is used. All dimensionless quantities have 16 binary places
- (i.e. &10000 represents the constant 1.0).
-
- Note that in the standard matrix:
-
- ( a b 0 )
- ( c d 0 )
- ( e f 1 ),
-
- a, b, c and d are dimensionless quantities (so have 16 binary places), while
- e and f represent a translation in the output co-ordinate space and so are
- expressed in output units (i.e. units after transformation). This varying
- interpretation of matrix elements is unpleasant, but necessary to retain
- reasonable behaviour (e.g. we want the inverses of all sensible matrices to
- be representable with reasonable accuracy).
-
- The floating point versions use IEEE single precision floating point numbers
- in all circumstances. They are distinguished by the suffix FP on the name of
- the call. The default flatness is 2.0, for the same reason as above.
-
- Note: unless otherwise specified below, all co-ordinates are user
- co-ordinates. PostScript concepts that are not redefined here should be
- interpreted as PostScript interprets them.
-
- A further note: all calls use the colour (both pixel pattern and operation)
- set up for the OS VDU routines.
-
- This means in particular that they can do things that PostScript cannot do -
- e.g. fill using operations such as AND, OR, EOR that pay attention to the
- current contents of the screen. Given this fact, I see no reason to restrict
- the module to PostScript's capabilities in other areas. This has resulted in
- the following additional non-PostScript abilities for the Draw module:
-
- (a) Choice of fill style - e.g. fill including/excluding boundary, fill to
- halfway through boundary, fill exterior, etc.
- (b) "Positive winding number" and "negative winding number" rules as well
- as PostScript's "non-zero winding number" and "even-odd winding number"
- rules.
- (c) Line cap enhancements - particularly differing "leading" and "trailing"
- line caps and triangular line caps (together, these allow arrowed lines
- and similar effects).
-
- Any program which wants to remain PostScript-compatible (which includes e.g.
- working with printer drivers) will of course have to avoid using these
- enhancements.
-
-
- Draw_Fill, Draw_FillFP
- ======================
-
- These imitate the PostScript "fill" operator - i.e. they close open subpaths,
- flatten the path, transform it to standard co-ordinates, fix it if the call
- is Draw_FillFP and fill the result.
-
- "Closing open subpaths" means adding a path element of type 5 ("close with
- line") to the end of any open subpaths in the path.
-
- "Flattening" a path means bisecting any Bezier curves it contains
- recursively, at least until each of the resulting Bezier curves lies
- completely within a specified distance of the line segment joining its
- endpoints, and then replacing each such of the resulting Bezier curves by the
- line segment joining its endpoints. The specified distance is called the
- "flatness".
-
- Entry: R0 points to the path.
-
- R1 contains the fill style:
-
- Bits 0,1: 0 = non-zero winding number rule;
- 1 = negative winding number rule;
- 2 = even-odd winding number rule;
- 3 = positive winding number rule;
- Bit 2: Set if non-boundary exterior pixels are to be
- plotted, clear if they are not;
- Bit 3: Set if boundary exterior pixels are to be plotted,
- clear if they are not;
- Bit 4: Set if boundary interior pixels are to be plotted,
- clear if they are not.
- Bit 5: Set if non-boundary interior pixels are to be
- plotted, clear if they are not;
- Bits 6-31 are reserved and should be zero.
-
- R1=0 is a special case. According to the above, it means "don't
- fill anything, non-zero rule" - a pretty useless operation. For
- convenience, it specifies a sensible default fill style, namely
- &30 (i.e. "fill to halfway through boundary, non-zero rule").
-
- R2 points to the matrix, held as 6 words in memory (in the order
- a,b,c,d,e,f for the matrix above); R2=0 means the identity
- matrix. Note that the code assumes that one user-defined unit is
- a small fraction of a pixel, and matrices that multiply
- distances by large factors may lead to inaccurate results.
-
- R3 contains the flatness, in user co-ordinates; R3=0 means default
- flatness.
-
- Exit: R0 is corrupt (if V clear),
- or points to error block (if V set).
-
- R1-R11 preserved.
-
- Some of the terms used above need defining. Briefly, pixels whose centres lie
- inside the path according to the winding number rule chosen are interior
- pixels, and pixels that would be plotted if the (flattened) path were plotted
- with thin line segments (i.e. 1 pixel wide line segments) are boundary
- pixels. If you are happy with these definitions, skip down to the section on
- Draw_Stroke. If you want more precise details, read on...
-
- To determine whether a pixel is an "interior" pixel, calculate the winding
- number W of the path around the central point of the pixel. The pixel is then
- an interior pixel if:
-
- * the non-zero winding number rule is selected and W <> 0.
- * the negative winding number rule is selected and W < 0.
- * the even-odd winding number rule is selected and W is odd.
- * the positive winding number rule is selected and W > 0.
-
- Otherwise, the pixel is an exterior pixel.
-
- Lines (including flattened Bezier curves) and gaps both contribute to the
- winding number calculation, provided the subpath that contains them started
- with an "move to" path element of type 2. Those in subpaths which started
- with a "move to" path element of type 3 are ignored.
-
- To determine whether a pixel is a "boundary" pixel, consider the "diamond"
- that can be inscribed in the pixel by joining the centres of its sides. If a
- line (or part of a flattened Bezier curve, but not a gap) in the path passes
- through this "diamond", the pixel is a boundary pixel. Otherwise, it is a
- non-boundary pixel.
-
- For the purposes of all the calculations above, regard the path as consisting
- of mathematical (i.e. infinitely thin) line segments. If e.g. a pixel centre
- or a vertex of a "diamond" lies precisely on the path, resolve the problem by
- regarding the path as lying very slightly to the right of its real position.
- If this doesn't help (because the line segment involved is exactly
- horizontal), regard it as lying very alightly above its real position.
-
-
- Draw_Stroke, Draw_StrokeFP
- ==========================
-
- These emulate the PostScript "stroke" operator - i.e. they:
-
- (a) flatten the path;
- (b) apply a dash pattern to the path;
- (c) thicken the path, using the current line joins and caps;
- (d) re-flatten the path if the specified thickness is non-zero;
- (e) transform the path to standard co-ordinates;
- (f) fix the path if the call is Draw_StrokeFP;
- (g) fill the resulting path.
-
- "Applying a dash pattern to a path" means replacing the line segments it
- containns by an appropriate sequence of lines and dashes, determined from the
- dash pattern and the distance along the path from the start of the current
- line segment to the start of the line segment. It is not possible to apply a
- dash pattern to a path containing a Bezier curve.
-
- "Thickening" a path means:
-
- (a) If the thickness is zero, converting all "move to" path elements of
- type 2 to "move to" path elements of type 3, and otherwise leaving the
- path unchanged. Line caps and joins are ignored.
- (b) If the thickness is non-zero, expanding each line segment in the path
- to a subpath defining a rectangle centred on the original line segment
- and of width equal to the specified thickness and expanding endpoints
- of line segments to subpaths defining appropriately sized and shaped
- caps and joins. Joins are used at common endpoints of two adjacent line
- segments. Caps are used at other endpoints, with the leading or
- trailing cap style being used depending on whether the endpoint
- concerned is a leading or trailing endpoint as the path is traversed.
-
- It is not possible to thicken a path with non-zero thickness if it contains a
- Bezier curve.
-
- Except in the special case of the line width being 0 (which means that as
- thin a path as possible is plotted, with line caps and joins being ignored),
- thickening the path is likely to result in a path that winds multiply around
- some pixels and/or in multiple plotting of some pixels. It is therefore
- inadvisable to use winding number rules other than the non-zero one, or
- non-idempotent colour operations (e.g. EOR). It is also inadvisable to try
- plotting the non-boundary exterior pixels. The on-screen results of doing any
- of these will probably not be what you expect!
-
- Entry: R0 points to the path.
-
- R1 contains the fill style, as for Draw_Fill, except that R1=0 has a
- slightly different interpretation. If the line width is non-zero,
- it means &30 as above. If the line width is zero, it means &18
- (i.e. "fill boundary"), as the flattened and thickened path will
- in fact have no interior in this case! For zero width lines, the
- default fill style is usually the only sensible one.
- In addition, the top bit of R1 can be set to require the Draw
- module to plot the stroke all at once (i.e. using the "plot
- normally" option of Draw_ProcessPath rather than the "plot subpath
- by subpath" option). The main effects of this change are that the
- code will never double-plot a pixel, but also that it uses more
- workspace - possibly quite a lot more!
-
- R2 points to the matrix or contains 0, as for Draw_Fill.
-
- R3 contains the flatness or contains 0, as for Draw_Fill.
-
- R4 contains the line thickness, or 0 for a thin stroke (one pixel
- wide, with line caps and joins being ignored).
-
- R5 points to a line cap and join specification, which is a word-
- aligned four word area containing:
-
- Offset 0: Byte 0 holds join style:
- 0 = mitered joins;
- 1 = round joins;
- 2 = bevelled joins.
- Byte 1 holds leading cap style:
- 0 = butt caps;
- 1 = round caps;
- 2 = projecting square caps;
- 3 = triangular caps.
- Byte 2 holds trailing cap style, with the same
- allowed values as for leading caps.
- Byte 3 is reserved and should be zero.
- Offset 4: This holds a parameter associated with joins. For
- mitered joins, this is the miter limit. It is not
- used for the other join types. Note that the miter
- limit is a dimensionless quantity and so (for
- Draw_Stroke) is a fixed point number with 16 binary
- places.
- Offset 8: This holds a parameter associated with leading caps.
- For triangular caps, this contains two 16 bit
- unsigned numbers, each of which should be regarded as
- having 8 binary places. The most significant part of
- the number specifies how many line widths the cap
- goes beyond the end of the line, and the least
- significant part how many line widths it goes to the
- side of the centre of the line. Thus e.g. &1000100
- means a cap going 1 line width beyond the end of the
- line and 1 line width to each side of its centre -
- i.e. the cap width is twice the line width, and its
- shape is a 45/90/45 degree triangle. This parameter
- is not used for the other cap styles.
- Offset 12: This holds a similar parameter associated with
- trailing caps.
-
- The module will make no attempt to read the last three words if
- the corresponding cap or join style does not use them, so it is
- legitimate to use a smaller area than four words if these
- parameters are not required.
-
- R6 points to a dash pattern, or contains 0 if an undashed line is
- required. A dash pattern must be word-aligned and has the
- following format:
-
- Offset 0: Distance into the dash pattern to start.
- Offset 4: Number N of elements in the dash pattern.
- Offsets 8 to 4N+4: Elements of the dash pattern, each of which
- is a distance.
-
- The dash pattern starts with a dash of length equal to the first
- element above, then a gap of length equal to the second element
- above, etc. When the last element of the dash pattern has been
- used, the module starts again from the beginning. Note that if the
- number of elements of the dash pattern is odd, the distances will
- be interpreted differently the second time through, with the first
- element being a gap, the second a dash, etc.
-
- Exit: R0 is corrupt (if V clear),
- or points to error block (if V set).
-
- R1-R11 preserved.
-
-
- Draw_StrokePath, Draw_StrokePathFP
- ==================================
-
- Entry: R0, R2-R6 set as for Draw_Stroke.
-
- R1 points to a word-aligned output buffer (which holds words 0, N,
- then N free bytes), or contains 0 to ask for the required output
- buffer size (i.e. N+8).
-
- Exit: If V set, R0 points to an error block.
-
- If V clear and R1 was non-zero on entry, the output path has been
- inserted into the buffer, ending with an end of path indicator (i.e.
- words 0, N, where N is the number of free bytes following in the
- buffer). R0 points to this end of path indicator (and so is a
- suitable output buffer value for a subsequent path generating call
- that is to append to the path).
-
- If V clear and R1 was zero, R0 holds the required length.
-
- R1-R11 preserved.
-
- This call puts the given path through all the stages done by Draw_Stroke or
- Draw_StrokeFP above, except the final fill. It then either saves the path
- that would be filled in a specified buffer or reports on how big a buffer is
- required, as requested.
-
-
- Draw_FlattenPath, Draw_FlattenPathFP
- ====================================
-
- Entry: R0 points to the input path.
-
- R1 points to a word-aligned output buffer (which holds words 0, N,
- then N free bytes), or contains 0 to ask for the required output
- buffer size (i.e. N+8).
-
- R2 contains the flatness, or 0 if the default flatness is to be used.
-
- Exit: If V set, R0 points to an error block.
-
- If V clear and R1 was non-zero, the output path has been inserted
- into the buffer, ending with an end of path indicator (i.e. words 0,
- N, where N is the number of free bytes following in the buffer). R0
- points to this end of path indicator.
-
- If V clear and R1 was zero, R0 holds the required length.
-
- R1-R11 preserved.
-
- This call flattens the given path. It then either saves the resulting path in
- a specified buffer or reports on how big a buffer is required, as requested.
-
-
- Draw_TransformPath, Draw_TransformPathFP
- ========================================
-
- Entry: R0 points to the input path.
-
- R1 points to a word-aligned output buffer (which holds words 0, N,
- then N free bytes), or contains 0 to transform the path in situ.
-
- R2 points to the matrix or contains 0, as for Draw_Fill.
-
- R3 is zero for fixed point output, &80000000 for floating point
- output. All other values are reserved.
-
- Exit: If V set, R0 points to an error block.
-
- If V clear and R1 was 0, R0 is corrupt.
-
- If V clear and R1 pointed to an output buffer, the output path has
- been inserted into the buffer, ending with an end of path indicator
- (i.e. words 0, N, where N is the number of free bytes following in
- the buffer). R0 points to this end of path indicator.
-
- R1-R11 preserved.
-
- This call puts the path through a transformation matrix and possibly fixes or
- floats it. It then either outputs the resulting path to a specified output
- buffer or puts it into the memory originally occupied by the input path.
- (Note that this call will never change the length of the path or indeed of
- any of its components. This last option is therefore safe - something which
- was not true for the two preceding calls.)
-
-
- Draw_ProcessPath, Draw_ProcessPathFP
- ====================================
-
- This allows a path to be put through a general set of the processes used when
- doing Stroke or Fill. One or more of the following can be requested, in the
- order given:
-
- (a) close open subpaths;
- (b) flatten the path;
- (c) apply a dash pattern to the path;
- (d) thicken the path;
- (e) re-flatten the path;
- (f) transform the path by a matrix;
- (g) fix a floating point path or float a fixed point one;
- (h) output the resulting path by one of six techniques:
- (i) output to a specified output buffer;
- (ii) count how long an output buffer is required for the given path
- and operations.
- (iii) fill the path normally - not legitimate for a floating point
- path;
- (iv) fill the path subpath by subpath (this option saves workspace and
- can sometimes be used legitimately - for example, Draw_Stroke
- will often use it). Also not legitimate for a floating point path.
- (v) output to the input buffer (i.e. modify the path in situ). Only
- valid if the path's length cannot be changed by the call - i.e.
- if steps (a) to (e) above are not requested.
- (vi) output the path's bounding box, in transformed co-ordinates. This
- bounding box does not pay attention to pixel boundaries and is
- "inclusive" on all sides.
-
- All combinations of these are allowed, other than the exceptions noted above.
- However, some are likely to produce errors (e.g. thickening a non- flattened
- path) and others are likely to produce strange results (e.g. filling a path
- containing open subpaths).
-
- All the calls above (Draw_Fill, etc.) translate into specific calls to
- Draw_ProcessPath or Draw_ProcessPathFP: they are provided to ensure that
- suitable names exist for common operations and to reduce the number of
- registers requiring setting up and/or preserving.
-
- Entry: R0 points to the input path.
-
- R1 contains a fill style in its bottom 6 bits, as for Draw_Fill,
- except that R1=0 has no special meaning. Other bits have the
- following meanings:
-
- Bits 6-26 are reserved and should be zero.
- Bit 27: set if open subpaths are to be closed (step (a) above).
- Bit 28: set if the path is to be flattened initially (step (b)
- above).
- Bit 29: set if the path is to be thickened (step (d) above).
- Bit 30: set if path is to be re-flattened (step (e) above).
- Bit 31: set if output path should be floating point, clear if
- it should be fixed point (step (g) above).
-
- R2 points to a matrix, or contains 0 if no transformation by a matrix
- is to be done (step (f) above).
-
- R3 contains the flatness, or 0 for the default flatness (used in
- steps (b) and (e) above).
-
- R4 contains the line thickness (used in step (d) above). R5 points to
- a line join and cap specification (used in step (d) above).
-
- R6 points to a dash pattern, or contains 0 if the path is not to be
- dashed (step (c) above).
-
- R7 points to a word-aligned output buffer (which holds words 0, N,
- then N free bytes), or contains one of the following special
- values:
-
- 0: output to the input path. This will only be accepted if the
- requested operations on the path are ones that cannot change
- its length - i.e. transforming the path by a matrix and
- fixing or floating it.
- 1: fill the path normally.
- 2: fill the path subpath by subpath.
- 3: count the size of output buffer required.
- &80000000+address: output the bounding box of the processed path
- to the (word-aligned) address and the three following words,
- in the order lowX, lowY, highX, highY. Note: if this option
- is applied to an non-flat path, a valid but non-minimal
- bounding box will be produced.
-
- Exit: R1-R11 preserved.
-
- If V set, R0 points to an error block.
-
- If V clear:
- If R7 was 0, 1 or 2 on entry, R0 is corrupt.
- If R7 was 3 on entry, R0 holds the size of output buffer required
- (i.e. N+8 if the output buffer should be words 0, N, followed
- by N free bytes).
- If R7 pointed to an output buffer, the output path will have been
- inserted into the buffer and R0 points to the new end of path
- indicator.
-
-
- The Draw module vector DrawV
- ============================
-
- This provides a means of indirecting the calls above.
-
- Entry: R0-R7 hold values appropriate for the call concerned.
- R8 specifies which call is involved:
- 0: Draw_ProcessPath
- 1: Draw_ProcessPathFP
- 2: Draw_Fill
- 3: Draw_FillFP
- 4: Draw_Stroke
- 5: Draw_StrokeFP
- 6: Draw_StrokePath
- 7: Draw_StrokePathFP
- 8: Draw_FlattenPath
- 9: Draw_FlattenPathFP
- 10: Draw_TransformPath
- 11: Draw_TransformPathFP
-
- Exit: R0 holds a suitable return value.
- V set or clear as appropriate.
- R1-R11 corrupt.
-