[comp.sys.amiga.tech] IFF FORM DR2D for structured graphics

cunniff@hpfcso.HP.COM (Ross Cunniff) (10/24/89)

89/10/03

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).  Note that most chunks have
both a chunk Size and an object Count.  I know this is redundant;
however, this allows the data structures to be extended in a
compatible manner if it should become necessary in the far future.
Please address questions and comments to:

			Ross Cunniff
			...{ucbvax,hplabs}!hpfcla!cunniff
			cunniff%hpfcrt@hplabs.HP.COM
			(303)-229-4644 -or- (303)-482-6077

(or you can post reponses here...)


FORM (0x464F524D)	/* All drawings are a FORM */

	struct FORMstruct {
	    LONG	ID;
	    LONG	Size;		/* Total size of the file	*/
	};


DR2D (0x44523244)	/* ID of 2D drawing */

DRHD (0x44524844)	/* Drawing header */

	struct DRHDstruct {
	    LONG	ID;
	    LONG	Size;		/* Always 18 */
	    IEEE	p_xmin, p_ymin,	/* Minimum and maximum */
			p_xmax, p_ymax;	/*   coordinates of the drawing area */
	};

CMAP (0x434D4150)	/* Color map */

	struct CMAPstruct {
	    LONG	ID;
	    LONG	Size;		/* Usually 256*3, or 768 */
#define			NUMCOLOR(Size)	(Size / 3)
	    UBYTE	ColorMap[NUMCOLOR(Size)][3];
	};

PREF (0x50524546)	/* Application preferences */

	struct PREFstruct {
	    LONG	ID;
	    LONG	Size;
	    SHORT	NumPrefs;
	    UBYTE	PrefStrings[Size - 2];
	};
	/* PrefStrings is an array containing strings of the form

		name=value

	   The strings are null-separated in the array.
	   Other applications may safely ignore this chunk,
	   although it is requested that applications that
	   manipulate DR2D files do not delete preferences
	   settings that they do not understand.  Some possible
	   settings include:

		DATE=10/28/88
		COPYRIGHT=Copyright 1989 by Taliesin, Inc.
		PROGRAM=ProVector
		ARTIST=Ross Cunniff
		LMARGIN=1 inch
		ORIENT=portrait
		ZOOM=1.0 1.0 2.0 2.0
	*/


PATT (0x50415454)	/* 8x8 bitmap fill patterns */ /* OBSOLETE */

	struct PATTstruct {
	    LONG	ID;
	    LONG	Size;		/* 2 + 10*NumPatts */
	    SHORT	NumPatts;	/* Typically 16 */
	    UBYTE	Patterns[NumPatts][10];
	};

	/* The 10 bytes of the patterns are arranged as follows:
	     The first byte is the foreground color of the pattern
	     The second byte is the background color of the pattern
	     The next 8 bytes are the actual rows of the pattern;
		the leftmost pixel in a row is 0x80, the rightmost
		is 0x01. */

FONT (0x464F4E54)	/* Font table */

	struct FONTstruct {
	    LONG	ID;
	    LONG	Size;
	    SHORT	NumFonts;
	    CHAR	FontNames[Size-2];
	};
	/* FontNames is an array containing the names of all the fonts
	   used in this drawing.  The names are stored as null-separated
	   strings. */

FILL (0x46494C4C)	/* Object-oriented fill pattern table */

	struct FILLstruct {
	    LONG	ID;
	    LONG	Size;		/* 2 + sum(sizeof(Patterns)) */
	    SHORT	NumPatts;	/* Typically 16 */
	    CHAR	Patterns[NumPatts];	/* See note 4 */
	};

	/* An object-oriented fill pattern consists of an arbitrary
	   number of objects.  The objects are tiled across the
	   bounding box of the filled object, and clipped to the
	   boundaries of that object. */


DSYM (0x4453594D)	/* Define a symbol (NOT IMPLEMENTED) */

	struct DSYMstruct {
	    LONG	ID;
	    LONG	Size;
	    SHORT	SymbID;			/* Unique ID for this symbol */
	    SHORT	NumObjs;
	    UBYTE	SymbChunk[Size-4];	/* See note 4 */
	};


SYMB (0x53594D42)	/* Use a symbol (NOT IMPLEMENTED) */

	struct SYMBstruct {
	    LONG	ID;
	    LONG	Size;			/* Always 22	*/
	    SHORT	SymbID;			/* Which symbol	*/
	    USHORT	WhichLayer;		/* Which layer it's in */
	    IEEE	XPos, YPos,		/* Where to put it */
			XMag, YMag,		/* How big should it be? */
			Rotation;		/* Angle of rotation */
	};

