#include "WinPcx.inc"

/*~***************************************************************************/

/*                 WinMain() - Start here. Main function                     */

/*****************************************************************************/
int PASCAL WinMain(hInstance, hPrevInst, lpCmdLine, nCmdShow)
HANDLE hInstance;
HANDLE hPrevInst;
LPSTR lpCmdLine;
int nCmdShow;
{
MSG   msg;

if (!hPrevInst)                         /* Has application been initialized? */

if (!MainInit(hInstance))
   return(NULL);                            /* Exits if unable to initialize */

hInst = hInstance;

hMenu  = LoadMenu(hInst, "MainMenu");

xScreen = GetSystemMetrics(SM_CXSCREEN);                  /* Get Screen size */
yScreen = GetSystemMetrics(SM_CYSCREEN);

hMainWnd = CreateWindow("Main",                               /* window class */
            "Read PCX File" ,
            WS_OVERLAPPED | WS_SYSMENU |     /* window style just system menu */
            WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
            WS_CLIPCHILDREN, 
            0,                       /* x position start at upper left corner */
            0,                       /* y position start at upper left corner */
            xScreen,                                     /* width full screen */
            yScreen,                                    /* height full screen */
            NULL,                                            /* parent handle */
            hMenu,                              /* menu at top of main window */
            hInstance,                                            /* instance */
            NULL);                                         /* additional info */

if (!hMainWnd)                                     /* was the window created? */
   return (NULL);

ShowWindow(hMainWnd, nCmdShow);                           /* Shows the window */
UpdateWindow(hMainWnd);                             /* Sends WM_PAINT message */

while
   (GetMessage(&msg, NULL, 0, 0))
       {
       TranslateMessage(&msg);                /* Translates virtual key codes */
       DispatchMessage(&msg);                 /* Dispatches message to window */
       }
return (msg.wParam);                /* Returns the value from PostQuitMessage */

}
/*~***************************************************************************/

/*                      MainInit() - Set up window                            */

/******************************************************************************/
BOOL MainInit(hInstance)                                  /* current instance */
HANDLE hInstance;
{
WNDCLASS  WndClass;

WndClass.style            = CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc      = MainProc;
WndClass.hInstance        = hInstance;
WndClass.hIcon            = NULL;
WndClass.hCursor          = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground    = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName     = "Main";
WndClass.lpszClassName    = "Main";
WndClass.cbClsExtra       = 0;
WndClass.cbWndExtra       = 0;

if (!RegisterClass (&WndClass))
   return (FALSE);                /* Returns result of registering the window */

}
/*~***************************************************************************/

/*                            MainProc() Function                             */

/*****************************************************************************/
long FAR PASCAL MainProc(hMainWnd, message, wParam, lParam)
HWND hMainWnd;
unsigned message;
WORD wParam;
LONG lParam;
{
FARPROC    lpProc;
HDC        hDC;

switch (message) 
   {
   case WM_CREATE:
      hMenu = GetSystemMenu (hMainWnd, FALSE); /* Add Choices To System Menu. */
      ChangeMenu (hMenu, NULL, "A&bout WinPcx", ID_ABOUT, MF_APPEND | MF_STRING);
   break;

   case WM_DESTROY:                       /* message: window being destroyed */
          PostQuitMessage(0);
   break;

   case WM_CLOSE:
       DestroyWindow (hMainWnd);

       DeleteDC (BMapDC);
       DeleteObject (BMap);

       DeleteDC (NewBMapDC);
       DeleteObject (NewBMap);
 
       DeleteDC (TmpDC);
       DeleteObject (TmpMap);

   break;
        
/*----------------------------------------------------------------------------*/
        
   case WM_COMMAND:
      switch (wParam)
      {
      case IDM_FILE:                                         /* Read PCX File */
         lpProc = MakeProcInstance (DoPictFileBox, hInst);
         DialogBox (hInst, "RCPictFileBox", hMainWnd, lpProc);
         FreeProcInstance (lpProc);

         hDC = GetDC (hMainWnd);
         LoadBitMap(hDC);
         ReleaseDC (hMainWnd, hDC);
      break;

      case IDM_SHOW:                              /* Display Bitmap To Screen */
         hDC = GetDC (hMainWnd);
         if (NewBMap)                          /* Display Size Altered Bitmap */
            BitBlt (hDC, 0, 0, xScreen, yScreen, NewBMapDC, 0, 0, SRCCOPY);
         else                 /* Display Bitmap As Is, Not Larger Than Screen */
            BitBlt (hDC, 0, 0, xScreen, yScreen, BMapDC, 0, 0, SRCCOPY);
 
         ReleaseDC (hMainWnd, hDC);
      break;

      case IDM_CLEAR:                                         /* Clear Screen */
         InvalidateRect (hMainWnd, NULL, TRUE);
      break;
      }
   break;

/*----------------------------------------------------------------------------*/

   case WM_SYSCOMMAND:                  /* message: command from system menu */
      switch (wParam)
         {
         case ID_ABOUT:
            lpProc = MakeProcInstance(About, hInst);
            DialogBox(hInst, "RCAboutBox", hMainWnd, lpProc);
            FreeProcInstance(lpProc);
         break;
         }

/*----------------------------------------------------------------------------*/

   default:                                   /* Passes it on if unprocessed */
       return (DefWindowProc(hMainWnd, message, wParam, lParam));
   }                                                      /* End Main Switch */
 return (TRUE);
}

