home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / animate.c next >
C/C++ Source or Header  |  2002-07-05  |  19KB  |  508 lines

  1.  
  2. /*
  3.  *@@sourcefile animate.c:
  4.  *      contains a bit of helper code for animations.
  5.  *
  6.  *      This is a new file with V0.81. Most of this code used to reside
  7.  *      in common.c with previous versions.
  8.  *      Note that with V0.9.0, the code for icon animations has been
  9.  *      moved to the new comctl.c file.
  10.  *
  11.  *      Usage: All PM programs.
  12.  *
  13.  *      Function prefixes (new with V0.81):
  14.  *      --  anm*   Animation helper functions
  15.  *
  16.  *      Note: Version numbering in this file relates to XWorkplace version
  17.  *            numbering.
  18.  *
  19.  *@@header "helpers\animate.h"
  20.  */
  21.  
  22. /*
  23.  *      Copyright (C) 1997-2000 Ulrich Möller.
  24.  *      This file is part of the "XWorkplace helpers" source package.
  25.  *      This is free software; you can redistribute it and/or modify
  26.  *      it under the terms of the GNU General Public License as published
  27.  *      by the Free Software Foundation, in version 2 as it comes in the
  28.  *      "COPYING" file of the XWorkplace main distribution.
  29.  *      This program is distributed in the hope that it will be useful,
  30.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  31.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  32.  *      GNU General Public License for more details.
  33.  */
  34.  
  35. #define OS2EMX_PLAIN_CHAR
  36.     // this is needed for "os2emx.h"; if this is defined,
  37.     // emx will define PSZ as _signed_ char, otherwise
  38.     // as unsigned char
  39.  
  40. #define INCL_DOSPROCESS
  41. #define INCL_DOSDEVICES
  42. #define INCL_DOSDEVIOCTL
  43. #define INCL_DOSMISC
  44. #define INCL_DOSERRORS
  45.  
  46. #define INCL_WINWINDOWMGR
  47. #define INCL_WINPOINTERS
  48. #define INCL_WINSYS
  49.  
  50. #define INCL_GPILOGCOLORTABLE
  51. #define INCL_GPIPRIMITIVES
  52. #define INCL_GPIBITMAPS             // added UM 99-10-22; needed for EMX headers
  53. #include <os2.h>
  54.  
  55. #include <stdlib.h>
  56. #include <string.h>
  57.  
  58. #include "setup.h"                      // code generation and debugging options
  59.  
  60. // #include "helpers\animate.h"
  61.  
  62. // #include "helpers\winh.h"
  63. // #include "helpers\gpih.h"
  64.  
  65. /*
  66.  *@@category: Helpers\PM helpers\Animation helpers
  67.  *      See animate.c.
  68.  */
  69.  
  70. /*
  71.  *@@ anmBlowUpBitmap:
  72.  *      this displays an animation based on a given bitmap.
  73.  *      The bitmap is "blown up" in that it is continually
  74.  *      increased in size until the original size is reached.
  75.  *      The animation is calculated so that it lasts exactly
  76.  *      ulAnimation milliseconds, no matter how fast the
  77.  *      system is.
  78.  *
  79.  *      This function does not return until the animation
  80.  *      has completed.
  81.  *
  82.  *      You should run this routine in a thread with higher-
  83.  *      than-normal priority, because otherwise the kernel
  84.  *      might interrupt the thread, causing a somewhat jerky
  85.  *      display.
  86.  *
  87.  *      Returns the count of animation steps that were drawn.
  88.  *      This is dependent on the speed of the system.
  89.  *
  90.  *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
  91.  */
  92.  
  93. BOOL anmBlowUpBitmap(HPS hps,               // in: from WinGetScreenPS(HWND_DESKTOP)
  94.                      HBITMAP hbm,           // in: bitmap to be displayed
  95.                      ULONG ulAnimationTime) // in: total animation time (ms)
  96. {
  97.     ULONG   ulrc = 0;
  98.     ULONG   ulInitialTime,
  99.             ulNowTime;
  100.             // ulCurrentSize = 10;
  101.  
  102.     if (hps)
  103.     {
  104.         POINTL  ptl = {0, 0};
  105.         RECTL   rtlStretch;
  106.         ULONG   ul,
  107.                 ulSteps = 20;
  108.         BITMAPINFOHEADER bih;
  109.         GpiQueryBitmapParameters(hbm, &bih);
  110.         /* ptl.y = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN)
  111.                         - BMPSPACING
  112.                         - bih.cy; */
  113.         ptl.x = (WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN)
  114.                         - bih.cx) / 2;
  115.         ptl.y = (WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN)
  116.                         - bih.cy) / 2;
  117.  
  118.         // we now use ul for the current animation step,
  119.         // which is a pointer on a scale from 1 to ulAnimationTime;
  120.         // ul will be recalculated after each animation
  121.         // step according to how much time the animation
  122.         // has cost on this display so far. This has the
  123.         // following advantages:
  124.         // 1) no matter how fast the system is, the animation
  125.         //    will always last ulAnimationTime milliseconds
  126.         // 2) since large bitmaps take more time to calculate,
  127.         //    the animation won't appear to slow down then
  128.         DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
  129.                         &ulInitialTime,
  130.                         sizeof(ulInitialTime));
  131.         ul = 1;
  132.         ulSteps = 1000;
  133.         do {
  134.             LONG cx = (((bih.cx-20) * ul) / ulSteps) + 20;
  135.             LONG cy = (((bih.cy-20) * ul) / ulSteps) + 20;
  136.             rtlStretch.xLeft   = ptl.x + ((bih.cx - cx) / 2);
  137.             rtlStretch.yBottom = ptl.y + ((bih.cy - cy) / 2);
  138.             rtlStretch.xRight = rtlStretch.xLeft + cx;
  139.             rtlStretch.yTop   = rtlStretch.yBottom + cy;
  140.  
  141.             WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&rtlStretch,
  142.                           0, 0,       // we don't need colors
  143.                           DBM_STRETCH);
  144.  
  145.             DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
  146.                             &ulNowTime,
  147.                             sizeof(ulNowTime));
  148.  
  149.             // recalculate ul: rule of three based on the
  150.             // time we've spent on animation so far
  151.             ul = (ulSteps
  152.                     * (ulNowTime - ulInitialTime)) // time spent so far
  153.                     / ulAnimationTime;      // time to spend altogether
  154.  
  155.             ulrc++;                         // return count
  156.  
  157.         } while (ul < ulSteps);
  158.  
  159.         // finally, draw the 1:1 version
  160.         WinDrawBitmap(hps, hbm, NULL, &ptl,
  161.                       0, 0,       // we don't need colors
  162.                       DBM_NORMAL);
  163.  
  164.     } // end if (hps)
  165.  
  166.     return ulrc;
  167. }
  168.  
  169. #define LAST_LINE_WIDTH 2
  170.  
  171. /* ******************************************************************
  172.  *
  173.  *   Other animations
  174.  *
  175.  ********************************************************************/
  176.  
  177. /*
  178.  *@@ anmPowerOff:
  179.  *      displays an animation that looks like a
  180.  *      monitor being turned off; hps must have
  181.  *      been acquired using WinGetScreenPS.
  182.  *
  183.  *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
  184.  */
  185.  
  186. VOID anmPowerOff(HPS hps,
  187.                  ULONG ulMaxTime1, //  = 500,
  188.                  ULONG ulMaxTime2, //  = 800,
  189.                  ULONG ulMaxTime3, //  = 200,
  190.                  ULONG ulWaitEnd)  //  = 300
  191. {
  192.     RECTL       rclScreen,
  193.                 rclNow,
  194.                 rclLast,
  195.                 rclDraw;
  196.     ULONG       ulPhase = 1,
  197.                 ulCXLastLine;
  198.  
  199.     ULONG       ulStartTime = 0,
  200.                 ulTimeNow = 0;
  201.  
  202.     WinQueryWindowRect(HWND_DESKTOP, &rclScreen);
  203.     ulCXLastLine = rclScreen.xRight / 3;
  204.  
  205.     WinShowPointer(HWND_DESKTOP, FALSE);
  206.  
  207.     memcpy(&rclLast, &rclScreen, sizeof(RECTL));
  208.  
  209.     // In order to draw the animation, we tell apart three
  210.     // "phases", signified by the ulPhase variable. While
  211.     // ulPhase != 99, we stay in a do-while loop.
  212.     ulPhase = 1;
  213.  
  214.     do
  215.     {
  216.         // get current time
  217.         DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
  218.                         &ulTimeNow,
  219.                         sizeof(ulTimeNow));
  220.  
  221.         // get start time
  222.         if (ulStartTime == 0)
  223.             // this is reset when we enter a new phase
  224.             ulStartTime = ulTimeNow;
  225.  
  226.         if (ulPhase == 1)
  227.         {
  228.             // Phase 1: "shrink" the screen by drawing black
  229.             // rectangles from the edges towards the center
  230.             // of the screen. With every loop, we draw the
  231.             // rectangles a bit closer to the center, until
  232.             // the center is black too. Sort of like this:
  233.  
  234.             //          ╔═════════════════════════╗
  235.             //          ║       black             ║
  236.             //          ║                         ║
  237.             //          ║      ┌───────────┐      ║
  238.             //          ║      │ rclNow:   │      ║
  239.             //          ║  ->  │ untouched │  <-  ║
  240.             //          ║      └───────────┘      ║
  241.             //          ║            ^            ║
  242.             //          ║            |            ║
  243.             //          ╚═════════════════════════╝
  244.  
  245.             // This part lasts exactly (ulMaxTime1) milliseconds.
  246.  
  247.             // rclNow contains the rectangle _around_ which
  248.             // the black rectangles are to be drawn. With
  249.             // every iteration, rclNow is reduced in size.
  250.             ULONG ulMaxX = (rclScreen.xRight - ulCXLastLine) / 2,
  251.                   ulMaxY = rclScreen.yTop / 2 - LAST_LINE_WIDTH;
  252.             ULONG ulTimePassed = (ulTimeNow - ulStartTime);
  253.             if (ulTimePassed >= ulMaxTime1)
  254.             {
  255.                 // time has elapsed:
  256.                 ulTimePassed = ulMaxTime1;
  257.                 // enter next phase on next loop
  258.                 ulPhase++;
  259.                 // reget start time
  260.                 ulStartTime = 0;
  261.             }
  262.             rclNow.xLeft = ulMaxX * ulTimePassed / ulMaxTime1;
  263.             rclNow.yBottom = ulMaxY * ulTimePassed / ulMaxTime1;
  264.             rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
  265.             rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
  266.  
  267.             /* rclNow.xLeft = ((rclScreen.yTop / 2) * ul / ulSteps );
  268.             rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
  269.             rclNow.yBottom = ((rclScreen.yTop / 2) * ul / ulSteps );
  270.             rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom; */
  271.  
  272.             /* if (rclNow.yBottom > (rclNow.yTop - LAST_WIDTH) )
  273.             {
  274.                 rclNow.yBottom = (rclScreen.yTop / 2) - LAST_WIDTH;
  275.                 rclNow.yTop = (rclScreen.yTop / 2) + LAST_WIDTH;
  276.             } */
  277.  
  278.             // draw black rectangle on top of rclNow
  279.             rclDraw.xLeft = rclLast.xLeft;
  280.             rclDraw.xRight = rclLast.xRight;
  281.             rclDraw.yBottom = rclNow.yTop;
  282.             rclDraw.yTop = rclLast.yTop;
  283.             WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
  284.  
  285.             // draw black rectangle left of rclNow
  286.             rclDraw.xLeft = rclLast.xLeft;
  287.             rclDraw.xRight = rclNow.xLeft;
  288.             rclDraw.yBottom = rclLast.yBottom;
  289.             rclDraw.yTop = rclLast.yTop;
  290.             WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
  291.  
  292.             // draw black rectangle right of rclNow
  293.             rclDraw.xLeft = rclNow.xRight;
  294.             rclDraw.xRight = rclLast.xRight;
  295.             rclDraw.yBottom = rclLast.yBottom;
  296.             rclDraw.yTop = rclLast.yTop;
  297.             WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
  298.  
  299.             // draw black rectangle at the bottom of rclNow
  300.             rclDraw.xLeft = rclLast.xLeft;
  301.             rclDraw.xRight = rclLast.xRight;
  302.             rclDraw.yBottom = rclLast.yBottom;
  303.             rclDraw.yTop = rclNow.yBottom;
  304.             WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
  305.  
  306.             // remember rclNow for next iteration
  307.             memcpy(&rclLast, &rclNow, sizeof(RECTL));
  308.  
  309.             // done with "shrinking"?
  310.             /* if ( rclNow.xRight < ((rclScreen.xRight / 2) + LAST_WIDTH) )
  311.             {
  312.                 ulPhase = 2; // exit
  313.                 // reget start time
  314.                 ulStartTime = 0;
  315.             } */
  316.  
  317.             if (ulPhase == 2)
  318.             {
  319.                 // this was the last step in this phase:
  320.                 memcpy(&rclLast, &rclScreen, sizeof(RECTL));
  321.             }
  322.         }
  323.         else if (ulPhase == 2)
  324.         {
  325.             // Phase 2: draw a horizontal white line about
  326.             // where the last rclNow was. and shrink it
  327.             // towards the middle. This ends with a white
  328.             // dot in the middle of the screen.
  329.  
  330.             //          ╔═════════════════════════╗
  331.             //          ║       black             ║
  332.             //          ║                         ║
  333.             //          ║                         ║
  334.             //          ║  -->   ─white────   <-- ║
  335.             //          ║                         ║
  336.             //          ║                         ║
  337.             //          ║                         ║
  338.             //          ╚═════════════════════════╝
  339.  
  340.             // This part lasts exactly (ulMaxTime2) milliseconds.
  341.  
  342.             // start is same as max in step 1
  343.             ULONG ulStartX = (rclScreen.xRight - ulCXLastLine) / 2,
  344.                   ulY      = rclScreen.yTop / 2 - LAST_LINE_WIDTH;
  345.             ULONG ulMaxX = (rclScreen.xRight) / 2 - LAST_LINE_WIDTH;      // center
  346.             ULONG ulTimePassed = (ulTimeNow - ulStartTime);
  347.             if (ulTimePassed >= ulMaxTime2)
  348.             {
  349.                 // time has elapsed:
  350.                 ulTimePassed = ulMaxTime2;
  351.                 // enter next phase on next loop
  352.                 ulPhase++;
  353.                 // reget start time
  354.                 ulStartTime = 0;
  355.             }
  356.  
  357.             rclNow.xLeft =  ulStartX
  358.                           + ( (ulMaxX - ulStartX) * ulTimePassed / ulMaxTime2 );
  359.             rclNow.yBottom = ulY;
  360.             rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
  361.             rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
  362.  
  363.             // draw black rectangle left of rclNow
  364.             rclDraw.xLeft = rclLast.xLeft;
  365.             rclDraw.xRight = rclNow.xLeft;
  366.             rclDraw.yBottom = rclLast.yBottom;
  367.             rclDraw.yTop = rclLast.yTop;
  368.             WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
  369.  
  370.             // draw black rectangle right of rclNow
  371.             rclDraw.xLeft = rclNow.xRight;
  372.             rclDraw.xRight = rclLast.xRight;
  373.             rclDraw.yBottom = rclLast.yBottom;
  374.             rclDraw.yTop = rclLast.yTop;
  375.             WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
  376.  
  377.             // WinFillRect(hps, &rclNow, CLR_WHITE); // exclusive
  378.  
  379.             // remember rclNow for next iteration
  380.             memcpy(&rclLast, &rclNow, sizeof(RECTL));
  381.  
  382.             if (ulPhase == 3)
  383.             {
  384.                 // this was the last step in this phase:
  385.                 // keep the dot visible for a while
  386.                 DosSleep(ulMaxTime3);
  387.  
  388.                 // draw a white line for phase 3
  389.                 rclLast.xLeft = ulMaxX;
  390.                 rclLast.yBottom = rclScreen.yTop / 4;
  391.                 rclLast.xRight = rclScreen.xRight - rclLast.xLeft;
  392.                 rclLast.yTop = rclScreen.yTop - rclLast.yBottom;
  393.  
  394.                 WinFillRect(hps, &rclLast, CLR_WHITE); // exclusive
  395.             }
  396.         }
  397.         else if (ulPhase == 3)
  398.         {
  399.             // Phase 3: make the white line shorter with
  400.             // every iteration by drawing black rectangles
  401.             // above and below it. These are drawn closer
  402.             // to the center with each iteration.
  403.  
  404.             //          ╔═════════════════════════╗
  405.             //          ║                         ║
  406.             //          ║                         ║
  407.             //          ║            |            ║
  408.             //          ║            |            ║
  409.             //          ║            |            ║
  410.             //          ║                         ║
  411.             //          ║                         ║
  412.             //          ╚═════════════════════════╝
  413.  
  414.             // This part lasts exactly ulMaxTime3 milliseconds.
  415.             ULONG ulX = (rclScreen.xRight) / 2 - LAST_LINE_WIDTH,      // center
  416.                   ulStartY = rclScreen.yTop / 4;
  417.             ULONG ulMaxY = (rclScreen.yTop) / 2 - LAST_LINE_WIDTH;      // center
  418.             ULONG ulTimePassed = (ulTimeNow - ulStartTime);
  419.             if (ulTimePassed >= ulMaxTime3)
  420.             {
  421.                 // time has elapsed:
  422.                 ulTimePassed = ulMaxTime3;
  423.                 // stop
  424.                 ulPhase = 99;
  425.             }
  426.  
  427.             rclNow.xLeft =  ulX;
  428.             rclNow.yBottom = ulStartY
  429.                           + ( (ulMaxY - ulStartY) * ulTimePassed / ulMaxTime3 );
  430.             rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
  431.             rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
  432.  
  433.             // draw black rectangle on top of rclNow
  434.             rclDraw.xLeft = rclLast.xLeft;
  435.             rclDraw.xRight = rclLast.xRight;
  436.             rclDraw.yBottom = rclNow.yTop;
  437.             rclDraw.yTop = rclLast.yTop;
  438.             WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
  439.  
  440.             // draw black rectangle at the bottom of rclNow
  441.             rclDraw.xLeft = rclLast.xLeft;
  442.             rclDraw.xRight = rclLast.xRight;
  443.             rclDraw.yBottom = rclLast.yBottom;
  444.             rclDraw.yTop = rclNow.yBottom;
  445.             WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
  446.  
  447.             // remember rclNow for next iteration
  448.             memcpy(&rclLast, &rclNow, sizeof(RECTL));
  449.  
  450.             /* rclDraw.xLeft = (rclScreen.xRight / 2) - LAST_LINE_WIDTH;
  451.             rclDraw.xRight = (rclScreen.xRight / 2) + LAST_LINE_WIDTH;
  452.             rclDraw.yTop = (rclScreen.yTop * 3 / 4);
  453.             rclDraw.yBottom = (rclScreen.yTop * 3 / 4) - ((rclScreen.yTop * 1 / 4) * ul / LAST_STEPS);
  454.             if (rclDraw.yBottom < ((rclScreen.yTop / 2) + LAST_LINE_WIDTH))
  455.                 rclDraw.yBottom = ((rclScreen.yTop / 2) + LAST_LINE_WIDTH);
  456.             WinFillRect(hps, &rclDraw, CLR_BLACK);
  457.  
  458.             rclDraw.xLeft = (rclScreen.xRight / 2) - LAST_LINE_WIDTH;
  459.             rclDraw.xRight = (rclScreen.xRight / 2) + LAST_LINE_WIDTH;
  460.             rclDraw.yBottom = (rclScreen.yTop * 1 / 4);
  461.             rclDraw.yTop = (rclScreen.yTop * 1 / 4) + ((rclScreen.yTop * 1 / 4) * ul / LAST_STEPS);
  462.             if (rclDraw.yTop > ((rclScreen.yTop / 2) - LAST_LINE_WIDTH))
  463.                 rclDraw.yBottom = ((rclScreen.yTop / 2) - LAST_LINE_WIDTH);
  464.  
  465.             WinFillRect(hps, &rclDraw, CLR_BLACK);
  466.  
  467.             ul++;
  468.             if (ul > LAST_STEPS) */
  469.             //     ulPhase = 99;
  470.         }
  471.  
  472.     } while (ulPhase != 99);
  473.  
  474.     // sleep a while
  475.     DosSleep(ulWaitEnd / 2);
  476.     WinFillRect(hps, &rclScreen, CLR_BLACK); // exclusive
  477.     DosSleep(ulWaitEnd / 2);
  478.  
  479.     WinShowPointer(HWND_DESKTOP, TRUE);
  480. }
  481.  
  482.  
  483. // testcase
  484.  
  485. /* int main(int argc, char* argp)
  486. {
  487.     HENUM henum;
  488.     HWND hwndTop;
  489.     HAB hab = WinInitialize(0);
  490.     HMQ hmq = WinCreateMsgQueue(hab, 0);
  491.     HPS hps = WinGetScreenPS(HWND_DESKTOP);
  492.  
  493.     anmPowerOff(hps);
  494.  
  495.     henum = WinBeginEnumWindows(HWND_DESKTOP);
  496.     while ((hwndTop = WinGetNextWindow(henum)))
  497.         if (WinIsWindowShowing(hwndTop))
  498.             WinInvalidateRect(hwndTop, NULL, TRUE);
  499.     WinEndEnumWindows(henum);
  500.  
  501.     WinShowPointer(HWND_DESKTOP, TRUE);
  502.  
  503.     WinDestroyMsgQueue(hmq);
  504.     WinTerminate(hab);
  505.  
  506.     return (0);
  507. } */
  508.