70 static const byte *_colour_remap_ptr;
 
   73 static const uint DIRTY_BLOCK_HEIGHT   = 8;
 
   74 static const uint DIRTY_BLOCK_WIDTH    = 64;
 
   76 static uint _dirty_bytes_per_line = 0;
 
   77 static byte *_dirty_blocks = NULL;
 
   78 extern uint _dirty_block_colour;
 
   80 void GfxScroll(
int left, 
int top, 
int width, 
int height, 
int xo, 
int yo)
 
   84   if (xo == 0 && yo == 0) 
return;
 
   86   if (_cursor.
visible) UndrawMouseCursor();
 
   92   blitter->
ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo);
 
  117   const int otop = top;
 
  118   const int oleft = left;
 
  121   if (left > right || top > bottom) 
return;
 
  122   if (right < dpi->left || left >= dpi->left + dpi->width) 
return;
 
  123   if (bottom < dpi->top || top >= dpi->top + dpi->height) 
return;
 
  125   if ( (left -= dpi->left) < 0) left = 0;
 
  126   right = right - dpi->left + 1;
 
  127   if (right > dpi->width) right = dpi->width;
 
  131   if ( (top -= dpi->top) < 0) top = 0;
 
  132   bottom = bottom - dpi->top + 1;
 
  133   if (bottom > dpi->height) bottom = dpi->height;
 
  137   dst = blitter->
MoveTo(dpi->dst_ptr, left, top);
 
  141       blitter->
DrawRect(dst, right, bottom, (uint8)colour);
 
  149       byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
 
  151         for (
int i = (bo ^= 1); i < right; i += 2) blitter->
SetPixel(dst, i, 0, (uint8)colour);
 
  152         dst = blitter->
MoveTo(dst, 0, 1);
 
  153       } 
while (--bottom > 0);
 
  173 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)
 
  179   if (y2 == y || x2 == x) {
 
  181     blitter->
DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash);
 
  185   int grade_y = y2 - y;
 
  186   int grade_x = x2 - x;
 
  189   int extra = (int)
CeilDiv(3 * width, 4); 
 
  190   Rect clip = { -extra, -extra, screen_width - 1 + extra, screen_height - 1 + extra };
 
  194   while (INT_MAX / 
abs(grade_y) < 
max(
abs(clip.left - x), 
abs(clip.right - x))) {
 
  204   int left_isec_y = y + (clip.left - x) * grade_y / grade_x;
 
  205   int right_isec_y = y + (clip.right - x) * grade_y / grade_x;
 
  206   if ((left_isec_y > clip.bottom + margin && right_isec_y > clip.bottom + margin) ||
 
  207       (left_isec_y < clip.top - margin && right_isec_y < clip.top - margin)) {
 
  217   blitter->
DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash);
 
  239   if (x + width / 2 < 0           && x2 + width / 2 < 0          ) 
return false;
 
  240   if (y + width / 2 < 0           && y2 + width / 2 < 0          ) 
return false;
 
  241   if (x - width / 2 > dpi->width  && x2 - width / 2 > dpi->width ) 
return false;
 
  242   if (y - width / 2 > dpi->height && y2 - width / 2 > dpi->height) 
return false;
 
  246 void GfxDrawLine(
int x, 
int y, 
int x2, 
int y2, 
int colour, 
int width, 
int dash)
 
  250     GfxDoDrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, colour, width, dash);
 
  254 void GfxDrawLineUnscaled(
int x, 
int y, 
int x2, 
int y2, 
int colour)
 
  278 void DrawBox(
int x, 
int y, 
int dx1, 
int dy1, 
int dx2, 
int dy2, 
int dx3, 
int dy3)
 
  295   static const byte colour = 
PC_WHITE;
 
  297   GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour);
 
  298   GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour);
 
  299   GfxDrawLineUnscaled(x, y, x + dx3, y + dy3, colour);
 
  301   GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, colour);
 
  302   GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, colour);
 
  303   GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, colour);
 
  304   GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, colour);
 
  305   GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, colour);
 
  306   GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, colour);
 
  315   if (colour == TC_INVALID) 
