/* Copyright (C) 1991 Aladdin Enterprises. All rights reserved. Distributed by Free Software Foundation, Inc. This file is part of Ghostscript. Ghostscript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the Ghostscript General Public License for full details. Everyone is granted permission to copy, modify and redistribute Ghostscript, but only under the conditions described in the Ghostscript General Public License. A copy of this license is supposed to have been given to you along with Ghostscript so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ /* gdevvdi.c */ /* Bitmapped screen device for the Atari ST. This driver contains * portions of code originally written by Hauke Hess. It uses the * vdi for all screen operations. It recognizes and supports 1, 2, * 4, 8, 16, and 24 bit color. Tim Gallivan 5/94. */ /* For monochrome, Ghostscript produces a bitmap in memory which * is referenced directly by 'base'. For color images, GS produces * a bitmap at 'base' with each pixel represented by several * consecutive bits (packed or chunky pixel format). The routine * 'pack_to_plane()' copies the GS "packed" image format into the * appropriate number of color planes, referenced by 'cbase'. The * image in 'cbase' is then copied back to 'base' with the vdi routine * 'vr_trnfm()', and is then copied to the screen. This is rather * convoluted, but is needed for portability. */ #include "gdevvdi.h" /* External Variables */ extern VWRK VWork; /* from gp_atar1.c */ extern PSTATE State; /* from gp_atar1.c */ extern OBJECT menuobj[]; /* from gp_atar1.h */ extern WINDOW imagwin; /* from gp_atar3.c */ extern WINLIST *WList, *WinListAdd(), *WinListDelete(); /* General screen driver variables. */ byte *cbase=0; /* pointer to the color buffer */ byte **lineptr; /* pointer for each scan line in bitmap */ ushort *plane[16]; /* addresses of each color plane */ ushort *tbase; /* copy of base accessed by assembly routines */ uint csize; /* size of the color buffer referenced by cbase */ ulong mem_space; /* amount of memory taken by the bitmap */ int words; int ByteWidth, WordWidth, Raster, CopyWidth, CopyHeight; MFDB plane_image; GRAPHIC Graphic = { 0, /* PlotX */ 0, /* PlotY */ 0, /* XRes */ 0, /* YRes */ 0, /* Width */ 0, /* Height */ 0, /* StepX */ 0, /* StepY */ {0, 0, 0, 0, 0, 0}, /* image */ {0, 0, 0, 0, 0, 0} /* screen */ }; private dev_proc_open_device(stvdi_open); private dev_proc_close_device(stvdi_close); private dev_proc_output_page(stvdi_output_page); private dev_proc_print_page(stvdi_print_page); private dev_proc_map_rgb_color(stvdi_map_rgb_color); private dev_proc_map_color_rgb(stvdi_map_color_rgb); private gx_device_procs stvdi_procs = prn_color_procs(stvdi_open, stvdi_output_page, stvdi_close, stvdi_map_rgb_color, stvdi_map_color_rgb); gx_device_printer gs_stvdi_device = prn_device(stvdi_procs, "stvdi", WIDTH_10THS, HEIGHT_10THS, X_DPI, Y_DPI, 0,0,0,0, /* margins */ 1, stvdi_print_page); /* default to monochrome */ /* Open the stvdi device--get the resolution, allocate memory, etc. */ int stvdi_open(gx_device *pdev) { byte *base=0; char *left = 0; const gx_device_memory *mdev; /* gx_device_procs *pprocs = pdev->procs; */ static short AspectAdjusted=0; int ret; if (State.Gdebug) eprintf("stvdi_open ..."); /* Adjust the image for the hardware's aspect ratio, but * only once. If the device is initialized a second time, * the aspect ratio will already be taken into account. */ if (!AspectAdjusted) { pdev->y_pixels_per_inch = nint(VWork.AspectRatio * pdev->y_pixels_per_inch); pdev->height = nint(VWork.AspectRatio * pdev->height); AspectAdjusted = 1; } /* Get an appropriate memory device. */ if ((mdev = gdev_mem_device_for_bits(VWork.ColorBits)) == 0) return_error(gs_error_rangecheck); Graphic.XRes = pmemdev->x_pixels_per_inch; /* x dpi */ Graphic.YRes = pmemdev->y_pixels_per_inch; /* y dpi */ Graphic.Width = pmemdev->width; /* width in pixels */ Graphic.Height = pmemdev->height; /* height in pixels */ ByteWidth = (Graphic.Width + 7) >> 3; /* pixel width / 8 */ WordWidth = (ByteWidth + 1) >> 1; /* pixel width / 16 */ /* Ensure that the width is a multiple of 16 pixels. */ pmemdev->width = Graphic.Width = 16 * WordWidth; if (VWork.ColorBits > 1) { int MaxGray = (int)(pow(2, VWork.ColorBits) - .5); /* Fill the color_info structure. */ ppdev->color_info.num_components = 3; ppdev->color_info.depth = mdev->color_info.depth; ppdev->color_info.max_gray = MaxGray; ppdev->color_info.max_rgb = VWork.MaxRGB; ppdev->color_info.dither_gray = DITH_GRAY(VWork.ColorBits); ppdev->color_info.dither_rgb = DITH_RGB(VWork.ColorBits); if (State.Gdebug) { eprintf1("Depth = %ld\n", ppdev->color_info.depth); eprintf1("Max Gray = %ld\n", ppdev->color_info.max_gray); eprintf1("Max RGB = %ld\n", ppdev->color_info.max_rgb); eprintf1("Dither Gray = %ld\n", ppdev->color_info.dither_gray); eprintf1("Dither RGB = %ld\n", ppdev->color_info.dither_rgb); } } /* Begin code included from gdevprn.c. */ memset(ppdev->skip, 0, sizeof(ppdev->skip)); ppdev->orig_procs = pdev->std_procs; ppdev->file = ppdev->ccfile = ppdev->cbfile = NULL; mem_space = gdev_mem_bitmap_size(pmemdev); /* Base points to a buffer that GS uses to construct the image. */ if ( mem_space >= ppdev->max_bitmap || mem_space != (uint)mem_space || /* too big to allocate */ (base = (byte *)gs_malloc((uint)mem_space, 1, "printer buffer(open)")) == 0 || /* can't allocate */ (PRN_MIN_MEMORY_LEFT != 0 && (left = gs_malloc(PRN_MIN_MEMORY_LEFT, 1, "printer memory left")) == 0) /* not enough left */ ) { eprintf("stvdi_open: Malloc for printer buffer failed.\n"); return_error(gs_error_VMerror); } /* End code included from gdevprn.c. */ /* Cbase points to a buffer that holds the standard GEM * color plane image. */ if ((VWork.ColorBits > 1) && !State.Chunky8 && !VWork.TrueColor) { csize = (uint)(2 * WordWidth * Graphic.Height * VWork.ColorBits); if ((cbase = (byte *)gs_malloc(csize, 1, "color buffer")) == 0) { eprintf("stvdi_open: Malloc for color buffer failed.\n"); return_error(gs_error_VMerror); } } /* Begin more code from gdevprn.c. */ /* Render the image entirely in memory. */ /* Release the leftover memory. */ gs_free(left, PRN_MIN_MEMORY_LEFT, 1, "printer memory left"); ppdev->buffer_space = 0; pmemdev->base = base; ppdev->std_procs = mdev->std_procs; ppdev->std_procs.get_page_device = gx_page_device_get_page_device; /* Synthesize the procedure vector. */ /* Rendering operations come from the memory or clist device, */ /* non-rendering come from the printer device. */ #define copy_proc(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p) copy_proc(get_initial_matrix); copy_proc(output_page); copy_proc(close_device); copy_proc(map_rgb_color); copy_proc(map_color_rgb); copy_proc(get_params); copy_proc(put_params); copy_proc(map_cmyk_color); copy_proc(get_xfont_procs); copy_proc(get_xfont_device); copy_proc(map_rgb_alpha_color); copy_proc(get_page_device); #undef copy_proc /* End code included from gdevprn.c. */ /* Open the memory device. */ if ((ret = (*pdev->procs->open_device)(pdev)) != 0) { return ret; } Raster = pmemdev->raster; /* Set up the MFDBs for the GS image and the screen. */ Graphic.screen.fd_addr = (long)NULL; Graphic.image.fd_addr = (long)base; Graphic.image.fd_w = (VWork.ColorBits > 1) ? 16 * WordWidth: 8 * Raster; Graphic.image.fd_h = Graphic.Height; Graphic.image.fd_wdwidth = Graphic.image.fd_w/16; Graphic.image.fd_stand = 0; Graphic.image.fd_nplanes = VWork.ColorBits; if (VWork.ColorBits > 1 && cbase) { /* Set up the MFDB for the color image buffer. */ plane_image.fd_addr = (long)cbase; plane_image.fd_w = 16 * WordWidth; plane_image.fd_h = Graphic.Height; plane_image.fd_wdwidth = Graphic.image.fd_w/16; plane_image.fd_stand = 1; plane_image.fd_nplanes = VWork.ColorBits; } return 0; } /* Close the stvdi device--free memory, close workstations, etc. */ int stvdi_close(gx_device *pdev) { WINLIST *wl = WList; /* Close the image window. */ if (imagwin.opened || imagwin.iconified) { WinClose(&imagwin); WinListDelete(wl, &imagwin); WinListRedraw(wl, &State); } /* Free the memory device bitmap. */ gs_free((char *)pmemdev->base, (uint)gdev_mem_bitmap_size(pmemdev), 1, "printer buffer"); /* Free the memory for the color image buffer. */ if (VWork.ColorBits > 1 && cbase) { gs_free((char *)cbase, csize, 1, "color buffer"); } pdev->std_procs = ppdev->orig_procs; return 0; } int stvdi_output_page(gx_device *pdev, int num_copies, int flush) { int code; ppdev->page_count++; /* Print the accumulated page description. */ code = (*ppdev->print_page)(ppdev, ppdev->file); /* Make palette entries available to the next page. */ State.PaletteCount = 1; if ( code < 0 ) return code; return 0; } /* Print the bitmap for the current page to the screen. */ private int stvdi_print_page(gx_device_printer *pdev, FILE *dummy) { byte *base; int count, show_end, pad, length, top, empty; long ch; show_end = 0; /* Calculate the number of padding bits in the last byte * of each scan line. */ pad = (8 * ByteWidth - Graphic.Width) * VWork.ColorBits; length = ByteWidth * VWork.ColorBits; Graphic.PlotY = 0; lineptr = pmemdev->line_ptrs; base = *lineptr; tbase = (ushort *)base; /* accessed from assembly routines */ /* Find the first line containing nonzero bits. */ while (Graphic.PlotY < Graphic.Height) { /* Search the scanline for a nonzero bit. */ for (count=0; (count < length) && (base[count] == 0); ++count) ; if (count >= length) { /* Empty line, continue. */ Graphic.PlotY++; base = lineptr[Graphic.PlotY]; } else if ((count==length-1) && (base[count]>>pad == 0)) { Graphic.PlotY++; /* nonzero bits in padding, continue */ base = lineptr[Graphic.PlotY]; } else { /* Nonzero bits found, break loop. */ if (--Graphic.PlotY < 0) { Graphic.PlotY = 0; } break; } } /* Skip transformation and display of modes my hardware * doesn't support. */ if (State.Debug8 || State.Debug16) { dprintf1("%s\n", "Done!"); return 0; } /* Convert the packed image to standard GEM color planes, * then convert the plane image to the final platform-dependent * screen format. If the platform-dependent format is chunky, * then do nothing. */ if (VWork.TrueColor) { ; } else if (VWork.ColorBits == 8 && State.Chunky8) { ; } else { stvdi_pack_to_plane(); vr_trnfm(VWork.VdiHandle, &plane_image, &Graphic.image); } /* Open a window and display the image. */ if (State.Windows) { graf_mouse(M_OFF, 0L ); if (imagwin.opened) { /* Already opened. */ State.Event->Message[3] = imagwin.handle; HandleRedraw(FULL_WIN, &State); update_scroll(imagwin.handle); } else { /* Window closed or iconified. */ if ((menuobj[NEXT].ob_state & DISABLED) && (menuobj[PREV].ob_state & DISABLED)) { menu_ienable(menuobj, NEXT, 1); } WinListAdd(WList, &imagwin); BitWinOpen(&imagwin, &VWork, &State); } graf_mouse(BUSY_BEE, 0L); graf_mouse(M_ON, 0L); } else { /* Display the image with no windows. */ CopyWidth = MIN(VWork.XRes, Graphic.Width-1); /* in pixels */ CopyHeight = MIN(VWork.YRes, Graphic.Height-1); /* in pixels */ Graphic.StepX = .9 * CopyWidth; Graphic.StepY = .9 * CopyHeight; if (Graphic.PlotY < 0) Graphic.PlotY = 0; if (Graphic.PlotY >= Graphic.Height - CopyHeight) Graphic.PlotY = (Graphic.Height - 1) - CopyHeight; v_exit_cur(VWork.VdiHandle); } while (!show_end && !State.Windows) { State.pxy[0] = Graphic.PlotX; State.pxy[1] = Graphic.PlotY; State.pxy[2] = State.pxy[0] + CopyWidth; State.pxy[3] = State.pxy[1] + CopyHeight; State.pxy[4] = 0; State.pxy[5] = 0; State.pxy[6] = State.pxy[4] + CopyWidth; State.pxy[7] = State.pxy[5] + CopyHeight; graf_mouse(M_OFF, 0L ); vs_clip(VWork.VdiHandle, 1, &State.pxy[4]); wind_update(BEG_UPDATE); /* lock the screen */ vro_cpyfm(VWork.VdiHandle, 3, State.pxy, &Graphic.image, &Graphic.screen); wind_update(END_UPDATE); /* release screen */ vs_clip(VWork.VdiHandle, 0, &State.pxy[4]); graf_mouse(ARROW, 0L ); graf_mouse(M_ON, 0L ); /* Accept keyboard commands to manipulate the screen image. */ ch = (Bconin(2) >> 16) & 255; /* Get key scancode */ switch(ch) { case 16: /* Q */ show_end = 1; break; case 71: /* Clr/Home */ Graphic.StepX /= 2; Graphic.StepY /= 2; if (Graphic.StepX < 2) Graphic.StepX = 1; if (Graphic.StepY < 2) Graphic.StepY = 1; break; case 72: /* Up cursor */ Graphic.PlotY = MAX(Graphic.PlotY - Graphic.StepY, 0); break; case 75: /* Left cursor */ Graphic.PlotX = MAX(Graphic.PlotX - Graphic.StepX, 0); break; case 77: /* Right cursor */ Graphic.PlotX = Graphic.PlotX + Graphic.StepX; if (Graphic.PlotX >= Graphic.Width - CopyWidth) Graphic.PlotX = (Graphic.Width - 1) - CopyWidth; if (Graphic.PlotX < 0) Graphic.PlotX = 0; break; case 80: /* Down cursor */ Graphic.PlotY = Graphic.PlotY + Graphic.StepY; if (Graphic.PlotY >= Graphic.Height - CopyHeight) Graphic.PlotY = (Graphic.Height - 1) - CopyHeight; if (Graphic.PlotY < 0) Graphic.PlotY = 0; break; case 82: /* Insert */ Graphic.StepX *= 2; Graphic.StepY *= 2; if (Graphic.StepX > CopyWidth) Graphic.StepX = CopyWidth; if (Graphic.StepY > CopyHeight) Graphic.StepY = CopyHeight; break; case 97: /* Undo */ Graphic.PlotX = 0; Graphic.PlotY = 0; break; case 98: /* Help */ stvdi_DisplayHelp(); Bconin(2); stvdi_clear_screen(0); break; } } if (!State.Windows) { v_enter_cur(VWork.VdiHandle); } return (0); } int stvdi_DisplayHelp() { dprintf2("%c%c Help for GhostScript Screen Driver\n", 27, 'E'); dprintf(" Original Code by Hauke Hess.\n\n"); dprintf(" Q: Quit this page (to next page or GS prompt).\n"); dprintf(" Cursor Keys: Scroll screen in direction of cursor.\n"); dprintf(" Help: Display help screen.\n"); dprintf(" Undo: Move to upper-left corner of page.\n"); dprintf(" Insert: Multiply scroll incrememt by 2.\n"); dprintf(" Clr/Home: Divide scroll increment by 2.\n"); dprintf("\n Command line option -rx sets resolution.\n"); #if 0 dprintf("\n Helpseite des GhostScript Previewers no(c)\n"); dprintf(" Hauke Hež 1991\n"); dprintf(" Cursortasten: bewegen in entsprechender Richtung\n"); dprintf(" Undo: Zurck nach links oben auf der Seite\n"); dprintf(" Insert: Schrittweiter vergr”žern\n"); dprintf(" Clr/Home: Schrittweite verkleinern\n"); dprintf("\n Kommandozeilenparameter -rx setzt die Aufl”sung\n"); #endif dprintf("\n >> Hit any key to continue. <<"); return(0); } int stvdi_clear_screen(int cursor) { if (cursor) { v_enter_cur(VWork.VdiHandle); } else { v_exit_cur(VWork.VdiHandle); } } /* Map a r-g-b color to a color index. */ /* Ghostscript asks this routine which color index should be associated * with a given RGB triplet. The palette is set from the high end as GS * requests colors. Black and white, however, always reside at color * indices 1 and 0. When the palette is full and a new color is requested, * the closest color in the palette is returned. */ #define BK 0 #define WT 3000 gx_color_index stvdi_map_rgb_color(gx_device *pdev, gx_color_value r, gx_color_value g, gx_color_value b) { register int diff; register int *pptr = VWork.Palette + VWork.PaletteSize; static int BlackSet=0, WhiteSet=0; gx_color_index Pixel; int *which, Index; int rgb[3], red, grn, blu; int best = 1000*3, psize = (VWork.PaletteSize/3 - 2); float max_value = (float)gx_max_color_value; if (VWork.ColorBits == 1) { /* monochrome */ return ((r | g | b) > gx_max_color_value / 2 ? (gx_color_index)0 : (gx_color_index)1); } else if (VWork.TrueColor) { IndexToPixel(&Pixel, 1); return Pixel; } /* Change GS rgb values to ST vdi rgb values. */ red = rgb[0] = 1000 * ((float)r / max_value); grn = rgb[1] = 1000 * ((float)g / max_value); blu = rgb[2] = 1000 * ((float)b / max_value); Index = State.PaletteCount; switch (red + grn + blu) { case WT: /* white -- keep at vdi index 0 */ if (!WhiteSet) { VWork.Palette[0] = rgb[0]; VWork.Palette[1] = rgb[1]; VWork.Palette[2] = rgb[2]; vs_color(VWork.VdiHandle, 0, rgb); WhiteSet = 1; } return (gx_color_index)VWork.ColorReg[0]; case BK: /* black -- keep at vdi index 1 */ if (!BlackSet) { VWork.Palette[3] = rgb[0]; VWork.Palette[4] = rgb[1]; VWork.Palette[5] = rgb[2]; vs_color(VWork.VdiHandle, 1, rgb); BlackSet = 1; } return (gx_color_index)VWork.ColorReg[1]; default: /* Search for color from end of palette. */ while ( Index-- > 1 ) { pptr -= 3; diff = *pptr - red; if ( diff < 0 ) diff = -diff; if ( diff < best ) { /* quick rejection */ int dg = pptr[1] - grn; if ( dg < 0 ) dg = -dg; if ( (diff += dg) < best ) { /* quick rejection */ int db = pptr[2] - blu; if ( db < 0 ) db = -db; if ( (diff += db) < best ) which = pptr, best = diff; if (best == 0) break; } } } /* If the color is found or the palette is full, return * the result of the palette search. Otherwise, set the * next palette entry to the requested color. */ if (best == 0 || State.PaletteCount >= psize) { Index = (which - VWork.Palette)/3; return (gx_color_index)VWork.ColorReg[Index]; } else { int i = VWork.PaletteSize - 3 * State.PaletteCount; Index = i/3; VWork.Palette[i] = rgb[0]; VWork.Palette[i+1] = rgb[1]; VWork.Palette[i+2] = rgb[2]; vs_color(VWork.VdiHandle, Index, rgb); ++State.PaletteCount; return (gx_color_index)VWork.ColorReg[Index]; } break; } } /* Map a color index to a r-g-b color. */ int stvdi_map_color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3]) { int *pptr; int max_value = gx_max_color_value; /* HACK ALERT! The manner for extracting RGB values for * true color modes uses information which may be hardware * dependent or may change in the future. This routine never * seems to be called anyway, so it doesn't seem too critical. */ if (VWork.ColorBits == 1) { /* monochrome */ return gdev_prn_map_color_rgb(pdev, color, prgb); } else if (VWork.TrueColor) { if (VWork.ColorBits == 16) { prgb[0] = (color & 0xf800) << (gx_color_value_bits - 16); prgb[1] = (color & 0x07e0) << (gx_color_value_bits - 11); prgb[2] = (color & 0x001f) << (gx_color_value_bits - 5); } else { int shift = gx_color_value_bits - 24; if (shift >= 0) { prgb[0] = (color & 0x00ff0000L) << shift; } else { prgb[0] = (color & 0x00ff0000L) >> (-shift); } prgb[1] = (color & 0x0000ff00L) << (gx_color_value_bits - 16); prgb[2] = (color & 0x000000ffL) << (gx_color_value_bits - 8); } return 0; } pptr = VWork.Palette + (int)color * 3; prgb[0] = (pptr[0] * max_value) / 1000; prgb[1] = (pptr[1] * max_value) / 1000; prgb[2] = (pptr[2] * max_value) / 1000; return 0; } /* Copy an image from Ghostscript's format to standard color planes. */ int stvdi_pack_to_plane(void) { int i, plane_size; words = Graphic.Height * WordWidth - 1; /* pixels/16 - 1 */ plane_size = 2 * WordWidth * Graphic.Height; /* Plane[i] holds the address of the ith color plane. */ for (i=0; i