RAST (0x52415354)	/* Raster image */

	struct RASTstruct {
	    LONG	ID;
	    LONG	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 */

	/* Various fill types */
	#define FT_NONE		0	/* No fill			*/
	#define FT_COLOR	1	/* Fill with color from palette */
	#define FT_BITMAP	2	/* Fill with bitmap pattern	*/
	#define FT_OBJECTS	3	/* Fill with objects [see note 4]) */

	/* Various edge types */
	#define ET_MASK		0x07	/* Mask for edge types */
	#define ET_NONE		0x00	/* No edges		*/
	#define ET_SOLID	0x01	/* Solid lines		*/
	#define ET_DASH		0x02	/* Dashed lines		*/
	#define ET_DOT		0x03	/* Dotted lines		*/
	#define ET_DOT_DASH	0x04	/* dot-dash-dot-dash	*/

	/* Arrow head types (NOT IMPLEMENTED) */
	#define AT_MASK		0x18	/* Mask for arrow types */
	#define AT_NONE		0x00	/* No arrowheads	*/
	#define AT_FIRST	0x08	/* Arrowhead on first vertex */
	#define AT_LAST		0x10	/* Arrowhead on last vertex */
	#define AT_BOTH		0x18	/* Arrows on first and last vertices */

	/* Join types */
	#define JT_MASK		0x60	/* Mask for join types */
	#define JT_MITER	0x20	/* Mitered join */
	#define JT_BEVEL	0x40	/* Beveled join */
	#define JT_ROUND	0x60	/* Round join */

	/* Unused bits */
	#define ET_UNUSED	0x80	/* Should always be zero */

	typedef struct {
	    UBYTE	FillType;	/* One of FT_*, above	*/
	    UBYTE	FillValue;	/* See note 3		*/
	    UBYTE	EdgeType;	/* One of ET_*, above	*/
	    UBYTE	EdgeValue;	/* Edge color index	*/
	    USHORT	WhichLayer;	/* Which layer it's in	*/
	    IEEE	EdgeThick;	/* Line width		*/
	    IEEE	XMin, YMin,	/* Bounding box of obj. */
			XMax, YMax;	/* including line width	*/
	} ObjHdr;	/* Size == 26 */

	struct POLYstruct {
	    LONG	ID;
	    LONG	Size;		/* 28 + 4*NumPoints */
	    ObjHdr	Styles;
	    SHORT	NumPoints;
	    IEEE	PolyPoints[NumPoints]; /* See note 2 */
	};



GRUP (0x47525550)	/* Group */

	struct GROUPstruct {
	    LONG	ID;
	    LONG	Size;
	    ObjHdr	Info;		/* The style stuff isn't used */
	    SHORT	NumObjs;
	    UBYTE	GroupChunk[Size-28];	/* See note 4 */
	};

XTRN (0x4554524E)	/* Externally controlled group */

	/* Flags for application callbacks */
	#define X_MOVE		0x0001	/* 'appl optr move dx dy' */
	#define	X_CLONE		0x0002	/* 'appl optr clone dx dy' */
	#define	X_DELETE	0x0004	/* 'appl optr del' */
	#define	X_ROTATE	0x0008	/* 'appl optr rot cx cy angle' */
	#define	X_RESIZE	0x0010	/* 'appl optr size cx cy sx sy' */
	#define X_CUT		0x0020	/* 'appl optr cut' */
	#define X_COPY		0x0040	/* 'appl optr copy' */
	#define X_PASTE		0x0080	/* 'appl optr paste x y' */

	struct XTRNstruct {
	    LONG	ID;
	    LONG	Size;
	    ObjHdr	Info;
	    SHORT	NumObjs;
	    SHORT	ApplCallBacks;		/* See definitions above */
	    SHORT	ApplNameLength;		/* Should ALWAYS be padded */
	    char	ApplName[ApplNameLength];
	    UBYTE	GroupChunk[Size-32-ApplNameLength];
	};

TEXT (0x54455854)	/* A text string */

	struct TEXTstruct {
	    LONG	ID;
	    LONG	Size;		/* 34 + NumChars + NumChars%2 */
	    ObjHdr	Styles;
	    SHORT	WhichFont;	/* Index into font table */
	    IEEE	CharW, CharH,	/* W/H of an individual char	*/
			BaseX, BaseY,	/* Start of baseline */
			Rotation;	/* Angle of text (in radians) */
	    SHORT	NumChars;
	    char	TextChars[NumChars];
	    UBYTE	PAD[NumChars%2];/* Padding to make Size even */
	};


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: The actual fill of one of these objects is done as follows:

	switch( FillType ) {
	case FT_NONE :
	    SetNoFill();
	    break;
	case FT_COLOR :
	    SetSolidFill( Palette[FillValue] );
	    break;
	case FT_BITMAP :
	    SetSolidFill( Bitmaps[FillValue] );
	    break;
	case FT_OBJECTS :
	    SetObjFill( FillPats[FillValue] );
	    break;
	}

	Note also that on most pen plotters, FT_LINES and FT_NONE
	are the only meaningful fills, and other fills may be
	rendered as FT_NONE.


NOTE 4: The  data in a FILL,  DSYM  or  GRUP chunk is a series of nested
	object chunks.  All object chunks except DSYM, CMAP, PATT, FILL,
	and FONT are allowed in a DSYM or GRUP.