fdc925f2bbbec6fcff23e67c17114340c7a38d5f
[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 0
352   {
353     static int mScrollX_tmp = -1;
354     static int mScrollY_tmp = -1;
355
356     if (mScrollX != mScrollX_tmp || mScrollY != mScrollY_tmp)
357     {
358       printf("::: %ld, %ld\n", mScrollX, mScrollY);
359
360       mScrollX_tmp = mScrollX;
361       mScrollY_tmp = mScrollY;
362     }
363   }
364 #endif
365
366 #if 0
367   {
368     static boolean x = 0;
369
370     if (x == 0)
371     {
372       printf("::: %d, %d (%d, %d) (%d, %d) [%ld, %ld] [%ld, %ld] \n",
373              sx, sy, xsize, ysize, full_xsize, full_ysize,
374              mScrollX, mScrollY, mScrollX_last, mScrollY_last);
375
376       x = 1;
377     }
378   }
379 #endif
380
381 #if 1
382   if (!menBorder.Checked)
383   {
384     px += TILEX / 2;
385     py += TILEY / 2;
386   }
387 #endif
388
389 #if 0
390   if (mScrollX >= 0 && mScrollX <= 16)
391   {
392     px -= mScrollX;
393   }
394 #if 0
395   else if (mScrollX >= 352 && mScrollX <= 368)
396   {
397     px -= mScrollX;
398   }
399 #endif
400   else if (mScrollX >= 16) // && mScrollX <= 352)
401   {
402     px -= TILEX / 2;
403   }
404 #endif
405
406 #if 0
407   /* !!! TEST ONLY !!! */
408   px = py = 0;
409   sx = sy = SX;
410 #endif
411
412   BlitBitmap(screenBitmap, target_bitmap, px, py, sxsize, sysize, sx, sy);
413 }
414
415 void OLD_BlitScreenToBitmap_SP(Bitmap *target_bitmap)
416 {
417   int x = mScrollX % (MAX_BUF_XSIZE * TILEX);
418   int y = mScrollY % (MAX_BUF_YSIZE * TILEY);
419
420   if (x < 2 * TILEX && y < 2 * TILEY)
421   {
422     BlitBitmap(screenBitmap, target_bitmap, x, y,
423                SCR_FIELDX * TILEX, SCR_FIELDY * TILEY, SX, SY);
424   }
425   else if (x < 2 * TILEX && y >= 2 * TILEY)
426   {
427     BlitBitmap(screenBitmap, target_bitmap, x, y,
428                SCR_FIELDX * TILEX, MAX_BUF_YSIZE * TILEY - y,
429                SX, SY);
430     BlitBitmap(screenBitmap, target_bitmap, x, 0,
431                SCR_FIELDX * TILEX, y - 2 * TILEY,
432                SX, SY + MAX_BUF_YSIZE * TILEY - y);
433   }
434   else if (x >= 2 * TILEX && y < 2 * TILEY)
435   {
436     BlitBitmap(screenBitmap, target_bitmap, x, y,
437                MAX_BUF_XSIZE * TILEX - x, SCR_FIELDY * TILEY,
438                SX, SY);
439     BlitBitmap(screenBitmap, target_bitmap, 0, y,
440                x - 2 * TILEX, SCR_FIELDY * TILEY,
441                SX + MAX_BUF_XSIZE * TILEX - x, SY);
442   }
443   else
444   {
445     BlitBitmap(screenBitmap, target_bitmap, x, y,
446                MAX_BUF_XSIZE * TILEX - x, MAX_BUF_YSIZE * TILEY - y,
447                SX, SY);
448     BlitBitmap(screenBitmap, target_bitmap, 0, y,
449                x - 2 * TILEX, MAX_BUF_YSIZE * TILEY - y,
450                SX + MAX_BUF_XSIZE * TILEX - x, SY);
451     BlitBitmap(screenBitmap, target_bitmap, x, 0,
452                MAX_BUF_XSIZE * TILEX - x, y - 2 * TILEY,
453                SX, SY + MAX_BUF_YSIZE * TILEY - y);
454     BlitBitmap(screenBitmap, target_bitmap, 0, 0,
455                x - 2 * TILEX, y - 2 * TILEY,
456                SX + MAX_BUF_XSIZE * TILEX - x, SY + MAX_BUF_YSIZE * TILEY - y);
457   }
458 }
459
460 void BackToFront_SP(void)
461 {
462   static boolean scrolling_last = FALSE;
463   int left = mScrollX / TILEX;
464   int top  = mScrollY / TILEY;
465   boolean scrolling = (mScrollX % TILEX != 0 || mScrollY % TILEY != 0);
466   int x, y;
467
468   SyncDisplay();
469
470   if (1 ||
471       redraw_tiles > REDRAWTILES_THRESHOLD || scrolling || scrolling_last)
472   {
473 #if 1
474     BlitScreenToBitmap_SP(window);
475 #else
476     /* blit all (up to four) parts of the scroll buffer to the backbuffer */
477     BlitScreenToBitmap_SP(backbuffer);
478
479     /* blit the completely updated backbuffer to the window (in one blit) */
480     BlitBitmap(backbuffer, window, SX, SY, SXSIZE, SYSIZE, SX, SY);
481 #endif
482   }
483   else
484   {
485     for (x = 0; x < SCR_FIELDX; x++)
486     {
487       for (y = 0; y < SCR_FIELDY; y++)
488       {
489         int xx = (left + x) % MAX_BUF_XSIZE;
490         int yy = (top  + y) % MAX_BUF_YSIZE;
491
492         if (redraw[xx][yy])
493           BlitBitmap(screenBitmap, window,
494                      xx * TILEX, yy * TILEY, TILEX, TILEY,
495                      SX + x * TILEX, SY + y * TILEY);
496       }
497     }
498   }
499
500   FlushDisplay();
501
502   for (x = 0; x < MAX_BUF_XSIZE; x++)
503     for (y = 0; y < MAX_BUF_YSIZE; y++)
504       redraw[x][y] = FALSE;
505   redraw_tiles = 0;
506
507   scrolling_last = scrolling;
508 }
509
510
511 void DDScrollBuffer_Blt_Ext(Bitmap *target_bitmap)
512 {
513   RECT DR, SR;
514   long tX, tY, L;
515   int sX, sY;
516   // RECT ERect;
517   // long Restore;
518
519   if (NoDisplayFlag)
520     return;
521
522 #if 1
523   DR.left = 0;
524   DR.top = 0;
525   DR.right = SCR_FIELDX * TILEX;
526   DR.bottom = SCR_FIELDY * TILEY;
527 #else
528   // --- On Error GoTo BltEH
529   DirectX.GetWindowRect(mhWnd, DR);
530   // --- On Error GoTo 0
531 #endif
532
533   {
534     tX = (DR.right - DR.left) / Stretch;
535     tY = (DR.bottom - DR.top) / Stretch;
536   }
537
538   {
539     SR.left = mScrollX + mDestXOff;
540     SR.top = mScrollY + mDestYOff;
541
542     SR.right = SR.left + tX;
543     SR.bottom = SR.top + tY;
544
545     //    If mWidth < SR.right Then
546     //      SR.right = mWidth
547     //      DR.right = DR.left + Stretch * (SR.right - SR.left)
548     //    End If
549     //    If mHeight < SR.bottom Then
550     //      SR.bottom = mHeight
551     //      DR.bottom = DR.top + Stretch * (SR.bottom - SR.top)
552     //    End If
553     //    If (mScrollX + mDestXOff) < 0 Then
554     //      SR.left = 0
555     //      DR.left = DR.left - Stretch * (mScrollX + mDestXOff)
556     //    End If
557     //    If (mScrollY + mDestYOff) < 0 Then
558     //      SR.top = 0
559     //      DR.top = DR.top - Stretch * (mScrollY + mDestYOff)
560     //    End If
561   }
562
563 #if 1
564   SR.left = (SR.left < 0 ? 0 : SR.left);
565   SR.top  = (SR.top  < 0 ? 0 : SR.top);
566 #endif
567
568 #if 1
569   {
570     int full_xsize = (FieldWidth  - (menBorder.Checked ? 0 : 1)) * TILEX;
571     int full_ysize = (FieldHeight - (menBorder.Checked ? 0 : 1)) * TILEY;
572     int sxsize = SCR_FIELDX * TILEX;
573     int sysize = SCR_FIELDY * TILEY;
574
575     tX = (full_xsize < sxsize ? full_xsize : tX);
576     tY = (full_ysize < sysize ? full_ysize : tY);
577     sX = SX + (full_xsize < sxsize ? (sxsize - full_xsize) / 2 : 0);
578     sY = SY + (full_ysize < sysize ? (sysize - full_ysize) / 2 : 0);
579   }
580 #endif
581
582 #if 1
583   if (!menBorder.Checked)
584   {
585     SR.left += TILEX / 2;
586     SR.top  += TILEY / 2;
587   }
588 #endif
589
590 #if 1
591
592 #if 1
593   printf("::: DDScrollBuffer.c: DDScrollBuffer_Blt(): blit from %d, %d [%ld, %ld] [%ld, %ld] [%ld, %ld]\n",
594          SR.left, SR.top, mScrollX, mScrollY, mDestXOff, mDestYOff, tX, tY);
595 #endif
596
597 #if 0
598   /* !!! quick and dirty -- FIX THIS !!! */
599   if (tape.playing && tape.fast_forward &&
600       target_bitmap == window &&
601       (FrameCounter % 2) != 0)
602     printf("::: FrameCounter == %d\n", FrameCounter);
603 #endif
604
605 #if 1
606   SyncDisplay();
607 #endif
608
609 #if 1
610   BlitBitmap(screenBitmap, target_bitmap,
611              SR.left, SR.top, tX, tY, sX, sY);
612 #else
613   BlitBitmap(screenBitmap, target_bitmap,
614              SR.left, SR.top,
615              SCR_FIELDX * TILEX, SCR_FIELDY * TILEY, SX, SY);
616 #endif
617
618 #if 1
619   FlushDisplay();
620 #endif
621
622   return;
623
624 #endif
625
626   // DDraw.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN, 0
627   if (IS_NOTHING(&Buffer, sizeof(Buffer)))
628     return;
629
630   if (IS_NOTHING(&PrimarySurface, sizeof(PrimarySurface)))
631     return;
632
633   L = PrimarySurface.Blt(DR, &Buffer, SR, DDBLT_WAIT);
634   if (L != DD_OK)
635   {
636     switch (L)
637     {
638 #if 0
639       case DDERR_GENERIC:
640         Debug.Assert(False);
641         break;
642
643       case DDERR_INVALIDCLIPLIST:
644         Debug.Assert(False);
645         break;
646
647       case DDERR_INVALIDOBJECT:
648         Debug.Assert(False);
649         break;
650
651       case DDERR_INVALIDPARAMS:
652         Debug.Assert(False);
653         break;
654
655       case DDERR_INVALIDRECT:
656         Debug.Assert(False);
657         break;
658
659       case DDERR_NOALPHAHW:
660         Debug.Assert(False);
661         break;
662
663       case DDERR_NOBLTHW:
664         Debug.Assert(False);
665         break;
666
667       case DDERR_NOCLIPLIST:
668         Debug.Assert(False);
669         break;
670
671       case DDERR_NODDROPSHW:
672         Debug.Assert(False);
673         break;
674
675       case DDERR_NOMIRRORHW:
676         Debug.Assert(False);
677         break;
678
679       case DDERR_NORASTEROPHW:
680         Debug.Assert(False);
681         break;
682
683       case DDERR_NOROTATIONHW:
684         Debug.Assert(False);
685         break;
686
687       case DDERR_NOSTRETCHHW:
688         Debug.Assert(False);
689         break;
690
691       case DDERR_NOZBUFFERHW:
692         Debug.Assert(False);
693         break;
694
695       case DDERR_SURFACEBUSY:
696         Debug.Assert(False);
697         break;
698 #endif
699
700       case DDERR_SURFACELOST:
701         DDraw.RestoreAllSurfaces();
702         if (! PrimarySurface.isLost())
703         {
704           subDisplayLevel();
705           // Blt();
706         }
707
708         // RestorePrimarySurface
709         // ClipToWindow 0
710         break;
711
712 #if 0
713       case DDERR_UNSUPPORTED:
714         Debug.Assert(False);
715         break;
716
717       case DDERR_WASSTILLDRAWING:
718         Debug.Assert(False);
719         break;
720
721       default:
722         Debug.Assert(False);
723         break;
724 #endif
725     }
726   }
727
728 #if 0
729   //  Buffer.UpdateOverlay SR, PrimarySurface, DR, DDOVER_SHOW
730   if (EditFlag)
731     FMark.RefreshMarker();
732 #endif
733
734   // BltEH:
735 }
736
737 void DDScrollBuffer_Blt()
738 {
739 #if 1
740
741 #if 1
742   BackToFront_SP();
743 #else
744   /* !!! TEST ONLY !!! */
745   BlitBitmap(screenBitmap, window,
746              0, 0, SCR_FIELDX * TILEX, SCR_FIELDY * TILEY, SX, SY);
747 #endif
748
749 #else
750   DDScrollBuffer_Blt_Ext(window);
751 #endif
752 }
753
754 void DDScrollBuffer_ScrollTo(int X, int Y)
755 {
756   if (NoDisplayFlag)
757     return;
758
759   X = X / Stretch;
760   Y = Y / Stretch;
761   mScrollX = X;
762   mScrollY = Y;
763   ScrollX = mScrollX;
764   ScrollY = mScrollY;
765
766 #if 0
767   printf("::: DDScrollBuffer.c: DDScrollBuffer_ScrollTo():  mScroll: %ld, %ld [%d, %d]\n",
768          mScrollX, mScrollY, X, Y);
769 #endif
770
771 #if 1
772   ScrollPlayfieldIfNeeded();
773 #endif
774 }
775
776 void DDScrollBuffer_ScrollTowards(int X, int Y, double Step)
777 {
778   double dx, dY, r;
779
780   if (NoDisplayFlag)
781     return;
782
783 #if 0
784   printf("::: DDScrollBuffer.c: DDScrollBuffer_ScrollTowards(): (1) mScroll: %ld, %ld [%d, %d, %f]\n",
785          mScrollX, mScrollY, X, Y, Step);
786 #endif
787
788   X = X / Stretch;
789   Y = Y / Stretch;
790   dx = X - mScrollX;
791   dY = Y - mScrollY;
792   r = Sqr(dx * dx + dY * dY);
793   if (r == 0) // we are there already
794     return;
795
796   if (Step < r)
797     r = Step / r;
798   else
799     r = 1;
800
801   mScrollX = mScrollX + dx * r;
802   mScrollY = mScrollY + dY * r;
803   ScrollX = mScrollX;
804   ScrollY = mScrollY;
805
806 #if 0
807   printf("::: DDScrollBuffer.c: DDScrollBuffer_ScrollTowards(): (2) mScroll: %ld, %ld [%d, %d, %f]\n",
808          mScrollX, mScrollY, X, Y, Step);
809 #endif
810
811 #if 1
812   ScrollPlayfieldIfNeeded();
813 #endif
814 }
815
816 void DDScrollBuffer_SoftScrollTo(int X, int Y, long TimeMS, int FPS)
817 {
818   double dx, dY;
819 #if 0
820   TickCountObject Tick;
821 #endif
822   long dT, StepCount;
823   double T, tStep;
824   long oldX, oldY, maxD;
825   static boolean AlreadyRunning = False;
826
827   if (NoDisplayFlag)
828     return;
829
830   if (AlreadyRunning)
831   {
832     return;
833   }
834
835   AlreadyRunning = True;
836   X = X / Stretch;
837   Y = Y / Stretch;
838   dx = X - mScrollX;
839   dY = Y - mScrollY;
840   maxD = (Abs(dx) < Abs(dY) ? Abs(dY) : Abs(dx));
841   StepCount = FPS * (TimeMS / (double)1000);
842   if (StepCount > maxD)
843     StepCount = maxD;
844
845   if (StepCount == 0)
846     StepCount = 1;
847
848   dT = 1000 / FPS;
849   tStep = (double)1 / StepCount;
850   oldX = mScrollX;
851   oldY = mScrollY;
852   // R = Sqr(dX * dX + dY * dY)
853   // If R = 0 Then Exit Sub 'we are there already
854   for (T = (double)tStep; T <= (double)1; T += tStep)
855   {
856     if (UserDragFlag)
857       goto SoftScrollEH;
858
859     // If Claim Then Exit For
860
861 #if 0
862     Tick.DelayMS(dT, False);
863 #endif
864
865     mScrollX = oldX + T * dx;
866     mScrollY = oldY + T * dY;
867     ScrollX = mScrollX;
868     ScrollY = mScrollY;
869     // Blt();
870   }
871
872   if (UserDragFlag)
873     goto SoftScrollEH;
874
875 #if 0
876   Tick.DelayMS(dT, False);
877 #endif
878
879   mScrollX = X;
880   mScrollY = Y;
881   ScrollX = mScrollX;
882   ScrollY = mScrollY;
883   // Blt();
884
885 SoftScrollEH:
886   AlreadyRunning = False;
887
888 #if 0
889   printf("::: DDScrollBuffer.c: DDScrollBuffer_SoftScrollTo(): mScroll: %ld, %ld\n",
890          mScrollX, mScrollY);
891 #endif
892
893 #if 1
894   ScrollPlayfieldIfNeeded();
895 #endif
896 }