90/08/24 The following is the format of the DR2D IFF FORM file produced by ProVector, a 2-dimensional structured graphics program. Each chunk is described by first giving the chunk ID (both in ASCII and in hex) and then giving the structure associated with the chunk, as well as any extra definitions that make sense. Coordinates are specified in IEEE format (see note 1 for a description of the IEEE format). It is assumed that these 'drawings' are on white 'paper'. FORM (0x464F524D) /* All drawings are a FORM */ struct FORMstruct { ULONG ID; ULONG Size; /* Total size of the file */ }; DR2D (0x44523244) /* ID of 2D drawing */ DRHD (0x44524844) /* Drawing header */ struct DRHDstruct { ULONG ID; ULONG Size; /* Always 18 */ IEEE XLeft, YTop, XRight, YBot; }; /* The point [XLeft,YTop] defines the virtual coordinates of the upper left corner of the project. The point [XRight,YBot] defines the virtual coordinates of the lower right corner of the project. If XLeft < XRight, the X-axis increases toward the right. If YTop < YBot, the Y-axis increases toward the bottom. Other combinations are possible; for example, in Cartesian coordinates, XLeft would be less than XRight but YTop would be GREATER than YBot. */ /* The following are global project properties */ PPRF (0x50505249) /* Page preferences */ struct PPRFstruct { ULONG ID; ULONG Size; char Prefs[Size]; }; /* The Prefs are a list of null-terminated strings. The currently supported strings are: Units= Portrait= PageType= GridSize= where: is one of Inch, Cm, or Pica is one of True or False is one of Standard, Legal, B4, B5, A3, A4, A5, or Custom is a floating-point number It is not required that programs understand this chunk; it is mostly for the convenience of ProVector. */ CMAP (0x434D4150) /* Color map */ /* Same as ILBM CMAP */ struct CMAPstruct { ULONG ID; ULONG Size; UBYTE ColorMap[Size]; }; FONS (0x464F4E53) /* Font for text */ /* Same as FTXT.FONS */ struct FONSstruct { ULONG ID; ULONG Size; UBYTE FontID; /* ID it's called */ UBYTE Pad1; /* Always 0 */ UBYTE Proportional; /* Is it proportional? */ UBYTE Serif; /* Has it serifs? */ CHAR Name[Size-4]; /* The name of the font */ }; DASH (0x44415348) /* Line dash pattern for edges */ struct DASHstruct { ULONG ID; ULONG Size; USHORT DashID; /* Name of the dash pattern */ USHORT NumDashes; /* Should always be even */ IEEE Dashes[NumDashes]; /* On-off pattern */ }; /* The numbers in the dash patterns are relative to the line weight. The dash pattern {1.0,0.0} will always yield a dotted line with the dots as long as they are tall. By convention, DashID 0 is reserved to mean 'No line pattern at all', i.e. the edges are invisible. This DASH pattern should NOT appear in a DR2D FORM. Again by convention, a NumDashes of 0 means that the line is solid. */ AROW (0x41524F57) /* An arrow-head pattern */ #define ARROW_FIRST 0x01 /* Draw an arrow on the first point */ #define ARROW_LAST 0x02 /* Draw an arrow on the last point */ struct AROWstruct { ULONG ID; ULONG Size; UBYTE Flags; /* Flags, from ARROW_*, above */ UBYTE Pad0; /* Should always 0 */ USHORT ArrowID; /* Name of the arrow head */ USHORT NumPoints; IEEE ArrowPoints[NumPoints]; /* See note 2 */ }; /* The ArrowPoints are the points of a CPLY in the SAME coordinate system as the rest of the project. Note that the (0,0) point of the coordinate system coincides with the appropriate endpoint of the OPLY that this arrow is attached to. The arrow head should be drawn facing right, so that the appropriate rotation may be applied to it before rendering. */ FILL (0x46494C4C) /* Object-oriented fill pattern */ /* See note 3 */ struct FILLstruct { ULONG ID; ULONG Size; USHORT FillID; /* ID of the fill */ }; LAYR (0x4C415952) /* Define a layer */ #define LF_ACTIVE 0x01 /* Active for editing */ #define LF_DISPLAYED 0x02 /* Displayed on the screen */ struct LAYRstruct { ULONG ID; ULONG Size; USHORT LayerID; /* ID of the layer */ char LayerName[16]; /* Null terminated and padded */ UBYTE Flags; /* Flags, from LF_*, above */ UBYTE Pad0; /* Always 0 */ }; /* The following sets object attributes for the next object(s). The attributes are in effect until the next ATTR chunk is found, or until the end of the enclosing FORM, whichever comes first. */ ATTR (0x41545452) /* Object attributes */ /* Various fill types */ #define FT_NONE 0 /* No fill */ #define FT_COLOR 1 /* Fill with color from palette */ #define FT_OBJECTS 2 /* Fill with tiled objects */ /* Join types */ #define JT_NONE 0 /* Don't do line joins */ #define JT_MITER 1 /* Mitered join */ #define JT_BEVEL 2 /* Beveled join */ #define JT_ROUND 3 /* Round join */ struct ATTRstruct { ULONG ID; ULONG Size; UBYTE FillType; /* One of FT_*, above */ UBYTE JoinType; /* One of JT_*, above */ UBYTE EdgePattern; /* ID of edge dash pattern*/ UBYTE ArrowHeads; /* ID of arrowhead to use */ USHORT FillValue; /* Color or object with which to fill */ USHORT EdgeValue; /* Edge color index */ USHORT WhichLayer; /* ID of layer it's in */ IEEE EdgeThick; /* Line width */ }; BBOX (0x42424F48) /* Bounding box of the next object in the FORM */ struct BBOXstruct { ULONG ID; ULONG Size; IEEE XMin, YMin, /* Bounding box of obj. */ XMax, YMax; /* including line width */ }; /* This chunk is ONLY in effect for the NEXT object in the FORM. Note that a BBOX may apply to a FILL or an AROW. */ /* The following are object definitions */ VBM (0x56424D20) /* Virtual BitMap */ struct VBMstruct { IEEE XPos, YPos, /* Virtual coords */ XSize, YSize, /* Virtual size */ Rotation; /* Ignored for now... */ USHORT PathLen; /* Length of dir path */ char Path[PathLen]; /* Null-terminated path of file */ }; CPLY (0x43504C59) /* Closed polygon */ OPLY (0x4F504C59) /* Open polygon, i.e. line segments */ struct POLYstruct { ULONG ID; ULONG Size; USHORT NumPoints; IEEE PolyPoints[2*NumPoints]; /* See note 2 */ }; GRUP (0x47525550) /* Group */ /* See note 3 */ struct GROUPstruct { ULONG ID; ULONG Size; USHORT NumObjs; }; /* NOTE that for GRUPs, the Layer information of the GRUP FORM overrides the Layer information of the nested objects. */ STXT (0x53545854) /* Simple text */ struct STXTstruct { ULONG ID; ULONG Size; UBYTE Pad0; /* Always 0 (for future expansion) */ UBYTE WhichFont; /* Which font to use */ IEEE CharW, CharH, /* W/H of an individual char */ BaseX, BaseY, /* Start of baseline */ Rotation; /* Angle of text (in radians) */ USHORT NumChars; char TextChars[NumChars]; }; TPTH (0x54505448) /* A text string along a path */ struct TPTHstruct { ULONG ID; ULONG Size; UBYTE Pad0; /* Always 0 (for future expansion) */ UBYTE WhichFont; /* Which font to use */ IEEE CharW, CharH; /* W/H of an individual char */ USHORT NumChars; /* Number of chars in the string */ USHORT NumPoints; /* Number of points in the path */ char TextChars[NumChars]; /* PAD TO EVEN #! */ IEEE Path[2*NumPoints]; /* The path on which the text lies */ }; NOTE 1: IEEE represents a single-precision IEEE floating point number. These numbers consist of 32 bits, arranged as follows: +---------------+---------------+---------------+---------------+ |s e e e e e e e|e m m m m m m m|m m m m m m m m|m m m m m m m m| +---------------+---------------+---------------+---------------+ 31 24 23 16 15 8 7 0 where s is the sign bit of the entire number. If this bit is '1', the number is negative. If '0', the number is positive. e is the 8-bit exponent, in excess-127 form. This is the power of two to which the mantissa should be raised before using the number in calculations. Excess-127 means that 127 is added to the exponent before packing it into the number. An exponent of 0 here means the real exponent is actually -127. A value of 127 means the exponent is actually 0. A value of 255 means the exponenent is actually 128. m is the 23-bit mantissa. A leading binary 1 is assumed. This means that the mantissa may vary from 1.0000000 to 1.999999... The value 0.0000000 is represented by all bits being cleared to zero. Note that on many computers, the natural format of single-precision floating point numbers *IS* IEEE. This is true of the Amiga. There are system calls to transform IEEE numbers to and from Motorola FFP numbers, should your application require them. NOTE 2: The algorithm for drawing polygons is as follows: typedef union { IEEE num; LONG bits; } Coord; #define INDICATOR 0xFFFFFFFF #define IND_CURVE 0x00000001 #define IND_MOVETO 0x00000002 Coord Temp0, Temp1; int FirstPoint, i, Increment; /* Initialize the path */ NewPath(); FirstPoint = 1; /* Draw the path */ i = 0; while( i < NumPoints ) { Temp0.num = PolyPoints[2*i]; Temp1.num = PolyPoints[2*i + 1]; if( Temp0.bits == INDICATOR ) { /* Increment past the indicator */ Increment = 1; if( Temp1.bits & IND_MOVETO ) { /* Close and fill, if appropriate */ if( ID == CPLY ) { FillPath(); } else { StrokePath(); } /* Set up the new path */ NewPath(); FirstPoint = 1; } if( Temp1.bits & IND_CURVE ) { /* The next 4 points are Bezier cubic control points */ if( FirstPoint ) MoveTo( PolyPoints[2*i + 2], PolyPoints[2*i + 3] ); else LineTo( PolyPoints[2*i + 2], PolyPoints[2*i + 3] ); CurveTo( PolyPoints[2*i + 4], PolyPoints[2*i + 5], PolyPoints[2*i + 6], PolyPoints[2*i + 7], PolyPoints[2*i + 8], PolyPoints[2*i + 9] ); FirstPoint = 0; /* Increment past the control points */ Increment += 4; } } else { if( FirstPoint ) MoveTo( PolyPoints[2*i], PolyPoints[2*i + 1] ); else LineTo( PolyPoints[2*i], PolyPoints[2*i + 1] ); FirstPoint = 0; /* Increment past the last endpoint */ Increment = 1; } /* Add the increment */ i += Increment; } /* Close the last path */ if( ID == CPLY ) { FillPath(); } else { StrokePath(); } Fills are according to the even-odd rule, so 'holes' in polygons are easy to create (desirable in many cases). Most objects produced by ProVector (polygons, smoothed polygons, ellipses, rectangles, and even the rendering of indivdiual characters in fonts) are represented by this form. NOTE 3: FILL and GRUP chunks are ONLY valid inside nested DR2D FORMs. Here is an example: FORM { DR2D /* Top-level drawing... */ DRHD { ... } /* Confirmed by presence of DRHD chunk */ CMAP { ... } /* Various other things... */ FONS { ... } FORM { DR2D /* A nested form... */ FILL { 1 } /* Ah! The fill-pattern table */ CPLY { ... } /* with only 1 object */ } FORM { DR2D /* Yet another nested form */ GRUP { ..., 3 } /* Ah! A group of 3 objects */ TEXT { ... } CPLY { ... } OPLY { ... } } FORM { DR2D /* Still another nested form */ GRUP { ..., 2 } /* A GRUP with 2 objects */ OPLY { ... } TEXT { ... } } } All OBJECTS (i.e. CPLY, OPLY, TEXT, FORM { DR2D GRUP }, etc.) are allowed inside these nested FORMs, but global drawing attributes (i.e. CMAP, FILL, etc.) are not. Here is a (symbolic) DR2D form: FORM { DR2D DRHD { 0.0, 0.0, 10.0, 8.0 } CMAP { 0,0,0, 255,255,255 } FONS { 1, 0, 1, 0, "Roman" } DASH { 1, 2, {1.0, 1.0} } ATTR { 0, 0, 0, 0, 0, 0, 0, 0.0 } BBOX { 2.0, 2.0, 8.0, 6.0 } FORM { DR2D GRUP { 2 } BBOX { 3.0, 4.0, 7.0, 5.0 } TEXT { 1, 0.5, 1.0, 3.0, 5.0, 0.0, 12, "Hello, World" } BBOX { 2.0, 2.0, 8.0, 6.0 } OPLY { 5, {2.0,2.0, 8.0,2.0, 8.0,6.0, 2.0,6.0, 2.0,2.0 } } } This picture should look something like this: ................. . . . Hello, World! . .................