/*~***************************************************************************/

/*                   LoadBitMap() - Load Bitmap PCX File                     */

/*****************************************************************************/
int LoadBitMap (hDC)
HDC hDC;
{
int size, bsize, i, pos, y, j, BitInt, k, z, q, status;
unsigned char Bits[128], Bit, BitValue, Bytes[320], List[4002];
FILE *fd;
unsigned char ColorMap[48], Filler[58];
int Manuf, Ver, Enc, BpPixel, Xmin, Ymin, Xmax, Ymax, HRes, VRes, Resv;
int NPlanes, PInfo, Tmp;

fd = fopen (PictureFile, "rb");
if (fd == NULL)
   {
   sprintf (out, "ERROR - Opening %s File.", PictureFile);
   MsgEx(hMainWnd);
   return (FALSE);
   }

Manuf = fgetc(fd);                                      /* Get Manufacture ID */
Ver = fgetc(fd);                                        /* Get Version Number */
Enc = fgetc(fd);                                         /* Get Encoding Used */
BpPixel = fgetc(fd);                                    /* Get Bits Per Pixel */
fread (&Xmin, 2, 1, fd);                            /* Get Picture Dimensions */
fread (&Ymin, 2, 1, fd);
fread (&Xmax, 2, 1, fd);
fread (&Ymax, 2, 1, fd);
fread (&HRes, 2, 1, fd);                         /* Get Horizontal Resolution */
fread (&VRes, 2, 1, fd);                           /* Get Vertical Resolution */
fread (ColorMap, 1, 48, fd);                     /* Get Color Palette Setting */
Resv = fgetc(fd);                                                 /* Reserved */
NPlanes = fgetc(fd);                            /* Get Number Of Color Planes */
fread (&BpLine, 2, 1, fd);                               /* Get Bits Per Line */
fread (&PInfo, 2, 1, fd);                                 /* Get Palette Info */
fread (Filler, 1, 58, fd);                                     /* Blank Stuff */

/*----------------------------------------------------------------------------*/

Xsize = Xmax - Xmin + 1;                              /* Cal. Size Of Picture */
Ysize = Ymax - Ymin + 1;
TotalBytes = NPlanes * BpLine;                    /* Cal. Total Bytes In Line */

if (BMap)
   {                                              /* delete previous tmp map */
   DeleteDC (BMapDC);
   DeleteObject (BMap);
   }

BMapDC = CreateCompatibleDC (hDC);    
if (BMapDC == NULL) 
   {
   strcpy (out, "ERROR - Creating DC");
   MsgEx (hMainWnd);
   return (FALSE);
   }

BMap = CreateCompatibleBitmap (hDC, Xsize, Ysize);
if (BMap == NULL)
   {
   strcpy (out, "ERROR - Creating Bitmap");
   MsgEx (hMainWnd);
   return (FALSE);
   }

if (BMap == NULL) 
   {             /* NOT ENOUGH MEMORY!! */
   strcpy (out, "ERROR - Not Enough Memory For Bitmap");
   MsgEx (hMainWnd);
   return(FALSE);
   };

SelectObject(BMapDC,BMap);

if ((status = CreateTmpMap (hDC, Xsize, 1, 0xff)) == -1)
   return (FALSE);

for ( y = 0; y < Ysize; y ++)                                 /* Clear Bitmap */
   BitBlt (BMapDC, 0, y, Xsize, 1, TmpDC, 0, 0, SRCCOPY);

size = fread (List, 1, 4000, fd);   /* Read a 4000 byte chunk to be processed */

y = pos = 0;
while ((size >= 0) && (y < Ysize))
   {
   i = 0;
   while (i < TotalBytes)
       {
       BitInt = (int)List[pos];
       pos ++; 
       size --;
       if (size <= 0) 
           {
           size = fread (List, 1, 4000, fd);
           if (size <= 0) 
               goto DONE;

           pos = 0;
           }

       if ((BitInt & 192) == 192) 
           {                                           /* Run length encoded */
           bsize = BitInt & 63;                      /* Get # of repetitions */
           for (j = i; j < bsize + i; j ++) Bytes[j] = List[pos];
           pos ++;
           size --;
           i = i + bsize;
           }

       else
           {                                            /* Actual pixel data */
           Bytes[i] = List[pos-1];
           i ++;
           }

       if (size <= 0) 
           {
           size = fread (List, 1, 4000, fd);
           if (size <= 0) 
               goto DONE;

           pos = 0;
           }
       }                               /* end while still reading 1 scan line */
   y ++;

   for (z = 0; z < BpLine; z ++)                                 /* Color Fix */
      {
      Bit = Bytes[z];
      Bytes[z] = Bytes[z + (BpLine * 2)];
      Bytes[z + (BpLine * 2)] = Bit;
      }

Tmp = TotalBytes - BpLine;                             /* Fix If Only 1 Plane */
if (Tmp == 0)
   Tmp = BpLine;

   SetBitmapBits (TmpMap, (LONG)Tmp, (LPSTR)Bytes);
                           
   if (y > 0)
       BitBlt (BMapDC, 0, y, Xsize, 1, TmpDC, 0, 0, SRCCOPY);
   }                                                   /* End for y=0 to Rows */

/*----------------------------------------------------------------------------*/

DONE:

   if (Xsize > xScreen || Ysize > yScreen)         /* Shrink Bitmap If Larger */
      {                                                /* Than Screen Ex. CGA */
      if (NewBMap)
         {                                         /* delete previous tmp map */
         DeleteDC (NewBMapDC);
         DeleteObject (NewBMap);
         }

      NewBMapDC = CreateCompatibleDC (hDC);    
      if (NewBMapDC == NULL) 
         {
         strcpy (out, "ERROR - Creating New DC");
         MsgEx (hMainWnd);
         return (FALSE);
         }

      NewBMap = CreateCompatibleBitmap (hDC, xScreen, yScreen);
      if (NewBMap == NULL)
         {
         strcpy (out, "ERROR - Creating New Bitmap");
         MsgEx (hMainWnd);
         return (FALSE);
         }

      if (NewBMap == NULL) 
         {             /* NOT ENOUGH MEMORY!! */
         strcpy (out, "ERROR - Not Enough Memory For New Bitmap");
         MsgEx (hMainWnd);
         return(FALSE);
         };

      SelectObject (NewBMapDC, NewBMap);

      StretchBlt (NewBMapDC, 0, 0, xScreen, yScreen, 
                  BMapDC, 0, 0, Xsize, Ysize, SRCCOPY);

      DeleteDC (BMapDC);                             /* Get Rid Of Out Bitmap */
      DeleteObject (BMap);
      }

fclose (fd);                                                    /* Close File */
return (TRUE);
}
/******************************************************************************/

