cunniff@hpfcso.HP.COM (Ross Cunniff) (12/13/89)
Here is a revised DR2D format that responds to some of the comments posted here or e-mailed. The changes include: * Object attributes (fill color, etc.) are now more IFF-like * It uses the FTXT FONS chunk for font information * Nested objects (groups) are now more IFF-like * ProVector specific chunks are no longer documented here * Arrowhead attributes have been added * Bounding box information is optional * The limit of 256 fill and edge colors has been removed (it is now 65536) * Layer description information has been added * Line dash patterns are no longer hard coded (i.e. they are configurable/modifiable) The single change which some people have requested that is NOT here is: coordinates are still in IEEE format. The arguments for changing them are: * Hard to read and parse not true; see my previous response on this where I give a 20-line C routine to convert to fixed-point notation * Integers are more natural debatable; anyway, a program can decide to convert to integers if it wants to * Would require two passes over the file to decide which scaling factor to use for integers not true, the DRHD chunk has bounding box information which can be used to determine a suitable scaling factor * Integers are more flexible; they have a greater precision; you could have a project-wide scaling factor for them Integers do potentially have a greater precision; however, remember that this is an INTERCHANGE format. Consider Project A, with a scaling factor of 1,000,000 and Project B with a scaling factor of 100. Consider cut-and-paste between the projects. If you cut from project B, you can have objects that WILL NOT FIT in the range of Project A. If you cut from Project A, you can have objects that will resolve to singularities in the range of Project B. "Ah," you say, "What if each object has its own scaling factor?" to which I would reply "Let's just take it all the way; each coordinate has its own scaling factor. Oops, that is what a floating point number IS..." Anyway, here is the revised format: 89/12/10 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'. Please address questions and comments to: Ross Cunniff Taliesin, Inc. P.O. Box 1671 Fort Collins, CO 80522 (303) 484-7321 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; IEEE XMin, YMin, /* Minimum and maximum */ XMax, YMax; /* coordinates of the drawing area */ }; /* The following are global project properties */ 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 */ }; FILL (0x46494C4C) /* Object-oriented fill pattern */ /* See note 3 */ struct FILLstruct { ULONG ID; ULONG Size; USHORT FillID; /* ID of the fill */ USHORT NumObjs; /* Number of objects in 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 */ 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 { 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; /* Which 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 */ RAST (0x52415354) /* Raster image */ struct RASTstruct { ULONG ID; ULONG Size; IEEE XPos, YPos, /* Virtual coords */ XSize, YSize; /* Virtual size */ SHORT NumX, NumY, Depth; /* Actual size */ UBYTE Colors[3*(1<<Depth)]; /* Color map */ UBYTE Closest[(1<<Depth)]; /* Closest equivs in CMAP */ #define RSIZE(x,y,d) ((x+15)/16)*y*d USHORT Rast[RSIZE(NumX,NumY,Depth)]; /* Lookups into Colors*/ }; 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. */ TEXT (0x54455854) /* A text string */ struct TEXTstruct { ULONG ID; ULONG Size; USHORT 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]; }; 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_SPLINE 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_SPLINE ) { /* The next 4 points are BSpline control points */ if( FirstPoint ) MoveTo( PolyPoints[2*i + 2], PolyPoints[2*i + 3] ); else LineTo( PolyPoints[2*i + 2], PolyPoints[2*i + 3] ); SplineTo( 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 { ... } } } 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! . .................
filbo@gorn.santa-cruz.ca.us (Bela Lubkin) (12/17/89)
In article <9310006@hpfcso.HP.COM> Ross Cunniff writes: >Here is a revised DR2D format that responds to some of the comments >posted here or e-mailed. The changes include: [...] >The single change which some people have requested that is NOT here is: >coordinates are still in IEEE format. The arguments for changing them are: > > * Hard to read and parse > not true; see my previous response on this where I give > a 20-line C routine to convert to fixed-point notation [...] Ross, I think you miss the point of this argument. >*It is not always POSSIBLE to insert an arbitrary 20 lines of C code*< into a program. Where does this leave programmers who are writing in BASIC, Forth, Lisp, ARexx, database languages, etc.? There are some now, there will be more later, programs and programming languages that have built-in tools for manipulating IFF structures but which have no support either for IEEE number formats OR bit-twiddling. Up to now the IFF spec has been kept free of floating point. Whatever your arguments for it, they are not as strong as that. Here is one line of C code to translate from integer to IEEE: coordinate=icoordinate*scalefactor; Bela Lubkin * * // filbo@gorn.santa-cruz.ca.us CI$: 73047,1112 (slow) @ * * // belal@sco.com ..ucbvax!ucscc!{gorn!filbo,sco!belal} R Pentomino * \X/ Filbo @ Pyrzqxgl +408-476-4633 and XBBS +408-476-4945