source: trunk/src/helpers/animate.c@ 18

Last change on this file since 18 was 18, checked in by umoeller, 25 years ago

Tons of updates.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 18.6 KB
Line 
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 */
68
69/*
70 *@@ anmBlowUpBitmap:
71 * this displays an animation based on a given bitmap.
72 * The bitmap is "blown up" in that it is continually
73 * increased in size until the original size is reached.
74 * The animation is calculated so that it lasts exactly
75 * ulAnimation milliseconds, no matter how fast the
76 * system is.
77 *
78 * This function does not return until the animation
79 * has completed.
80 *
81 * You should run this routine in a thread with higher-
82 * than-normal priority, because otherwise the kernel
83 * might interrupt the thread, causing a somewhat jerky
84 * display.
85 *
86 * Returns the count of animation steps that were drawn.
87 * This is dependent on the speed of the system.
88 *
89 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
90 */
91
92BOOL anmBlowUpBitmap(HPS hps, // in: from WinGetScreenPS(HWND_DESKTOP)
93 HBITMAP hbm, // in: bitmap to be displayed
94 ULONG ulAnimationTime) // in: total animation time (ms)
95{
96 ULONG ulrc = 0;
97 ULONG ulInitialTime,
98 ulNowTime;
99 // ulCurrentSize = 10;
100
101 if (hps)
102 {
103 POINTL ptl = {0, 0};
104 RECTL rtlStretch;
105 ULONG ul,
106 ulSteps = 20;
107 BITMAPINFOHEADER bih;
108 GpiQueryBitmapParameters(hbm, &bih);
109 /* ptl.y = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN)
110 - BMPSPACING
111 - bih.cy; */
112 ptl.x = (WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN)
113 - bih.cx) / 2;
114 ptl.y = (WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN)
115 - bih.cy) / 2;
116
117 // we now use ul for the current animation step,
118 // which is a pointer on a scale from 1 to ulAnimationTime;
119 // ul will be recalculated after each animation
120 // step according to how much time the animation
121 // has cost on this display so far. This has the
122 // following advantages:
123 // 1) no matter how fast the system is, the animation
124 // will always last ulAnimationTime milliseconds
125 // 2) since large bitmaps take more time to calculate,
126 // the animation won't appear to slow down then
127 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
128 &ulInitialTime,
129 sizeof(ulInitialTime));
130 ul = 1;
131 ulSteps = 1000;
132 do {
133 LONG cx = (((bih.cx-20) * ul) / ulSteps) + 20;
134 LONG cy = (((bih.cy-20) * ul) / ulSteps) + 20;
135 rtlStretch.xLeft = ptl.x + ((bih.cx - cx) / 2);
136 rtlStretch.yBottom = ptl.y + ((bih.cy - cy) / 2);
137 rtlStretch.xRight = rtlStretch.xLeft + cx;
138 rtlStretch.yTop = rtlStretch.yBottom + cy;
139
140 WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&rtlStretch,
141 0, 0, // we don't need colors
142 DBM_STRETCH);
143
144 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
145 &ulNowTime,
146 sizeof(ulNowTime));
147
148 // recalculate ul: rule of three based on the
149 // time we've spent on animation so far
150 ul = (ulSteps
151 * (ulNowTime - ulInitialTime)) // time spent so far
152 / ulAnimationTime; // time to spend altogether
153
154 ulrc++; // return count
155
156 } while (ul < ulSteps);
157
158 // finally, draw the 1:1 version
159 WinDrawBitmap(hps, hbm, NULL, &ptl,
160 0, 0, // we don't need colors
161 DBM_NORMAL);
162
163 } // end if (hps)
164
165 return (ulrc);
166}
167
168#define LAST_LINE_WIDTH 2
169
170/* ******************************************************************
171 *
172 * Other animations
173 *
174 ********************************************************************/
175
176/*
177 *@@ anmPowerOff:
178 * displays an animation that looks like a
179 * monitor being turned off; hps must have
180 * been acquired using WinGetScreenPS.
181 *
182 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
183 */
184
185VOID anmPowerOff(HPS hps,
186 ULONG ulMaxTime1, // = 500,
187 ULONG ulMaxTime2, // = 800,
188 ULONG ulMaxTime3, // = 200,
189 ULONG ulWaitEnd) // = 300
190{
191 RECTL rclScreen,
192 rclNow,
193 rclLast,
194 rclDraw;
195 ULONG ulPhase = 1,
196 ulCXLastLine;
197
198 ULONG ulStartTime = 0,
199 ulTimeNow = 0;
200
201 WinQueryWindowRect(HWND_DESKTOP, &rclScreen);
202 ulCXLastLine = rclScreen.xRight / 3;
203
204 WinShowPointer(HWND_DESKTOP, FALSE);
205
206 memcpy(&rclLast, &rclScreen, sizeof(RECTL));
207
208 // In order to draw the animation, we tell apart three
209 // "phases", signified by the ulPhase variable. While
210 // ulPhase != 99, we stay in a do-while loop.
211 ulPhase = 1;
212
213 do
214 {
215 // get current time
216 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
217 &ulTimeNow,
218 sizeof(ulTimeNow));
219
220 // get start time
221 if (ulStartTime == 0)
222 // this is reset when we enter a new phase
223 ulStartTime = ulTimeNow;
224
225 if (ulPhase == 1)
226 {
227 // Phase 1: "shrink" the screen by drawing black
228 // rectangles from the edges towards the center
229 // of the screen. With every loop, we draw the
230 // rectangles a bit closer to the center, until
231 // the center is black too. Sort of like this:
232
233 // ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
234 // º black º
235 // º º
236 // º ÚÄÄÄÄÄÄÄÄÄÄÄ¿ º
237 // º ³ rclNow: ³ º
238 // º -> ³ untouched ³ <- º
239 // º ÀÄÄÄÄÄÄÄÄÄÄÄÙ º
240 // º ^ º
241 // º | º
242 // ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
243
244 // This part lasts exactly (ulMaxTime1) milliseconds.
245
246 // rclNow contains the rectangle _around_ which
247 // the black rectangles are to be drawn. With
248 // every iteration, rclNow is reduced in size.
249 ULONG ulMaxX = (rclScreen.xRight - ulCXLastLine) / 2,
250 ulMaxY = rclScreen.yTop / 2 - LAST_LINE_WIDTH;
251 ULONG ulTimePassed = (ulTimeNow - ulStartTime);
252 if (ulTimePassed >= ulMaxTime1)
253 {
254 // time has elapsed:
255 ulTimePassed = ulMaxTime1;
256 // enter next phase on next loop
257 ulPhase++;
258 // reget start time
259 ulStartTime = 0;
260 }
261 rclNow.xLeft = ulMaxX * ulTimePassed / ulMaxTime1;
262 rclNow.yBottom = ulMaxY * ulTimePassed / ulMaxTime1;
263 rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
264 rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
265
266 /* rclNow.xLeft = ((rclScreen.yTop / 2) * ul / ulSteps );
267 rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
268 rclNow.yBottom = ((rclScreen.yTop / 2) * ul / ulSteps );
269 rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom; */
270
271 /* if (rclNow.yBottom > (rclNow.yTop - LAST_WIDTH) )
272 {
273 rclNow.yBottom = (rclScreen.yTop / 2) - LAST_WIDTH;
274 rclNow.yTop = (rclScreen.yTop / 2) + LAST_WIDTH;
275 } */
276
277 // draw black rectangle on top of rclNow
278 rclDraw.xLeft = rclLast.xLeft;
279 rclDraw.xRight = rclLast.xRight;
280 rclDraw.yBottom = rclNow.yTop;
281 rclDraw.yTop = rclLast.yTop;
282 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
283
284 // draw black rectangle left of rclNow
285 rclDraw.xLeft = rclLast.xLeft;
286 rclDraw.xRight = rclNow.xLeft;
287 rclDraw.yBottom = rclLast.yBottom;
288 rclDraw.yTop = rclLast.yTop;
289 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
290
291 // draw black rectangle right of rclNow
292 rclDraw.xLeft = rclNow.xRight;
293 rclDraw.xRight = rclLast.xRight;
294 rclDraw.yBottom = rclLast.yBottom;
295 rclDraw.yTop = rclLast.yTop;
296 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
297
298 // draw black rectangle at the bottom of rclNow
299 rclDraw.xLeft = rclLast.xLeft;
300 rclDraw.xRight = rclLast.xRight;
301 rclDraw.yBottom = rclLast.yBottom;
302 rclDraw.yTop = rclNow.yBottom;
303 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
304
305 // remember rclNow for next iteration
306 memcpy(&rclLast, &rclNow, sizeof(RECTL));
307
308 // done with "shrinking"?
309 /* if ( rclNow.xRight < ((rclScreen.xRight / 2) + LAST_WIDTH) )
310 {
311 ulPhase = 2; // exit
312 // reget start time
313 ulStartTime = 0;
314 } */
315
316 if (ulPhase == 2)
317 {
318 // this was the last step in this phase:
319 memcpy(&rclLast, &rclScreen, sizeof(RECTL));
320 }
321 }
322 else if (ulPhase == 2)
323 {
324 // Phase 2: draw a horizontal white line about
325 // where the last rclNow was. and shrink it
326 // towards the middle. This ends with a white
327 // dot in the middle of the screen.
328
329 // ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
330 // º black º
331 // º º
332 // º º
333 // º --> ÄwhiteÄÄÄÄ <-- º
334 // º º
335 // º º
336 // º º
337 // ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
338
339 // This part lasts exactly (ulMaxTime2) milliseconds.
340
341 // start is same as max in step 1
342 ULONG ulStartX = (rclScreen.xRight - ulCXLastLine) / 2,
343 ulY = rclScreen.yTop / 2 - LAST_LINE_WIDTH;
344 ULONG ulMaxX = (rclScreen.xRight) / 2 - LAST_LINE_WIDTH; // center
345 ULONG ulTimePassed = (ulTimeNow - ulStartTime);
346 if (ulTimePassed >= ulMaxTime2)
347 {
348 // time has elapsed:
349 ulTimePassed = ulMaxTime2;
350 // enter next phase on next loop
351 ulPhase++;
352 // reget start time
353 ulStartTime = 0;
354 }
355
356 rclNow.xLeft = ulStartX
357 + ( (ulMaxX - ulStartX) * ulTimePassed / ulMaxTime2 );
358 rclNow.yBottom = ulY;
359 rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
360 rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
361
362 // draw black rectangle left of rclNow
363 rclDraw.xLeft = rclLast.xLeft;
364 rclDraw.xRight = rclNow.xLeft;
365 rclDraw.yBottom = rclLast.yBottom;
366 rclDraw.yTop = rclLast.yTop;
367 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
368
369 // draw black rectangle right of rclNow
370 rclDraw.xLeft = rclNow.xRight;
371 rclDraw.xRight = rclLast.xRight;
372 rclDraw.yBottom = rclLast.yBottom;
373 rclDraw.yTop = rclLast.yTop;
374 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
375
376 // WinFillRect(hps, &rclNow, CLR_WHITE); // exclusive
377
378 // remember rclNow for next iteration
379 memcpy(&rclLast, &rclNow, sizeof(RECTL));
380
381 if (ulPhase == 3)
382 {
383 // this was the last step in this phase:
384 // keep the dot visible for a while
385 DosSleep(ulMaxTime3);
386
387 // draw a white line for phase 3
388 rclLast.xLeft = ulMaxX;
389 rclLast.yBottom = rclScreen.yTop / 4;
390 rclLast.xRight = rclScreen.xRight - rclLast.xLeft;
391 rclLast.yTop = rclScreen.yTop - rclLast.yBottom;
392
393 WinFillRect(hps, &rclLast, CLR_WHITE); // exclusive
394 }
395 }
396 else if (ulPhase == 3)
397 {
398 // Phase 3: make the white line shorter with
399 // every iteration by drawing black rectangles
400 // above and below it. These are drawn closer
401 // to the center with each iteration.
402
403 // ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
404 // º º
405 // º º
406 // º | º
407 // º | º
408 // º | º
409 // º º
410 // º º
411 // ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
412
413 // This part lasts exactly ulMaxTime3 milliseconds.
414 ULONG ulX = (rclScreen.xRight) / 2 - LAST_LINE_WIDTH, // center
415 ulStartY = rclScreen.yTop / 4;
416 ULONG ulMaxY = (rclScreen.yTop) / 2 - LAST_LINE_WIDTH; // center
417 ULONG ulTimePassed = (ulTimeNow - ulStartTime);
418 if (ulTimePassed >= ulMaxTime3)
419 {
420 // time has elapsed:
421 ulTimePassed = ulMaxTime3;
422 // stop
423 ulPhase = 99;
424 }
425
426 rclNow.xLeft = ulX;
427 rclNow.yBottom = ulStartY
428 + ( (ulMaxY - ulStartY) * ulTimePassed / ulMaxTime3 );
429 rclNow.xRight = (rclScreen.xRight) - rclNow.xLeft;
430 rclNow.yTop = (rclScreen.yTop) - rclNow.yBottom;
431
432 // draw black rectangle on top of rclNow
433 rclDraw.xLeft = rclLast.xLeft;
434 rclDraw.xRight = rclLast.xRight;
435 rclDraw.yBottom = rclNow.yTop;
436 rclDraw.yTop = rclLast.yTop;
437 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
438
439 // draw black rectangle at the bottom of rclNow
440 rclDraw.xLeft = rclLast.xLeft;
441 rclDraw.xRight = rclLast.xRight;
442 rclDraw.yBottom = rclLast.yBottom;
443 rclDraw.yTop = rclNow.yBottom;
444 WinFillRect(hps, &rclDraw, CLR_BLACK); // exclusive
445
446 // remember rclNow for next iteration
447 memcpy(&rclLast, &rclNow, sizeof(RECTL));
448
449 /* rclDraw.xLeft = (rclScreen.xRight / 2) - LAST_LINE_WIDTH;
450 rclDraw.xRight = (rclScreen.xRight / 2) + LAST_LINE_WIDTH;
451 rclDraw.yTop = (rclScreen.yTop * 3 / 4);
452 rclDraw.yBottom = (rclScreen.yTop * 3 / 4) - ((rclScreen.yTop * 1 / 4) * ul / LAST_STEPS);
453 if (rclDraw.yBottom < ((rclScreen.yTop / 2) + LAST_LINE_WIDTH))
454 rclDraw.yBottom = ((rclScreen.yTop / 2) + LAST_LINE_WIDTH);
455 WinFillRect(hps, &rclDraw, CLR_BLACK);
456
457 rclDraw.xLeft = (rclScreen.xRight / 2) - LAST_LINE_WIDTH;
458 rclDraw.xRight = (rclScreen.xRight / 2) + LAST_LINE_WIDTH;
459 rclDraw.yBottom = (rclScreen.yTop * 1 / 4);
460 rclDraw.yTop = (rclScreen.yTop * 1 / 4) + ((rclScreen.yTop * 1 / 4) * ul / LAST_STEPS);
461 if (rclDraw.yTop > ((rclScreen.yTop / 2) - LAST_LINE_WIDTH))
462 rclDraw.yBottom = ((rclScreen.yTop / 2) - LAST_LINE_WIDTH);
463
464 WinFillRect(hps, &rclDraw, CLR_BLACK);
465
466 ul++;
467 if (ul > LAST_STEPS) */
468 // ulPhase = 99;
469 }
470
471 } while (ulPhase != 99);
472
473 // sleep a while
474 DosSleep(ulWaitEnd / 2);
475 WinFillRect(hps, &rclScreen, CLR_BLACK); // exclusive
476 DosSleep(ulWaitEnd / 2);
477
478 WinShowPointer(HWND_DESKTOP, TRUE);
479}
480
481
482// testcase
483
484/* int main(int argc, char* argp)
485{
486 HENUM henum;
487 HWND hwndTop;
488 HAB hab = WinInitialize(0);
489 HMQ hmq = WinCreateMsgQueue(hab, 0);
490 HPS hps = WinGetScreenPS(HWND_DESKTOP);
491
492 anmPowerOff(hps);
493
494 henum = WinBeginEnumWindows(HWND_DESKTOP);
495 while ((hwndTop = WinGetNextWindow(henum)))
496 if (WinIsWindowShowing(hwndTop))
497 WinInvalidateRect(hwndTop, NULL, TRUE);
498 WinEndEnumWindows(henum);
499
500 WinShowPointer(HWND_DESKTOP, TRUE);
501
502 WinDestroyMsgQueue(hmq);
503 WinTerminate(hab);
504
505 return (0);
506} */
Note: See TracBrowser for help on using the repository browser.