/*****************************************************************************/
/*                                                                           */
/*   VECTREX HP3000 Software Emulator              Copyright K.Wilkins 1996  */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*   Title      : Vectrex emulator text/graphics I/O functions               */
/*                                                                           */
/*   File Name  : IO.C                                                       */
/*                                                                           */
/*   Author     : Keith Wilkins / Christopher Salomon                        */
/*                                                                           */
/*   Version    : 1.20                                                       */
/*                                                                           */
/*   Desciption : This file contains the functions that allow the vectrex    */
/*                emulator to output data to the screen and read data from   */
/*                the keyboard etc..                                         */
/*                                                                           */
/*                These functions are the most PRIMATIVE Level of IO and     */
/*                as such are the fastest. The next level up from here are   */
/*                the window primatives found in WINDOW.C. Hopefully most    */
/*                functions can interface thorugh the upper functions as     */
/*                these provide better control.                              */
/*                                                                           */
/* Changes:       1.2                                                        */
/*                Removed nearly all VESA code of Keith.                     */
/*                It wasn't all that compatible in my opinion                */
/*                Granularity was defined as 64K per default, which is       */
/*                not allways T_TRUE, bank switching was done via interrupt    */
/*                (very time consuming), now via realmode function call,     */
/*                which is still not that good, but I didn't want to fiddle  */
/*                with the 32bit pmode routine provided with VESA 2.0.       */
/*                Furthermore he used to set both, read AND write windows    */
/*                which allways took TWO interrupts to complete!!!           */
/*                                                                           */
/*                I use the function provided by 1.? BIOS extentions.        */
/*                I used the SVGALIB V6.0 from scitech.                      */
/*                The only function call which differs from the version 1.0  */
/*                is:  T_VOID fIOsetpalette(T_VOID)                              */
/*                and palette.h is now an own palette.c file                 */
/*                                                                           */
/*                  Note: LineDraw() function does NO CLIPPING anymore!      */
/*                        Since the emulator uses 'inline' linedrawing which */
/*                        uses clipping, I changed the function not to use   */
/*                        clipping, for drawing windows and the like with    */
/*                        it.                                                */
/*                                                                           */
/*                                                                           */
/*   Functions  : fIOInit()        - Initialise the I/O System               */
/*                fIORestore()     - Restore I/O to its virgin state         */
/*                fIOOutChar()     - Output a single T_CHAR to the screen      */
/*                fIOOutText()     - Output a text string to the screen      */
/*                fIOPrintf()      - PrT_INT a text string to the screen       */
/*                fIOSetClipping() - Set the clipping window                 */
/*                fIOGetScreenRes()- Return the screen size                  */
/*                fIOPlotPixel()   - Plot a pixel                            */
/*                fIOGetPixel()    - get a pixel                             */
/*                fIODrawLine()    - Draw a line                             */
/*                fIODrawBox()     - Draw a box on screen filled/outline     */
/*                fIOAreaSave()    - Save a screen area to memory            */
/*                fIOAreaLoad()    - Load a screen area from memory          */
/*                fIOAreaMove()    - Move a screen area                      */
/*                fIOAreaScroll()  - Scroll a given screen area              */
/*                fIOAreaClear()   - Erase a screen area                     */
/*                fIOload_pcx_overlay() - Load a PCX overlay file            */
/*****************************************************************************/
/*                                                                           */
/*   Revision History:                                                       */
/*                                                                           */
/*   Version    Date    Who  Description of changes                          */
/*   -------    ----    ---  ----------------------                          */
/*                                                                           */
/*    0.01    20/03/93  K.W  Creation                                        */
/*    1.00    05/08/96  K.W  Public release of DVE V1.0                      */
/*    1.20    03/10/96  C.S  Basic functions rewritten                       */
/*                                                                           */
/*****************************************************************************/

/*****************************************************************************/
/* These functions MUST NOT use any fDebug calls as they may be begin used   */
/* to setup the debug window and as such will generate recusive function     */
/* calls until the stack if they call fDebug whilst it is being setup        */
/*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <dos.h>

#include <standard.h>
#include <tools.h>

#include "keyboard.h"
//#include "font.h"
#include "display.h"
#include "vpalette.h"
#include "vectrex.h"
#include "verror.h"
#include "io.h"


/*********************************************************/
/* function prototypes for banked and linear framebuffer */
/*********************************************************/
T_VOID fIOPlotPixellin(T_SWORD iXpos,T_SWORD iYpos,T_SWORD iColour);
T_VOID fIOPlotPixelbank(T_SWORD iXpos,T_SWORD iYpos,T_SWORD iColour);
T_UBYTE fIOGetPixellin(T_SWORD iXpos,T_SWORD iYpos);
T_UBYTE fIOGetPixelbank(T_SWORD iXpos,T_SWORD iYpos);
T_VOID fIODrawLinelin(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iColour);
T_VOID fIODrawLinebank(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iColour);
T_VOID fIODrawMaskLinelin(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iColour);
T_VOID fIODrawMaskLinebank(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iColour);
T_VOID fIOcopyvesascreenlin(T_PUCHAR source,T_SLONG swidth,T_SLONG sheight,T_SLONG bpp);
T_VOID fIOcopyvesascreenbank(T_PUCHAR source,T_SLONG swidth,T_SLONG sheight,T_SLONG bpp);
T_INT fIOAreaLoadlin(T_SWORD iXdest,T_SWORD iYdest,BITBLOCK *tData);
T_INT fIOAreaLoadbank(T_SWORD iXdest,T_SWORD iYdest,BITBLOCK *tData);

BITBLOCK* fIOAreaSavelin(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2);
BITBLOCK* fIOAreaSavebank(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2);

T_UBYTE (* fIOGetPixel) (T_SWORD, T_SWORD);

/***********************************************************/
/* old style functions get pointer to the above at runtime */
/***********************************************************/
T_VOID      (* fIOPlotPixel)(T_SWORD,T_SWORD,T_SWORD);
T_VOID      (* fIODrawMaskLine)(T_SWORD,T_SWORD,T_SWORD,T_SWORD,T_SWORD);
T_VOID      (* fIODrawLine)(T_SWORD,T_SWORD,T_SWORD,T_SWORD,T_SWORD);
T_VOID      (* fIOcopyvesascreen)(T_PUCHAR ,T_SLONG,T_SLONG,T_SLONG);
T_INT       (* fIOAreaLoad)(T_SWORD,T_SWORD,BITBLOCK *);
BITBLOCK*   (* fIOAreaSave)(T_SWORD,T_SWORD,T_SWORD,T_SWORD);

/********************/
/* global variables */
/********************/
T_UWORD  rectengle_clipping_enable=T_TRUE;
T_ULONG  vlinestartpos[MAX_SCREEN_LINES];
T_PUCHAR  overlay_memory=NULL;
T_INT vio_initialised=T_FALSE;

T_BYTE mousepointer_vectrex[8*8]=
{
 2,2,2,2,2,2,2,0,
 2,1,1,1,1,2,0,0,
 2,1,1,2,2,0,0,0,
 2,1,2,1,2,0,0,0,
 2,1,2,2,1,2,0,0,
 2,2,0,0,2,1,2,0,
 2,0,0,0,0,2,1,2,
 0,0,0,0,0,0,2,2,
};
MOUSE_POINTER vectrex_mousepointer={8,8,mousepointer_vectrex,2,1,0};

