home *** CD-ROM | disk | FTP | other *** search
/ Boston 2 / boston-2.iso / WINDOWS / TOOLS / WINLAVA / LAVA.C next >
C/C++ Source or Header  |  1993-12-01  |  42KB  |  1,347 lines

  1. /*----------------------------------------------------------------------------*\
  2. |   Lava.c - A Lava Flow Simulator for Windows application                    |
  3. |                                                                              |
  4. |                                                                              |
  5. \*----------------------------------------------------------------------------*/
  6. /*
  7.      (C) Copyright Microsoft Corp. 1991.  All rights reserved.
  8.  
  9.      You have a royalty-free right to use, modify, reproduce and 
  10.      distribute the Sample Files (and/or any modified version) in 
  11.      any way you find useful, provided that you agree that 
  12.      Microsoft has no warranty obligations or liability for any 
  13.      Sample Application Files which are modified. 
  14.  */     
  15.  
  16. #define PUBLIC far pascal
  17. #define PRIVATE near pascal
  18. #include <windows.h>
  19.  
  20. #define WinAssert(x)    
  21.  
  22. #include <math.h>
  23.  
  24. #include "lava.h"
  25.  
  26. #define    PC_NOCOLLAPSE    0x04       // non-collapsing flag
  27.  
  28. #define rgbBlack    RGB(0,0,0)
  29. #define rgbWhite    RGB(255,255,255)
  30. //#define rgbRed      RGB(255,0,0)
  31. //#define rgbGreen    RGB(0,255,0)
  32. //#define rgbBlue     RGB(0,0,255)
  33. #define rgbMenu     GetSysColor(COLOR_MENU)
  34. #define rgbMenuText GetSysColor(COLOR_MENUTEXT)
  35.  
  36. #define MAXCOLORS   256
  37.  
  38. #define wDibUsage  (fPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS)
  39.  
  40. typedef struct CHARGE
  41. {
  42.     POINT pt;
  43.     int value;
  44. }CHARGE;
  45.  
  46. /*----------------------------------------------------------------------------*\
  47. |                                                                              |
  48. |   g l o b a l   v a r i a b l e s                                            |
  49. |                                                                              |
  50. \*----------------------------------------------------------------------------*/
  51. static  char    szAppName[]="LavaFlow";
  52.  
  53. static  HANDLE  hInstApp;
  54. static  HWND    hwndApp;
  55.  
  56. /*----------------------------------------------------------------------------*\
  57. |                                                                              |
  58. |   f u n c t i o n   d e f i n i t i o n s                                    |
  59. |                                                                              |
  60. \*----------------------------------------------------------------------------*/
  61.  
  62. LONG FAR PASCAL AppWndProc (HWND hwnd, unsigned uiMessage, WORD wParam, LONG lParam);
  63. int  ErrMsg (LPSTR sz,...);
  64. BOOL fDialog(int id,HWND hwnd,FARPROC fpfn);
  65.  
  66. HMENU   hmenuPopup;
  67.  
  68. BOOL    fSetDIBits = TRUE;
  69. BOOL    fPalColors = TRUE;
  70. BOOL    fPalette;
  71. BOOL    fFastCycle;
  72. short   fSinPalette=FALSE;
  73. short   fCrossFade=FALSE;
  74. short   fColorCycle=TRUE;
  75. short   fNoCollapse=FALSE;
  76. short   paletteval[MAXCOLORS];
  77.  
  78. //
  79. //  A brush for every color in the palette, for use on non palette devices.
  80. //
  81. HBRUSH  hbrPalette[MAXCOLORS];
  82.  
  83. HPALETTE hpalLava;
  84. LOGPALETTE *pLogPal;
  85. int      nColors  = 128;
  86. int     NumCenters = 4;
  87. int      nBandScale = 1;
  88.  
  89. short       nColorPhase = 0;
  90. RGBQUAD     rgbLava     = {0,0,255};
  91.  
  92. //
  93. //  TRUE if a Lava computation is in progress
  94. //
  95. BOOL    fLavaSem;
  96.  
  97. //
  98. //  if set to a non zero value will cause lava calculation to abort
  99. //
  100. BOOL    fStopLava;
  101. #define F_LAVAOK    0
  102. #define F_LAVASTOP  1
  103. #define F_LAVADIE   2
  104.  
  105. HBITMAP hbmLava;
  106. BITMAP    bmLava;
  107. BYTE    abScanLine[2048];
  108.  
  109. BITMAPINFOHEADER *pbiLava;
  110.  
  111. LONG  PRIVATE AppOwnerDraw(HWND hwnd, WORD msg, WORD wParam, LONG lParam);
  112. LONG  PRIVATE AppCommand(HWND hwnd, unsigned msg, WORD wParam, LONG lParam);
  113. HBITMAP CopyBitmap (HBITMAP hbm);
  114. HPALETTE CopyPalette(HPALETTE hpal);
  115. HANDLE CreateLogicalDib(HBITMAP hbm, HPALETTE hpal);
  116.  
  117. extern LONG LavaFlowXY386(int nCenter, CHARGE *aptCenter, int x, int y);
  118. void LavaFlow(HDC hdc, int nCenter, CHARGE aptCenter[], PRECT prc);
  119. void CyclePalette(HDC hdc);
  120. void InitPalette();
  121. void SetPalette(PALETTEENTRY * pPal, int nPhase, RGBQUAD rgb);
  122.  
  123. #define MAXI (16*1024)
  124.  
  125. /*----------------------------------------------------------------------------*\
  126. |                                                                              |
  127. |   Random functions                                                           |
  128. |                                                                              |
  129. \*----------------------------------------------------------------------------*/
  130.  
  131. #define RAND(x)  (rand() % (x))
  132.  
  133. DWORD dwRand = 1L;
  134. void PASCAL srand(DWORD dwSeed)
  135. {
  136.     dwRand = dwSeed;
  137. }
  138.  
  139. WORD PASCAL rand(void)
  140. {
  141.     dwRand = dwRand * 214013L + 2531011L;
  142.     return (WORD)((dwRand >> 16) & 0xffff);
  143. }
  144.  
  145. POINT PASCAL PtRand(int x, int y)
  146. {
  147.     POINT pt;
  148.  
  149.     pt.x = RAND(x);
  150.     pt.y = RAND(y);
  151.  
  152.     return pt;
  153. }
  154.  
  155. VOID WinYield()
  156. {
  157.     MSG msg;
  158.  
  159.     while(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  160.     {
  161.     TranslateMessage(&msg);
  162.     DispatchMessage(&msg);
  163.     }
  164. }
  165.  
  166. /*----------------------------------------------------------------------------*\
  167. |   AppAbout( hDlg, uiMessage, wParam, lParam )                    |
  168. |                                           |
  169. |   Description:                                   |
  170. |    This function handles messages belonging to the "About" dialog box.    |
  171. |    The only message that it looks for is WM_COMMAND, indicating the use   |
  172. |    has pressed the "OK" button.  When this happens, it takes down           |
  173. |    the dialog box.                                |
  174. |                                           |
  175. |   Arguments:                                       |
  176. |    hDlg        window handle of about dialog window               |
  177. |    uiMessage    message number                           |
  178. |    wParam        message-dependent                       |
  179. |    lParam        message-dependent                       |
  180. |                                           |
  181. |   Returns:                                       |
  182. |    TRUE if message has been processed, else FALSE                   |
  183. |                                           |
  184. \*----------------------------------------------------------------------------*/
  185. BOOL FAR PASCAL AppAbout( hDlg, uiMessage, wParam, lParam )
  186.     HWND     hDlg;
  187.     unsigned uiMessage;
  188.     WORD     wParam;
  189.     long     lParam;
  190. {
  191.     switch (uiMessage) {
  192.         case WM_COMMAND:
  193.             if (wParam == IDOK)
  194.                 EndDialog(hDlg,TRUE);
  195.         break;
  196.  
  197.     case WM_INITDIALOG:
  198.         return TRUE;
  199.     }
  200.     return FALSE;
  201. }
  202.  
  203. VOID SetupPalette()
  204. {
  205.     int i;
  206.     WORD *pw;
  207.     RGBQUAD *prgb;
  208.     PALETTEENTRY *ppe;
  209.  
  210.     if (hpalLava)
  211.     {
  212.     DeleteObject(hpalLava);
  213.     hpalLava = NULL;
  214.     }
  215.     //hpalLava = CreateWashPalette(rgbBlue,rgbBlack,-nColors);
  216.     if(pLogPal == NULL)
  217.     {
  218.        pLogPal = (VOID *)LocalAlloc(LPTR,sizeof(LOGPALETTE) + MAXCOLORS * sizeof(PALETTEENTRY));
  219.     }
  220.     WinAssert(pLogPal);
  221.  
  222.     pLogPal->palVersion = 0x300;
  223.     pLogPal->palNumEntries = nColors;
  224.  
  225.     SetPalette(pLogPal->palPalEntry,nColorPhase,rgbLava);
  226.  
  227.     if (!fPalette)
  228.     {
  229.         for(i=0,ppe=pLogPal->palPalEntry;i<nColors;i++,ppe++)
  230.         {
  231.             if (hbrPalette[i])
  232.                 DeleteObject(hbrPalette[i]);
  233.  
  234.             hbrPalette[i] = CreateSolidBrush(RGB(ppe->peRed,ppe->peGreen,ppe->peBlue));
  235.         }
  236.     }
  237.  
  238.     hpalLava = CreatePalette(pLogPal);
  239.  
  240.     if (pbiLava == NULL)
  241.     {
  242.         pbiLava = (VOID *)LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER) + MAXCOLORS * sizeof(RGBQUAD));
  243.  
  244.         pbiLava->biSize     = sizeof(BITMAPINFOHEADER);
  245.         pbiLava->biWidth    = 0;
  246.         pbiLava->biHeight   = 0;
  247.         pbiLava->biPlanes   = 1;
  248.         pbiLava->biBitCount = 8;
  249.  
  250.         pbiLava->biCompression   = BI_RGB;
  251.         pbiLava->biSizeImage     = 0;
  252.         pbiLava->biXPelsPerMeter = 0;
  253.         pbiLava->biYPelsPerMeter = 0;
  254.         pbiLava->biClrUsed       = nColors;
  255.         pbiLava->biClrImportant  = 0;
  256.     }
  257.     WinAssert(pbiLava);
  258.  
  259.     if (fPalColors)
  260.     {
  261.         pw = (WORD*)((BYTE*)pbiLava+pbiLava->biSize);
  262.         for (i=0; i<nColors; i++)
  263.         {
  264.             *pw++ = i;
  265.         }
  266.     }
  267.     else
  268.     {
  269.         prgb = (RGBQUAD*)((BYTE*)pbiLava+pbiLava->biSize);
  270.         for (i=0; i<nColors; i++)
  271.         {
  272.             prgb[i].rgbRed   = pLogPal->palPalEntry[i].peRed;
  273.             prgb[i].rgbGreen = pLogPal->palPalEntry[i].peGreen;
  274.             prgb[i].rgbBlue  = pLogPal->palPalEntry[i].peBlue;
  275.             prgb[i].rgbReserved = 0;
  276.         }
  277.     }
  278. }
  279.  
  280. /*----------------------------------------------------------------------------*\
  281. |   AppExit()                                                                  |
  282. |                                                                              |
  283. |   Description:                                   |
  284. |       This is called when the application is removed from memory             |
  285. |       It free all global objects and other things                            |
  286. |                                                                              |
  287. |   Returns:                                       |
  288. |       Exit code to be returned to KERNEL                                     |
  289. |                                           |
  290. \*----------------------------------------------------------------------------*/
  291. WORD AppExit()
  292. {
  293.     int i;
  294.  
  295.     for (i=0; i<nColors; i++)
  296.     {
  297.         if (hbrPalette[i])
  298.             DeleteObject(hbrPalette[i]);
  299.     }
  300.  
  301.     if (hbmLava)
  302.         DeleteObject(hbmLava);
  303.  
  304.     if (hpalLava)
  305.         DeleteObject(hpalLava);
  306.  
  307.     //if (hmenuPopup)
  308.     //    DeleteMenu(hmenuPopup);
  309.  
  310.     return 0;
  311. }
  312.  
  313. /*----------------------------------------------------------------------------*\
  314. |   AppInit( hInst, hPrev)                               |
  315. |                                           |
  316. |   Description:                                   |
  317. |    This is called when the application is first loaded into           |
  318. |    memory.  It performs all initialization that doesn't need to be done   |
  319. |    once per instance.                               |
  320. |                                           |
  321. |   Arguments:                                       |
  322. |    hInstance    instance handle of current instance               |
  323. |    hPrev        instance handle of previous instance               |
  324. |                                           |
  325. |   Returns:                                       |
  326. |    TRUE if successful, FALSE if not                       |
  327. |                                           |
  328. \*----------------------------------------------------------------------------*/
  329. BOOL AppInit(hInst,hPrev,sw,szCmd)
  330.     HANDLE hInst;
  331.     HANDLE hPrev;
  332.     WORD   sw;
  333.     LPSTR  szCmd;
  334. {
  335.     WNDCLASS rClass;
  336.     int      dx,dy;
  337.     char     ach[80];
  338.     HMENU    hmenu;
  339.     HPALETTE hpal;
  340.     HDC      hdc;
  341.  
  342.     if (LOWORD(GetWinFlags()) & (WF_CPU086|WF_CPU186|WF_CPU286))
  343.     {
  344.         MessageBox(NULL,"Lava requires a 386 or better","Lava",MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL);
  345.         return FALSE;
  346.     }
  347.  
  348.     /* Save instance handle for DialogBoxs */
  349.     hInstApp = hInst;
  350.  
  351.     if (!hPrev) {
  352.     /*
  353.      *  Register a class for the main application window
  354.      */
  355.     rClass.hCursor          = LoadCursor(NULL,IDC_ARROW);
  356.     rClass.hIcon          = LoadIcon(hInst,"AppIcon");
  357.         rClass.lpszMenuName   = NULL;
  358.         rClass.lpszClassName  = szAppName;
  359.     rClass.hbrBackground  = (HBRUSH)COLOR_WINDOW + 1;
  360.     rClass.hInstance      = hInst;
  361.     rClass.style          = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
  362.     rClass.lpfnWndProc    = AppWndProc;
  363.     rClass.cbWndExtra     = 0;
  364.     rClass.cbClsExtra     = 0;
  365.  
  366.     if (!RegisterClass(&rClass))
  367.         return FALSE;
  368.     }
  369.  
  370.     dx = GetSystemMetrics (SM_CXSCREEN);
  371.     dy = GetSystemMetrics (SM_CYSCREEN);
  372.  
  373.     hwndApp = CreateWindow (szAppName,szAppName,
  374.                 WS_OVERLAPPEDWINDOW,
  375.                 CW_USEDEFAULT, 0,dx/2,dy/2,
  376.                             (HWND)NULL,        /* no parent */
  377.                             (HMENU)NULL,       /* use class menu */
  378.                 (HANDLE)hInst,     /* handle to window instance */
  379.                             (LPSTR)NULL        /* no params to pass on */
  380.                            );
  381.     WinAssert(hwndApp);
  382.     ShowWindow (hwndApp,sw);
  383.  
  384.     hmenu = LoadMenu(hInst,"AppMenu");
  385.     WinAssert(hmenu);
  386.     hmenuPopup = GetSubMenu(hmenu, 0);
  387.     WinAssert(hmenuPopup);
  388.  
  389.     CheckMenuItem(hmenuPopup,MENU_NUMCENTERS+NumCenters,MF_CHECKED);
  390.     CheckMenuItem(hmenuPopup,MENU_NUMCOLORS+nColors,MF_CHECKED);
  391.     CheckMenuItem(hmenuPopup,MENU_BANDSCALE+nBandScale,MF_CHECKED);
  392.  
  393.     InitPalette();
  394.     SetupPalette();
  395.  
  396.     SetTimer(hwndApp,1,10,NULL);
  397.  
  398.     srand(GetCurrentTime());
  399.  
  400.     hdc = GetDC(NULL);
  401.     fPalette = fSetDIBits = (GetDeviceCaps(hdc,RASTERCAPS) & RC_PALETTE);
  402.     ReleaseDC(NULL,hdc);
  403.  
  404.     return TRUE;
  405. }
  406.  
  407. /*----------------------------------------------------------------------------*\
  408. |   WinMain( hInst, hPrev, lpszCmdLine, cmdShow )                   |
  409. |                                                                              |
  410. |   Description:                                                               |
  411. |       The main procedure for the App.  After initializing, it just goes      |
  412. |       into a message-processing loop until it gets a WM_QUIT message         |
  413. |       (meaning the app was closed).                                          |
  414. |                                                                              |
  415. |   Arguments:                                                                 |
  416. |    hInst        instance handle of this instance of the app           |
  417. |    hPrev        instance handle of previous instance, NULL if first    |
  418. |       lpszCmdLine     ->null-terminated command line                         |
  419. |       cmdShow         specifies how the window is initially displayed        |
  420. |                                                                              |
  421. |   Returns:                                                                   |
  422. |       The exit code as specified in the WM_QUIT message.                     |
  423. |                                                                              |
  424. \*----------------------------------------------------------------------------*/
  425. int PASCAL WinMain( hInst, hPrev, fpcCmdLine, iCmdShow )
  426.     HANDLE  hInst, hPrev;
  427.     LPSTR   fpcCmdLine;
  428.     int     iCmdShow;
  429. {
  430.     MSG     msg;
  431.  
  432.     /* Call initialization procedure */
  433.     if (!AppInit(hInst,hPrev,iCmdShow,fpcCmdLine))
  434.         return FALSE;
  435.  
  436.     for (;;)
  437.     {
  438.         /* Polling messages from event queue */
  439.         while (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
  440.         {
  441.             if (msg.message == WM_QUIT)
  442.                 goto exit;
  443.  
  444.             TranslateMessage(&msg);
  445.             DispatchMessage(&msg);
  446.         }
  447.  
  448.         if (fFastCycle)
  449.             SendMessage(hwndApp,WM_TIMER,0,0L);
  450.         else
  451.             WaitMessage();
  452.     }
  453. exit:
  454.     return AppExit();
  455. }
  456.  
  457. /*----------------------------------------------------------------------------*\
  458. |   AppPaint(hwnd, hdc)                                |
  459. |                                                                              |
  460. |   Description:                                                               |
  461. |       The paint function.  Right now this does nothing.                      |
  462. |                                                                              |
  463. |   Arguments:                                       |
  464. |    hwnd         window painting into                       |
  465. |    hdc         display context to paint to                   |
  466. |                                                                              |
  467. |   Returns:                                                                   |
  468. |       nothing                                                                |
  469. |                                                                              |
  470. \*----------------------------------------------------------------------------*/
  471. AppPaint (HWND hwnd, HDC hdc)
  472. {
  473.     RECT    rc;
  474.     HBITMAP hbmT;
  475.     HDC     hdcBits;
  476.  
  477.     if (hbmLava == NULL)
  478.     return FALSE;
  479.  
  480.     if (hpalLava)
  481.     {
  482.     SelectPalette(hdc,hpalLava,FALSE);
  483.         RealizePalette(hdc);
  484.     }
  485.  
  486.     hdcBits = CreateCompatibleDC(hdc);
  487.  
  488.     GetClientRect(hwnd,&rc);
  489.  
  490.     hbmT = SelectObject(hdcBits,hbmLava);
  491.     BitBlt(hdc,0,0,bmLava.bmWidth,bmLava.bmHeight,hdcBits,0,0,SRCCOPY);
  492.     SelectObject(hdcBits,hbmT);
  493.  
  494.     DeleteDC(hdcBits);
  495.     return TRUE;
  496. }
  497.  
  498. /*----------------------------------------------------------------------------*\
  499. |                                                                              |
  500. |   w i n d o w   p r o c s                                                    |
  501. |                                                                              |
  502. \*----------------------------------------------------------------------------*/
  503.  
  504. /*----------------------------------------------------------------------------*\
  505. |   AppWndProc( hwnd, uiMessage, wParam, lParam )                   |
  506. |                                                                              |
  507. |   Description:                                                               |
  508. |       The window proc for the app's main (tiled) window.  This processes all |
  509. |       of the parent window's messages.                                       |
  510. |                                                                              |
  511. |   Arguments:                                                                 |
  512. |    hwnd        window handle for the window                   |
  513. |       uiMessage       message number                                         |
  514. |       wParam          message-dependent                                      |
  515. |       lParam          message-dependent                                      |
  516. |                                                                              |
  517. |   Returns:                                                                   |
  518. |       0 if processed, nonzero if ignored                                     |
  519. |                                                                              |
  520. \*----------------------------------------------------------------------------*/
  521. LONG FAR PASCAL AppWndProc(hwnd, msg, wParam, lParam)
  522.     HWND     hwnd;
  523.     unsigned msg;
  524.     WORD     wParam;
  525.     long     lParam;
  526. {
  527.     PAINTSTRUCT ps;
  528.     BOOL        f;
  529.     HDC         hdc;
  530.     RECT        rc;
  531.  
  532.     switch (msg) {
  533.     case WM_CREATE:
  534.             break;
  535.  
  536.         case WM_QUERYNEWPALETTE:
  537.             if (hpalLava)
  538.             {
  539.                 hdc = GetDC(hwnd);
  540.         SelectPalette(hdc,hpalLava,FALSE);
  541.                 f = RealizePalette(hdc);
  542.                 ReleaseDC(hwnd,hdc);
  543.                 return (LONG)f;
  544.             }
  545.             return FALSE;
  546.  
  547.         case WM_PALETTECHANGED:
  548.             if (wParam != hwnd && hpalLava)
  549.                 InvalidateRect(hwnd,NULL,TRUE);
  550.             break;
  551.  
  552.         case WM_LBUTTONDOWN:
  553.             ClientToScreen(hwnd, (LPPOINT)&lParam);
  554.             TrackPopupMenu(hmenuPopup, 0, LOWORD(lParam)-30, HIWORD(lParam)+4, 0, hwnd, NULL);
  555.             break;
  556.  
  557.         case WM_DRAWITEM:
  558.         case WM_MEASUREITEM:
  559.         case WM_DELETEITEM:
  560.             return AppOwnerDraw(hwnd,msg,wParam,lParam);
  561.  
  562.         case WM_INITMENU:
  563.             EnableMenuItem(wParam,MENU_GO,
  564.                 fLavaSem ? MF_GRAYED : MF_ENABLED);
  565.             EnableMenuItem(wParam,MENU_STOP,
  566.                 !fLavaSem ? MF_GRAYED : MF_ENABLED);
  567.             EnableMenuItem(wParam,MENU_PASTE,
  568.                 IsClipboardFormatAvailable(CF_BITMAP) ? MF_ENABLED : MF_GRAYED);
  569.             EnableMenuItem(wParam,MENU_COPY,
  570.                 hbmLava ? MF_ENABLED : MF_GRAYED);
  571.             EnableMenuItem(wParam,MENU_PALCOLORS,
  572.                 fSetDIBits ? MF_ENABLED : MF_GRAYED);
  573.             CheckMenuItem(wParam,MENU_PALETTE,
  574.                 fPalette ? MF_CHECKED : MF_UNCHECKED);
  575.         CheckMenuItem(wParam,MENU_SATIN,
  576.         fSinPalette ? MF_CHECKED : MF_UNCHECKED);
  577.         CheckMenuItem(wParam,MENU_CROSSFADE,
  578.         fCrossFade ? MF_CHECKED : MF_UNCHECKED);
  579.             CheckMenuItem(wParam,MENU_SETDIBITS,
  580.                 fSetDIBits ? MF_CHECKED : MF_UNCHECKED);
  581.             CheckMenuItem(wParam,MENU_PALCOLORS,
  582.                 (fPalColors && fSetDIBits)? MF_CHECKED : MF_UNCHECKED);
  583.             CheckMenuItem(wParam,MENU_FASTCYCLE,
  584.                 fFastCycle ? MF_CHECKED : MF_UNCHECKED);
  585.             CheckMenuItem(wParam,MENU_COLORCYCLE,
  586.                 fColorCycle ? MF_CHECKED : MF_UNCHECKED);
  587.             CheckMenuItem(wParam,MENU_NOCOLLAPSE,
  588.                 fNoCollapse ? MF_CHECKED : MF_UNCHECKED);
  589.             break;
  590.  
  591.         case WM_COMMAND:
  592.             return AppCommand(hwnd,msg,wParam,lParam);
  593.  
  594.     case WM_DESTROY:
  595.         PostQuitMessage(0);
  596.         break;
  597.  
  598.         case WM_CLOSE:
  599.             //
  600.             // if a lava calculation is under way stop it before closing
  601.             //
  602.             if (fLavaSem)
  603.             {
  604.                 fStopLava = F_LAVADIE;
  605.                 return 0L;
  606.             }
  607.         break;
  608.  
  609.         case WM_TIMER:
  610.             if (fPalette && hpalLava)
  611.             {
  612.                 hdc = GetDC(hwnd);
  613.  
  614.                 SelectPalette(hdc,hpalLava,FALSE);
  615.                 RealizePalette(hdc);
  616.  
  617.                 CyclePalette(hdc);
  618.  
  619.                 ReleaseDC(hwnd,hdc);
  620.             }
  621.             break;
  622.  
  623.         case WM_PAINT:
  624.             BeginPaint(hwnd,&ps);
  625.             AppPaint (hwnd,ps.hdc);
  626.             EndPaint(hwnd,&ps);
  627.         return 0L;
  628.     }
  629.     return DefWindowProc(hwnd,msg,wParam,lParam);
  630. }
  631.  
  632.  
  633. /*----------------------------------------------------------------------------*\
  634. |   ErrMsg - Opens a Message box with a error message in it.  The user can     |
  635. |         select the OK button to continue or the CANCEL button to kill     |
  636. |         the parent application.                           |
  637. \*----------------------------------------------------------------------------*/
  638. int ErrMsg (LPSTR sz,...)
  639. {
  640.     char ach[128];
  641.  
  642.     wsprintf (ach,sz,(LPSTR)(&sz+1));     /* Format the string */
  643.     MessageBox(NULL,ach,NULL,MB_YESNO|MB_ICONEXCLAMATION|MB_DEFBUTTON2|MB_SYSTEMMODAL);
  644.     return FALSE;
  645. }
  646.  
  647. /*----------------------------------------------------------------------------*\
  648. |   fDialog(id,hwnd,fpfn)                               |
  649. |                                           |
  650. |   Description:                                                               |
  651. |    This function displays a dialog box and returns the exit code.           |
  652. |    the function passed will have a proc instance made for it.           |
  653. |                                           |
  654. |   Arguments:                                                                 |
  655. |    id        resource id of dialog to display               |
  656. |    hwnd        parent window of dialog                    |
  657. |    fpfn        dialog message function                    |
  658. |                                                                              |
  659. |   Returns:                                                                   |
  660. |    exit code of dialog (what was passed to EndDialog)               |
  661. |                                                                              |
  662. \*----------------------------------------------------------------------------*/
  663. BOOL fDialog(int id,HWND hwnd,FARPROC fpfn)
  664. {
  665.     BOOL    f;
  666.     HANDLE    hInst;
  667.  
  668.     hInst = GetWindowWord(hwnd,GWW_HINSTANCE);
  669.     fpfn  = MakeProcInstance(fpfn,hInst);
  670.     f = DialogBox(hInst,MAKEINTRESOURCE(id),hwnd,fpfn);
  671.     FreeProcInstance (fpfn);
  672.     return f;
  673. }
  674.  
  675. void PRIVATE WinSetCursor(HWND hwnd, HCURSOR hcur)
  676. {
  677.     SetCursor(hcur);
  678.     SetClassWord(hwnd,GCW_HCURSOR,(WORD)hcur);
  679. }
  680.  
  681. LONG PRIVATE AppCommand (hwnd, msg, wParam, lParam)
  682.     HWND     hwnd;
  683.     unsigned msg;
  684.     WORD     wParam;
  685.     long     lParam;
  686. {
  687.     switch(wParam)
  688.     {
  689.         case MENU_COPY:
  690.             if (!OpenClipboard(hwnd))
  691.                 break;
  692.  
  693.             EmptyClipboard();
  694.  
  695.             rgbLava.rgbRed = rgbLava.rgbGreen = rgbLava.rgbBlue = 255;
  696.             SetPalette(pLogPal->palPalEntry,0,rgbLava);
  697.             SetPaletteEntries(hpalLava,0,nColors,pLogPal->palPalEntry);
  698.  
  699.             if (hbmLava)
  700.                 SetClipboardData(CF_BITMAP,CopyBitmap(hbmLava));
  701.  
  702.             if (hpalLava)
  703.                 SetClipboardData(CF_PALETTE,CopyPalette(hpalLava));
  704.  
  705.             if (hbmLava)
  706.                 SetClipboardData(CF_DIB,CreateLogicalDib(hbmLava,hpalLava));
  707.  
  708.             CloseClipboard();
  709.             break;
  710.  
  711.     case MENU_ABOUT:
  712.             fDialog(ABOUTBOX,hwnd,AppAbout);
  713.             break;
  714.  
  715.         case MENU_EXIT:
  716.         PostMessage(hwnd,WM_CLOSE,0,0L);
  717.             break;
  718.     case MENU_SATIN:
  719.         fSinPalette = !fSinPalette;
  720.             InitPalette();
  721.         SetupPalette();
  722.         break;
  723.     case MENU_CROSSFADE:
  724.         fCrossFade = !fCrossFade;
  725.         break;
  726.         case MENU_SETDIBITS:
  727.             fSetDIBits = !fSetDIBits;
  728.         break;
  729.         case MENU_COLORCYCLE:
  730.             fColorCycle = !fColorCycle;
  731.         break;
  732.         case MENU_PALCOLORS:
  733.             fPalColors = !fPalColors;
  734.         SetupPalette();
  735.         break;
  736.         case MENU_FASTCYCLE:
  737.             fFastCycle = !fFastCycle;
  738.  
  739.             KillTimer(hwndApp,1);
  740.  
  741.             if (!fFastCycle)
  742.                 SetTimer(hwndApp,1,10,NULL);
  743.  
  744.         break;
  745.         case MENU_NOCOLLAPSE:
  746.             fNoCollapse = !fNoCollapse;
  747.         SetupPalette();
  748.         break;
  749.     case MENU_PALETTE:
  750.             fPalette = !fPalette;
  751.         SetupPalette();
  752.         break;
  753.         case MENU_STOP:
  754.             if (fLavaSem)
  755.                 fStopLava = F_LAVASTOP;
  756.             break;
  757.         case MENU_GO:
  758.             if (!fLavaSem)
  759.             {
  760.                 HDC   hdc;
  761.                 CHARGE apt[40];
  762.                 RECT  rc;
  763.                 int   i;
  764.  
  765.                 //
  766.                 // Change the GO menu item to stop
  767.                 //
  768.                 ChangeMenu(hmenuPopup,MENU_GO,"Stop!",MENU_STOP,MF_CHANGE|MF_BYCOMMAND);
  769.  
  770.                 WinSetCursor(hwnd,LoadCursor(NULL,IDC_WAIT));
  771.  
  772.                 fLavaSem++;
  773.                 fStopLava = F_LAVAOK;
  774.  
  775.                 hdc = GetDC(hwnd);
  776.                 SelectPalette(hdc,hpalLava,FALSE);
  777.                 RealizePalette(hdc);
  778.  
  779.                 //
  780.                 // Hack, if the window is maximized generate a SCREEN size
  781.                 // bitmap
  782.                 //
  783.                 if (IsZoomed(hwnd))
  784.                     SetRect(&rc,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
  785.                 else
  786.                     GetClientRect(hwnd,&rc);
  787.  
  788.                 //
  789.                 //  Pick random charge centers and weights
  790.                 //
  791.                 for (i=0; i<NumCenters; i++)
  792.                 {
  793.                     apt[i].pt = PtRand(rc.right,rc.bottom);
  794.                     do
  795.                         apt[i].value = RAND(9)-4;
  796.                     while (apt[i].value == 0);
  797.                 }
  798.  
  799.                 LavaFlow(hdc, NumCenters, apt, &rc);
  800.  
  801.                 fLavaSem--;
  802.                 ReleaseDC(hwnd,hdc);
  803.  
  804.                 WinSetCursor(hwnd,LoadCursor(NULL,IDC_ARROW));
  805.  
  806.                 //
  807.                 // Change the STOP menu item back to go
  808.                 //
  809.                 ChangeMenu(hmenuPopup,MENU_STOP,"Go!",MENU_GO,MF_CHANGE|MF_BYCOMMAND);
  810.  
  811.                 //
  812.                 //  If the user tried to close the app while we were working
  813.                 //  do it now
  814.                 //
  815.                 if (fStopLava == F_LAVADIE)
  816.                     PostMessage(hwnd,WM_CLOSE,0,0L);
  817.             }
  818.             break;
  819.  
  820.         default:
  821.             switch (wParam & 0xFF00)
  822.             {
  823.                 int n;
  824.  
  825.                 case MENU_NUMCENTERS:
  826.                     n = wParam & 0xFF;
  827.                     CheckMenuItem(hmenuPopup,MENU_NUMCENTERS+NumCenters,MF_UNCHECKED);
  828.                     CheckMenuItem(hmenuPopup,MENU_NUMCENTERS+n,MF_CHECKED);
  829.                     NumCenters = n;
  830.             break;
  831.         case MENU_NUMCOLORS:
  832.                     n = wParam & 0xFF;
  833.             CheckMenuItem(hmenuPopup,MENU_NUMCOLORS+nColors,MF_UNCHECKED);
  834.             CheckMenuItem(hmenuPopup,MENU_NUMCOLORS+n,MF_CHECKED);
  835.             nColors = n;
  836.             SetupPalette();
  837.             break;
  838.         case MENU_BANDSCALE:
  839.                     n = wParam & 0xFF;
  840.             CheckMenuItem(hmenuPopup,MENU_BANDSCALE+nBandScale,MF_UNCHECKED);
  841.             CheckMenuItem(hmenuPopup,MENU_BANDSCALE+n,MF_CHECKED);
  842.             nBandScale = n;
  843.             break;
  844.         }
  845.             break;
  846.     }
  847.     return 0L;
  848. }
  849.  
  850. LONG PRIVATE AppOwnerDraw(HWND hwnd, WORD msg, WORD wParam, LONG lParam)
  851. {
  852.     #define lpMIS  ((LPMEASUREITEMSTRUCT)lParam)
  853.     #define lpDIS  ((LPDRAWITEMSTRUCT)lParam)
  854.  
  855.     switch (msg)
  856.     {
  857.         case WM_MEASUREITEM:
  858.             lpMIS->itemHeight = 10;
  859.             lpMIS->itemWidth  = 10;
  860.         return TRUE;
  861.  
  862.         case WM_DRAWITEM:
  863.             return TRUE;
  864.  
  865.     case WM_DELETEITEM:
  866.         return TRUE;
  867.     }
  868.     return TRUE;
  869. }
  870.  
  871. void InitPalette()
  872. {
  873.     int i;
  874.     int j;
  875.  
  876.     j = 0;
  877.     for(i=0;i<nColors;i++)
  878.     {
  879.         if (fSinPalette)
  880.             paletteval[i] = (int)(MAXI-sin(i*3.14/(nColors-1))*MAXI);
  881.         else
  882.             paletteval[i] = (int)((1-pow(2.0*i/(nColors-1)-1,2.0))*MAXI);
  883.     }
  884. }
  885.  
  886. /*
  887.  *  llSetPixel(hdc,x,y,n)
  888.  *
  889.  *  Sets a pixel in a HDC, will use dither patterns if fPalette not set
  890.  *
  891.  */
  892. void llSetPixel(HDC hdc, int x, int y, int n)
  893. {
  894.     HBRUSH hbrT;
  895.  
  896.     if (fPalette)
  897.     {
  898.     SetPixel(hdc,x,y,PALETTEINDEX(n));
  899.     }
  900.     else
  901.     {
  902.     hbrT = SelectObject(hdc,hbrPalette[n]);
  903.     PatBlt(hdc,x,y,1,1,PATCOPY);
  904.     SelectObject(hdc,hbrT);
  905.     }
  906. }
  907.  
  908. /*
  909.  *  LavaFlow()
  910.  *
  911.  *  calulates the "Lava Lamp" equation for each point in the passed
  912.  *  rectangle.   The Lava equation at any point is defined as the sum
  913.  *  of the distance squared from each center point
  914.  *
  915.  */
  916. void LavaFlow(HDC hdc, int nCenter, CHARGE aptCenter[], PRECT prc)
  917. {
  918.     int      x,y,i,a1;
  919.     static   short a = 0;
  920.     int      dx,dy;
  921.     HDC      hdcBits;
  922.     HBITMAP  hbmT;
  923.     HPALETTE hpalT;
  924.  
  925.     hdcBits = CreateCompatibleDC(hdc);
  926.  
  927.     dx = prc->right  - prc->left;
  928.     dy = prc->bottom - prc->top;
  929.  
  930.     a1 = a;
  931.  
  932.     if (!hbmLava || bmLava.bmWidth != dx || bmLava.bmHeight != dy)
  933.     {
  934.     if (hbmLava)
  935.         DeleteObject(hbmLava);
  936.  
  937.     hbmLava = CreateCompatibleBitmap(hdc,dx,dy);
  938.  
  939.     if (!hbmLava)
  940.          return;
  941.  
  942.     GetObject(hbmLava,sizeof(bmLava),(LPSTR)&bmLava);
  943.  
  944.         pbiLava->biWidth    = dx;
  945.         pbiLava->biHeight   = dy;
  946.         pbiLava->biPlanes   = 1;
  947.         pbiLava->biBitCount = 8;
  948.  
  949.         pbiLava->biClrUsed       = nColors;
  950.         pbiLava->biClrImportant  = 0;
  951.  
  952.         hbmT = SelectObject(hdcBits,hbmLava);
  953.         PatBlt(hdcBits,0,0,dx,dy,BLACKNESS);
  954.         SelectObject(hdcBits,hbmT);
  955.     }
  956.  
  957.     for (y=prc->top; y<prc->bottom; y++)
  958.     {
  959.         if (fCrossFade)
  960.         {
  961.              hbmT = SelectObject(hdcBits,hbmLava);
  962.              hpalT = SelectPalette(hdcBits,hpalLava,FALSE);
  963.              RealizePalette(hdcBits);
  964.  
  965.          a = !a;
  966.          for (x=prc->left+a; x<prc->right; x+=2)
  967.          {
  968.                  i = LavaFlowXY386(nCenter,aptCenter,x,y) / nBandScale % nColors;
  969.                  llSetPixel(hdc,x,y,i);
  970.                  llSetPixel(hdcBits,x,y,i);
  971.              }
  972.  
  973.              SelectObject(hdcBits,hbmT);
  974.              SelectPalette(hdcBits,hpalT,FALSE);
  975.     }
  976.     else
  977.     {
  978.             for (x=prc->left; x<prc->right; x++)
  979.             {
  980.                  i = LavaFlowXY386(nCenter,aptCenter,x,y) / nBandScale % nColors;
  981.                  abScanLine[x] = (BYTE)i;
  982.             }
  983.  
  984.             if (fSetDIBits)
  985.             {
  986.                 SetDIBits(hdc,hbmLava,dy-1-y,1,abScanLine,(LPBITMAPINFO)pbiLava,wDibUsage);
  987.  
  988.                 hbmT = SelectObject(hdcBits,hbmLava);
  989.                 hpalT = SelectPalette(hdcBits,hpalLava,FALSE);
  990.                 RealizePalette(hdcBits);
  991.  
  992.                 BitBlt(hdc,0,y,dx,1,hdcBits,0,y,SRCCOPY);
  993.  
  994.                 SelectObject(hdcBits,hbmT);
  995.                 SelectPalette(hdcBits,hpalT,FALSE);
  996.             }
  997.             else
  998.             {
  999.                 hbmT = SelectObject(hdcBits,hbmLava);
  1000.                 hpalT = SelectPalette(hdcBits,hpalLava,FALSE);
  1001.                 RealizePalette(hdcBits);
  1002.  
  1003.                 for (x=prc->left; x<prc->right; x++)
  1004.                 {
  1005.                     i = abScanLine[x];
  1006.                     llSetPixel(hdc,x,y,i);
  1007.                     llSetPixel(hdcBits,x,y,i);
  1008.                 }
  1009.  
  1010.                 SelectObject(hdcBits,hbmT);
  1011.                 SelectPalette(hdcBits,hpalT,FALSE);
  1012.             }
  1013.         }
  1014.  
  1015.         if (fPalette)
  1016.             CyclePalette(hdc);
  1017.  
  1018.         WinYield();
  1019.  
  1020.         //
  1021.         //  See if we should abort early
  1022.         //
  1023.         if (fStopLava != F_LAVAOK)
  1024.             break;
  1025.     }
  1026.  
  1027.     a = !a1;
  1028.  
  1029.     DeleteDC(hdcBits);
  1030. }
  1031.  
  1032. void SetPalette(PALETTEENTRY * pPal, int nPhase, RGBQUAD rgb)
  1033. {
  1034.     int i,n;
  1035.  
  1036.     for(i=0;i<nColors;i++)
  1037.     {
  1038.         n = paletteval[(nPhase + i) % nColors];
  1039.  
  1040.         pPal[i].peRed   = (BYTE)((long)rgb.rgbRed  * n / MAXI);
  1041.         pPal[i].peGreen = (BYTE)((long)rgb.rgbGreen* n / MAXI);
  1042.         pPal[i].peBlue  = (BYTE)((long)rgb.rgbBlue * n / MAXI);
  1043.  
  1044.         if (fNoCollapse)
  1045.             pPal[i].peFlags = (BYTE)PC_NOCOLLAPSE;
  1046.         else
  1047.             pPal[i].peFlags = (BYTE)PC_RESERVED;
  1048.     }
  1049. }
  1050.  
  1051. void CyclePalette(HDC hdc)
  1052. {
  1053.     int i;
  1054.     PALETTEENTRY peT;
  1055.  
  1056.     static short       nLenColorCycle = 0;
  1057.     static RGBQUAD     rgbLavaOrg;
  1058.     static short       dr,dg,db;
  1059.  
  1060.     if (fColorCycle)
  1061.     {
  1062.         if (nColorPhase >= nLenColorCycle)
  1063.         {
  1064.             nLenColorCycle = (RAND(4) + 1) * nColors;
  1065.             nColorPhase = 0;
  1066.  
  1067.             rgbLavaOrg = rgbLava;
  1068.  
  1069.             dr = RAND(256) - (int)rgbLava.rgbRed;
  1070.             dg = RAND(256) - (int)rgbLava.rgbGreen;
  1071.             db = RAND(256) - (int)rgbLava.rgbBlue;
  1072.         }
  1073.  
  1074.         rgbLava.rgbRed   = (int)rgbLavaOrg.rgbRed   + (long)dr * nColorPhase / nLenColorCycle;
  1075.         rgbLava.rgbGreen = (int)rgbLavaOrg.rgbGreen + (long)dg * nColorPhase / nLenColorCycle;
  1076.         rgbLava.rgbBlue  = (int)rgbLavaOrg.rgbBlue  + (long)db * nColorPhase / nLenColorCycle;
  1077.  
  1078.         nColorPhase++;
  1079.  
  1080.         SetPalette(pLogPal->palPalEntry,nColorPhase,rgbLava);
  1081.     }
  1082.     else
  1083.     {
  1084.         peT = pLogPal->palPalEntry[0];
  1085.  
  1086.         for (i = 0; i < (pLogPal->palNumEntries - 1); i++)
  1087.             pLogPal->palPalEntry[i] = pLogPal->palPalEntry[i+1];
  1088.  
  1089.         pLogPal->palPalEntry[i] = peT;
  1090.     }
  1091.  
  1092.     if (fNoCollapse)
  1093.     {
  1094.         SetPaletteEntries(hpalLava, 0, pLogPal->palNumEntries, pLogPal->palPalEntry);
  1095.         RealizePalette(hdc);
  1096.     }
  1097.     else
  1098.     {
  1099.         AnimatePalette(hpalLava, 0, pLogPal->palNumEntries, pLogPal->palPalEntry);
  1100.     }
  1101. }
  1102.  
  1103. #define WIDTHBYTES(i)   ((i+31)/32*4)      /* ULONG aligned ! */
  1104. #define MAKEP(sel,off)  ((VOID FAR *)MAKELONG(off,sel))
  1105.  
  1106. #define PaletteSize(lpbi) (sizeof(RGBQUAD)*DibNumColors(lpbi))
  1107.  
  1108. WORD DibNumColors(LPBITMAPINFOHEADER lpbi)
  1109. {
  1110.     if (lpbi->biClrUsed != 0 || lpbi->biBitCount == 24)
  1111.         return (WORD)lpbi->biClrUsed;
  1112.     else
  1113.         return 1<<lpbi->biBitCount;
  1114. }
  1115.  
  1116. /*
  1117.  *  CreateLogicalDib
  1118.  *
  1119.  *  Given a DDB and a HPALETTE create a "logical" DIB
  1120.  *
  1121.  *  if the HBITMAP is NULL create a DIB from the system "stock" bitmap
  1122.  *      This is used to save a logical palette to a disk file as a DIB
  1123.  *
  1124.  *  if the HPALETTE is NULL use the system "stock" palette (ie the
  1125.  *      system palette)
  1126.  *
  1127.  *  a "logical" DIB is a DIB where the DIB color table *exactly* matches
  1128.  *  the passed logical palette.  There will be no system colors in the DIB
  1129.  *  block, and a pixel value of <n> in the DIB will correspond to logical
  1130.  *  palette index <n>.
  1131.  *
  1132.  *  This is accomplished by doing a GetDIBits() with the DIB_PAL_COLORS
  1133.  *  option then converting the palindexes returned in the color table
  1134.  *  from palette indexes to logical RGB values.  The entire passed logical
  1135.  *  palette is always copied to the DIB color table.
  1136.  *
  1137.  *  The DIB color table will have exactly the same number of entries as
  1138.  *  the logical palette.  Normaly GetDIBits() will always set biClrUsed to
  1139.  *  the maximum colors supported by the device regardless of the number of
  1140.  *  colors in the logical palette
  1141.  *
  1142.  *  Why would you want to do this?  The major reason for a "logical" DIB
  1143.  *  is so when the DIB is written to a disk file then reloaded the logical
  1144.  *  palette created from the DIB color table will be the same as one used
  1145.  *  originaly to create the bitmap.  It also will prevent GDI from doing
  1146.  *  nearest color matching on PC_RESERVED palettes.
  1147.  *
  1148.  *  ** What do we do if the logical palette has more than 256 entries!!!!!
  1149.  *  ** GetDIBits() may return logical palette index's that are greater than
  1150.  *  ** 256, we cant represent these colors in the "logical" DIB
  1151.  *  **
  1152.  *  ** for now hose the caller?????
  1153.  *
  1154.  */
  1155.  
  1156. HANDLE CreateLogicalDib(HBITMAP hbm, HPALETTE hpal)
  1157. {
  1158.     BITMAP              bm;
  1159.     BITMAPINFOHEADER    bi;
  1160.     LPBITMAPINFOHEADER  lpDib;      // pointer to DIB
  1161.     LPBITMAPINFOHEADER  lpbi;       // temp pointer to BITMAPINFO
  1162.     DWORD               dwLen;
  1163.     DWORD               dw;
  1164.     int                 n;
  1165.     int                 nColors;
  1166.     HANDLE              hdib;
  1167.     HDC                 hdc;
  1168.     BYTE FAR *          lpBits;
  1169.     WORD FAR *          lpCT;
  1170.     RGBQUAD FAR *       lpRgb;
  1171.     PALETTEENTRY        peT;
  1172.     HPALETTE            hpalT;
  1173.     WORD                biBits;
  1174.  
  1175.     if (hpal == NULL)
  1176.         hpal = GetStockObject(DEFAULT_PALETTE);
  1177.  
  1178.     if (hbm == NULL)
  1179.         hbm = NULL; // ????GetStockObject(STOCK_BITMAP);
  1180.  
  1181.     GetObject(hpal,sizeof(nColors),(LPSTR)&nColors);
  1182.     GetObject(hbm,sizeof(bm),(LPSTR)&bm);
  1183.  
  1184.     biBits = nColors > 16 ? 8 : 4;
  1185.  
  1186.     if (nColors > 256)      // ACK!
  1187.         ;                   // How do we handle this????
  1188.  
  1189.     bi.biSize               = sizeof(BITMAPINFOHEADER);
  1190.     bi.biWidth              = bm.bmWidth;
  1191.     bi.biHeight             = bm.bmHeight;
  1192.     bi.biPlanes             = 1;
  1193.     bi.biBitCount           = biBits;
  1194.     bi.biCompression        = BI_RGB;
  1195.     bi.biSizeImage          = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
  1196.     bi.biXPelsPerMeter      = 0;
  1197.     bi.biYPelsPerMeter      = 0;
  1198.     bi.biClrUsed            = nColors;
  1199.     bi.biClrImportant       = 0;
  1200.  
  1201.     dwLen = bi.biSize + PaletteSize(&bi) + bi.biSizeImage;
  1202.  
  1203.     hdib = GlobalAlloc(GMEM_MOVEABLE,dwLen);
  1204.  
  1205.     if (!hdib)
  1206.         return NULL;
  1207.  
  1208.     lpbi = MAKEP(GlobalAlloc(GMEM_FIXED,bi.biSize + 256 * sizeof(RGBQUAD)),0);
  1209.  
  1210.     if (!lpbi)
  1211.     {
  1212.         GlobalFree(hdib);
  1213.         return NULL;
  1214.     }
  1215.  
  1216.     hdc = GetDC(NULL);
  1217.     hpalT = SelectPalette(hdc,hpal,FALSE);
  1218.     RealizePalette(hdc);  // why is this needed on a MEMORY DC? GDI bug??
  1219.  
  1220.     lpDib = (VOID FAR *)GlobalLock(hdib);
  1221.  
  1222.     *lpbi  = bi;
  1223.     *lpDib = bi;
  1224.     lpCT   = (WORD FAR *)((LPSTR)lpbi + (WORD)lpbi->biSize);
  1225.     lpRgb  = (RGBQUAD FAR *)((LPSTR)lpDib + (WORD)lpDib->biSize);
  1226.     lpBits = (LPSTR)lpDib + (WORD)lpDib->biSize + PaletteSize(lpDib);
  1227.  
  1228.     /*
  1229.      *  call GetDIBits to get the DIB bits and fill the color table with
  1230.      *  logical palette index's
  1231.      */
  1232.     GetDIBits(hdc, hbm, 0, (WORD)bi.biHeight,
  1233.         lpBits,(LPBITMAPINFO)lpbi, DIB_PAL_COLORS);
  1234.  
  1235.     /*
  1236.      *  Now convert the DIB bits into "real" logical palette index's
  1237.      *
  1238.      *  lpCT        points to the DIB color table wich is a WORD array of
  1239.      *              logical palette index's
  1240.      *
  1241.      *  lpBits      points to the DIB bits, each DIB pixel is a index into
  1242.      *              the DIB color table.
  1243.      *
  1244.      */
  1245.  
  1246.     if (biBits == 8)
  1247.     {
  1248.         for (dw = 0; dw < bi.biSizeImage; dw++, ((BYTE huge *)lpBits)++)
  1249.             *lpBits = (BYTE)lpCT[*lpBits];
  1250.     }
  1251.     else // biBits == 4
  1252.     {
  1253.         for (dw = 0; dw < bi.biSizeImage; dw++, ((BYTE huge *)lpBits)++)
  1254.             *lpBits = lpCT[*lpBits & 0x0F] | (lpCT[(*lpBits >> 4) & 0x0F] << 4);
  1255.     }
  1256.  
  1257.     /*
  1258.      *  Now copy the RGBs in the logical palette to the dib color table
  1259.      */
  1260.     for (n=0; n<nColors; n++,lpRgb++)
  1261.     {
  1262.         GetPaletteEntries(hpal,n,1,&peT);
  1263.  
  1264.         lpRgb->rgbRed      = peT.peRed;
  1265.         lpRgb->rgbGreen    = peT.peGreen;
  1266.         lpRgb->rgbBlue     = peT.peBlue;
  1267.         lpRgb->rgbReserved = (BYTE)0;
  1268.     }
  1269.  
  1270.     GlobalUnlock(hdib);
  1271.     GlobalFree(HIWORD((DWORD)lpbi));
  1272.  
  1273.     SelectPalette(hdc,hpalT,FALSE);
  1274.     ReleaseDC(NULL,hdc);
  1275.  
  1276.     return hdib;
  1277. }
  1278.  
  1279. /*----------------------------------------------------------------------------
  1280.   CopyBitmap (hbm) - Returns a copy of the passed bitmap
  1281.   ----------------------------------------------------------------------------*/
  1282. HBITMAP CopyBitmap (HBITMAP hbm)
  1283. {
  1284.     HDC     hMemDCsrc;
  1285.     HDC     hMemDCdst;
  1286.     HDC     hdc;
  1287.     HBITMAP hNewBm;
  1288.     BITMAP  bm;
  1289.  
  1290.     if (!hbm)
  1291.          return NULL;
  1292.  
  1293.     hdc = GetDC(NULL);
  1294.     hMemDCsrc = CreateCompatibleDC(hdc);
  1295.     hMemDCdst = CreateCompatibleDC(hdc);
  1296.  
  1297.     GetObject(hbm,sizeof(BITMAP),(LPSTR)&bm);
  1298.  
  1299.     hNewBm = CreateBitmap(bm.bmWidth,bm.bmHeight,bm.bmPlanes,bm.bmBitsPixel,NULL);
  1300.  
  1301.     if (hNewBm)
  1302.     {
  1303.         SelectObject (hMemDCsrc,hbm);
  1304.         SelectObject (hMemDCdst,hNewBm);
  1305.  
  1306.         BitBlt (hMemDCdst,0,0,bm.bmWidth,bm.bmHeight,hMemDCsrc,0,0,SRCCOPY);
  1307.     }
  1308.  
  1309.     ReleaseDC(NULL,hdc);
  1310.     DeleteDC(hMemDCsrc);
  1311.     DeleteDC(hMemDCdst);
  1312.     return hNewBm;
  1313. }
  1314.  
  1315. /*
  1316.  * CopyPalette, makes a copy of a GDI logical palette
  1317.  */
  1318. HPALETTE CopyPalette(HPALETTE hpal)
  1319. {
  1320.     PLOGPALETTE ppal;
  1321.     int         nNumEntries;
  1322.  
  1323.     if (!hpal)
  1324.     return NULL;
  1325.  
  1326.     GetObject(hpal,sizeof(int),(LPSTR)&nNumEntries);
  1327.  
  1328.     if (nNumEntries == 0)
  1329.         return NULL;
  1330.  
  1331.     ppal = (PLOGPALETTE)LocalAlloc(LPTR,sizeof(LOGPALETTE) +
  1332.                 nNumEntries * sizeof(PALETTEENTRY));
  1333.  
  1334.     if (!ppal)
  1335.         return NULL;
  1336.  
  1337.     ppal->palVersion    = 0x300;
  1338.     ppal->palNumEntries = nNumEntries;
  1339.  
  1340.     GetPaletteEntries(hpal,0,nNumEntries,ppal->palPalEntry);
  1341.  
  1342.     hpal = CreatePalette(ppal);
  1343.  
  1344.     LocalFree((HANDLE)ppal);
  1345.     return hpal;
  1346. }
  1347.