1 #include <stdexcept>
2
3 #include "Font.h"
4 #include "Local.h"
5 #include "WorldDef.h"
6 #include "RenderWorld.h"
7 #include "VSurface.h"
8 #include "Render_Dirty.h"
9 #include "SysUtil.h"
10 #include "Video.h"
11 #include "VObject_Blitters.h"
12 #include <stdarg.h>
13 #include "MemMan.h"
14 #include "Debug.h"
15 #include "UILayout.h"
16
17 #include <vector>
18
19 #include "Logger.h"
20
21
22 #define BACKGROUND_BUFFERS 500
23
24
25 // Struct for backgrounds
26 struct BACKGROUND_SAVE
27 {
28 BOOLEAN fAllocated;
29 BOOLEAN fFilled;
30 BOOLEAN fFreeMemory;
31 BackgroundFlags uiFlags;
32 UINT16* pSaveArea;
33 UINT16* pZSaveArea;
34 INT16 sLeft;
35 INT16 sTop;
36 INT16 sRight;
37 INT16 sBottom;
38 INT16 sWidth;
39 INT16 sHeight;
40 BOOLEAN fPendingDelete;
41 BOOLEAN fDisabled;
42 };
43
44
45 static std::vector<BACKGROUND_SAVE*> gBackSaves;
46 static UINT32 guiNumBackSaves=0;
47
48 static VIDEO_OVERLAY* gVideoOverlays;
49
50
51 #define FOR_EACH_VIDEO_OVERLAY(iter) \
52 for (VIDEO_OVERLAY* iter = gVideoOverlays; iter; iter = iter->next) \
53 if (iter->fDisabled) continue; else
54
55 #define FOR_EACH_VIDEO_OVERLAY_SAFE(iter) \
56 for (VIDEO_OVERLAY* iter = gVideoOverlays, * iter##__next; iter; iter = iter##__next) \
57 if (iter##__next = iter->next, iter->fDisabled) continue; else
58
59
60 SGPRect gDirtyClipRect;
61
62
63 static BOOLEAN gfViewportDirty = FALSE;
64
65
AddBaseDirtyRect(INT32 iLeft,INT32 iTop,INT32 iRight,INT32 iBottom)66 void AddBaseDirtyRect(INT32 iLeft, INT32 iTop, INT32 iRight, INT32 iBottom)
67 {
68 if (iLeft < 0) iLeft = 0;
69 if (iLeft > SCREEN_WIDTH) iLeft = SCREEN_WIDTH;
70
71 if (iTop < 0) iTop = 0;
72 if (iTop > SCREEN_HEIGHT) iTop = SCREEN_HEIGHT;
73
74 if (iRight < 0) iRight = 0;
75 if (iRight > SCREEN_WIDTH) iRight = SCREEN_WIDTH;
76
77 if (iBottom < 0) iBottom = 0;
78 if (iBottom > SCREEN_HEIGHT) iBottom = SCREEN_HEIGHT;
79
80 if (iLeft == iRight || iTop == iBottom) return;
81
82 if (iLeft == gsVIEWPORT_START_X &&
83 iRight == gsVIEWPORT_END_X &&
84 iTop == gsVIEWPORT_WINDOW_START_Y &&
85 iBottom == gsVIEWPORT_WINDOW_END_Y)
86 {
87 gfViewportDirty = TRUE;
88 return;
89 }
90
91 InvalidateRegionEx(iLeft, iTop, iRight, iBottom);
92 }
93
94
ExecuteBaseDirtyRectQueue(void)95 void ExecuteBaseDirtyRectQueue(void)
96 {
97 if (!gfViewportDirty) return;
98 gfViewportDirty = FALSE;
99
100 InvalidateScreen();
101 }
102
103
GetFreeBackgroundBuffer(void)104 static BACKGROUND_SAVE* GetFreeBackgroundBuffer(void)
105 {
106 for (UINT32 i = 0; i < guiNumBackSaves; ++i)
107 {
108 BACKGROUND_SAVE* const b = gBackSaves[i];
109 if (!b->fAllocated && !b->fFilled) return b;
110 }
111
112 if (guiNumBackSaves == gBackSaves.size())
113 {
114 // out of back saves capacity
115 // let's add some more
116 const int increment = 100;
117 SLOGD("Increasing background slots to %d", gBackSaves.size() + increment);
118 for(int i = 0; i < increment; i++) {
119 gBackSaves.push_back(new BACKGROUND_SAVE());
120 }
121 }
122
123 return gBackSaves[guiNumBackSaves++];
124 }
125
126
RegisterBackgroundRect(BackgroundFlags const uiFlags,INT16 sLeft,INT16 sTop,INT16 const usWidth,INT16 const usHeight)127 BACKGROUND_SAVE* RegisterBackgroundRect(BackgroundFlags const uiFlags, INT16 sLeft, INT16 sTop, INT16 const usWidth, INT16 const usHeight)
128 {
129 const INT32 ClipX1 = gDirtyClipRect.iLeft;
130 const INT32 ClipY1 = gDirtyClipRect.iTop;
131 const INT32 ClipX2 = gDirtyClipRect.iRight;
132 const INT32 ClipY2 = gDirtyClipRect.iBottom;
133
134 INT16 sRight = sLeft + usWidth;
135 INT16 sBottom = sTop + usHeight;
136
137 const INT32 iTempX = sLeft;
138 const INT32 iTempY = sTop;
139
140 // Clip to rect
141 const INT32 uiLeftSkip = __min(ClipX1 - MIN(ClipX1, iTempX), (INT32)usWidth);
142 const INT32 uiTopSkip = __min(ClipY1 - __min(ClipY1, iTempY), (INT32)usHeight);
143 const INT32 uiRightSkip = __min( MAX(ClipX2, iTempX + (INT32)usWidth) - ClipX2, (INT32)usWidth);
144 const INT32 uiBottomSkip = __min(__max(ClipY2, iTempY + (INT32)usHeight) - ClipY2, (INT32)usHeight);
145
146 // check if whole thing is clipped
147 if (uiLeftSkip >= (INT32)usWidth || uiRightSkip >= (INT32)usWidth) return NO_BGND_RECT;
148 if (uiTopSkip >= (INT32)usHeight || uiBottomSkip >= (INT32)usHeight) return NO_BGND_RECT;
149
150 // Set re-set values given based on clipping
151 sLeft += uiLeftSkip;
152 sRight -= uiRightSkip;
153 sTop += uiTopSkip;
154 sBottom -= uiBottomSkip;
155
156 BACKGROUND_SAVE* const b = GetFreeBackgroundBuffer();
157 *b = BACKGROUND_SAVE{};
158
159 const UINT32 uiBufSize = (sRight - sLeft) * (sBottom - sTop);
160 if (uiBufSize == 0) return NO_BGND_RECT;
161
162 if (uiFlags & BGND_FLAG_SAVERECT) b->pSaveArea = new UINT16[uiBufSize]{};
163 if (uiFlags & BGND_FLAG_SAVE_Z) b->pZSaveArea = new UINT16[uiBufSize]{};
164
165 b->fFreeMemory = TRUE;
166 b->fAllocated = TRUE;
167 b->uiFlags = uiFlags;
168 b->sLeft = sLeft;
169 b->sTop = sTop;
170 b->sRight = sRight;
171 b->sBottom = sBottom;
172 b->sWidth = sRight - sLeft;
173 b->sHeight = sBottom - sTop;
174 b->fFilled = FALSE;
175
176 return b;
177 }
178
179
RegisterBackgroundRectSingleFilled(INT16 const x,INT16 const y,INT16 const w,INT16 const h)180 void RegisterBackgroundRectSingleFilled(INT16 const x, INT16 const y, INT16 const w, INT16 const h)
181 {
182 BACKGROUND_SAVE* const b = RegisterBackgroundRect(BGND_FLAG_SINGLE, x, y, w, h);
183 if (b == NO_BGND_RECT) return;
184
185 b->fFilled = TRUE;
186 AddBaseDirtyRect(b->sLeft, b->sTop, b->sRight, b->sBottom);
187 }
188
189
RestoreBackgroundRects(void)190 void RestoreBackgroundRects(void)
191 {
192 { SGPVSurface::Lock lsrc(guiSAVEBUFFER);
193 SGPVSurface::Lock ldst(FRAME_BUFFER);
194 UINT16* const pSrcBuf = lsrc.Buffer<UINT16>();
195 UINT32 uiSrcPitchBYTES = lsrc.Pitch();
196 UINT16* const pDestBuf = ldst.Buffer<UINT16>();
197 UINT32 uiDestPitchBYTES = ldst.Pitch();
198
199 for (UINT32 i = 0; i < guiNumBackSaves; ++i)
200 {
201 const BACKGROUND_SAVE* const b = gBackSaves[i];
202 if (!b->fFilled || b->fDisabled) continue;
203
204 if (b->pSaveArea != NULL)
205 {
206 Blt16BPPTo16BPP(pDestBuf, uiDestPitchBYTES, b->pSaveArea, b->sWidth * 2, b->sLeft, b->sTop, 0, 0, b->sWidth, b->sHeight);
207 AddBaseDirtyRect(b->sLeft, b->sTop, b->sRight, b->sBottom);
208 }
209 else if (b->pZSaveArea != NULL)
210 {
211 Blt16BPPTo16BPP(gpZBuffer, gZBufferPitch, b->pZSaveArea, b->sWidth * sizeof(*b->pZSaveArea), b->sLeft, b->sTop, 0, 0, b->sWidth, b->sHeight);
212 }
213 else
214 {
215 Blt16BPPTo16BPP(pDestBuf, uiDestPitchBYTES, pSrcBuf, uiSrcPitchBYTES, b->sLeft, b->sTop, b->sLeft, b->sTop, b->sWidth, b->sHeight);
216 AddBaseDirtyRect(b->sLeft, b->sTop, b->sRight, b->sBottom);
217 }
218 }
219 }
220
221 EmptyBackgroundRects();
222 }
223
224
EmptyBackgroundRects(void)225 void EmptyBackgroundRects(void)
226 {
227 for (UINT32 i = 0; i < guiNumBackSaves; ++i)
228 {
229 BACKGROUND_SAVE* const b = gBackSaves[i];
230 if (b->fFilled)
231 {
232 b->fFilled = FALSE;
233
234 if (!b->fAllocated && b->fFreeMemory)
235 {
236 if (b->pSaveArea != NULL) delete[] b->pSaveArea;
237 if (b->pZSaveArea != NULL) delete[] b->pZSaveArea;
238
239 b->fAllocated = FALSE;
240 b->fFreeMemory = FALSE;
241 b->fFilled = FALSE;
242 b->pSaveArea = NULL;
243 }
244 }
245
246 if (b->uiFlags & BGND_FLAG_SINGLE || b->fPendingDelete)
247 {
248 if (b->fFreeMemory)
249 {
250 if (b->pSaveArea != NULL) delete[] b->pSaveArea;
251 if (b->pZSaveArea != NULL) delete[] b->pZSaveArea;
252 }
253
254 b->fAllocated = FALSE;
255 b->fFreeMemory = FALSE;
256 b->fFilled = FALSE;
257 b->pSaveArea = NULL;
258 b->fPendingDelete = FALSE;
259 }
260 }
261 }
262
263
SaveBackgroundRects(void)264 void SaveBackgroundRects(void)
265 {
266 SGPVSurface::Lock l(FRAME_BUFFER);
267 UINT16* const pSrcBuf = l.Buffer<UINT16>();
268 UINT32 const uiDestPitchBYTES = l.Pitch();
269
270 for (UINT32 i = 0; i < guiNumBackSaves; ++i)
271 {
272 BACKGROUND_SAVE* const b = gBackSaves[i];
273 if (!b->fAllocated || b->fDisabled) continue;
274
275 if (b->pSaveArea != NULL)
276 {
277 Blt16BPPTo16BPP(b->pSaveArea, b->sWidth * 2, pSrcBuf, uiDestPitchBYTES, 0, 0, b->sLeft, b->sTop, b->sWidth, b->sHeight);
278 }
279 else if (b->pZSaveArea != NULL)
280 {
281 Blt16BPPTo16BPP(b->pZSaveArea, b->sWidth * sizeof(*b->pZSaveArea), gpZBuffer, gZBufferPitch, 0, 0, b->sLeft, b->sTop, b->sWidth, b->sHeight);
282 }
283 else
284 {
285 AddBaseDirtyRect(b->sLeft, b->sTop, b->sRight, b->sBottom);
286 }
287
288 b->fFilled = TRUE;
289 }
290 }
291
292
FreeBackgroundRect(BACKGROUND_SAVE * const b)293 void FreeBackgroundRect(BACKGROUND_SAVE* const b)
294 {
295 if (b == NULL) return;
296
297 b->fAllocated = FALSE;
298 }
299
300
FreeBackgroundRectPending(BACKGROUND_SAVE * const b)301 void FreeBackgroundRectPending(BACKGROUND_SAVE* const b)
302 {
303 if(b)
304 {
305 b->fPendingDelete = TRUE;
306 }
307 }
308
309
FreeBackgroundRectNow(BACKGROUND_SAVE * const b)310 static void FreeBackgroundRectNow(BACKGROUND_SAVE* const b)
311 {
312 if (b->fFreeMemory)
313 {
314 if (b->pSaveArea) delete[] b->pSaveArea;
315 if (b->pZSaveArea) delete[] b->pZSaveArea;
316 }
317
318 b->fAllocated = FALSE;
319 b->fFreeMemory = FALSE;
320 b->fFilled = FALSE;
321 b->pSaveArea = NULL;
322 }
323
324
FreeBackgroundRectType(BackgroundFlags const uiFlags)325 void FreeBackgroundRectType(BackgroundFlags const uiFlags)
326 {
327 for (UINT32 i = 0; i < guiNumBackSaves; ++i)
328 {
329 BACKGROUND_SAVE* const b = gBackSaves[i];
330 if (b->uiFlags & uiFlags) FreeBackgroundRectNow(b);
331 }
332 }
333
334
InitializeBackgroundRects(void)335 void InitializeBackgroundRects(void)
336 {
337 guiNumBackSaves = 0;
338 gDirtyClipRect.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
339 }
340
341
InvalidateBackgroundRects(void)342 void InvalidateBackgroundRects(void)
343 {
344 for (UINT32 i = 0; i < guiNumBackSaves; ++i)
345 {
346 gBackSaves[i]->fFilled = FALSE;
347 }
348 }
349
350
ShutdownBackgroundRects(void)351 void ShutdownBackgroundRects(void)
352 {
353 for (auto backgroundSave : gBackSaves)
354 {
355 if (backgroundSave->fAllocated) FreeBackgroundRectNow(backgroundSave);
356 delete backgroundSave;
357 }
358 gBackSaves.clear();
359 guiNumBackSaves = 0;
360 }
361
362
UpdateSaveBuffer(void)363 void UpdateSaveBuffer(void)
364 {
365 // Update saved buffer - do for the viewport size ony!
366 BlitBufferToBuffer(FRAME_BUFFER, guiSAVEBUFFER, 0, gsVIEWPORT_WINDOW_START_Y, SCREEN_WIDTH, gsVIEWPORT_WINDOW_END_Y - gsVIEWPORT_WINDOW_START_Y);
367 }
368
369
RestoreExternBackgroundRect(const INT16 sLeft,const INT16 sTop,const INT16 sWidth,const INT16 sHeight)370 void RestoreExternBackgroundRect(const INT16 sLeft, const INT16 sTop, const INT16 sWidth, const INT16 sHeight)
371 {
372 Assert(0 <= sLeft && sLeft + sWidth <= SCREEN_WIDTH && 0 <= sTop && sTop + sHeight <= SCREEN_HEIGHT);
373
374 BlitBufferToBuffer(guiSAVEBUFFER, FRAME_BUFFER, sLeft, sTop, sWidth, sHeight);
375
376 // Add rect to frame buffer queue
377 InvalidateRegionEx(sLeft, sTop, sLeft + sWidth, sTop + sHeight);
378 }
379
380
RestoreExternBackgroundRectGivenID(const BACKGROUND_SAVE * const b)381 void RestoreExternBackgroundRectGivenID(const BACKGROUND_SAVE* const b)
382 {
383 if (!b->fAllocated) return;
384 RestoreExternBackgroundRect(b->sLeft, b->sTop, b->sWidth, b->sHeight);
385 }
386
387
388 /* Dirties a single-frame rect exactly the size needed to save the background
389 * for a given call to gprintf. Note that this must be called before the
390 * backgrounds are saved, and before the actual call to gprintf that writes to
391 * the video buffer. */
GDirty(INT16 x,INT16 y,const ST::utf32_buffer & codepoints)392 static void GDirty(INT16 x, INT16 y, const ST::utf32_buffer& codepoints)
393 {
394 UINT16 const length = StringPixLength(codepoints, FontDefault);
395 if (length > 0)
396 {
397 UINT16 const height = GetFontHeight(FontDefault);
398 RegisterBackgroundRectSingleFilled(x, y, length, height);
399 }
400 }
401
402
GDirtyPrint(INT16 x,INT16 y,const ST::utf32_buffer & codepoints)403 void GDirtyPrint(INT16 x, INT16 y, const ST::utf32_buffer& codepoints)
404 {
405 GDirty(x, y, codepoints);
406 MPrint(x, y, codepoints);
407 }
408
409
GPrintInvalidate(INT16 x,INT16 y,const ST::utf32_buffer & codepoints)410 void GPrintInvalidate(INT16 x, INT16 y, const ST::utf32_buffer& codepoints)
411 {
412 MPrint(x, y, codepoints);
413
414 UINT16 const length = StringPixLength(codepoints, FontDefault);
415 if (length > 0)
416 {
417 UINT16 const height = GetFontHeight(FontDefault);
418 InvalidateRegionEx(x, y, x + length, y + height);
419 }
420 }
421
422
RegisterVideoOverlay(OVERLAY_CALLBACK const callback,INT16 const x,INT16 const y,INT16 const w,INT16 const h)423 VIDEO_OVERLAY* RegisterVideoOverlay(OVERLAY_CALLBACK const callback, INT16 const x, INT16 const y, INT16 const w, INT16 const h)
424 try
425 {
426 BACKGROUND_SAVE* const bgs = RegisterBackgroundRect(BGND_FLAG_PERMANENT, x, y, w, h);
427 if (!bgs) return 0;
428
429 VIDEO_OVERLAY* const v = new VIDEO_OVERLAY{};
430 VIDEO_OVERLAY* const head = gVideoOverlays;
431 v->prev = 0;
432 v->next = head;
433 v->fAllocated = 2;
434 v->background = bgs;
435 v->sX = x;
436 v->sY = y;
437 v->uiDestBuff = FRAME_BUFFER;
438 v->BltCallback = callback;
439
440 if (head) head->prev = v;
441 gVideoOverlays = v;
442 return v;
443 }
444 catch (...) { return 0; }
445
446
RegisterVideoOverlay(OVERLAY_CALLBACK callback,INT16 x,INT16 y,SGPFont font,UINT8 foreground,UINT8 background,const ST::utf32_buffer & codepoints)447 VIDEO_OVERLAY* RegisterVideoOverlay(OVERLAY_CALLBACK callback, INT16 x, INT16 y, SGPFont font, UINT8 foreground, UINT8 background, const ST::utf32_buffer& codepoints)
448 {
449 INT16 const w = StringPixLength(codepoints, font);
450 INT16 const h = GetFontHeight(font);
451 VIDEO_OVERLAY* const v = RegisterVideoOverlay(callback, x, y, w, h);
452 if (v)
453 {
454 v->uiFontID = font;
455 v->ubFontFore = foreground;
456 v->ubFontBack = background;
457 v->codepoints = codepoints;
458 }
459 return v;
460 }
461
462
RemoveVideoOverlay(VIDEO_OVERLAY * const v)463 void RemoveVideoOverlay(VIDEO_OVERLAY* const v)
464 {
465 if (!v) return;
466
467 // Check if we are actively scrolling
468 if (v->fActivelySaving)
469 {
470 v->fDeletionPending = TRUE;
471 }
472 else
473 {
474 //RestoreExternBackgroundRectGivenID(v->background);
475
476 FreeBackgroundRect(v->background);
477
478 if (v->pSaveArea != NULL) delete v->pSaveArea;
479 v->pSaveArea = NULL;
480
481 VIDEO_OVERLAY* const prev = v->prev;
482 VIDEO_OVERLAY* const next = v->next;
483 *(prev ? &prev->next : &gVideoOverlays) = next;
484 if (next) next->prev = prev;
485 delete v;
486 }
487 }
488
489
490 // FUnctions for entrie array of blitters
ExecuteVideoOverlays(void)491 void ExecuteVideoOverlays(void)
492 {
493 FOR_EACH_VIDEO_OVERLAY(v)
494 {
495 // If we are scrolling but haven't saved yet, don't!
496 if (!v->fActivelySaving && g_scroll_inertia) continue;
497
498 // ATE: Wait a frame before executing!
499 switch (v->fAllocated)
500 {
501 case 1: v->BltCallback(v); break;
502 case 2: v->fAllocated = 1; break;
503 }
504 }
505 }
506
507
ExecuteVideoOverlaysToAlternateBuffer(SGPVSurface * const buffer)508 void ExecuteVideoOverlaysToAlternateBuffer(SGPVSurface* const buffer)
509 {
510 FOR_EACH_VIDEO_OVERLAY(v)
511 {
512 if (!v->fActivelySaving) continue;
513
514 SGPVSurface* const old_dst = v->uiDestBuff;
515 v->uiDestBuff = buffer;
516 v->BltCallback(v);
517 v->uiDestBuff = old_dst;
518 }
519 }
520
521
AllocateVideoOverlayArea(VIDEO_OVERLAY * const v)522 static void AllocateVideoOverlayArea(VIDEO_OVERLAY* const v)
523 {
524 Assert(!v->fDisabled);
525
526 // Get buffer size
527 const BACKGROUND_SAVE* const bgs = v->background;
528 UINT32 const buf_size = (bgs->sRight - bgs->sLeft) * (bgs->sBottom - bgs->sTop);
529
530 v->fActivelySaving = TRUE;
531 v->pSaveArea = new UINT16[buf_size]{};
532 }
533
534
AllocateVideoOverlaysArea(void)535 void AllocateVideoOverlaysArea(void)
536 {
537 FOR_EACH_VIDEO_OVERLAY(v)
538 {
539 AllocateVideoOverlayArea(v);
540 }
541 }
542
543
SaveVideoOverlaysArea(SGPVSurface * const src)544 void SaveVideoOverlaysArea(SGPVSurface* const src)
545 {
546 SGPVSurface::Lock l(src);
547 UINT16* const pSrcBuf = l.Buffer<UINT16>();
548 UINT32 const uiSrcPitchBYTES = l.Pitch();
549
550 FOR_EACH_VIDEO_OVERLAY(v)
551 {
552 // OK, if our saved area is null, allocate it here!
553 if (v->pSaveArea == NULL)
554 {
555 AllocateVideoOverlayArea(v);
556 if (v->pSaveArea == NULL) continue;
557 }
558
559 // Save data from frame buffer!
560 const BACKGROUND_SAVE* const b = v->background;
561 Blt16BPPTo16BPP(v->pSaveArea, b->sWidth * 2, pSrcBuf, uiSrcPitchBYTES, 0, 0, b->sLeft, b->sTop, b->sWidth, b->sHeight);
562 }
563 }
564
565
DeleteVideoOverlaysArea(void)566 void DeleteVideoOverlaysArea(void)
567 {
568 FOR_EACH_VIDEO_OVERLAY_SAFE(v)
569 {
570 if (v->pSaveArea != NULL) delete[] v->pSaveArea;
571 v->pSaveArea = NULL;
572 v->fActivelySaving = FALSE;
573 if (v->fDeletionPending) RemoveVideoOverlay(v);
574 }
575 }
576
577
RestoreShiftedVideoOverlays(const INT16 sShiftX,const INT16 sShiftY)578 void RestoreShiftedVideoOverlays(const INT16 sShiftX, const INT16 sShiftY)
579 {
580 const INT32 ClipX1 = 0;
581 const INT32 ClipY1 = gsVIEWPORT_WINDOW_START_Y;
582 const INT32 ClipX2 = SCREEN_WIDTH;
583 const INT32 ClipY2 = gsVIEWPORT_WINDOW_END_Y - 1;
584
585 SGPVSurface::Lock l(BACKBUFFER);
586 UINT16* const pDestBuf = l.Buffer<UINT16>();
587 UINT32 const uiDestPitchBYTES = l.Pitch();
588
589 FOR_EACH_VIDEO_OVERLAY_SAFE(v)
590 {
591 if (v->pSaveArea == NULL) continue;
592
593 // Get restore background values
594 const BACKGROUND_SAVE* const b = v->background;
595 INT16 sLeft = b->sLeft;
596 INT16 sTop = b->sTop;
597 INT16 sRight = b->sRight;
598 INT16 sBottom = b->sBottom;
599 UINT32 usHeight = b->sHeight;
600 UINT32 usWidth = b->sWidth;
601
602 // Clip!!
603 const INT32 iTempX = sLeft - sShiftX;
604 const INT32 iTempY = sTop - sShiftY;
605
606 // Clip to rect
607 const INT32 uiLeftSkip = __min(ClipX1 - MIN(ClipX1, iTempX), (INT32)usWidth);
608 const INT32 uiTopSkip = __min(ClipY1 - __min(ClipY1, iTempY), (INT32)usHeight);
609 const INT32 uiRightSkip = __min( MAX(ClipX2, iTempX + (INT32)usWidth) - ClipX2, (INT32)usWidth);
610 const INT32 uiBottomSkip = __min(__max(ClipY2, iTempY + (INT32)usHeight) - ClipY2, (INT32)usHeight);
611
612 // check if whole thing is clipped
613 if (uiLeftSkip >= (INT32)usWidth || uiRightSkip >= (INT32)usWidth) continue;
614 if (uiTopSkip >= (INT32)usHeight || uiBottomSkip >= (INT32)usHeight) continue;
615
616 // Set re-set values given based on clipping
617 sLeft = iTempX + (INT16)uiLeftSkip;
618 sTop = iTempY + (INT16)uiTopSkip;
619 sRight = sRight - sShiftX - (INT16)uiRightSkip;
620 sBottom = sBottom - sShiftY - (INT16)uiBottomSkip;
621
622 usHeight = sBottom - sTop;
623 usWidth = sRight - sLeft;
624
625 Blt16BPPTo16BPP(pDestBuf, uiDestPitchBYTES, v->pSaveArea, b->sWidth * 2, sLeft, sTop, uiLeftSkip, uiTopSkip, usWidth, usHeight);
626
627 // Once done, check for pending deletion
628 if (v->fDeletionPending) RemoveVideoOverlay(v);
629 }
630 }
631
632
BlitBufferToBuffer(SGPVSurface * const src,SGPVSurface * const dst,const UINT16 usSrcX,const UINT16 usSrcY,const UINT16 usWidth,const UINT16 usHeight)633 void BlitBufferToBuffer(SGPVSurface* const src, SGPVSurface* const dst, const UINT16 usSrcX, const UINT16 usSrcY, const UINT16 usWidth, const UINT16 usHeight)
634 {
635 SGPBox const r = { usSrcX, usSrcY, usWidth, usHeight };
636 BltVideoSurface(dst, src, usSrcX, usSrcY, &r);
637 }
638
639
EnableVideoOverlay(const BOOLEAN fEnable,VIDEO_OVERLAY * const v)640 void EnableVideoOverlay(const BOOLEAN fEnable, VIDEO_OVERLAY* const v)
641 {
642 if (!v) return;
643 v->fDisabled = !fEnable;
644 v->background->fDisabled = !fEnable;
645 }
646
647
SetVideoOverlayText(VIDEO_OVERLAY * v,const ST::utf32_buffer & codepoints)648 void SetVideoOverlayText(VIDEO_OVERLAY* v, const ST::utf32_buffer& codepoints)
649 {
650 if (!v) return;
651 v->codepoints = codepoints;
652 }
653
654
SetVideoOverlayPos(VIDEO_OVERLAY * const v,const INT16 X,const INT16 Y)655 void SetVideoOverlayPos(VIDEO_OVERLAY* const v, const INT16 X, const INT16 Y)
656 {
657 if (!v) return;
658
659 // If position has changed and there is text, adjust
660 if (v->codepoints.size() > 0)
661 {
662 UINT16 uiStringLength = StringPixLength(v->codepoints, v->uiFontID);
663 UINT16 uiStringHeight = GetFontHeight(v->uiFontID);
664
665 // Delete old rect
666 // Remove background
667 FreeBackgroundRectPending(v->background);
668
669 v->background = RegisterBackgroundRect(BGND_FLAG_PERMANENT, X, Y, uiStringLength, uiStringHeight);
670 v->sX = X;
671 v->sY = Y;
672 }
673 }
674