// module variables
static T_SWORD iClippingX1;
static T_SWORD iClippingY1;
static T_SWORD iClippingX2;
static T_SWORD iClippingY2;
static FILE *pcx_akt_handle=NULL;
static PCX_HEADER pcx_header;
static T_PUCHAR pcx_load_buffer=NULL;
static T_UWORD pcx_muss_gelesen_werden=T_FALSE;
static T_INT pcx_buffer_counter=0;

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOInit()                                                 */
/*                                                                           */
/*   Author      : original K.W now C.S.                                     */
/*                                                                           */
/*   Description : This function sets the screen mode and any other IO module*/
/*                 variables such as cursor position. It also sets the       */
/*                 screen pallette.                                          */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/
T_INT fIOInit(T_VOID)
{
 T_INT   loop;
 T_ULONG screenmem;
/************************/
/* Sanity check on mode */
/************************/
 if(wGblDisplayMode>=RESOLUTION_COUNT)
 {
  fFatal("fIOinit() - Invalid display mode chosen");
 }
/****************/
/*  INIT VESA   */
/****************/
 if (vesa_karte_da()!=T_OK)
 {
  t_printf(E_VERBOSE_NONE,"\nNo Vesa found (SVGALIB)!");
  fFatal("fIOinit() - graphics initialization failed!!!");
 }
 else
 {
  if (bGblDisplayVerbose==T_TRUE)
   t_printf(E_VERBOSE_NONE,"\nVBE Version %i.%i found!",svdc->VBEVersion/256,svdc->VBEVersion-(svdc->VBEVersion/256)*256);
 }
 if (bGblForceVesa12==T_TRUE)
  vesa_force_bank=T_TRUE;
 if (vesa_setze_modus(wGblDisplayMode)!=T_OK)
 {
  fFatal("fIOinit() - corresponding VESA mode not found!!!");
 }
 else if (framebuffer==FB_BANKED)
 {
  if (bGblDisplayVerbose==T_TRUE)
  {
   t_printf(E_VERBOSE_NONE,"\nbanked framebuffer video mode found: %04hx!\n",vesa_modus_active);
  }
  if (bGblDisplayVerbose==T_TRUE)
  {
   t_printf(E_VERBOSE_NONE,"\nlinear framebuffer videonMode found: %04hx!\n",vesa_modus_active);
  }
 }
 if (framebuffer==FB_BANKED)
 {
  fIOPlotPixel=fIOPlotPixelbank;
  fIODrawLine=fIODrawLinebank;
  fIODrawMaskLine=fIODrawMaskLinebank;
  fIOcopyvesascreen=fIOcopyvesascreenbank;
  fIOAreaLoad=fIOAreaLoadbank;
  fIOAreaSave=fIOAreaSavebank;
  fIOGetPixel=fIOGetPixelbank;
 }
 else if (framebuffer==FB_LINEAR)
 {
  fIOPlotPixel=fIOPlotPixellin;
  fIODrawLine=fIODrawLinelin;
  fIODrawMaskLine=fIODrawMaskLinelin;
  fIOcopyvesascreen=fIOcopyvesascreenlin;
  fIOAreaLoad=fIOAreaLoadlin;
  fIOAreaSave=fIOAreaSavelin;
  fIOGetPixel=fIOGetPixellin;
 }
 else
 {
  fFatal("fIOinit() - Unkown VESA initialization ERROR!");
 }
/********************************************/
/* Set default Clipping regions (old style) */
/********************************************/
 iClippingX1=0;
 iClippingY1=0;
 iClippingX2=vesa_x-1;
 iClippingY2=vesa_y-1;

/*******************************************/
/* Setup the array of line start positions */
/* 65536, since a negative line positions  */
/* possible (slight speedup)               */
/*******************************************/
 for (loop=0;loop<MAX_SCREEN_LINES;loop++)
 {
  if (loop < vesa_y)
   vlinestartpos[(T_UWORD)loop]=loop*vesa_bytes_per_scanline;//vesa_x;
  else if (loop < vesa_y+10000)
  {
   vlinestartpos[(T_UWORD)loop]=(vesa_y-1)*vesa_bytes_per_scanline;//vesa_x;
  }
  else
   vlinestartpos[(T_UWORD)loop]=0;
 }

/***************************************************/
/* Setup the colour map that we will use (default) */
/***************************************************/
 fIOsetpalette();
/*******************************/
/* Create overlay memory block */
/*******************************/
// screenmem=(T_ULONG)vesa_x*(T_ULONG)vesa_y;
 screenmem=(T_ULONG)vesa_bytes_per_scanline*(T_ULONG)vesa_y;
 if ((overlay_memory=malloc(screenmem))==NULL)
  fFatal("fIOInit() - Display overlay memory allocation failure (%ld bytes)",screenmem);
 memset(overlay_memory,wGblDisplayBaseColour<<4,screenmem);

 vesa_load_mehrere_dac(0, "tool.dat\\black16g.col");
 init_colors();
/*****************/
/* Init complete */
/*****************/
 vio_initialised=T_TRUE;
 return(T_TRUE);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIORestore()                                              */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Restore the IO system back to the condition it started in */
/*                 by putting the screen back and releasing any borrowed irq */
/*                 functions.                                                */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : T_INTEAN T_TRUE=OK T_FALSE=ERROR                               */
/*                                                                           */
/*****************************************************************************/

T_INT fIORestore(T_VOID)
{
 if (overlay_memory)
 {
  free(overlay_memory);
  overlay_memory=NULL;
 }
 if (vio_initialised)
 {
  vesa_alten_modus_setzen();
 }
 vio_initialised=T_FALSE;
 return(T_TRUE);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOSetClipping()                                          */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Set the clipping rectangle for all printing,plotting and  */
/*                 drawing operations.                                       */
/*                                                                           */
/*   Accepts     : T_INT X and Y Corner window positions                       */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/
T_VOID fIOUnSetClipBox(T_INT iXpos,T_INT iYpos,T_INT iXsize,T_INT iYsize)
{
 T_INT i;
 if (iXpos<0) iXpos=0;
 if (iYpos<0) iYpos=0;
 if (iXpos>vesa_x-1) iXpos=vesa_x-1;
 if (iYpos>vesa_y-1) iYpos=vesa_y-1;
 if (iXsize<0) iXsize=0;
 if (iYsize<0) iYsize=0;
 if (iXpos+iXsize>vesa_x-1) iXsize=(vesa_x-1)-iXpos;
 if (iYpos+iYsize>vesa_y-1) iYsize=(vesa_y-1)-iYpos;
 for (i=iYpos;i<=iYsize;i++)
  memset(clip_memory+vlinestartpos[(T_UWORD)i]+iXpos,0,iXsize-iXpos);
}
T_VOID fIOSetClipBox(T_INT iXpos,T_INT iYpos,T_INT iXsize,T_INT iYsize)
{
 T_INT i;
 if (iXpos<0) iXpos=0;
 if (iYpos<0) iYpos=0;
 if (iXpos>vesa_x-1) iXpos=vesa_x-1;
 if (iYpos>vesa_y-1) iYpos=vesa_y-1;
 if (iXsize<0) iXsize=0;
 if (iYsize<0) iYsize=0;
 if (iXpos+iXsize>vesa_x-1) iXsize=(vesa_x-1)-iXpos;
 if (iYpos+iYsize>vesa_y-1) iYsize=(vesa_y-1)-iYpos;
 for (i=iYpos;i<=iYsize;i++)
  memset(clip_memory+vlinestartpos[(T_UWORD)i]+iXpos,1,iXsize-iXpos);
}
T_VOID fIOSetClipping(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2)
{
 T_INT i;
 /******************************************/
 /* Do a sanity check and make sure X1,Y1  */
 /* is upper left and X2,Y2 is lower right */
 /******************************************/
 if(iX1>iX2)
  fSwap(&iX1,&iX2);
 if(iY1>iY2)
  fSwap(&iY1,&iY2);

 if ((iY1==-1)||(iY2==-1)||(iX1==-1)||(iX2==-1))
 {
  iX1=0;
  iX2=vesa_x-1;
  iY1=0;
  iY2=vesa_y-1;
 }
 if (iX1<0)          iX1=0;
 if (iX1>vesa_x-1)   iX1=vesa_x-1;

 if (iY1<0)          iY1=0;
 if (iY1>vesa_y-1)   iY1=vesa_y-1;

 if (iX2<0)          iX2=vesa_x-1;
 if (iX2>vesa_x-1)   iX2=vesa_x-1;

 if (iY2<0)          iY2=vesa_y-1;
 if (iY2>vesa_y-1)   iY2=vesa_y-1;

 /*********************************************************/
 /* If any parameters are -1 then set MAX clipping window */
 /*********************************************************/
 if (rectengle_clipping_enable==T_TRUE)
 {
  /******************/
  /* First Clip all */
  /******************/
  for (i=0;i<vesa_y;i++)
   memset(clip_memory+vlinestartpos[(T_UWORD)i],1,vesa_x);
  /****************************************/
  /* Then set region which is 'unclipped' */
  /****************************************/
  for (i=iY1;i<iY2+1;i++)
   memset(clip_memory+vlinestartpos[(T_UWORD)i]+iX1,0,iX2-iX1);
 }
 iClippingX1=iX1;
 iClippingY1=iY1;
 iClippingX2=iX2;
 iClippingY2=iY2;
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOGetScreenRes()                                         */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Returns the current screen X,Y and Z resolution in a PIXEL*/
/*                 structure.                                                */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : PIXEL with X,Y and colour resolutions                     */
/*                                                                           */
/*****************************************************************************/
PIXEL fIOGetScreenRes(T_VOID)
{
 PIXEL   tsResolution;

 tsResolution.iXpos=vesa_x;
 tsResolution.iYpos=vesa_y;
 tsResolution.iColour=iScreenZres;

 return(tsResolution);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOGetOverlayBuffer()                                     */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Returns address of overlay buffer                         */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : ptr to overlay buffer                                     */
/*                                                                           */
/*****************************************************************************/

T_PUCHAR  fIOGetOverlayBuffer(T_VOID)
{
 return(overlay_memory);
}
/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOGetClipBuffer()                                        */
/*                                                                           */
/*   Author      : C.S                                                       */
/*                                                                           */
/*   Description : Returns address of overlay buffer                         */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : ptr to overlay buffer                                     */
/*                                                                           */
/*****************************************************************************/
T_PUCHAR  fIOGetClipBuffer(T_VOID)
{
 return(clip_memory);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIODrawBox()                                              */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Draws either a filled or a box outline using the          */
/*                                                                           */
/*   Accepts     : PIXELs given box corners and colour                       */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_VOID fIODrawBox(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iColour,T_INT tSolid)
{
 T_UWORD yloop;

 /******************************************/
 /* Do a sanity check and make sure X1,Y1  */
 /* is upper left and X2,Y2 is lower right */
 /******************************************/
 if(iX1>iX2)
  fSwap(&iX1,&iX2);
 if(iY1>iY2)
  fSwap(&iY1,&iY2);

 /**********************/
 /* Set the BOX colour */
 /**********************/
 /*******************************/
 /* Draw filled or unfilled box */
 /*******************************/
 if (tSolid)
 {
  for(yloop=iY1;yloop<=iY2;yloop++)
   fIODrawLine(iX1,yloop,iX2,yloop,iColour);
 }
 else
 {
  fIODrawLine(iX1,iY1,iX2,iY1,iColour);
  fIODrawLine(iX1,iY2,iX2,iY2,iColour);
  fIODrawLine(iX1,iY1,iX1,iY2,iColour);
  fIODrawLine(iX2,iY1,iX2,iY2,iColour);
 }
}
/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOAreaClear()                                            */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Clear an area back to the backgrounf colour.              */
/*                                                                           */
/*   Accepts     : PIXELs given box corners and colour                       */
/*                                                                           */
/*   Returns     : T_INTEAN to say if area was cleared or not                 */
/*                                                                           */
/*****************************************************************************/
T_VOID fIOAreaClear(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iBackgroundColour)
{
 if(iX1==-1) iX1=0;
 if(iX2==-1) iX2=vesa_x-1;
 if(iY1==-1) iY1=0;
 if(iY2==-1) iY2=vesa_y-1;

 fIODrawBox(iX1,iY1,iX2,iY2,iBackgroundColour,BOX_FILLED);
 return;
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fGFXsetInk()                                              */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Change pen colour                                         */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : PIXEL struct                                              */
/*                                                                           */
/*****************************************************************************/
T_VOID fIOsetink(T_UWORD iInk,T_UBYTE ubRed,T_UBYTE ubGreen,T_UBYTE ubBlue)
{
 vpalette[iInk][PRED]=ubRed;
 vpalette[iInk][PGREEN]=ubGreen;
 vpalette[iInk][PBLUE]=ubBlue;
 return;
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fGFXsetpalette()                                          */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Wham down a new pallete during the vertical re-trace      */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : PIXEL struct                                              */
/*                                                                           */
/*****************************************************************************/
T_VOID fIOsetpalette(T_VOID)
{
 vesa_set_palette(vpalette);
 vesa_load_mehrere_dac(224, "tool.dat\\16colors.col");
 return;
}

/*************************************************************************/


/************************************************************************/
/* with all following functions I do NOT CHECK if iX1<0 this shouldn't  */
/* matter as long as iY1 is not 0                                       */
/*                                                                      */
/* the same goes for iX2>iScreenResX and iY2=iScreenResY                */
/*                                                                      */
/* The poT_INT of not checking is speed.                                  */
/* If the Scaling factors are set correctly nothing bad should come out */
/* of it, but if one tends to fill the entire screen with vectrex       */
/* or I dunno what... If the above should occure a PAGE Fault           */
/* WILL come down on you!!!                                             */
/************************************************************************/




/*****************************/
/* from here linear funtions */
/*****************************/

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOcopyvesascreen()                                       */
/*                                                                           */
/*   Author      : K.W from original code by P.Jones (fil@muon.demon.co.uk)  */
/*                                                                           */
/*   Description : Copys a screen buffer to the active screen area           */
/*                                                                           */
/*   Accepts     : Pointer to source buffer size, width & depth              */
/*                                                                           */
/*   Returns     : nowt                                                      */
/*                                                                           */
/*****************************************************************************/

T_VOID fIOcopyvesascreenlin(T_PUCHAR source,T_SLONG swidth,T_SLONG sheight,T_SLONG bpp)
{
 memcpy(svdc->videoMem,(T_VOID *)source,vesa_bytes_per_scanline*vesa_y);//vesa_x*vesa_y);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOPlotPixel()                                            */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Plot a Pixel to the screen, pixels are checked for screen */
/*                 boundaries before plotting.                               */
/*                                                                           */
/*   Accepts     : PIXEL giving position and colour                          */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/
T_VOID fIOPlotPixellin(T_SWORD iXpos,T_SWORD iYpos,T_SWORD iColour)
{
// if (*(clip_memory+vlinestartpos[(T_UWORD)iYpos]+(T_ULONG)iXpos))
//  return;
 /*******************************************/
 /* Calulate byte position + Write the byte */
 /*******************************************/
 *(((T_PUCHAR )svdc->videoMem)+vlinestartpos[(T_UWORD)iYpos]+(T_ULONG)iXpos)=(T_UBYTE)iColour;
}
T_UBYTE fIOGetPixellin(T_SWORD iXpos,T_SWORD iYpos)
{
 /*******************************************/
 /* Calulate byte position + Read the byte */
 /*******************************************/
 return (*(((T_PUCHAR )svdc->videoMem)+vlinestartpos[(T_UWORD)iYpos]+(T_ULONG)iXpos));
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIODrawLine()                                             */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Draws a line on the screen clipped to the screen boundary */
/*                 and in the given colour.                                  */
/*                                                                           */
/*   Accepts     : PIXELs given start and end position of line and colour    */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/
T_VOID fIODrawLinelin(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iColour)
{
 T_PUCHAR dest=(T_PUCHAR )svdc->videoMem;
 T_SWORD dx=0,dy=0,err=0,inc=0;

/**************************/
/* Do straight line cases */
/**************************/
 if(iX1==iX2)
 {
  if(iY1>iY2)
  {
   fSwap(&iY1,&iY2);
  }
  do
  {
   /******************************************************************************************/
   /* not to be put out of loop, offset can get to high... (high iY1 are pointing to maxline)*/
   /******************************************************************************************/
   offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
//   if (!(*(clip_memory+offset)))
   {
    *(dest+offset)=iColour;
   }
  }
  while(iY1++!=iY2);
 }
 else if(iY1==iY2)
 {
  if(iX1>iX2)
  {
   fSwap(&iX1,&iX2);
  }
  offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
  do
  {
//   if (!(*(clip_memory+offset)))
   {
    *(dest+offset)=iColour;
   }
   offset++;
  }
  while(iX1++!=iX2);
 }
 else
 {
  /*************/
  /* X Variant */
  /*************/
  dx=iX2-iX1;
  dy=iY2-iY1;
  if(abs(dx)>=abs(dy))
  {
   if(iX1>iX2)
   {
    fSwap(&iX1,&iX2);
    fSwap(&iY1,&iY2);
   }
   dx=iX2-iX1;
   dy=iY2-iY1;
   err=-(dx>>1);
   if(dy>0)
   {
    inc=1;
   }
   else
   {
    inc=-1;
    dy=-dy;
   }
   do
   {
    /**************************/
    /* Calulate byte position */
    /**************************/
    offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
//    if (!(*(clip_memory+offset)))
    {
     *(dest+offset)=iColour;
    }
    /**********************/
    /* Check error status */
    /**********************/
    err+=dy;
    if(err>0)
    {
     err-=dx;
     iY1+=inc;
    }
   }
   while(iX1++!=iX2);
  }
  else
  {
   if(iY1>iY2)
   {
    fSwap(&iX1,&iX2);
    fSwap(&iY1,&iY2);
   }
   dx=iX2-iX1;
   dy=iY2-iY1;
   err=-(dy>>1);
   if(dx>0)
   {
    inc=1;
   }
   else
   {
    inc=-1;
    dx=-dx;
   }
   do
   {
    /**************************/
    /* Calulate byte position */
    /**************************/
    offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
//    if (!(*(clip_memory+offset)))
    {
     *(dest+offset)=iColour;
    }
    /**********************/
    /* Check error status */
    /**********************/
    err+=dx;
    if(err>=0)
    {
     err-=dy;
     iX1+=inc;
    }
   }
   while(iY1++!=iY2);
  }
 }
}
/*****************************************************************************/
/*                                                                           */
/*   Function    : fIODrawMaskLine()                                         */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Draws a line on the screen clipped to the screen boundary */
/*                 and in the given colour BUT ALL screen writes are OR'd    */
/*                 with the overlay memory BEFORE being written.             */
/*                                                                           */
/*   Accepts     : PIXELs given start and end position of line and colour    */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_VOID fIODrawMaskLinelin(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iColour)
{
 T_SWORD   dx=0,dy=0,err=0,inc=0;
 T_UBYTE   *dest=(T_PUCHAR )svdc->videoMem;
 T_UBYTE   data;
 /**************************/
 /* Do straight line cases */
 /**************************/
 if(iX1==iX2)
 {
  if(iY1>iY2)
  {
   fSwap(&iY1,&iY2);
  }
  do
  {
   /******************************************************************************************/
   /* not to be put out of loop, offset can get to high... (high iY1 are pointing to maxline)*/
   /******************************************************************************************/
   offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
   if (!(*(clip_memory+offset)))
   {
    data=(T_UBYTE)iColour | *(overlay_memory+offset);
    *(dest+offset)=data;
   }
  }
  while(iY1++!=iY2);
 }
 else if (iY1==iY2)
 {
  if (iX1>iX2)
  {
   fSwap(&iX1,&iX2);
  }
  offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
  do
  {
   if (!(*(clip_memory+offset)))
   {
    data=(T_UBYTE)iColour | *(overlay_memory+offset);
    *(dest+offset)=data;
   }
   offset++;
  }
  while(iX1++!=iX2);
 }
 else
 {
  /*************/
  /* X Variant */
  /*************/
  dx=iX2-iX1;
  dy=iY2-iY1;

  if (abs(dx)>=abs(dy))
  {
   if (iX1>iX2)
   {
    fSwap(&iX1,&iX2);
    fSwap(&iY1,&iY2);
   }
   dx=iX2-iX1;
   dy=iY2-iY1;

   err=-(dx>>1);
   if (dy>0)
   {
    inc=1;
   }
   else
   {
    inc=-1;
    dy=-dy;
   }
   do
   {
    /**************************/
    /* Calulate byte position */
    /**************************/
    offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
    if (!(*(clip_memory+offset)))
    {
     data=(T_UBYTE)iColour | *(overlay_memory+offset);
     *(dest+offset)=data;
    }
    /**********************/
    /* Check error status */
    /**********************/
    err+=dy;
    if(err>0)
    {
     err-=dx;
     iY1+=inc;
    }
   }
   while(iX1++!=iX2);
  }
  else
  {
   if(iY1>iY2)
   {
    fSwap(&iX1,&iX2);
    fSwap(&iY1,&iY2);
   }
   dx=iX2-iX1;
   dy=iY2-iY1;

   err=-(dy>>1);
   if (dx>0)
   {
    inc=1;
   }
   else
   {
    inc=-1;
    dx=-dx;
   }
   do
   {
    /**************************/
    /* Calulate byte position */
    /**************************/
    offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
    if (!(*(clip_memory+offset)))
    {
     data=(T_UBYTE)iColour | *(overlay_memory+offset);
     *(dest+offset)=data;
    }
    /**********************/
    /* Check error status */
    /**********************/
    err+=dx;

    if (err>=0)
    {
     err-=dy;
     iX1+=inc;
    }
   }
   while(iY1++!=iY2);
  }
 }
}
/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOAreaSave()                                             */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Save a screen area and return a pointer to a bitbloc      */
/*                 structure containing a pointer to the data. The user must */
/*                 use fIOBitBlockRelease() to free an unwanted block.       */
/*                                                                           */
/*                                                                           */
/*   Accepts     : PIXELs giving Area boundaries                             */
/*                                                                           */
/*   Returns     : Pointer to save bitblock area                             */
/*                                                                           */
/*****************************************************************************/

BITBLOCK* fIOAreaSavelin(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2)
{
 BITBLOCKPTR   tBlock=NULL;
 T_ULONG         lImageSize;
 T_ULONG         src;
 T_UBYTE         *base=(T_PUCHAR )svdc->videoMem;
 T_UBYTE         *dest;
 T_UWORD         xloop,yloop;

 /********************************************************************************/
 /* Do a sanity check and make sure X1,Y1 is upper left and X2,Y2 is lower right */
 /********************************************************************************/
 if (iX1>iX2)
  fSwap(&iX1,&iX2);
 if (iY1>iY2)
  fSwap(&iY1,&iY2);

 /************************************************/
 /* Malloc some space for the bitblock structure */
 /************************************************/
 if ((tBlock=malloc(sizeof(BITBLOCK)))==NULL)
 {
  fFatal("I/O ERROR: fIOAreaSave() malloc Failed for BITBLOCK structure");
  return(NULL);
 }

 /*************************************/
 /* Calc the image size and malloc it */
 /*************************************/
 lImageSize=((iX2-iX1)+1)*((iY2-iY1)+1);
 if ((dest=tBlock->tBlockData=(T_PUCHAR )malloc(lImageSize*sizeof(T_UBYTE)))==NULL)
 {
  fFatal("I/O ERROR: fIOAreaSave() malloc failed for image");
  free(tBlock);
  return(NULL);
 }

 /*************************************/
 /* Now get the image into the buffer */
 /*************************************/
 tBlock->width=(iX2-iX1)+1;
 tBlock->height=(iY2-iY1)+1;
// src=(iY1*vesa_x)+iX1;
 src=(iY1*vesa_bytes_per_scanline)+iX1;
 for(yloop=iY1;yloop<=iY2;yloop++)
 {
  for(xloop=iX1;xloop<=iX2;xloop++)
  {
   *(dest++)=*(base+(src++));
  }
//  src+=vesa_x-tBlock->width;
  src+=vesa_bytes_per_scanline-tBlock->width;
 }

 /*************************/
 /* Set the Magic numbers */
 /*************************/
 tBlock->tBitblockMagicNumber1=0xa55aa55al;
 tBlock->tBitblockMagicNumber2=0xa55aa55al;

 return(tBlock);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOAreaLoad()                                             */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Loads a saved image into an area, erasing the old area.   */
/*                                                                           */
/*   Accepts     : PIXEL pointing to load position and block pointer         */
/*                                                                           */
/*   Returns     : T_INTEAN to say if area was loaded sucessfully             */
/*                                                                           */
/*****************************************************************************/

T_INT fIOAreaLoadlin(T_SWORD iXdest,T_SWORD iYdest,BITBLOCK *tData)
{
 T_UBYTE         *base=(T_PUCHAR )svdc->videoMem;
 T_UBYTE         *src;
 T_UWORD         xloop,yloop;
 T_ULONG         dest;

 if(tData->tBitblockMagicNumber1 != tData->tBitblockMagicNumber2)
 {
  fFatal("I/O ERROR: fIOAreaLoad() Bad Block Handle, aborting load");
 }
 else
 {
  /*************************************/
  /* Now get the image into the buffer */
  /*************************************/
  //dest=(iYdest*vesa_x)+iXdest;
  dest=(iYdest*vesa_bytes_per_scanline)+iXdest;
  src=tData->tBlockData;
  for(yloop=iYdest;yloop<iYdest+tData->height;yloop++)
  {
   for(xloop=iXdest;xloop<iXdest+tData->width;xloop++)
   {
    /*****************************************/
    /* Check clipping and reject if required */
    /*****************************************/
    if (xloop>=iClippingX1 && xloop<=iClippingX2 && yloop>=iClippingY1 && yloop<=iClippingY2)
    {
     *(base+dest)=*src;
    }
    dest++;
    src++;
   }
//   dest+=vesa_x-(tData->width);
   dest+=vesa_bytes_per_scanline-(tData->width);
  }
 }
 return(T_TRUE);
}





/*******************************************************************/
/* Note all banked functions would get a 'great' speed increase if */
/* a check was done for if a new bank is reached within the        */
/* actual bounderies..., than go for it straight on without any    */
/* further checking... or perhaps even draw in parts...            */
/*                                                                 */
/* I didn't do it 'cause I'm lazy and I                            */
/* have a linear framebuffer grafics card...                       */
/*******************************************************************/

/*****************************/
/* from here banked funtions */
/*****************************/
/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOcopyvesascreen()                                       */
/*                                                                           */
/*   Author      : K.W from original code by P.Jones (fil@muon.demon.co.uk)  */
/*                                                                           */
/*   Description : Copys a screen buffer to the active screen area           */
/*                                                                           */
/*   Accepts     : Pointer to source buffer size, width & depth              */
/*                                                                           */
/*   Returns     : nowt                                                      */
/*                                                                           */
/*****************************************************************************/

T_VOID fIOcopyvesascreenbank(T_PUCHAR source,T_SLONG swidth,T_SLONG sheight,T_SLONG bpp)
{
 T_INT i;
 vesa_address_of_window[vesa_write_window]=0;
 vesa_set_write_window();
// for (i=0;i<=((vesa_x*vesa_y+1023)/1024)/vesa_granularity;i++)
 for (i=0;i<=((vesa_bytes_per_scanline*vesa_y+1023)/1024)/vesa_granularity;i++)
 {
  memcpy((T_VOID *)vesa_write_seg,(T_VOID *)source,vesa_granularity*1024);
  source+=vesa_granularity*1024;
  vesa_address_of_window[vesa_write_window]++;
  vesa_set_write_window();
 }
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOPlotPixel()                                            */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Plot a Pixel to the screen, pixels are checked for screen */
/*                 boundaries before plotting.                               */
/*                                                                           */
/*   Accepts     : PIXEL giving position and colour                          */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/
T_VOID fIOPlotPixelbank(T_SWORD iXpos,T_SWORD iYpos,T_SWORD iColour)
{
 /*******************************************/
 /* Calulate byte position + Write the byte */
 /*******************************************/
 offset=iXpos+vlinestartpos[(T_UWORD)iYpos];
 offset_x=(T_UWORD)(offset&vesa_and_x);
 if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
 {
  vesa_address_of_window[vesa_write_window]=new_win_address;
  vesa_set_write_window();
 }
 *((T_PUCHAR )(vesa_write_seg+offset_x))=(T_UBYTE)iColour;
}

T_UBYTE fIOGetPixelbank(T_SWORD iXpos,T_SWORD iYpos)
{
 /*******************************************/
 /* Calulate byte position + Read the byte */
 /*******************************************/
 offset=iXpos+vlinestartpos[(T_UWORD)iYpos];
 offset_x=(T_UWORD)(offset&vesa_and_x);
 if (vesa_address_of_window[vesa_read_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
 {
  vesa_address_of_window[vesa_read_window]=new_win_address;
  vesa_set_read_window();
 }
 return (*((T_PUCHAR )(vesa_read_seg+offset_x)));
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIODrawLine()                                             */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Draws a line on the screen clipped to the screen boundary */
/*                 and in the given colour.                                  */
/*                                                                           */
/*   Accepts     : PIXELs given start and end position of line and colour    */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/
T_VOID fIODrawLinebank(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iColour)
{
 T_SWORD   dx=0,dy=0,err=0,inc=0;
 /**************************/
 /* Do straight line cases */
 /**************************/
 if(iX1==iX2)
 {
  if(iY1>iY2)
  {
   fSwap(&iY1,&iY2);
  }
  do
  {
   /******************************************************************************************/
   /* not to be put out of loop, offset can get to high... (high iY1 are pointung to maxline)*/
   /******************************************************************************************/
   offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
//   if (!(*(clip_memory+offset)))
   {
    offset_x=(T_UWORD)(offset&vesa_and_x);
    if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
    {
     vesa_address_of_window[vesa_write_window]=new_win_address;
     vesa_set_write_window();
    }
    *((T_PUCHAR )(vesa_write_seg+offset_x))=(T_UBYTE)iColour;
   }
  }
  while(iY1++!=iY2);
 }
 else if(iY1==iY2)
 {
  if(iX1>iX2)
  {
   fSwap(&iX1,&iX2);
  }
  offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
  do
  {
//   if (!(*(clip_memory+offset)))
   {
    offset_x=(T_UWORD)(offset&vesa_and_x);
    if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
    {
     vesa_address_of_window[vesa_write_window]=new_win_address;
     vesa_set_write_window();
    }
    *((T_PUCHAR )(vesa_write_seg+offset_x))=(T_UBYTE)iColour;
   }
   offset++;
  }
  while(iX1++!=iX2);
 }
 else
 {
  /*************/
  /* X Variant */
  /*************/
  dx=iX2-iX1;
  dy=iY2-iY1;
  if(abs(dx)>=abs(dy))
  {
   if(iX1>iX2)
   {
    fSwap(&iX1,&iX2);
    fSwap(&iY1,&iY2);
   }
   dx=iX2-iX1;
   dy=iY2-iY1;
   err=-(dx>>1);
   if(dy>0)
   {
    inc=1;
   }
   else
   {
    inc=-1;
    dy=-dy;
   }
   do
   {
    /**************************/
    /* Calulate byte position */
    /**************************/
    offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
//    if (!(*(clip_memory+offset)))
    {
     offset_x=(T_UWORD)(offset&vesa_and_x);
     if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
     {
      vesa_address_of_window[vesa_write_window]=new_win_address;
      vesa_set_write_window();
     }
     *((T_PUCHAR )(vesa_write_seg+offset_x))=(T_UBYTE)iColour;
    }
    /**********************/
    /* Check error status */
    /**********************/
    err+=dy;
    if(err>0)
    {
     err-=dx;
     iY1+=inc;
    }
   }
   while(iX1++!=iX2);
  }
  else
  {
   if(iY1>iY2)
   {
    fSwap(&iX1,&iX2);
    fSwap(&iY1,&iY2);
   }
   dx=iX2-iX1;
   dy=iY2-iY1;
   err=-(dy>>1);
   if(dx>0)
   {
    inc=1;
   }
   else
   {
    inc=-1;
    dx=-dx;
   }
   do
   {
    /**************************/
    /* Calulate byte position */
    /**************************/
    offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
//    if (!(*(clip_memory+offset)))
    {
     offset_x=(T_UWORD)(offset&vesa_and_x);
     if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
     {
      vesa_address_of_window[vesa_write_window]=new_win_address;
      vesa_set_write_window();
     }
     *((T_PUCHAR )(vesa_write_seg+offset_x))=(T_UBYTE)iColour;
    }
    /**********************/
    /* Check error status */
    /**********************/
    err+=dx;
    if(err>=0)
    {
     err-=dy;
     iX1+=inc;
    }
   }
   while(iY1++!=iY2);
  }
 }
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIODrawMaskLine()                                         */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Draws a line on the screen clipped to the screen boundary */
/*                 and in the given colour BUT ALL screen writes are OR'd    */
/*                 with the overlay memory BEFORE being written.             */
/*                                                                           */
/*   Accepts     : PIXELs given start and end position of line and colour    */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/
T_VOID fIODrawMaskLinebank(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2,T_SWORD iColour)
{
 T_SWORD   dx=0,dy=0,err=0,inc=0;
 T_UBYTE   data;
 /**************************/
 /* Do straight line cases */
 /**************************/
 if(iX1==iX2)
 {
  if(iY1>iY2)
  {
   fSwap(&iY1,&iY2);
  }
  do
  {
   /******************************************************************************************/
   /* not to be put out of loop, offset can get to high... (high iY1 are pointing to maxline)*/
   /******************************************************************************************/
   offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
   if (!(*(clip_memory+offset)))
   {
    data=(T_UBYTE)iColour | *(overlay_memory+offset);
    offset_x=(T_UWORD)(offset&vesa_and_x);
    if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
    {
     vesa_address_of_window[vesa_write_window]=new_win_address;
     vesa_set_write_window();
    }
    *((T_PUCHAR )(vesa_write_seg+offset_x))=(T_UBYTE)data;
   }
  }
  while(iY1++!=iY2);
 }
 else if(iY1==iY2)
 {
  if(iX1>iX2)
  {
   fSwap(&iX1,&iX2);
  }
  offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
  do
  {
   if (!(*(clip_memory+offset)))
   {
    data=(T_UBYTE)iColour | *(overlay_memory+offset);
    offset_x=(T_UWORD)(offset&vesa_and_x);
    if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
    {
     vesa_address_of_window[vesa_write_window]=new_win_address;
     vesa_set_write_window();
    }
    *((T_PUCHAR )(vesa_write_seg+offset_x))=(T_UBYTE)data;
   }
   offset++;
  }
  while(iX1++!=iX2);
 }
 else
 {
  /* X Variant */
  dx=iX2-iX1;
  dy=iY2-iY1;

  if(abs(dx)>=abs(dy))
  {
   if(iX1>iX2)
   {
    fSwap(&iX1,&iX2);
    fSwap(&iY1,&iY2);
   }

   dx=iX2-iX1;
   dy=iY2-iY1;

   err=-(dx>>1);

   if(dy>0)
   {
    inc=1;
   }
   else
   {
    inc=-1;
    dy=-dy;
   }
   do
   {
    /**************************/
    /* Calulate byte position */
    /**************************/
    offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
    if (!(*(clip_memory+offset)))
    {
     data=(T_UBYTE)iColour | *(overlay_memory+offset);
     offset_x=(T_UWORD)(offset&vesa_and_x);
     if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
     {
      vesa_address_of_window[vesa_write_window]=new_win_address;
      vesa_set_write_window();
     }
     *((T_PUCHAR )(vesa_write_seg+offset_x))=(T_UBYTE)data;
    }
    /**********************/
    /* Check error status */
    /**********************/
    err+=dy;
    if (err>0)
    {
     err-=dx;
     iY1+=inc;
    }
   }
   while(iX1++!=iX2);
  }
  else
  {
   if (iY1>iY2)
   {
    fSwap(&iX1,&iX2);
    fSwap(&iY1,&iY2);
   }
   dx=iX2-iX1;
   dy=iY2-iY1;

   err=-(dy>>1);
   if(dx>0)
   {
    inc=1;
   }
   else
   {
    inc=-1;
    dx=-dx;
   }
   do
   {
    /**************************/
    /* Calulate byte position */
    /**************************/
    offset=vlinestartpos[(T_UWORD)iY1]+(T_ULONG)iX1;
    if (!(*(clip_memory+offset)))
    {
     data=(T_UBYTE)iColour | *(overlay_memory+offset);
     offset_x=(T_UWORD)(offset&vesa_and_x);
     if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(offset>>vesa_granularity_potenz)))
     {
      vesa_address_of_window[vesa_write_window]=new_win_address;
      vesa_set_write_window();
     }
     *((T_PUCHAR )(vesa_write_seg+offset_x))=(T_UBYTE)data;
    }
    /**********************/
    /* Check error status */
    /**********************/
    err+=dx;

    if (err>=0)
    {
     err-=dy;
     iX1+=inc;
    }
   }
   while(iY1++!=iY2);
  }
 }
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOAreaSave()                                             */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Save a screen area and return a pointer to a bitbloc      */
/*                 structure containing a pointer to the data. The user must */
/*                 use fIOBitBlockRelease() to free an unwanted block.       */
/*                                                                           */
/*                                                                           */
/*   Accepts     : PIXELs giving Area boundaries                             */
/*                                                                           */
/*   Returns     : Pointer to save bitblock area                             */
/*                                                                           */
/*****************************************************************************/

BITBLOCK* fIOAreaSavebank(T_SWORD iX1,T_SWORD iY1,T_SWORD iX2,T_SWORD iY2)
{
 BITBLOCKPTR   tBlock=NULL;
 T_ULONG         lImageSize;
 T_ULONG         src;
 T_UBYTE         *dest;
 T_UWORD         xloop,yloop;

 /********************************************************************************/
 /* Do a sanity check and make sure X1,Y1 is upper left and X2,Y2 is lower right */
 /********************************************************************************/
 if (iX1>iX2)
  fSwap(&iX1,&iX2);
 if (iY1>iY2)
  fSwap(&iY1,&iY2);

 /************************************************/
 /* malloc some space for the bitblock structure */
 /************************************************/
 if ((tBlock=malloc(1*sizeof(BITBLOCK)))==NULL)
 {
  fFatal("I/O ERROR: fIOAreaSave() malloc Failed for BITBLOCK structure");
  return(NULL);
 }

 /*************************************/
 /* Calc the image size and malloc it */
 /*************************************/
 lImageSize=((iX2-iX1)+1)*((iY2-iY1)+1);
 if ((dest=tBlock->tBlockData=(T_PUCHAR )malloc(lImageSize*sizeof(T_UBYTE)))==NULL)
 {
  fFatal("I/O ERROR: fIOAreaSave() malloc failed for image");
  free(tBlock);
  return(NULL);
 }

 /*************************************/
 /* Now get the image into the buffer */
 /*************************************/
 tBlock->width=(iX2-iX1)+1;
 tBlock->height=(iY2-iY1)+1;

// src=(iY1*vesa_x)+iX1;
 src=(iY1*vesa_bytes_per_scanline)+iX1;
 for(yloop=iY1;yloop<=iY2;yloop++)
 {
  for(xloop=iX1;xloop<=iX2;xloop++)
  {
   offset_x=(T_UWORD)(src&vesa_and_x);
   if (vesa_address_of_window[vesa_read_window]!=(new_win_address=(T_UWORD)(src>>vesa_granularity_potenz)))
   {
    vesa_address_of_window[vesa_read_window]=new_win_address;
    vesa_set_read_window();
   }
   *(dest++)=*((T_PUCHAR )(vesa_read_seg+offset_x));
   src++;
  }
//  src+=vesa_x-tBlock->width;
  src+=vesa_bytes_per_scanline-tBlock->width;
 }

 /*************************/
 /* Set the Magic numbers */
 /*************************/
 tBlock->tBitblockMagicNumber1=0xa55aa55al;
 tBlock->tBitblockMagicNumber2=0xa55aa55al;
 return(tBlock);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fIOAreaLoad()                                             */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Loads a saved image into an area, erasing the old area.   */
/*                                                                           */
/*   Accepts     : PIXEL pointing to load position and block pointer         */
/*                                                                           */
/*   Returns     : T_INTEAN to say if area was loaded sucessfully             */
/*                                                                           */
/*****************************************************************************/

T_INT fIOAreaLoadbank(T_SWORD iXdest,T_SWORD iYdest,BITBLOCK *tData)
{
 T_UBYTE         *src;
 T_UWORD         xloop,yloop;
 T_ULONG         dest;

 if(tData->tBitblockMagicNumber1 != tData->tBitblockMagicNumber2)
 {
  fFatal("I/O ERROR: fIOAreaLoad() Bad Block Handle, aborting load");
 }
 else
 {
  /*************************************/
  /* Now get the image into the buffer */
  /*************************************/
//  dest=(iYdest*vesa_x)+iXdest;
  dest=(iYdest*vesa_bytes_per_scanline)+iXdest;
  src=tData->tBlockData;
  for(yloop=iYdest;yloop<iYdest+tData->height;yloop++)
  {
   for(xloop=iXdest;xloop<iXdest+tData->width;xloop++)
   {
    /*****************************************/
    /* Check clipping and reject if required */
    /*****************************************/
    if (xloop>=iClippingX1 && xloop<=iClippingX2 && yloop>=iClippingY1 && yloop<=iClippingY2)
    {
     offset_x=(T_UWORD)(dest&vesa_and_x);
     if (vesa_address_of_window[vesa_write_window]!=(new_win_address=(T_UWORD)(dest>>vesa_granularity_potenz)))
     {
      vesa_address_of_window[vesa_write_window]=new_win_address;
      vesa_set_write_window();
     }
     *((T_PUCHAR )(vesa_write_seg+offset_x))=*(src);
    }
    dest++;
    src++;
   }
 //  dest+=vesa_x-(tData->width);
   dest+=vesa_bytes_per_scanline-(tData->width);
  }
 }
 return(T_TRUE);
}

/***********************************************/
/* file must be open, handle in pcx_akt_handle */
/* loads some of a pcx file into a buffer      */
/* returns number of bytes read                */
/* sets pcx_muss_gelesen_werden to T_FALSE       */
/* if EOF                                      */
/***********************************************/
T_UWORD vpcx_load_bild_buffer(T_VOID)
{
 T_UWORD fehler=T_FALSE;
 T_UWORD bytes_read=0;
 if (pcx_muss_gelesen_werden==T_TRUE)
 {
  bytes_read=fread(pcx_load_buffer, 1, LOAD_BUFFER_SIZE,pcx_akt_handle);
  if (bytes_read!=LOAD_BUFFER_SIZE)
   pcx_muss_gelesen_werden=T_FALSE;
  pcx_buffer_counter=0;
  fehler=T_TRUE;
 }
 return fehler;
}

/*************************************************************************/

/********************************************************************/
/* loads color information of a pcx file into the 'vectrex-palette' */
/* file must be open and handle in 'pcx_akt_handle'                 */
/* colors 31,47,...223 are 'line-colors', they are graded down to 0 */
/* within their 16 color block                                      */
/* colors 223-239 are 'gui' colors                                  */
/* colors 240-255 are 'border' colors, which are taken directly     */
/* from the file to the palette                                     */
/* vpalette is 8 bit, FARB_TABELLE_256 is usually 6 bit, here used  */
/* only for loading, that means temporarily 8 bit                   */
/********************************************************************/
T_VOID vpcx_get_color256(T_VOID)
{
 T_INT i;
 FARB_TABELLE_256 pcx_256_farb_tabelle;
 fseek(pcx_akt_handle,-768,FROM_FILE_END);
 fread(&pcx_256_farb_tabelle,3,256,pcx_akt_handle);

 /* try for background == 0 differnt from black 1 */
 for (i=0;i<256;i++)
 {
  {
   vpalette[i][PRED]=pcx_256_farb_tabelle.rgb_farben[i].red;
   vpalette[i][PGREEN]=pcx_256_farb_tabelle.rgb_farben[i].green;
   vpalette[i][PBLUE]=pcx_256_farb_tabelle.rgb_farben[i].blue;
  }
 }

 if (bGblLoadColorsExact!=T_TRUE)
 {
  for (i=15+16;i<240;i+=16)
  {
   /****************************/
   /* only process colors != 0 */
   /****************************/
   if (pcx_256_farb_tabelle.rgb_farben[i].red+
       pcx_256_farb_tabelle.rgb_farben[i].green+
       pcx_256_farb_tabelle.rgb_farben[i].blue!=0)
   {
    if (bGblNoShades==T_TRUE)
    {
     T_INT ii;
     for (ii=0;ii<16;ii++)
     {
      vpalette[i-ii][PRED]=pcx_256_farb_tabelle.rgb_farben[i].red;
      vpalette[i-ii][PGREEN]=pcx_256_farb_tabelle.rgb_farben[i].green;
      vpalette[i-ii][PBLUE]=pcx_256_farb_tabelle.rgb_farben[i].blue;
     }
    }
    else
    {
     /******************************************/
     /* scale the color from highest to lowest */
     /******************************************/
     T_INT ii;
     float r,g,b;
     if (pcx_256_farb_tabelle.rgb_farben[i].red-pcx_256_farb_tabelle.rgb_farben[i>>4].red>0)
      r=abs((int) (pcx_256_farb_tabelle.rgb_farben[i].red-pcx_256_farb_tabelle.rgb_farben[i>>4].red))/15;
     else
      r=0;
     if (pcx_256_farb_tabelle.rgb_farben[i].green-pcx_256_farb_tabelle.rgb_farben[i>>4].green>0)
      g=abs((int) (pcx_256_farb_tabelle.rgb_farben[i].green-pcx_256_farb_tabelle.rgb_farben[i>>4].green))/15;
     else
      g=0;
     if (pcx_256_farb_tabelle.rgb_farben[i].blue-pcx_256_farb_tabelle.rgb_farben[i>>4].blue>0)
      b=abs((int) (pcx_256_farb_tabelle.rgb_farben[i].blue-pcx_256_farb_tabelle.rgb_farben[i>>4].blue))/15;
     else
      b=0;
     for (ii=0;ii<16;ii++)
     {
      vpalette[i-ii][PRED]=pcx_256_farb_tabelle.rgb_farben[i].red-r*ii;
      vpalette[i-ii][PGREEN]=pcx_256_farb_tabelle.rgb_farben[i].green-g*ii;
      vpalette[i-ii][PBLUE]=pcx_256_farb_tabelle.rgb_farben[i].blue-b*ii;
      if (ii==0)
      {
       if (vpalette[i][PRED]+20<255)
        vpalette[i][PRED]+=20;
       else
        vpalette[i][PRED]=255;

       if (vpalette[i][PGREEN]+20<255)
        vpalette[i][PGREEN]+=20;
       else
        vpalette[i][PGREEN]=255;

       if (vpalette[i][PBLUE]+20<255)
        vpalette[i][PBLUE]+=20;
       else
        vpalette[i][PBLUE]=255;
      }
     }
    }
   }
  }
 }
 for (i=240;i<256;i++)
 {
  /********************************************/
  /* just takes these colors into the palette */
  /********************************************/
  if (pcx_256_farb_tabelle.rgb_farben[i].red+
      pcx_256_farb_tabelle.rgb_farben[i].green+
      pcx_256_farb_tabelle.rgb_farben[i].blue!=0)
  {
   vpalette[i][PRED]=pcx_256_farb_tabelle.rgb_farben[i].red;
   vpalette[i][PGREEN]=pcx_256_farb_tabelle.rgb_farben[i].green;
   vpalette[i][PBLUE]=pcx_256_farb_tabelle.rgb_farben[i].blue;
  }
 }
}

/**********************************************************************/
/* reads and pcx file to the screen                                   */
/* pcx file MUST HAVE THE SAME SIZE AS SCREEN RESOLUTION!!!           */
/* colors 0-239 are taken as overlay colors, screen set to background */
/*              clipping memory is set to 0                           */
/*              overlay is set to the correspronding color            */
/*                                                                    */
/* colors 240-255 are printed to screen as they are                   */
/*                clipping memory is set to 1                         */
/*                overlay is ignored                                  */
/**********************************************************************/
T_UWORD fIOload_pcx_overlay(T_CHAR *filename)
{
 T_INT zeilen_laenge;
 T_INT zeilen_counter;
 T_INT i;
 T_INT zeilen=0;
 T_UWORD pcx_bild_art=BILD_UNBEKANNT;
 T_UBYTE crunched_wert;
 T_UBYTE anzahl_der_bytes;
 T_PUCHAR overlay_pointer=(T_PUCHAR )overlay_memory;
 T_PUCHAR clip_pointer=(T_PUCHAR )clip_memory;
 T_PCHAR current_path=NULL;

 /*****************/
 /* open PCX file */
 /*****************/
 current_path=get_current_path();
 if (GblPicDir!=NULL)
  change_directory(GblPicDir);
 if (f_file_exist(filename)==T_FALSE)
 {
  if (current_path!=NULL)
  {
   change_directory(current_path);
   free(current_path);
   current_path=NULL;
  }
 }
 if ((pcx_akt_handle=fopen(filename,"rb"))==NULL)
 {
  if (current_path!=NULL)
  {
   change_directory(current_path);
   free(current_path);
   current_path=NULL;
  }
  fFatal("load_pcx_overlay() - Picture not found!");
 }
 /***************************/
 /* read header information */
 /***************************/
 fread(&pcx_header, sizeof(PCX_HEADER), 1, pcx_akt_handle);
 zeilen_laenge=pcx_header.bytes_pro_zeile;

 /*************************************/
 /* is the number of colors correct ? */
 /*************************************/
 if ((pcx_header.bits_pro_pixel==8)&&(pcx_header.anzahl_farbebenen==1))
 {
  /***************************/
  /* has is the right size ? */
  /***************************/
  if (   (vesa_x!=pcx_header.xmax-pcx_header.xmin+1)
      || (vesa_y!=pcx_header.ymax-pcx_header.ymin+1))
  {
   if (current_path!=NULL)
   {
    change_directory(current_path);
    free(current_path);
    current_path=NULL;
   }
   fclose(pcx_akt_handle);
   fFatal("load_pcx_overlay() - Wrong overlay size!");
  }
  pcx_bild_art=BILD_IST_256_FARBE_BILD;
 }
 if (pcx_bild_art==BILD_UNBEKANNT)
 {
  if (current_path!=NULL)
  {
   change_directory(current_path);
   free(current_path);
   current_path=NULL;
  }
  fclose(pcx_akt_handle);
  fFatal("load_pcx_overlay() - Wrong picture format!");
 }

 /************************************************/
 /* PCX file is ok, set file to start of picture */
 /************************************************/
 fseek(pcx_akt_handle,128,FROM_FILE_START);

 /******************************/
 /* get memory for load buffer */
 /******************************/
 if ((pcx_load_buffer=(T_UBYTE  *)malloc(LOAD_BUFFER_SIZE+1))==NULL )
 {
  if (current_path!=NULL)
  {
   change_directory(current_path);
   free(current_path);
   current_path=NULL;
  }
  fclose(pcx_akt_handle);
  fFatal("load_pcx_overlay() - No memory buffer left!");
 }
 pcx_muss_gelesen_werden=T_TRUE;
 vpcx_load_bild_buffer();

 /*****************************************************/
 /* well and decode it... I won't go into it here ... */
 /*****************************************************/
 while (zeilen<vesa_y)
 {
  zeilen_counter=0;
  while (zeilen_counter!=zeilen_laenge)
  {
   crunched_wert=pcx_load_buffer[pcx_buffer_counter++];
   if (pcx_buffer_counter==LOAD_BUFFER_SIZE)
    vpcx_load_bild_buffer();
   if (crunched_wert<192)
   {
    fIOPlotPixel(zeilen_counter,zeilen,crunched_wert>>4);
    overlay_pointer[zeilen_counter]=crunched_wert&(128+64+32+16);
    clip_pointer[zeilen_counter]=0;
    zeilen_counter++;
   }
   else
   {
    anzahl_der_bytes=crunched_wert&63;
    crunched_wert=pcx_load_buffer[pcx_buffer_counter++];
    if (pcx_buffer_counter==LOAD_BUFFER_SIZE)
     vpcx_load_bild_buffer();
    for (i=0;i<anzahl_der_bytes;i++)
    {
     if (crunched_wert<240)
     {
      fIOPlotPixel(zeilen_counter,zeilen,crunched_wert>>4);
      overlay_pointer[zeilen_counter]=crunched_wert&(128+64+32+16);
      clip_pointer[zeilen_counter]=0;
      zeilen_counter++;
     }
     else
     {
      fIOPlotPixel(zeilen_counter,zeilen,crunched_wert);
      clip_pointer[zeilen_counter]=1;
      zeilen_counter++;
     }
    }
   }
  }
//  clip_pointer+=zeilen_laenge;
//  overlay_pointer+=zeilen_laenge;
  clip_pointer+=vesa_bytes_per_scanline;
  overlay_pointer+=vesa_bytes_per_scanline;
  zeilen++;
 }
 if (pcx_load_buffer)
 {
  free(pcx_load_buffer);
  pcx_load_buffer=NULL;
 }
 vpcx_get_color256();
 fclose(pcx_akt_handle);
 if (current_path!=NULL)
 {
  change_directory(current_path);
  free(current_path);
  current_path=NULL;
 }
 return T_TRUE;
}

/*************************************************************************/

