home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / zoombm.zip / ZOOMBMP.C < prev    next >
Text File  |  1993-07-27  |  20KB  |  461 lines

  1. /* ********************************************************************** */
  2. /*                                                                        */
  3. /*   ZoomBMP  Main Module                                                 */
  4. /*                                                                        */
  5. /*   This quick and dirty sample demostrates one method for displaying,   */
  6. /*   zooming in, and zooming out of a bitmap. Clicking in the window      */
  7. /*   with the left mouse button causes a zoom in. Clicking in the window  */
  8. /*   with the right mouse button causes a zoom out.                       */
  9. /*                                                                        */
  10. /*   This is a very simplistic program that is meant only to demonstrate  */
  11. /*   a method of calculating source and target rectangles when doing      */
  12. /*   bitmap "zooming". It is not meant as a demonstration of good,        */
  13. /*   general (PM) programing (i.e. not a lot of time was spent on it's    */
  14. /*   development). It is meant more to demonstrate ideas rather than      */
  15. /*   actual code implementation.                                          */
  16. /*                                                                        */
  17. /*   My apologies if the original choice for display bitmap offends       */
  18. /*   anyone, as that was never the intention.                             */
  19. /*                                                                        */
  20. /*    Standard legalities:                                                */
  21. /*    DISCLAIMER OF WARRANTIES.  The following [enclosed] code is         */
  22. /*    sample code created by IBM Corporation. This sample code is not     */
  23. /*    part of any standard or IBM product and is provided to you solely   */
  24. /*    for  the purpose of assisting you in the development of your        */
  25. /*    applications.  The code is provided "AS IS", without                */
  26. /*    warranty of any kind.  IBM shall not be liable for any damages      */
  27. /*    arising out of your use of the sample code, even if they have been  */
  28. /*    advised of the possibility of such damages.                         */
  29. /*                                                                        */
  30. /*    John Webb                                    (c) IBM Corp, 1993     */
  31. /* ********************************************************************** */
  32.  
  33.  
  34. #define INCL_WIN
  35. #define INCL_GPI
  36. #include <os2.h>
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include "ZoomBMP.h"
  41.  
  42.       /* ------ defines for bit blit points array indices ------ */
  43. #define  TGT_BL  0      //  lower-left corner of target rect
  44. #define  TGT_TR  1      //  upper-right corner of target rect
  45. #define  SRC_BL  2      //  lower-left corner of source rect
  46. #define  SRC_TR  3      //  upper-right corner of source rect
  47.  
  48. #define  NOMINAL_REZ 100   // 100% image size
  49.  
  50. HAB     hab;
  51. HMQ     hmq;
  52. HWND    hwndClient;
  53. HWND    hwndFrame;
  54. HWND    hwndVScroll ;
  55. HBITMAP hbmBitmap ;
  56.  
  57. QMSG    qmsg;
  58.  
  59. ULONG   ulBitmapCX ;
  60. ULONG   ulBitmapCY ;
  61.  
  62.     /* ---- These scale factors will be used to zoom in and out ----- */
  63.     /*
  64.      *   The Source Scale Factor will be used for zooming in from the
  65.      *   normal size bitmap, and the Target Scale Factor will be used
  66.      *   for zooming out from the normal sized bitmap. Note that only
  67.      *   one of these factors will ever be greater than 1 at any given
  68.      *   time. By using two scaling factors, we can get away without having
  69.      *   to use floating point (e.g. we will never need a factor of 0.5),
  70.      *   and we can make sure we are always working will the minimum number
  71.      *   of points necessary. Also note that zooming in and out will be done
  72.      *   by a fixed factor of increment of X2 ( i.e. *4, *2, *1, *1/2, *1/4)
  73.      */
  74. ULONG   ulSourceScaleFactor = 1 ;
  75. ULONG   ulTargetScaleFactor = 1 ;
  76.  
  77. PSZ    szClassName  = "ZoomBMPClass" ;
  78. PSZ    szMainTitle  = "ZoomBMP" ;
  79. PSZ    szErrorTitle = "ZoomBMP Error" ;
  80.  
  81.         /* ----------------  Prototypes  ------------------------ */
  82. MRESULT EXPENTRY MainWindowProc( HWND, USHORT, MPARAM, MPARAM );
  83. VOID             CalcTransformedPoints( HWND, PPOINTL );
  84. VOID             SetTitlePercentageIndicator( ULONG );
  85. VOID             ShowErrorWindow( PSZ, BOOL );
  86.  
  87.  
  88.  
  89. /* ********************************************************************** */
  90. /*                                                                        */
  91. /*   Main                                                                 */
  92. /*                                                                        */
  93. /*      Standard Main window creation and message loop. Boring.           */
  94. /*                                                                        */
  95. /* ********************************************************************** */
  96.  
  97. VOID main()
  98. {
  99.  
  100.   if ( (hab = WinInitialize( 0L )) == (HAB) NULL ){
  101.      printf( "ZoomBMP Error:  WinInitialize failed \n" );
  102.      return;
  103.   }
  104.   else {
  105.      if ( (hmq = WinCreateMsgQueue( hab, 0 )) == (HMQ) NULL ){
  106.         printf( "ZoomBMP Error:  WinCreateMsgQueue failed \n" );
  107.         return;
  108.      }
  109.      else {
  110.  
  111.        ULONG fulCreate= FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER |
  112.                         FCF_MINMAX | FCF_SHELLPOSITION | FCF_ICON  ;
  113.  
  114.         WinSetPointer( HWND_DESKTOP,
  115.                        WinQuerySysPointer(HWND_DESKTOP,SPTR_WAIT,TRUE));
  116.  
  117.         WinRegisterClass(hab, szClassName, (PFNWP)MainWindowProc, CS_SIZEREDRAW, 0);
  118.  
  119.         hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
  120.                                        0L,
  121.                                        (PULONG)&fulCreate,
  122.                                        szClassName ,
  123.                                        "",
  124.                                        0L,
  125.                                        (HMODULE)NULL,
  126.                                        ID_MAIN_WIN,
  127.                                        &hwndClient);
  128.         if ( hwndFrame == NULLHANDLE ) {
  129.            ShowErrorWindow( "Error creating Main window !", TRUE );
  130.         }
  131.         else {
  132.            PID     pid ;
  133.            SWCNTRL swCntrl;
  134.            HSWITCH hSwitch ;
  135.  
  136.              /* ------  set the title percentage indicator  ------ */
  137.            SetTitlePercentageIndicator( NOMINAL_REZ );
  138.              /* ---------  set window size and pos  -------------- */
  139.            WinSetWindowPos( hwndFrame,
  140.                             HWND_TOP,
  141.                             0, 0, 2*ulBitmapCX, ulBitmapCY,
  142.                             SWP_SHOW | SWP_SIZE | SWP_ACTIVATE );
  143.  
  144.             /* ----------- add program to tasklist  --------------- */
  145.            WinQueryWindowProcess( hwndFrame, &pid, NULL );
  146.            swCntrl.hwnd = hwndFrame ;
  147.            swCntrl.hwndIcon = (HWND) NULL ;
  148.            swCntrl.hprog = (HPROGRAM) NULL ;
  149.            swCntrl.idProcess = pid ;
  150.            swCntrl.idSession = (LONG) NULL ;
  151.            swCntrl.uchVisibility = SWL_VISIBLE ;
  152.            swCntrl.fbJump = SWL_JUMPABLE ;
  153.            sprintf( swCntrl.szSwtitle, szMainTitle );
  154.            hSwitch = WinCreateSwitchEntry( hab, (PSWCNTRL)&swCntrl);
  155.  
  156.  
  157.            WinSetPointer(HWND_DESKTOP,
  158.                          WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,TRUE));
  159.  
  160.               /* ---------- start the main processing loop ----------- */
  161.            while (WinGetMsg(hab, &qmsg,NULLHANDLE,0,0)){
  162.                WinDispatchMsg(hab, &qmsg);
  163.            }
  164.  
  165.            WinRemoveSwitchEntry( hSwitch );
  166.            WinDestroyWindow(hwndFrame);
  167.         }  /* end of else */
  168.  
  169.         WinSetPointer(HWND_DESKTOP,
  170.                       WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,TRUE));
  171.         WinDestroyMsgQueue(hmq);
  172.      }  /* end of else ( ...WinCreateMsgQueue() */
  173.  
  174.    WinTerminate(hab);
  175.    }  /* end of else (...WinInitialize(NULL) */
  176. }  /*  end of main() */
  177.  
  178. /* ********************************************************************** */
  179. /*                                                                        */
  180. /*   MainWindowProc                                                       */
  181. /*                                                                        */
  182. /* ********************************************************************** */
  183.  
  184. MRESULT EXPENTRY
  185. MainWindowProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  186. {
  187.  
  188.   switch (msg) {
  189.  
  190.     case WM_CREATE:
  191.         {
  192.           HPS                 hps;
  193.           BITMAPINFOHEADER2   bmp2Data ;
  194.  
  195.                /* ---- get temp PS for the window  --------- */
  196.            hps = WinGetPS( hwnd );
  197.  
  198.                /* ----- load bitmap out of resource  ------- */
  199.            hbmBitmap = GpiLoadBitmap( hps, NULLHANDLE, ID_BMP, 0L, 0L );
  200.  
  201.                /* ------- get actual bitmap size  ---------- */
  202.            bmp2Data.cbFix = 16 ;
  203.            GpiQueryBitmapInfoHeader( hbmBitmap, &bmp2Data );
  204.            ulBitmapCX = bmp2Data.cx ;
  205.            ulBitmapCY = bmp2Data.cy ;
  206.  
  207.            WinReleasePS( hps );
  208.         }
  209.         break;
  210.  
  211.     case WM_BUTTON1UP :
  212.         {
  213.           ULONG   ulPercentScale ;
  214.            /* -----------------  ZOOM IN  ------------------ */
  215.            /*
  216.             * First check if we are zoomed out any. If so then we need to
  217.             * remove some of the "zoom out" factor. Otherwise, bump up the
  218.             * "zoom in" factor.
  219.             */
  220.         if ( ulTargetScaleFactor > 1 ){
  221.            ulTargetScaleFactor /= 2 ;
  222.            ulPercentScale = NOMINAL_REZ / ulTargetScaleFactor ;
  223.         }
  224.         else {
  225.            ulSourceScaleFactor *= 2 ;
  226.            ulPercentScale = NOMINAL_REZ * ulSourceScaleFactor ;
  227.         }
  228.            /* ------ adjust title bar size indicator  ----------- */
  229.         SetTitlePercentageIndicator( ulPercentScale );
  230.            /* ------------- trigger window repaint -------------- */
  231.         WinInvalidateRect( hwnd, (PRECTL)NULL, FALSE );  
  232.         }
  233.         break;
  234.  
  235.     case WM_BUTTON2UP :
  236.         {
  237.           ULONG   ulPercentScale ;
  238.            /* -----------------  ZOOM OUT ----------------- */
  239.            /*
  240.             * First check if we are zoomed in any. If so then we need to
  241.             * remove some of the "zoom in" factor. Otherwise, bump up the
  242.             * "zoom out" factor.
  243.             */
  244.         if ( ulSourceScaleFactor > 1 ){
  245.           ulSourceScaleFactor /= 2 ;
  246.           ulPercentScale = NOMINAL_REZ * ulSourceScaleFactor ;
  247.         }
  248.         else {
  249.            ulTargetScaleFactor *= 2 ;
  250.            ulPercentScale = NOMINAL_REZ / ulTargetScaleFactor ;
  251.         }
  252.            /* ------ adjust title bar size indicator  ----------- */
  253.         SetTitlePercentageIndicator( ulPercentScale );
  254.            /* ------------- trigger window repaint -------------- */
  255.         WinInvalidateRect( hwnd, (PRECTL)NULL, FALSE );  
  256.         }
  257.         break;
  258.  
  259.     case WM_PAINT:
  260.        {
  261.          RECTL   rectl ;
  262.          HPS     hps;
  263.          POINTL  aptlPoints[4] ;
  264.  
  265.          hps = WinBeginPaint( hwnd, (HPS) NULL, &rectl );
  266.  
  267.              /* ------- calc source and target boundry points  ------- */
  268.          CalcTransformedPoints( hwnd, aptlPoints );
  269.  
  270.              /* ----------------- wait pointer on  ---------------- */
  271.          WinSetPointer( HWND_DESKTOP,
  272.                         WinQuerySysPointer(HWND_DESKTOP,SPTR_WAIT,TRUE));
  273.  
  274.              /* ------ if zoomed out, fill in black around image ----- */
  275.          if ( ulTargetScaleFactor > 1 ) {
  276.             WinFillRect( hps, &rectl, CLR_BLACK );
  277.          }
  278.  
  279.              /* ------  blit the bitmap into the window  --------- */
  280.          GpiWCBitBlt( hps,
  281.                       hbmBitmap,
  282.                       4L,
  283.                       aptlPoints,
  284.                       ROP_SRCCOPY,
  285.                       BBO_IGNORE );
  286.  
  287.               /* ------------ restore normal pointer  -------------- */
  288.           WinSetPointer(HWND_DESKTOP,
  289.                         WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,TRUE));
  290.  
  291.          WinEndPaint( hps );
  292.       }
  293.       break;
  294.  
  295.     case WM_DESTROY :
  296.       GpiDeleteBitmap( hbmBitmap );
  297.       return WinDefWindowProc(hwnd,msg,mp1,mp2);
  298.  
  299.     default:
  300.       return WinDefWindowProc(hwnd,msg,mp1,mp2);
  301.  
  302.   } /*  end of switch () */
  303.   return( FALSE );
  304.  
  305. } /*  end of MainWindowProc */
  306. /* ********************************************************************** */
  307. /*                                                                        */
  308. /*   CalcTransformedPoints()                                              */
  309. /*                                                                        */
  310. /*      This is were the fun starts...                                    */
  311. /*                                                                        */
  312. /*      Note: There are four points that need to be calculated in the     */
  313. /*            aptlPoints array:                                           */
  314. /*          aptlPoints[TGT_BL] = lower-left corner of target rect         */
  315. /*          aptlPoints[TGT_TR] = upper-right corner of target rect        */
  316. /*          aptlPoints[SRC_BL] = lower-left corner of source rect         */
  317. /*          aptlPoints[SRC_TR] = upper-right corner of source rect        */
  318. /*                                                                        */
  319. /*                                                                        */
  320. /* ********************************************************************** */
  321. VOID
  322. CalcTransformedPoints( HWND hwndTarget, PPOINTL aptlPoints )
  323. {
  324.   POINTL  ptlWindowCenter,      // center point of window
  325.           ptlBmpCenter,         // center point of actual bitmap
  326.           ptlSourceCenter,      // center point of source rectangle
  327.           ptlTargetCenter ;     // center point of target rectangle
  328.  
  329.   RECTL   rectl;
  330.  
  331.      /* ------ get current window size and window center pt  ----- */
  332.   WinQueryWindowRect( hwndTarget, &rectl );
  333.   ptlWindowCenter.x = (rectl.xRight - rectl.xLeft) / 2 ;
  334.   ptlWindowCenter.y = (rectl.yTop - rectl.yBottom) / 2 ;
  335.  
  336.       /* -------- set "normal" bitmap to get aspect ratio -------- */
  337.       /*
  338.        *  First set source rectangle and target rectangle to be
  339.        *  equal to the window rectangle. If drawn now, the bitmap
  340.        *  would appear justified in the lower left corner ( i.e. it's
  341.        *  0,0 origin at the 0,0 origin of the window). Note that if
  342.        *  the actual bitmap rect is smaller than the window rect, the
  343.        *  extra area will be filled in with black. This step might be
  344.        *  able to be skipped, but for demostration purposes it's good
  345.        *  to start out at a "known" normal sized point
  346.        */
  347.   aptlPoints[TGT_BL].x = aptlPoints[SRC_BL].x = rectl.xLeft ;
  348.   aptlPoints[TGT_BL].y = aptlPoints[SRC_BL].y = rectl.yBottom ;
  349.   aptlPoints[TGT_TR].x = aptlPoints[SRC_TR].x = rectl.xRight ;
  350.   aptlPoints[TGT_TR].y = aptlPoints[SRC_TR].y = rectl.yTop ;
  351.  
  352.       /* -----------  apply source scaling  ----------------- */
  353.       /*
  354.        *  The trick for good performance is to make sure we are only
  355.        *  manipulating the smallest number of points necessary (i.e.
  356.        *  only those that will fit with in the window rect). The Source
  357.        *  Scaling Factor is used for zooming IN. However, we are going
  358.        *  to use the factor to reduce the source rectangle rather than
  359.        *  enlarge the target. For example, assume our Source Scaling
  360.        *  factor is 2. We want to see everything twice as large as it
  361.        *  was; however, given the same window size, we will only be
  362.        *  seeing half the number of original bitmap points. Therefore,
  363.        *  instead of multipling the target rectangle by the source factor
  364.        *  to create a target twice as large (of which half the points won't
  365.        *  be seen), we will divide the source rectangle by the source factor
  366.        *  to create a source that is half as big and will be stretched to
  367.        *  fit the window doubling it's size in the process. This way we only
  368.        *  manipulate the minimum number of points necessary.
  369.        *
  370.        *  Note: we are making an assumtion that Source bottom left (SRC_BL)
  371.        *      is at 0,0 and Source top right (SRC_TR) is equal to source size
  372.        */
  373.   aptlPoints[SRC_TR].x /= ulSourceScaleFactor ;
  374.   aptlPoints[SRC_TR].y /= ulSourceScaleFactor ;
  375.  
  376.       /* ------------ get center point of scaled source  ---------- */
  377.   ptlSourceCenter.x = (aptlPoints[SRC_TR].x - aptlPoints[SRC_BL].x) / 2 ;
  378.   ptlSourceCenter.y = (aptlPoints[SRC_TR].y - aptlPoints[SRC_BL].y) / 2 ;
  379.  
  380.       /* -----------  center Bitmap in Source rect --------------- */
  381.       /*
  382.        *  We want to "slide" the source rect around (without changing
  383.        *  it's size!) to get the center of the actual bitmap aligned with
  384.        *  the center of the source rectangle
  385.        */
  386.   ptlBmpCenter.x = ulBitmapCX / 2 ;
  387.   ptlBmpCenter.y = ulBitmapCY / 2 ;
  388.   aptlPoints[SRC_BL].x += ptlBmpCenter.x - ptlSourceCenter.x ;
  389.   aptlPoints[SRC_BL].y += ptlBmpCenter.y - ptlSourceCenter.y ;
  390.   aptlPoints[SRC_TR].x += ptlBmpCenter.x - ptlSourceCenter.x ;
  391.   aptlPoints[SRC_TR].y += ptlBmpCenter.y - ptlSourceCenter.y ;
  392.  
  393.       /* --------- apply target scaling  ---------- */
  394.       /*
  395.        *  See description above about source scaling. Target scaling
  396.        *  is done to "zoom out". The target rect is divided by the
  397.        *  scaling factor to decrease the size and cause the original
  398.        *  bitmap to be compressed into the rect.
  399.        */
  400.   aptlPoints[TGT_TR].x /= ulTargetScaleFactor ;
  401.   aptlPoints[TGT_TR].y /= ulTargetScaleFactor ;
  402.  
  403.       /* --------- adjust target so always centered --------- */
  404.       /*
  405.        *  Slide Target rectangle so that it is centered in
  406.        *  the window rectangle
  407.        */
  408.   ptlTargetCenter.x = (aptlPoints[TGT_TR].x - aptlPoints[TGT_BL].x) / 2 ;
  409.   ptlTargetCenter.y = (aptlPoints[TGT_TR].y - aptlPoints[TGT_BL].y) / 2 ;
  410.  
  411.   aptlPoints[TGT_BL].x += ptlWindowCenter.x - ptlTargetCenter.x ;
  412.   aptlPoints[TGT_BL].y += ptlWindowCenter.y - ptlTargetCenter.y ;
  413.   aptlPoints[TGT_TR].x += ptlWindowCenter.x - ptlTargetCenter.x ;
  414.   aptlPoints[TGT_TR].y += ptlWindowCenter.y - ptlTargetCenter.y ;
  415.  
  416. } // end of CalcTransformedPoints
  417. /* ********************************************************************** */
  418. /*                                                                        */
  419. /*   SetTitlePercentageIndicator()                                        */
  420. /*                                                                        */
  421. /* ********************************************************************** */
  422. VOID
  423. SetTitlePercentageIndicator( ULONG ulPercent )
  424. {
  425.   CHAR  acString[64];
  426.  
  427.   sprintf( acString, " %s - %d%%", szMainTitle, ulPercent );
  428.   WinSetWindowText( hwndFrame, acString );
  429.  
  430. }  // end of SetTitlePercentageIndicator()
  431. /* ********************************************************************** */
  432. /*                                                                        */
  433. /*   ShowErrorWindow                                                      */
  434. /*                                                                        */
  435. /* ********************************************************************** */
  436. VOID
  437. ShowErrorWindow( PSZ  pszErrorMsg, BOOL bUseLastError )
  438. {
  439.   CHAR      acErrorBuffer[256] ;
  440.  
  441.   if ( bUseLastError ) {
  442.       ERRORID   errorID = WinGetLastError( hab );
  443.  
  444.       sprintf( acErrorBuffer,
  445.                "%s \n(code = 0x%lX)",
  446.                pszErrorMsg,
  447.                (ULONG) errorID );
  448.       pszErrorMsg = (PSZ) acErrorBuffer ;
  449.   }  /* end of if ( bUseLastError ) */
  450.  
  451.   WinMessageBox( HWND_DESKTOP,
  452.                  HWND_DESKTOP,
  453.                  pszErrorMsg ,
  454.                  szErrorTitle ,
  455.                  0,
  456.                  MB_CUACRITICAL | MB_OK );
  457.  
  458. }
  459. 
  460.  
  461.