/* graph1.c (emx+gcc) -- Copyright (c) 1987-1993 by Eberhard Mattes */

#include <stdlib.h>
#include <graph.h>
#include <dos.h>
#include <memory.h>
#include <sys/hw.h>
#define INCL_DOSMEMMGR
#define INCL_DOSPROCESS
#define INCL_VIO
#include <os2emx.h>
#include <os2thunk.h>
#include "graph2.h"

#define FALSE 0
#define TRUE  1

static int graph_mode = 0;
static int setmode = 0;
static int old_mode_number = 3;
static int _g_save_saved = 0;
static int _g_save_segsize = 0;

#if 0
static void *_g_save_buf = NULL;
#endif

static VIOMODEINFO old_vio_mode;
static VIOMODEINFO new_vio_mode;
static VIOPHYSBUF phys;

int g_xsize = 1;
int g_ysize = 1;
int g_colors = 1;

int _g_xsize = 1;
int _g_ysize = 1;
int _g_colors = 1;

int _g_clipx0 = 0;
int _g_clipy0 = 0;
int _g_clipx1 = 0;
int _g_clipy1 = 0;

int _g_locklevel = 0;

unsigned char *_g_mem = NULL;

static int g_mode_on (int width, int height, int mode_number);
static void g_mode_off (void);
static void g_mode_vgal (void);
static void g_init2 (void);
static void g_mode_s (void);


int _ggetmode (void)
{
  union REGS r;

  r.h.ah = 0x0f;
  _int86 (0x10, &r, &r);
  return (r.h.al);
}


void _gsetmode (int mode)
{
  union REGS r;

  r.h.ah = 0x00;
  r.h.al = (unsigned char)mode;
  _int86 (0x10, &r, &r);
}


void g_wmode (int wmode)
{
}


void g_lock (void)
{
  BYTE not_locked;

  if (_osmode == OS2_MODE && _g_locklevel == 0)
    {
      ++_g_locklevel;
      VioScrLock (LOCKIO_WAIT, &not_locked, 0);
    }
}


void g_unlockall (void)
{
  if (_g_locklevel != 0)
    {
      _g_locklevel = 1;
      g_unlock ();
    }
}


void g_unlock (void)
{
  if (_osmode == OS2_MODE && _g_locklevel > 0)
    {
      --_g_locklevel;
      if (_g_locklevel == 0)
        VioScrUnLock (0);
    }
}


int g_modeset (int mode, int flag)
{
  g_xsize = g_ysize = g_colors = 1; setmode = 0;
  switch (mode)
    {
    case G_MODE_VGA_L:
      g_xsize = 320; g_ysize = 200; g_colors = 256; setmode = 19;
      break;
    default:
      mode = G_MODE_OFF;
      break;
    }
  return (mode);
}


int g_mode (int mode)
{
  g_unlockall ();
  if (mode == G_MODE_OFF)
    {
      if (graph_mode != 0)
        {
          g_mode_off ();
          graph_mode = 0;
        }
      return (FALSE);
    }
  else
    {
      g_mode (G_MODE_OFF);
      g_lock ();
      if (_osmode == OS2_MODE)
        {
          _g_save_saved = 0;
          old_vio_mode.cb = sizeof (old_vio_mode);
          VioGetMode (&old_vio_mode, 0);
        }
      else
        old_mode_number = _ggetmode ();
      mode = g_modeset (mode, G_SET_KEEP);
      if (setmode == 0)
        {
          g_unlock ();
          return (FALSE);
        }
      _g_xsize = g_xsize; _g_ysize = g_ysize; _g_colors = g_colors;
      _g_clipx0 = 0; _g_clipx1 = _g_xsize - 1;
      _g_clipy0 = 0; _g_clipy1 = _g_ysize - 1;
      switch (setmode)
        {
        case 19:    /* G_MODE_VGA_L */
          _g_save_segsize = _g_xsize * _g_ysize;
          if (!g_mode_on (40, 25, 19))
            {
              g_unlock ();
              return (FALSE);
            }
          g_mode_vgal ();
          break;
        }
      g_wmode (G_NORM);
      graph_mode = setmode;
      g_init2 ();
      g_mode_s ();
      if (_osmode == OS2_MODE)
        g_clear (G_BLACK);
      g_unlock ();
      return (TRUE);
    }
}


static int g_mode_on (int width, int height, int mode_number)
{
  if (_osmode == OS2_MODE)
    {
#if 0
      TID tid;

      if (DosAllocMem (&_g_save_buf, _g_save_segsize,
                       PAG_COMMIT|PAG_READ|PAG_WRITE|OBJ_TILE))
        return (FALSE);
      if (DosCreateThread (&tid, redraw_wait, 0, 2, 0x2000) != 0)
        return (FALSE);
      if (DosCreateThread (&tid, mode_wait, 0, 2, 0x2000) != 0)
        return (FALSE);
#endif
      new_vio_mode = old_vio_mode;
      switch (_g_colors)
        {
        case 4:
          new_vio_mode.color = 2; break;
        case 16:
          new_vio_mode.color = 4; break;
        case 256:
          new_vio_mode.color = 8; break;
        default:
          if (setmode == 15 || setmode == 17)
            new_vio_mode.color = 0;
          else
            new_vio_mode.color = 1;
          break;
        }
      new_vio_mode.fbType |= VGMT_GRAPHICS;
      new_vio_mode.hres = _g_xsize;
      new_vio_mode.vres = _g_ysize;
      new_vio_mode.row = height;
      new_vio_mode.col = width;
      VioSetMode (&new_vio_mode, 0);
      phys.pBuf = (PBYTE)0xa0000;
      phys.cb = 0x10000;
      if (VioGetPhysBuf (&phys, 0) != 0)
        return (FALSE);
      _g_mem = MAKEP (phys.asel[0], 0);
    }
  else
    {
      _gsetmode (mode_number);
      _g_mem = _memaccess (0xa0000, 0xaffff, 1);
      if (_g_mem == NULL)
        return (FALSE);
    }
  return (TRUE);
}


static void g_mode_off (void)
{
  if (_osmode == OS2_MODE)
    {
      VioSetMode (&old_vio_mode, 0);
#if 0
      VioSavRedrawUndo (1, 1, 0);
      VioModeUndo (1, 1, 0);
      DosFreeMem (_g_save_buf);
#endif
    }
  else
    _gsetmode (old_mode_number);
}


static void g_init2 (void)
{
}


static void g_mode_vgal (void)
{
}


static void g_mode_s (void)
{
}


void g_clear (int color)
{
  GLOCK;
  memset (_g_mem, color, 320*200);
  GUNLOCK;
}
