rnd-20091124-1-src
[rocksndiamonds.git] / src / game_sp / DDScrollBuffer.c
1 // ----------------------------------------------------------------------------
2 // DDScrollBuffer.c
3 // ----------------------------------------------------------------------------
4
5 #include "DDScrollBuffer.h"
6
7 #include <math.h>
8
9
10 // --- VERSION 1.0 CLASS
11 // --- BEGIN
12 // ---   MultiUse = -1  'True  // True
13 // ---   Persistable = 0  'NotPersistable  // NotPersistable
14 // ---   DataBindingBehavior = 0  'vbNone  // vbNone
15 // ---   DataSourceBehavior  = 0  'vbNone  // vbNone
16 // ---   MTSTransactionMode  = 0  'NotAnMTSObject  // NotAnMTSObject
17 // --- END
18
19 // static char *VB_Name = "DDScrollBuffer";
20 // static boolean VB_GlobalNameSpace = False;
21 // static boolean VB_Creatable = True;
22 // static boolean VB_PredeclaredId = False;
23 // static boolean VB_Exposed = False;
24
25 // --- Option Explicit
26
27 // needs reference to: DirectX7 for Visual Basic Type Library
28
29 DirectDrawSurface7 Buffer;
30 DirectDrawSurface7 mPrimary;
31 long mWidth, mHeight;
32 long mhWnd;
33 long mScrollX, mScrollY;
34 long mScrollX_last, mScrollY_last;
35 long mDestXOff, mDestYOff;
36
37 long ScreenBuffer[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
38 boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
39
40 int TEST_flag = 0;
41
42
43 static void ScrollPlayfield(int dx, int dy)
44 {
45   int x1 = mScrollX_last / TILEX - 2;
46   int y1 = mScrollY_last / TILEY - 2;
47   int x2 = mScrollX_last / TILEX + (SCR_FIELDX - 1) + 2;
48   int y2 = mScrollY_last / TILEY + (SCR_FIELDY - 1) + 2;
49   int x, y;
50
51   BlitBitmap(screenBitmap, screenBitmap,
52              TILEX * (dx == -1),
53              TILEY * (dy == -1),
54              (MAX_BUF_XSIZE * TILEX) - TILEX * (dx != 0),
55              (MAX_BUF_YSIZE * TILEY) - TILEY * (dy != 0),
56              TILEX * (dx == 1),
57              TILEY * (dy == 1));
58
59   /* when scrolling the whole playfield, do not redraw single tiles */
60   for (x = 0; x < MAX_BUF_XSIZE; x++)
61     for (y = 0; y < MAX_BUF_YSIZE; y++)
62       redraw[x][y] = FALSE;
63   redraw_tiles = 0;
64
65 #if 1
66   DrawFrameIfNeeded();
67 #endif
68
69   for (y = DisplayMinY; y <= DisplayMaxY; y++)
70   {
71     for (x = DisplayMinX; x <= DisplayMaxX; x++)
72     {
73       if (x >= x1 && x <= x2 && y >= y1 && y <= y2)
74       {
75         int sx = x - x1;
76         int sy = y - y1;
77         int tsi = GetSI(x, y);
78         long id = ((PlayField16[tsi]) |
79                    (PlayField8[tsi] << 16) |
80                    (DisPlayField[tsi] << 24));
81
82 #if 0
83 #if 1
84         printf("::: [%d] %d [%d, %d] [%d]\n", dx, sx, x, y, buf_xsize);
85 #else
86         if (sx == 0 || sx == MAX_BUF_XSIZE - 1)
87           printf("::: %d, %d\n", dx, sx);
88 #endif
89 #endif
90
91         if ((dx == -1 && x == x2) ||
92             (dx == +1 && x == x1) ||
93             (dy == -1 && y == y2) ||
94             (dy == +1 && y == y1))
95         {
96 #if 0
97           printf("::: %d, %d\n", sx, sy);
98 #endif
99
100           TEST_flag = 1;
101
102           DrawFieldNoAnimated(x, y);
103           DrawFieldAnimated(x, y);
104
105           TEST_flag = 0;
106         }
107
108         ScreenBuffer[sx][sy] = id;
109       }
110     }
111   }
112 }
113
114 static void ScrollPlayfieldIfNeededExt(boolean reset)
115 {
116   if (reset)
117   {
118     mScrollX_last = -1;
119     mScrollY_last = -1;
120
121     return;
122   }
123
124   if (mScrollX_last == -1 || mScrollY_last == -1)
125   {
126     mScrollX_last = mScrollX;
127     mScrollY_last = mScrollY;
128
129     return;
130   }
131
132   /* check if scrolling the playfield reached the destination tile position */
133   if ((mScrollX != mScrollX_last || mScrollY != mScrollY_last) &&
134       mScrollX % TILEX == 0 && mScrollY % TILEY == 0)
135   {
136     int dx = (mScrollX < mScrollX_last ? 1 : mScrollX > mScrollX_last ? -1 : 0);
137     int dy = (mScrollY < mScrollY_last ? 1 : mScrollY > mScrollY_last ? -1 : 0);
138
139     mScrollX_last = mScrollX;
140     mScrollY_last = mScrollY;
141
142     ScrollPlayfield(dx, dy);
143   }
144 }
145
146 static void ScrollPlayfieldIfNeeded()
147 {
148   ScrollPlayfieldIfNeededExt(FALSE);
149 }
150
151 void InitScrollPlayfield()
152 {
153   ScrollPlayfieldIfNeededExt(TRUE);
154 }
155
156 void UpdatePlayfield()
157 {
158   int x1 = mScrollX_last / TILEX - 2;
159   int y1 = mScrollY_last / TILEY - 2;
160   int x2 = mScrollX_last / TILEX + (SCR_FIELDX - 1) + 2;
161   int y2 = mScrollY_last / TILEY + (SCR_FIELDY - 1) + 2;
162   int x, y;
163
164   for (y = DisplayMinY; y <= DisplayMaxY; y++)
165   {
166     for (x = DisplayMinX; x <= DisplayMaxX; x++)
167     {
168       if (x >= x1 && x <= x2 && y >= y1 && y <= y2)
169       {
170         int sx = x - x1;
171         int sy = y - y1;
172         int tsi = GetSI(x, y);
173         long id = ((PlayField16[tsi]) |
174                    (PlayField8[tsi] << 16) |
175                    (DisPlayField[tsi] << 24));
176         boolean redraw_screen_tile = (ScreenBuffer[sx][sy] != id);
177
178 #if 0
179         if (LowByte(PlayField16[tsi]) == fiMurphy)
180           continue;
181 #endif
182
183         if (redraw_screen_tile)
184         {
185 #if 0
186           DrawFieldNoAnimated(x, y);
187           DrawFieldAnimated(x, y);
188 #endif
189
190           ScreenBuffer[sx][sy] = id;
191
192           redraw[sx][sy] = TRUE;
193           redraw_tiles++;
194         }
195       }
196     }
197   }
198 }
199
200 void OLD_UpdatePlayfield()
201 {
202   int x, y;
203   int left = mScrollX / TILEX;
204   int top  = mScrollY / TILEY;
205
206   for (y = top; y < top + MAX_BUF_YSIZE; y++)
207   {
208     for (x = left; x < left + MAX_BUF_XSIZE; x++)
209     {
210       int sx = x % MAX_BUF_XSIZE;
211       int sy = y % MAX_BUF_YSIZE;
212       int tsi = GetSI(x, y);
213       long id = ((PlayField16[tsi]) |
214                  (PlayField8[tsi] << 16) |
215                  (DisPlayField[tsi] << 24));
216       boolean redraw_screen_tile = (ScreenBuffer[sx][sy] != id);
217
218       if (redraw_screen_tile)
219       {
220         DrawFieldNoAnimated(x, y);
221         DrawFieldAnimated(x, y);
222
223         ScreenBuffer[sx][sy] = id;
224
225         redraw[sx][sy] = TRUE;
226         redraw_tiles++;
227       }
228     }
229   }
230 }
231
232 void DDScrollBuffer_Let_DestXOff(long NewVal)
233 {
234   mDestXOff = NewVal;
235 }
236
237 long DDScrollBuffer_Get_DestXOff()
238 {
239   long DestXOff;
240
241   DestXOff = mDestXOff;
242
243   return DestXOff;
244 }
245
246 void DDScrollBuffer_Let_DestYOff(long NewVal)
247 {
248   mDestYOff = NewVal;
249 }
250
251 long DDScrollBuffer_Get_DestYOff()
252 {
253   long DestYOff;
254
255   DestYOff = mDestYOff;
256
257   return DestYOff;
258 }
259
260 DirectDrawSurface7 DDScrollBuffer_Get_Surface()
261 {
262   DirectDrawSurface7 Surface;
263
264   Surface = Buffer;
265
266   return Surface;
267 }
268
269 long DDScrollBuffer_Get_Width()
270 {
271   long Width;
272
273   Width = mWidth;
274
275   return Width;
276 }
277
278 int DDScrollBuffer_Get_Height()
279 {
280   int Height;
281
282   Height = mHeight;
283
284   return Height;
285 }
286
287 long DDScrollBuffer_CreateAtSize(long Width, long Height, long hWndViewPort)
288 {
289   long CreateAtSize;
290
291   DDSURFACEDESC2 SD;
292
293   CreateAtSize = 0;
294   mhWnd = hWndViewPort;
295   // Create ScrollBuffer:
296   {
297     SD.lFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
298     SD.ddsCaps.lCaps = DDSCAPS_VIDEOMEMORY;
299     // SD.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
300     SD.LWidth = Width;
301     SD.LHeight = Height;
302   }
303
304   // --- On Error Resume Next
305   Buffer = DDraw.CreateSurface(SD);
306   if (Err.Number != 0)
307     return CreateAtSize;
308
309   // --- On Error GoTo 0
310
311   mWidth = Width;
312   mHeight = Height;
313   mScrollX = 0;
314   mScrollY = 0;
315   CreateAtSize = -1;
316
317   return CreateAtSize;
318 }
319
320 void DDScrollBuffer_Cls(int BackColor)
321 {
322   RECT EmptyRect;
323
324   if (NoDisplayFlag)
325     return;
326
327   Buffer.BltColorFill(EmptyRect, BackColor);
328 }
329
330
331 /* copy the entire screen to the window at the scroll position */
332
333 void BlitScreenToBitmap_SP(Bitmap *target_bitmap)
334 {
335   int px = 2 * TILEX + (mScrollX - mScrollX_last) % TILEX;
336   int py = 2 * TILEY + (mScrollY - mScrollY_last) % TILEY;
337   int sx, sy, sxsize, sysize;
338
339 #if 1
340   int xsize = SXSIZE;
341   int ysize = SYSIZE;
342   int full_xsize = (FieldWidth  - (menBorder.Checked ? 0 : 1)) * TILEX;
343   int full_ysize = (FieldHeight - (menBorder.Checked ? 0 : 1)) * TILEY;
344
345   sxsize = (full_xsize < xsize ? full_xsize : xsize);
346   sysize = (full_ysize < ysize ? full_ysize : ysize);
347   sx = SX + (full_xsize < xsize ? (xsize - full_xsize) / 2 : 0);
348   sy = SY + (full_ysize < ysize ? (ysize - full_ysize) / 2 : 0);
349 #endif
350
351 #if 1
352   if (!menBorder.Checked)
353   {
354     px += TILEX / 2;
355     py += TILEY / 2;
356   }
357 #endif
358
359   BlitBitmap(screenBitmap, target_bitmap, px, py, sxsize, sysize, sx, sy);
360 }
361
362 void OLD_BlitScreenToBitmap_SP(Bitmap *target_bitmap)
363 {
364   int x = mScrollX % (MAX_BUF_XSIZE * TILEX);
365   int y = mScrollY % (MAX_BUF_YSIZE * TILEY);
366
367   if (x < 2 * TILEX && y < 2 * TILEY)
368   {
369     BlitBitmap(screenBitmap, target_bitmap, x, y,
370                SCR_FIELDX * TILEX, SCR_FIELDY * TILEY, SX, SY);
371   }
372   else if (x < 2 * TILEX && y >= 2 * TILEY)
373   {
374     BlitBitmap(screenBitmap, target_bitmap, x, y,
375                SCR_FIELDX * TILEX, MAX_BUF_YSIZE * TILEY - y,
376                SX, SY);
377     BlitBitmap(screenBitmap, target_bitmap, x, 0,
378                SCR_FIELDX * TILEX, y - 2 * TILEY,
379                SX, SY + MAX_BUF_YSIZE * TILEY - y);
380   }
381   else if (x >= 2 * TILEX && y < 2 * TILEY)
382   {
383     BlitBitmap(screenBitmap, target_bitmap, x, y,
384                MAX_BUF_XSIZE * TILEX - x, SCR_FIELDY * TILEY,
385                SX, SY);
386     BlitBitmap(screenBitmap, target_bitmap, 0, y,
387                x - 2 * TILEX, SCR_FIELDY * TILEY,
388                SX + MAX_BUF_XSIZE * TILEX - x, SY);
389   }
390   else
391   {
392     BlitBitmap(screenBitmap, target_bitmap, x, y,
393                MAX_BUF_XSIZE * TILEX - x, MAX_BUF_YSIZE * TILEY - y,
394                SX, SY);
395     BlitBitmap(screenBitmap, target_bitmap, 0, y,
396                x - 2 * TILEX, MAX_BUF_YSIZE * TILEY - y,
397                SX + MAX_BUF_XSIZE * TILEX - x, SY);
398     BlitBitmap(screenBitmap, target_bitmap, x, 0,
399                MAX_BUF_XSIZE * TILEX - x, y - 2 * TILEY,
400                SX, SY + MAX_BUF_YSIZE * TILEY - y);
401     BlitBitmap(screenBitmap, target_bitmap, 0, 0,
402                x - 2 * TILEX, y - 2 * TILEY,
403                SX + MAX_BUF_XSIZE * TILEX - x, SY + MAX_BUF_YSIZE * TILEY - y);
404   }
405 }
406
407 void BackToFront_SP(void)
408 {
409   static boolean scrolling_last = FALSE;
410   int left = mScrollX / TILEX;
411   int top  = mScrollY / TILEY;
412   boolean scrolling = (mScrollX % TILEX != 0 || mScrollY % TILEY != 0);
413   int x, y;
414
415   SyncDisplay();
416
417   if (1 ||
418       redraw_tiles > REDRAWTILES_THRESHOLD || scrolling || scrolling_last)
419   {
420 #if 1
421     BlitScreenToBitmap_SP(window);
422 #else
423     /* blit all (up to four) parts of the scroll buffer to the backbuffer */
424     BlitScreenToBitmap_SP(backbuffer);
425
426     /* blit the completely updated backbuffer to the window (in one blit) */
427     BlitBitmap(backbuffer, window, SX, SY, SXSIZE, SYSIZE, SX, SY);
428 #endif
429   }
430   else
431   {
432     for (x = 0; x < SCR_FIELDX; x++)
433     {
434       for (y = 0; y < SCR_FIELDY; y++)
435       {
436         int xx = (left + x) % MAX_BUF_XSIZE;
437         int yy = (top  + y) % MAX_BUF_YSIZE;
438
439         if (redraw[xx][yy])
440           BlitBitmap(screenBitmap, window,
441                      xx * TILEX, yy * TILEY, TILEX, TILEY,
442                      SX + x * TILEX, SY + y * TILEY);
443       }
444     }
445   }
446
447   FlushDisplay();
448
449   for (x = 0; x < MAX_BUF_XSIZE; x++)
450     for (y = 0; y < MAX_BUF_YSIZE; y++)
451       redraw[x][y] = FALSE;
452   redraw_tiles = 0;
453
454   scrolling_last = scrolling;
455 }
456
457
458 void DDScrollBuffer_Blt_Ext(Bitmap *target_bitmap)
459 {
460   RECT DR, SR;
461   long tX, tY, L;
462   int sX, sY;
463   // RECT ERect;
464   // long Restore;
465
466   if (NoDisplayFlag)
467     return;
468
469 #if 1
470   DR.left = 0;
471   DR.top = 0;
472   DR.right = SCR_FIELDX * TILEX;
473   DR.bottom = SCR_FIELDY * TILEY;
474 #else
475   // --- On Error GoTo BltEH
476   DirectX.GetWindowRect(mhWnd, DR);
477   // --- On Error GoTo 0
478 #endif
479
480   {
481     tX = (DR.right - DR.left) / Stretch;
482     tY = (DR.bottom - DR.top) / Stretch;
483   }
484
485   {
486     SR.left = mScrollX + mDestXOff;
487     SR.top = mScrollY + mDestYOff;
488
489     SR.right = SR.left + tX;
490     SR.bottom = SR.top + tY;
491
492     //    If mWidth < SR.right Then
493     //      SR.right = mWidth
494     //      DR.right = DR.left + Stretch * (SR.right - SR.left)
495     //    End If
496     //    If mHeight < SR.bottom Then
497     //      SR.bottom = mHeight
498     //      DR.bottom = DR.top + Stretch * (SR.bottom - SR.top)
499     //    End If
500     //    If (mScrollX + mDestXOff) < 0 Then
501     //      SR.left = 0
502     //      DR.left = DR.left - Stretch * (mScrollX + mDestXOff)
503     //    End If
504     //    If (mScrollY + mDestYOff) < 0 Then
505     //      SR.top = 0
506     //      DR.top = DR.top - Stretch * (mScrollY + mDestYOff)
507     //    End If
508   }
509
510 #if 1
511   SR.left = (SR.left < 0 ? 0 : SR.left);
512   SR.top  = (SR.top  < 0 ? 0 : SR.top);
513 #endif
514
515 #if 1
516   {
517     int full_xsize = (FieldWidth  - (menBorder.Checked ? 0 : 1)) * TILEX;
518     int full_ysize = (FieldHeight - (menBorder.Checked ? 0 : 1)) * TILEY;
519     int sxsize = SCR_FIELDX * TILEX;
520     int sysize = SCR_FIELDY * TILEY;
521
522     tX = (full_xsize < sxsize ? full_xsize : tX);
523     tY = (full_ysize < sysize ? full_ysize : tY);
524     sX = SX + (full_xsize < sxsize ? (sxsize - full_xsize) / 2 : 0);
525     sY = SY + (full_ysize < sysize ? (sysize - full_ysize) / 2 : 0);
526   }
527 #endif
528
529 #if 1
530   if (!menBorder.Checked)
531   {
532     SR.left += TILEX / 2;
533     SR.top  += TILEY / 2;
534   }
535 #endif
536
537 #if 1
538
539 #if 1
540   printf("::: DDScrollBuffer.c: DDScrollBuffer_Blt(): blit from %d, %d [%ld, %ld] [%ld, %ld] [%ld, %ld]\n",
541          SR.left, SR.top, mScrollX, mScrollY, mDestXOff, mDestYOff, tX, tY);
542 #endif
543
544 #if 0
545   /* !!! quick and dirty -- FIX THIS !!! */
546   if (tape.playing && tape.fast_forward &&
547       target_bitmap == window &&
548       (FrameCounter % 2) != 0)
549     printf("::: FrameCounter == %d\n", FrameCounter);
550 #endif
551
552 #if 1
553   SyncDisplay();
554 #endif
555
556 #if 1
557   BlitBitmap(screenBitmap, target_bitmap,
558              SR.left, SR.top, tX, tY, sX, sY);
559 #else
560   BlitBitmap(screenBitmap, target_bitmap,
561              SR.left, SR.top,
562              SCR_FIELDX * TILEX, SCR_FIELDY * TILEY, SX, SY);
563 #endif
564
565 #if 1
566   FlushDisplay();
567 #endif
568
569   return;
570
571 #endif
572
573   // DDraw.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN, 0
574   if (IS_NOTHING(&Buffer, sizeof(Buffer)))
575     return;
576
577   if (IS_NOTHING(&PrimarySurface, sizeof(PrimarySurface)))
578     return;
579
580   L = PrimarySurface.Blt(DR, &Buffer, SR, DDBLT_WAIT);
581   if (L != DD_OK)
582   {
583     switch (L)
584     {
585 #if 0
586       case DDERR_GENERIC:
587         Debug.Assert(False);
588         break;
589
590       case DDERR_INVALIDCLIPLIST:
591         Debug.Assert(False);
592         break;
593
594       case DDERR_INVALIDOBJECT:
595         Debug.Assert(False);
596         break;
597
598       case DDERR_INVALIDPARAMS:
599         Debug.Assert(False);
600         break;
601
602       case DDERR_INVALIDRECT:
603         Debug.Assert(False);
604         break;
605
606       case DDERR_NOALPHAHW:
607         Debug.Assert(False);
608         break;
609
610       case DDERR_NOBLTHW:
611         Debug.Assert(False);
612         break;
613
614       case DDERR_NOCLIPLIST:
615         Debug.Assert(False);
616         break;
617
618       case DDERR_NODDROPSHW:
619         Debug.Assert(False);
620         break;
621
622       case DDERR_NOMIRRORHW:
623         Debug.Assert(False);
624         break;
625
626       case DDERR_NORASTEROPHW:
627         Debug.Assert(False);
628         break;
629
630       case DDERR_NOROTATIONHW:
631         Debug.Assert(False);
632         break;
633
634       case DDERR_NOSTRETCHHW:
635         Debug.Assert(False);
636         break;
637
638       case DDERR_NOZBUFFERHW:
639         Debug.Assert(False);
640         break;
641
642       case DDERR_SURFACEBUSY:
643         Debug.Assert(False);
644         break;
645 #endif
646
647       case DDERR_SURFACELOST:
648         DDraw.RestoreAllSurfaces();
649         if (! PrimarySurface.isLost())
650         {
651           subDisplayLevel();
652           // Blt();
653         }
654
655         // RestorePrimarySurface
656         // ClipToWindow 0
657         break;
658
659 #if 0
660       case DDERR_UNSUPPORTED:
661         Debug.Assert(False);
662         break;
663
664       case DDERR_WASSTILLDRAWING:
665         Debug.Assert(False);
666         break;
667
668       default:
669         Debug.Assert(False);
670         break;
671 #endif
672     }
673   }
674
675 #if 0
676   //  Buffer.UpdateOverlay SR, PrimarySurface, DR, DDOVER_SHOW
677   if (EditFlag)
678     FMark.RefreshMarker();
679 #endif
680
681   // BltEH:
682 }
683
684 void DDScrollBuffer_Blt()
685 {
686 #if 1
687
688 #if 1
689   BackToFront_SP();
690 #else
691   /* !!! TEST ONLY !!! */
692   BlitBitmap(screenBitmap, window,
693              0, 0, SCR_FIELDX * TILEX, SCR_FIELDY * TILEY, SX, SY);
694 #endif
695
696 #else
697   DDScrollBuffer_Blt_Ext(window);
698 #endif
699 }
700
701 void DDScrollBuffer_ScrollTo(int X, int Y)
702 {
703   if (NoDisplayFlag)
704     return;
705
706   X = X / Stretch;
707   Y = Y / Stretch;
708   mScrollX = X;
709   mScrollY = Y;
710   ScrollX = mScrollX;
711   ScrollY = mScrollY;
712
713 #if 0
714   printf("::: DDScrollBuffer.c: DDScrollBuffer_ScrollTo():  mScroll: %ld, %ld [%d, %d]\n",
715          mScrollX, mScrollY, X, Y);
716 #endif
717
718 #if 1
719   ScrollPlayfieldIfNeeded();
720 #endif
721 }
722
723 void DDScrollBuffer_ScrollTowards(int X, int Y, double Step)
724 {
725   double dx, dY, r;
726
727   if (NoDisplayFlag)
728     return;
729
730 #if 0
731   printf("::: DDScrollBuffer.c: DDScrollBuffer_ScrollTowards(): (1) mScroll: %ld, %ld [%d, %d, %f]\n",
732          mScrollX, mScrollY, X, Y, Step);
733 #endif
734
735   X = X / Stretch;
736   Y = Y / Stretch;
737   dx = X - mScrollX;
738   dY = Y - mScrollY;
739   r = Sqr(dx * dx + dY * dY);
740   if (r == 0) // we are there already
741     return;
742
743   if (Step < r)
744     r = Step / r;
745   else
746     r = 1;
747
748   mScrollX = mScrollX + dx * r;
749   mScrollY = mScrollY + dY * r;
750   ScrollX = mScrollX;
751   ScrollY = mScrollY;
752
753 #if 0
754   printf("::: DDScrollBuffer.c: DDScrollBuffer_ScrollTowards(): (2) mScroll: %ld, %ld [%d, %d, %f]\n",
755          mScrollX, mScrollY, X, Y, Step);
756 #endif
757
758 #if 1
759   ScrollPlayfieldIfNeeded();
760 #endif
761 }
762
763 void DDScrollBuffer_SoftScrollTo(int X, int Y, long TimeMS, int FPS)
764 {
765   double dx, dY;
766 #if 0
767   TickCountObject Tick;
768 #endif
769   long dT, StepCount;
770   double T, tStep;
771   long oldX, oldY, maxD;
772   static boolean AlreadyRunning = False;
773
774   if (NoDisplayFlag)
775     return;
776
777   if (AlreadyRunning)
778   {
779     return;
780   }
781
782   AlreadyRunning = True;
783   X = X / Stretch;
784   Y = Y / Stretch;
785   dx = X - mScrollX;
786   dY = Y - mScrollY;
787   maxD = (Abs(dx) < Abs(dY) ? Abs(dY) : Abs(dx));
788   StepCount = FPS * (TimeMS / (double)1000);
789   if (StepCount > maxD)
790     StepCount = maxD;
791
792   if (StepCount == 0)
793     StepCount = 1;
794
795   dT = 1000 / FPS;
796   tStep = (double)1 / StepCount;
797   oldX = mScrollX;
798   oldY = mScrollY;
799   // R = Sqr(dX * dX + dY * dY)
800   // If R = 0 Then Exit Sub 'we are there already
801   for (T = (double)tStep; T <= (double)1; T += tStep)
802   {
803     if (UserDragFlag)
804       goto SoftScrollEH;
805
806     // If Claim Then Exit For
807
808 #if 0
809     Tick.DelayMS(dT, False);
810 #endif
811
812     mScrollX = oldX + T * dx;
813     mScrollY = oldY + T * dY;
814     ScrollX = mScrollX;
815     ScrollY = mScrollY;
816     // Blt();
817   }
818
819   if (UserDragFlag)
820     goto SoftScrollEH;
821
822 #if 0
823   Tick.DelayMS(dT, False);
824 #endif
825
826   mScrollX = X;
827   mScrollY = Y;
828   ScrollX = mScrollX;
829   ScrollY = mScrollY;
830   // Blt();
831
832 SoftScrollEH:
833   AlreadyRunning = False;
834
835 #if 0
836   printf("::: DDScrollBuffer.c: DDScrollBuffer_SoftScrollTo(): mScroll: %ld, %ld\n",
837          mScrollX, mScrollY);
838 #endif
839
840 #if 1
841   ScrollPlayfieldIfNeeded();
842 #endif
843 }