gfxdos.cc

//*************************************************************************
//  MODULE : Gfx - Module functions and globals                           *
//  AUTHOR : Ron Chernich                                                 *
//  PURPOSE: This module contains all the compiler dependant primitives.  *
//  HISTORY:                                                              *
//   02-DEC-92  First (MSC/C++ 7.00) version                              *
//   24-JAN-93  Clipping routines added                                   *
//   07-APR-93  Borland pixel addressing is relative clip origin!!        *
//   23-MAY-93  Explicit path removed from BC  (Needs EGAVGA)  *
//   05-FEB-94  GfxFill combined into GfxRect 'cause Xlib has no support! *
//*************************************************************************

#include "gfx.hh"


/*************** MICROSOFT AND SYMANTIC SPECIFIC CODE ********************/

#if defined(MSC700) || defined(SYM60)

  /*******************
  * variables private to this module..
  */
  static double dRadFac;                          /* degrees -> radians   */
  static UINT16 nFillStyle;                       /* current fill style   */
  static UINT16 nFgColor, nBgColor;               /* stored color setings */
  static unsigned char __far *pSolidMask;         /* solid pattern mask   */
  static unsigned char pDotMask1[8] =             /* 50% background mask  */
     {0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55};
  static unsigned char pDotMask2[8] =             /* 25% background mask  */
     {0xcc,0x44,0xcc,0x11,0xcc,0x44,0xcc,0x11};



  /************************************************************************
  * Take whatever actions required to place the system in graphics mode
  * and ensure resolution is at least 640 x 480 pixels. The coordinate
  * convention requires the the screen top/left is (0, 0).
  * RETURNS:    TRUE  .. ready for operation
  *             FALSE .. unable to set graphics mode
  */
  BOOL GfxInit (void)
  {
    struct videoconfig vc;
    static char *pszEmsg = "RCOS: %s!\n";
    static char *pszErrs[] = {"Can't find Font files",
			     "Graphics initialization error",
			     "Insufficient display resolution"};

    dRadFac = atan(1.0)/(double)45.0;
    if (_registerfonts("*.FON") < 0)
      fprintf(stderr, pszEmsg, pszErrs[0]);
    else {
      _setfont("t'system'h12w9br");
      if (_setvideomode(_VRES16COLOR) == 0)
	fprintf(stderr, pszEmsg, pszErrs[1]);
      else {                                                                
	nFillStyle = GFX_Solid;
	pSolidMask = _getfillmask(pSolidMask);
	_getvideoconfig(&vc);
	if ((vc.numxpixels >= GFX_Xmin) && (vc.numypixels >= GFX_Ymin)) {
	  _setviewport(0, 0, GFX_Xmin-1, GFX_Ymin-1);
	  _setcliprgn(0, 0, GFX_Xmin-1, GFX_Ymin-1);
	  return(TRUE);
	}
	GfxClose();
	fprintf(stderr, pszEmsg, pszErrs[2]);
      }
    }
    return(FALSE);
  }

  /*************
  * Return system to "normal" operation.
  */
  void GfxClose (void)
  {
    _unregisterfonts();
    _setvideomode(_DEFAULTMODE);
  }

  /*************
  * Limit the area in which graphic operations will occur.
  */
  void GfxSetClip (INT16 x1, INT16 y1, INT16 x2, INT16 y2)
  {
    _setcliprgn(x1, y1, x2, y2);
  }

  /**********
  * Permit drawing of graphics and text fonts anywhere on "our" screen..
  */
  void GfxClrClip (void)
  {
    _setcliprgn(0, 0, GFX_Xmin-1, GFX_Ymin-1);
  }

  /**********
  * Set the position for the next operation..
  */
  void GfxMoveTo (INT16 x, INT16 y)
  {
    _moveto(x, y);
  }

  /*************
  * Draw a line from the "current" location to the passed location
  * using the current color.
  */
  void GfxLineTo (INT16 x, INT16 y)
  {
    _setcolor((short)nFgColor);
    _lineto(x, y);
  }

  /*************
  * Returns the number of pixels the string argument will occupy
  */
  UINT16  GfxTextExtent (char *str)
  {
    return (UINT16)(_getgtextextent(str));
  }

  /*************
  * Returns the height (in pixels) of a text character cell
  */
  UINT16  GfxTextHeight (void)
  {
    struct _fontinfo vc;

    _getfontinfo(&vc);
    return (UINT16)(vc.pixheight);
  }

  /*************
  * Set the graphics fill mode to specified pattern
  */
  void GfxPattern (UINT16 nStyle)
  {
    nFillStyle = nStyle;
  }

  /*************
  * Sets the foreground color for text output
  */
  void GfxTextColor (UINT16 nColor)
  {
    nFgColor = nColor;
  }

  /*************
  * Sets the background color for text outout
  */
  void GfxTextColorBg (UINT16 nColor)
  {
    nBgColor = nColor;
  }

  /*************
  * Draw a circle, centred on  of radius , in passed style
  * and color
  */
  void GfxCircle (INT16 x, INT16 y, INT16 nRad, UINT16 nStyle, UINT16 nColor)
  {
    INT16 x1, y1, x2, y2;

    x1 = x - nRad, y1 = y - nRad;
    x2 = x + nRad, y2 = y + nRad;
    _setcolor((short)nColor);
    switch (nStyle) {
      case GFX_Fill:  _ellipse(_GFILLINTERIOR, x1, y1, x2, y2); break;
      case GFX_Frame: _ellipse(_GBORDER, x1, y1, x2, y2);       break;
    }
  }

  /***************
  * Draw an arc centred on  of radius , beginning at 
  * degrees (zero is straight up), ending at  degrees.
  */
  void GfxArc (INT16 x, INT16 y, INT16 nRad,
	       double dStart, double dEnd, UINT16 nColor)
  {
    INT16 x1, y1, x2, y2, x3, y3, x4, y4;

    x1 = x - nRad, y1 = y - nRad;
    x2 = x + nRad, y2 = y + nRad;
    y3 = y - (INT16)((double)nRad * sin(dStart * dRadFac));
    y4 = y - (INT16)((double)nRad * sin(dEnd * dRadFac));
    x3 = (dStart >= 180.0) ? x1 : x2;
    x4 = (dEnd >= 180.0) ? x1 : x2;
    _setcolor((short)nColor);
    _arc(x1, y1, x2, y2, x3, y3, x4, y4);
  }

  /*************
  * Draw a rectangle bracketed by  (Top Left) and 
  * (Bottom Right), of passed style and Color.  If the currnet style
  * is not GFX_Solid, we dither based on the current background color.
  * Because the FloodFill used to dither needs a bounding color, for
  * simplicity, we (blindly) assume _Black (this is all your fault, DJ).
  */
  void GfxRect (INT16 x1, INT16 y1,
		INT16 x2, INT16 y2, UINT16 nStyle, UINT16 nColor)
  {
    _setcolor((short)nColor);
    switch (nStyle) {
      case GFX_Frame:
	_rectangle(_GBORDER, x1, y1, x2, y2);
	break;
      case GFX_Fill:
	_rectangle(_GFILLINTERIOR, x1, y1, x2, y2);
	if ((nFillStyle != GFX_Solid) && (nBgColor != nColor)) {
	  _setfillmask(((nFillStyle == GFX_HalfTone) ? pDotMask1:pDotMask2));
	  _setcolor(nBgColor), _floodfill(x1+1, y1+1, _Black);
	  _setfillmask(pSolidMask);
	}
    }
  }

  /*************
  * Draw the passed text string at the passed location, in the passed style,
  * using the current colors (point  marks top/left of text extent).
  */
  void GfxText (INT16 x, INT16 y, char *st, UINT16 nStyle)
  {
    if (nStyle == GFX_Replace) {
      _setcolor((short)nBgColor);
      _rectangle(_GFILLINTERIOR,x,y,x+GfxTextExtent(st),y+GfxTextHeight());
    }
    _setcolor((short)nFgColor);
    _moveto(x, y);
    _outgtext(st);
  }

  /*************
  * Allocate a mamory block to hold the bounded screen image bit map
  * in the passed co-ords and store it.
  * RETURNS: pointer to storage, or NULL if unable to comply
  */
  PIMBUF GfxGetImage (INT16 x1, INT16 y1, INT16 x2, INT16 y2)
  { 
    PIMBUF p;
    
    if (p = (PIMBUF)_fmalloc((size_t)_imagesize(x1, y1, x2, y2)) )
      _getimage(x1, y1, x2, y2, p);
    return p;
  }

  /*************
  * copy the image in the passed buffer to the screen at x, y,
  */
  BOOL GfxPutImage (INT16 x, INT16 y, PIMBUF p)
  {
    _putimage(x, y, p, _GPSET);
    return (BOOL)_grstatus();
  }

  /*************
  * copy the image in the passed buffer to the screen at x, y,
  * then release the storage.
  */
  void GfxFreeImage (PIMBUF p)
  {
    if (p)
      _ffree((void far*)p);
  }

