/* Hello, Emacs, this is -*-C-*- * $Id: amiga.trm,v 1.20 2006/07/21 02:35:45 sfeam Exp $ * */ /* GNUPLOT - amiga.trm */ /*[ * Copyright 1991, 1992, 1993, 1998, 2004 * * Permission to use, copy, and distribute this software and its * documentation for any purpose with or without fee is hereby granted, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. * * Permission to modify the software is granted, but not the right to * distribute the complete modified source code. Modifications are to * be distributed as patches to the released version. Permission to * distribute binaries produced by compiling modified sources is granted, * provided you * 1. distribute the corresponding source modifications from the * released version in the form of a patch file along with the binaries, * 2. add special version identification to distinguish your version * in addition to the base release version number, * 3. provide your name and address as the primary contact for the * support of your modified version, and * 4. retain our contact information in regard to use of the base * software. * Permission to distribute the released version of the source code along * with corresponding source modifications in the form of a patch file is * granted with same provisions 2 through 4 for binary distributions. * * This software is provided "as is" without express or implied warranty * to the extent permitted by applicable law. ]*/ /* * This file is included by ../term.c. * * This terminal driver supports: * Amiga Custom Screen * * AUTHORS * Carsten Steger * * Pat R. Empleo Slightly modified for Aztec C v5.2a (beta); sort of * 08/27/91 supports overscan; for large WB 2.0 virtual screens, * we limit the plot size so we don't have to scroll * around (not fun). * * Carsten Steger Modified to support Kickstart 2.0. * 09/11/91 Opens a text overscan screen when used with WB 2.0. * Discerns between NTSC and PAL Amigas when used with * WB 1.3 and lower. * * Pat R. Empleo Defined some 2.0 stuff in order to get Aztec C to * 09/20/91 work with Carsten's new code (see above). When * KS/WB 2.0 support gets implemented in Aztec C, this * kludge will get deleted! * (Aztec C release 5.2 beta) * * Carsten Steger Converted to new terminal layout. * 10/01/95 * * Lars Hecking Add code from George Coulouris to * 06/20/97 implement window option, requires AmigaOS 3.0+. * General cleanup, better readability. * * Lars Hecking Replace static arrays for AMIGA_FontName and temporary * 06/21/97 arrays with AllocMem()'d memory. * * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net). * */ #include "driver.h" #ifdef TERM_REGISTER register_term(amiga) #endif #ifdef TERM_PROTO #define AMIGA_XMAX 640 #define AMIGA_YMAX 512 #define AMIGA_VCHAR 12 #define AMIGA_HCHAR 8 #define AMIGA_VTIC 5 #define AMIGA_HTIC 5 TERM_PUBLIC void AMIGA_reset __PROTO((void)); TERM_PUBLIC void AMIGA_init __PROTO((void)); TERM_PUBLIC void AMIGA_options __PROTO((void)); TERM_PUBLIC void AMIGA_text __PROTO((void)); TERM_PUBLIC void AMIGA_graphics __PROTO((void)); TERM_PUBLIC void AMIGA_move __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void AMIGA_vector __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void AMIGA_linetype __PROTO((int linetype)); TERM_PUBLIC void AMIGA_put_text __PROTO((unsigned int x, unsigned int y, const char *str)); TERM_PUBLIC int AMIGA_justify_text __PROTO((enum JUSTIFY mode)); TERM_PUBLIC int AMIGA_set_font __PROTO((const char *font)); TERM_PUBLIC void AMIGA_suspend __PROTO((void)); TERM_PUBLIC void AMIGA_resume __PROTO((void)); #define GOT_AMIGA_PROTO #endif /* TERM_PROTO */ #ifndef TERM_PROTO_ONLY #ifdef TERM_BODY #ifdef AMIGA_AC_5 #include #include #include #include #else /* You will have to use the Kickstart 2.0 header files for this to compile */ #include #include #include #include #include #include #include #include #endif /* !AMIGA_AC_5 */ #ifdef HAVE_ATEXIT void AMIGA_exit(void); # define ATEXIT(x) (atexit(x) != 0) # ifdef AMIGA_SC_6_1 /* # define ATEXIT(x) (onexit(x) == 0) */ # define RAWCON(x) rawcon(x) # else # define RAWCON(x) /* nought */ # endif /* SAS */ #else # define ATEXIT(x) 0 #endif /* HAVE_ATEXIT */ #ifndef RETURN_FAIL # define RETURN_FAIL 20 #endif #define LIB_VERSION(LibBase) ((LibBase)->LibNode.lib_Version) #define AMIGA_ERROR(string,rc) {fprintf (stderr,"%s\n",string);\ AMIGA_reset (); exit (rc);} /* from plot.c */ extern TBOOLEAN interactive; /* The origin is in the upper left hand corner, so we have to translate */ /* and flip the coordinates: */ #define AMIGA_VTF(y) (AMIGA_ymax-1-(y)) /* Libraries */ struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Library *DiskfontBase; /* Name of font, size in pts */ static char *AMIGA_FontName = NULL; static int AMIGA_FontNameLen = 0; static int AMIGA_FontSize = 8; static char AMIGA_default_font[MAX_ID_LEN+1] = {'\0'}; #define AMIGA_DEFAULTFONT "topaz" /* Font stuff */ static struct TextAttr AMIGA_Font = { "topaz.font", TOPAZ_EIGHTY, FS_NORMAL, FPF_ROMFONT }; static struct TextFont *AMIGA_TextFont; /* Screen stuff */ static struct NewScreen AMIGA_NewScreen = { 0, 0, AMIGA_XMAX, AMIGA_YMAX, 4, 15, 0, HIRES | LACE, CUSTOMSCREEN | SCREENBEHIND | SCREENQUIET, NULL, NULL, NULL, NULL }; static struct Screen *AMIGA_Screen; static struct TagItem AMIGA_ScrTagList[] = { { SA_Overscan, OSCAN_TEXT }, { TAG_DONE, 0 } }; /* Window stuff */ /* FALSE: plot to screen; TRUE: plot to window */ static TBOOLEAN AMIGA_window_mode = FALSE; #define AMIGA_WIN_XMAX 512 #define AMIGA_WIN_YMAX 320 static struct Window *AMIGA_Window; static struct TagItem AMIGA_WinTagList[] = { { WA_InnerWidth, AMIGA_WIN_XMAX }, { WA_InnerHeight, AMIGA_WIN_YMAX }, { WA_Title, (ULONG) "gnuplot" }, { WA_DragBar, TRUE }, { WA_DepthGadget, TRUE }, { WA_WBenchWindow, TRUE }, { WA_SmartRefresh, TRUE }, { WA_GimmeZeroZero, TRUE }, { WA_AutoAdjust, TRUE }, { TAG_DONE, 0 } }; /* * This is the palette. Values are stored as 0xrrggbb, where rr, gg, and, bb * are big-endian 8-bit intensities for red, green, and blue, respectively. */ static unsigned int palette[] = { 0xffffff, /* white */ 0x000000, /* black */ 0xff0000, /* red */ 0x00ff00, /* green */ 0x0000ff, /* blue */ 0x00ffff, /* cyan */ 0xff00ff, /* magenta */ 0xffff00, /* yellow */ 0x7f007f, /* purple */ 0xff7f00, /* orange */ }; #define PALETTE_SIZE (sizeof (palette) / sizeof (unsigned int)) /* This is the color look-up table, indexed in the same order as * the above palette. The values stored in this table are pen numbers; * e.g clut[2] is the pen which represents the color "red". */ static unsigned int clut[PALETTE_SIZE]; /* Colors */ static UWORD AMIGA_Colors[] = { 0x000, 0xfff, 0xbbb, 0x0f0, 0xf00, 0x00f, 0x3ca, 0xf0f, 0x94d, 0x0ff, 0x82f, 0xff0, 0x0af, 0xc5e, 0xfa2, 0xf44 }; /* Misc */ static int AMIGA_slinetype; static enum JUSTIFY AMIGA_justify = LEFT; static unsigned int AMIGA_ymax, AMIGA_xmax; static WORD AMIGA_cwd, AMIGA_cht, AMIGA_bsl, AMIGA_vadj; /* Common RastPort */ static struct RastPort *AMIGA_RastPort; enum AMIGA_id { AMI_SCREEN, AMI_WINDOW, AMI_OTHER }; static struct gen_table AMIGA_opts[] = { {"scr$een", AMI_SCREEN }, {"win$dow", AMI_WINDOW }, { NULL, AMI_OTHER } }; /* * Scan terminal options */ TERM_PUBLIC void AMIGA_options() { while (!END_OF_COMMAND) { switch(lookup_table(&AMIGA_opts[0],c_token)) { case AMI_SCREEN: AMIGA_window_mode = FALSE; c_token++; break; case AMI_WINDOW: AMIGA_window_mode = TRUE; c_token++; break; case AMI_OTHER: default: /* Font name */ if (isstring(c_token)) { if (AMIGA_FontName != NULL) { FreeMem(AMIGA_FontName,AMIGA_FontNameLen); AMIGA_FontName = NULL; AMIGA_FontNameLen = 0; } AMIGA_FontNameLen = token_len(c_token); AMIGA_FontName = AllocMem(AMIGA_FontNameLen,0); if (AMIGA_FontName == NULL) AMIGA_ERROR("No memory for font name", RETURN_FAIL); quote_str(AMIGA_FontName, c_token, AMIGA_FontNameLen); c_token++; } else { /* Font size */ struct value a; AMIGA_FontSize = (int) real(const_express(&a)); } break; } } if (AMIGA_FontName == NULL && AMIGA_FontSize != 0) { AMIGA_FontNameLen = strlen(AMIGA_DEFAULTFONT) + 1; AMIGA_FontName = AllocMem(AMIGA_FontNameLen,0); if (AMIGA_FontName == NULL) AMIGA_ERROR("No memory for font name", RETURN_FAIL); strcpy(AMIGA_FontName, AMIGA_DEFAULTFONT); } if (AMIGA_FontName != NULL && AMIGA_FontSize == 0) AMIGA_FontSize = 8; if (AMIGA_FontName != NULL && AMIGA_FontSize != 0) { sprintf(AMIGA_default_font, "%s,%d", AMIGA_FontName, AMIGA_FontSize); sprintf(term_options, "%s \"%s\" %d", \ (AMIGA_window_mode != TRUE ? "screen" : "window"), \ AMIGA_FontName, AMIGA_FontSize); } else sprintf(term_options, "%s", (AMIGA_window_mode != TRUE ? "screen" : "window")); } /* * Close open font, screen and libraries. */ TERM_PUBLIC void AMIGA_reset() { if (AMIGA_window_mode == TRUE) { int i = 0; /* Free the pens */ while (i < PALETTE_SIZE) { if (clut[i] != -1) ReleasePen(AMIGA_Window->WScreen->ViewPort.ColorMap, clut[i]); i++; } /* Close the window */ if (AMIGA_Window != NULL) CloseWindow(AMIGA_Window); AMIGA_Window = NULL; AMIGA_window_mode = FALSE; } if (AMIGA_TextFont != NULL) CloseFont(AMIGA_TextFont); if (DiskfontBase != NULL) CloseLibrary(DiskfontBase); if (AMIGA_Screen != NULL) CloseScreen(AMIGA_Screen); if (IntuitionBase != NULL) CloseLibrary((struct Library *) IntuitionBase); if (GfxBase != NULL) CloseLibrary((struct Library *) GfxBase); if (AMIGA_FontName != NULL) FreeMem(AMIGA_FontName,AMIGA_FontNameLen); AMIGA_FontName = NULL; AMIGA_FontNameLen = 0; AMIGA_TextFont = NULL; DiskfontBase = NULL; AMIGA_Screen = NULL; IntuitionBase = NULL; GfxBase = NULL; AMIGA_RastPort = NULL; } /* * Init terminal. */ TERM_PUBLIC void AMIGA_init() { /* Install exit trap in case of abnormal termination (see below). */ if (ATEXIT(AMIGA_exit)) AMIGA_ERROR("Couldn't set exit trap", RETURN_FAIL); /* Open needed libraries */ GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0); if (GfxBase == NULL) AMIGA_ERROR("No Graphics-Library", RETURN_FAIL); IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0); if (IntuitionBase == NULL) AMIGA_ERROR("No Intuition-Library", RETURN_FAIL); if (AMIGA_window_mode == TRUE) { int i = 0; /* Initialize the clut */ while (i < PALETTE_SIZE) clut[i++] = -1; } if (LIB_VERSION(IntuitionBase) <= 34) { /* We compute the vertical resolution for those poor NTSC-souls :-) */ if (GfxBase->DisplayFlags & PAL) AMIGA_ymax = 512; else AMIGA_ymax = 400; AMIGA_xmax = 640; AMIGA_NewScreen.Width = AMIGA_xmax; AMIGA_NewScreen.Height = AMIGA_ymax; AMIGA_Screen = OpenScreen(&AMIGA_NewScreen); if (AMIGA_Screen == NULL) AMIGA_ERROR("No Screen", RETURN_FAIL); AMIGA_RastPort = &AMIGA_Screen->RastPort; } else { /* Intuition version > 34 */ /* Kickstart 2.0 support */ AMIGA_NewScreen.Width = STDSCREENWIDTH; AMIGA_NewScreen.Height = STDSCREENHEIGHT; if (AMIGA_window_mode != TRUE) { AMIGA_Screen = OpenScreenTagList(&AMIGA_NewScreen, AMIGA_ScrTagList); if (AMIGA_Screen == NULL) AMIGA_ERROR("No Screen", RETURN_FAIL); AMIGA_RastPort = &AMIGA_Screen->RastPort; AMIGA_xmax = AMIGA_Screen->Width; AMIGA_ymax = AMIGA_Screen->Height; } else if (LIB_VERSION(GfxBase) >= 39) { /* AMIGA_window_mode == TRUE */ /* Open the plot window */ AMIGA_Window = (struct Window *)OpenWindowTagList(NULL, AMIGA_WinTagList); /* Don't do this: fall back to screen */ if (AMIGA_Window == NULL) AMIGA_ERROR("Could not open plot window", RETURN_FAIL); AMIGA_RastPort = AMIGA_Window->RPort; AMIGA_xmax = AMIGA_WIN_XMAX; AMIGA_ymax = AMIGA_WIN_YMAX; } /* Gfx version >= 39 */ } /* Intuition version <= 34 */ term->xmax = AMIGA_xmax; term->ymax = AMIGA_ymax; if (AMIGA_window_mode != TRUE) { char *name = NULL; /* assert(AMIGA_FontName != NULL); */ /* should even do for ridiculously large FontSize :) */ name = AllocMem(AMIGA_FontNameLen + 1 + INT_STR_LEN + 1,0); if (name == NULL) AMIGA_ERROR("No memory for font name", RETURN_FAIL); sprintf(name, "%s,%d", AMIGA_FontName, AMIGA_FontSize); AMIGA_set_font(name); FreeMem(name,AMIGA_FontNameLen + INT_STR_LEN + 2); LoadRGB4(&AMIGA_Screen->ViewPort, AMIGA_Colors, 16); RemakeDisplay(); AMIGA_slinetype = 1; SetAPen(&AMIGA_Screen->RastPort, AMIGA_slinetype); } else { int i, r, g, b; AMIGA_bsl = AMIGA_Window->RPort->TxBaseline; /* Reference line */ AMIGA_cht = AMIGA_Window->RPort->TxHeight; /* Height of characters */ /* Allocate pens */ for (i = 0; i < PALETTE_SIZE; i++) { r = (palette[i] << 8) & 0xFF000000; g = (palette[i] << 16) & 0xFF000000; b = (palette[i] << 24) & 0xFF000000; clut[i] = ObtainBestPenA(AMIGA_Window->WScreen->ViewPort.ColorMap, r, g, b, NULL); } } SetDrMd(AMIGA_RastPort, JAM1); } /* * */ TERM_PUBLIC void AMIGA_text() { if (AMIGA_window_mode != TRUE) { if (interactive == TRUE) { FILE *fp; if ((fp = fopen("*", "r")) != NULL) { int c = getc(fp); ungetc(c, stdin); fclose(fp); } ScreenToBack(AMIGA_Screen); } } } /* * */ TERM_PUBLIC void AMIGA_graphics() { SetRast(AMIGA_RastPort, 0); if (AMIGA_window_mode == TRUE) { /* clear the window */ SetAPen(AMIGA_Window->RPort, clut[0]); RectFill(AMIGA_Window->RPort, 0, 0, 640, 400); AMIGA_slinetype = clut[1]; } SetAPen(AMIGA_RastPort, AMIGA_slinetype); AMIGA_resume(); } /* * */ TERM_PUBLIC void AMIGA_move(unsigned int x, unsigned int y) { if ((x >= AMIGA_xmax) || (y >= AMIGA_ymax)) return; Move(AMIGA_RastPort, x, AMIGA_VTF(y)); } /* * */ TERM_PUBLIC void AMIGA_vector(unsigned int x, unsigned int y) { if ((x >= AMIGA_xmax) || (y >= AMIGA_ymax)) return; Draw(AMIGA_RastPort, x, AMIGA_VTF(y)); } /* * */ TERM_PUBLIC void AMIGA_linetype(int linetype) { if (AMIGA_window_mode != TRUE) { if (linetype >= 13) linetype %= 13; if (linetype < -3) linetype = LT_BLACK; AMIGA_slinetype = linetype + 3; } else { if (linetype >= 0) linetype = (linetype % 9) + 1; if (linetype < 0) linetype = 1; AMIGA_slinetype = clut[linetype]; } SetAPen(AMIGA_RastPort, AMIGA_slinetype); } /* * */ TERM_PUBLIC void AMIGA_put_text(unsigned int x, unsigned int y, const char *str) { LONG len, tx_len; WORD x_min, x_max, y_min, y_max; len = strlen(str); tx_len = TextLength(AMIGA_RastPort, str, len); switch (AMIGA_justify) { case LEFT: x_min = x; x_max = x + tx_len; break; case CENTRE: x_min = x - tx_len / 2; x_max = x + tx_len - tx_len / 2; /* avoid roundoff errors ! */ break; default: /* does this make sense ?? */ case RIGHT: x_min = x - tx_len; x_max = x; break; } y_min = AMIGA_VTF(y) - AMIGA_vadj; y_max = y_min + AMIGA_cht; /* Check if character-string lies completely within the screen: */ /* What about clipping? */ if ((x_max >= AMIGA_xmax) || (y_min < 0) || (y_max >= AMIGA_ymax)) return; Move(AMIGA_RastPort, x_min, y_min + AMIGA_bsl); Text(AMIGA_RastPort, str, len); } /* * */ TERM_PUBLIC int AMIGA_justify_text(enum JUSTIFY mode) { AMIGA_justify = mode; return TRUE; } /* * */ TERM_PUBLIC int AMIGA_set_font(const char *font) { static char test_str[] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; static WORD test_len, test_pxl; /* Disable for window mode */ if (AMIGA_window_mode != TRUE) { char *name = NULL; int size, sep, namelen; /* Allow caller to pass "" to indicate default font */ if (!font || !(*font)) font = AMIGA_default_font; sep = strcspn(font, ","); namelen = strlen(font) + strlen(".font") + 1; name = AllocMem(namelen,0); if (name == NULL) AMIGA_ERROR("No memory for font name", RETURN_FAIL); strcpy(name,font); name[sep] = NUL; size = AMIGA_FontSize; if (font[sep] == ',') sscanf(&(font[sep + 1]), "%d", &size); if (name != NULL && strcmp(name, "") != 0) { strcat(name, ".font"); /* Avoid opening "diskfont.library" if a built-in font is desired */ if ((strcmp("topaz.font", name) == 0) && ((size == TOPAZ_EIGHTY) || (size == TOPAZ_SIXTY))) { AMIGA_Font.ta_Name = name; AMIGA_Font.ta_YSize = size; AMIGA_Font.ta_Style = FS_NORMAL; AMIGA_Font.ta_Flags = FPF_ROMFONT; AMIGA_TextFont = OpenFont(&AMIGA_Font); if (AMIGA_TextFont != NULL) SetFont(&AMIGA_Screen->RastPort, AMIGA_TextFont); } else { DiskfontBase = OpenLibrary("diskfont.library", 0); if (DiskfontBase != NULL) { AMIGA_Font.ta_Name = name; AMIGA_Font.ta_YSize = size; AMIGA_Font.ta_Style = FS_NORMAL; AMIGA_Font.ta_Flags = FPF_ROMFONT | FPF_DISKFONT; AMIGA_TextFont = OpenDiskFont(&AMIGA_Font); if (AMIGA_TextFont != NULL) SetFont(&AMIGA_Screen->RastPort, AMIGA_TextFont); } } } /* Width of characters: This works better for proportional fonts than */ /* AMIGA_Screen->RastPort.TxWidth + AMIGA_Screen->RastPort.TxSpacing */ test_len = strlen(test_str); test_pxl = TextLength(&AMIGA_Screen->RastPort, test_str, test_len); AMIGA_cwd = test_pxl / test_len; AMIGA_cht = AMIGA_Screen->RastPort.TxHeight; /* Height of characters */ AMIGA_bsl = AMIGA_Screen->RastPort.TxBaseline; /* Reference line */ /* Amount by which characters have to be shifted upwards to be */ /* vertically justified: */ AMIGA_vadj = AMIGA_bsl / 2; term->v_char = AMIGA_cht + 4; /* So lines won't be too close */ term->h_char = AMIGA_cwd; FreeMem(name,namelen); } /* !window_mode */ return TRUE; } /* * */ TERM_PUBLIC void AMIGA_suspend() { if (AMIGA_window_mode != TRUE) { if (interactive == TRUE) { FILE *fp; if ((fp = fopen("*", "r")) != NULL) { int c = getc(fp); ungetc(c, stdin); fclose(fp); } ScreenToBack(AMIGA_Screen); } } } /* * */ TERM_PUBLIC void AMIGA_resume() { if (AMIGA_window_mode != TRUE) ScreenToFront(AMIGA_Screen); else WindowToFront(AMIGA_Window); } #ifdef HAVE_ATEXIT /* This function is mainly included if the program terminates abnormally * and the screen and libraries are still open. It closes down all opened * libraries and screens. This happens e.g. when loading "bivariat.demo" * and the stack is smaller than 120000 bytes. */ void AMIGA_exit() { AMIGA_reset(); RAWCON(0); } #endif /* HAVE_ATEXIT */ #endif /* TERM_BODY */ #ifdef TERM_TABLE TERM_TABLE_START(amiga_driver) "amiga", "Amiga Custom Screen/Window [screen window]", AMIGA_XMAX, AMIGA_YMAX, AMIGA_VCHAR, AMIGA_HCHAR, AMIGA_VTIC, AMIGA_HTIC, AMIGA_options, AMIGA_init, AMIGA_reset, AMIGA_text, null_scale, AMIGA_graphics, AMIGA_move, AMIGA_vector, AMIGA_linetype, AMIGA_put_text, null_text_angle, AMIGA_justify_text, do_point, do_arrow, AMIGA_set_font, 0, /* pointsize */ TERM_CAN_MULTIPLOT, AMIGA_suspend, AMIGA_resume TERM_TABLE_END(amiga_driver) #undef LAST_TERM #define LAST_TERM amiga_driver #endif /* TERM_TABLE */ #endif /* TERM_PROTO_ONLY */ #ifdef TERM_HELP START_HELP(amiga) "1 amiga", "?commands set terminal amiga", "?set terminal amiga", "?set term amiga", "?terminal amiga", "?term amiga", "?amiga", " The `amiga` terminal, for Commodore Amiga computers, allows the user to", " plot either to a screen (default), or, if Kickstart 3.0 or higher is", " installed, to a window on the current public screen. The font and its size", " can also be selected.", "", " Syntax:", " set terminal amiga {screen | window} {\"\"} {}", "", " The default font is 8-point \"topaz\".", "", " The screen option uses a virtual screen, so it is possible that the graph", " will be larger than the screen." END_HELP(amiga) #endif /* TERM_HELP */