return;
 
  319   bool no_shade   = (colour & 
TC_NO_SHADE) != 0 || colour == TC_BLACK;
 
  345   if (line->CountRuns() == 0) 
return 0;
 
  347   int w = line->GetWidth();
 
  348   int h = line->GetLeading();
 
  362   int max_w = right - left + 1; 
 
  368   truncation &= max_w < w;         
 
  370   const Sprite *dot_sprite = NULL; 
 
  379     FontCache *fc = ((
const Font*)line->GetVisualRun(0)->GetFont())->fc;
 
  382     dot_sprite = fc->
GetGlyph(dot_glyph);
 
  385       min_x += 3 * dot_width;
 
  386       offset_x = w - 3 * dot_width - max_w;
 
  388       max_x -= 3 * dot_width;
 
  402   switch (align & SA_HOR_MASK) {
 
  405       right = left + w - 1;
 
  411       right = left + w - 1;
 
  415       left = right + 1 - w;
 
  423   bool draw_shadow = 
false;
 
  424   for (
int run_index = 0; run_index < line->CountRuns(); run_index++) {
 
  426     const Font *f = (
const Font*)run->GetFont();
 
  433     int dpi_left  = dpi->left;
 
  434     int dpi_right = dpi->left + dpi->width - 1;
 
  438     for (
int i = 0; i < run->GetGlyphCount(); i++) {
 
  439       GlyphID glyph = run->GetGlyphs()[i];
 
  442       if (glyph == 0xFFFF) 
continue;
 
  444       int begin_x = (int)run->GetPositions()[i * 2]     + left - offset_x;
 
  445       int end_x   = (int)run->GetPositions()[i * 2 + 2] + left - offset_x  - 1;
 
  446       int top     = (int)run->GetPositions()[i * 2 + 1] + y;
 
  449       if (truncation && (begin_x < min_x || end_x > max_x)) 
continue;
 
  453       if (begin_x + sprite->
x_offs > dpi_right || begin_x + sprite->
x_offs + sprite->
width  < dpi_left) 
continue;
 
  455       if (draw_shadow && (glyph & SPRITE_GLYPH) == 0) {
 
  466     for (
int i = 0; i < 3; i++, x += dot_width) {
 
  480   return (align & SA_HOR_MASK) == 
SA_RIGHT ? left : right;
 
  505   int extra = max_height / 2;
 
  507   if (_cur_dpi->top + _cur_dpi->height + extra < top || _cur_dpi->top > top + max_height + extra ||
 
  508       _cur_dpi->left + _cur_dpi->width + extra < left || _cur_dpi->left > right + extra) {
 
  512   Layouter layout(str, INT32_MAX, colour, fontsize);
 
  513   if (layout.
Length() == 0) 
return 0;
 
  537   GetString(buffer, str, 
lastof(buffer));
 
  538   return DrawString(left, right, top, buffer, colour, align, underline, fontsize);
 
  549   Layouter layout(str, maxw, TC_FROMSTRING, fontsize);
 
  562   GetString(buffer, str, 
lastof(buffer));
 
  575   GetString(buffer, str, 
lastof(buffer));
 
  622   int maxw = right - left + 1;
 
  623   int maxh = bottom - top + 1;
 
  627   if (maxh <= 0) 
return top;
 
  629   Layouter layout(str, maxw, colour, fontsize);
 
  630   int total_height = layout.
GetBounds().height;
 
  638       y = 
RoundDivSU(bottom + top - total_height, 2);
 
  642       y = bottom - total_height;
 
  645     default: NOT_REACHED();
 
  649   int first_line = bottom;
 
  654     int line_height = line->GetLeading();
 
  655     if (y >= top && y < bottom) {
 
  656       last_line = y + line_height;
 
  657       if (first_line > y) first_line = y;
 
  664   return ((align & SA_VERT_MASK) == 
SA_BOTTOM) ? first_line : last_line;
 
  685   GetString(buffer, str, 
lastof(buffer));
 
  686   return DrawStringMultiLine(left, right, top, bottom, buffer, colour, align, underline, fontsize);
 
  701   Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
 
  715   GetString(buffer, strid, 
lastof(buffer));
 
  729   Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
 
  742   if (x < 0) 
return NULL;
 
  744   Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
 
  772   if (offset != NULL) {
 
  812   } 
else if (pal != PAL_NONE) {
 
  820     GfxMainBlitterViewport(GetSprite(real_sprite, 
ST_NORMAL), x, y, 
BM_NORMAL, sub, real_sprite);
 
  839   } 
else if (pal != PAL_NONE) {
 
  847     GfxMainBlitter(GetSprite(real_sprite, 
ST_NORMAL), x, y, 
BM_NORMAL, sub, real_sprite, zoom);
 
  862 template <
int ZOOM_BASE, 
bool SCALED_XY>
 
  886     int clip_left   = 
max(0,                   -sprite->
x_offs +  sub->left        * ZOOM_BASE );
 
  887     int clip_top    = 
max(0,                   -sprite->
y_offs +  sub->top         * ZOOM_BASE );
 
  888     int clip_right  = 
max(0, sprite->
width  - (-sprite->
x_offs + (sub->right + 1)  * ZOOM_BASE));
 
  889     int clip_bottom = 
max(0, sprite->
height - (-sprite->
y_offs + (sub->bottom + 1) * ZOOM_BASE));
 
  891     if (clip_left + clip_right >= sprite->
width) 
return;
 
  892     if (clip_top + clip_bottom >= sprite->
height) 
return;
 
  910   bp.
dst = dpi->dst_ptr;
 
  911   bp.
pitch = dpi->pitch;
 
  912   bp.
remap = _colour_remap_ptr;
 
  914   assert(sprite->
width > 0);
 
  915   assert(sprite->
height > 0);
 
  917   if (bp.
width <= 0) 
return;
 
  918   if (bp.
height <= 0) 
return;
 
  920   y -= SCALED_XY ? 
ScaleByZoom(dpi->top, zoom) : dpi->top;
 
  925     if (bp.
height <= 0) 
return;
 
  936     if (bp.
height <= 0) 
return;
 
  939   x -= SCALED_XY ? 
ScaleByZoom(dpi->left, zoom) : dpi->left;
 
  943     bp.
width -= -x_unscaled;
 
  944     if (bp.
width <= 0) 
return;
 
  948     bp.
left = x_unscaled;
 
  955     if (bp.
width <= 0) 
return;
 
  969     if (topleft <= clicked && clicked <= bottomright) {
 
  970       uint offset = (((size_t)clicked - (
size_t)topleft) / (blitter->
GetScreenDepth() / 8)) % bp.
pitch;
 
  971       if (offset < (uint)bp.
width) {
 
  982   GfxBlitter<ZOOM_LVL_BASE, false>(sprite, x, y, mode, sub, sprite_id, _cur_dpi->zoom);
 
  987   GfxBlitter<1, true>(sprite, x, y, mode, sub, sprite_id, zoom);
 
  990 void DoPaletteAnimations();
 
  992 void GfxInitPalettes()
 
  994   memcpy(&_cur_palette, &
_palette, 
sizeof(_cur_palette));
 
  995   DoPaletteAnimations();
 
  998 #define EXTR(p, q) (((uint16)(palette_animation_counter * (p)) * (q)) >> 16) 
  999 #define EXTR2(p, q) (((uint16)(~palette_animation_counter * (p)) * (q)) >> 16) 
 1001 void DoPaletteAnimations()
 
 1004   static int palette_animation_counter = 0;
 
 1005   palette_animation_counter += 8;
 
 1011   const uint old_tc = palette_animation_counter;
 
 1016     palette_animation_counter = 0;
 
 1022   memcpy(old_val, palette_pos, 
sizeof(old_val));
 
 1028     *palette_pos++ = s[j];
 
 1037     *palette_pos++ = s[j];
 
 1044     byte i = (palette_animation_counter >> 1) & 0x7F;
 
 1049     } 
else if (i < 0x4A || i >= 0x75) {
 
 1062     } 
else if (i < 0x4A || i >= 0x75) {
 
 1077     *palette_pos++ = s[j];
 
 1086     *palette_pos++ = s[j];
 
 1095     *palette_pos++ = s[j];
 
 1101     palette_animation_counter = old_tc;
 
 1121   uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114;
 
 1123   return sq1000_brightness < 128 * 128 * 1000 ? TC_WHITE : TC_BLACK;
 
 1133     for (uint i = 0; i != 224; i++) {
 
 1164   for (
char c = 
'0'; c <= 
'9'; c++) {
 
 1179   for (
char c = 
'9'; c >= 
'0'; c--) {
 
 1184       if (c != 
'0') *front = c - 
'0';
 
 1189 void ScreenSizeChanged()
 
 1191   _dirty_bytes_per_line = 
CeilDiv(_screen.width, DIRTY_BLOCK_WIDTH);
 
 1192   _dirty_blocks = ReallocT<byte>(_dirty_blocks, _dirty_bytes_per_line * 
CeilDiv(_screen.height, DIRTY_BLOCK_HEIGHT));
 
 1195   if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
 
 1196   if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height;
 
 1202 void UndrawMouseCursor()
 
 1205   if (_screen.dst_ptr == NULL) 
return;
 
 1215 void DrawMouseCursor()
 
 1223   if (_screen.dst_ptr == NULL) 
return;
 
 1232     if (!_cursor.
dirty) 
return;
 
 1233     UndrawMouseCursor();
 
 1237   int left = _cursor.
pos.x + _cursor.total_offs.x;
 
 1243   if (left + width > _screen.width) {
 
 1244     width = _screen.width - left;
 
 1246   if (width <= 0) 
return;
 
 1248   int top = _cursor.
pos.y + _cursor.total_offs.y;
 
 1254   if (top + height > _screen.height) {
 
 1255     height = _screen.height - top;
 
 1257   if (height <= 0) 
return;
 
 1259   _cursor.draw_pos.x = left;
 
 1260   _cursor.draw_pos.y = top;
 
 1270   _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;
 
 1546       _cursor.total_offs = offs;
 
 1549       int right  = 
max(_cursor.total_offs.x + _cursor.
total_size.x, offs.x + size.x);
 
 1550       int bottom = 
max(_cursor.total_offs.y + _cursor.
total_size.y, offs.y + size.y);
 
 1551       if (offs.x < _cursor.total_offs.x) _cursor.total_offs.x = offs.x;
 
 1552       if (offs.y < _cursor.total_offs.y) _cursor.total_offs.y = offs.y;
 
 1553       _cursor.
total_size.x = right  - _cursor.total_offs.x;
 
 1554       _cursor.
total_size.y = bottom - _cursor.total_offs.y;
 
 1558   _cursor.
dirty = 
true;
 
 1579 static void SwitchAnimatedCursor()
 
 1594     SwitchAnimatedCursor();
 
 1635   SwitchAnimatedCursor();
 
 1658   if (x == this->
pos.x && y == this->pos.y) {
 
 1660     this->queued_warp = 
false;
 
 1663   this->
delta.x = x - (this->queued_warp ? this->last_position.x : this->
pos.x);
 
 1664   this->
delta.y = y - (this->queued_warp ? this->last_position.y : this->
pos.y);
 
 1666   this->last_position.x = x;
 
 1667   this->last_position.y = y;
 
 1669   bool need_warp = 
false;
 
 1671     if (this->
delta.x != 0 || this->delta.y != 0) {
 
 1676       this->queued_warp = queued_warp;
 
 1679   } 
else if (this->
pos.x != x || this->pos.y != y) {
 
 1680     this->queued_warp = 
false; 
 
 1688 bool ChangeResInGame(
int width, 
int height)
 
 1693 bool ToggleFullScreen(
bool fs)
 
 1697     DEBUG(driver, 0, 
"Could not find a suitable fullscreen resolution");
 
 1704   int x = pa->width - pb->width;
 
 1705   if (x != 0) 
return x;
 
 1706   return pa->height - pb->height;
 
 1709 void SortResolutions(
int count)