/*                CreateTmpMap() - Create Tmp. Bitmap                         */

/******************************************************************************/
int CreateTmpMap (hDC, x, y, FILL)
HDC hDC;
int x,y;
unsigned char FILL;
{
int j, Tmp;
unsigned char Bytes[320];

if (TmpMap) 
   {                                              /* delete previous tmp map */
   DeleteDC (TmpDC);
   DeleteObject (TmpMap);
   }

TmpDC = CreateCompatibleDC (hDC);
if (TmpDC == NULL) 
   {
   strcpy (out, "ERROR - Creating Tmp DC");
   MsgEx (hMainWnd);
   return(-1);
   }

TmpMap = CreateDiscardableBitmap (hDC, x, y);
if (TmpMap == NULL) 
   {
   strcpy (out, "ERROR - Creating Tmp Bitmap");
   MsgEx (hMainWnd);
   return(-1);
   }

SelectObject (TmpDC, TmpMap);
for (j = 0; j < 320; j ++) 
   Bytes[j] = (unsigned char)FILL;

SetBitmapBits (TmpMap, (LONG)240, (LPSTR)Bytes);
return(0);
}

/*~***************************************************************************/

/*                   DoPictFileBox() - Get New PCX File                      */

/*****************************************************************************/
BOOL FAR PASCAL DoPictFileBox(hWnd, message, wParam, lParam)
HWND hWnd;
unsigned message;
WORD wParam;
LONG lParam;
{
HDC            hDC;
static char    FileBuf[200];

switch (message)
   {
   case WM_INITDIALOG:                      /* message: intialize dialog box */
                                                  /* Load Files Into ListBox */
       strcpy (FileBuf, "*.pcx");
       DlgDirList (hWnd, FileBuf, LB_RESTORE, ID_RESTOREPATH, 0x4010);
       SetFocus (GetDlgItem (hWnd, LB_RESTORE));

       return (FALSE);
   break;

/*---------------------------------------------------------------------------*/

   case WM_COMMAND:                           /* message : recived a command */
       switch(wParam)
           {
           case LB_RESTORE:
               if (HIWORD(lParam) != 2)              /* Double click on item */
           break;

/*---------------------------------------------------------------------------*/

           case IDOK: 
               ok = DlgDirSelect (hWnd, FileBuf, LB_RESTORE);
               if (ok != 0)                             /* Directory Selected */
                   {
                   strcat(FileBuf, "*.pcx");             /* Add *.pcx To Path */
                                                    /* Put Files Into ListBox */
                   DlgDirList(hWnd, FileBuf, LB_RESTORE,ID_RESTOREPATH,0x4010);
                   break;
                   }

               sprintf( out, "Load PCX File %s", FileBuf);
               strcpy (buffer, "PCX File");
               ok = MsgYN (hWnd);

               if (ok == IDNO)
                   return(FALSE);                          /* Don't Load File */
                  
               EndDialog(hWnd, TRUE);

               strcpy (PictureFile, FileBuf);

               hDC = GetDC (hMainWnd);
               LoadCursor (hInst, IDC_WAIT);
               LoadBitMap (hDC);
               LoadCursor (hInst, IDC_ARROW);

               ReleaseDC (hMainWnd, hDC);
               return(TRUE);
           break;

/*---------------------------------------------------------------------------*/

           case IDCANCEL:
               EndDialog(hWnd, FALSE);
               return(FALSE);
           break;
           }                                           /* End Command Switch */
       default:
           return(FALSE);
           break;
   }                                                      /* End Main Switch */
}
/*****************************************************************************/

