69 static const byte *_colour_remap_ptr;
72 static const uint DIRTY_BLOCK_HEIGHT = 8;
73 static const uint DIRTY_BLOCK_WIDTH = 64;
75 static uint _dirty_bytes_per_line = 0;
76 static byte *_dirty_blocks = NULL;
77 extern uint _dirty_block_colour;
79 void GfxScroll(
int left,
int top,
int width,
int height,
int xo,
int yo)
83 if (xo == 0 && yo == 0)
return;
85 if (_cursor.
visible) UndrawMouseCursor();
91 blitter->
ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo);
116 const int otop = top;
117 const int oleft = left;
120 if (left > right || top > bottom)
return;
121 if (right < dpi->left || left >= dpi->left + dpi->width)
return;
122 if (bottom < dpi->top || top >= dpi->top + dpi->height)
return;
124 if ( (left -= dpi->left) < 0) left = 0;
125 right = right - dpi->left + 1;
126 if (right > dpi->width) right = dpi->width;
130 if ( (top -= dpi->top) < 0) top = 0;
131 bottom = bottom - dpi->top + 1;
132 if (bottom > dpi->height) bottom = dpi->height;
136 dst = blitter->
MoveTo(dpi->dst_ptr, left, top);
140 blitter->
DrawRect(dst, right, bottom, (uint8)colour);
148 byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
150 for (
int i = (bo ^= 1); i < right; i += 2) blitter->
SetPixel(dst, i, 0, (uint8)colour);
151 dst = blitter->
MoveTo(dst, 0, 1);
152 }
while (--bottom > 0);
172 static inline void GfxDoDrawLine(
void *video,
int x,
int y,
int x2,
int y2,
int screen_width,
int screen_height, uint8 colour,
int width,
int dash = 0)
181 Clamp(x, 0, screen_width), y,
182 Clamp(x2, 0, screen_width), y2,
183 screen_width, screen_height, colour, width, dash);
189 x,
Clamp(y, 0, screen_height),
190 x2,
Clamp(y2, 0, screen_height),
191 screen_width, screen_height, colour, width, dash);
195 int grade_y = y2 - y;
196 int grade_x = x2 - x;
200 while (INT_MAX /
abs(grade_y) <
max(
abs(x),
abs(screen_width - x))) {
208 int offset_0 = y - x * grade_y / grade_x;
209 int offset_width = y + (screen_width - x) * grade_y / grade_x;
210 if ((offset_0 > screen_height + width / 2 + margin && offset_width > screen_height + width / 2 + margin) ||
211 (offset_0 < -width / 2 - margin && offset_width < -width / 2 - margin)) {
221 blitter->
DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash);
243 if (x + width / 2 < 0 && x2 + width / 2 < 0 )
return false;
244 if (y + width / 2 < 0 && y2 + width / 2 < 0 )
return false;
245 if (x - width / 2 > dpi->width && x2 - width / 2 > dpi->width )
return false;
246 if (y - width / 2 > dpi->height && y2 - width / 2 > dpi->height)
return false;
250 void GfxDrawLine(
int x,
int y,
int x2,
int y2,
int colour,
int width,
int dash)
254 GfxDoDrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, colour, width, dash);
258 void GfxDrawLineUnscaled(
int x,
int y,
int x2,
int y2,
int colour)
282 void DrawBox(
int x,
int y,
int dx1,
int dy1,
int dx2,
int dy2,
int dx3,
int dy3)
299 static const byte colour =
PC_WHITE;
301 GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour);
302 GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour);
303 GfxDrawLineUnscaled(x, y, x + dx3, y + dy3, colour);
305 GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, colour);
306 GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, colour);
307 GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, colour);
308 GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, colour);
309 GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, colour);
310 GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, colour);
319 if (colour == TC_INVALID)
return;
323 bool no_shade = (colour &
TC_NO_SHADE) != 0 || colour == TC_BLACK;
349 if (line->CountRuns() == 0)
return 0;
351 int w = line->GetWidth();
352 int h = line->GetLeading();
366 int max_w = right - left + 1;
372 truncation &= max_w < w;
374 const Sprite *dot_sprite = NULL;
383 FontCache *fc = ((
const Font*)line->GetVisualRun(0)->GetFont())->fc;
386 dot_sprite = fc->
GetGlyph(dot_glyph);
389 min_x += 3 * dot_width;
390 offset_x = w - 3 * dot_width - max_w;
392 max_x -= 3 * dot_width;
406 switch (align & SA_HOR_MASK) {
409 right = left + w - 1;
415 right = left + w - 1;
419 left = right + 1 - w;
427 bool draw_shadow =
false;
428 for (
int run_index = 0; run_index < line->CountRuns(); run_index++) {
430 const Font *f = (
const Font*)run->GetFont();
437 int dpi_left = dpi->left;
438 int dpi_right = dpi->left + dpi->width - 1;
442 for (
int i = 0; i < run->GetGlyphCount(); i++) {
443 GlyphID glyph = run->GetGlyphs()[i];
446 if (glyph == 0xFFFF)
continue;
448 int begin_x = (int)run->GetPositions()[i * 2] + left - offset_x;
449 int end_x = (int)run->GetPositions()[i * 2 + 2] + left - offset_x - 1;
450 int top = (int)run->GetPositions()[i * 2 + 1] + y;
453 if (truncation && (begin_x < min_x || end_x > max_x))
continue;
457 if (begin_x + sprite->
x_offs > dpi_right || begin_x + sprite->
x_offs + sprite->
width < dpi_left)
continue;
459 if (draw_shadow && (glyph & SPRITE_GLYPH) == 0) {
470 for (
int i = 0; i < 3; i++, x += dot_width) {
484 return (align & SA_HOR_MASK) ==
SA_RIGHT ? left : right;
509 int extra = max_height / 2;
511 if (_cur_dpi->top + _cur_dpi->height + extra < top || _cur_dpi->top > top + max_height + extra ||
512 _cur_dpi->left + _cur_dpi->width + extra < left || _cur_dpi->left > right + extra) {
516 Layouter layout(str, INT32_MAX, colour, fontsize);
517 if (layout.
Length() == 0)
return 0;
541 GetString(buffer, str,
lastof(buffer));
542 return DrawString(left, right, top, buffer, colour, align, underline, fontsize);
553 Layouter layout(str, maxw, TC_FROMSTRING, fontsize);
566 GetString(buffer, str,
lastof(buffer));
579 GetString(buffer, str,
lastof(buffer));
626 int maxw = right - left + 1;
627 int maxh = bottom - top + 1;
631 if (maxh <= 0)
return top;
633 Layouter layout(str, maxw, colour, fontsize);
634 int total_height = layout.
GetBounds().height;
642 y =
RoundDivSU(bottom + top - total_height, 2);
646 y = bottom - total_height;
649 default: NOT_REACHED();
653 int first_line = bottom;
658 int line_height = line->GetLeading();
659 if (y >= top && y < bottom) {
660 last_line = y + line_height;
661 if (first_line > y) first_line = y;
668 return ((align & SA_VERT_MASK) ==
SA_BOTTOM) ? first_line : last_line;
689 GetString(buffer, str,
lastof(buffer));
690 return DrawStringMultiLine(left, right, top, bottom, buffer, colour, align, underline, fontsize);
705 Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
719 GetString(buffer, strid,
lastof(buffer));
733 Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
746 if (x < 0)
return NULL;
748 Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
776 if (offset != NULL) {
816 }
else if (pal != PAL_NONE) {
824 GfxMainBlitterViewport(GetSprite(real_sprite,
ST_NORMAL), x, y,
BM_NORMAL, sub, real_sprite);
843 }
else if (pal != PAL_NONE) {
851 GfxMainBlitter(GetSprite(real_sprite,
ST_NORMAL), x, y,
BM_NORMAL, sub, real_sprite, zoom);
866 template <
int ZOOM_BASE,
bool SCALED_XY>
890 int clip_left =
max(0, -sprite->
x_offs + sub->left * ZOOM_BASE );
891 int clip_top =
max(0, -sprite->
y_offs + sub->top * ZOOM_BASE );
892 int clip_right =
max(0, sprite->
width - (-sprite->
x_offs + (sub->right + 1) * ZOOM_BASE));
893 int clip_bottom =
max(0, sprite->
height - (-sprite->
y_offs + (sub->bottom + 1) * ZOOM_BASE));
895 if (clip_left + clip_right >= sprite->
width)
return;
896 if (clip_top + clip_bottom >= sprite->
height)
return;
914 bp.
dst = dpi->dst_ptr;
915 bp.
pitch = dpi->pitch;
916 bp.
remap = _colour_remap_ptr;
918 assert(sprite->
width > 0);
919 assert(sprite->
height > 0);
921 if (bp.
width <= 0)
return;
922 if (bp.
height <= 0)
return;
924 y -= SCALED_XY ?
ScaleByZoom(dpi->top, zoom) : dpi->top;
929 if (bp.
height <= 0)
return;
940 if (bp.
height <= 0)
return;
943 x -= SCALED_XY ?
ScaleByZoom(dpi->left, zoom) : dpi->left;
947 bp.
width -= -x_unscaled;
948 if (bp.
width <= 0)
return;
952 bp.
left = x_unscaled;
959 if (bp.
width <= 0)
return;
973 if (topleft <= clicked && clicked <= bottomright) {
974 uint offset = (((size_t)clicked - (
size_t)topleft) / (blitter->
GetScreenDepth() / 8)) % bp.
pitch;
975 if (offset < (uint)bp.
width) {
986 GfxBlitter<ZOOM_LVL_BASE, false>(sprite, x, y, mode, sub, sprite_id, _cur_dpi->zoom);
991 GfxBlitter<1, true>(sprite, x, y, mode, sub, sprite_id, zoom);
994 void DoPaletteAnimations();
996 void GfxInitPalettes()
998 memcpy(&_cur_palette, &
_palette,
sizeof(_cur_palette));
999 DoPaletteAnimations();
1002 #define EXTR(p, q) (((uint16)(palette_animation_counter * (p)) * (q)) >> 16)
1003 #define EXTR2(p, q) (((uint16)(~palette_animation_counter * (p)) * (q)) >> 16)
1005 void DoPaletteAnimations()
1008 static int palette_animation_counter = 0;
1009 palette_animation_counter += 8;
1015 const uint old_tc = palette_animation_counter;
1020 palette_animation_counter = 0;
1026 memcpy(old_val, palette_pos,
sizeof(old_val));
1032 *palette_pos++ = s[j];
1041 *palette_pos++ = s[j];
1048 byte i = (palette_animation_counter >> 1) & 0x7F;
1053 }
else if (i < 0x4A || i >= 0x75) {
1066 }
else if (i < 0x4A || i >= 0x75) {
1081 *palette_pos++ = s[j];
1090 *palette_pos++ = s[j];
1099 *palette_pos++ = s[j];
1105 palette_animation_counter = old_tc;
1125 uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114;
1127 return sq1000_brightness < 128 * 128 * 1000 ? TC_WHITE : TC_BLACK;
1137 for (uint i = 0; i != 224; i++) {
1168 for (
char c =
'0'; c <=
'9'; c++) {
1183 for (
char c =
'9'; c >=
'0'; c--) {
1188 if (c !=
'0') *front = c -
'0';
1193 void ScreenSizeChanged()
1195 _dirty_bytes_per_line =
CeilDiv(_screen.width, DIRTY_BLOCK_WIDTH);
1196 _dirty_blocks = ReallocT<byte>(_dirty_blocks, _dirty_bytes_per_line *
CeilDiv(_screen.height, DIRTY_BLOCK_HEIGHT));
1199 if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
1200 if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height;
1206 void UndrawMouseCursor()
1209 if (_screen.dst_ptr == NULL)
return;
1219 void DrawMouseCursor()
1227 if (_screen.dst_ptr == NULL)
return;
1240 if (!_cursor.
dirty)
return;
1241 UndrawMouseCursor();
1250 if (w > _screen.width - x) w = _screen.width - x;
1252 _cursor.draw_pos.x = x;
1256 y = _cursor.pos.y + _cursor.offs.y;
1261 if (h > _screen.height - y) h = _screen.height - y;
1263 _cursor.draw_pos.y = y;
1272 _cur_dpi = &_screen;
1278 _cursor.
dirty =
false;
1281 void RedrawScreenRect(
int left,
int top,
int right,
int bottom)
1283 assert(right <= _screen.width && bottom <= _screen.height);
1285 if (right > _cursor.draw_pos.x &&
1286 left < _cursor.draw_pos.x + _cursor.
draw_size.x &&
1287 bottom > _cursor.draw_pos.y &&
1288 top < _cursor.draw_pos.y + _cursor.
draw_size.y) {
1289 UndrawMouseCursor();
1293 #ifdef ENABLE_NETWORK
1309 byte *b = _dirty_blocks;
1310 const int w =
Align(_screen.width, DIRTY_BLOCK_WIDTH);
1311 const int h =
Align(_screen.height, DIRTY_BLOCK_HEIGHT);
1341 int right = x + DIRTY_BLOCK_WIDTH;
1349 p += _dirty_bytes_per_line;
1350 bottom += DIRTY_BLOCK_HEIGHT;
1351 }
while (bottom != h && *p != 0);
1354 h2 = (bottom - y) / DIRTY_BLOCK_HEIGHT;
1358 while (right != w) {
1363 if (!*p2)
goto no_more_coalesc;
1364 p2 += _dirty_bytes_per_line;
1369 right += DIRTY_BLOCK_WIDTH;
1375 p2 += _dirty_bytes_per_line;
1383 if (left < _invalid_rect.left ) left = _invalid_rect.left;
1384 if (top < _invalid_rect.top ) top = _invalid_rect.top;
1385 if (right > _invalid_rect.right ) right = _invalid_rect.right;
1386 if (bottom > _invalid_rect.bottom) bottom = _invalid_rect.bottom;
1388 if (left < right && top < bottom) {
1389 RedrawScreenRect(left, top, right, bottom);
1393 }
while (b++, (x += DIRTY_BLOCK_WIDTH) != w);
1394 }
while (b += -(
int)(w / DIRTY_BLOCK_WIDTH) + _dirty_bytes_per_line, (y += DIRTY_BLOCK_HEIGHT) != h);
1396 ++_dirty_block_colour;
1397 _invalid_rect.left = w;
1398 _invalid_rect.top = h;
1399 _invalid_rect.right = 0;
1400 _invalid_rect.bottom = 0;
1424 if (left < 0) left = 0;
1425 if (top < 0) top = 0;
1426 if (right > _screen.width) right = _screen.width;
1427 if (bottom > _screen.height) bottom = _screen.height;
1429 if (left >= right || top >= bottom)
return;
1431 if (left < _invalid_rect.left ) _invalid_rect.left = left;
1432 if (top < _invalid_rect.top ) _invalid_rect.top = top;
1433 if (right > _invalid_rect.right ) _invalid_rect.right = right;
1434 if (bottom > _invalid_rect.bottom) _invalid_rect.bottom = bottom;
1436 left /= DIRTY_BLOCK_WIDTH;
1437 top /= DIRTY_BLOCK_HEIGHT;
1439 b = _dirty_blocks + top * _dirty_bytes_per_line + left;
1441 width = ((right - 1) / DIRTY_BLOCK_WIDTH) - left + 1;
1442 height = ((bottom - 1) / DIRTY_BLOCK_HEIGHT) - top + 1;
1444 assert(width > 0 && height > 0);
1449 do b[--i] = 0xFF;
while (i != 0);
1451 b += _dirty_bytes_per_line;
1452 }
while (--height != 0);
1490 if ((left -= o->left) < 0) {
1492 if (width <= 0)
return false;
1499 if (width > o->width - left) {
1500 width = o->width - left;
1501 if (width <= 0)
return false;
1505 if ((top -= o->top) < 0) {
1507 if (height <= 0)
return false;
1514 n->dst_ptr = blitter->
MoveTo(o->dst_ptr, left, top);
1515 n->pitch = o->pitch;
1517 if (height > o->height - top) {
1518 height = o->height - top;
1519 if (height <= 0)
return false;
1551 if (cv->
sprite == cursor)
return;
1560 static void SwitchAnimatedCursor()
1575 SwitchAnimatedCursor();
1602 _cursor.pal = PAL_NONE;
1603 SwitchAnimatedCursor();
1626 if (x == this->pos.x && y == this->pos.y) {
1628 this->queued_warp =
false;
1631 this->
delta.x = x - (this->queued_warp ? this->last_position.x : this->pos.x);
1632 this->
delta.y = y - (this->queued_warp ? this->last_position.y : this->pos.y);
1634 this->last_position.x = x;
1635 this->last_position.y = y;
1637 bool need_warp =
false;
1639 if (this->
delta.x != 0 || this->delta.y != 0) {
1644 this->queued_warp = queued_warp;
1647 }
else if (this->pos.x != x || this->pos.y != y) {
1648 this->queued_warp =
false;
1656 bool ChangeResInGame(
int width,
int height)
1661 bool ToggleFullScreen(
bool fs)
1665 DEBUG(driver, 0,
"Could not find a suitable fullscreen resolution");
1672 int x = pa->width - pb->width;
1673 if (x != 0)
return x;
1674 return pa->height - pb->height;
1677 void SortResolutions(
int count)