#endif         /************** END MICROSOFT SPECIFIC CODE ***************/

#ifdef BC31    /***************** BORLAND C/C++ 3.1 ***********************
	       * CAUTION: File "EGAVGA.BGI" must be in the RCOS start-up
	       * directory (or change to link-in the binary - see UTIL.DOC)
	       * Author's Lament: The Borland BGI is infinitely inferior
	       * to Microsoft's graphic support.  If you can only afford
	       * one real C/C++ development system, do NOT by swayed by
	       * Phillipe's slick advertising.  Yes, his IDE is faster for
	       * development than MS Programmer's Workbench, but MS C/C++
	       * 7.0 compiles smaller, runs faster, optimises better (if
	       * slower) and the Graphic services and font support are FAR
	       * superior.  Finally, MS "Code View" urinates on the Turbo
	       * Debugger from a great height.  Evidence: look at what has
	       * to be done in this module to achieve a PALE imitation of
	       * what the MS code does so simply, and see how much faster
	       * the prittier MSCV700 version runs.      (arcy, 27-JAN-93)
	       */


  /*******************
  * variables private to this module..
  */


  static BOOL   bVpActive;                      /* set when clipping on */
  static INT16  vpxo, vpyo;                     /* view port origin     */
  static UINT16 nFillStyle;                     /* stored fill pattern  */
  static UINT16 nFgColor, nBgColor;             /* stored color setings */
  
  #ifdef BC20
  static char pDotMask1[8] =           /* 50% background mask  */
     {0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55};
  static char pDotMask2[8] =           /* 25% background mask  */
     {0xcc,0x44,0xcc,0x11,0xcc,0x44,0xcc,0x11};
  #else
  static unsigned char pDotMask1[8] =           /* 50% background mask  */
     {0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55};
  static unsigned char pDotMask2[8] =           /* 25% background mask  */
     {0xcc,0x44,0xcc,0x11,0xcc,0x44,0xcc,0x11};
  #endif

  /************************************************************************
  * Take whatever actions required to place the system in graphics mode
  * and ensure resolution is at least 640 x 480 pixels. The coordinate
  * convention requires the the screen top/left is (0, 0).
  * RETURNS:    TRUE  .. ready for operation
  *             FALSE .. unable to set graphics mode
  */
  BOOL GfxInit (void)
  {
    int gdriver, gmode, errorcode;
    static char *pszEmsg = "RCOS: %s!\n";
    static char *pszErrs[] = {"Graphics initialization error",
			     "Insufficient display resolution"};

    gdriver = DETECT;
    initgraph(&gdriver, &gmode, NULL);
    errorcode = graphresult();
    if (errorcode != 0)
      fprintf(stderr, pszEmsg, pszErrs[0]);
    else {
      nFillStyle = GFX_Solid;
      if ((getmaxx()+1 >= GFX_Xmin) && (getmaxy()+1 >= GFX_Ymin)) {
	GfxClrClip();
	return(TRUE);
      }
      GfxClose();
      fprintf(stderr, pszEmsg, pszErrs[1]);
    }
    return FALSE;
  }

  /*************
  * Return system to "normal" operation.
  */
  void GfxClose (void)
  {
    closegraph();
  }

  /*************
  * We can't actually set a clipping reigon using the BGI.  The best
  * alternate is to set a viewport (refer UCQ 84247, Graphics) which
  * makes subsequent output relative to the top left corner, then
  * set a switch and store the origin as an offset which needs to be
  * subrtacted from all coordinates while the switch is set (uugh).
  */
  void GfxSetClip (INT16 x1, INT16 y1, INT16 x2, INT16 y2)
  {
    bVpActive = TRUE;
    vpxo = x1, vpyo = y1;
    setviewport(x1, y1, x2, y2, TRUE);
  }

  /**********
  * Permit drawing of graphics and text fonts anywhere on "our" screen..
  */
  void GfxClrClip (void)
  {
    bVpActive = FALSE;
    vpxo = 0, vpyo = 0;
    setviewport(0, 0, GFX_Xmin-1, GFX_Ymin-1, TRUE);
  }

  /**********
  * Set the position for the next operation..
  */
  void GfxMoveTo (INT16 x, INT16 y)
  {
    if (bVpActive)
      moveto(x-vpxo, y-vpyo);
    else
      moveto(x, y);
  }

  /*************
  * Draw a line from the "current" location to the passed location
  * using the current color.
  */
  void GfxLineTo (INT16 x, INT16 y)
  {
    setcolor(nFgColor);
    if (bVpActive)
      lineto(x-vpxo, y-vpyo);
    else
      lineto(x, y);
  }

  /*************
  * Returns the number of pixels the string argument will occupy
  */
  UINT16 GfxTextExtent (char *str)
  {
    return (UINT16)textwidth(str);
  }

  /*************
  * Returns the height (in pixels) of a text character cell. ASIDE: why
  * does the BGI need a parameter? ENDOFASIDE.  Note:  I have increased
  * the cell height set by Borland for aesthetic reasons. The 
  * routine compensates accordingly.
  */
  UINT16 GfxTextHeight (void)
  {
    return (UINT16)(textheight("I") + 2);
  }

  /*************
  * Set the graphics fill mode to specified pattern
  */
  void GfxPattern (UINT16 nStyle)
  {
    nFillStyle = nStyle;
  }

  /*************
  * Sets the foreground color for text output
  */
  void GfxTextColor (UINT16 nColor)
  {
    nFgColor = nColor;
  }

  /*************
  * Sets the background color for text outout
  */
  void GfxTextColorBg (UINT16 nColor)
  {
    nBgColor = nColor;
  }

  /*************
  * Draw a circle, centred on  of radius , in passed style
  * and color.  NOTE: Ignores clipping! (see also color lament above).
  */
  void GfxCircle (INT16 x, INT16 y, INT16 nRad, UINT16 nStyle, UINT16 nColor)
  {
    if (bVpActive)
      x -= vpxo, y -= vpyo;
    setcolor(nColor);
    switch (nStyle) {
      case GFX_Frame:
	circle(x, y, nRad);
	break;
      case GFX_Fill:
	setfillstyle(SOLID_FILL, nColor);
	fillellipse(x, y, nRad, nRad);
	break;
    }
  }

  /***************
  * Draw an arc centred on  of radius , beginning at 
  * degrees (zero is straight up), ending at  degrees.
  * NOTE: Ignores clipping!
  */
  void GfxArc (INT16 x, INT16 y, INT16 nRad,
	       double dStart, double dEnd, UINT16 nColor)
  {
    if (bVpActive)
      x -= vpxo, y -= vpyo;
    setcolor(nColor);
    arc(x, y, (int)dStart, (int)dEnd, nRad);
  }

  /*************
  * Draw a rectangle bracketed by  (Top Left) and 
  * (Bottom Right), of passed style and Color.  NOTE: Ignores clipping!
  * This one is real bad.  There is simply no way that the background color
  * in the filled area can be anything other than BGI color zero (normally
  * black).  This means we can't dither new and attractive shades like the
  * Microsoft code can - jeeze.
  */
  void GfxRect (INT16 x1, INT16 y1,
		INT16 x2, INT16 y2, UINT16 nStyle, UINT16 nColor)
  {
    if (bVpActive)
      x1 -= vpxo, y1 -= vpyo, x2 -= vpxo, y2 -= vpyo;
    setcolor(nColor);
    if (nStyle == GFX_Frame)
      rectangle(x1, y1, x2, y2);
    if (nStyle == GFX_Fill) {
      setfillstyle(SOLID_FILL, nColor);
      bar(x1, y1, x2, y2);
    }
    if ((nFillStyle != GFX_Solid) && (nBgColor != nColor)) {
      setfillpattern(((nFillStyle == GFX_HalfTone)?pDotMask1:pDotMask2),
	nBgColor);
      floodfill(x1+1, y1+1, _Black);
    }
  }

  /*************
  * Draw the passed text string at the passed location, in the passed style,
  * using the current colors (point  marks top/left of text extent).
  */
  void GfxText (INT16 x, INT16 y, char *st, UINT16 nStyle)
  {
    if (nStyle == GFX_Transparent) {
      if (bVpActive)
	x -= vpxo, y -= vpyo;
      setcolor(nFgColor);
      outtextxy(x, y+1, st);
    }
  }

  /*************
  * Allocate a mamory block to hold the bounded screen image bit map
  * in the passed co-ords and store it.
  * RETURNS: pointer to storage, or NULL if unable to comply
  */
  PIMBUF GfxGetImage (INT16 x1, INT16 y1, INT16 x2, INT16 y2)
  {                                                          
    PIMBUF p;
    
    if (p = farmalloc((unsigned long)imagesize(x1, y1, x2, y2)) ) {
      if (bVpActive)
	x1 -= vpxo, y1 -= vpyo, x2 -= vpxo, y2 -= vpyo;
      getimage(x1, y1, x2, y2, p);
    }
    return p;
  }

  /*************
  * copy the image in the passed buffer to the screen at x, y
  */
  BOOL GfxPutImage (INT16 x, INT16 y, PIMBUF p)
  {
    if (bVpActive)
      x -= vpxo, y -= vpyo;
    putimage(x, y, p, COPY_PUT);
    return(TRUE);
  }

  /*************
  * copy the image in the passed buffer to the screen at x, y
  * then release the storage.
  */
  void GfxFreeImage (PIMBUF p)
  {
    if (p)
      farfree((void far*)p);
  }


#endif     /******************* END BORLAND C/C++ 3.1 ********************/

/********************************** eof **********************************/