home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / gnu / gs-2.6.1.4-src.lha / src / amiga / gs-2.6.1.4 / gdevamiga.c < prev    next >
C/C++ Source or Header  |  1994-02-02  |  116KB  |  5,538 lines

  1. /* Copyright (C) 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gdevamiga.c */
  21. /* Amiga driver for Ghostscript library, requires Kickstart 2.04 or higher */
  22.  
  23. /* Written by Olaf `Olsen' Barthel, last change 29 January 1994
  24.  *
  25.  * My address:   Olaf Barthel
  26.  *               Brabeckstrasse 35
  27.  *             D-30559 Hannover
  28.  *
  29.  *      eMail:   olsen@sourcery.han.de
  30.  */
  31.  
  32. #define CheckIO foo123
  33. #define ushort foo
  34.  
  35. #include <intuition/intuitionbase.h>
  36. #include <intuition/gadgetclass.h>
  37. #include <intuition/imageclass.h>
  38. #include <intuition/icclass.h>
  39. #include <graphics/displayinfo.h>
  40. #include <libraries/iffparse.h>
  41. #include <graphics/gfxbase.h>
  42. #include <devices/printer.h>
  43. #include <devices/prtbase.h>
  44. #include <devices/prtgfx.h>
  45. #include <libraries/asl.h>
  46. #include <exec/memory.h>
  47. #include <clib/macros.h>
  48. #include <dos/dostags.h>
  49. #include <dos/rdargs.h>
  50. #include <dos/var.h>
  51. #include <dos/dos.h>
  52.  
  53. #include <clib/intuition_protos.h>
  54. #include <clib/graphics_protos.h>
  55. #include <clib/iffparse_protos.h>
  56. #include <clib/utility_protos.h>
  57. #include <clib/layers_protos.h>
  58. #include <clib/exec_protos.h>
  59. #include <clib/dos_protos.h>
  60. #include <clib/asl_protos.h>
  61.  
  62. /*
  63. #include <inline/stubs.h>
  64. #include <inline/iffparse.h>
  65. #include <inline/utility.h>
  66. #include <inline/exec.h>
  67. #include <inline/dos.h>
  68. */
  69.  
  70. #include <string.h>
  71. #include <signal.h>
  72.  
  73. #undef ushort
  74. #undef CheckIO
  75.  
  76. struct IORequest *CheckIO(struct IORequest *);
  77.  
  78. #include "gx.h"        /* for gx_bitmap; includes std.h */
  79. #include "gsmatrix.h"    /* needed for gxdevice.h */
  80. #include "gxdevice.h"
  81. #include "gserrors.h"
  82. #include "gsprops.h"
  83.  
  84.     /* Here is how to select a default page size format:
  85.      *
  86.      * Either enter include a line such as
  87.      *
  88.      *   #define AMIGA_PAGE_A4 1
  89.      *
  90.      * Somewhere above in this module, or edit the makefile
  91.      * to feature the option
  92.      *
  93.      *   -dAMIGA_PAGE_A4
  94.      *
  95.      * among the device specific flags. Available default page
  96.      * size formats are:
  97.      *
  98.      *   AMIGA_PAGE_A4         European A4 page size (default)
  99.      *   AMIGA_PAGE_A3         European A3 page size
  100.      *   AMIGA_PAGE_LETTER     US letter page size
  101.      *   AMIGA_PAGE_LEGAL      US legal page size
  102.      *   AMIGA_PAGE_LEDGER     US ledger paper size
  103.      *   AMIGA_PAGE_TABLOID    US tabloid paper size
  104.      */
  105.  
  106.     /* Select the default paper size if none specified. */
  107.  
  108. #if !defined(AMIGA_PAGE_A4) && !defined(AMIGA_PAGE_A3) && !defined(AMIGA_PAGE_LETTER) && !defined(AMIGA_PAGE_LEGAL) && !defined(AMIGA_PAGE_LEDGER) && !defined(AMIGA_PAGE_TABLOID)
  109. /*#define AMIGA_PAGE_A4 1*/
  110. #define AMIGA_PAGE_A3 1
  111. #endif    /* PAGE SIZE */
  112.  
  113.     /* A4 page size (in inches!) */
  114.  
  115. #ifdef AMIGA_PAGE_A4
  116. #define DEFAULT_WIDTH        8.2
  117. #define DEFAULT_HEIGHT        11.6
  118. #endif    /* AMIGA_PAGE_A4 */
  119.  
  120.     /* A3 page size */
  121.  
  122. #ifdef AMIGA_PAGE_A3
  123. #define DEFAULT_WIDTH        11.6
  124. #define DEFAULT_HEIGHT        16.5
  125. #endif    /* AMIGA_PAGE_A4 */
  126.  
  127.     /* US letter page size */
  128.  
  129. #ifdef AMIGA_PAGE_LETTER
  130. #define DEFAULT_WIDTH        8.5
  131. #define DEFAULT_HEIGHT        11.0
  132. #endif    /* AMIGA_PAGE_LETTER */
  133.  
  134.     /* US legal page size */
  135.  
  136. #ifdef AMIGA_PAGE_LEGAL
  137. #define DEFAULT_WIDTH        8.5
  138. #define DEFAULT_HEIGHT        14.0
  139. #endif    /* AMIGA_PAGE_LEGAL */
  140.  
  141.     /* US ledger page size */
  142.  
  143. #ifdef AMIGA_PAGE_LEDGER
  144. #define DEFAULT_WIDTH        16.0
  145. #define DEFAULT_HEIGHT        11.0
  146. #endif    /* AMIGA_PAGE_LEDGER */
  147.  
  148.     /* US tabloid page size */
  149.  
  150. #ifdef AMIGA_PAGE_TABLOID
  151. #define DEFAULT_WIDTH        11.0
  152. #define DEFAULT_HEIGHT        17.0
  153. #endif    /* AMIGA_PAGE_LEDGER */
  154.  
  155.     /* Default output file name. */
  156.  
  157. #define DEFAULT_FILENAME    "gs_page"
  158.  
  159.     /* Turn a byte into a 24 bit colour value. */
  160.  
  161. #define SPREAD(i)    ((ULONG)(i) << 24 | (ULONG)(i) << 16 | (ULONG)(i) << 8 | (i))
  162.  
  163.     /* Scroller gadget IDs. */
  164.  
  165. enum    {    VERTICAL_SCROLLER,    HORIZONTAL_SCROLLER,
  166.         UP_ARROW,        DOWN_ARROW,
  167.         LEFT_ARROW,        RIGHT_ARROW,
  168.  
  169.         GADGET_COUNT };
  170.  
  171.     /* Scroller arrow IDs. */
  172.  
  173. enum    {    UP_IMAGE,        DOWN_IMAGE,
  174.         LEFT_IMAGE,        RIGHT_IMAGE,
  175.  
  176.         IMAGE_COUNT };
  177.  
  178.     /* Codes for the MoveAround() routine. */
  179.  
  180. enum    {    MOVE_MIN,MOVE_FAR_DOWN,MOVE_DOWN,MOVE_UP,MOVE_FAR_UP,MOVE_MAX };
  181.  
  182.     /* Some handy bit masks. */
  183.  
  184. #define SIG_KILL    SIGBREAKF_CTRL_C
  185. #define SIG_HANDSHAKE    SIGF_SINGLE
  186.  
  187.     /* Static dimensions of scroller arrows. */
  188.  
  189. #define ARROW_WIDTH    16
  190. #define ARROW_HEIGHT    11
  191.  
  192.     /* The `Help' key raw code. */
  193.  
  194. #define HELP_CODE    95
  195.  
  196.     /* Minimum window inner area dimension. */
  197.  
  198. #define MINIMUM_WIDTH    64
  199. #define MINIMUM_HEIGHT    32
  200.  
  201.     /* Handy superbitmap window macros. */
  202.  
  203. #define LAYERXOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_X)
  204. #define LAYERYOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_Y)
  205.  
  206.     /* User input to listen to. */
  207.  
  208. #define IDCMP_FLAGS    (IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE | IDCMP_NEWSIZE | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_RAWKEY)
  209.  
  210.     /* Chunk IDs. */
  211.  
  212. #define ID_ILBM        MAKE_ID('I','L','B','M')
  213. #define ID_BMHD        MAKE_ID('B','M','H','D')
  214. #define ID_CMAP        MAKE_ID('C','M','A','P')
  215. #define ID_CAMG        MAKE_ID('C','A','M','G')
  216. #define ID_ANNO        MAKE_ID('A','N','N','O')
  217. #define ID_DPI        MAKE_ID('D','P','I',' ')
  218. #define ID_BODY        MAKE_ID('B','O','D','Y')
  219.  
  220.     /* Chunk contents definitions. */
  221.  
  222. typedef struct
  223. {
  224.     UWORD        w,h;            /* raster width & height in pixels */
  225.     WORD        x,y;            /* position for this image */
  226.     UBYTE        nPlanes;        /* # source bitplanes */
  227.     UBYTE        masking;        /* masking technique */
  228.     UBYTE        compression;        /* compression algoithm */
  229.     UBYTE        pad1;            /* UNUSED.  For consistency, put 0 here.*/
  230.     UWORD        transparentColor;    /* transparent "color number" */
  231.     UBYTE        xAspect,yAspect;    /* aspect ratio, a rational number x/y */
  232.     WORD        pageWidth,pageHeight;    /* source "page" size in pixels */
  233. } BitMapHeader;
  234.  
  235. typedef struct
  236. {
  237.     UWORD        dpi_x;
  238.     UWORD        dpi_y;
  239. } DPIHeader;
  240.  
  241.     /* Packer modes. */
  242.  
  243. #define DUMP        0
  244. #define RUN        1
  245.  
  246.     /* Minimum data run size, maximum data run size and maximum cache size. */
  247.  
  248. #define MINRUN        3
  249. #define MAXRUN        128
  250. #define MAXDAT        128
  251.  
  252.     /* This module actually implements four different Amiga based
  253.      * devices. As the rendering operations are all the same,
  254.      * one single device definition is sufficient.
  255.      */
  256.  
  257. typedef struct gx_device_amiga
  258. {
  259.     gx_device_common;
  260.  
  261.     struct Screen    *screen;    /* Any screen */
  262.     struct Window    *window;    /* Some window to be opened on the Workbench screen */
  263.  
  264.     LONG         super_width,    /* Superbitmap width */
  265.              super_height;    /* Superbitmap height */
  266.  
  267.     struct BitMap    *super_bitmap;    /* Window superbitmap area */
  268.     struct Gadget    **gadget;    /* Scroller gadgets */
  269.     struct Image    **image;    /* Scroller arrow images */
  270.  
  271.     struct Task    *dispatcher;    /* Slider dispatch task */
  272.     struct Process    *main;        /* Main program */
  273.  
  274.     struct RastPort    *rport;        /* Rendering area */
  275.  
  276.     struct IODRPReq *printer;    /* Printer interface data */
  277.     struct MsgPort    *port;        /* Printer io data */
  278.  
  279.     struct ColorMap    *colormap;    /* A black/white colour map */
  280.     struct BitMap    *bitmap;    /* Rendering bitmap data */
  281.     PLANEPTR     bitplane;    /* Rendering raster */
  282.  
  283.     gx_color_index     last_pen;    /* The last colour set */
  284.  
  285.     float         page_width,    /* The page width */
  286.              page_height;    /* The page height */
  287.     char         file_name[256];/* The output file name */
  288.     int         page_count;    /* The page number counter */
  289.  
  290.     int         cube_size;    /* Colour cube size, 0 for b/w */
  291.     struct RastPort    *temp_rport;    /* Temporary raster port for pixmap imaging. */
  292.     UBYTE        *temp_array;    /* Temporary colour manipulation array. */
  293.     LONG        *pens;
  294. } gx_device_amiga;
  295.  
  296.     /* Function prototypes */
  297.  
  298. VOID            set_mono_device(gx_device_amiga *dev);
  299. VOID            set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens);
  300. VOID            set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize);
  301. VOID            DeleteBitMap(struct BitMap *BitMap,BOOL Private);
  302. struct BitMap *        CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private);
  303. VOID            DeleteTempRPort(struct RastPort *Temp);
  304. struct RastPort *    CreateTempRPort(struct RastPort *Source);
  305. LONG            Euclid(LONG a,LONG b);
  306. BYTE *            PutDump(register BYTE *Destination,register LONG Count);
  307. BYTE *            PutRun(register BYTE *Destination,LONG Count,WORD Char);
  308. LONG            PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize);
  309. BOOL            PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap);
  310. BOOL            PutANNO(struct IFFHandle *Handle);
  311. BOOL            PutCAMG(struct IFFHandle *Handle);
  312. BOOL            PutCMAP(struct IFFHandle *Handle);
  313. BOOL            PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI);
  314. BOOL            PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI);
  315. BOOL            SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI);
  316. float            GetInches(STRPTR Buffer);
  317. VOID            DispatchTask(VOID);
  318. VOID            DeleteScrollers(gx_device *dev);
  319. BOOL            CreateScrollers(gx_device *dev,struct Screen *Screen);
  320. VOID            WindowResize(gx_device *dev);
  321. VOID            WindowUpdate(struct Gadget *Gadget,gx_device *dev);
  322. VOID            MoveAround(struct Gadget *Gadget,LONG How,gx_device *dev);
  323. VOID            DispatchSuperWindow(gx_device *dev);
  324. void            devcleanup(VOID);
  325. gx_color_index        amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue);
  326. int            amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]);
  327. LONG *            AllocatePens(struct ViewPort *VPort,LONG CubeSize);
  328. int            amiga_open_default(gx_device *dev);
  329. int            amiga_open_low(gx_device *dev);
  330. int            amiga_open_high(gx_device *dev);
  331. int            amiga_open_super(gx_device *dev);
  332. int            amiga_open_a2024(gx_device *dev);
  333. int            amiga_open_picassoii(gx_device *dev);
  334. int            amiga_open_custom(gx_device *dev);
  335. int            amiga_open_printer(gx_device *dev);
  336. int            amiga_output_page_printer(gx_device *dev,int num_copies,int flush);
  337. int            amiga_close_printer(gx_device *dev);
  338. int            amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data);
  339. int            amiga_open(gx_device *dev,ULONG Mode);
  340. int            amiga_output_page(gx_device *dev,int num_copies,int flush);
  341. int            amiga_close(gx_device *dev);
  342. int            amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color);
  343. int            amiga_copy_mono(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one);
  344. int            amiga_copy_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  345. int            amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color);
  346. int            amiga_copy_mono_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one);
  347. int            amiga_copy_color_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  348. int            amiga_fill_rectangle_raw(gx_device *dev,int x,int y,int w,int h,gx_color_index color);
  349. int            amiga_draw_line_raw(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color);
  350. int            amiga_open_ilbm(gx_device *dev);
  351. int            amiga_output_page_ilbm(gx_device *dev,int num_copies,int flush);
  352. int            amiga_close_ilbm(gx_device *dev);
  353. int            amiga_get_props(gx_device *dev,gs_prop_item *plist);
  354. int            amiga_put_props(gx_device *dev,gs_prop_item *plist,int count);
  355. gx_color_index        amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue);
  356. int            amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]);
  357. gx_color_index        amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue);
  358. int            amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3]);
  359. int            amiga_copy_color8(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  360. int            amiga_copy_mono_raw_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one);
  361. int            amiga_copy_color_raw_color16(gx_device *dev,const UBYTE *data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  362. int            amiga_fill_rectangle_raw_color(gx_device *dev,int x,int y,int w,int h,gx_color_index color);
  363. int            amiga_draw_line_raw_color(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color);
  364.  
  365.     /* External reference to some libraries, required for version checking, etc. */
  366.  
  367. extern struct GfxBase *GfxBase;
  368. extern struct Library *AslBase;
  369.  
  370.     /* Number of packed bytes and pack buffer. */
  371.  
  372. LONG    PackedBytes;
  373. BYTE    Buffer[MAXDAT + 1];
  374.  
  375.     /* Bit masks. */
  376.  
  377. STATIC UBYTE    shift[8] = { 128, 64, 32, 16,  8,  4,  2,  1 },
  378.         masks[8] = { 127,191,223,239,247,251,253,254 };
  379.  
  380.     /* Device routine jump tables */
  381.  
  382. STATIC gx_device_procs amiga_default_procs =
  383. {
  384.     amiga_open_default,
  385.     gx_default_get_initial_matrix,
  386.     gx_default_sync_output,
  387.     amiga_output_page,
  388.     amiga_close,
  389.     amiga_map_rgb_color,
  390.     amiga_map_color_rgb,
  391.     amiga_fill_rectangle,
  392.     gx_default_tile_rectangle,
  393.     amiga_copy_mono,
  394.     amiga_copy_color,
  395.     amiga_draw_line,
  396.     gx_default_get_bits,
  397.     amiga_get_props,
  398.     amiga_put_props
  399. };
  400.  
  401. STATIC gx_device_procs amiga_low_procs =
  402. {
  403.     amiga_open_low,
  404.     gx_default_get_initial_matrix,
  405.     gx_default_sync_output,
  406.     amiga_output_page,
  407.     amiga_close,
  408.     amiga_map_rgb_color,
  409.     amiga_map_color_rgb,
  410.     amiga_fill_rectangle,
  411.     gx_default_tile_rectangle,
  412.     amiga_copy_mono,
  413.     amiga_copy_color,
  414.     amiga_draw_line,
  415.     gx_default_get_bits,
  416.     amiga_get_props,
  417.     amiga_put_props
  418. };
  419.  
  420. STATIC gx_device_procs amiga_high_procs =
  421. {
  422.     amiga_open_high,
  423.     gx_default_get_initial_matrix,
  424.     gx_default_sync_output,
  425.     amiga_output_page,
  426.     amiga_close,
  427.     amiga_map_rgb_color,
  428.     amiga_map_color_rgb,
  429.     amiga_fill_rectangle,
  430.     gx_default_tile_rectangle,
  431.     amiga_copy_mono,
  432.     amiga_copy_color,
  433.     amiga_draw_line,
  434.     gx_default_get_bits,
  435.     amiga_get_props,
  436.     amiga_put_props
  437. };
  438.  
  439. STATIC gx_device_procs amiga_super_procs =
  440. {
  441.     amiga_open_super,
  442.     gx_default_get_initial_matrix,
  443.     gx_default_sync_output,
  444.     amiga_output_page,
  445.     amiga_close,
  446.     amiga_map_rgb_color,
  447.     amiga_map_color_rgb,
  448.     amiga_fill_rectangle,
  449.     gx_default_tile_rectangle,
  450.     amiga_copy_mono,
  451.     amiga_copy_color,
  452.     amiga_draw_line,
  453.     gx_default_get_bits,
  454.     amiga_get_props,
  455.     amiga_put_props
  456. };
  457.  
  458. STATIC gx_device_procs amiga_a2024_procs =
  459. {
  460.     amiga_open_a2024,
  461.     gx_default_get_initial_matrix,
  462.     gx_default_sync_output,
  463.     amiga_output_page,
  464.     amiga_close,
  465.     amiga_map_rgb_color,
  466.     amiga_map_color_rgb,
  467.     amiga_fill_rectangle,
  468.     gx_default_tile_rectangle,
  469.     amiga_copy_mono,
  470.     amiga_copy_color,
  471.     amiga_draw_line,
  472.     gx_default_get_bits,
  473.     amiga_get_props,
  474.     amiga_put_props
  475. };
  476.  
  477. STATIC gx_device_procs amiga_picassoii_procs =
  478. {
  479.     amiga_open_picassoii,
  480.     gx_default_get_initial_matrix,
  481.     gx_default_sync_output,
  482.     amiga_output_page,
  483.     amiga_close,
  484.     amiga_map_rgb_color,
  485.     amiga_map_color_rgb,
  486.     amiga_fill_rectangle,
  487.     gx_default_tile_rectangle,
  488.     amiga_copy_mono,
  489.     amiga_copy_color,
  490.     amiga_draw_line,
  491.     gx_default_get_bits,
  492.     amiga_get_props,
  493.     amiga_put_props
  494. };
  495.  
  496. STATIC gx_device_procs amiga_custom_procs =
  497. {
  498.     amiga_open_custom,
  499.     gx_default_get_initial_matrix,
  500.     gx_default_sync_output,
  501.     amiga_output_page,
  502.     amiga_close,
  503.     amiga_map_rgb_color,
  504.     amiga_map_color_rgb,
  505.     amiga_fill_rectangle,
  506.     gx_default_tile_rectangle,
  507.     amiga_copy_mono,
  508.     amiga_copy_color,
  509.     amiga_draw_line,
  510.     gx_default_get_bits,
  511.     amiga_get_props,
  512.     amiga_put_props
  513. };
  514.  
  515. STATIC gx_device_procs amiga_printer_procs =
  516. {
  517.     amiga_open_printer,
  518.     gx_default_get_initial_matrix,
  519.     gx_default_sync_output,
  520.     amiga_output_page_printer,
  521.     amiga_close_printer,
  522.     amiga_map_rgb_color,
  523.     amiga_map_color_rgb,
  524.     amiga_fill_rectangle_raw,
  525.     gx_default_tile_rectangle,
  526.     amiga_copy_mono_raw,
  527.     amiga_copy_color_raw,
  528.     amiga_draw_line_raw,
  529.     amiga_get_bits,
  530.     amiga_get_props,
  531.     amiga_put_props
  532. };
  533.  
  534. STATIC gx_device_procs amiga_ilbm_procs =
  535. {
  536.     amiga_open_ilbm,
  537.     gx_default_get_initial_matrix,
  538.     gx_default_sync_output,
  539.     amiga_output_page_ilbm,
  540.     amiga_close_ilbm,
  541.     amiga_map_rgb_color,
  542.     amiga_map_color_rgb,
  543.     amiga_fill_rectangle_raw,
  544.     gx_default_tile_rectangle,
  545.     amiga_copy_mono_raw,
  546.     amiga_copy_color_raw,
  547.     amiga_draw_line_raw,
  548.     amiga_get_bits,
  549.     amiga_get_props,
  550.     amiga_put_props
  551. };
  552.  
  553.     /* Default device: opens a window on the Workbench screen and renders into it */
  554.  
  555. gx_device_amiga gs_amiga_device =
  556. {
  557.     sizeof(gx_device_amiga),    /* params_size */
  558.     &amiga_default_procs,        /* procs */
  559.     "amiga",            /* dname */
  560.     0, 0,                /* width, height */
  561.     72.27, 72.27,            /* xdpi, ydpi */
  562.     no_margins,            /* margins */
  563.     dci_black_and_white,        /* color info */
  564.     0,                /* is_open */
  565.  
  566.     NULL,                /* screen */
  567.     NULL,                /* window */
  568.  
  569.     0,                /* super_width */
  570.     0,                /* super_height */
  571.     NULL,                /* super_bitmap */
  572.     NULL,                /* gadget */
  573.     NULL,                /* image */
  574.  
  575.     NULL,                /* dispatcher */
  576.     NULL,                /* main */
  577.  
  578.     NULL,                /* rport */
  579.  
  580.     NULL,                /* printer */
  581.     NULL,                /* port */
  582.     NULL,                /* colormap */
  583.     NULL,                /* bitmap */
  584.     NULL,                /* bitplane */
  585.  
  586.     1,                /* last_pen */
  587.  
  588.     DEFAULT_WIDTH,            /* page width */
  589.     DEFAULT_HEIGHT,            /* page height */
  590.     DEFAULT_FILENAME,        /* output file */
  591.     1,                /* page counter */
  592.  
  593.     0,                /* cube_size */
  594.     NULL,                /* temp_rport */
  595.     NULL,                /* temp_array */
  596.     NULL                /* pens */
  597. };
  598.  
  599.     /* Low resolution device: opens a lores custom screen and renders into it */
  600.  
  601. gx_device_amiga gs_amiga_low_device =
  602. {
  603.     sizeof(gx_device_amiga),    /* params_size */
  604.     &amiga_low_procs,        /* procs */
  605.     "amiga_low",            /* dname */
  606.     0, 0,                /* width, height */
  607.     72.27, 72.27,            /* xdpi, ydpi */
  608.     no_margins,            /* margins */
  609.     dci_black_and_white,        /* color info */
  610.     0,                /* is_open */
  611.  
  612.     NULL,                /* screen */
  613.     NULL,                /* window */
  614.  
  615.     0,                /* super_width */
  616.     0,                /* super_height */
  617.     NULL,                /* super_bitmap */
  618.     NULL,                /* gadget */
  619.     NULL,                /* image */
  620.  
  621.     NULL,                /* dispatcher */
  622.     NULL,                /* main */
  623.  
  624.     NULL,                /* rport */
  625.  
  626.     NULL,                /* printer */
  627.     NULL,                /* port */
  628.     NULL,                /* colormap */
  629.     NULL,                /* bitmap */
  630.     NULL,                /* bitplane */
  631.  
  632.     1,                /* last_pen */
  633.  
  634.     DEFAULT_WIDTH,            /* page width */
  635.     DEFAULT_HEIGHT,            /* page height */
  636.     DEFAULT_FILENAME,        /* output file */
  637.     1,                /* page counter */
  638.  
  639.     0,                /* cube_size */
  640.     NULL,                /* temp_rport */
  641.     NULL,                /* temp_array */
  642.     NULL                /* pens */
  643. };
  644.  
  645.     /* High resolution device: opens a highres-interlaced custom screen */
  646.  
  647. gx_device_amiga gs_amiga_high_device =
  648. {
  649.     sizeof(gx_device_amiga),    /* params_size */
  650.     &amiga_high_procs,        /* procs */
  651.     "amiga_high",            /* dname */
  652.     0, 0,                /* width, height */
  653.     72.27, 72.27,            /* xdpi, ydpi */
  654.     no_margins,            /* margins */
  655.     dci_black_and_white,        /* color info */
  656.     0,                /* is_open */
  657.  
  658.     NULL,                /* screen */
  659.     NULL,                /* window */
  660.  
  661.     0,                /* super_width */
  662.     0,                /* super_height */
  663.     NULL,                /* super_bitmap */
  664.     NULL,                /* gadget */
  665.     NULL,                /* image */
  666.  
  667.     NULL,                /* dispatcher */
  668.     NULL,                /* main */
  669.  
  670.     NULL,                /* rport */
  671.  
  672.     NULL,                /* printer */
  673.     NULL,                /* port */
  674.     NULL,                /* colormap */
  675.     NULL,                /* bitmap */
  676.     NULL,                /* bitplane */
  677.  
  678.     1,                /* last_pen */
  679.  
  680.     DEFAULT_WIDTH,            /* page width */
  681.     DEFAULT_HEIGHT,            /* page height */
  682.     DEFAULT_FILENAME,        /* output file */
  683.     1,                /* page counter */
  684.  
  685.     0,                /* cube_size */
  686.     NULL,                /* temp_rport */
  687.     NULL,                /* temp_array */
  688.     NULL                /* pens */
  689. };
  690.  
  691.     /* Super high resolution device: opens a super-highres-interlaced custom screen */
  692.  
  693. gx_device_amiga gs_amiga_super_device =
  694. {
  695.     sizeof(gx_device_amiga),    /* params_size */
  696.     &amiga_super_procs,        /* procs */
  697.     "amiga_super",            /* dname */
  698.     0, 0,                /* width, height */
  699.     72.27, 72.27,            /* xdpi, ydpi */
  700.     no_margins,            /* margins */
  701.     dci_black_and_white,        /* color info */
  702.     0,                /* is_open */
  703.  
  704.     NULL,                /* screen */
  705.     NULL,                /* window */
  706.  
  707.     0,                /* super_width */
  708.     0,                /* super_height */
  709.     NULL,                /* super_bitmap */
  710.     NULL,                /* gadget */
  711.     NULL,                /* image */
  712.  
  713.     NULL,                /* dispatcher */
  714.     NULL,                /* main */
  715.  
  716.     NULL,                /* rport */
  717.  
  718.     NULL,                /* printer */
  719.     NULL,                /* port */
  720.     NULL,                /* colormap */
  721.     NULL,                /* bitmap */
  722.     NULL,                /* bitplane */
  723.  
  724.     1,                /* last_pen */
  725.  
  726.     DEFAULT_WIDTH,            /* page width */
  727.     DEFAULT_HEIGHT,            /* page height */
  728.     DEFAULT_FILENAME,        /* output file */
  729.     1,                /* page counter */
  730.  
  731.     0,                /* cube_size */
  732.     NULL,                /* temp_rport */
  733.     NULL,                /* temp_array */
  734.     NULL                /* pens */
  735. };
  736.  
  737.     /* A2024 device: opens an A2024 custom screen */
  738.  
  739. gx_device_amiga gs_amiga_a2024_device =
  740. {
  741.     sizeof(gx_device_amiga),    /* params_size */
  742.     &amiga_a2024_procs,        /* procs */
  743.     "amiga_a2024",            /* dname */
  744.     0, 0,                /* width, height */
  745.     72.27, 72.27,            /* xdpi, ydpi */
  746.     no_margins,            /* margins */
  747.     dci_black_and_white,        /* color info */
  748.     0,                /* is_open */
  749.  
  750.     NULL,                /* screen */
  751.     NULL,                /* window */
  752.  
  753.     0,                /* super_width */
  754.     0,                /* super_height */
  755.     NULL,                /* super_bitmap */
  756.     NULL,                /* gadget */
  757.     NULL,                /* image */
  758.  
  759.     NULL,                /* dispatcher */
  760.     NULL,                /* main */
  761.  
  762.     NULL,                /* rport */
  763.  
  764.     NULL,                /* printer */
  765.     NULL,                /* port */
  766.     NULL,                /* colormap */
  767.     NULL,                /* bitmap */
  768.     NULL,                /* bitplane */
  769.  
  770.     1,                /* last_pen */
  771.  
  772.     DEFAULT_WIDTH,            /* page width */
  773.     DEFAULT_HEIGHT,            /* page height */
  774.     DEFAULT_FILENAME,        /* output file */
  775.     1,                /* page counter */
  776.  
  777.     0,                /* cube_size */
  778.     NULL,                /* temp_rport */
  779.     NULL,                /* temp_array */
  780.     NULL                /* pens */
  781. };
  782.  
  783.     /* Picasso II device: opens a Picasso II custom screen */
  784.  
  785. gx_device_amiga gs_amiga_picassoii_device =
  786. {
  787.     sizeof(gx_device_amiga),    /* params_size */
  788.     &amiga_picassoii_procs,        /* procs */
  789.     "amiga_picassoii",        /* dname */
  790.     0, 0,                /* width, height */
  791.     72.27, 72.27,            /* xdpi, ydpi */
  792.     no_margins,            /* margins */
  793.     dci_black_and_white,        /* color info */
  794.     0,                /* is_open */
  795.  
  796.     NULL,                /* screen */
  797.     NULL,                /* window */
  798.  
  799.     0,                /* super_width */
  800.     0,                /* super_height */
  801.     NULL,                /* super_bitmap */
  802.     NULL,                /* gadget */
  803.     NULL,                /* image */
  804.  
  805.     NULL,                /* dispatcher */
  806.     NULL,                /* main */
  807.  
  808.     NULL,                /* rport */
  809.  
  810.     NULL,                /* printer */
  811.     NULL,                /* port */
  812.     NULL,                /* colormap */
  813.     NULL,                /* bitmap */
  814.     NULL,                /* bitplane */
  815.  
  816.     1,                /* last_pen */
  817.  
  818.     DEFAULT_WIDTH,            /* page width */
  819.     DEFAULT_HEIGHT,            /* page height */
  820.     DEFAULT_FILENAME,        /* output file */
  821.     1,                /* page counter */
  822.  
  823.     0,                /* cube_size */
  824.     NULL,                /* temp_rport */
  825.     NULL,                /* temp_array */
  826.     NULL                /* pens */
  827. };
  828.  
  829.     /* Custom device: opens a custom screen, will ask for screen mode or check env variable. */
  830.  
  831. gx_device_amiga gs_amiga_custom_device =
  832. {
  833.     sizeof(gx_device_amiga),    /* params_size */
  834.     &amiga_custom_procs,        /* procs */
  835.     "amiga_custom",            /* dname */
  836.     0, 0,                /* width, height */
  837.     72.27, 72.27,            /* xdpi, ydpi */
  838.     no_margins,            /* margins */
  839.     dci_black_and_white,        /* color info */
  840.     0,                /* is_open */
  841.  
  842.     NULL,                /* screen */
  843.     NULL,                /* window */
  844.  
  845.     0,                /* super_width */
  846.     0,                /* super_height */
  847.     NULL,                /* super_bitmap */
  848.     NULL,                /* gadget */
  849.     NULL,                /* image */
  850.  
  851.     NULL,                /* dispatcher */
  852.     NULL,                /* main */
  853.  
  854.     NULL,                /* rport */
  855.  
  856.     NULL,                /* printer */
  857.     NULL,                /* port */
  858.     NULL,                /* colormap */
  859.     NULL,                /* bitmap */
  860.     NULL,                /* bitplane */
  861.  
  862.     1,                /* last_pen */
  863.  
  864.     DEFAULT_WIDTH,            /* page width */
  865.     DEFAULT_HEIGHT,            /* page height */
  866.     DEFAULT_FILENAME,        /* output file */
  867.     1,                /* page counter */
  868.  
  869.     0,                /* cube_size */
  870.     NULL,                /* temp_rport */
  871.     NULL,                /* temp_array */
  872.     NULL                /* pens */
  873. };
  874.  
  875.     /* Printer device: renders the imagery and sends it to the printer */
  876.  
  877. gx_device_amiga gs_amiga_printer_device =
  878. {
  879.     sizeof(gx_device_amiga),    /* params_size */
  880.     &amiga_printer_procs,        /* procs */
  881.     "amiga_printer",        /* dname */
  882.     0, 0,                /* width, height */
  883.     72.27, 72.27,            /* xdpi, ydpi */
  884.     no_margins,            /* margins */
  885.     dci_black_and_white,        /* color info */
  886.     0,                /* is_open */
  887.  
  888.     NULL,                /* screen */
  889.     NULL,                /* window */
  890.  
  891.     0,                /* super_width */
  892.     0,                /* super_height */
  893.     NULL,                /* super_bitmap */
  894.     NULL,                /* gadget */
  895.     NULL,                /* image */
  896.  
  897.     NULL,                /* dispatcher */
  898.     NULL,                /* main */
  899.  
  900.     NULL,                /* rport */
  901.  
  902.     NULL,                /* printer */
  903.     NULL,                /* port */
  904.     NULL,                /* colormap */
  905.     NULL,                /* bitmap */
  906.     NULL,                /* bitplane */
  907.  
  908.     1,                /* last_pen */
  909.  
  910.     DEFAULT_WIDTH,            /* page width */
  911.     DEFAULT_HEIGHT,            /* page height */
  912.     DEFAULT_FILENAME,        /* output file */
  913.     1,                /* page counter */
  914.  
  915.     0,                /* cube_size */
  916.     NULL,                /* temp_rport */
  917.     NULL,                /* temp_array */
  918.     NULL                /* pens */
  919. };
  920.  
  921.     /* ILBM device: renders the imagery and saves it to an IFF-ILBM file. */
  922.  
  923. gx_device_amiga gs_amiga_ilbm_device =
  924. {
  925.     sizeof(gx_device_amiga),    /* params_size */
  926.     &amiga_ilbm_procs,        /* procs */
  927.     "amiga_ilbm",            /* dname */
  928.     0, 0,                /* width, height */
  929.     72.27, 72.27,            /* xdpi, ydpi */
  930.     no_margins,            /* margins */
  931.     dci_black_and_white,        /* color info */
  932.     0,                /* is_open */
  933.  
  934.     NULL,                /* screen */
  935.     NULL,                /* window */
  936.  
  937.     0,                /* super_width */
  938.     0,                /* super_height */
  939.     NULL,                /* super_bitmap */
  940.     NULL,                /* gadget */
  941.     NULL,                /* image */
  942.  
  943.     NULL,                /* dispatcher */
  944.     NULL,                /* main */
  945.  
  946.     NULL,                /* rport */
  947.  
  948.     NULL,                /* printer */
  949.     NULL,                /* port */
  950.     NULL,                /* colormap */
  951.     NULL,                /* bitmap */
  952.     NULL,                /* bitplane */
  953.  
  954.     1,                /* last_pen */
  955.  
  956.     DEFAULT_WIDTH,            /* page width */
  957.     DEFAULT_HEIGHT,            /* page height */
  958.     DEFAULT_FILENAME,        /* output file */
  959.     1,                /* page counter */
  960.  
  961.     0,                /* cube_size */
  962.     NULL,                /* temp_rport */
  963.     NULL,                /* temp_array */
  964.     NULL                /* pens */
  965. };
  966.  
  967.     /* Dark (black) and light (white) rendering colours; the default device
  968.      * determines the actual colours to be used by looking into the screen
  969.      * colour lookup table, the other device drivers leave these values
  970.      * untouched.
  971.      */
  972.  
  973. STATIC UBYTE    DarkPen        = 0,
  974.         LightPen    = 1;
  975.  
  976.     /* Cheap, but effective ;-) */
  977.  
  978. #define xdev ((gx_device_amiga *)dev)
  979.  
  980.     /* set_mono_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  981.      *
  982.      *    Reconfigure a device for monochrome output.
  983.      */
  984.  
  985. VOID
  986. set_mono_device(gx_device_amiga *dev)
  987. {
  988.     xdev -> color_info . depth        = 1;
  989.     xdev -> color_info . num_components    = 1;
  990.     xdev -> color_info . max_gray        = 1;
  991.     xdev -> color_info . max_rgb        = 0;
  992.     xdev -> color_info . dither_gray    = 2;
  993.     xdev -> color_info . dither_rgb        = 0;
  994.  
  995.     xdev -> procs -> copy_color        = amiga_copy_color;
  996.     xdev -> procs -> map_rgb_color        = amiga_map_rgb_color;
  997.     xdev -> procs -> map_color_rgb        = amiga_map_color_rgb;
  998.  
  999.     xdev -> cube_size            = 0;
  1000. }
  1001.  
  1002.     /* set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  1003.      *
  1004.      *    Reconfigure a device for colour output.
  1005.      */
  1006.  
  1007. VOID
  1008. set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens)
  1009. {
  1010.     xdev -> color_info . depth        = 8;
  1011.     xdev -> color_info . num_components    = 3;
  1012.     xdev -> color_info . max_gray        = cube_size - 1;
  1013.     xdev -> color_info . max_rgb        = cube_size - 1;
  1014.     xdev -> color_info . dither_gray    = cube_size;
  1015.     xdev -> color_info . dither_rgb        = cube_size;
  1016.  
  1017.     xdev -> procs -> copy_color        = amiga_copy_color8;
  1018.  
  1019.         /* Any colours to be remapped? */
  1020.  
  1021.     if(pens)
  1022.     {
  1023.         xdev -> procs -> map_rgb_color    = amiga_color_map_rgb_color_pen;
  1024.         xdev -> procs -> map_color_rgb    = amiga_color_map_color_rgb_pen;
  1025.         xdev -> pens            = pens;
  1026.     }
  1027.     else
  1028.     {
  1029.         xdev -> procs -> map_rgb_color    = amiga_color_map_rgb_color;
  1030.         xdev -> procs -> map_color_rgb    = amiga_color_map_color_rgb;
  1031.     }
  1032.  
  1033.         /* Remember the size of the RGB cube. */
  1034.  
  1035.     xdev -> cube_size            = cube_size;
  1036. }
  1037.  
  1038.     /* set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize):
  1039.      *
  1040.      *    Configure the printer device for colour output.
  1041.      */
  1042.  
  1043. VOID
  1044. set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize)
  1045. {
  1046.     xdev -> color_info . depth        = 16;
  1047.     xdev -> color_info . num_components    = 3;
  1048.     xdev -> color_info . max_gray        = CubeSize - 1;
  1049.     xdev -> color_info . max_rgb        = CubeSize - 1;
  1050.     xdev -> color_info . dither_gray    = CubeSize;
  1051.     xdev -> color_info . dither_rgb        = CubeSize;
  1052.  
  1053.     xdev -> procs -> fill_rectangle        = amiga_fill_rectangle_raw_color;
  1054.     xdev -> procs -> copy_mono        = amiga_copy_mono_raw_color;
  1055.     xdev -> procs -> copy_color        = amiga_copy_color_raw_color16;
  1056.     xdev -> procs -> draw_line        = amiga_draw_line_raw_color;
  1057.     xdev -> procs -> get_bits        = gx_default_get_bits;
  1058.     xdev -> procs -> map_rgb_color        = amiga_color_map_rgb_color;
  1059.     xdev -> procs -> map_color_rgb        = amiga_color_map_color_rgb;
  1060.     xdev -> cube_size            = CubeSize;
  1061. }
  1062.  
  1063.     /* DeleteBitMap(struct BitMap *BitMap,BOOL Private):
  1064.      *
  1065.      *    Free memory associated with a custom rendering bitmap.
  1066.      */
  1067.  
  1068. VOID
  1069. DeleteBitMap(struct BitMap *BitMap,BOOL Private)
  1070. {
  1071.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  1072.         FreeBitMap(BitMap);
  1073.     else
  1074.     {
  1075.         LONG i;
  1076.  
  1077.         for(i = 0 ; i < BitMap -> Depth ; i++)
  1078.         {
  1079.             if(BitMap -> Planes[i])
  1080.                 FreeVec(BitMap -> Planes[i]);
  1081.         }
  1082.  
  1083.         FreeVec(BitMap);
  1084.     }
  1085. }
  1086.  
  1087.     /* CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private):
  1088.      *
  1089.      *    Create a custom rendering bitmap.
  1090.      */
  1091.  
  1092. struct BitMap *
  1093. CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private)
  1094. {
  1095.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  1096.         return(AllocBitMap(Width,Height,Depth,Flags,Friend));
  1097.     else
  1098.     {
  1099.         struct BitMap    *BitMap;
  1100.         LONG         Plus;
  1101.         ULONG         MemType;
  1102.  
  1103.             /* Bitmap structure needs to be padded if more
  1104.              * than the standard eight bitplanes are to be
  1105.              * allocated.
  1106.              */
  1107.  
  1108.         if(Depth > 8)
  1109.             Plus = (Depth - 8) * sizeof(PLANEPTR);
  1110.         else
  1111.             Plus = 0;
  1112.  
  1113.         if(Private)
  1114.             MemType = MEMF_ANY;
  1115.         else
  1116.             MemType = MEMF_CHIP;
  1117.  
  1118.         if(BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap) + Plus,MEMF_ANY | MEMF_CLEAR))
  1119.         {
  1120.             LONG i,PageSize;
  1121.  
  1122.             InitBitMap(BitMap,Depth,Width,Height);
  1123.  
  1124.             PageSize = BitMap -> BytesPerRow * BitMap -> Rows;
  1125.  
  1126.             for(i = 0 ; i < BitMap -> Depth ; i++)
  1127.             {
  1128.                 if(!(BitMap -> Planes[i] = (PLANEPTR)AllocVec(PageSize,MemType)))
  1129.                 {
  1130.                     LONG j;
  1131.  
  1132.                     for(j = 0 ; j < i ; j++)
  1133.                         FreeVec(BitMap -> Planes[j]);
  1134.  
  1135.                     FreeVec(BitMap);
  1136.  
  1137.                     return(NULL);
  1138.                 }
  1139.             }
  1140.  
  1141.             return(BitMap);
  1142.         }
  1143.     }
  1144. }
  1145.  
  1146.     /* DeleteTempRPort(struct RastPort *Temp):
  1147.      *
  1148.      *    Free memory associated with a temporary raster port.
  1149.      */
  1150.  
  1151. VOID
  1152. DeleteTempRPort(struct RastPort *Temp)
  1153. {
  1154.     DeleteBitMap(Temp -> BitMap,FALSE);
  1155.  
  1156.     FreeVec(Temp);
  1157. }
  1158.  
  1159.     /* CreateTempRPort(struct RastPort *Source):
  1160.      *
  1161.      *    Allocate memory for temporary raster port (one line high).
  1162.      */
  1163.  
  1164. struct RastPort *
  1165. CreateTempRPort(struct RastPort *Source)
  1166. {
  1167.     struct RastPort *Temp;
  1168.  
  1169.     if(Temp = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
  1170.     {
  1171.         LONG Width,Depth;
  1172.  
  1173.         CopyMem(Source,Temp,sizeof(struct RastPort));
  1174.  
  1175.         Temp -> Layer = NULL;
  1176.  
  1177.         if(GfxBase -> LibNode . lib_Version >= 39)
  1178.         {
  1179.             Width    = GetBitMapAttr(Source -> BitMap,BMA_WIDTH);
  1180.             Depth    = GetBitMapAttr(Source -> BitMap,BMA_DEPTH);
  1181.         }
  1182.         else
  1183.         {
  1184.             Width    = Source -> BitMap -> BytesPerRow * 8;
  1185.             Depth    = Source -> BitMap -> Depth;
  1186.         }
  1187.  
  1188.         if(Temp -> BitMap = CreateBitMap(Width,1,Depth,NULL,Source -> BitMap,FALSE))
  1189.             return(Temp);
  1190.         else
  1191.             FreeVec(Temp);
  1192.     }
  1193.  
  1194.     return(NULL);
  1195. }
  1196.  
  1197.     /* Euclid(LONG a,LONG b):
  1198.      *
  1199.      *    Compute the greatest common divisor of two integers.
  1200.      */
  1201.  
  1202. LONG
  1203. Euclid(LONG a,LONG b)
  1204. {
  1205.     do
  1206.     {
  1207.         if(a < b)
  1208.         {
  1209.             LONG t;
  1210.  
  1211.             t = a;
  1212.             a = b;
  1213.             b = t;
  1214.         }
  1215.  
  1216.         a = a % b;
  1217.     }
  1218.     while(a);
  1219.  
  1220.     return(b);
  1221. }
  1222.  
  1223.     /* PutDump(register BYTE *Destination,register LONG Count):
  1224.      *
  1225.      *    Store a byte dump.
  1226.      */
  1227.  
  1228. BYTE *
  1229. PutDump(register BYTE *Destination,register LONG Count)
  1230. {
  1231.     register BYTE *Source = Buffer;
  1232.  
  1233.     *Destination++     = Count - 1;
  1234.      PackedBytes    += Count + 1;
  1235.  
  1236.     while(Count--)
  1237.         *Destination++ = *Source++;
  1238.  
  1239.     return(Destination);
  1240. }
  1241.  
  1242.     /* PutRun(register BYTE *Destination,LONG Count,WORD Char):
  1243.      *
  1244.      *    Store a byte run.
  1245.      */
  1246.  
  1247. BYTE *
  1248. PutRun(register BYTE *Destination,LONG Count,WORD Char)
  1249. {
  1250.     *Destination++     = -(Count - 1);
  1251.     *Destination++     = Char;
  1252.      PackedBytes    += 2; 
  1253.  
  1254.     return(Destination);
  1255. }
  1256.  
  1257.     /* PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize):
  1258.      *
  1259.      *    Pack a raster line using the CmpByteRun1 algorithm.
  1260.      */
  1261.  
  1262. LONG
  1263. PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize)
  1264. {
  1265.     register BYTE *Source = *SourcePtr;
  1266.  
  1267.     WORD    Buffered    = 1,
  1268.         RunStart    = 0;
  1269.     BYTE    Mode        = DUMP,
  1270.         LastChar,
  1271.         Char;
  1272.  
  1273.     PackedBytes = 0;
  1274.  
  1275.     Buffer[0] = LastChar = Char = *Source++;
  1276.  
  1277.     RowSize--;
  1278.  
  1279.     while(RowSize--)
  1280.     {
  1281.         Buffer[Buffered++] = Char = *Source++;
  1282.  
  1283.         if(Mode)
  1284.         {
  1285.             if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
  1286.             {
  1287.                 Destination    = PutRun(Destination,Buffered - 1 - RunStart,LastChar);
  1288.                 Buffer[0]    = Char;
  1289.                 Buffered    = 1;
  1290.                 RunStart    = 0;
  1291.                 Mode        = DUMP;
  1292.             }
  1293.         }
  1294.         else
  1295.         {
  1296.             if(Buffered > MAXDAT)
  1297.             {
  1298.                 Destination    = PutDump(Destination,Buffered - 1);
  1299.                 Buffer[0]    = Char;
  1300.                 Buffered    = 1;
  1301.                 RunStart    = 0;
  1302.             }
  1303.             else
  1304.             {
  1305.                 if(Char == LastChar)
  1306.                 {
  1307.                     if(Buffered - RunStart >= MINRUN)
  1308.                     {
  1309.                         if(RunStart)
  1310.                             Destination = PutDump(Destination,RunStart);
  1311.  
  1312.                         Mode = RUN;
  1313.                     }
  1314.                     else
  1315.                     {
  1316.                         if(!RunStart)
  1317.                             Mode = RUN;
  1318.                     }
  1319.                 }
  1320.                 else
  1321.                     RunStart = Buffered - 1;
  1322.             }
  1323.         }
  1324.  
  1325.         LastChar = Char;
  1326.     }
  1327.  
  1328.     if(Mode)
  1329.         PutRun(Destination,Buffered - RunStart,LastChar);
  1330.     else
  1331.         PutDump(Destination,Buffered);
  1332.  
  1333.     *SourcePtr = Source;
  1334.  
  1335.     return(PackedBytes);
  1336. }
  1337.  
  1338.     /* PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap):
  1339.      *
  1340.      *    Store a bitmap in a BODY chunk.
  1341.      */
  1342.  
  1343. BOOL
  1344. PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap)
  1345. {
  1346.     PLANEPTR    *Planes;
  1347.     BYTE        *PackBuffer;
  1348.     BOOL         Success = FALSE;
  1349.     LONG         PackedBytes,
  1350.              i,j;
  1351.  
  1352.         /* Allocate the bitplane information. */
  1353.  
  1354.     if(Planes = (PLANEPTR *)AllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR))
  1355.     {
  1356.             /* Allocate the compression buffer. */
  1357.  
  1358.         if(PackBuffer = (BYTE *)AllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY))
  1359.         {
  1360.                 /* Copy the planes over. */
  1361.  
  1362.             for(i = 0 ; i < BitMap -> Depth ; i++)
  1363.                 Planes[i] = BitMap -> Planes[i];
  1364.  
  1365.             if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  1366.             {
  1367.                 Success = TRUE;
  1368.  
  1369.                     /* Run down the rows. */
  1370.  
  1371.                 for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  1372.                 {
  1373.                     for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  1374.                     {
  1375.                             /* Pack the data. */
  1376.  
  1377.                         PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
  1378.  
  1379.                             /* Write it to disk. */
  1380.  
  1381.                         if(WriteChunkRecords(Handle,PackBuffer,PackedBytes,1) != 1)
  1382.                             Success = FALSE;
  1383.                     }
  1384.                 }
  1385.  
  1386.                 if(PopChunk(Handle))
  1387.                     Success = FALSE;
  1388.             }
  1389.  
  1390.             FreeVec(PackBuffer);
  1391.         }
  1392.  
  1393.         FreeVec(Planes);
  1394.     }
  1395.  
  1396.     return(Success);
  1397. }
  1398.  
  1399.     /* PutANNO(struct IFFHandle *Handle):
  1400.      *
  1401.      *    Store annotation chunk.
  1402.      */
  1403.  
  1404. BOOL
  1405. PutANNO(struct IFFHandle *Handle)
  1406. {
  1407.     STATIC STRPTR Note = "Rendered by GNU Ghostscript 2.6.0";
  1408.  
  1409.     if(!PushChunk(Handle,0,ID_ANNO,strlen(Note)))
  1410.     {
  1411.         if(WriteChunkRecords(Handle,Note,strlen(Note),1) == 1)
  1412.         {
  1413.             if(!PopChunk(Handle))
  1414.                 return(TRUE);
  1415.         }
  1416.     }
  1417.  
  1418.     return(FALSE);
  1419. }
  1420.  
  1421.     /* PutCAMG(struct IFFHandle *Handle):
  1422.      *
  1423.      *    Store display mode chunk.
  1424.      */
  1425.  
  1426. BOOL
  1427. PutCAMG(struct IFFHandle *Handle)
  1428. {
  1429.     ULONG ViewModes = HIRESLACE_KEY;
  1430.  
  1431.     if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
  1432.     {
  1433.         if(WriteChunkRecords(Handle,&ViewModes,sizeof(ULONG),1) == 1)
  1434.         {
  1435.             if(!PopChunk(Handle))
  1436.                 return(TRUE);
  1437.         }
  1438.     }
  1439.  
  1440.     return(FALSE);
  1441. }
  1442.  
  1443.     /* PutCMAP(struct IFFHandle *Handle):
  1444.      *
  1445.      *    Store colour map chunk.
  1446.      */
  1447.  
  1448. BOOL
  1449. PutCMAP(struct IFFHandle *Handle)
  1450. {
  1451.     STATIC UBYTE Colours[2][3] =
  1452.     {
  1453.         0x00,0x00,0x00,
  1454.         0xFF,0xFF,0xFF
  1455.     };
  1456.  
  1457.     if(!PushChunk(Handle,0,ID_CMAP,sizeof(Colours)))
  1458.     {
  1459.         if(WriteChunkRecords(Handle,Colours,2,3) == 3)
  1460.         {
  1461.             if(!PopChunk(Handle))
  1462.                 return(TRUE);
  1463.         }
  1464.     }
  1465.  
  1466.     return(FALSE);
  1467. }
  1468.  
  1469.     /* PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI):
  1470.      *
  1471.      *    Store DPI chunk.
  1472.      */
  1473.  
  1474. BOOL
  1475. PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI)
  1476. {
  1477.     DPIHeader Header;
  1478.  
  1479.     Header . dpi_x = X_DPI;
  1480.     Header . dpi_y = Y_DPI;
  1481.  
  1482.     if(!PushChunk(Handle,0,ID_DPI,sizeof(Header)))
  1483.     {
  1484.         if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1485.         {
  1486.             if(!PopChunk(Handle))
  1487.                 return(TRUE);
  1488.         }
  1489.     }
  1490.  
  1491.     return(FALSE);
  1492. }
  1493.  
  1494.     /* PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1495.      *
  1496.      *    Store BMHD chunk.
  1497.      */
  1498.  
  1499. BOOL
  1500. PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1501. {
  1502.         /* Valid parameters? */
  1503.  
  1504.     if(X_DPI > 0 && Y_DPI > 0 && Width > 0 && Height > 0)
  1505.     {
  1506.         BitMapHeader    Header;
  1507.         UWORD        gcd;
  1508.  
  1509.             /* So we can store neat & small
  1510.              * aspect ration values.
  1511.              */
  1512.  
  1513.         gcd = Euclid(X_DPI,Y_DPI);
  1514.  
  1515.         Header . w            = Width;
  1516.         Header . h            = Height;
  1517.         Header . pageWidth        = Width;
  1518.         Header . pageHeight        = Height;
  1519.         Header . x            = 0;
  1520.         Header . y            = 0;
  1521.         Header . nPlanes        = 1;
  1522.         Header . masking        = 0;
  1523.         Header . compression        = 1;
  1524.         Header . pad1            = 0;
  1525.         Header . transparentColor    = 0;
  1526.         Header . xAspect        = X_DPI / gcd;
  1527.         Header . yAspect        = Y_DPI / gcd;
  1528.  
  1529.         if(!PushChunk(Handle,0,ID_BMHD,sizeof(Header)))
  1530.         {
  1531.             if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1532.             {
  1533.                 if(!PopChunk(Handle))
  1534.                     return(TRUE);
  1535.             }
  1536.         }
  1537.     }
  1538.  
  1539.     return(FALSE);
  1540. }
  1541.  
  1542.     /* SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1543.      *
  1544.      *    Store a bitmap in an IFF-ILBM file.
  1545.      */
  1546.  
  1547. BOOL
  1548. SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1549. {
  1550.     struct IFFHandle    *Handle;
  1551.     BOOL             Success = FALSE;
  1552.  
  1553.     if(Handle = AllocIFF())
  1554.     {
  1555.         if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
  1556.         {
  1557.             InitIFFasDOS(Handle);
  1558.  
  1559.             if(!OpenIFF(Handle,IFFF_WRITE))
  1560.             {
  1561.                 if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
  1562.                 {
  1563.                     if(PutBMHD(Handle,Width,Height,X_DPI,Y_DPI))
  1564.                     {
  1565.                         if(PutANNO(Handle))
  1566.                         {
  1567.                             if(PutCMAP(Handle))
  1568.                             {
  1569.                                 if(PutCAMG(Handle))
  1570.                                 {
  1571.                                     if(PutDPI(Handle,X_DPI,Y_DPI))
  1572.                                     {
  1573.                                         if(PutBODY(Handle,BitMap))
  1574.                                             Success = TRUE;
  1575.                                     }
  1576.                                 }
  1577.                             }
  1578.                         }
  1579.                     }
  1580.  
  1581.                     if(PopChunk(Handle))
  1582.                         Success = FALSE;
  1583.                 }
  1584.  
  1585.                 CloseIFF(Handle);
  1586.             }
  1587.  
  1588.             Close(Handle -> iff_Stream);
  1589.  
  1590.             if(!Success)
  1591.                 DeleteFile(Name);
  1592.         }
  1593.  
  1594.         FreeIFF(Handle);
  1595.     }
  1596.  
  1597.     return(Success);
  1598. }
  1599.  
  1600.     /* GetInches(STRPTR Buffer):
  1601.      *
  1602.      *    Turn a parameter string into a number representing
  1603.      *    a certain number of inches.
  1604.      */
  1605.  
  1606. float
  1607. GetInches(STRPTR Buffer)
  1608. {
  1609.     STATIC struct { STRPTR Unit; float Factor; } Units[7] =
  1610.     {
  1611.         "pt",    1.0,            /* Point */
  1612.         "pc",    12.0,            /* Pica */
  1613.         "in",    72.72,            /* Inch */
  1614.         "cm",    72.72 / 2.54,        /* Centimeter */
  1615.         "mm",    727.2 / 2.54,        /* Millimeter */
  1616.         "dd",    1157.0 / 1238.0,    /* Didot point */
  1617.         "cc",    1157.0 / 103.0        /* Cicero */
  1618.     };
  1619.  
  1620.     UBYTE    Temp[40];
  1621.     float    Value;
  1622.     LONG    i;
  1623.  
  1624.     i = 0;
  1625.  
  1626.         /* Strip the numeric part. */
  1627.  
  1628.     while((Buffer[i] >= '0' && Buffer[i] <= '9') || Buffer[i] == '.' || Buffer[i] == '+' || Buffer[i] == '-' || Buffer[i] == 'e')
  1629.     {
  1630.         Temp[i] = Buffer[i];
  1631.  
  1632.         i++;
  1633.     }
  1634.  
  1635.         /* Provide null-termination. */
  1636.  
  1637.     Temp[i] = 0;
  1638.  
  1639.         /* atof() appears to be broken in ixemul.library 39.45. */
  1640.  
  1641.     sscanf(Temp,"%f",&Value);
  1642.  
  1643.     Buffer += i;
  1644.  
  1645.         /* Which measuring unit? */
  1646.  
  1647.     for(i = 0 ; i < 7 ; i++)
  1648.     {
  1649.             /* Return the result in inches. */
  1650.  
  1651.         if(!Stricmp(Buffer,Units[i] . Unit))
  1652.             return(Value * Units[i] . Factor / 72.27);
  1653.     }
  1654.  
  1655.         /* Return the result in inches. */
  1656.  
  1657.     return(Value / 72.27);
  1658. }
  1659.  
  1660.     /* DispatchTask():
  1661.      *
  1662.      *    Asynchronous window message dispatcher.
  1663.      */
  1664.  
  1665. VOID
  1666. DispatchTask()
  1667. {
  1668.     struct Task    *me;
  1669.     gx_device    *dev;
  1670.  
  1671.         /* Set up global data area base register. */
  1672.  
  1673.     ix_geta4();
  1674.  
  1675.         /* Who am I? */
  1676.  
  1677.     me = FindTask(NULL);
  1678.  
  1679.         /* Wait for wakeup call. */
  1680.  
  1681.     Wait(SIG_HANDSHAKE);
  1682.  
  1683.         /* Obtain device pointer. */
  1684.  
  1685.     dev = me -> tc_UserData;
  1686.  
  1687.         /* Enable user input. */
  1688.  
  1689.     if(ModifyIDCMP(xdev -> window,IDCMP_FLAGS))
  1690.     {
  1691.         ULONG    Mask = 1 << xdev -> window -> UserPort -> mp_SigBit,
  1692.             Set;
  1693.         BOOL    Done = FALSE;
  1694.  
  1695.             /* Fill in the dispatcher entry. */
  1696.  
  1697.         xdev -> dispatcher = me;
  1698.  
  1699.             /* Ring back. */
  1700.  
  1701.         Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1702.  
  1703.             /* Wait for input... */
  1704.  
  1705.         do
  1706.         {
  1707.             Set = Wait(Mask | SIG_KILL);
  1708.  
  1709.             if(Set & Mask)
  1710.                 DispatchSuperWindow(dev);
  1711.  
  1712.             if(Set & SIG_KILL)
  1713.                 Done = TRUE;
  1714.         }
  1715.         while(!Done);
  1716.  
  1717.             /* Disable user input. */
  1718.  
  1719.         ModifyIDCMP(xdev -> window,NULL);
  1720.     }
  1721.  
  1722.         /* Disable task switching. */
  1723.  
  1724.     Forbid();
  1725.  
  1726.         /* Clear the dispatcher entry. */
  1727.  
  1728.     xdev -> dispatcher = NULL;
  1729.  
  1730.         /* Signal the main process that we are done. */
  1731.  
  1732.     Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1733.  
  1734.         /* Remove ourselves. */
  1735.  
  1736.     RemTask(NULL);
  1737. }
  1738.  
  1739.     /* DeleteScrollers(gx_device *dev):
  1740.      *
  1741.      *    Delete the window border scrollers.
  1742.      */
  1743.  
  1744. VOID
  1745. DeleteScrollers(gx_device *dev)
  1746. {
  1747.     if(xdev -> gadget)
  1748.     {
  1749.         if(xdev -> gadget[HORIZONTAL_SCROLLER])
  1750.             DisposeObject(xdev -> gadget[HORIZONTAL_SCROLLER]);
  1751.  
  1752.         if(xdev -> gadget[VERTICAL_SCROLLER])
  1753.             DisposeObject(xdev -> gadget[VERTICAL_SCROLLER]);
  1754.  
  1755.         if(xdev -> gadget[UP_ARROW])
  1756.             DisposeObject(xdev -> gadget[UP_ARROW]);
  1757.  
  1758.         if(xdev -> gadget[DOWN_ARROW])
  1759.             DisposeObject(xdev -> gadget[DOWN_ARROW]);
  1760.  
  1761.         if(xdev -> gadget[LEFT_ARROW])
  1762.             DisposeObject(xdev -> gadget[LEFT_ARROW]);
  1763.  
  1764.         if(xdev -> gadget[RIGHT_ARROW])
  1765.             DisposeObject(xdev -> gadget[RIGHT_ARROW]);
  1766.  
  1767.         FreeVec(xdev -> gadget);
  1768.  
  1769.         xdev -> gadget = NULL;
  1770.     }
  1771.  
  1772.     if(xdev -> image)
  1773.     {
  1774.         if(xdev -> image[UP_IMAGE])
  1775.             DisposeObject(xdev -> image[UP_IMAGE]);
  1776.  
  1777.         if(xdev -> image[DOWN_IMAGE])
  1778.             DisposeObject(xdev -> image[DOWN_IMAGE]);
  1779.  
  1780.         if(xdev -> image[LEFT_IMAGE])
  1781.             DisposeObject(xdev -> image[LEFT_IMAGE]);
  1782.  
  1783.         if(xdev -> image[RIGHT_IMAGE])
  1784.             DisposeObject(xdev -> image[RIGHT_IMAGE]);
  1785.  
  1786.         FreeVec(xdev -> image);
  1787.  
  1788.         xdev -> image = NULL;
  1789.     }
  1790. }
  1791.  
  1792.     /* CreateScrollers(gx_device *dev,struct Screen *Screen):
  1793.      *
  1794.      *    Create the window border scroller handles.
  1795.      */
  1796.  
  1797. BOOL
  1798. CreateScrollers(gx_device *dev,struct Screen *Screen)
  1799. {
  1800.     BOOL Result = FALSE;
  1801.  
  1802.     if(xdev -> gadget = (struct Gadget **)AllocVec(sizeof(struct Gadget *) * GADGET_COUNT,MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
  1803.     {
  1804.         if(xdev -> image = (struct Image **)AllocVec(sizeof(struct Image *) * IMAGE_COUNT,MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
  1805.         {
  1806.             struct DrawInfo *DrawInfo;
  1807.  
  1808.             if(DrawInfo = GetScreenDrawInfo(Screen))
  1809.             {
  1810.                 LONG    SizeWidth,
  1811.                     SizeHeight;
  1812.                 UWORD    SizeType;
  1813.  
  1814.                 if(Screen -> Flags & SCREENHIRES)
  1815.                 {
  1816.                     SizeWidth    = 18;
  1817.                     SizeHeight    = 10;
  1818.  
  1819.                     SizeType    = SYSISIZE_MEDRES;
  1820.                 }
  1821.                 else
  1822.                 {
  1823.                     SizeWidth    = 13;
  1824.                     SizeHeight    = 11;
  1825.  
  1826.                     SizeType    = SYSISIZE_LOWRES;
  1827.                 }
  1828.  
  1829.                 if(xdev -> image[UP_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1830.                     SYSIA_Size,    SizeType,
  1831.                     SYSIA_Which,    UPIMAGE,
  1832.                     SYSIA_DrawInfo,    DrawInfo,
  1833.                 TAG_DONE))
  1834.                 {
  1835.                     if(xdev -> image[DOWN_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1836.                         SYSIA_Size,    SizeType,
  1837.                         SYSIA_Which,    DOWNIMAGE,
  1838.                         SYSIA_DrawInfo,    DrawInfo,
  1839.                     TAG_DONE))
  1840.                     {
  1841.                         if(xdev -> image[LEFT_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1842.                             SYSIA_Size,    SizeType,
  1843.                             SYSIA_Which,    LEFTIMAGE,
  1844.                             SYSIA_DrawInfo,    DrawInfo,
  1845.                         TAG_DONE))
  1846.                         {
  1847.                             if(xdev -> image[RIGHT_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1848.                                 SYSIA_Size,    SizeType,
  1849.                                 SYSIA_Which,    RIGHTIMAGE,
  1850.                                 SYSIA_DrawInfo,    DrawInfo,
  1851.                             TAG_DONE))
  1852.                             {
  1853.                                 if(xdev -> gadget[VERTICAL_SCROLLER] = NewObject(NULL,"propgclass",
  1854.                                     GA_ID,        VERTICAL_SCROLLER,
  1855.  
  1856.                                     GA_Top,        Screen -> WBorTop + Screen -> Font -> ta_YSize + 2,
  1857.                                     GA_RelHeight,    -(Screen -> WBorTop + Screen -> Font -> ta_YSize + 2 + SizeHeight + 1 + 2 * ARROW_HEIGHT),
  1858.                                     GA_Width,    SizeWidth - 8,
  1859.                                     GA_RelRight,    -(SizeWidth - 5),
  1860.  
  1861.                                     GA_GZZGadget,    TRUE,
  1862.                                     GA_Immediate,    TRUE,
  1863.                                     GA_FollowMouse,    TRUE,
  1864.                                     GA_RelVerify,    TRUE,
  1865.                                     GA_RightBorder,    TRUE,
  1866.  
  1867.                                     PGA_Freedom,    FREEVERT,
  1868.                                     PGA_NewLook,    TRUE,
  1869.                                     PGA_Borderless,    TRUE,
  1870.  
  1871.                                     PGA_Visible,    1,
  1872.                                     PGA_Total,    1,
  1873.                                 TAG_DONE))
  1874.                                 {
  1875.                                     if(xdev -> gadget[HORIZONTAL_SCROLLER] = NewObject(NULL,"propgclass",
  1876.                                         GA_ID,        HORIZONTAL_SCROLLER,
  1877.                                         GA_Previous,    xdev -> gadget[VERTICAL_SCROLLER],
  1878.  
  1879.                                         GA_Height,    SizeHeight - 4,
  1880.                                         GA_RelBottom,    -(SizeHeight - 4 + 1),
  1881.                                         GA_Left,    4,
  1882.                                         GA_RelWidth,    -(2 + SizeWidth + 4 + 2 * ARROW_WIDTH),
  1883.  
  1884.                                         GA_GZZGadget,    TRUE,
  1885.                                         GA_Immediate,    TRUE,
  1886.                                         GA_FollowMouse,    TRUE,
  1887.                                         GA_RelVerify,    TRUE,
  1888.                                         GA_BottomBorder,TRUE,
  1889.  
  1890.                                         PGA_Freedom,    FREEHORIZ,
  1891.                                         PGA_NewLook,    TRUE,
  1892.                                         PGA_Borderless,    TRUE,
  1893.  
  1894.                                         PGA_Visible,    1,
  1895.                                         PGA_Total,    1,
  1896.                                     TAG_DONE))
  1897.                                     {
  1898.                                         STATIC struct TagItem ArrowMappings[] = { GA_ID, GA_ID, TAG_END };
  1899.  
  1900.                                         if(xdev -> gadget[UP_ARROW] = NewObject(NULL,"buttongclass",
  1901.                                             GA_ID,        UP_ARROW,
  1902.                                             GA_Previous,    xdev -> gadget[HORIZONTAL_SCROLLER],
  1903.  
  1904.                                             GA_GZZGadget,    TRUE,
  1905.                                             GA_Image,    xdev -> image[UP_IMAGE],
  1906.                                             GA_RelRight,    -(SizeWidth - 1),
  1907.                                             GA_RelBottom,    -(SizeHeight - 1 + 2 * ARROW_HEIGHT),
  1908.                                             GA_Height,    ARROW_HEIGHT,
  1909.                                             GA_Width,    SizeWidth,
  1910.                                             GA_Immediate,    TRUE,
  1911.                                             GA_RelVerify,    TRUE,
  1912.                                             GA_RightBorder,    TRUE,
  1913.  
  1914.                                             ICA_TARGET,    ICTARGET_IDCMP,
  1915.                                             ICA_MAP,    ArrowMappings,
  1916.                                         TAG_DONE))
  1917.                                         {
  1918.                                             if(xdev -> gadget[DOWN_ARROW] = NewObject(NULL,"buttongclass",
  1919.                                                 GA_ID,        DOWN_ARROW,
  1920.                                                 GA_Previous,    xdev -> gadget[UP_ARROW],
  1921.  
  1922.                                                 GA_GZZGadget,    TRUE,
  1923.                                                 GA_Image,    xdev -> image[DOWN_IMAGE],
  1924.                                                 GA_RelRight,    -(SizeWidth - 1),
  1925.                                                 GA_RelBottom,    -(SizeHeight - 1 + ARROW_HEIGHT),
  1926.                                                 GA_Height,    ARROW_HEIGHT,
  1927.                                                 GA_Width,    SizeWidth,
  1928.                                                 GA_Immediate,    TRUE,
  1929.                                                 GA_RelVerify,    TRUE,
  1930.                                                 GA_RightBorder,    TRUE,
  1931.  
  1932.                                                 ICA_TARGET,    ICTARGET_IDCMP,
  1933.                                                 ICA_MAP,    ArrowMappings,
  1934.                                             TAG_DONE))
  1935.                                             {
  1936.                                                 if(xdev -> gadget[LEFT_ARROW] = NewObject(NULL,"buttongclass",
  1937.                                                     GA_ID,        LEFT_ARROW,
  1938.                                                     GA_Previous,    xdev -> gadget[DOWN_ARROW],
  1939.  
  1940.                                                     GA_GZZGadget,    TRUE,
  1941.                                                     GA_Image,    xdev -> image[LEFT_IMAGE],
  1942.                                                     GA_RelRight,    -(SizeWidth - 1 + 2 * ARROW_WIDTH),
  1943.                                                     GA_RelBottom,    -(SizeHeight - 1),
  1944.                                                     GA_Height,    SizeHeight,
  1945.                                                     GA_Width,    ARROW_WIDTH,
  1946.                                                     GA_Immediate,    TRUE,
  1947.                                                     GA_RelVerify,    TRUE,
  1948.                                                     GA_BottomBorder,TRUE,
  1949.  
  1950.                                                     ICA_TARGET,    ICTARGET_IDCMP,
  1951.                                                     ICA_MAP,    ArrowMappings,
  1952.                                                 TAG_DONE))
  1953.                                                 {
  1954.                                                     if(xdev -> gadget[RIGHT_ARROW] = NewObject(NULL,"buttongclass",
  1955.                                                         GA_ID,        RIGHT_ARROW,
  1956.                                                         GA_Previous,    xdev -> gadget[LEFT_ARROW],
  1957.  
  1958.                                                         GA_GZZGadget,    TRUE,
  1959.                                                         GA_Image,    xdev -> image[RIGHT_IMAGE],
  1960.                                                         GA_RelRight,    -(SizeWidth - 1 + ARROW_WIDTH),
  1961.                                                         GA_RelBottom,    -(SizeHeight - 1),
  1962.                                                         GA_Height,    SizeHeight,
  1963.                                                         GA_Width,    ARROW_WIDTH,
  1964.                                                         GA_Immediate,    TRUE,
  1965.                                                         GA_RelVerify,    TRUE,
  1966.                                                         GA_BottomBorder,TRUE,
  1967.  
  1968.                                                         ICA_TARGET,    ICTARGET_IDCMP,
  1969.                                                         ICA_MAP,    ArrowMappings,
  1970.                                                     TAG_DONE))
  1971.                                                         Result = TRUE;
  1972.                                                 }
  1973.                                             }
  1974.                                         }
  1975.                                     }
  1976.                                 }
  1977.                             }
  1978.                         }
  1979.                     }
  1980.                 }
  1981.  
  1982.                 FreeScreenDrawInfo(Screen,DrawInfo);
  1983.             }
  1984.         }
  1985.     }
  1986.  
  1987.     return(Result);
  1988. }
  1989.  
  1990.     /* WindowResize(gx_device *dev):
  1991.      *
  1992.      *    Update the slider sizes and positions after the window
  1993.      *    was resized.
  1994.      */
  1995.  
  1996. VOID
  1997. WindowResize(gx_device *dev)
  1998. {
  1999.     LONG    DeltaX,
  2000.         DeltaY,
  2001.         Temp;
  2002.  
  2003.         /* Query the current horizontal slider position. */
  2004.  
  2005.     if((Temp = LAYERXOFFSET(xdev -> window) + xdev -> window -> GZZWidth) > xdev -> super_width)
  2006.         DeltaX = xdev -> super_width - Temp;
  2007.     else
  2008.         DeltaX = 0;
  2009.  
  2010.         /* Query the current vertical slider position. */
  2011.  
  2012.     if((Temp = LAYERYOFFSET(xdev -> window) + xdev -> window -> GZZHeight) > xdev -> super_height)
  2013.         DeltaY = xdev -> super_height - Temp;
  2014.     else
  2015.         DeltaY = 0;
  2016.  
  2017.         /* Move the currently displayed window area around. */
  2018.  
  2019.     if(DeltaX || DeltaY)
  2020.         ScrollLayer(NULL,xdev -> window -> RPort -> Layer,DeltaX,DeltaY);
  2021.  
  2022.         /* Update the new horizontal slider position and size. */
  2023.  
  2024.     SetGadgetAttrs(xdev -> gadget[HORIZONTAL_SCROLLER],xdev -> window,NULL,
  2025.         PGA_Top,    LAYERXOFFSET(xdev -> window),
  2026.         PGA_Visible,    xdev -> window -> GZZWidth,
  2027.         PGA_Total,    xdev -> super_width,
  2028.     TAG_DONE);
  2029.  
  2030.         /* Update the new vertical slider position and size. */
  2031.  
  2032.     SetGadgetAttrs(xdev -> gadget[VERTICAL_SCROLLER],xdev -> window,NULL,
  2033.         PGA_Top,    LAYERYOFFSET(xdev -> window),
  2034.         PGA_Visible,    xdev -> window -> GZZHeight,
  2035.         PGA_Total,    xdev -> super_height,
  2036.     TAG_DONE);
  2037. }
  2038.  
  2039.     /* WindowUpdate(struct Gadget *Gadget,gx_device *dev):
  2040.      *
  2041.      *    Move the currently visible portion of the
  2042.      *    window according to the current slider
  2043.      *    position.
  2044.      */
  2045.  
  2046. VOID
  2047. WindowUpdate(struct Gadget *Gadget,gx_device *dev)
  2048. {
  2049.     LONG Storage;
  2050.  
  2051.     switch(Gadget -> GadgetID)
  2052.     {
  2053.         case HORIZONTAL_SCROLLER:
  2054.  
  2055.             if(GetAttr(PGA_Top,Gadget,&Storage))
  2056.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  2057.  
  2058.             break;
  2059.  
  2060.         case VERTICAL_SCROLLER:
  2061.  
  2062.             if(GetAttr(PGA_Top,Gadget,&Storage))
  2063.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  2064.  
  2065.             break;
  2066.     }
  2067. }
  2068.  
  2069.     /* MoveAround(struct Gadget *Gadget,int How,gx_device *dev):
  2070.      *
  2071.      *    Move the currently visible window area according to
  2072.      *    user input.
  2073.      */
  2074.  
  2075. VOID
  2076. MoveAround(struct Gadget *Gadget,LONG How,gx_device *dev)
  2077. {
  2078.     LONG Storage;
  2079.  
  2080.     if(GetAttr(PGA_Top,Gadget,&Storage))
  2081.     {
  2082.         LONG Max;
  2083.  
  2084.         switch(Gadget -> GadgetID)
  2085.         {
  2086.             case HORIZONTAL_SCROLLER:
  2087.  
  2088.                 Max = xdev -> super_width - xdev -> window -> GZZWidth;
  2089.                 break;
  2090.  
  2091.             case VERTICAL_SCROLLER:
  2092.  
  2093.                 Max = xdev -> super_height - xdev -> window -> GZZHeight;
  2094.                 break;
  2095.         }
  2096.  
  2097.         switch(How)
  2098.         {
  2099.             case MOVE_MIN:
  2100.  
  2101.                 Storage = 0;
  2102.                 break;
  2103.  
  2104.             case MOVE_MAX:
  2105.  
  2106.                 Storage = Max;
  2107.                 break;
  2108.  
  2109.             case MOVE_DOWN:
  2110.  
  2111.                 if(Storage > xdev -> super_height / 100)
  2112.                     Storage -= xdev -> super_height / 100;
  2113.                 else
  2114.                     Storage = 0;
  2115.  
  2116.                 break;
  2117.  
  2118.             case MOVE_FAR_DOWN:
  2119.  
  2120.                 if(Storage > xdev -> super_height / 10)
  2121.                     Storage -= xdev -> super_height / 10;
  2122.                 else
  2123.                     Storage = 0;
  2124.  
  2125.                 break;
  2126.  
  2127.             case MOVE_FAR_UP:
  2128.  
  2129.                 if(Storage + xdev -> super_width / 10 < Max)
  2130.                     Storage += xdev -> super_width / 10;
  2131.                 else
  2132.                     Storage = Max;
  2133.  
  2134.                 break;
  2135.  
  2136.             case MOVE_UP:
  2137.  
  2138.                 if(Storage + xdev -> super_width / 100 < Max)
  2139.                     Storage += xdev -> super_width / 100;
  2140.                 else
  2141.                     Storage = Max;
  2142.  
  2143.                 break;
  2144.         }
  2145.  
  2146.         switch(Gadget -> GadgetID)
  2147.         {
  2148.             case HORIZONTAL_SCROLLER:
  2149.  
  2150.                 if(LAYERXOFFSET(xdev -> window) != Storage)
  2151.                 {
  2152.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  2153.  
  2154.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  2155.                         PGA_Top,Storage,
  2156.                     TAG_DONE);
  2157.                 }
  2158.  
  2159.                 break;
  2160.  
  2161.             case VERTICAL_SCROLLER:
  2162.  
  2163.                 if(LAYERYOFFSET(xdev -> window) != Storage)
  2164.                 {
  2165.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  2166.  
  2167.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  2168.                         PGA_Top,Storage,
  2169.                     TAG_DONE);
  2170.                 }
  2171.  
  2172.                 break;
  2173.         }
  2174.     }
  2175. }
  2176.  
  2177.     /* DispatchSuperWindow(gx_device *dev):
  2178.      *
  2179.      *    Dispatch user window input.
  2180.      */
  2181.  
  2182. VOID
  2183. DispatchSuperWindow(gx_device *dev)
  2184. {
  2185.     STATIC struct Gadget    *CurrentGadget = NULL;
  2186.  
  2187.     struct IntuiMessage    *IntuiMessage;
  2188.     ULONG             MsgClass,
  2189.                  MsgCode,
  2190.                  MsgQualifier;
  2191.     struct Gadget        *MsgGadget;
  2192.  
  2193.     while(IntuiMessage = (struct IntuiMessage *)GetMsg(xdev -> window -> UserPort))
  2194.     {
  2195.         MsgClass    = IntuiMessage -> Class;
  2196.         MsgCode        = IntuiMessage -> Code;
  2197.         MsgQualifier    = IntuiMessage -> Qualifier;
  2198.         MsgGadget    = IntuiMessage -> IAddress;
  2199.  
  2200.         ReplyMsg((struct Message *)IntuiMessage);
  2201.  
  2202.         switch(MsgClass)
  2203.         {
  2204.             case IDCMP_VANILLAKEY:
  2205.  
  2206.                 if(MsgCode == '\033' || MsgCode == '\003')
  2207.                     Signal((struct Task *)xdev -> main,SIG_KILL);
  2208.  
  2209.                 break;
  2210.  
  2211.             case IDCMP_RAWKEY:
  2212.  
  2213.                 switch(MsgCode)
  2214.                 {
  2215.                     case HELP_CODE:
  2216.  
  2217.                         DisplayBeep(xdev -> window -> WScreen);
  2218.  
  2219.                         break;
  2220.  
  2221.                     case CURSORUP:
  2222.  
  2223.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2224.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MIN,dev);
  2225.                         else
  2226.                         {
  2227.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2228.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_DOWN,dev);
  2229.                             else
  2230.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  2231.                         }
  2232.  
  2233.                         break;
  2234.  
  2235.                     case CURSORLEFT:
  2236.  
  2237.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2238.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MIN,dev);
  2239.                         else
  2240.                         {
  2241.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2242.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_DOWN,dev);
  2243.                             else
  2244.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  2245.                         }
  2246.  
  2247.                         break;
  2248.  
  2249.                     case CURSORRIGHT:
  2250.  
  2251.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2252.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MAX,dev);
  2253.                         else
  2254.                         {
  2255.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2256.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_UP,dev);
  2257.                             else
  2258.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  2259.                         }
  2260.  
  2261.                         break;
  2262.  
  2263.                     case CURSORDOWN:
  2264.  
  2265.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2266.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MAX,dev);
  2267.                         else
  2268.                         {
  2269.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2270.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_UP,dev);
  2271.                             else
  2272.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  2273.                         }
  2274.  
  2275.                         break;
  2276.  
  2277.                     default:
  2278.  
  2279.                         break;
  2280.                 }
  2281.  
  2282.                 break;
  2283.  
  2284.             case IDCMP_CLOSEWINDOW:
  2285.  
  2286.                 Signal((struct Task *)xdev -> main,SIG_KILL);
  2287.  
  2288.                 break;
  2289.  
  2290.             case IDCMP_GADGETDOWN:
  2291.  
  2292.                 CurrentGadget = MsgGadget;
  2293.  
  2294.                 WindowUpdate(MsgGadget,dev);
  2295.  
  2296.                 break;
  2297.  
  2298.             case IDCMP_GADGETUP:
  2299.  
  2300.                 CurrentGadget = NULL;
  2301.  
  2302.                 WindowUpdate(MsgGadget,dev);
  2303.  
  2304.                 break;
  2305.  
  2306.             case IDCMP_MOUSEMOVE:
  2307.  
  2308.                 if(CurrentGadget)
  2309.                     WindowUpdate(CurrentGadget,dev);
  2310.  
  2311.                 break;
  2312.  
  2313.             case IDCMP_IDCMPUPDATE:
  2314.  
  2315.                 switch(GetTagData(GA_ID,0,(struct TagItem *)MsgGadget))
  2316.                 {
  2317.                     case UP_ARROW:
  2318.  
  2319.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  2320.                         break;
  2321.  
  2322.                     case DOWN_ARROW:
  2323.  
  2324.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  2325.                         break;
  2326.  
  2327.                     case LEFT_ARROW:
  2328.  
  2329.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  2330.                         break;
  2331.  
  2332.                     case RIGHT_ARROW:
  2333.  
  2334.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  2335.                         break;
  2336.  
  2337.                     default:
  2338.  
  2339.                         break;
  2340.                 }
  2341.  
  2342.                 break;
  2343.  
  2344.             case IDCMP_NEWSIZE:
  2345.  
  2346.                 WindowResize(dev);
  2347.  
  2348.                 break;
  2349.  
  2350.             default:
  2351.  
  2352.                 break;
  2353.         }
  2354.     }
  2355. }
  2356.  
  2357.     /* Simple routine to call the cleanup routine of a device,
  2358.      * all devices are smart enough to handle shutdown in
  2359.      * case they have not been opened yet.
  2360.      */
  2361.  
  2362. STATIC void __inline
  2363. close_device(gx_device_amiga *dev)
  2364. {
  2365.     (*xdev -> procs -> close_device)((gx_device *)dev);
  2366. }
  2367.  
  2368.     /* devcleanup():
  2369.      *
  2370.      *    Clean up all devices, free all resources.
  2371.      */
  2372.  
  2373. void
  2374. devcleanup()
  2375. {
  2376.     close_device(&gs_amiga_device);
  2377.     close_device(&gs_amiga_low_device);
  2378.     close_device(&gs_amiga_high_device);
  2379.     close_device(&gs_amiga_super_device);
  2380.     close_device(&gs_amiga_a2024_device);
  2381.     close_device(&gs_amiga_picassoii_device);
  2382.     close_device(&gs_amiga_custom_device);
  2383.     close_device(&gs_amiga_printer_device);
  2384.     close_device(&gs_amiga_ilbm_device);
  2385. }
  2386.  
  2387.     /* amiga_set_pen(gx_device *dev,gx_color_index color):
  2388.      *
  2389.      *    Sets the rendering pen and remembers the current
  2390.      *    settings.
  2391.      */
  2392.  
  2393. STATIC VOID __inline
  2394. amiga_set_pen(gx_device *dev,gx_color_index color)
  2395. {
  2396.     if(xdev -> last_pen != color)
  2397.         SetAPen(xdev -> rport,xdev -> last_pen = color);
  2398. }
  2399.  
  2400.     /* amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  2401.      *
  2402.      *    Map a colour either to the black or the light rendering pen.
  2403.      */
  2404.  
  2405. gx_color_index
  2406. amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  2407. {
  2408.     if((red | green | blue) > gx_max_color_value / 2)
  2409.         return(LightPen);
  2410.     else
  2411.         return(DarkPen);
  2412. }
  2413.  
  2414.     /* amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  2415.      *
  2416.      *    Map the light/dark rendering pen to RGB values.
  2417.      */
  2418.  
  2419. int
  2420. amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  2421. {
  2422.     int i;
  2423.  
  2424.     if(color == LightPen)
  2425.     {
  2426.         for(i = 0 ; i < 3 ; i++)
  2427.             rgb[i] = gx_max_color_value;
  2428.     }
  2429.     else
  2430.     {
  2431.         for(i = 0 ; i < 3 ; i++)
  2432.             rgb[i] = 0;
  2433.     }
  2434.  
  2435.     return(0);
  2436. }
  2437.  
  2438.     /* AllocatePens(struct ViewPort *VPort,LONG CubeSize):
  2439.      *
  2440.      *    Allocate shareable viewport pens.
  2441.      */
  2442.  
  2443. LONG *
  2444. AllocatePens(struct ViewPort *VPort,LONG CubeSize)
  2445. {
  2446.     if(GfxBase -> LibNode . lib_Version >= 39)
  2447.     {
  2448.         LONG Total = CubeSize * CubeSize * CubeSize,*Pens;
  2449.  
  2450.         if(Pens = (LONG *)AllocVec(sizeof(LONG) * Total,MEMF_ANY))
  2451.         {
  2452.             LONG i,r,g,b,max = CubeSize - 1;
  2453.  
  2454.             for(i = 0 ; i < Total ; i++)
  2455.                 Pens[i] = -1;
  2456.  
  2457.             i = 0;
  2458.  
  2459.             for(r = 0 ; r < CubeSize ; r++)
  2460.             {
  2461.                 for(g = 0 ; g < CubeSize ; g++)
  2462.                 {
  2463.                     for(b = 0 ; b < CubeSize ; b++)
  2464.                     {
  2465.                         if((Pens[i++] = ObtainBestPen(VPort -> ColorMap,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max),
  2466.                             OBP_FailIfBad,    TRUE,
  2467.                             OBP_Precision,    PRECISION_IMAGE,
  2468.                         TAG_DONE)) == -1)
  2469.                         {
  2470.                             FreeVec(Pens);
  2471.  
  2472.                             return(NULL);
  2473.                         }
  2474.                     }
  2475.                 }
  2476.             }
  2477.  
  2478.             return(Pens);
  2479.         }
  2480.     }
  2481.  
  2482.     return(NULL);
  2483. }
  2484.  
  2485.     /* amiga_open_default(gx_device *dev):
  2486.      *
  2487.      *    Open the default device, i.e. a window on the Workbench screen.
  2488.      */
  2489.  
  2490. int
  2491. amiga_open_default(gx_device *dev)
  2492. {
  2493.     struct Screen *DefaultScreen;
  2494.  
  2495.         /* Get a lock on the default public screen. */
  2496.  
  2497.     if(DefaultScreen = LockPubScreen(NULL))
  2498.     {
  2499.         struct DisplayInfo    DisplayInfo;
  2500.         ULONG             Mode;
  2501.  
  2502.             /* Get the default public screen display mode. */
  2503.  
  2504.         Mode = GetVPModeID(&DefaultScreen -> ViewPort);
  2505.  
  2506.             /* Inquire display mode information. */
  2507.  
  2508.         if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode))
  2509.         {
  2510.             LONG    ScreenWidth,
  2511.                 ScreenHeight;
  2512.             LONG    i;
  2513.             float    Width,
  2514.                 Height;
  2515.             LONG    Depth;
  2516.  
  2517.             if(GfxBase -> LibNode . lib_Version >= 39)
  2518.                 Depth = GetBitMapAttr(DefaultScreen -> RastPort . BitMap,BMA_DEPTH);
  2519.             else
  2520.                 Depth = DefaultScreen -> RastPort . BitMap -> Depth;
  2521.  
  2522.                 /* Determine screen view dimensions. */
  2523.  
  2524.             if(DefaultScreen -> ViewPort . ColorMap -> cm_vpe)
  2525.             {
  2526.                 struct ViewPortExtra *Extra = DefaultScreen -> ViewPort . ColorMap -> cm_vpe;
  2527.  
  2528.                 ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2529.                 ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2530.             }
  2531.             else
  2532.             {
  2533.                 struct ViewPortExtra *Extra;
  2534.  
  2535.                 if(Extra = (struct ViewPortExtra *)GfxLookUp(&DefaultScreen -> ViewPort))
  2536.                 {
  2537.                     ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2538.                     ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2539.                 }
  2540.                 else
  2541.                 {
  2542.                     ScreenWidth    = DefaultScreen -> Width;
  2543.                     ScreenHeight    = DefaultScreen -> Height;
  2544.                 }
  2545.             }
  2546.  
  2547.                 /* Use the best guess, we will take the standard
  2548.                  * low resolution x-dpi value and scale it by
  2549.                  * the pixel speed.
  2550.                  */
  2551.  
  2552.             if(DisplayInfo . PixelSpeed)
  2553.             {
  2554.                 xdev -> x_pixels_per_inch = (35.0 * 140.0) / (float)DisplayInfo . PixelSpeed;
  2555.                 xdev -> y_pixels_per_inch = (xdev -> x_pixels_per_inch * (float)DisplayInfo . Resolution . x) / (float)DisplayInfo . Resolution . y;
  2556.             }
  2557.             else
  2558.             {
  2559.                 xdev -> x_pixels_per_inch = 72.27;
  2560.                 xdev -> y_pixels_per_inch = 72.27;
  2561.             }
  2562.  
  2563.             if(xdev -> width > 0 && xdev -> height > 0)
  2564.             {
  2565.                 xdev -> super_width    = xdev -> width;
  2566.                 xdev -> super_height    = xdev -> height;
  2567.             }
  2568.             else
  2569.             {
  2570.                 if(xdev -> page_width > 0.0)
  2571.                     xdev -> super_width = (LONG)(xdev -> page_width * xdev -> x_pixels_per_inch);
  2572.                 else
  2573.                     xdev -> super_width = 640;
  2574.  
  2575.                 if(xdev -> page_height > 0.0)
  2576.                     xdev -> super_height = (LONG)(xdev -> page_height * xdev -> y_pixels_per_inch);
  2577.                 else
  2578.                     xdev -> super_height = 512;
  2579.             }
  2580.  
  2581.                 /* Allocate a bitmap ready to be used for
  2582.                  * rendering.
  2583.                  */
  2584.  
  2585.             if(xdev -> super_bitmap = CreateBitMap(xdev -> super_width,xdev -> super_height,Depth,BMF_DISPLAYABLE,DefaultScreen -> RastPort . BitMap,FALSE))
  2586.             {
  2587.                     /* Clear the bitplanes. */
  2588.  
  2589.                 BltBitMap(xdev -> super_bitmap,0,0,xdev -> super_bitmap,0,0,xdev -> super_width,xdev -> super_height,0x00,(1 << xdev -> super_bitmap -> Depth) - 1,NULL);
  2590.  
  2591.                     /* Create the scroller handles. */
  2592.  
  2593.                 if(CreateScrollers(dev,DefaultScreen))
  2594.                 {
  2595.                     struct IBox ZoomBox;
  2596.  
  2597.                         /* Set up the window alternate
  2598.                          * position.
  2599.                          */
  2600.  
  2601.                     ZoomBox . Left        = 0;
  2602.                     ZoomBox . Top        = DefaultScreen -> BarHeight + 1;
  2603.                     ZoomBox . Width        = ScreenWidth;
  2604.                     ZoomBox . Height    = ScreenHeight - ZoomBox . Top;
  2605.  
  2606.                         /* Eventually, open the display window. */
  2607.  
  2608.                     if(xdev -> window = OpenWindowTags(NULL,
  2609.                         WA_InnerWidth,        MIN(DefaultScreen -> Width / 2,xdev -> super_width),
  2610.                         WA_InnerHeight,        MIN(DefaultScreen -> Height / 2,xdev -> super_height),
  2611.                         WA_CloseGadget,        TRUE,
  2612.                         WA_DepthGadget,        TRUE,
  2613.                         WA_SizeGadget,        TRUE,
  2614.                         WA_SizeBRight,        TRUE,
  2615.                         WA_SizeBBottom,        TRUE,
  2616.                         WA_Zoom,        &ZoomBox,
  2617.                         WA_DragBar,        TRUE,
  2618.                         WA_NoCareRefresh,    TRUE,
  2619.                         WA_GimmeZeroZero,    TRUE,
  2620.                         WA_RMBTrap,        TRUE,
  2621.                         WA_SuperBitMap,        xdev -> super_bitmap,
  2622.                         WA_Gadgets,        xdev -> gadget[VERTICAL_SCROLLER],
  2623.                         WA_CustomScreen,    DefaultScreen,
  2624.                         WA_Title,        "Ghostscript Amiga output window",
  2625.                     TAG_DONE))
  2626.                     {
  2627.                         if(xdev -> temp_rport = CreateTempRPort(xdev -> window -> RPort))
  2628.                         {
  2629.                             if(xdev -> temp_array = (UBYTE *)AllocVec((xdev -> window -> WScreen -> Width + 15) & ~15,MEMF_ANY))
  2630.                             {
  2631.                                 struct Task *Task;
  2632.  
  2633.                                     /* Bring the window dispatcher task
  2634.                                      * to life...
  2635.                                      */
  2636.  
  2637.                                 if(Task = (struct Task *)CreateTask("Ghostscript window dispatcher",5,DispatchTask,8192))
  2638.                                 {
  2639.                                     const sigset_t trapped = sigmask(SIGINT);
  2640.  
  2641.                                         /* Cheap... */
  2642.  
  2643.                                     Task -> tc_UserData = dev;
  2644.  
  2645.                                         /* Who's calling? */
  2646.  
  2647.                                     xdev -> main = (struct Process *)FindTask(NULL);
  2648.  
  2649.                                         /* Don't let anybody interrupt us! */
  2650.  
  2651.                                     sigprocmask(SIG_BLOCK,&trapped,NULL);
  2652.  
  2653.                                     Forbid();
  2654.  
  2655.                                         /* Wake it up. */
  2656.  
  2657.                                     Signal(Task,SIG_HANDSHAKE);
  2658.  
  2659.                                         /* Clear the handshake bit. */
  2660.  
  2661.                                     SetSignal(0,SIG_HANDSHAKE);
  2662.  
  2663.                                         /* Wait for the report. */
  2664.  
  2665.                                     Wait(SIG_HANDSHAKE);
  2666.  
  2667.                                     Permit();
  2668.  
  2669.                                         /* Get the result. */
  2670.  
  2671.                                     Task = xdev -> dispatcher;
  2672.  
  2673.                                         /* Unblock signals. */
  2674.  
  2675.                                     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2676.                                 }
  2677.  
  2678.                                     /* Did we succeed in creating
  2679.                                      * the dispatcher task?
  2680.                                      */
  2681.  
  2682.                                 if(Task)
  2683.                                 {
  2684.                                     UWORD    MaxValue    = 0,
  2685.                                         MinValue    = 15000,
  2686.                                         Value,
  2687.                                         R,G,B;
  2688.  
  2689.                                         /* Set the window limits. */
  2690.  
  2691.                                     WindowLimits(xdev -> window,xdev -> window -> BorderLeft + MINIMUM_WIDTH + xdev -> window -> BorderRight,xdev -> window -> BorderTop + MINIMUM_HEIGHT + xdev -> window -> BorderBottom,xdev -> window -> BorderLeft + xdev -> super_width + xdev -> window -> BorderRight,xdev -> window -> BorderTop + xdev -> super_height + xdev -> window -> BorderBottom);
  2692.  
  2693.                                         /* Update the sliders. */
  2694.  
  2695.                                     WindowResize(dev);
  2696.  
  2697.                                         /* Look for the darkest and the lightest screen colours. */
  2698.  
  2699.                                     for(i = 0 ; i < MIN(xdev -> window -> WScreen -> ViewPort . ColorMap -> Count,(1 << Depth)) ; i++)
  2700.                                     {
  2701.                                         Value = GetRGB4(xdev -> window -> WScreen -> ViewPort . ColorMap,i);
  2702.  
  2703.                                         R = (Value >> 8) & 0xF;
  2704.                                         G = (Value >> 4) & 0xF;
  2705.                                         B =  Value       & 0xF;
  2706.  
  2707.                                             /* Luminance conversion included */
  2708.  
  2709.                                         Value = R * 299 + G * 588 + B * 113;
  2710.  
  2711.                                         if(Value > MaxValue)
  2712.                                         {
  2713.                                             MaxValue = Value;
  2714.  
  2715.                                             LightPen = i;
  2716.                                         }
  2717.  
  2718.                                         if(Value < MinValue)
  2719.                                         {
  2720.                                             MinValue = Value;
  2721.  
  2722.                                             DarkPen = i;
  2723.                                         }
  2724.                                     }
  2725.  
  2726.                                         /* Fill in the rest. */
  2727.  
  2728.                                     xdev -> width    = xdev -> super_width;
  2729.                                     xdev -> height    = xdev -> super_height;
  2730.                                     xdev -> rport    = xdev -> window -> RPort;
  2731.  
  2732.                                         /* Does the display support
  2733.                                          * at least eight colours?
  2734.                                          */
  2735.  
  2736.                                     if(Depth >= 3)
  2737.                                     {
  2738.                                         LONG cube_size,max;
  2739.  
  2740.                                             /* Set up a fitting colour cube. */
  2741.  
  2742.                                         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  2743.                                         {
  2744.                                             if((max = cube_size * cube_size * cube_size) <= 1 << Depth)
  2745.                                                 break;
  2746.                                         }
  2747.  
  2748.                                             /* Got enough colours? */
  2749.  
  2750.                                         if(cube_size != 1)
  2751.                                         {
  2752.                                             LONG *Pens;
  2753.  
  2754.                                                 /* Try to grab the cube colours,
  2755.                                                  * making a colour display.
  2756.                                                  */
  2757.  
  2758.                                             if(Pens = AllocatePens(&xdev -> window -> WScreen -> ViewPort,cube_size))
  2759.                                                 set_colour_device((gx_device_amiga *)dev,cube_size,Pens);
  2760.                                         }
  2761.                                     }
  2762.  
  2763.                                     SetBPen(xdev -> rport,0);
  2764.                                     SetDrMd(xdev -> rport,JAM2);
  2765.  
  2766.                                     amiga_set_pen(dev,DarkPen);
  2767.  
  2768.                                     UnlockPubScreen(NULL,DefaultScreen);
  2769.  
  2770.                                     return(0);
  2771.                                 }
  2772.                                 else
  2773.                                     perror("Ghostscript: failed to create dispatcher task");
  2774.                             }
  2775.                             else
  2776.                                 perror("Ghostscript: failed to create temporary line buffer.");
  2777.                         }
  2778.                         else
  2779.                             perror("Ghostscript: failed to create temporary raster port");
  2780.                     }
  2781.                     else
  2782.                         perror("Ghostscript: failed to open window");
  2783.                 }
  2784.                 else
  2785.                     perror("Ghostscript: failed to allocate scrollers");
  2786.             }
  2787.             else
  2788.                 perror("Ghostscript: failed to allocate bitmap");
  2789.         }
  2790.         else
  2791.             perror("Ghostscript: failed to get display mode information");
  2792.  
  2793.         UnlockPubScreen(NULL,DefaultScreen);
  2794.     }
  2795.     else
  2796.         perror("Ghostscript: failed to lock default public screen");
  2797.  
  2798.     return(-1);
  2799. }
  2800.  
  2801.     /* amiga_open_low(gx_device *dev):
  2802.      *
  2803.      *    Open the low resolution device.
  2804.      */
  2805.  
  2806. int
  2807. amiga_open_low(gx_device *dev)
  2808. {
  2809.     return(amiga_open(dev,LORES_KEY));
  2810. }
  2811.  
  2812.     /* amiga_open_high(gx_device *dev):
  2813.      *
  2814.      *    Open the high resolution device.
  2815.      */
  2816.  
  2817. int
  2818. amiga_open_high(gx_device *dev)
  2819. {
  2820.     return(amiga_open(dev,HIRESLACE_KEY));
  2821. }
  2822.  
  2823.     /* amiga_open_super(gx_device *dev):
  2824.      *
  2825.      *    Open the super high resolution device.
  2826.      */
  2827.  
  2828. int
  2829. amiga_open_super(gx_device *dev)
  2830. {
  2831.         /* Fall back to the default if not available. */
  2832.  
  2833.     if(ModeNotAvailable(SUPERLACE_KEY))
  2834.         return(amiga_open_high(dev));
  2835.     else
  2836.         return(amiga_open(dev,SUPERLACE_KEY));
  2837. }
  2838.  
  2839.     /* amiga_open_a2024(gx_device *dev):
  2840.      *
  2841.      *    Open the A2024 device.
  2842.      */
  2843.  
  2844. int
  2845. amiga_open_a2024(gx_device *dev)
  2846. {
  2847.         /* Fall back to the default if not available. */
  2848.  
  2849.     if(ModeNotAvailable(A2024TENHERTZ_KEY))
  2850.         return(amiga_open_super(dev));
  2851.     else
  2852.         return(amiga_open(dev,A2024TENHERTZ_KEY));
  2853. }
  2854.  
  2855.     /* amiga_open_picassoii(gx_device *dev):
  2856.      *
  2857.      *    Open the Picasso II device.
  2858.      */
  2859.  
  2860. int
  2861. amiga_open_picassoii(gx_device *dev)
  2862. {
  2863.         /* Fall back to the default if not available. */
  2864.  
  2865.     if(ModeNotAvailable(0x40020002))
  2866.         return(amiga_open_super(dev));
  2867.     else
  2868.         return(amiga_open(dev,0x40020002));
  2869. }
  2870.  
  2871. int
  2872. amiga_open_custom(gx_device *dev)
  2873. {
  2874.     UBYTE    Buffer[256];
  2875.     ULONG    ScreenID    = INVALID_ID;
  2876.     BOOL    DontTouch    = FALSE;
  2877.  
  2878.         /* First step: check for an environment variable to give
  2879.          *             the name of the display mode to use.
  2880.          */
  2881.  
  2882.     if(GetVar("GSCUSTOMMODE",Buffer,256,NULL) != -1)
  2883.     {
  2884.         UBYTE PatternBuffer[516];
  2885.  
  2886.             /* Set up the search pattern. */
  2887.  
  2888.         if(ParsePatternNoCase(Buffer,PatternBuffer,516) >= 0)
  2889.         {
  2890.             ULONG CurrentID = INVALID_ID,ID;
  2891.  
  2892.                 /* Scan the entire list. */
  2893.  
  2894.             while((CurrentID = NextDisplayInfo(CurrentID)) != INVALID_ID)
  2895.             {
  2896.                     /* Valid mode? */
  2897.  
  2898.                 if(!ModeNotAvailable(CurrentID))
  2899.                 {
  2900.                     struct NameInfo    NameInfo;
  2901.  
  2902.                         /* Get the name information. */
  2903.  
  2904.                     if(GetDisplayInfoData(NULL,&NameInfo,sizeof(struct NameInfo),DTAG_NAME,CurrentID))
  2905.                     {
  2906.                             /* Does the mode name match the pattern given? */
  2907.  
  2908.                         if(MatchPatternNoCase(PatternBuffer,NameInfo . Name))
  2909.                         {
  2910.                             ScreenID = CurrentID;
  2911.  
  2912.                                 /* Don't overwrite the variable contents. */
  2913.  
  2914.                             DontTouch = TRUE;
  2915.  
  2916.                             break;
  2917.                         }
  2918.                     }
  2919.                 }
  2920.             }
  2921.         }
  2922.     }
  2923.  
  2924.     if(ScreenID == INVALID_ID && AslBase)
  2925.     {
  2926.         struct ScreenModeRequester *ScreenModeRequester;
  2927.  
  2928.         if(ScreenModeRequester = (struct ScreenModeRequester *)AllocAslRequestTags(ASL_ScreenModeRequest,TAG_DONE))
  2929.         {
  2930.             if(AslRequestTags(ScreenModeRequester,
  2931.                 ASLSM_TitleText,    "Select GhostScript screen display mode",
  2932.                 ASLSM_MinDepth,        1,
  2933.                 ASLSM_MaxDepth,        8,
  2934.             TAG_DONE))
  2935.                 ScreenID = ScreenModeRequester -> sm_DisplayID;
  2936.  
  2937.             FreeAslRequest(ScreenModeRequester);
  2938.         }
  2939.     }
  2940.  
  2941.         /* Fall back to the default if not available. */
  2942.  
  2943.     if(ModeNotAvailable(ScreenID))
  2944.         return(amiga_open_default(dev));
  2945.     else
  2946.     {
  2947.         int result = amiga_open(dev,ScreenID);
  2948.  
  2949.             /* If successful store the name of the
  2950.              * screen mode selected.
  2951.              */
  2952.  
  2953.         if(!result && !DontTouch)
  2954.         {
  2955.             struct NameInfo    NameInfo;
  2956.  
  2957.             if(GetDisplayInfoData(NULL,&NameInfo,sizeof(struct NameInfo),DTAG_NAME,ScreenID))
  2958.                 SetVar("GSCUSTOMMODE",NameInfo . Name,-1,NULL);
  2959.         }
  2960.  
  2961.         return(result);
  2962.     }
  2963. }
  2964.  
  2965.     /* amiga_open_printer(gx_device *dev):
  2966.      *
  2967.      *    Open the printer device.
  2968.      */
  2969.  
  2970. int
  2971. amiga_open_printer(gx_device *dev)
  2972. {
  2973.     if(xdev -> port = CreateMsgPort())
  2974.     {
  2975.         if(xdev -> printer = (struct IODRPReq *)CreateIORequest(xdev -> port,sizeof(struct IODRPReq)))
  2976.         {
  2977.             if(!OpenDevice("printer.device",0,(struct IORequest *)xdev -> printer,0))
  2978.             {
  2979.                 if(xdev -> rport = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
  2980.                 {
  2981.                     const sigset_t    trapped = sigmask(SIGINT);
  2982.                     struct BitMap    DummyBitMap;
  2983.                     UWORD        DummyLine[12];
  2984.  
  2985.                     InitRastPort(xdev -> rport);
  2986.  
  2987.                         /* Cook up a dummy bitmap to keep
  2988.                          * `smart' drivers from complaining.
  2989.                          */
  2990.  
  2991.                     InitBitMap(&DummyBitMap,12,16,16);
  2992.  
  2993.                     DummyBitMap . Planes[0] = (PLANEPTR)&DummyLine;
  2994.  
  2995.                     xdev -> rport -> BitMap = &DummyBitMap;
  2996.  
  2997.                         /* Query page size requirements. */
  2998.  
  2999.                     xdev -> printer -> io_Command    = PRD_DUMPRPORT;
  3000.                     xdev -> printer -> io_RastPort    = xdev -> rport;
  3001.                     xdev -> printer -> io_SrcWidth    = 16;
  3002.                     xdev -> printer -> io_SrcHeight    = 16;
  3003.                     xdev -> printer -> io_Modes    = LORES_KEY;
  3004.  
  3005.                     xdev -> printer -> io_Special    |= SPECIAL_FULLCOLS | SPECIAL_FULLROWS | SPECIAL_NOPRINT;
  3006.  
  3007.                         /* Don't let them stop us now! */
  3008.  
  3009.                     sigprocmask(SIG_BLOCK,&trapped,NULL);
  3010.  
  3011.                         /* Ask for it... */
  3012.  
  3013.                     if(!DoIO((struct IORequest *)xdev -> printer))
  3014.                     {
  3015.                         struct PrinterExtendedData    *PED;
  3016.                         struct PrinterData        *PD;
  3017.                         struct Preferences        *Prefs;
  3018.                         LONG                 Depth,
  3019.                                          NumColours,
  3020.                                          CubeSize;
  3021.                         LONG                 PageWidth,
  3022.                                          PageHeight;
  3023.  
  3024.                             /* Unblock ^C signal. */
  3025.  
  3026.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3027.  
  3028.                         xdev -> printer -> io_Special &= ~(SPECIAL_FULLCOLS | SPECIAL_FULLROWS | SPECIAL_NOPRINT);
  3029.  
  3030.                             /* Get the printer internal data. */
  3031.  
  3032.                         PD    = (struct PrinterData *)xdev -> printer -> io_Device;
  3033.                         PED    = &PD -> pd_SegmentData -> ps_PED;
  3034.                         Prefs    = &PD -> pd_Preferences;
  3035.  
  3036.                             /* Calculate the printer page size. */
  3037.  
  3038.                         PageWidth    = PED -> ped_XDotsInch * (Prefs -> PrintRightMargin - Prefs -> PrintLeftMargin + 1);
  3039.                         PageHeight    = PED -> ped_YDotsInch * Prefs -> PaperLength;
  3040.  
  3041.                         switch(Prefs -> PrintPitch)
  3042.                         {
  3043.                             case PICA:
  3044.  
  3045.                                 PageWidth /= 10;
  3046.                                 break;
  3047.  
  3048.                             case ELITE:
  3049.  
  3050.                                 PageWidth /= 12;
  3051.                                 break;
  3052.  
  3053.                             case FINE:
  3054.  
  3055.                                 PageWidth /= 15;
  3056.                                 break;
  3057.                         }
  3058.  
  3059.                         switch(Prefs -> PrintSpacing)
  3060.                         {
  3061.                             case SIX_LPI:
  3062.  
  3063.                                 PageHeight /= 6;
  3064.                                 break;
  3065.  
  3066.                             case EIGHT_LPI:
  3067.  
  3068.                                 PageHeight /= 8;
  3069.                                 break;
  3070.                         }
  3071.  
  3072.                         if(PageWidth > PED -> ped_MaxXDots)
  3073.                             PageWidth = PED -> ped_MaxXDots;
  3074.  
  3075.                         if(PageHeight > PED -> ped_MaxYDots && PED -> ped_MaxYDots)
  3076.                             PageHeight = PED -> ped_MaxYDots;
  3077.  
  3078.                             /* Set up the default colour values. */
  3079.  
  3080.                         if(Prefs -> PrintShade == SHADE_BW)
  3081.                         {
  3082.                             Depth        = 1;
  3083.                             NumColours    = 2;
  3084.                             CubeSize    = 0;
  3085.                         }
  3086.                         else
  3087.                         {
  3088.                             Depth        = 12;
  3089.                             NumColours    = 4096;
  3090.                             CubeSize    = 16;
  3091.                         }
  3092.  
  3093.                             /* Get the page size */
  3094.  
  3095.                         if(xdev -> width > 0 && xdev -> height > 0)
  3096.                         {
  3097.                             if(PageWidth < xdev -> width)
  3098.                                 xdev -> width = PageWidth;
  3099.  
  3100.                             if(PageHeight < xdev -> height)
  3101.                                 xdev -> height = PageHeight;
  3102.                         }
  3103.                         else
  3104.                         {
  3105.                             xdev -> width    = PageWidth;
  3106.                             xdev -> height    = PageHeight;
  3107.                         }
  3108.  
  3109.                             /* Get the DPI values */
  3110.  
  3111.                         xdev -> x_pixels_per_inch    = (float)PED -> ped_XDotsInch;
  3112.                         xdev -> y_pixels_per_inch    = (float)PED -> ped_YDotsInch;
  3113.  
  3114.                             /* Try to allocate a suitable bitmap.
  3115.                              * If an allocation fails, rescale the
  3116.                              * colour cube and bitmap depth and
  3117.                              * retry. Minimum are eight colours.
  3118.                              */
  3119.  
  3120.                         do
  3121.                         {
  3122.                                 /* Try to allocate the raster... */
  3123.  
  3124.                             if(!(xdev -> bitmap = CreateBitMap(xdev -> width,xdev -> height,Depth,NULL,NULL,TRUE)))
  3125.                             {
  3126.                                     /* Any chance to rescale the cube? */
  3127.  
  3128.                                 if(Depth < 2)
  3129.                                     break;
  3130.                                 else
  3131.                                 {
  3132.                                         /* One plane less... */
  3133.  
  3134.                                     Depth--;
  3135.  
  3136.                                         /* Rescale the cube. */
  3137.  
  3138.                                     while(CubeSize >= 2)
  3139.                                     {
  3140.                                         if((NumColours = CubeSize * CubeSize * CubeSize) <= (1 << Depth))
  3141.                                             break;
  3142.                                         else
  3143.                                             CubeSize--;
  3144.                                     }
  3145.  
  3146.                                         /* Less than eight colours? */
  3147.  
  3148.                                     if(CubeSize < 2)
  3149.                                         break;
  3150.                                 }
  3151.                             }
  3152.                         }
  3153.                         while(!xdev -> bitmap);
  3154.  
  3155.                             /* Got the bitmap? */
  3156.  
  3157.                         if(xdev -> bitmap)
  3158.                         {
  3159.                                 /* Allocate a suitable colour map. */
  3160.  
  3161.                             if(xdev -> colormap = GetColorMap(NumColours))
  3162.                             {
  3163.                                     /* Black & white only? */
  3164.  
  3165.                                 if(NumColours == 2)
  3166.                                 {
  3167.                                     SetRGB4CM(xdev -> colormap,0,0x0,0x0,0x0);
  3168.                                     SetRGB4CM(xdev -> colormap,1,0xF,0xF,0xF);
  3169.                                 }
  3170.                                 else
  3171.                                 {
  3172.                                     LONG i = 0,r,g,b,max = CubeSize - 1;
  3173.  
  3174.                                         /* Fill in the colour cube. */
  3175.  
  3176.                                     for(r = 0 ; r < CubeSize ; r++)
  3177.                                     {
  3178.                                         for(g = 0 ; g < CubeSize ; g++)
  3179.                                         {
  3180.                                             for(b = 0 ; b < CubeSize ; b++)
  3181.                                                 SetRGB4CM(xdev -> colormap,i++,(15 * r) / max,(15 * g) / max,(15 * b) / max);
  3182.                                         }
  3183.                                     }
  3184.  
  3185.                                     set_colour_printer_device((gx_device_amiga *)dev,CubeSize);
  3186.                                 }
  3187.  
  3188.                                 xdev -> printer -> io_ColorMap    = xdev -> colormap;
  3189.                                 xdev -> rport -> BitMap        = xdev -> bitmap;
  3190.  
  3191.                                 return(0);
  3192.                             }
  3193.                             else
  3194.                                 perror("Ghostscript: failed to allocate colour map");
  3195.                         }
  3196.                         else
  3197.                         {
  3198.                             char buffer[256];
  3199.  
  3200.                             sprintf(buffer,"Ghostscript: failed to allocate raster (wanted %ld, largest %ld)",(xdev -> width + 15) / 8 * xdev -> height * Depth,AvailMem(MEMF_ANY | MEMF_LARGEST));
  3201.  
  3202.                             perror(buffer);
  3203.                         }
  3204.                     }
  3205.                     else
  3206.                     {
  3207.                         char buffer[256];
  3208.  
  3209.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3210.  
  3211.                         sprintf(buffer,"Ghostscript: failed to query printer page size (error code #%ld)",xdev -> printer -> io_Error);
  3212.  
  3213.                         perror(buffer);
  3214.                     }
  3215.                 }
  3216.                 else
  3217.                     perror("Ghostscript: failed to allocate raster port");
  3218.             }
  3219.             else
  3220.             {
  3221.                 char buffer[256];
  3222.  
  3223.                 sprintf(buffer,"Ghostscript: failed to open printer.device (error code #%ld)",xdev -> printer -> io_Error);
  3224.  
  3225.                 perror(buffer);
  3226.             }
  3227.         }
  3228.         else
  3229.             perror("Ghostscript: failed to allocate device driver");
  3230.     }
  3231.     else
  3232.         perror("Ghostscript: failed to create io port");
  3233.  
  3234.     return(-1);
  3235. }
  3236.  
  3237.     /* amiga_output_page_printer(gx_device *dev,int,int):
  3238.      *
  3239.      *    Send a bitmap to the printer.
  3240.      */
  3241.  
  3242. int
  3243. amiga_output_page_printer(gx_device *dev,int num_copies,int flush)
  3244. {
  3245.     const sigset_t trapped = sigmask(SIGINT);
  3246.     int result,i;
  3247.     ULONG Signals;
  3248.  
  3249.     xdev -> printer -> io_Command    = PRD_DUMPRPORT;
  3250.     xdev -> printer -> io_SrcWidth    = xdev -> width;
  3251.     xdev -> printer -> io_SrcHeight    = xdev -> height;
  3252.     xdev -> printer -> io_DestCols    = xdev -> width;
  3253.     xdev -> printer -> io_DestRows    = xdev -> height;
  3254.  
  3255.         /* We cannot possibly allow being interrupted in the middle
  3256.          * of a raster dump!
  3257.          */
  3258.  
  3259.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  3260.  
  3261.     for(i = 0 ; i < num_copies ; i++)
  3262.     {
  3263.         SetSignal(0,SIGBREAKF_CTRL_C | (1L << xdev -> port -> mp_SigBit));
  3264.  
  3265.         SendIO((struct IORequest *)xdev -> printer);
  3266.  
  3267.         Signals = Wait(SIGBREAKF_CTRL_C | (1L << xdev -> port -> mp_SigBit));
  3268.  
  3269.         if(Signals & SIGBREAKF_CTRL_C)
  3270.         {
  3271.             char buffer[256];
  3272.  
  3273.             if(!CheckIO((struct IORequest *)xdev -> printer))
  3274.                 AbortIO((struct IORequest *)xdev -> printer);
  3275.  
  3276.             WaitIO((struct IORequest *)xdev -> printer);
  3277.  
  3278.             sprintf(buffer,"Ghostscript: printing aborted");
  3279.  
  3280.             perror(buffer);
  3281.  
  3282.             result = -1;
  3283.  
  3284.             sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3285.  
  3286.             break;
  3287.         }
  3288.  
  3289.         if(Signals & (1L << xdev -> port -> mp_SigBit))
  3290.         {
  3291.             if(WaitIO((struct IORequest *)xdev -> printer))
  3292.             {
  3293.                 char buffer[256];
  3294.  
  3295.                 sprintf(buffer,"Ghostscript: failed to print raster (error code #%ld)",xdev -> printer -> io_Error);
  3296.  
  3297.                 perror(buffer);
  3298.  
  3299.                 result = -1;
  3300.  
  3301.                 sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3302.  
  3303.                 break;
  3304.             }
  3305.             else
  3306.                 result = 0;
  3307.         }
  3308.     }
  3309.  
  3310.     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3311.  
  3312.     return(result);
  3313. }
  3314.  
  3315.     /* amiga_close_printer(gx_device *dev):
  3316.      *
  3317.      *    Close the printer driver.
  3318.      */
  3319.  
  3320. int
  3321. amiga_close_printer(gx_device *dev)
  3322. {
  3323.     if(xdev -> bitmap)
  3324.     {
  3325.         DeleteBitMap(xdev -> bitmap,TRUE);
  3326.  
  3327.         xdev -> bitmap = NULL;
  3328.     }
  3329.  
  3330.     if(xdev -> rport)
  3331.     {
  3332.         FreeVec(xdev -> rport);
  3333.  
  3334.         xdev -> rport = NULL;
  3335.     }
  3336.  
  3337.     if(xdev -> colormap)
  3338.     {
  3339.         FreeColorMap(xdev -> colormap);
  3340.  
  3341.         xdev -> colormap = NULL;
  3342.     }
  3343.  
  3344.     if(xdev -> printer)
  3345.     {
  3346.         if(xdev -> printer -> io_Device)
  3347.             CloseDevice((struct IORequest *)xdev -> printer);
  3348.  
  3349.         DeleteIORequest(xdev -> printer);
  3350.  
  3351.         xdev -> printer = NULL;
  3352.     }
  3353.  
  3354.     if(xdev -> port)
  3355.     {
  3356.         DeleteMsgPort(xdev -> port);
  3357.  
  3358.         xdev -> port = NULL;
  3359.     }
  3360.  
  3361.     xdev -> width = xdev -> height = 0;
  3362. /*    xdev -> x_pixels_per_inch = x_pixels_per_inch = 72.72;*/
  3363.  
  3364.     return(0);
  3365. }
  3366.  
  3367.     /* amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data):
  3368.      *
  3369.      *    Read the raster bits into a buffer.
  3370.      */
  3371.  
  3372. int
  3373. amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data)
  3374. {
  3375.     if(y < 0 || y > xdev -> height)
  3376.         return(-1);
  3377.     else
  3378.     {
  3379.         if(actual_data)
  3380.             *actual_data = (byte *)(xdev -> bitmap -> Planes[0] + xdev -> bitmap -> BytesPerRow * y);
  3381.         else
  3382.             memcpy(str,xdev -> bitmap -> Planes[0] + xdev -> bitmap -> BytesPerRow * y,xdev -> bitmap -> BytesPerRow);
  3383.  
  3384.         return(0);
  3385.     }
  3386. }
  3387.  
  3388.     /* amiga_open(gx_device *dev,ULONG Mode):
  3389.      *
  3390.      *    Open a custom screen.
  3391.      */
  3392.  
  3393. int
  3394. amiga_open(gx_device *dev,ULONG Mode)
  3395. {
  3396.     struct DisplayInfo    DisplayInfo;
  3397.     struct DimensionInfo    DimensionInfo;
  3398.  
  3399.         /* Get the display dimensions. */
  3400.  
  3401.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode) && GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,Mode))
  3402.     {
  3403.             /* Two shades only, black & white */
  3404.  
  3405.         STATIC struct ColorSpec Colours[] =
  3406.         {
  3407.              0,    0x0000, 0x0000, 0x0000,
  3408.              1,    0xFFFF, 0xFFFF, 0xFFFF,
  3409.  
  3410.             -1
  3411.         };
  3412.  
  3413.         float    Width,
  3414.             Height;
  3415.         LONG    i,cube_size,max;
  3416.         LONG    ScreenWidth,
  3417.             ScreenHeight,
  3418.             ScreenDepth;
  3419.  
  3420.             /* Start up with a maximum depth display. */
  3421.  
  3422.         ScreenDepth = DimensionInfo . MaxDepth;
  3423.  
  3424.             /* Check to see whether we will be able to
  3425.              * build a colour display or not.
  3426.              */
  3427.  
  3428.         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  3429.         {
  3430.             if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3431.                 break;
  3432.         }
  3433.  
  3434.             /* Got enough colours? */
  3435.  
  3436.         if(cube_size != 1)
  3437.             set_colour_device((gx_device_amiga *)dev,cube_size,NULL);
  3438.         else
  3439.         {
  3440.             ScreenDepth = 1;
  3441.  
  3442.             set_mono_device((gx_device_amiga *)dev);
  3443.         }
  3444.  
  3445.         if(xdev -> width > 0 && xdev -> height > 0)
  3446.         {
  3447.             Width    = xdev -> width;
  3448.             Height    = xdev -> height;
  3449.         }
  3450.         else
  3451.         {
  3452.             if(xdev -> page_width > 0.0)
  3453.                 Width = xdev -> page_width;
  3454.             else
  3455.                 Width = 0.0;
  3456.  
  3457.             if(xdev -> page_height > 0.0)
  3458.                 Height = xdev -> page_height;
  3459.             else
  3460.                 Height = 0.0;
  3461.         }
  3462.  
  3463.             /* Use the best guess, we will take the standard
  3464.              * low resolution x-dpi value and scale it by
  3465.              * the pixel speed.
  3466.              */
  3467.  
  3468.         if(DisplayInfo . PixelSpeed)
  3469.         {
  3470.             xdev -> x_pixels_per_inch = (35.0 * 140.0) / (float)DisplayInfo . PixelSpeed;
  3471.             xdev -> y_pixels_per_inch = (xdev -> x_pixels_per_inch * (float)DisplayInfo . Resolution . x) / (float)DisplayInfo . Resolution . y;
  3472.         }
  3473.         else
  3474.         {
  3475.             xdev -> x_pixels_per_inch = 72.27;
  3476.             xdev -> y_pixels_per_inch = 72.27;
  3477.         }
  3478.  
  3479.         if(Width > 0.0)
  3480.             ScreenWidth = (LONG)(Width * xdev -> x_pixels_per_inch);
  3481.         else
  3482.             ScreenWidth = 0;
  3483.  
  3484.         if(Height > 0.0)
  3485.             ScreenHeight = (LONG)(Height * xdev -> y_pixels_per_inch);
  3486.         else
  3487.             ScreenHeight = 0;
  3488.  
  3489.         if(ScreenWidth < DimensionInfo . MinRasterWidth || ScreenWidth > DimensionInfo . MaxRasterWidth)
  3490.             ScreenWidth = 0;
  3491.  
  3492.         if(ScreenHeight < DimensionInfo . MinRasterHeight || ScreenHeight > DimensionInfo . MaxRasterHeight)
  3493.             ScreenHeight = 0;
  3494.  
  3495.             /* Try to open a custom screen; if this fails, try to
  3496.              * rescale the colour cube and retry.
  3497.              */
  3498.  
  3499.         do
  3500.         {
  3501.             if(!(xdev -> screen = OpenScreenTags(NULL,
  3502.                 SA_Depth,    ScreenDepth,
  3503.                 SA_Overscan,    OSCAN_TEXT,
  3504.                 SA_Quiet,    TRUE,
  3505.                 SA_Behind,    TRUE,
  3506.                 SA_DisplayID,    Mode,
  3507.                 SA_Colors,    Colours,
  3508.                 SA_AutoScroll,    TRUE,
  3509.                 SA_ShowTitle,    FALSE,
  3510.                 SA_Title,    "Ghostscript Amiga output screen",
  3511.  
  3512.                 ScreenWidth  > 0 ? SA_Width  : TAG_IGNORE,    ScreenWidth,
  3513.                 ScreenHeight > 0 ? SA_Height : TAG_IGNORE,    ScreenHeight,
  3514.             TAG_DONE)))
  3515.             {
  3516.                 if(ScreenDepth < 2)
  3517.                     break;
  3518.                 else
  3519.                 {
  3520.                     ScreenDepth--;
  3521.  
  3522.                         /* Check to see whether we will be able to
  3523.                          * build a colour display or not.
  3524.                          */
  3525.  
  3526.                     while(cube_size >= 2)
  3527.                     {
  3528.                         if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3529.                             break;
  3530.                         else
  3531.                             cube_size--;
  3532.                     }
  3533.  
  3534.                         /* Got enough colours? */
  3535.  
  3536.                     if(cube_size == 1 || ScreenDepth == 1)
  3537.                     {
  3538.                             /* Obviously not. */
  3539.  
  3540.                         ScreenDepth = 1;
  3541.  
  3542.                         set_mono_device((gx_device_amiga *)dev);
  3543.                     }
  3544.                 }
  3545.             }
  3546.         }
  3547.         while(!xdev -> screen);
  3548.  
  3549.             /* Did we succeed in opening the screen? */
  3550.  
  3551.         if(xdev -> screen)
  3552.         {
  3553.             if(xdev -> window = OpenWindowTags(NULL,
  3554.                 WA_Left,    0,
  3555.                 WA_Top,        0,
  3556.                 WA_Width,    xdev -> screen -> Width,
  3557.                 WA_Height,    xdev -> screen -> Height,
  3558.                 WA_Backdrop,    TRUE,
  3559.                 WA_RMBTrap,    TRUE,
  3560.                 WA_Borderless,    TRUE,
  3561.                 WA_CustomScreen,xdev -> screen,
  3562.             TAG_DONE))
  3563.             {
  3564.                 xdev -> rport    = xdev -> window -> RPort;
  3565.                 xdev -> width    = xdev -> screen -> Width;
  3566.                 xdev -> height    = xdev -> screen -> Height;
  3567.             }
  3568.             else
  3569.             {
  3570.                 xdev -> rport    = &xdev -> screen -> RastPort;
  3571.                 xdev -> width    = xdev -> screen -> Width;
  3572.                 xdev -> height    = xdev -> screen -> Height;
  3573.             }
  3574.  
  3575.                 /* Establish defaults. */
  3576.  
  3577.             DarkPen        = 0;
  3578.             LightPen    = 1;
  3579.  
  3580.             SetBPen(xdev -> rport,0);
  3581.             SetDrMd(xdev -> rport,JAM2);
  3582.  
  3583.                 /* Create the temporary drawing area. */
  3584.  
  3585.             if(xdev -> temp_rport = CreateTempRPort(xdev -> rport))
  3586.             {
  3587.                 if(xdev -> temp_array = (UBYTE *)AllocVec((xdev -> screen -> Width + 15) & ~15,MEMF_ANY))
  3588.                 {
  3589.                         /* Colour output enabled? */
  3590.  
  3591.                     if(xdev -> cube_size > 0)
  3592.                     {
  3593.                         LONG r,g,b,max = xdev -> cube_size - 1;
  3594.  
  3595.                         i = 0;
  3596.  
  3597.                             /* Build a suitable colour map. */
  3598.  
  3599.                         if(GfxBase -> LibNode . lib_Version >= 39)
  3600.                         {
  3601.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3602.                             {
  3603.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3604.                                 {
  3605.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3606.                                         SetRGB32(&xdev -> screen -> ViewPort,i++,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max));
  3607.                                 }
  3608.                             }
  3609.                         }
  3610.                         else
  3611.                         {
  3612.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3613.                             {
  3614.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3615.                                 {
  3616.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3617.                                         SetRGB4(&xdev -> screen -> ViewPort,i++,(15 * r) / max,(15 * g) / max,(15 * b) / max);
  3618.                                 }
  3619.                             }
  3620.                         }
  3621.                     }
  3622.                 }
  3623.                 else
  3624.                 {
  3625.                     perror("Ghostscript: failed to allocate temporary line");
  3626.  
  3627.                     return(-1);
  3628.                 }
  3629.             }
  3630.             else
  3631.             {
  3632.                 perror("Ghostscript: failed to allocate temporary raster");
  3633.  
  3634.                 return(-1);
  3635.             }
  3636.  
  3637.             amiga_set_pen(dev,DarkPen);
  3638.  
  3639.             return(0);
  3640.         }
  3641.         else
  3642.             perror("Ghostscript: failed to open screen");
  3643.     }
  3644.     else
  3645.         perror("Ghostscript: failed to get display mode information");
  3646.  
  3647.     return(-1);
  3648. }
  3649.  
  3650.     /* amiga_output_page(gx_device *dev,int,int):
  3651.      *
  3652.      *    Page is not `buffered', just bring screen/window
  3653.      *    to the front.
  3654.      */
  3655.  
  3656. int
  3657. amiga_output_page(gx_device *dev,int num_copies,int flush)
  3658. {
  3659.     if(xdev -> screen)
  3660.         ScreenToFront(xdev -> screen);
  3661.     else
  3662.     {
  3663.         if(xdev -> window)
  3664.             WindowToFront(xdev -> window);
  3665.     }
  3666.  
  3667.     return(0);
  3668. }
  3669.  
  3670.     /* amiga_close(gx_device *dev):
  3671.      *
  3672.      *    Close the screen and free associated resources.
  3673.      */
  3674.  
  3675. int
  3676. amiga_close(gx_device *dev)
  3677. {
  3678.     if(xdev -> dispatcher)
  3679.     {
  3680.         const sigset_t trapped = sigmask(SIGINT);
  3681.  
  3682.         sigprocmask(SIG_BLOCK,&trapped,NULL);
  3683.  
  3684.         Forbid();
  3685.  
  3686.         Signal(xdev -> dispatcher,SIG_KILL);
  3687.  
  3688.         SetSignal(0,SIG_HANDSHAKE);
  3689.  
  3690.         Wait(SIG_HANDSHAKE);
  3691.  
  3692.         Permit();
  3693.  
  3694.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3695.     }
  3696.  
  3697.     if(xdev -> temp_array)
  3698.     {
  3699.         FreeVec(xdev -> temp_array);
  3700.  
  3701.         xdev -> temp_array = NULL;
  3702.     }
  3703.  
  3704.     if(xdev -> pens)
  3705.     {
  3706.         LONG i;
  3707.  
  3708.         for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  3709.         {
  3710.             if(xdev -> pens[i] != -1)
  3711.                 ReleasePen(xdev -> window -> WScreen -> ViewPort . ColorMap,xdev -> pens[i]);
  3712.         }
  3713.  
  3714.         FreeVec(xdev -> pens);
  3715.  
  3716.         xdev -> pens = NULL;
  3717.     }
  3718.  
  3719.     if(xdev -> temp_rport)
  3720.     {
  3721.         DeleteTempRPort(xdev -> temp_rport);
  3722.  
  3723.         xdev -> temp_rport = NULL;
  3724.     }
  3725.  
  3726.     if(xdev -> window)
  3727.     {
  3728.         CloseWindow(xdev -> window);
  3729.  
  3730.         xdev -> window = NULL;
  3731.     }
  3732.  
  3733.     DeleteScrollers(dev);
  3734.  
  3735.     if(xdev -> super_bitmap)
  3736.     {
  3737.         DeleteBitMap(xdev -> super_bitmap,FALSE);
  3738.  
  3739.         xdev -> super_bitmap = NULL;
  3740.     }
  3741.  
  3742.     if(xdev -> screen)
  3743.     {
  3744.         CloseScreen(xdev -> screen);
  3745.  
  3746.         xdev -> screen = NULL;
  3747.     }
  3748.  
  3749.     xdev -> width = xdev -> height = 0;
  3750. /*    xdev -> x_pixels_per_inch = x_pixels_per_inch = 72.72;*/
  3751.  
  3752.     return(0);
  3753. }
  3754.  
  3755.     /* amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color):
  3756.      *
  3757.      *    Fill a rectangle with a given colour. This one is simple as it can
  3758.      *    be done with the Amiga graphics primitives.
  3759.      */
  3760.  
  3761. int
  3762. amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  3763. {
  3764.     if(x < 0 || x > xdev -> width - w || y < 0 || y > xdev -> height - h)
  3765.         return(-1);
  3766.     else
  3767.     {
  3768.         if(w > 0 && h > 0 && color != gx_no_color_index)
  3769.         {
  3770.             amiga_set_pen(dev,color);
  3771.  
  3772.             RectFill(xdev -> rport,x,y,x + w - 1,y + h - 1);
  3773.         }
  3774.  
  3775.         return(0);
  3776.     }
  3777. }
  3778.  
  3779.     /* amiga_copy_mono():
  3780.      *
  3781.      *    Copy a monochrome image. This operation requires a bit of work as
  3782.      *    we cannot simply blit the image into the bitmap.
  3783.      */
  3784.  
  3785. int
  3786. amiga_copy_mono(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3787. {
  3788.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3789.         return(-1);
  3790.     else
  3791.     {
  3792.         if(w > 0 && h > 0)
  3793.         {
  3794.             LONG i,j;
  3795.  
  3796.             if(zero == gx_no_color_index)
  3797.             {
  3798.                 if(one != gx_no_color_index)
  3799.                 {
  3800.                     do
  3801.                     {
  3802.                         ReadPixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3803.  
  3804.                         for(i = sourcex, j = 0 ; i < sourcex + w ; i++, j++)
  3805.                         {
  3806.                             if(base[i >> 3] & shift[i & 7])
  3807.                                 xdev -> temp_array[j] = one;
  3808.                         }
  3809.  
  3810.                         WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3811.  
  3812.                         base += raster;
  3813.  
  3814.                         y++;
  3815.                     }
  3816.                     while(--h);
  3817.                 }
  3818.             }
  3819.             else
  3820.             {
  3821.                 if(one == gx_no_color_index)
  3822.                 {
  3823.                     do
  3824.                     {
  3825.                         ReadPixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3826.  
  3827.                         for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3828.                         {
  3829.                             if(!(base[i >> 3] & shift[i & 7]))
  3830.                                 xdev -> temp_array[j] = zero;
  3831.                         }
  3832.  
  3833.                         WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3834.  
  3835.                         base += raster;
  3836.  
  3837.                         y++;
  3838.                     }
  3839.                     while(--h);
  3840.                 }
  3841.                 else
  3842.                 {
  3843.                     do
  3844.                     {
  3845.                         for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3846.                         {
  3847.                             if(base[i >> 3] & shift[i & 7])
  3848.                                 xdev -> temp_array[j] = one;
  3849.                             else
  3850.                                 xdev -> temp_array[j] = zero;
  3851.                         }
  3852.  
  3853.                         WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3854.  
  3855.                         base += raster;
  3856.  
  3857.                         y++;
  3858.                     }
  3859.                     while(--h);
  3860.                 }
  3861.             }
  3862.         }
  3863.  
  3864.         return(0);
  3865.     }
  3866. }
  3867.  
  3868.     /* amiga_copy_color():
  3869.      *
  3870.      *    Copy a color image (oh well...). This is just the same as the
  3871.      *    copy_mono() routine.
  3872.      */
  3873.  
  3874. int
  3875. amiga_copy_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  3876. {
  3877.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3878.         return(-1);
  3879.     else
  3880.     {
  3881.         if(w > 0 && h > 0)
  3882.         {
  3883.             LONG i,j;
  3884.  
  3885.             do
  3886.             {
  3887.                 for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3888.                 {
  3889.                     if(base[i >> 3] & shift[i & 7])
  3890.                         xdev -> temp_array[j] = DarkPen;
  3891.                     else
  3892.                         xdev -> temp_array[j] = LightPen;
  3893.                 }
  3894.  
  3895.                 WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3896.  
  3897.                 base += raster;
  3898.  
  3899.                 y++;
  3900.             }
  3901.             while(--h);
  3902.         }
  3903.  
  3904.         return(0);
  3905.     }
  3906. }
  3907.  
  3908.     /* amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color):
  3909.      *
  3910.      *    Draw a line between two points. This one is easy as it can be done
  3911.      *    with the Amiga graphics primitives, the only glitch is having to reset
  3912.      *    the last dot to its original colour.
  3913.      */
  3914.  
  3915. int
  3916. amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color)
  3917. {
  3918.     if(color != gx_no_color_index && (x0 != x1 || y0 != y1))
  3919.     {
  3920.         LONG pen;
  3921.  
  3922.         pen = ReadPixel(xdev -> rport,x1,y1);
  3923.  
  3924.         amiga_set_pen(dev,color);
  3925.  
  3926.         Move(xdev -> rport,x0,y0);
  3927.         Draw(xdev -> rport,x1,y1);
  3928.  
  3929.         if(pen == color)
  3930.         {
  3931.             amiga_set_pen(dev,pen);
  3932.  
  3933.             WritePixel(xdev -> rport,x1,y1);
  3934.         }
  3935.     }
  3936.  
  3937.     return(0);
  3938. }
  3939.  
  3940.     /* amiga_copy_mono_raw():
  3941.      *
  3942.      *    Copy a monochrome image to a bitmap. Just watch the
  3943.      *    astounding number of case switches.
  3944.      */
  3945.  
  3946. int
  3947. amiga_copy_mono_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3948. {
  3949.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3950.         return(-1);
  3951.     else
  3952.     {
  3953.         if(w > 0 && h > 0)
  3954.         {
  3955.             LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3956.             UBYTE *line;
  3957.  
  3958.             w += sourcex;
  3959.  
  3960.             line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  3961.  
  3962.             if(zero == gx_no_color_index)
  3963.             {
  3964.                 if(one != gx_no_color_index)
  3965.                 {
  3966.                     if(one)
  3967.                     {
  3968.                         do
  3969.                         {
  3970.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3971.                             {
  3972.                                 if(base[i >> 3] & shift[i & 7])
  3973.                                     line[j >> 3] |= shift[j & 7];
  3974.                             }
  3975.  
  3976.                             base += raster;
  3977.  
  3978.                             line += modulo;
  3979.                         }
  3980.                         while(--h);
  3981.                     }
  3982.                     else
  3983.                     {
  3984.                         do
  3985.                         {
  3986.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3987.                             {
  3988.                                 if(base[i >> 3] & shift[i & 7])
  3989.                                     line[j >> 3] &= masks[j & 7];
  3990.                             }
  3991.  
  3992.                             base += raster;
  3993.  
  3994.                             line += modulo;
  3995.                         }
  3996.                         while(--h);
  3997.                     }
  3998.                 }
  3999.             }
  4000.             else
  4001.             {
  4002.                 if(one == gx_no_color_index)
  4003.                 {
  4004.                     if(zero)
  4005.                     {
  4006.                         do
  4007.                         {
  4008.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  4009.                             {
  4010.                                 if(!(base[i >> 3] & shift[i & 7]))
  4011.                                     line[j >> 3] |= shift[j & 7];
  4012.                             }
  4013.  
  4014.                             base += raster;
  4015.  
  4016.                             line += modulo;
  4017.                         }
  4018.                         while(--h);
  4019.                     }
  4020.                     else
  4021.                     {
  4022.                         do
  4023.                         {
  4024.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  4025.                             {
  4026.                                 if(!(base[i >> 3] & shift[i & 7]))
  4027.                                     line[j >> 3] &= masks[j & 7];
  4028.                             }
  4029.  
  4030.                             base += raster;
  4031.  
  4032.                             line += modulo;
  4033.                         }
  4034.                         while(--h);
  4035.                     }
  4036.                 }
  4037.                 else
  4038.                 {
  4039.                     if(one)
  4040.                     {
  4041.                         do
  4042.                         {
  4043.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  4044.                             {
  4045.                                 if(base[i >> 3] & shift[i & 7])
  4046.                                     line[j >> 3] |= shift[j & 7];
  4047.                                 else
  4048.                                     line[j >> 3] &= masks[j & 7];
  4049.                             }
  4050.  
  4051.                             base += raster;
  4052.  
  4053.                             line += modulo;
  4054.                         }
  4055.                         while(--h);
  4056.                     }
  4057.                     else
  4058.                     {
  4059.                         do
  4060.                         {
  4061.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  4062.                             {
  4063.                                 if(base[i >> 3] & shift[i & 7])
  4064.                                     line[j >> 3] &= masks[j & 7];
  4065.                                 else
  4066.                                     line[j >> 3] |= shift[j & 7];
  4067.                             }
  4068.  
  4069.                             base += raster;
  4070.  
  4071.                             line += modulo;
  4072.                         }
  4073.                         while(--h);
  4074.                     }
  4075.                 }
  4076.             }
  4077.         }
  4078.  
  4079.         return(0);
  4080.     }
  4081. }
  4082.  
  4083.     /* amiga_copy_color_raw():
  4084.      *
  4085.      *    Copy a color image (oh well...). This is just the same as the
  4086.      *    copy_mono() routine.
  4087.      */
  4088.  
  4089. int
  4090. amiga_copy_color_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4091. {
  4092.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4093.         return(-1);
  4094.     else
  4095.     {
  4096.         if(w > 0 && h > 0)
  4097.         {
  4098.             LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  4099.             UBYTE *line;
  4100.  
  4101.             line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  4102.  
  4103.             w += sourcex;
  4104.  
  4105.             do
  4106.             {
  4107.                 for(i = sourcex, j = x ; i < w ; i++, j++)
  4108.                 {
  4109.                     if(base[i >> 3] & shift[i & 7])
  4110.                         line[j >> 3] |= shift[j & 7];
  4111.                     else
  4112.                         line[j >> 3] &= masks[j & 7];
  4113.                 }
  4114.  
  4115.                 base += raster;
  4116.  
  4117.                 line += modulo;
  4118.             }
  4119.             while(--h);
  4120.         }
  4121.  
  4122.         return(0);
  4123.     }
  4124. }
  4125.  
  4126.     /* amiga_fill_rectangle_raw():
  4127.      *
  4128.      *    Fill a rectangular area in a bitmap.
  4129.      */
  4130.  
  4131. int
  4132. amiga_fill_rectangle_raw(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  4133. {
  4134.     if(x < 0 || x > xdev -> width - w || y < 0 || y > xdev -> height - h)
  4135.         return(-1);
  4136.     else
  4137.     {
  4138.         if(w > 0 && h > 0 && color != gx_no_color_index)
  4139.         {
  4140.             UBYTE *line,startmask,endmask;
  4141.             LONG right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  4142.  
  4143.             right    = x + w;
  4144.             mid    = (right >> 3) - (x >> 3);
  4145.             line    = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow + (x >> 3);
  4146.  
  4147.             x    &= 7;
  4148.             right    &= 7;
  4149.  
  4150.             if(color)
  4151.             {
  4152.                 startmask    = 0xFF >> x;
  4153.                 endmask        = ~(0xFF >> right);
  4154.  
  4155.                 if(mid)
  4156.                 {
  4157.                     UBYTE *ptr;
  4158.                     int i;
  4159.  
  4160.                     do
  4161.                     {
  4162.                         ptr = line;
  4163.  
  4164.                         *ptr++ |= startmask;
  4165.  
  4166.                         i = mid;
  4167.  
  4168.                         while(--i > 0)
  4169.                             *ptr++ = 0xFF;
  4170.  
  4171.                         *ptr |= endmask;
  4172.  
  4173.                         line += modulo;
  4174.                     }
  4175.                     while(--h);
  4176.                 }
  4177.                 else
  4178.                 {
  4179.                     startmask &= endmask;
  4180.  
  4181.                     do
  4182.                     {
  4183.                         *line |= startmask;
  4184.  
  4185.                         line += modulo;
  4186.                     }
  4187.                     while(--h);
  4188.                 }
  4189.             }
  4190.             else
  4191.             {
  4192.                 startmask    = ~(0xFF >> x);
  4193.                 endmask        = 0xFF >> right;
  4194.  
  4195.                 if(mid)
  4196.                 {
  4197.                     UBYTE *ptr;
  4198.                     LONG i;
  4199.  
  4200.                     do
  4201.                     {
  4202.                         ptr = line;
  4203.  
  4204.                         *ptr++ &= startmask;
  4205.  
  4206.                         i = mid;
  4207.  
  4208.                         while(--i > 0)
  4209.                             *ptr++ = 0x00;
  4210.  
  4211.                         *ptr &= endmask;
  4212.  
  4213.                         line += modulo;
  4214.                     }
  4215.                     while(--h);
  4216.                 }
  4217.                 else
  4218.                 {
  4219.                     startmask |= endmask;
  4220.  
  4221.                     do
  4222.                     {
  4223.                         *line &= startmask;
  4224.  
  4225.                         line += modulo;
  4226.                     }
  4227.                     while(--h);
  4228.                 }
  4229.             }
  4230.         }
  4231.  
  4232.         return(0);
  4233.     }
  4234. }
  4235.  
  4236.     /* amiga_draw_line_raw():
  4237.      *
  4238.      *    Draw a hair line, your basic DDA algorithm;
  4239.      *    keep your fingers crossed.
  4240.      */
  4241.  
  4242. int
  4243. amiga_draw_line_raw(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  4244. {
  4245.     if(color != gx_no_color_index && (x != x1 || y != y1))
  4246.     {
  4247.         short xstep,ystep,dx,dy,diff,modulo;
  4248.         UBYTE *line,*plane,pen;
  4249.         LONG last;
  4250.  
  4251.         modulo    = xdev -> rport -> BitMap -> BytesPerRow;
  4252.         plane    = xdev -> rport -> BitMap -> Planes[0];
  4253.  
  4254.         line    = &plane[y1 * modulo];
  4255.         last    = y1;
  4256.         pen    = line[x1 >> 3] & (x1 & 7);
  4257.  
  4258.         dx = x1 - x;
  4259.         dy = y1 - y;
  4260.  
  4261.         if(dx < 0)
  4262.         {
  4263.             dx = -dx;
  4264.             dy = -dy;
  4265.  
  4266.             x = x1;
  4267.             y = y1;
  4268.         }
  4269.  
  4270.         if(y != last)
  4271.             line = &plane[(last = y) * modulo];
  4272.  
  4273.         if(color)
  4274.         {
  4275.             line[x >> 3] |= shift[x & 7];
  4276.  
  4277.             xstep = ystep = 0;
  4278.  
  4279.             if(dy < 0)
  4280.             {
  4281.                 if(dx > -dy)
  4282.                 {
  4283.                     diff = -dx / 2;
  4284.  
  4285.                     do
  4286.                     {
  4287.                         xstep++;
  4288.  
  4289.                         if(diff > 0)
  4290.                         {
  4291.                             ystep--;
  4292.  
  4293.                             diff = diff - dy - dx;
  4294.                         }
  4295.                         else
  4296.                             diff -= dy;
  4297.  
  4298.                         {
  4299.                             LONG x1 = x + xstep,y1 = y + ystep;
  4300.  
  4301.                             if(y1 != last)
  4302.                                 line = &plane[(last = y1) * modulo];
  4303.  
  4304.                             line[x1 >> 3] |= shift[x1 & 7];
  4305.                         }
  4306.                     }
  4307.                     while(xstep < dx);
  4308.                 }
  4309.                 else
  4310.                 {
  4311.                     if(dx == -dy)
  4312.                         diff = 0;
  4313.                     else
  4314.                         diff = -dy / 2;
  4315.  
  4316.                     do
  4317.                     {
  4318.                         ystep--;
  4319.  
  4320.                         if(diff > 0)
  4321.                             diff -= dx;
  4322.                         else
  4323.                         {
  4324.                             xstep++;
  4325.  
  4326.                             diff = diff - dy - dx;
  4327.                         }
  4328.  
  4329.                         {
  4330.                             LONG x1 = x + xstep,y1 = y + ystep;
  4331.  
  4332.                             if(y1 != last)
  4333.                                 line = &plane[(last = y1) * modulo];
  4334.  
  4335.                             line[x1 >> 3] |= shift[x1 & 7];
  4336.                         }
  4337.                     }
  4338.                     while(ystep > dy);
  4339.                 }
  4340.             }
  4341.             else
  4342.             {
  4343.                 if(dx > dy)
  4344.                 {
  4345.                     diff = -dx / 2;
  4346.  
  4347.                     do
  4348.                     {
  4349.                         xstep++;
  4350.  
  4351.                         if(diff > 0)
  4352.                         {
  4353.                             ystep++;
  4354.  
  4355.                             diff = diff + dy - dx;
  4356.                         }
  4357.                         else
  4358.                             diff += dy;
  4359.  
  4360.                         {
  4361.                             LONG x1 = x + xstep,y1 = y + ystep;
  4362.  
  4363.                             if(y1 != last)
  4364.                                 line = &plane[(last = y1) * modulo];
  4365.  
  4366.                             line[x1 >> 3] |= shift[x1 & 7];
  4367.                         }
  4368.                     }
  4369.                     while(xstep < dx);
  4370.                 }
  4371.                 else
  4372.                 {
  4373.                     if(dx == dy)
  4374.                         diff = 0;
  4375.                     else
  4376.                         diff = dy / 2;
  4377.  
  4378.                     do
  4379.                     {
  4380.                         ystep++;
  4381.  
  4382.                         if(diff > 0)
  4383.                             diff -= dx;
  4384.                         else
  4385.                         {
  4386.                             xstep++;
  4387.  
  4388.                             diff = diff + dy - dx;
  4389.                         }
  4390.  
  4391.                         {
  4392.                             LONG x1 = x + xstep,y1 = y + ystep;
  4393.  
  4394.                             if(y1 != last)
  4395.                                 line = &plane[(last = y1) * modulo];
  4396.  
  4397.                             line[x1 >> 3] |= shift[x1 & 7];
  4398.                         }
  4399.                     }
  4400.                     while(ystep < dy);
  4401.                 }
  4402.             }
  4403.  
  4404.             if(!pen)
  4405.             {
  4406.                 if(y1 != last)
  4407.                     line = &plane[(last = y1) * modulo];
  4408.  
  4409.                 line[x1 >> 3] &= masks[x1 & 7];
  4410.             }
  4411.         }
  4412.         else
  4413.         {
  4414.             line[x >> 3] &= masks[x & 7];
  4415.  
  4416.             xstep = ystep = 0;
  4417.  
  4418.             if(dy < 0)
  4419.             {
  4420.                 if(dx > -dy)
  4421.                 {
  4422.                     diff = -dx / 2;
  4423.  
  4424.                     do
  4425.                     {
  4426.                         xstep++;
  4427.  
  4428.                         if(diff > 0)
  4429.                         {
  4430.                             ystep--;
  4431.  
  4432.                             diff = diff - dy - dx;
  4433.                         }
  4434.                         else
  4435.                             diff -= dy;
  4436.  
  4437.                         {
  4438.                             LONG x1 = x + xstep,y1 = y + ystep;
  4439.  
  4440.                             if(y1 != last)
  4441.                                 line = &plane[(last = y1) * modulo];
  4442.  
  4443.                             line[x1 >> 3] &= masks[x1 & 7];
  4444.                         }
  4445.                     }
  4446.                     while(xstep < dx);
  4447.                 }
  4448.                 else
  4449.                 {
  4450.                     if(dx == -dy)
  4451.                         diff = 0;
  4452.                     else
  4453.                         diff = -dy / 2;
  4454.  
  4455.                     do
  4456.                     {
  4457.                         ystep--;
  4458.  
  4459.                         if(diff > 0)
  4460.                             diff -= dx;
  4461.                         else
  4462.                         {
  4463.                             xstep++;
  4464.  
  4465.                             diff = diff - dy - dx;
  4466.                         }
  4467.  
  4468.                         {
  4469.                             LONG x1 = x + xstep,y1 = y + ystep;
  4470.  
  4471.                             if(y1 != last)
  4472.                                 line = &plane[(last = y1) * modulo];
  4473.  
  4474.                             line[x1 >> 3] &= masks[x1 & 7];
  4475.                         }
  4476.                     }
  4477.                     while(ystep > dy);
  4478.                 }
  4479.             }
  4480.             else
  4481.             {
  4482.                 if(dx > dy)
  4483.                 {
  4484.                     diff = -dx / 2;
  4485.  
  4486.                     do
  4487.                     {
  4488.                         xstep++;
  4489.  
  4490.                         if(diff > 0)
  4491.                         {
  4492.                             ystep++;
  4493.  
  4494.                             diff = diff + dy - dx;
  4495.                         }
  4496.                         else
  4497.                             diff += dy;
  4498.  
  4499.                         {
  4500.                             LONG x1 = x + xstep,y1 = y + ystep;
  4501.  
  4502.                             if(y1 != last)
  4503.                                 line = &plane[(last = y1) * modulo];
  4504.  
  4505.                             line[x1 >> 3] &= masks[x1 & 7];
  4506.                         }
  4507.                     }
  4508.                     while(xstep < dx);
  4509.                 }
  4510.                 else
  4511.                 {
  4512.                     if(dx == dy)
  4513.                         diff = 0;
  4514.                     else
  4515.                         diff =  dy / 2;
  4516.  
  4517.                     do
  4518.                     {
  4519.                         ystep++;
  4520.  
  4521.                         if(diff > 0)
  4522.                             diff -= dx;
  4523.                         else
  4524.                         {
  4525.                             xstep++;
  4526.  
  4527.                             diff = diff + dy - dx;
  4528.                         }
  4529.  
  4530.                         {
  4531.                             LONG x1 = x + xstep,y1 = y + ystep;
  4532.  
  4533.                             if(y1 != last)
  4534.                                 line = &plane[(last = y1) * modulo];
  4535.  
  4536.                             line[x1 >> 3] &= masks[x1 & 7];
  4537.                         }
  4538.                     }
  4539.                     while(ystep < dy);
  4540.                 }
  4541.             }
  4542.  
  4543.             if(pen)
  4544.             {
  4545.                 if(y1 != last)
  4546.                     line = &plane[(last = y1) * modulo];
  4547.  
  4548.                 line[x1 >> 3] |= pen;
  4549.             }
  4550.         }
  4551.     }
  4552.  
  4553.     return(0);
  4554. }
  4555.  
  4556.     /* amiga_open_ilbm(gx_device *dev):
  4557.      *
  4558.      *    Open the ilbm device.
  4559.      */
  4560.  
  4561. int
  4562. amiga_open_ilbm(gx_device *dev)
  4563. {
  4564.     if(xdev -> width <= 0 || xdev -> height <= 0)
  4565.     {
  4566.         if(xdev -> page_width > 0.0)
  4567.             xdev -> width = (int)(xdev -> x_pixels_per_inch * xdev -> page_width);
  4568.         else
  4569.             xdev -> width = 640;
  4570.  
  4571.         if(xdev -> page_height > 0.0)
  4572.             xdev -> height = (int)(xdev -> y_pixels_per_inch * xdev -> page_height);
  4573.         else
  4574.             xdev -> height = 512;
  4575.     }
  4576.  
  4577.     if(xdev -> rport = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
  4578.     {
  4579.         InitRastPort(xdev -> rport);
  4580.  
  4581.         if(xdev -> bitmap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY))
  4582.         {
  4583.             InitBitMap(xdev -> bitmap,1,xdev -> width,xdev -> height);
  4584.  
  4585.             if(xdev -> bitplane = AllocVec(xdev -> bitmap -> Rows * xdev -> bitmap -> BytesPerRow,MEMF_ANY | MEMF_CLEAR))
  4586.             {
  4587.                 xdev -> bitmap -> Planes[0]    = xdev -> bitplane;
  4588.                 xdev -> rport -> BitMap        = xdev -> bitmap;
  4589.                 xdev -> page_count        = 1;
  4590.  
  4591.                 DarkPen        = 0;
  4592.                 LightPen    = 1;
  4593.  
  4594.                 return(0);
  4595.             }
  4596.             else
  4597.             {
  4598.                 char buffer[256];
  4599.  
  4600.                 sprintf(buffer,"Ghostscript: failed to allocate raster (wanted %ld, largest %ld)",xdev -> bitmap -> Rows * xdev -> bitmap -> BytesPerRow,AvailMem(MEMF_ANY | MEMF_LARGEST));
  4601.  
  4602.                 perror(buffer);
  4603.             }
  4604.         }
  4605.         else
  4606.             perror("Ghostscript: failed to allocate bitmap");
  4607.     }
  4608.     else
  4609.         perror("Ghostscript: failed to allocate raster port");
  4610.  
  4611.     return(-1);
  4612. }
  4613.  
  4614.     /* amiga_output_page_ilbm(gx_device *dev,int,int):
  4615.      *
  4616.      *    Send a bitmap to an IFF-ILBM file.
  4617.      */
  4618.  
  4619. int
  4620. amiga_output_page_ilbm(gx_device *dev,int num_copies,int flush)
  4621. {
  4622.     const sigset_t trapped = sigmask(SIGINT);
  4623.     char buffer[270];
  4624.     LONG result = -1;
  4625.  
  4626.     sprintf(buffer,"%s_%04d.ilbm",xdev -> file_name,xdev -> page_count);
  4627.  
  4628.     fprintf(stdout,"\n\033[ASaving page Nº%d to \"%s\"...\033[K",xdev -> page_count,buffer);
  4629.     fflush(stdout);
  4630.  
  4631.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  4632.  
  4633.     if(SaveBitMap(buffer,xdev -> bitmap,xdev -> width,xdev -> height,(UWORD)xdev -> x_pixels_per_inch,xdev -> y_pixels_per_inch))
  4634.     {
  4635.         fprintf(stdout,"\n\033[APage saved to file \"%s\".\033[K\n",buffer);
  4636.  
  4637.         result = 0;
  4638.  
  4639.         xdev -> page_count;
  4640.     }
  4641.     else
  4642.         perror("\n\033[AGhostscript: error saving page\033[K");
  4643.  
  4644.     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  4645.  
  4646.     return(result);
  4647. }
  4648.  
  4649.     /* amiga_close_ilbm(gx_device *dev):
  4650.      *
  4651.      *    Close the ilbm driver.
  4652.      */
  4653.  
  4654. int
  4655. amiga_close_ilbm(gx_device *dev)
  4656. {
  4657.     if(xdev -> bitplane)
  4658.     {
  4659.         FreeVec(xdev -> bitplane);
  4660.  
  4661.         xdev -> bitplane = NULL;
  4662.     }
  4663.  
  4664.     if(xdev -> bitmap)
  4665.     {
  4666.         FreeVec(xdev -> bitmap);
  4667.  
  4668.         xdev -> bitmap = NULL;
  4669.     }
  4670.  
  4671.     if(xdev -> rport)
  4672.     {
  4673.         FreeVec(xdev -> rport);
  4674.  
  4675.         xdev -> rport = NULL;
  4676.     }
  4677.  
  4678.     xdev -> width = xdev -> height = 0;
  4679. /*    xdev -> x_pixels_per_inch = x_pixels_per_inch = 72.72;*/
  4680.  
  4681.     return(0);
  4682. }
  4683.  
  4684. private const gs_prop_item props_amiga[] =
  4685. {
  4686.     prop_def("PageWidth",    prt_string),
  4687.     prop_def("PageHeight",    prt_string),
  4688.     prop_def("OutputFile",    prt_string)
  4689. };
  4690.  
  4691. int
  4692. amiga_get_props(gx_device *dev,gs_prop_item *plist)
  4693. {
  4694.     int start = gx_default_get_props(dev,plist);
  4695.  
  4696.     if(plist != 0)
  4697.     {
  4698.         gs_prop_item *pi = plist + start;
  4699.  
  4700.         memcpy(pi,props_amiga,sizeof(props_amiga));
  4701.  
  4702.         pi[0] . value .a.p.s    = "";
  4703.         pi[0] . value .a.size    = -1;
  4704.  
  4705.         pi[1] . value .a.p.s    = "";
  4706.         pi[1] . value .a.size    = -1;
  4707.  
  4708.         pi[2] . value .a.p.s    = "";
  4709.         pi[2] . value .a.size    = -1;
  4710.     }
  4711.  
  4712.     return(start + (sizeof(props_amiga) / sizeof(gs_prop_item)));
  4713. }
  4714.  
  4715. int
  4716. amiga_put_props(gx_device *dev,gs_prop_item *plist,int count)
  4717. {
  4718.     gs_prop_item *known[3];
  4719.     LONG code = 0;
  4720.  
  4721.     props_extract(plist,count,props_amiga,3,known,0);
  4722.  
  4723.     if((code = gx_default_put_props(dev,plist,count)) < 0)
  4724.         return(code);
  4725.     else
  4726.     {
  4727.         if(known[0] != 0)
  4728.         {
  4729.             gs_prop_item *pn = known[0];
  4730.             LONG size = pn -> value . a . size;
  4731.             char temp[256];
  4732.  
  4733.             if(size >= 256)
  4734.             {
  4735.                 pn -> status = pv_limitcheck;
  4736.  
  4737.                 code = gs_error_limitcheck;
  4738.             }
  4739.             else
  4740.             {
  4741.                 memcpy(temp,pn -> value . a . p . s,size);
  4742.  
  4743.                 temp[size] = 0;
  4744.  
  4745.                 xdev -> page_width = GetInches(temp);
  4746.  
  4747.                 if(xdev -> page_width <= 0.0)
  4748.                 {
  4749.                     xdev -> page_width = 0.0;
  4750.  
  4751.                     pn -> status = pv_limitcheck;
  4752.  
  4753.                     code = gs_error_limitcheck;
  4754.                 }
  4755.                 else
  4756.                 {
  4757.                     if(code == 0)
  4758.                         code = 1;
  4759.                 }
  4760.             }
  4761.         }
  4762.  
  4763.         if(known[1] != 0)
  4764.         {
  4765.             gs_prop_item *pn = known[1];
  4766.             LONG size = pn -> value . a . size;
  4767.             char temp[256];
  4768.  
  4769.             if(size >= 256)
  4770.             {
  4771.                 pn -> status = pv_limitcheck;
  4772.  
  4773.                 code = gs_error_limitcheck;
  4774.             }
  4775.             else
  4776.             {
  4777.                 memcpy(temp,pn -> value . a . p . s,size);
  4778.  
  4779.                 temp[size] = 0;
  4780.  
  4781.                 xdev -> page_height = GetInches(temp);
  4782.  
  4783.                 if(xdev -> page_height <= 0.0)
  4784.                 {
  4785.                     xdev -> page_height = 0.0;
  4786.  
  4787.                     pn -> status = pv_limitcheck;
  4788.  
  4789.                     code = gs_error_limitcheck;
  4790.                 }
  4791.                 else
  4792.                 {
  4793.                     if(code == 0)
  4794.                         code = 1;
  4795.                 }
  4796.             }
  4797.         }
  4798.  
  4799.         if(known[2] != 0)
  4800.         {
  4801.             gs_prop_item *pn = known[2];
  4802.             LONG size = pn -> value . a . size;
  4803.  
  4804.             if(size >= 256)
  4805.             {
  4806.                 pn -> status = pv_limitcheck;
  4807.  
  4808.                 code = gs_error_limitcheck;
  4809.             }
  4810.             else
  4811.             {
  4812.                 memcpy(xdev -> file_name,pn -> value . a . p . s,size);
  4813.  
  4814.                 xdev -> file_name[size] = 0;
  4815.             }
  4816.         }
  4817.  
  4818.         if(code < 0)
  4819.             return_error(code);
  4820.  
  4821.         if(xdev -> is_open && code)
  4822.         {
  4823.             LONG ccode = gs_closedevice(dev);
  4824.  
  4825.             if(ccode < 0)
  4826.                 return(ccode);
  4827.         }
  4828.  
  4829.         return(code);
  4830.     }
  4831. }
  4832.  
  4833.     /* amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4834.      *
  4835.      *    Turn an RGB colour into a pen index.
  4836.      */
  4837.  
  4838. gx_color_index
  4839. amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4840. {
  4841.     LONG max = xdev -> cube_size - 1,r,g,b;
  4842.  
  4843.     r = (max * red)   / gx_max_color_value;
  4844.     g = (max * green) / gx_max_color_value;
  4845.     b = (max * blue)  / gx_max_color_value;
  4846.  
  4847.     return((r * xdev -> cube_size + g) * xdev -> cube_size + b);
  4848. }
  4849.  
  4850.     /* amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4851.      *
  4852.      *    Turn a pen index into RGB colour values.
  4853.      */
  4854.  
  4855. int
  4856. amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4857. {
  4858.     LONG i,value,max = xdev -> cube_size - 1;
  4859.  
  4860.     for(i = 2 ; i >= 0 ; i--)
  4861.     {
  4862.         value = color % xdev -> cube_size;
  4863.  
  4864.         rgb[i] = (gx_max_color_value * value) / max;
  4865.  
  4866.         color /= xdev -> cube_size;
  4867.     }
  4868.  
  4869.     return(0);
  4870. }
  4871.  
  4872.     /* amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4873.      *
  4874.      *    Turn an RGB colour into a pen index; this routine takes remapped
  4875.      *    pens into account.
  4876.      */
  4877.  
  4878. gx_color_index
  4879. amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4880. {
  4881.     LONG max = xdev -> cube_size - 1,r,g,b;
  4882.  
  4883.     r = (max * red)   / gx_max_color_value;
  4884.     g = (max * green) / gx_max_color_value;
  4885.     b = (max * blue)  / gx_max_color_value;
  4886.  
  4887.     return(xdev -> pens[(r * xdev -> cube_size + g) * xdev -> cube_size + b]);
  4888. }
  4889.  
  4890.     /* amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4891.      *
  4892.      *    Turn a pen index into RGB colour values; this routine takes remapped
  4893.      *    pens into account.
  4894.      */
  4895.  
  4896. int
  4897. amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4898. {
  4899.     LONG i,value,max = xdev -> cube_size - 1;
  4900.  
  4901.         /* Find the matching pen... */
  4902.  
  4903.     for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  4904.     {
  4905.         if(xdev -> pens[i] == color)
  4906.         {
  4907.             color = i;
  4908.  
  4909.             break;
  4910.         }
  4911.     }
  4912.  
  4913.     for(i = 2 ; i >= 0 ; i--)
  4914.     {
  4915.         value = color % xdev -> cube_size;
  4916.  
  4917.         rgb[i] = (gx_max_color_value * value) / max;
  4918.  
  4919.         color /= xdev -> cube_size;
  4920.     }
  4921.  
  4922.     return(0);
  4923. }
  4924.  
  4925.     /* amiga_copy_color8():
  4926.      *
  4927.      *    Copy a color image, the source is guaranteed to consist of
  4928.      *    one byte per colour.
  4929.      */
  4930.  
  4931. int
  4932. amiga_copy_color8(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4933. {
  4934.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4935.         return(-1);
  4936.     else
  4937.     {
  4938.         if(w > 0 && h > 0)
  4939.         {
  4940.             base += sourcex;
  4941.  
  4942.             if(w > xdev -> width)
  4943.                 w = xdev -> width;
  4944.  
  4945.             do
  4946.             {
  4947.                 
  4948.                 CopyMem((UBYTE *)base,xdev -> temp_array,w);
  4949.  
  4950.                 WritePixelLine8(xdev -> rport,x,y++,w,xdev -> temp_array,xdev -> temp_rport);
  4951.  
  4952.                 base += raster;
  4953.             }
  4954.             while(--h);
  4955.         }
  4956.  
  4957.         return(0);
  4958.     }
  4959. }
  4960.  
  4961.     /* amiga_copy_mono_raw_color():
  4962.      *
  4963.      *    Copy a monochrome image to a bitmap.
  4964.      */
  4965.  
  4966. int
  4967. amiga_copy_mono_raw_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  4968. {
  4969.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4970.         return(-1);
  4971.     else
  4972.     {
  4973.         if(w > 0 && h > 0 && zero != gx_no_color_index && one != gx_no_color_index)
  4974.         {
  4975.             PLANEPTR line[12];
  4976.             LONG i,j,k,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4977.  
  4978.             for(i = 0 ; i < depth ; i++)
  4979.                 line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  4980.  
  4981.             w += sourcex;
  4982.  
  4983.             if(zero == gx_no_color_index)
  4984.             {
  4985.                 do
  4986.                 {
  4987.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  4988.                     {
  4989.                         if(base[i >> 3] & shift[i & 7])
  4990.                         {
  4991.                             for(k = 0 ; k < depth ; k++)
  4992.                             {
  4993.                                 if(one & (1 << k))
  4994.                                     line[k][j >> 3] |= shift[j & 7];
  4995.                                 else
  4996.                                     line[k][j >> 3] &= masks[j & 7];
  4997.                             }
  4998.                         }
  4999.                     }
  5000.  
  5001.                     base += raster;
  5002.  
  5003.                     for(k = 0 ; k < depth ; k++)
  5004.                         line[k] += modulo;
  5005.                 }
  5006.                 while(--h);
  5007.             }
  5008.             else
  5009.             {
  5010.                 if(one == gx_no_color_index)
  5011.                 {
  5012.                     do
  5013.                     {
  5014.                         for(i = sourcex, j = x ; i < w ; i++, j++)
  5015.                         {
  5016.                             if(base[i >> 3] & shift[i & 7])
  5017.                             {
  5018.                                 for(k = 0 ; k < depth ; k++)
  5019.                                 {
  5020.                                     if(zero & (1 << k))
  5021.                                         line[k][j >> 3] |= shift[j & 7];
  5022.                                     else
  5023.                                         line[k][j >> 3] &= masks[j & 7];
  5024.                                 }
  5025.                             }
  5026.                         }
  5027.  
  5028.                         base += raster;
  5029.  
  5030.                         for(k = 0 ; k < depth ; k++)
  5031.                             line[k] += modulo;
  5032.                     }
  5033.                     while(--h);
  5034.                 }
  5035.                 else
  5036.                 {
  5037.                     do
  5038.                     {
  5039.                         for(i = sourcex, j = x ; i < w ; i++, j++)
  5040.                         {
  5041.                             if(base[i >> 3] & shift[i & 7])
  5042.                             {
  5043.                                 for(k = 0 ; k < depth ; k++)
  5044.                                 {
  5045.                                     if(one & (1 << k))
  5046.                                         line[k][j >> 3] |= shift[j & 7];
  5047.                                     else
  5048.                                         line[k][j >> 3] &= masks[j & 7];
  5049.                                 }
  5050.                             }
  5051.                             else
  5052.                             {
  5053.                                 for(k = 0 ; k < depth ; k++)
  5054.                                 {
  5055.                                     if(zero & (1 << k))
  5056.                                         line[k][j >> 3] |= shift[j & 7];
  5057.                                     else
  5058.                                         line[k][j >> 3] &= masks[j & 7];
  5059.                                 }
  5060.                             }
  5061.                         }
  5062.  
  5063.                         base += raster;
  5064.  
  5065.                         for(k = 0 ; k < depth ; k++)
  5066.                             line[k] += modulo;
  5067.                     }
  5068.                     while(--h);
  5069.                 }
  5070.             }
  5071.         }
  5072.  
  5073.         return(0);
  5074.     }
  5075. }
  5076.  
  5077.     /* amiga_copy_color_raw_color16():
  5078.      *
  5079.      *    Copy a color image, the source data is guaranteed to consist
  5080.      *    of one word per colour.
  5081.      */
  5082.  
  5083. int
  5084. amiga_copy_color_raw_color16(gx_device *dev,const UBYTE *data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  5085. {
  5086.     if(y < 0 || x < 0 || w < 0 || h < 0)
  5087.         return(-1);
  5088.     else
  5089.     {
  5090.         if(w > 0 && h > 0)
  5091.         {
  5092.             PLANEPTR line[12];
  5093.             LONG i,j,k,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  5094.             UWORD *base = (UWORD *)data;
  5095.  
  5096.             for(i = 0 ; i < depth ; i++)
  5097.                 line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  5098.  
  5099.             w += sourcex;
  5100.  
  5101.             raster /= 2;
  5102.  
  5103.             do
  5104.             {
  5105.                 for(i = sourcex, j = x ; i < w ; i++, j++)
  5106.                 {
  5107.                     for(k = 0 ; k < depth ; k++)
  5108.                     {
  5109.                         if(base[i] & (1 << k))
  5110.                             line[k][j >> 3] |= shift[j & 7];
  5111.                         else
  5112.                             line[k][j >> 3] &= masks[j & 7];
  5113.                     }
  5114.                 }
  5115.  
  5116.                 base += raster;
  5117.  
  5118.                 for(k = 0 ; k < depth ; k++)
  5119.                     line[k] += modulo;
  5120.             }
  5121.             while(--h);
  5122.         }
  5123.  
  5124.         return(0);
  5125.     }
  5126. }
  5127.  
  5128.     /* amiga_fill_rectangle_raw_color():
  5129.      *
  5130.      *    Fill a rectangular area in a bitmap.
  5131.      */
  5132.  
  5133. int
  5134. amiga_fill_rectangle_raw_color(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  5135. {
  5136.     if(x < 0 || x > xdev -> width - w || y < 0 || y > xdev -> height - h)
  5137.         return(-1);
  5138.     else
  5139.     {
  5140.         if(w > 0 && h > 0 && color != gx_no_color_index)
  5141.         {
  5142.             PLANEPTR line[12];
  5143.             LONG i,j,right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  5144.  
  5145.             for(i = 0 ; i < depth ; i++)
  5146.                 line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo + (x >> 3);
  5147.  
  5148.             right    = x + w;
  5149.             mid    = (right >> 3) - (x >> 3);
  5150.  
  5151.             x    &= 7;
  5152.             right    &= 7;
  5153.  
  5154.             if(mid)
  5155.             {
  5156.                 UBYTE *ptr;
  5157.  
  5158.                 do
  5159.                 {
  5160.                     for(j = 0 ; j < depth ; j++)
  5161.                     {
  5162.                         ptr = line[j];
  5163.  
  5164.                         i = mid;
  5165.  
  5166.                         if(color & (1 << j))
  5167.                         {
  5168.                             *ptr++ |= 0xFF >> x;
  5169.  
  5170.                             while(--i > 0)
  5171.                                 *ptr++ = 0xFF;
  5172.  
  5173.                             *ptr |= ~(0xFF >> right);
  5174.                         }
  5175.                         else
  5176.                         {
  5177.                             *ptr++ &= ~(0xFF >> x);
  5178.  
  5179.                             while(--i > 0)
  5180.                                 *ptr++ = 0x00;
  5181.  
  5182.                             *ptr &= 0xFF >> right;
  5183.                         }
  5184.  
  5185.                         line[j] += modulo;
  5186.                     }
  5187.                 }
  5188.                 while(--h);
  5189.             }
  5190.             else
  5191.             {
  5192.                 UBYTE    one_mask    = (0xFF >> x) & ~(0xFF >> right),
  5193.                     zero_mask    = ~(0xFF >> x) | (0xFF >> right);
  5194.                 do
  5195.                 {
  5196.                     for(j = 0 ; j < depth ; j++)
  5197.                     {
  5198.                         if(color & (1 << j))
  5199.                             *line[j] |= one_mask;
  5200.                         else
  5201.                             *line[j] &= zero_mask;
  5202.  
  5203.                         line[j] += modulo;
  5204.                     }
  5205.                 }
  5206.                 while(--h);
  5207.             }
  5208.         }
  5209.  
  5210.         return(0);
  5211.     }
  5212. }
  5213.  
  5214.     /* amiga_draw_line_raw_color():
  5215.      *
  5216.      *    Draw a hair line, your basic DDA algorithm;
  5217.      *    keep your fingers crossed.
  5218.      */
  5219.  
  5220. int
  5221. amiga_draw_line_raw_color(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  5222. {
  5223.     if(color != gx_no_color_index && (x != x1 || y != y1))
  5224.     {
  5225.         LONG xstep,ystep,dx,dy,diff,modulo;
  5226.         UBYTE *line,*plane,pen;
  5227.         LONG last,i,orig_x = x,orig_y = y;
  5228.  
  5229.         modulo = xdev -> rport -> BitMap -> BytesPerRow;
  5230.  
  5231.         for(i = 0 ; i < xdev -> rport -> BitMap -> Depth ; i++)
  5232.         {
  5233.             plane    = xdev -> rport -> BitMap -> Planes[i];
  5234.             line    = &plane[y1 * modulo];
  5235.             last    = y1;
  5236.             pen    = line[x1 >> 3] & (x1 & 7);
  5237.             x    = orig_x;
  5238.             y    = orig_y;
  5239.  
  5240.             dx = x1 - x;
  5241.             dy = y1 - y;
  5242.  
  5243.             if(dx < 0)
  5244.             {
  5245.                 dx = -dx;
  5246.                 dy = -dy;
  5247.  
  5248.                 x = x1;
  5249.                 y = y1;
  5250.             }
  5251.  
  5252.             if(y != last)
  5253.                 line = &plane[(last = y) * modulo];
  5254.  
  5255.             if(color & (1 << i))
  5256.             {
  5257.                 line[x >> 3] |= shift[x & 7];
  5258.  
  5259.                 xstep = ystep = 0;
  5260.  
  5261.                 if(dy < 0)
  5262.                 {
  5263.                     if(dx > -dy)
  5264.                     {
  5265.                         diff = -dx / 2;
  5266.  
  5267.                         do
  5268.                         {
  5269.                             xstep++;
  5270.  
  5271.                             if(diff > 0)
  5272.                             {
  5273.                                 ystep--;
  5274.  
  5275.                                 diff = diff - dy - dx;
  5276.                             }
  5277.                             else
  5278.                                 diff -= dy;
  5279.  
  5280.                             {
  5281.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5282.  
  5283.                                 if(y1 != last)
  5284.                                     line = &plane[(last = y1) * modulo];
  5285.  
  5286.                                 line[x1 >> 3] |= shift[x1 & 7];
  5287.                             }
  5288.                         }
  5289.                         while(xstep < dx);
  5290.                     }
  5291.                     else
  5292.                     {
  5293.                         if(dx == -dy)
  5294.                             diff = 0;
  5295.                         else
  5296.                             diff = -dy / 2;
  5297.  
  5298.                         do
  5299.                         {
  5300.                             ystep--;
  5301.  
  5302.                             if(diff > 0)
  5303.                                 diff -= dx;
  5304.                             else
  5305.                             {
  5306.                                 xstep++;
  5307.  
  5308.                                 diff = diff - dy - dx;
  5309.                             }
  5310.  
  5311.                             {
  5312.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5313.  
  5314.                                 if(y1 != last)
  5315.                                     line = &plane[(last = y1) * modulo];
  5316.  
  5317.                                 line[x1 >> 3] |= shift[x1 & 7];
  5318.                             }
  5319.                         }
  5320.                         while(ystep > dy);
  5321.                     }
  5322.                 }
  5323.                 else
  5324.                 {
  5325.                     if(dx > dy)
  5326.                     {
  5327.                         diff = -dx / 2;
  5328.  
  5329.                         do
  5330.                         {
  5331.                             xstep++;
  5332.  
  5333.                             if(diff > 0)
  5334.                             {
  5335.                                 ystep++;
  5336.  
  5337.                                 diff = diff + dy - dx;
  5338.                             }
  5339.                             else
  5340.                                 diff += dy;
  5341.  
  5342.                             {
  5343.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5344.  
  5345.                                 if(y1 != last)
  5346.                                     line = &plane[(last = y1) * modulo];
  5347.  
  5348.                                 line[x1 >> 3] |= shift[x1 & 7];
  5349.                             }
  5350.                         }
  5351.                         while(xstep < dx);
  5352.                     }
  5353.                     else
  5354.                     {
  5355.                         if(dx == dy)
  5356.                             diff = 0;
  5357.                         else
  5358.                             diff = dy / 2;
  5359.  
  5360.                         do
  5361.                         {
  5362.                             ystep++;
  5363.  
  5364.                             if(diff > 0)
  5365.                                 diff -= dx;
  5366.                             else
  5367.                             {
  5368.                                 xstep++;
  5369.  
  5370.                                 diff = diff + dy - dx;
  5371.                             }
  5372.  
  5373.                             {
  5374.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5375.  
  5376.                                 if(y1 != last)
  5377.                                     line = &plane[(last = y1) * modulo];
  5378.  
  5379.                                 line[x1 >> 3] |= shift[x1 & 7];
  5380.                             }
  5381.                         }
  5382.                         while(ystep < dy);
  5383.                     }
  5384.                 }
  5385.  
  5386.                 if(!pen)
  5387.                 {
  5388.                     if(y1 != last)
  5389.                         line = &plane[(last = y1) * modulo];
  5390.  
  5391.                     line[x1 >> 3] &= masks[x1 & 7];
  5392.                 }
  5393.             }
  5394.             else
  5395.             {
  5396.                 line[x >> 3] &= masks[x & 7];
  5397.  
  5398.                 xstep = ystep = 0;
  5399.  
  5400.                 if(dy < 0)
  5401.                 {
  5402.                     if(dx > -dy)
  5403.                     {
  5404.                         diff = -dx / 2;
  5405.  
  5406.                         do
  5407.                         {
  5408.                             xstep++;
  5409.  
  5410.                             if(diff > 0)
  5411.                             {
  5412.                                 ystep--;
  5413.  
  5414.                                 diff = diff - dy - dx;
  5415.                             }
  5416.                             else
  5417.                                 diff -= dy;
  5418.  
  5419.                             {
  5420.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5421.  
  5422.                                 if(y1 != last)
  5423.                                     line = &plane[(last = y1) * modulo];
  5424.  
  5425.                                 line[x1 >> 3] &= masks[x1 & 7];
  5426.                             }
  5427.                         }
  5428.                         while(xstep < dx);
  5429.                     }
  5430.                     else
  5431.                     {
  5432.                         if(dx == -dy)
  5433.                             diff = 0;
  5434.                         else
  5435.                             diff = -dy / 2;
  5436.  
  5437.                         do
  5438.                         {
  5439.                             ystep--;
  5440.  
  5441.                             if(diff > 0)
  5442.                                 diff -= dx;
  5443.                             else
  5444.                             {
  5445.                                 xstep++;
  5446.  
  5447.                                 diff = diff - dy - dx;
  5448.                             }
  5449.  
  5450.                             {
  5451.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5452.  
  5453.                                 if(y1 != last)
  5454.                                     line = &plane[(last = y1) * modulo];
  5455.  
  5456.                                 line[x1 >> 3] &= masks[x1 & 7];
  5457.                             }
  5458.                         }
  5459.                         while(ystep > dy);
  5460.                     }
  5461.                 }
  5462.                 else
  5463.                 {
  5464.                     if(dx > dy)
  5465.                     {
  5466.                         diff = -dx / 2;
  5467.  
  5468.                         do
  5469.                         {
  5470.                             xstep++;
  5471.  
  5472.                             if(diff > 0)
  5473.                             {
  5474.                                 ystep++;
  5475.  
  5476.                                 diff = diff + dy - dx;
  5477.                             }
  5478.                             else
  5479.                                 diff += dy;
  5480.  
  5481.                             {
  5482.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5483.  
  5484.                                 if(y1 != last)
  5485.                                     line = &plane[(last = y1) * modulo];
  5486.  
  5487.                                 line[x1 >> 3] &= masks[x1 & 7];
  5488.                             }
  5489.                         }
  5490.                         while(xstep < dx);
  5491.                     }
  5492.                     else
  5493.                     {
  5494.                         if(dx == dy)
  5495.                             diff = 0;
  5496.                         else
  5497.                             diff =  dy / 2;
  5498.  
  5499.                         do
  5500.                         {
  5501.                             ystep++;
  5502.  
  5503.                             if(diff > 0)
  5504.                                 diff -= dx;
  5505.                             else
  5506.                             {
  5507.                                 xstep++;
  5508.  
  5509.                                 diff = diff + dy - dx;
  5510.                             }
  5511.  
  5512.                             {
  5513.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5514.  
  5515.                                 if(y1 != last)
  5516.                                     line = &plane[(last = y1) * modulo];
  5517.  
  5518.                                 line[x1 >> 3] &= masks[x1 & 7];
  5519.                             }
  5520.                         }
  5521.                         while(ystep < dy);
  5522.                     }
  5523.                 }
  5524.  
  5525.                 if(pen)
  5526.                 {
  5527.                     if(y1 != last)
  5528.                         line = &plane[(last = y1) * modulo];
  5529.  
  5530.                     line[x1 >> 3] |= pen;
  5531.                 }
  5532.             }
  5533.         }
  5534.     }
  5535.  
  5536.     return(0);
  5537. }
  5538.