home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / 3_1DOCS.DMS / in.adf / tutorials.lha / tutorials / BulletLibrary < prev    next >
Encoding:
Text File  |  1993-11-04  |  59.9 KB  |  1,486 lines

  1.  
  2.         Bullet Library and Compugraphic Typefaces
  3.       (c) Copyright 1991-93 Commodore-Amiga, Inc.  All Rights Reserved
  4.  
  5. One of the improvements made to the Amiga's operating system for
  6. Workbench Release 2.1 is programmatic control of AGFA's IntelliFont
  7. scaling engine.  With this engine, application programs can fully
  8. utilize Compugraphic (CG) typefaces installed by Fountain (the CG
  9. typeface install that comes with 2.04 and 2.1).  Some of the features
  10. that the font scaling engine offers include:
  11.  
  12.    o  Rasterization of a typeface to arbitrary vertical and horizontal
  13. resolutions.
  14.    o  Baseline rotation of glyphs to an arbitrary angle.
  15.    o  Glyph shearing (italicizing) to any angle from -45 to 45 degrees
  16.       (inclusive).
  17.    o  Access to kerning tables.
  18.    o  Algorithmic emboldening.
  19.  
  20. Starting the Engine
  21.  
  22. There are several steps involved in using a font outline on the Amiga.
  23.  
  24.  
  25. 1. Open the font contents file (the ".font" file) and verify that
  26.    it has a corresponding outline tag file (an ".otag" file).
  27.  
  28. All system supported fonts on the Amiga have a font contents file.
  29. From this file, an application can determine a font's type, so the
  30. application knows how to utilize the font.  The font contents file is a
  31. FontContentsHeader structure (defined in <diskfont/diskfont.h>).  The
  32. first field of that structure (fch_FileID) contains an ID identifying
  33. the font's type.  If that type is OTAG_ID (0x0F03), the font is an
  34. outline and it should have a corresponding otag file.  The otag file
  35. should be in the same directory as the font contents file.
  36.  
  37.  
  38. 2. Open the otag file, verify that it is valid, load its tag list
  39.    into memory, and resolve any memory indirections in the tag list.
  40.  
  41. The otag file contains a tag list that describes the typeface.  All of
  42. these tags are defined in <diskfont/diskfonttag.h> as either level 1,
  43. level 2, or level 3 outline tags.  Level 1 tags are required to be
  44. present in an otag file.  Level 2 and 3 tags are optional.  See the
  45. include file for more information on the tag levels.
  46.  
  47. The first tag of the otag file is always OT_FileIdent.  Its value is
  48. the size of the otag file.  This tag is here to verify the validity of
  49. the otag file.  If the first tag is not OT_FileIdent, or the
  50. OT_FileIdent tag value is not the size of the otag file, the otag file
  51. is invalid, so don't attempt to use it.  If the file is valid, copy the
  52. entire file into a buffer.
  53.  
  54. The tags from the otag file have a special OT_Indirect bit.  If this
  55. bit is set, the tag's value is an indirect reference to data defined
  56. elsewhere in the otag file.  The tag's value is the offset to the data
  57. (in bytes) from the beginning of the otag file.  For example, the otag
  58. file fonts:CGTimes.otag that is on the 2.04 Release disks contains the
  59. tag OT_Family (0x80009003), which has its OT_Indirect bit set.  The
  60. value of the OT_Family tag is 195, meaning that the data for it--the
  61. NULL terminated string "CG Times"--is located 195 bytes into the otag
  62. file.
  63.  
  64. Of course, if an application read the file fonts:CGTimes.otag into a
  65. memory buffer, the "CG Times" string would be 195 bytes from the
  66. beginning of the buffer.  The OT_Family tag must point to the absolute
  67. address of its data, so when an application loads an otag file into
  68. memory, it has to resolve the indirection of the OT_Indirect tags in
  69. memory.  The application can do this by adding the buffer address to
  70. each OT_Indirect tag value.
  71.  
  72.  
  73. 3. Find out the name of the typeface's scaling engine and obtain a
  74.    pointer to the engine's GlyphEngine structure.
  75.  
  76. One of the level 1 outline tags is the OT_Engine tag.  This tag refers
  77. to the name of this typeface's scaling engine.  At present there is
  78. only one scaling engine available on the Amiga.  It is named Bullet.
  79. This is the IntelliFont scaling engine.  The name is left over from the
  80. original implementation of the IntelliFont engine used on the Amiga.
  81. The scaling engine itself is in its own Exec library, called
  82. bullet.library.  To open the engine, build a complete library name by
  83. adding the string ".library" to the OT_Engine string, and open it
  84. with OpenLibrary().  Don't assume that OT_Engine will always be the
  85. string "bullet."  In the future, Commodore or some third party
  86. developer may create additional scaling engines libraries that will
  87. allow the Amiga to use other types of outline typefaces (PostScript,
  88. Nimbus-Q, etc.).  Using the proper library name will help ensure
  89. compatibility with future possible scaling engines.
  90.  
  91. All scaling engine libraries contain several functions:
  92.  
  93. OpenEngine()
  94.    If successful, returns a pointer to the library's GlyphEngine structure.
  95.  
  96. CloseEngine()
  97.    Releases the GlyphEngine structure obtained in OpenEngine().
  98.  
  99. SetInfo()/SetInfoA()
  100.    Sets current parameters of a scaling engine (the current typeface,
  101. the current point size, the current output resolution, etc.)
  102.  
  103. ObtainInfo()/ObtainInfoA()
  104.    Queries a scaling engine for glyph information (a glyph's bitmap,
  105. the kerning value between two glyphs, etc.).
  106.  
  107. ReleaseInfo()/ReleaseInfoA()
  108.    Releases data obtained with ObtainInfo()/ObtainInfoA().
  109.  
  110. To obtain a pointer to a GlyphEngine structure for a particular scaling
  111. library, use that library's OpenEngine() routine.  The function takes
  112. no arguments.
  113.  
  114.  
  115. 4. Tell the engine which typeface to use.
  116.  
  117. Setting a scaling engine's current typeface involves the SetInfoA() (or
  118. SetInfo()) function and the Level 0 tags from <diskfont/diskfonttag.h>.
  119. The SetInfoA() function takes two parameters, a pointer to the
  120. GlyphEngine structure, and a tag list of level 0 outline tags.  The
  121. Level 0 tags act as commands for a scaling engine, some of which are
  122. for setting scaling engine parameters (with SetInfo() or SetInfoA()),
  123. and some of which are for querying information from a scaling engine
  124. (with ObtainInfo() or ObtainInfoA()).
  125.  
  126. Two tags set a scaling engine's current typeface: OT_OTagPath and
  127. OT_TagList.  The OT_OTagPath tag points to the full path name of a
  128. typeface's otag file (for example, fonts:CGTimes.otag).  The
  129. OT_OTagList tag points to the tag list created in step 2 above.
  130.  
  131.  
  132. 5. Set other scaling engine parameters.
  133.  
  134. There are three other parameters the scaling engine needs in order
  135. answer queries for information:
  136.  
  137.         OT_DeviceDPI
  138.         OT_PointHeight
  139.         OT_GlyphCode
  140.  
  141. The OT_DeviceDPI tag refers to the resolution of the output device.
  142. The tag value's high word is the horizontal resolution and the low word
  143. is the vertical resolution.  Both are unsigned words measured in dots
  144. per inch.
  145.  
  146. The OT_PointHeight tag refers to the height of a typeface in points.
  147. One point is approximately equal to 1/72 of an inch (AGFA/Compugraphic
  148. defines the point to be 0.01383 inches).  For CG typefaces, this height
  149. is the distance between baselines from one line to the next (without
  150. any leading adjustments).  The point height is represented as a fixed
  151. point, two's complement binary number, with the point situated in the
  152. middle of a long word.  This means the lower word is the fractional
  153. portion and the upper word the whole number portion (the number covers
  154. the powers of two from 2^15 through 2^-16).
  155.  
  156. For those who may not know, a two's complement number is a way of
  157. representing negative numbers.  To find the two's complement of a
  158. negative number, find the one's complement of the absolute value of
  159. that number (change all the binary ones to zeros and all the zeros to
  160. ones) and then add one to the result.  To change from two's complement,
  161. subtract one from the two's complement number and find the one's
  162. complement of the number.  For example,
  163.  
  164. Before conversion to two's complement, the absolute value of the one
  165. byte decimal quantity -32 is represented as:
  166.  
  167. In binary                       0010 0000       ($20)
  168.  One's complement               1101 1111       ($DF)
  169.  Add One                        0000 0001       ($01)
  170.  ----------------------------------------------------
  171.  Two's complement               1110 0000       ($E0)
  172.  
  173. So the number -32 is encoded as 1110 0000 or 0xE0 in hex.  Notice that
  174. the high bit (the sign bit) of the encoded number is set if the number
  175. is negative.  If the number is zero or greater, the high bit is clear.
  176. This procedure is independent of where the "point" is in the negative
  177. number (the "point" in this case is the divider between the whole
  178. portion of the number and the fractional portion).  When the computer
  179. adds one to the one's complement, it does not consider where the
  180. "point" is in the one's complement, the computer just treats the
  181. one's complement value as a whole integer.  For example, to encode the
  182. decimal quantity -531/256 as a two byte, fixed point, two's complement
  183. binary number where the point is situated in the middle of the two
  184. bytes:
  185.  
  186.   531/256 = -(2 + 19/256) = -2.13 in hex
  187.  
  188. In binary          0000 0010.0001 0011  ($02.13 in hex,
  189.                                                 with the point)
  190.  
  191.  One's complement  1111 1101 1110 1100  ($FDEC  in hex ignore the point
  192.                                                 from now on)
  193.  Add One           0000 0000 0000 0001  ($0001)
  194.  -----------------------------------------------------------------------
  195.  Two's complement  1111 1101 1110 1101  ($FDED)
  196.  
  197. Notice that the one added to the one's complement is in the 2^-8
  198. (= 1/256) column.
  199.  
  200. The OT_GlyphCode tag refers to the current glyph.  When an application
  201. asks the scaling engine to rasterize a glyph, this is the glyph the
  202. engine renders.  The scaling engine uses Unicode encoding to represent
  203. glyphs.  Unicode is an international character encoding standard that
  204. encompasses many of the world's national scripts in a 16-bit code
  205. space.  Conveniently, the Amiga's Latin-1, 8-bit character set
  206. corresponds to the same glyphs as the Unicode standard.  To set the
  207. current glyph to a character from the Amiga character set, use the same
  208. Latin-1 code, but pad it out to a 16-bit value.
  209.  
  210. Because the Compugraphic typefaces use their own character set, the
  211. scaling engine in the bullet.library has to map the Unicode glyph codes
  212. to Compugraphic glyph codes.  Note that the Unicode standard
  213. encompasses many more glyphs than just the Latin-1 character set or the
  214. Compugraphic character set, so many of the characters in the Unicode
  215. set do not map to any glyphs in the Compugraphic set.  For example,
  216. Unicode includes several Asian ideogram sets, that the Compugraphic set
  217. does not.  The result is the vast majority of the Unicode characters
  218. are not available using Compugraphic typefaces.  The Compugraphic
  219. character set covers roughly 400 glyphs.  For more information on the
  220. UniCode standard, see the Unicode Consortium's book The Unicode
  221. Standard, Worldwide Character Encoding published by Addison-Wesley
  222. (ISBN 0-201-56788-1).
  223.  
  224.  
  225. Rasterizing a Glyph
  226.  
  227. Once an application has set up the scaling engine, obtaining a glyph is
  228. a matter of asking for it.  As was mentioned earlier, the
  229. ObtainInfoA()/ObtainInfo() function queries a scaling engine for glyph
  230. information.  This function accepts a pointer to a GlyphEngine
  231. structure and a tag list.  To ask for a rasterization of a glyph, pass
  232. ObtainInfo() the OT_GlyphMap tag.  The engine expects the OT_GlyphMap
  233. value to be an address where it can place the address of a GlyphMap
  234. structure. The GlyphMap structure (defined in <diskfont/glyph.h>) is
  235. for reading only and looks like this:
  236.  
  237. struct GlyphMap {
  238.   UWORD  glm_BMModulo;   /* # of bytes in row: always multiple of 4 */
  239.   UWORD  glm_BMRows;     /* # of rows in bitmap */
  240.   UWORD  glm_BlackLeft;  /* # of blank pixel columns at left of glyph */
  241.   UWORD  glm_BlackTop;   /* # of blank rows at top of glyph */
  242.   UWORD  glm_BlackWidth; /* span of non-blank columns (horizontal
  243.                              span of the glyph) */
  244.   UWORD  glm_BlackHeight; /* span of non-blank rows (vertical span of
  245.                              the glyph) */
  246.   FIXED  glm_XOrigin;     /* distance from upper left corner of bitmap
  247.                              to lower */
  248.   FIXED  glm_YOrigin;     /* left of glyph (baseline), in
  249.                              fractional pixels */
  250.   WORD   glm_X0;      /* approximation of XOrigin in whole pixels */
  251.   WORD   glm_Y0;      /* approximation of YOrigin in whole pixels */
  252.   WORD   glm_X1;      /* approximation of XOrigin + Width */
  253.   WORD   glm_Y1;      /* approximation of YOrigin + Width */
  254.   FIXED  glm_Width;   /* character advance, as fraction of em width */
  255.   UBYTE *glm_BitMap;  /* actual glyph bitmap */
  256. };
  257.  
  258. The glm_BitMap field points to a single bitplane bitmap of the glyph.
  259. This bitmap is not necessarily in Chip RAM, so if an application needs
  260. to use the blitter to render the glyph, it has to copy the bitmap to a
  261. Chip RAM buffer.  The fields glm_BMModulo and glm_BMRows are the
  262. dimensions of the whole bitmap.  The glyph itself does not occupy the
  263. entire bitmap area.  The fields glm_BlackLeft, glm_BlackTop,
  264. glm_BlackWidth, and glm_BlackHeight describe the position and dimension
  265. of the glyph within the bitmap.  The fields glm_XOrigin and glm_YOrigin
  266. are the X and Y offsets from the bitmap's upper left corner to the
  267. glyph's lower left corner.  The lower left corner lies on the glyph's
  268. baseline.  These X and Y offsets are in fractional pixels.  The fields
  269. glm_X0 and glm_Y0 are rounded versions of glm_XOrigin and glm_YOrigin,
  270. respectively.
  271.  
  272. The glm_Width field is a measure of the width of the glyph in fractions
  273. of an em (pronounced like the letter 'M').  This value is a fixed point
  274. binary fraction.  The em is a relative measurement.  A distance of one
  275. em is equal to the point size of the typeface.  For example, in a 36
  276. point typeface, one em equals 36 points which is approximately equal to
  277. a half inch.  For a 72 point typeface, one em equals 72 points which is
  278. approximately equal to one inch.
  279.  
  280. When an application is finished with the GlyphMap structure, it must
  281. use the ReleaseInfoA() or ReleaseInfo() function to relinquish the
  282. GlyphMap structure.  This function uses the same format as
  283. ObtainInfoA()/ObtainInfo(), except the data value of the OT_GlyphMap
  284. tag is a pointer to the GlyphMap structure (rather than a pointer to a
  285. pointer).
  286.  
  287.  
  288. Kerning
  289.  
  290. The IntelliFont scaling engine also supports two types of kerning.  One
  291. type of kerning is called text kerning, which is for regular bodies of
  292. text.  The other type of kerning is called design kerning, which is for
  293. more obvious displays, like headlines.  The basic difference is that
  294. design kerning is generally more tightly spaced than text kerning.
  295.  
  296. Before asking for a kerning pair, an application has to tell the engine
  297. which character pair to kern.  It does this using one of the SetInfo()
  298. functions to set the primary glyph, OT_GlyphCode, and the secondary
  299. glyph code, OT_GlyphCode2.
  300.  
  301. To ask the scaling engine for a kerning value, use one of the
  302. ObtainInfo() functions with the OT_TextKernPair (for text kerning) or
  303. OT_DesignKernPair (for design kerning) tags.  The engine expects the
  304. value of the kerning tag to be an address where it can store a four
  305. byte long kerning value.  The kerning value is a fixed point binary
  306. fraction of an em square (like the glm_Width field from the GlyphMap
  307. structure).  This value is the distance to remove from the primary
  308. character advance (the glm_Width of OT_GlyphCode) when rendering the
  309. secondary glyph (OT_GlyphCode2) immediately following the primary glyph.
  310.  
  311. Unlike other ObtainInfo() tags, the scaling engine does not allocate
  312. any resources when answering queries about kerning values.
  313. Applications do not have to use ReleaseInfo() functions for kerning
  314. queries made with either OT_TextKernPair or OT_DesignKernPair.
  315.  
  316.  
  317. Width Lists
  318.  
  319. An application can find the widths of a typeface's glyphs using the
  320. OT_WidthList tag with one of the ObtainInfo() functions.  The engine
  321. expects the OT_WidthList value to be an address where it can place the
  322. address of a MinList structure.  This MinList points to a list of
  323. GlyphWidthEntry structures.  The GlyphWidthEntry structure (defined in
  324. <diskfont/glyph.h>) is for reading only and looks like this:
  325.  
  326. struct GlyphWidthEntry {
  327.   struct MinNode gwe_Node;  /* on list returned by OT_WidthList
  328.                                inquiry */
  329.   UWORD          gwe_Code;  /* entry's character code value */
  330.   FIXED          gwe_Width; /* character advance, as fraction of
  331.                                em width */
  332. };
  333.  
  334. The MinList contains an entry for each valid Unicode glyph ranging from
  335. the primary glyph, OT_GlyphCode, through the secondary glyph,
  336. OT_GlyphCode2.  The engine does not create a GlyphWidthEntry structure
  337. for codes without glyphs (for example the codes before the space
  338. character in the Latin-1 character set).
  339.  
  340. When an application is finished with the width list, it must use one of
  341. the ReleaseInfo() functions to relinquish the list.  This function uses
  342. the same format as the ObtainInfo() functions, except the data value of
  343. the OT_WidthList tag is a pointer to the MinList (rather than a pointer
  344. to a pointer).  The primary and secondary code values do not have to
  345. remain constant while an application is using a width list.  The engine
  346. deallocates the width list resources independently of the primary and
  347. secondary code values, so these can change after obtaining a width list.
  348.  
  349. The following code fragment asks the scaling engine, ge, for a list of
  350. character widths of the Unicode glyphs ranging from unicode
  351. (OT_GlyphCode) to unicode2 (OT_GlyphCode2), inclusive.  The fragment
  352. steps through the list of widths, printing each one.
  353.  
  354. struct MinList *widthlist; struct GlyphWidthEntry *widthentry;
  355.  
  356. .  .  . if (SetInfo(ge,
  357.             OT_GlyphCode,   unicode,
  358.             OT_GlyphCode2,  unicode2,
  359.             TAG_END) == OTERR_Success)
  360. {
  361.  if (ObtainInfo(ge, OT_WidthList, &widthlist, TAG_END) == OTERR_Success)
  362.  {
  363.      for (widthentry = (struct GlyphWidthEntry *) widthlist->mlh_Head;
  364.          widthentry->gwe_Node.mln_Succ;
  365.          widthentry = (struct GlyphWidthEntry *)
  366.          widthentry->gwe_Node.mln_Succ)
  367.      {
  368.          printf("$%lx: %ld.%ld\n",
  369.              widthentry->gwe_Code,
  370.              widthentry->gwe_Width>>16,
  371.              ((widthentry->gwe_Width&0xffff)*10000)>>16);
  372.      }
  373.      ReleaseInfo(ge, OT_WidthList, widthlist, TAG_END);
  374.  }
  375. }
  376.  
  377. Notice that the ObtainInfo() functions (as well as the SetInfo()
  378. functions) return an error code (the error codes are defined in
  379. <diskfont/oterrors.h>).  If that error code is equal to OTERR_Success,
  380. the operation was successful.
  381.  
  382.  
  383. Rotating
  384.  
  385. Taking advantage of other features of the Bullet library is a matter of
  386. setting other engine parameters using one of the SetInfo() functions
  387. with some other level 0 tags.  One interesting feature of the
  388. IntelliFont engine is its ability to rotate glyphs.  By setting the
  389. OT_RotateSin and OT_RotateCos values, the IntelliFont engine can rotate
  390. a glyph's baseline from the glyph origin (the glm_XOrigin and
  391. glm_YOrigin from the GlyphMap structure).
  392.  
  393. The OT_RotateSin and OT_RotateCos are, respectively, the sine and
  394. cosine of the baseline rotation angle.  The engine can rotate to any
  395. angle.  The sine and cosine must correspond to the same angle and must
  396. be in the sine and cosine value range (0 through 1 inclusive).  The
  397. engine does not do any error checking on the sine and cosine values.
  398. As a result, the engine will yield strange results if the sine and
  399. cosine are from very different angles or if these values are out of
  400. range for sines and cosines (greater than 1).  By default, the engine
  401. sets these values to 0.0 and 1.0, the sine and cosine of 0 degrees.
  402. These values are encoded as fixed point binary fractions (the negative
  403. values are two's complement).
  404.  
  405. When setting the baseline rotation, an application must set both the
  406. sine and cosine.  It must set OT_RotateSin first, then OT_RotateCos.
  407. An application can set both values in the same SetInfo() function, but
  408. the sine must come first.  For example, to set the rotation angle to
  409. 150 degrees:
  410.  
  411. The sine of 150 degrees is 0.5 which is 0x00008000 in hex.  The cosine
  412. of 150 degrees is approximately -0.866 which is approximately
  413. 0xffff224c in hex (two's complement), so:
  414.  
  415. if (SetInfo(ge,
  416.     OT_RotateSin, 0x8000,
  417.     OT_RotateCos, 0xFFFF224C,
  418.     TAG_END) == OTERR_Success) /* If SetInfo() returns OTERR_Success, */
  419.                                /* it worked OK. */
  420.  {
  421.    /* The baseline rotation has been set, now the application can
  422.       render it. */
  423.  
  424.     .  .  .
  425.  }
  426.  
  427.  
  428. Shearing
  429.  
  430. Like baseline rotation, glyph shearing (also known as italicizing) is a
  431. matter of setting some Level 0 tags.  The shearing tags, OT_ShearSin
  432. and OT_ShearCos, specify the shearing angle, or the angle at which the
  433. typeface is italicized.  This angle refers to the angle that results
  434. from rotating the vertical axis clockwise.  The angle can range from
  435. -45 to 45 degrees (inclusive).  Like the rotation angle, the shearing
  436. angle is represented as a sine and cosine value that must correspond to
  437. the same angle and must fall into normal bounds for sine and cosine
  438. values.  Also like the rotation angle sine and cosine tags, an
  439. application must set both the OT_ShearSin and OT_ShearCos tags, in that
  440. order.  By default, the shearing value is zero degrees meaning there is
  441. no shearing (OT_ShearSin = 0x00000000, OT_ShearCos = 0x00010000).
  442.  
  443.  
  444. Other Level 0 Tags
  445.  
  446. There are several other Level 0 tags:
  447.  
  448. OT_DotSize.  This tag specifies the X and Y size of the target device's
  449. dots.  The X and Y DPI imply a dot size.  For example, at 300 X and 300
  450. Y DPI, the resolution implied dot size is 1/300 inches by 1/300 inches.
  451. For some devices (like some dot matrix printers), the size of the
  452. output dot does not match its resolution implied size.  To a degree,
  453. the IntelliFont engine can account for this.  The dot size is
  454. represented as a percentage of the dot's resolution implied size.  The
  455. X percentage is in the tag value's upper word, and the Y percentage is
  456. in the tag value's lower word.
  457.  
  458. OT_SetFactor.  This tag distorts the width of a typeface by changing
  459. the width of the em square.  The scaling engine changes the em width to
  460. this tag's value.  The value is a fixed point binary fraction.
  461.  
  462. OT_EmboldenX/OT_EmboldenY.  These tags specify the algorithmic
  463. emboldening factor in the X and Y direction, respectively.  The tag
  464. values are fixed point two's complement binary numbers.  The units are
  465. measured in ems.  Emboldening values above zero embolden the typeface.
  466. Emboldening values below zero lighten the typeface.  By default, both
  467. values are zero.
  468.  
  469. OT_GlyphWidth.  This tag's value specifies a width for the current
  470. typeface.  It is a fraction of an em represented as a fixed point
  471. binary number.  If this value is set to something besides 0.0, all
  472. glyphs will have this width.  To turn off the constant width, set
  473. OT_GlyphMap back to 0.0 (its default value).
  474.  
  475.  
  476. The Otag File Tags
  477.  
  478. The Outline Tag (otag) file contains a number of tags that describe a
  479. font outline to the Diskfont library.  The purpose of most of these
  480. tags is to allow Diskfont to attribute styles to a typeface when
  481. loading a font outline as a standard Amiga system font.  Most
  482. applications that use the scaling engine will not need to worry about
  483. the meaning of the majority of these tags, but they are described
  484. below.  The following tags are Level 1 tags and must be present in
  485. every otag file:
  486.  
  487. OT_FileIdent.  Every valid otag file starts with this tag.  Its value
  488. is the size of the file.  It doesn't really have anything to do with
  489. the definition of the typeface, but it does serve as a way to check the
  490. validity of the otag file.
  491.  
  492. OT_Engine.  This tag's value points to a string naming the font scaling
  493. engine.  For example, the OT_Engine tag in fonts:CGTimes.otag is
  494. "bullet."
  495.  
  496. OT_Family.  This tag's value points to a string naming the typefaces
  497. font family.  For example, the OT_Family in fonts:CGTimes.otag is
  498. "bullet."
  499.  
  500. OT_SymbolSet.  This tag's value is a two byte ASCII code for this
  501. typeface's symbol set.  This tells the system which symbol set to use
  502. to map the Amiga character set to the Compugraphic character set.  The
  503. symbol set for most CG fonts designed for use with the Amiga is "L1",
  504. which stands for Latin1.  The exception is the CG fonts from Gold Disk,
  505. Inc.  They use the "GD" (Gold Disk) symbol set.
  506.  
  507. OT_YSizeFactor.  For traditional Amiga fonts, the font size does not
  508. include any spacing on top or bottom of the typeface--the Amiga doesn't
  509. consider it part of the font.  CG fonts include spacing on the top and
  510. bottom of their typefaces.  This tag's value is a ratio of the point
  511. height of a typeface to its "black" height (the point height minus
  512. the space on the typeface's top and bottom).  The high word is the
  513. point height factor and the low word is the black height factor.  Note
  514. that these values form a ratio.  Individually, they do not necessarily
  515. reflect any useful value.
  516.  
  517. OT_SerifFlag.  If this tag's value is TRUE, this typeface has serifs.
  518.  
  519. OT_StemWeight
  520.     This tag's value can be anywhere from 0 through 255 and
  521. indicates a nominal weight or "boldness" to the typeface.
  522. The<diskfont/diskfonttag.h> include file defines a set of ratings for
  523. this tag's value.  See that file for more details.  When the Diskfont
  524. library opens an outline font, it uses this value to determine if a
  525. typeface is bold.
  526.  
  527. OT_SlantStyle
  528.     The <diskfont/diskfonttag.h> include file defines a set of three
  529. possible values for this tag's value.  See that file for more details.
  530. When the Diskfont library opens an outline font, it uses this value to
  531. determine if a typeface is italicized/obliqued.
  532.  
  533. OT_HorizStyle
  534.     This tag's value can be anywhere from 0 through 255 and indicates a
  535. nominal width rating to the typeface.  The <diskfont/diskfonttag.h>
  536. include file defines a set of ratings for this tag's value.  See that
  537. file for more details.  When the Diskfont library opens an outline
  538. font, it uses this value to determine if a typeface is extended.
  539.  
  540. OT_AvailSizes
  541.     This tag's value points to a sorted list of UWORDs. The first UWORD
  542. is the number of entries in the sorted list.  The remaining UWORDs are
  543. the font sizes that the Diskfont library lists when calling
  544. AvailFonts().
  545.  
  546. OT_SpecCount
  547.     This tag's value is a number of spec tags that follow it.  A spec
  548. tag is private to the scaling engine.
  549.  
  550. The following are Level 2 tags.  They may also be in an otag file but
  551. are not required:
  552.  
  553. OT_BName
  554.     This tag points to a string naming the bold variant of this
  555. typeface.  For example, the fonts:CGTimes.otag file lists "CGTimesBold"
  556. as its bold variant.
  557.  
  558. OT_IName
  559.   This tag points to a string naming the italic variant of this
  560. typeface.
  561.  
  562. OT_BIName
  563.     This tag points to a string naming the bold italic variant of this
  564. typeface.
  565.  
  566. OT_SpaceWidth
  567.     This tag's value is the width of the space character at 250 points
  568. (where there are 72.307 points in an inch).  The width is in Design
  569. Window Units (DWUs).  One DWU is equal to 1/2540 inches.  To convert to
  570. X pixels:
  571.  
  572.  OT_SpaceWidth   pointsize
  573.  ------------- * --------- *  XDPI = spacewidth in pixels (X dots)
  574.      2540           250
  575.  
  576. OT_IsFixed
  577.     If this tag's value is TRUE, every glyph in this typeface has the
  578. same character advance (a fixed width).
  579.  
  580. OT_InhibitAlgoStyle
  581.     This tag's value is a bitmask that is compatible with the ta_Style
  582. field of the TextAttr structure (defined in <graphics/text.h>).  This
  583. tag tells which styles cannot be added to a typeface algorithmically.
  584. For example, if the FSF_BOLD bit in OT_InhibitAlgoStyle is set and a
  585. user asks for a bold version of the typeface, the diskfont.library (or
  586. an application) can add that style algorithmically.
  587.  
  588. At present there are no Level 3 tags.
  589.  
  590. About the Examples
  591.  
  592. This article contains two code examples.  The first, Rotate, rotates a
  593. user-specified glyph around a central point.  By default, it rotates a
  594. 36 point 'A' using the font fonts:CGTimes.font.  If Rotate finds an
  595. AmigaDOS environment variable called "XYDPI", it will use the X and Y
  596. DPI it finds in that variable as the default target device DPI (see the
  597. description of the Level 0 OT_DeviceDPI tag).  If that variable is not
  598. defined, Rotate will use an XDPI of 68 and a YDPI of 27 which,
  599. nominally, is the X and Y DPI of a standard Hires display.
  600.  
  601. The second example, View, displays a file using the same defaults as
  602. Rotate.  View utilizes kerning pairs to display its glyphs.  Because
  603. View only considers "visible" characters, it ignores characters that
  604. have widths but no glyph.  The result is, View doesn't print any space
  605. characters.  If View were smarter, it would ask the scaling engine for
  606. a width list so it could properly advance the current pointer when it
  607. comes across a space or some other character without a glyph.
  608.  
  609. Notice that View uses a slightly modified version of BulletMain.c
  610. called BulletMainFile.c.  Only BulletMain.c appears in the example
  611. code.  The only significant difference between the two is that
  612. BulletMainFile.c obtains a file name for View to display.
  613.  
  614.  
  615. ------------------------- Example Code ------------------------------
  616. BulletMain.c
  617.  
  618. ;/* BulletMain.c - Execute me to compile me with SAS/C 5.10a
  619. LC -cfistq -v -y -j73 BulletMain.c
  620. quit ;*/
  621.  
  622. #include <exec/types.h>
  623. #include <exec/memory.h>
  624. #include <dos/rdargs.h>
  625. #include <dos/dos.h>
  626. #include <dos/var.h>
  627. #include <diskfont/diskfonttag.h>
  628. #include <diskfont/diskfont.h>
  629. #include <diskfont/glyph.h>
  630. #include <diskfont/oterrors.h>
  631. #include <utility/tagitem.h>
  632. #include <string.h>
  633. #include <graphics/displayinfo.h>
  634. #include <intuition/intuition.h>
  635. #include <intuition/screens.h>
  636.  
  637. #include <clib/dos_protos.h>
  638. #include <clib/graphics_protos.h>
  639. #include <clib/exec_protos.h>
  640. #include <clib/utility_protos.h>
  641. #include <clib/bullet_protos.h>
  642. #include <clib/intuition_protos.h>
  643.  
  644. #define OTAG_ID 0x0f03
  645.  
  646. #ifdef LATTICE
  647. int CXBRK(void) { return (0);} /* Disable Lattice CTRL/C handling */
  648. int chkabort(void) { return (0);}
  649. #endif
  650.  
  651. UBYTE   *readargsstring = "FontName,Size/N,XDPI/N,YDPI/N,CharCode/N,CharCode2/N\n";
  652. UBYTE   *librarystring = ".library";
  653. UBYTE   *fontstring     = "fonts:cgtimes.font";
  654. UBYTE   *dpivarname = "XYDPI";  /* Name of an X/Y DPI environment variable. */
  655.                                 /* If this ENV: variable exists, this code  */
  656.                                 /* will use the X and Y DPI stored there.   */
  657.                                 /* This code will also save the X and Y DPI */
  658.                                 /* in XYDPI if the user supplies a DPI.     */
  659.                                 /* XYDPI encodes the DPI just like the      */
  660.                                 /* OT_DeviceDPI tag.                        */
  661. extern struct TagItem *AllocOtag(STRPTR);
  662. extern void     FreeOtag(void *);
  663. extern struct Library *OpenScalingLibrary(struct TagItem *);
  664. extern void     CloseScalingLibrary(struct Library *);
  665. extern struct GlyphEngine *GetGlyphEngine(struct TagItem *, STRPTR);
  666. extern void     ReleaseGlyphEngine(struct GlyphEngine *);
  667. extern void
  668. BulletExample(struct GlyphEngine *,
  669.               struct Window *,
  670.               struct RastPort *, ULONG, ULONG, ULONG, ULONG, ULONG);
  671.  
  672. #define BUFSIZE     256
  673.  
  674. #define NUM_ARGS    6    /* Arguments for ReadArgs(). */
  675. #define FONT_NAME   0
  676. #define SIZE        1
  677. #define XDPI        2
  678. #define YDPI        3
  679. #define CODE        4
  680. #define CODE2       5
  681. LONG            args[NUM_ARGS];
  682. struct RDargs  *myrda;
  683.  
  684. struct Library *BulletBase, *UtilityBase, *GfxBase, *IntuitionBase;
  685.  
  686. UBYTE           buf[BUFSIZE];
  687. BPTR            fontfile, dpifile;
  688. UBYTE          *otagname;
  689. UWORD           fchid;
  690.  
  691. struct GlyphEngine *ge;
  692.  
  693. struct DrawInfo *drawinfo;
  694. struct RastPort rp;
  695.  
  696. void            main(int argc, char **argv)
  697. {
  698.   struct TagItem *ti;
  699.   struct GlyphEngine *ge;
  700.   struct Window  *w;
  701.  
  702.   UBYTE           xydpi[5];
  703.  
  704.   ULONG           defpointheight = 36;   /* Default values for ReadArgs() */
  705.   ULONG           defxdpi = 68;          /* variables.                    */
  706.   ULONG           defydpi = 27;
  707.   ULONG           defcode = (ULONG) 'A';
  708.   ULONG           defcode2 = 0;
  709.  
  710.   if (GfxBase = OpenLibrary("graphics.library", 37L))
  711.   {
  712.     if (IntuitionBase = OpenLibrary("intuition.library", 37L))
  713.     {
  714.       if (myrda = ReadArgs(readargsstring, args, NULL))
  715.       {
  716.         if (args[XDPI] && args[YDPI]) /* If the user sets the DPI from the command  */
  717.         {            /* line, make sure the environment variable also gets changed. */
  718.           *(ULONG *)xydpi = ( (*(LONG *) args[XDPI]) << 16 | (*(ULONG *) args[YDPI]) );
  719.           SetVar(dpivarname, xydpi, 5,
  720.               GVF_GLOBAL_ONLY | GVF_BINARY_VAR | GVF_DONT_NULL_TERM);
  721.         }
  722.         else                            /* If the user did NOT set the X OR Y DPI...*/
  723.         {
  724.           args[XDPI] = (LONG) &defxdpi; /* ...set to default values and look for    */
  725.           args[YDPI] = (LONG) &defydpi; /* an environment variable called "XYDPI".  */
  726.                                                   /* Read the environment variable, */
  727.           if (GetVar(dpivarname, xydpi, 5,        /* XYDPI, if it exists.           */
  728.               GVF_GLOBAL_ONLY | GVF_BINARY_VAR | GVF_DONT_NULL_TERM))
  729.           {
  730.             if ( (*(ULONG *)xydpi & 0xFFFF0000) && (*(ULONG *)xydpi & 0x0000FFFF) )
  731.             {     /* Make sure the environment variable is OK to use by making sure */
  732.                   /* that neither X or YDPI is zero. If XYDPI is OK, use it as the  */
  733.               defxdpi = ((*(ULONG *)xydpi) & 0xFFFF0000) >> 16;        /* default.  */
  734.               defydpi = (*(ULONG *)xydpi) & 0x0000FFFF;
  735.             }
  736.           }
  737.         }
  738.         if (!(args[SIZE]))
  739.           args[SIZE] = (LONG) &defpointheight;
  740.         if (!(args[CODE]))
  741.           args[CODE] = (LONG) &defcode;
  742.         if (!(args[CODE2]))
  743.           args[CODE2] = (LONG) &defcode2;
  744.         if (!(args[FONT_NAME]))
  745.           args[FONT_NAME] = (LONG) fontstring;
  746.                                            /* Open the ".font" file which contains  */
  747.                                            /* the FontContentsHeader for this font. */
  748.         if (fontfile = Open((STRPTR) args[FONT_NAME], MODE_OLDFILE))
  749.         {
  750.           if (Read(fontfile, &fchid, sizeof(UWORD)))
  751.           {
  752.             if (fchid == OTAG_ID)             /* Does this font have an .otag file? */
  753.             {
  754.               strcpy(buf, (STRPTR) args[FONT_NAME]); /* Put together the otag file  */
  755.               if (otagname = &(buf[strlen(buf) - 4]))/* name from the .font file.   */
  756.               {
  757.                 strcpy(otagname, "otag");
  758.                 if (UtilityBase = OpenLibrary("utility.library", 37L))
  759.                 {
  760.                   if (ti = AllocOtag(buf))      /* open the otag file and copy its  */
  761.                   {                             /* tags into memory.                */
  762.                     if (BulletBase = OpenScalingLibrary(ti)) /* Pass the function   */
  763.                     {                                  /* the OTAG tag list which it*/
  764.                                                        /* needs to open the scaling */
  765.                       if (ge = GetGlyphEngine(ti, buf))/* library.  Open the        */
  766.                       {                                /* library's scaling engine. */
  767.  
  768.                         if (w = OpenWindowTags(NULL,
  769.                                                WA_Width,         640,
  770.                                                WA_Height,        200,
  771.                                                WA_SimpleRefresh, TRUE,
  772.                                                WA_SizeGadget,    FALSE,
  773.                                                WA_CloseGadget,   TRUE,
  774.                                                WA_IDCMP,         NULL,
  775.                                                WA_DragBar,       TRUE,
  776.                                                WA_DepthGadget,   TRUE,
  777.                                                WA_Title,         (ULONG)argv[0],
  778.                                                TAG_END))
  779.                         {
  780.                           rp = *(w->RPort); /* Clone window's RastPort.  The second */
  781.                                             /* Rastport is for rendering with the   */
  782.                                             /* background color.                    */
  783.  
  784.                           if (drawinfo = GetScreenDrawInfo(w->WScreen)) /* Get the  */
  785.                           {             /* Screen's DrawInfo to get its pen colors. */
  786.                             SetAPen(w->RPort, drawinfo->dri_Pens[TEXTPEN]);
  787.                             SetAPen(&rp, drawinfo->dri_Pens[BACKGROUNDPEN]);
  788.                             FreeScreenDrawInfo(w->WScreen, drawinfo);
  789.  
  790.                             BulletExample(ge, w, &rp, *(ULONG *) args[SIZE],
  791.                                           *(ULONG *) args[XDPI],
  792.                                           *(ULONG *) args[YDPI],
  793.                                           *(ULONG *) args[CODE],
  794.                                           *(ULONG *) args[CODE2]);
  795.                           }
  796.                           CloseWindow(w);
  797.                         }
  798.                         ReleaseGlyphEngine(ge);
  799.                       }
  800.                       CloseScalingLibrary(BulletBase);
  801.                     }
  802.                     FreeOtag(ti);
  803.                   }
  804.                   CloseLibrary(UtilityBase);
  805.                 }
  806.               }
  807.             }
  808.           }
  809.           Close(fontfile);
  810.         }
  811.         FreeArgs(myrda);
  812.       }
  813.       CloseLibrary(IntuitionBase);
  814.     }
  815.     CloseLibrary(GfxBase);
  816.   }
  817. }
  818.  
  819.  
  820.  
  821.  
  822.  
  823.  
  824.  
  825.  
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.  
  833.  
  834.  
  835.  
  836.  
  837.  
  838.  
  839.  
  840. Engine.c
  841.  
  842. ;/* Engine.c - Execute me to compile me with SAS/C 5.10a
  843. LC -cfistq -v -y -j73 Engine.c
  844. quit ;*/
  845.  
  846. #include <exec/types.h>
  847. #include <exec/memory.h>
  848. #include <dos/dostags.h>
  849. #include <dos/dos.h>
  850. #include <diskfont/diskfonttag.h>
  851. #include <diskfont/diskfont.h>
  852. #include <diskfont/glyph.h>
  853. #include <diskfont/oterrors.h>
  854. #include <utility/tagitem.h>
  855. #include <string.h>
  856.  
  857. #include <clib/dos_protos.h>
  858. #include <clib/exec_protos.h>
  859. #include <clib/utility_protos.h>
  860. #include <clib/bullet_protos.h>
  861.  
  862. #define OTAG_ID 0x0f03   /* this really belongs in <diskfont/diskfont.h>, */
  863.                          /* but it's not there, yet.                      */
  864.  
  865. extern UBYTE   *librarystring; /* ".library", defined in BulletMain.c. */
  866.  
  867. struct TagItem *AllocOtag(STRPTR);
  868. void            FreeOtag(void *);
  869. struct Library *OpenScalingLibrary(struct TagItem *);
  870. void            CloseScalingLibrary(struct Library *);
  871. struct GlyphEngine *GetGlyphEngine(struct TagItem *, STRPTR);
  872. void            ReleaseGlyphEngine(struct GlyphEngine *);
  873.  
  874. #define BUFSIZE     256
  875.  
  876. extern struct Library *BulletBase, *UtilityBase;
  877.  
  878. /*************************************************************************************/
  879. /* open the otag file, allocate a buffer, read the file into the buffer, verify that */
  880. /* the file is OK, relocate all of the address relocation tags, close the otag file. */
  881. /*************************************************************************************/
  882. struct TagItem *
  883. AllocOtag(STRPTR otagname)
  884. {
  885.   BPTR            otfile;
  886.   struct TagItem *ti, *tip, *returnti;
  887.   struct FileInfoBlock *fib;
  888.  
  889.   ti = NULL;
  890.  
  891.   if (fib = AllocDosObject(DOS_FIB, NULL))    /* The FileInfoBlock of the OTAG file */
  892.   {                                           /* contains the file's size.          */
  893.     if (otfile = Open(otagname, MODE_OLDFILE))
  894.     {
  895.       if (ExamineFH(otfile, fib))
  896.       {
  897.         if (returnti = (struct TagItem *) AllocVec(fib->fib_Size, MEMF_CLEAR))
  898.         {
  899.           if (Read(otfile, (UBYTE *) returnti, fib->fib_Size))
  900.           {
  901.             if ((returnti->ti_Tag == OT_FileIdent)               /* Test to see if */
  902.                 && (returnti->ti_Data == (ULONG) fib->fib_Size)) /* the OTAG file  */
  903.             {                                                    /* is valid.      */
  904.               tip = returnti;
  905.               while (ti = NextTagItem(&tip))     /* Step through and relocate tags */
  906.               {
  907.                 if (ti->ti_Tag & OT_Indirect)
  908.                 {
  909.                   ti->ti_Data = (ULONG) returnti + ti->ti_Data;
  910.                 }
  911.               }
  912.             }
  913.           }
  914.         }
  915.       }
  916.       Close(otfile);
  917.     }
  918.     FreeDosObject(DOS_FIB, fib);
  919.   }
  920.   return (returnti);
  921. }
  922.  
  923.  
  924. /**************************************************************************/
  925. /*********** Deallocates resources allocated by AllocOtag(). **************/
  926. /**************************************************************************/
  927. void
  928. FreeOtag(void *vector)
  929. {
  930.   FreeVec(vector);
  931. }
  932.  
  933.  
  934. /*****************************************************************************/
  935. /******* Scans through a TagList looking for an scaling engine name. *********/
  936. /*******           If it finds one, it opens that library.           *********/
  937. /*****************************************************************************/
  938. struct Library *
  939. OpenScalingLibrary(struct TagItem * ti)
  940. {
  941.   STRPTR          enginename;
  942.   UBYTE           libnamebuffer[BUFSIZE];
  943.  
  944.   if (enginename = (STRPTR) GetTagData(OT_Engine, NULL, ti))
  945.   {
  946.     strcpy(libnamebuffer, enginename);
  947.     strcat(libnamebuffer, librarystring);
  948.  
  949.     return (OpenLibrary(libnamebuffer, 0L));
  950.   }
  951. }
  952.  
  953.  
  954. /**************************************************************************/
  955. /******* Deallocates resources allocated by OpenScalingLibrary(). *********/
  956. /**************************************************************************/
  957. void
  958. CloseScalingLibrary(struct Library * bbase)
  959. {
  960.   CloseLibrary(bbase);
  961. }
  962.  
  963. /**************************************************************************/
  964. /* Open the glyph engine, give it the tags from the otag file, and set up */
  965. /* a default device dpi so it doesn't crash if someone forgets to set it. */
  966. /**************************************************************************/
  967. struct GlyphEngine *
  968. GetGlyphEngine(struct TagItem * ti, STRPTR otagpath)
  969. {
  970.   struct GlyphEngine *ge = NULL;
  971.   BOOL            ok = TRUE;
  972.  
  973.   if (ge = OpenEngine())
  974.   {
  975.     ok = FALSE;
  976.     if (SetInfo(ge,
  977.                 OT_OTagList, ti,
  978.                 OT_OTagPath, otagpath,
  979.                 TAG_END) == OTERR_Success)
  980.     {
  981.       if (SetInfo(ge,
  982.                   OT_DeviceDPI, ((ULONG) 77) << 16 | 75,
  983.                   TAG_END) == OTERR_Success)
  984.       {
  985.         ok = TRUE;
  986.       }
  987.     }
  988.   }
  989.  
  990.  
  991.   if (!ok)
  992.   {
  993.     CloseEngine(ge);
  994.     ge = NULL;
  995.   }
  996.   return (ge);
  997. }
  998.  
  999. /**************************************************************************/
  1000. /********* Deallocates resources allocated by GetGlyphEngine(). ***********/
  1001. /**************************************************************************/
  1002. void
  1003. ReleaseGlyphEngine(struct GlyphEngine * ge)
  1004. {
  1005.   CloseEngine(ge);
  1006. }
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015.  
  1016.  
  1017.  
  1018.  
  1019.  
  1020.  
  1021.  
  1022.  
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050.  
  1051.  
  1052.  
  1053.  
  1054.  
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064.  
  1065.  
  1066. ;/* Rotate.c - Execute me to compile me with SAS/C 5.10a
  1067. LC -cfistq -v -y -j73 Rotate.c
  1068. Blink FROM LIB:c.o,BulletMain.o,engine.o,Rotate.o TO Rotate LIBRARY LIB:LC.lib,LIB:Amiga.lib
  1069. quit ;*/
  1070.  
  1071. #include <exec/types.h>
  1072. #include <diskfont/diskfonttag.h>
  1073. #include <diskfont/diskfont.h>
  1074. #include <diskfont/glyph.h>
  1075. #include <diskfont/oterrors.h>
  1076. #include <graphics/gfx.h>
  1077. #include <graphics/regions.h>
  1078. #include <utility/tagitem.h>
  1079. #include <intuition/intuition.h>
  1080. #include <devices/timer.h>
  1081.  
  1082. #include <clib/alib_stdio_protos.h>
  1083. #include <clib/alib_protos.h>
  1084. #include <clib/bullet_protos.h>
  1085. #include <clib/exec_protos.h>
  1086. #include <clib/layers_protos.h>
  1087. #include <clib/graphics_protos.h>
  1088. #include <clib/intuition_protos.h>
  1089.  
  1090. extern struct Library *BulletBase, *UtilityBase, *GfxBase, *IntuitionBase;
  1091. struct Library *LayersBase;
  1092. void            BulletExample(struct GlyphEngine *,
  1093.                               struct Window *,
  1094.                               struct RastPort *,
  1095.                               ULONG, ULONG, ULONG, ULONG, ULONG);
  1096.  
  1097. UBYTE          *vers = "\e0$VER: Rotate 38.9";
  1098.  
  1099. #define TABLE_ENTRIES 24
  1100. #define SINE_INDEX    0
  1101. #define COSINE_INDEX  1
  1102.  
  1103. /* precalculated sine and cosine */
  1104. LONG            table[TABLE_ENTRIES][2] =
  1105. {
  1106.   {0x0, 0x10000},             /* 0   degrees */ /* Notice that the sine and cosine  */
  1107.   {0x424e, 0xf747},           /* 15  degrees */ /* values have to correspond to the */
  1108.   {0x8000, 0xddb4},           /* 30  degrees */ /* same angle.  The IntelliFont     */
  1109.   {0xb505, 0xb505},           /* 45  degrees */ /* engine will have severe mental   */
  1110.   {0xddb4, 0x8000},           /* 60  degrees */ /* problems if the values aren't    */
  1111.   {0xf747, 0x424e},           /* 75  degrees */ /* close to representing the same   */
  1112.   {0x10000, 0x0},             /* 90  degrees */ /* angle.                           */
  1113.   {0xf747, 0xffffbdbe},       /* 105 degrees */
  1114.   {0xddb4, 0xffff8000},       /* 120 degrees */
  1115.   {0xb505, 0xffff4afb},       /* 135 degrees */
  1116.   {0x8000, 0xffff224c},       /* 150 degrees */
  1117.   {0x424e, 0xffff08b9},       /* 165 degrees */
  1118.   {0x0, 0xffff0000},          /* 180 degrees */
  1119.   {0xffffbdbe, 0xffff08b9},   /* 195 degrees */
  1120.   {0xffff8000, 0xffff224c},   /* 210 degrees */
  1121.   {0xffff4afb, 0xffff4afb},   /* 225 degrees */
  1122.   {0xffff224c, 0xffff8000},   /* 240 degrees */
  1123.   {0xffff08b9, 0xffffbdbe},   /* 255 degrees */
  1124.   {0xffff0000, 0x0},          /* 270 degrees */
  1125.   {0xffff08b9, 0x424e},       /* 285 degrees */
  1126.   {0xffff224c, 0x8000},       /* 300 degrees */
  1127.   {0xffff4afb, 0xb505},       /* 315 degrees */
  1128.   {0xffff8000, 0xddb4},       /* 330 degrees */
  1129.   {0xffffbdbe, 0xf747}        /* 345 degrees */
  1130. };
  1131.  
  1132. struct Rectangle rectangle;
  1133. struct Region    *region;
  1134.  
  1135. void
  1136. BulletExample(struct GlyphEngine * ge,
  1137.               struct Window * w, struct RastPort * rp,
  1138.      ULONG pointheight, ULONG xdpi, ULONG ydpi, ULONG unicode, ULONG unicode2)
  1139. {
  1140.   struct GlyphMap *gm;
  1141.   PLANEPTR        tempbitmap;
  1142.   ULONG           centerx, centery, x, y, dx, dy, sin, cos, oldx, oldy, olddx,
  1143.                   olddy, emheight, emwidth;
  1144.   ULONG           i = 0;
  1145.  
  1146.   struct IntuiMessage *mymsg;
  1147.   BOOL            done = FALSE;
  1148.  
  1149.   if (pointheight > 180) pointheight = 180;
  1150.  
  1151.   if (SetInfo(ge,
  1152.               OT_DeviceDPI, ((ULONG) xdpi) << 16 | ydpi,
  1153.               TAG_END) != OTERR_Success)
  1154.         return;
  1155.  
  1156.   emheight = (pointheight * ydpi) / 72; /* Calculate the pixel dimensions */
  1157.   emwidth  = (pointheight * xdpi) / 72; /* of the EM square.              */
  1158.   centerx  = w->BorderLeft + emheight;
  1159.   centery  = w->BorderTop  + emwidth;
  1160.  
  1161.   dx = (2 * emwidth) + w->BorderLeft + w->BorderRight;  /* Calculate window size to */
  1162.   dy = (2 * emheight) + w->BorderTop + w->BorderBottom; /* fit around glyph com-    */
  1163.   dx = (dx > 640) ? 640 : dx;                           /* fortablely.              */
  1164.   dy = (dy > 200) ? 200 : dy;
  1165.   dx = (dx < 80) ? 80: dx;
  1166.   dy = (dy < 50) ? 50: dy;
  1167.  
  1168.   if (ModifyIDCMP(w, IDCMP_CHANGEWINDOW))
  1169.   {
  1170.     ChangeWindowBox(w, w->LeftEdge, w->TopEdge, dx, dy);        /* Set window size  */
  1171.     WaitPort(w->UserPort);                                      /* and wait for the */
  1172.     while (mymsg = (struct IntuiMessage *) GetMsg(w->UserPort)) /* dimension change */
  1173.       ReplyMsg((struct Message *) mymsg);                       /* to take place.   */
  1174.     if (!(ModifyIDCMP(w, NULL))) return;  /* Quit if there is a problem with IDCMP. */
  1175.   }
  1176.  
  1177.   x = centerx; /* calculate original rendering position. */
  1178.   y = centery;
  1179.   dx = 1;   /* Since dx and dy are no longer necessary for figuring out the window  */
  1180.   dy = 1;   /* dimensions, I use them to measure the full width and height of the   */
  1181.             /* glyph bitmap supplied by bullet.  I need this to erase the glyph.    */
  1182.  
  1183.   if (LayersBase = OpenLibrary("layers.library", 37L)) /* These lines are       */
  1184.   {                                                    /* here to install       */
  1185.     rectangle.MinX = w->BorderLeft;                    /* a clipping            */
  1186.     rectangle.MinY = w->BorderTop;                     /* region to the         */
  1187.     rectangle.MaxX = w->Width  - w->BorderRight - 1;   /* window to keep        */
  1188.     rectangle.MaxY = w->Height - w->BorderBottom - 1;  /* the glyph within      */
  1189.                                                        /* window bounds.        */
  1190.     if (region = NewRegion())                          /* For more information, */
  1191.     {                                                  /* see the "Layers"      */
  1192.       if (OrRectRegion(region, &rectangle))            /* chapter of the        */
  1193.       {                                                /* RKRM: Libraries       */
  1194.         InstallClipRegion(w->WLayer, region);          /* Manual.               */
  1195.  
  1196.         if (SetInfo(ge,
  1197.                     OT_GlyphCode, unicode,                      /* Set the glyph to */
  1198.                     OT_PointHeight, (ULONG) pointheight << 16,  /* rotate and its   */
  1199.                     TAG_END) == OTERR_Success)                  /* pointsize.       */
  1200.         {
  1201.           SetDrMd(w->RPort, JAM1);
  1202.           if (tempbitmap = AllocRaster(640, 200))
  1203.           {
  1204.             if (ModifyIDCMP(w, IDCMP_CLOSEWINDOW)) /* Turn on close window reports  */
  1205.             {                                      /* so the example can quit.      */
  1206.               for (i = 0; done == FALSE; i++)
  1207.               {
  1208.                 if (i == TABLE_ENTRIES)
  1209.                   i = 0;
  1210.  
  1211.                 sin = table[i][SINE_INDEX];   /* Step through the sine/cosine array */
  1212.                 cos = table[i][COSINE_INDEX]; /* 360 degrees @ 15 degree increments */
  1213.  
  1214.  
  1215.                 if (SetInfo(ge,                  /* Set the current rotation angle. */
  1216.                             OT_RotateSin, sin,
  1217.                             OT_RotateCos, cos,
  1218.                             TAG_END) == OTERR_Success)
  1219.                 {
  1220.                   if ((ObtainInfo(ge, OT_GlyphMap, &gm, TAG_END)) == OTERR_Success)
  1221.                   {
  1222.                     oldx = x;               /* Calculate the dimension and position */
  1223.                     oldy = y;               /* of the new glyph's bitmap and save   */
  1224.                     olddx = dx;             /* the old values so we can erase the   */
  1225.                     olddy = dy;             /* glyph that is still on the screen.   */
  1226.                     x = centerx - gm->glm_X0;
  1227.                     y = centery - gm->glm_Y0;
  1228.                     dx = gm->glm_BMModulo * 8;
  1229.                     dy = gm->glm_BMRows;
  1230.  
  1231.                     CopyMem(gm->glm_BitMap,/* Copy the glyph's bitmap into Chip RAM */
  1232.                             tempbitmap,    /* so we can blit it into a RastPort.    */
  1233.                             gm->glm_BMModulo * gm->glm_BMRows);
  1234.  
  1235.                                                             /* Erase the old glyph. */
  1236.                     RectFill(rp, oldx, oldy, oldx + olddx, oldy + olddy);
  1237.  
  1238.                     WaitBlit();                 /* Wait for the old glyph to erase. */
  1239.  
  1240.                     BltTemplate(                   /* Blit the new glyph into the   */
  1241.                                  tempbitmap,       /* window's RastPort.            */
  1242.                                  0,
  1243.                                  gm->glm_BMModulo,
  1244.                                  w->RPort,
  1245.                                  x,
  1246.                                  y,
  1247.                                  dx,
  1248.                                  dy);          /* Running several instances of this */
  1249.                                                /* example simultaneously can really */
  1250.                                                /* slow the system, so we give other */
  1251.                     TimeDelay(UNIT_VBLANK, 0, 250000);  /*   tasks a chance to run. */
  1252.                     ReleaseInfo(ge, OT_GlyphMap, gm, TAG_END);
  1253.                   }
  1254.                 }                               /* Check for a CLOSEWINDOW message. */
  1255.                 while (mymsg = (struct IntuiMessage *) GetMsg(w->UserPort))
  1256.                 {
  1257.                   ReplyMsg((struct Message *) mymsg);
  1258.                   done = TRUE;
  1259.                 }
  1260.               }
  1261.             }
  1262.             FreeRaster(tempbitmap, 640, 200);
  1263.           }
  1264.         }
  1265.       }
  1266.       DisposeRegion(region);
  1267.     }
  1268.     CloseLibrary(LayersBase);
  1269.   }
  1270. }
  1271.  
  1272.  
  1273.  
  1274.  
  1275.  
  1276.  
  1277.  
  1278.  
  1279.  
  1280.  
  1281.  
  1282.  
  1283.  
  1284.  
  1285.  
  1286.  
  1287.  
  1288.  
  1289.  
  1290. ;/* View.c - Execute me to compile me with SAS/C 5.10a
  1291. LC -cfistq -v -y -j73 View.c
  1292. Blink FROM LIB:c.o,BulletMainFile.o,engine.o,View.o TO View LIBRARY LIB:LC.lib,LIB:Amiga.lib
  1293. quit ;*/
  1294.  
  1295.  
  1296. #include <exec/types.h>
  1297. #include <exec/memory.h>
  1298. #include <diskfont/diskfonttag.h>
  1299. #include <diskfont/diskfont.h>
  1300. #include <diskfont/glyph.h>
  1301. #include <diskfont/oterrors.h>
  1302. #include <graphics/gfx.h>
  1303. #include <utility/tagitem.h>
  1304. #include <intuition/intuition.h>
  1305. #include <devices/timer.h>
  1306. #include <dos/dos.h>
  1307.  
  1308. #include <clib/alib_stdio_protos.h>
  1309. #include <clib/alib_protos.h>
  1310. #include <clib/bullet_protos.h>
  1311. #include <clib/exec_protos.h>
  1312. #include <clib/dos_protos.h>
  1313. #include <clib/graphics_protos.h>
  1314. #include <clib/intuition_protos.h>
  1315.  
  1316. UBYTE          *vers = "\e0$VER: View 38.6";
  1317.  
  1318. extern struct Library *BulletBase, *UtilityBase, *GfxBase, *IntuitionBase;
  1319. void            BulletExample(struct GlyphEngine *,
  1320.                               struct Window *,
  1321.                               struct RastPort *,
  1322.                               ULONG, ULONG, ULONG, STRPTR);
  1323. struct GlyphMap *gm;
  1324. PLANEPTR        tempbitmap;
  1325. struct IntuiMessage *mymsg;
  1326. UBYTE          *viewfilebuf, *currchar;
  1327. ULONG           currposition, emheight, emwidth, x, y;
  1328.  
  1329. BPTR            viewfile;
  1330. LONG            actual;
  1331. struct Task    *mytask;
  1332. struct FileInfoBlock *fib;
  1333.  
  1334. void
  1335. BulletExample(struct GlyphEngine * ge,
  1336.               struct Window * w, struct RastPort * rp,
  1337.               ULONG pointheight, ULONG xdpi, ULONG ydpi, STRPTR viewfilename)
  1338. {
  1339.   UWORD           wlimitx, wlimity, newwidth;
  1340.   FIXED           kern;
  1341.  
  1342.   wlimitx = w->Width  - w->BorderRight  - 2; /* The X and Y extent of the window */
  1343.   wlimity = w->Height - w->BorderBottom - 2; /* that we can draw into.           */
  1344.  
  1345.   if (SetInfo(ge,                                      /* Set up the X and Y DPI of */
  1346.               OT_DeviceDPI, ((ULONG)xdpi) << 16 | ydpi,/* target raster.  Neither   */
  1347.               OT_PointHeight, (ULONG)pointheight << 16,/* of these can be zero!     */
  1348.               TAG_END) != OTERR_Success)               /* BulletMainFile.c checks   */
  1349.   return;                                              /* for zero.                 */
  1350.  
  1351.   if (viewfile = Open(viewfilename, MODE_OLDFILE))/* Open the ASCII file to display.*/
  1352.   {
  1353.     if (fib = AllocDosObject(DOS_FIB, NULL))      /* Find out how big the display   */
  1354.     {                                             /* file is by looking at its      */
  1355.       if (ExamineFH(viewfile, fib))               /* FileInfoBlock.  Allocate that  */
  1356.       {                                           /* Much memory.                   */
  1357.         if (viewfilebuf = (UBYTE *) AllocVec(fib->fib_Size, MEMF_CLEAR))
  1358.         {
  1359.           if (Read(viewfile, (UBYTE *) viewfilebuf, fib->fib_Size))    /* Read the  */
  1360.           {                                          /* whole file into its buffer. */
  1361.             SetDrMd(w->RPort, JAM1);
  1362.             if (tempbitmap = AllocRaster(640, 200)) /* Allocate some Chip RAM space */
  1363.             {      /* where we can temporarily store the glyph so we can blit it.   */
  1364.               if (ModifyIDCMP(w, IDCMP_CLOSEWINDOW))  /* Turn on the Close gadget.  */
  1365.               {
  1366.                 emheight = (pointheight * ydpi) / 72; /* Calculate the dimensions   */
  1367.                 emwidth = (pointheight * xdpi) / 72;  /* of the EM square in screen */
  1368.                      /* pixels. This is necessary because bullet.library measures   */
  1369.                      /* character widths and kerning values as fractions of an EM.  */
  1370.                      /* An EM (pronounced like the letter 'M') is a measure of      */
  1371.                      /* distance that is equal to the point size of a typeface      */
  1372.                      /* (which means one EM is not constant across different type   */
  1373.                      /* sizes).  For a 72 point typeface, one EM = 72 points which  */
  1374.                      /* approximately equals one inch.                              */
  1375.  
  1376.                 x = w->BorderLeft + 2;           /* Calculate the starting point    */
  1377.                 y = w->BorderTop + 2 + emheight; /* for glyph rendering.            */
  1378.  
  1379.                                       /* Step through each character in the buffer. */
  1380.                 for (currposition = 0; currposition < fib->fib_Size; currposition++)
  1381.                 {
  1382.                                 /* Set the current glyph, which is the one we'll be */
  1383.                                 /* rendering in this interation of the loop, and    */
  1384.                                 /* the secondary glyph, which, besides being the    */
  1385.                                 /* next glyph we will render, is necessary to find  */
  1386.                                 /* the proper kerning value between the glyphs.     */
  1387.                                 /* Notice that this example does not account for    */
  1388.                                 /* the presence of non-printables (carriage return, */
  1389.                                 /* DEL, etc.) which effects the kerning.  A real    */
  1390.                   if (SetInfo(ge,  /* application should consider these.            */
  1391.                               OT_GlyphCode,  (ULONG) viewfilebuf[currposition],
  1392.                               OT_GlyphCode2, (ULONG) viewfilebuf[currposition + 1],
  1393.                               TAG_END) == OTERR_Success)
  1394.                   {
  1395.                     kern = 0;         /* Find the kerning adjustment between glyph1 */
  1396.                                       /* and glyph2.  This example doesn't account  */
  1397.                                       /* for the validity of the glyphs.            */
  1398.                     ObtainInfo(ge, OT_TextKernPair, &kern, TAG_END);
  1399.  
  1400.                                                   /* Ask the scaling engine for the */
  1401.                                                   /* bitmap for the current glyph.  */
  1402.                     if ((ObtainInfo(ge, OT_GlyphMap, &gm, TAG_END)) == OTERR_Success)
  1403.                     {
  1404.                        /* Calculate the width of the current character including    */
  1405.                        /* any kerning adjustment.  Because the width is represented */
  1406.                        /* as a fixed point binary fraction of an EM, this needs to  */
  1407.                        /* be converted to a width in screen pixels.                 */
  1408.                       newwidth = ((gm->glm_Width - kern) * emwidth) / 65536;
  1409.  
  1410.  
  1411.                       if ((x + newwidth) > wlimitx)  /* Make sure the glyph gets    */
  1412.                       {                              /* rendered inside the window  */
  1413.                                                      /* bounds.                     */
  1414.                         x = w->BorderLeft + 2;
  1415.                         y += emheight;
  1416.                         if (y > wlimity)   /* If the text goes beyond the bottom of */
  1417.                         {                  /* the window, clear the window and move */
  1418.                                            /* the current rendering position to the */
  1419.                                            /* upper left.                           */
  1420.                           y = w->BorderTop + 2 + emheight;
  1421.                           RectFill(rp, w->BorderLeft, w->BorderTop, wlimitx, wlimity);
  1422.                         }
  1423.                       }
  1424.  
  1425.                       CopyMem(gm->glm_BitMap,/* Copy the raw bitmap to chip memory. */
  1426.                               tempbitmap,
  1427.                               gm->glm_BMModulo * gm->glm_BMRows);
  1428.  
  1429.                       BltTemplate(           /* Render the glyph using the blitter  */
  1430.                                              /* and the RastPort settings.          */
  1431.                                    (PLANEPTR) (((ULONG) tempbitmap)
  1432.                                      + (gm->glm_BMModulo * gm->glm_BlackTop)
  1433.                                          + ((gm->glm_BlackLeft >> 4) << 1)),
  1434.                                    gm->glm_BlackLeft & 0xF,
  1435.                                    gm->glm_BMModulo,
  1436.                                    w->RPort,
  1437.                                    x - gm->glm_X0 + gm->glm_BlackLeft,
  1438.                                    y - gm->glm_Y0 + gm->glm_BlackTop,
  1439.                                    gm->glm_BlackWidth,     /* glm_X0 & Y0 are used  */
  1440.                                    gm->glm_BlackHeight);   /* to make the example a */
  1441.                                     /* little simpler.  They are not as accurate as */
  1442.                                     /* using glm_XOrigin and glm_YOrigin in con-    */
  1443.                                     /* juntion with fractional width and kerning    */
  1444.                                     /* values.                                      */
  1445.  
  1446.                       x += newwidth;
  1447.                       ReleaseInfo(ge, OT_GlyphMap, gm, TAG_END);
  1448.                     }
  1449.                     while (mymsg = (struct IntuiMessage *) GetMsg(w->UserPort))
  1450.                     {                                       /* Did the user hit the */
  1451.                       ReplyMsg((struct Message *) mymsg);   /* Close Gadget?        */
  1452.                       currposition = fib->fib_Size + 1;
  1453.                     }
  1454.                   }
  1455.                 }
  1456.               }
  1457.               FreeRaster(tempbitmap, 640, 200);
  1458.             }
  1459.           }
  1460.           FreeVec(viewfilebuf);
  1461.         }
  1462.       }
  1463.       FreeDosObject(DOS_FIB, fib);
  1464.     }
  1465.     Close(viewfile);
  1466.   }
  1467. }
  1468.  
  1469.  
  1470.  
  1471.  
  1472.  
  1473.  
  1474.  
  1475.  
  1476.  
  1477.  
  1478.  
  1479.  
  1480.  
  1481.  
  1482.  
  1483.  
  1484.  
  1485.  
  1486.