/*            void MsgEx()    Message Box With OK And Exclamation            */

/*****************************************************************************/
void MsgEx(hWnd)
HWND   hWnd;
{
MessageBeep(0);
MessageBox(hWnd, out, buffer, MB_OK | MB_ICONEXCLAMATION);
}

/*****************************************************************************/

/*           int MsgYN()    Message Box With YES, NO And Question            */

/*****************************************************************************/
int MsgYN(hWnd)
HWND   hWnd;
{
ok = MessageBox(hMainWnd, out, buffer, MB_YESNO | MB_ICONQUESTION);

if (ok == IDYES)
      return(IDYES);                              /* User Pressed YES Button */

else
   return(IDNO);                                   /* User Pressed NO Button */

}
/*~***************************************************************************/

/*                     About() Function - For About Box                      */

/*****************************************************************************/
BOOL FAR PASCAL About(hAboutWnd, message, wParam, lParam)
HWND hAboutWnd;
unsigned message;
WORD wParam;
LONG lParam;
{
 switch (message)
   {
   case WM_INITDIALOG:                       /* Message: Intialize Dialog Box */
       return (TRUE);

   case WM_COMMAND:                            /* Message : Recived A Command */

      if (wParam == IDOK)
         {                                              /* "OK" Box Selected? */
         EndDialog(hAboutWnd, NULL);                  /* Exits The Dialog Box */
         return (TRUE);
         }
   break;

   }
return (FALSE);
}                                                 /* Didn't Process A Message */


