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