00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "gfx_func.h"
00008 #include "spritecache.h"
00009 #include "variables.h"
00010 #include "fontcache.h"
00011 #include "genworld.h"
00012 #include "debug.h"
00013 #include "zoom_func.h"
00014 #include "texteff.hpp"
00015 #include "blitter/factory.hpp"
00016 #include "video/video_driver.hpp"
00017 #include "strings_func.h"
00018 #include "core/math_func.hpp"
00019 #include "settings_type.h"
00020 #include "core/alloc_func.hpp"
00021 #include "core/sort_func.hpp"
00022 #include "landscape_type.h"
00023 #include "network/network_func.h"
00024
00025 #include "table/palettes.h"
00026 #include "table/sprites.h"
00027 #include "table/control_codes.h"
00028
00029 byte _dirkeys;
00030 bool _fullscreen;
00031 CursorVars _cursor;
00032 bool _ctrl_pressed;
00033 bool _shift_pressed;
00034 byte _fast_forward;
00035 bool _left_button_down;
00036 bool _left_button_clicked;
00037 bool _right_button_down;
00038 bool _right_button_clicked;
00039 DrawPixelInfo _screen;
00040 bool _screen_disable_anim = false;
00041 bool _exit_game;
00042 bool _networking;
00043 byte _game_mode;
00044 int8 _pause_game;
00045 int _pal_first_dirty;
00046 int _pal_count_dirty;
00047
00048 Colour _cur_palette[256];
00049 byte _stringwidth_table[FS_END][224];
00050 DrawPixelInfo *_cur_dpi;
00051 byte _colour_gradient[COLOUR_END][8];
00052
00053 static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL);
00054 static int ReallyDoDrawString(const char *string, int x, int y, uint16 real_colour, bool parse_string_also_when_clipped = false);
00055
00056 FontSize _cur_fontsize;
00057 static FontSize _last_fontsize;
00058 static uint8 _cursor_backup[64 * 64 * 4];
00059
00067 static Rect _invalid_rect;
00068 static const byte *_color_remap_ptr;
00069 static byte _string_colorremap[3];
00070
00071 enum {
00072 DIRTY_BLOCK_HEIGHT = 8,
00073 DIRTY_BLOCK_WIDTH = 64,
00074 };
00075 static uint _dirty_bytes_per_line = 0;
00076 static byte *_dirty_blocks = NULL;
00077
00078 void GfxScroll(int left, int top, int width, int height, int xo, int yo)
00079 {
00080 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00081
00082 if (xo == 0 && yo == 0) return;
00083
00084 if (_cursor.visible) UndrawMouseCursor();
00085
00086 #ifdef ENABLE_NETWORK
00087 NetworkUndrawChatMessage();
00088 #endif
00089
00090 blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo);
00091
00092 _video_driver->MakeDirty(left, top, width, height);
00093 }
00094
00095
00110 void GfxFillRect(int left, int top, int right, int bottom, int color, FillRectMode mode)
00111 {
00112 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00113 const DrawPixelInfo *dpi = _cur_dpi;
00114 void *dst;
00115 const int otop = top;
00116 const int oleft = left;
00117
00118 if (dpi->zoom != ZOOM_LVL_NORMAL) return;
00119 if (left > right || top > bottom) return;
00120 if (right < dpi->left || left >= dpi->left + dpi->width) return;
00121 if (bottom < dpi->top || top >= dpi->top + dpi->height) return;
00122
00123 if ( (left -= dpi->left) < 0) left = 0;
00124 right = right - dpi->left + 1;
00125 if (right > dpi->width) right = dpi->width;
00126 right -= left;
00127 assert(right > 0);
00128
00129 if ( (top -= dpi->top) < 0) top = 0;
00130 bottom = bottom - dpi->top + 1;
00131 if (bottom > dpi->height) bottom = dpi->height;
00132 bottom -= top;
00133 assert(bottom > 0);
00134
00135 dst = blitter->MoveTo(dpi->dst_ptr, left, top);
00136
00137 switch (mode) {
00138 default:
00139 blitter->DrawRect(dst, right, bottom, (uint8)color);
00140 break;
00141
00142 case FILLRECT_RECOLOR:
00143 blitter->DrawColorMappingRect(dst, right, bottom, GB(color, 0, PALETTE_WIDTH));
00144 break;
00145
00146 case FILLRECT_CHECKER: {
00147 byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
00148 do {
00149 for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)color);
00150 dst = blitter->MoveTo(dst, 0, 1);
00151 } while (--bottom > 0);
00152 break;
00153 }
00154 }
00155 }
00156
00157 void GfxDrawLine(int x, int y, int x2, int y2, int color)
00158 {
00159 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00160 DrawPixelInfo *dpi = _cur_dpi;
00161
00162 x -= dpi->left;
00163 x2 -= dpi->left;
00164 y -= dpi->top;
00165 y2 -= dpi->top;
00166
00167
00168 if (x < 0 && x2 < 0) return;
00169 if (y < 0 && y2 < 0) return;
00170 if (x > dpi->width && x2 > dpi->width) return;
00171 if (y > dpi->height && y2 > dpi->height) return;
00172
00173 blitter->DrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, color);
00174 }
00175
00176 void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int color)
00177 {
00178 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00179 DrawPixelInfo *dpi = _cur_dpi;
00180
00181 x -= dpi->left;
00182 x2 -= dpi->left;
00183 y -= dpi->top;
00184 y2 -= dpi->top;
00185
00186
00187 if (x < 0 && x2 < 0) return;
00188 if (y < 0 && y2 < 0) return;
00189 if (x > dpi->width && x2 > dpi->width) return;
00190 if (y > dpi->height && y2 > dpi->height) return;
00191
00192 blitter->DrawLine(dpi->dst_ptr, UnScaleByZoom(x, dpi->zoom), UnScaleByZoom(y, dpi->zoom),
00193 UnScaleByZoom(x2, dpi->zoom), UnScaleByZoom(y2, dpi->zoom),
00194 UnScaleByZoom(dpi->width, dpi->zoom), UnScaleByZoom(dpi->height, dpi->zoom), color);
00195 }
00196
00210 void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
00211 {
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 static const byte color = 255;
00228
00229 GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, color);
00230 GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, color);
00231 GfxDrawLineUnscaled(x, y, x + dx3, y + dy3, color);
00232
00233 GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, color);
00234 GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, color);
00235 GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, color);
00236 GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, color);
00237 GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, color);
00238 GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, color);
00239 }
00240
00241
00242 #if !defined(WITH_ICU)
00243 static void HandleBiDiAndArabicShapes(char *text, const char *lastof) {}
00244 #else
00245 #include "unicode/ubidi.h"
00246 #include "unicode/ushape.h"
00247
00276 static void HandleBiDiAndArabicShapes(char *buffer, const char *lastof)
00277 {
00278 UChar input_output[DRAW_STRING_BUFFER];
00279 UChar intermediate[DRAW_STRING_BUFFER];
00280
00281 char *t = buffer;
00282 size_t length = 0;
00283 while (*t != '\0' && length < lengthof(input_output)) {
00284 WChar tmp;
00285 t += Utf8Decode(&tmp, t);
00286 input_output[length++] = tmp;
00287 }
00288 input_output[length] = 0;
00289
00290 UErrorCode err = U_ZERO_ERROR;
00291 UBiDi *para = ubidi_openSized((int32_t)length, 0, &err);
00292 if (para == NULL) return;
00293
00294 ubidi_setPara(para, input_output, (int32_t)length, _dynlang.text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, NULL, &err);
00295 ubidi_writeReordered(para, intermediate, (int32_t)length, 0, &err);
00296 length = u_shapeArabic(intermediate, (int32_t)length, input_output, lengthof(input_output), U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_LETTERS_SHAPE, &err);
00297 ubidi_close(para);
00298
00299 if (U_FAILURE(err)) return;
00300
00301 t = buffer;
00302 for (size_t i = 0; i < length && t < (lastof - 4); i++) {
00303 t += Utf8Encode(t, input_output[i]);
00304 }
00305 *t = '\0';
00306 }
00307 #endif
00308
00309
00315 static int TruncateString(char *str, int maxw)
00316 {
00317 int w = 0;
00318 FontSize size = _cur_fontsize;
00319 int ddd, ddd_w;
00320
00321 WChar c;
00322 char *ddd_pos;
00323
00324 ddd_w = ddd = GetCharacterWidth(size, '.') * 3;
00325
00326 for (ddd_pos = str; (c = Utf8Consume((const char **)&str)) != '\0'; ) {
00327 if (IsPrintable(c)) {
00328 w += GetCharacterWidth(size, c);
00329
00330 if (w >= maxw) {
00331
00332
00333 for (int i = 0; *ddd_pos != '\0' && i < 3; i++, ddd_pos++) *ddd_pos = '.';
00334 *ddd_pos = '\0';
00335 return ddd_w;
00336 }
00337 } else {
00338 if (c == SCC_SETX) {
00339 w = *str;
00340 str++;
00341 } else if (c == SCC_SETXY) {
00342 w = *str;
00343 str += 2;
00344 } else if (c == SCC_TINYFONT) {
00345 size = FS_SMALL;
00346 ddd = GetCharacterWidth(size, '.') * 3;
00347 } else if (c == SCC_BIGFONT) {
00348 size = FS_LARGE;
00349 ddd = GetCharacterWidth(size, '.') * 3;
00350 }
00351 }
00352
00353
00354 if (w + ddd < maxw) {
00355 ddd_w = w + ddd;
00356 ddd_pos = str;
00357 }
00358 }
00359
00360 return w;
00361 }
00362
00373 static inline int TruncateStringID(StringID src, char *dest, int maxw, const char* last)
00374 {
00375 GetString(dest, src, last);
00376 return TruncateString(dest, maxw);
00377 }
00378
00389 int DrawString(int x, int y, StringID str, uint16 color)
00390 {
00391 char buffer[DRAW_STRING_BUFFER];
00392
00393 GetString(buffer, str, lastof(buffer));
00394 HandleBiDiAndArabicShapes(buffer, lastof(buffer));
00395 return ReallyDoDrawString(buffer, x, y, color);
00396 }
00397
00409 int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw)
00410 {
00411 char buffer[DRAW_STRING_BUFFER];
00412 TruncateStringID(str, buffer, maxw, lastof(buffer));
00413 HandleBiDiAndArabicShapes(buffer, lastof(buffer));
00414 return ReallyDoDrawString(buffer, x, y, color);
00415 }
00416
00427 int DrawStringRightAligned(int x, int y, StringID str, uint16 color)
00428 {
00429 char buffer[DRAW_STRING_BUFFER];
00430 int w;
00431
00432 GetString(buffer, str, lastof(buffer));
00433 HandleBiDiAndArabicShapes(buffer, lastof(buffer));
00434
00435 w = GetStringBoundingBox(buffer).width;
00436 ReallyDoDrawString(buffer, x - w, y, color);
00437
00438 return w;
00439 }
00440
00450 void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, uint maxw)
00451 {
00452 char buffer[DRAW_STRING_BUFFER];
00453
00454 TruncateStringID(str, buffer, maxw, lastof(buffer));
00455 HandleBiDiAndArabicShapes(buffer, lastof(buffer));
00456 ReallyDoDrawString(buffer, x - GetStringBoundingBox(buffer).width, y, color);
00457 }
00458
00467 void DrawStringRightAlignedUnderline(int x, int y, StringID str, uint16 color)
00468 {
00469 int w = DrawStringRightAligned(x, y, str, color);
00470 GfxFillRect(x - w, y + 10, x, y + 10, _string_colorremap[1]);
00471 }
00472
00483 int DrawStringCentered(int x, int y, StringID str, uint16 color)
00484 {
00485 char buffer[DRAW_STRING_BUFFER];
00486 int w;
00487
00488 GetString(buffer, str, lastof(buffer));
00489 HandleBiDiAndArabicShapes(buffer, lastof(buffer));
00490
00491 w = GetStringBoundingBox(buffer).width;
00492 ReallyDoDrawString(buffer, x - w / 2, y, color);
00493
00494 return w;
00495 }
00496
00508 int DrawStringCenteredTruncated(int xl, int xr, int y, StringID str, uint16 color)
00509 {
00510 char buffer[DRAW_STRING_BUFFER];
00511 TruncateStringID(str, buffer, xr - xl, lastof(buffer));
00512 HandleBiDiAndArabicShapes(buffer, lastof(buffer));
00513
00514 int w = GetStringBoundingBox(buffer).width;
00515 return ReallyDoDrawString(buffer, (xl + xr - w) / 2, y, color);
00516 }
00517
00528 int DoDrawStringCentered(int x, int y, const char *str, uint16 color)
00529 {
00530 char buffer[DRAW_STRING_BUFFER];
00531 strecpy(buffer, str, lastof(buffer));
00532 HandleBiDiAndArabicShapes(buffer, lastof(buffer));
00533
00534 int w = GetStringBoundingBox(buffer).width;
00535 ReallyDoDrawString(buffer, x - w / 2, y, color);
00536 return w;
00537 }
00538
00547 void DrawStringCenterUnderline(int x, int y, StringID str, uint16 color)
00548 {
00549 int w = DrawStringCentered(x, y, str, color);
00550 GfxFillRect(x - (w >> 1), y + 10, x - (w >> 1) + w, y + 10, _string_colorremap[1]);
00551 }
00552
00562 void DrawStringCenterUnderlineTruncated(int xl, int xr, int y, StringID str, uint16 color)
00563 {
00564 int w = DrawStringCenteredTruncated(xl, xr, y, str, color);
00565 GfxFillRect((xl + xr - w) / 2, y + 10, (xl + xr + w) / 2, y + 10, _string_colorremap[1]);
00566 }
00567
00586 uint32 FormatStringLinebreaks(char *str, int maxw)
00587 {
00588 FontSize size = _cur_fontsize;
00589 int num = 0;
00590
00591 assert(maxw > 0);
00592
00593 for (;;) {
00594 char *last_space = NULL;
00595 int w = 0;
00596
00597 for (;;) {
00598 WChar c = Utf8Consume((const char **)&str);
00599
00600 if (IsWhitespace(c)) last_space = str;
00601
00602 if (IsPrintable(c)) {
00603 w += GetCharacterWidth(size, c);
00604
00605
00606
00607
00608
00609 if (w > maxw) {
00610 if (last_space == NULL) {
00611 *Utf8PrevChar(str) = '\0';
00612 return num + (size << 16);
00613 }
00614 str = last_space;
00615 break;
00616 }
00617 } else {
00618 switch (c) {
00619 case '\0': return num + (size << 16); break;
00620 case SCC_SETX: str++; break;
00621 case SCC_SETXY: str += 2; break;
00622 case SCC_TINYFONT: size = FS_SMALL; break;
00623 case SCC_BIGFONT: size = FS_LARGE; break;
00624 case '\n': goto end_of_inner_loop;
00625 }
00626 }
00627 }
00628 end_of_inner_loop:
00629
00630
00631
00632 num++;
00633 char *s = Utf8PrevChar(str);
00634 *s++ = '\0';
00635
00636
00637 if (str - s >= 1) {
00638 for (; str[-1] != '\0';) *s++ = *str++;
00639 }
00640 }
00641 }
00642
00643
00650 static int GetMultilineStringHeight(const char *src, int num)
00651 {
00652 int maxy = 0;
00653 int y = 0;
00654 int fh = GetCharacterHeight(_cur_fontsize);
00655
00656 for (;;) {
00657 WChar c = Utf8Consume(&src);
00658
00659 switch (c) {
00660 case 0: y += fh; if (--num < 0) return maxy; break;
00661 case '\n': y += fh; break;
00662 case SCC_SETX: src++; break;
00663 case SCC_SETXY: src++; y = (int)*src++; break;
00664 case SCC_TINYFONT: fh = GetCharacterHeight(FS_SMALL); break;
00665 case SCC_BIGFONT: fh = GetCharacterHeight(FS_LARGE); break;
00666 default: maxy = max<int>(maxy, y + fh); break;
00667 }
00668 }
00669 }
00670
00671
00677 int GetStringHeight(StringID str, int maxw)
00678 {
00679 char buffer[DRAW_STRING_BUFFER];
00680
00681 GetString(buffer, str, lastof(buffer));
00682
00683 uint32 tmp = FormatStringLinebreaks(buffer, maxw);
00684
00685 return GetMultilineStringHeight(buffer, GB(tmp, 0, 16));
00686 }
00687
00688
00694 void DrawStringMultiCenter(int x, int y, StringID str, int maxw)
00695 {
00696 char buffer[DRAW_STRING_BUFFER];
00697 uint32 tmp;
00698 int num, mt;
00699 const char *src;
00700 WChar c;
00701
00702 GetString(buffer, str, lastof(buffer));
00703
00704 tmp = FormatStringLinebreaks(buffer, maxw);
00705 num = GB(tmp, 0, 16);
00706
00707 mt = GetCharacterHeight((FontSize)GB(tmp, 16, 16));
00708
00709 y -= (mt >> 1) * num;
00710
00711 src = buffer;
00712
00713 for (;;) {
00714 char buf2[DRAW_STRING_BUFFER];
00715 strecpy(buf2, src, lastof(buf2));
00716 HandleBiDiAndArabicShapes(buf2, lastof(buf2));
00717 int w = GetStringBoundingBox(buf2).width;
00718 ReallyDoDrawString(buf2, x - (w >> 1), y, 0xFE, true);
00719 _cur_fontsize = _last_fontsize;
00720
00721 for (;;) {
00722 c = Utf8Consume(&src);
00723 if (c == 0) {
00724 y += mt;
00725 if (--num < 0) {
00726 _cur_fontsize = FS_NORMAL;
00727 return;
00728 }
00729 break;
00730 } else if (c == SCC_SETX) {
00731 src++;
00732 } else if (c == SCC_SETXY) {
00733 src += 2;
00734 }
00735 }
00736 }
00737 }
00738
00739
00740 uint DrawStringMultiLine(int x, int y, StringID str, int maxw, int maxh)
00741 {
00742 char buffer[DRAW_STRING_BUFFER];
00743 uint32 tmp;
00744 int num, mt;
00745 uint total_height;
00746 const char *src;
00747 WChar c;
00748
00749 GetString(buffer, str, lastof(buffer));
00750
00751 tmp = FormatStringLinebreaks(buffer, maxw);
00752 num = GB(tmp, 0, 16);
00753
00754 mt = GetCharacterHeight((FontSize)GB(tmp, 16, 16));
00755 total_height = (num + 1) * mt;
00756
00757 if (maxh != -1 && (int)total_height > maxh) {
00758
00759 if (maxh < mt) return 0;
00760
00761 num = maxh / mt - 1;
00762 total_height = (num + 1) * mt;
00763 }
00764
00765 src = buffer;
00766
00767 for (;;) {
00768 char buf2[DRAW_STRING_BUFFER];
00769 strecpy(buf2, src, lastof(buf2));
00770 HandleBiDiAndArabicShapes(buf2, lastof(buf2));
00771 ReallyDoDrawString(buf2, x, y, 0xFE, true);
00772 _cur_fontsize = _last_fontsize;
00773
00774 for (;;) {
00775 c = Utf8Consume(&src);
00776 if (c == 0) {
00777 y += mt;
00778 if (--num < 0) {
00779 _cur_fontsize = FS_NORMAL;
00780 return total_height;
00781 }
00782 break;
00783 } else if (c == SCC_SETX) {
00784 src++;
00785 } else if (c == SCC_SETXY) {
00786 src += 2;
00787 }
00788 }
00789 }
00790 }
00791
00799 Dimension GetStringBoundingBox(const char *str)
00800 {
00801 FontSize size = _cur_fontsize;
00802 Dimension br;
00803 int max_width;
00804 WChar c;
00805
00806 br.width = br.height = max_width = 0;
00807 for (;;) {
00808 c = Utf8Consume(&str);
00809 if (c == 0) break;
00810 if (IsPrintable(c)) {
00811 br.width += GetCharacterWidth(size, c);
00812 } else {
00813 switch (c) {
00814 case SCC_SETX: br.width += (byte)*str++; break;
00815 case SCC_SETXY:
00816 br.width += (byte)*str++;
00817 br.height += (byte)*str++;
00818 break;
00819 case SCC_TINYFONT: size = FS_SMALL; break;
00820 case SCC_BIGFONT: size = FS_LARGE; break;
00821 case '\n':
00822 br.height += GetCharacterHeight(size);
00823 if (br.width > max_width) max_width = br.width;
00824 br.width = 0;
00825 break;
00826 }
00827 }
00828 }
00829 br.height += GetCharacterHeight(size);
00830
00831 br.width = max(br.width, max_width);
00832 return br;
00833 }
00834
00842 void DrawCharCentered(WChar c, int x, int y, uint16 real_color)
00843 {
00844 FontSize size = FS_NORMAL;
00845 byte color = real_color & 0xFF;
00846 int w = GetCharacterWidth(size, c);
00847
00848 _string_colorremap[1] = _string_colormap[_use_palette][color].text;
00849 _string_colorremap[2] = _string_colormap[_use_palette][color].shadow;
00850 _color_remap_ptr = _string_colorremap;
00851
00852 GfxMainBlitter(GetGlyph(size, c), x - w / 2, y, BM_COLOUR_REMAP);
00853 }
00854
00872 int DoDrawString(const char *string, int x, int y, uint16 real_colour, bool parse_string_also_when_clipped)
00873 {
00874 char buffer[DRAW_STRING_BUFFER];
00875 strecpy(buffer, string, lastof(buffer));
00876 HandleBiDiAndArabicShapes(buffer, lastof(buffer));
00877
00878 return ReallyDoDrawString(buffer, x, y, real_colour, parse_string_also_when_clipped);
00879 }
00880
00898 static int ReallyDoDrawString(const char *string, int x, int y, uint16 real_colour, bool parse_string_also_when_clipped)
00899 {
00900 DrawPixelInfo *dpi = _cur_dpi;
00901 FontSize size = _cur_fontsize;
00902 WChar c;
00903 int xo = x, yo = y;
00904
00905 byte colour = real_colour & 0xFF;
00906 byte previous_colour = colour;
00907
00908 if (!parse_string_also_when_clipped) {
00909
00910
00911 if (x >= dpi->left + dpi->width || y >= dpi->top + dpi->height) return x;
00912
00913 if (colour != TC_INVALID) {
00914 switch_colour:;
00915 if (real_colour & IS_PALETTE_COLOR) {
00916 _string_colorremap[1] = colour;
00917 _string_colorremap[2] = (_use_palette == PAL_DOS) ? 1 : 215;
00918 } else {
00919 _string_colorremap[1] = _string_colormap[_use_palette][colour].text;
00920 _string_colorremap[2] = _string_colormap[_use_palette][colour].shadow;
00921 }
00922 _color_remap_ptr = _string_colorremap;
00923 }
00924 }
00925
00926 check_bounds:
00927 if (y + 19 <= dpi->top || dpi->top + dpi->height <= y) {
00928 skip_char:;
00929 for (;;) {
00930 c = Utf8Consume(&string);
00931 if (!IsPrintable(c)) goto skip_cont;
00932 }
00933 }
00934
00935 for (;;) {
00936 c = Utf8Consume(&string);
00937 skip_cont:;
00938 if (c == 0) {
00939 _last_fontsize = size;
00940 return x;
00941 }
00942 if (IsPrintable(c)) {
00943 if (x >= dpi->left + dpi->width) goto skip_char;
00944 if (x + 26 >= dpi->left) {
00945 GfxMainBlitter(GetGlyph(size, c), x, y, BM_COLOUR_REMAP);
00946 }
00947 x += GetCharacterWidth(size, c);
00948 } else if (c == '\n') {
00949 x = xo;
00950 y += GetCharacterHeight(size);
00951 goto check_bounds;
00952 } else if (c >= SCC_BLUE && c <= SCC_BLACK) {
00953 previous_colour = colour;
00954 colour = (byte)(c - SCC_BLUE);
00955 goto switch_colour;
00956 } else if (c == SCC_PREVIOUS_COLOUR) {
00957 Swap(colour, previous_colour);
00958 goto switch_colour;
00959 } else if (c == SCC_SETX) {
00960 x = xo + (byte)*string++;
00961 } else if (c == SCC_SETXY) {
00962 x = xo + (byte)*string++;
00963 y = yo + (byte)*string++;
00964 } else if (c == SCC_TINYFONT) {
00965 size = FS_SMALL;
00966 } else if (c == SCC_BIGFONT) {
00967 size = FS_LARGE;
00968 } else {
00969 DEBUG(misc, 0, "[utf8] unknown string command character %d", c);
00970 }
00971 }
00972 }
00973
00986 int DoDrawStringTruncated(const char *str, int x, int y, uint16 color, uint maxw)
00987 {
00988 char buffer[DRAW_STRING_BUFFER];
00989 strecpy(buffer, str, lastof(buffer));
00990 TruncateString(buffer, maxw);
00991 return DoDrawString(buffer, x, y, color);
00992 }
00993
01002 void DrawSprite(SpriteID img, SpriteID pal, int x, int y, const SubSprite *sub)
01003 {
01004 if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) {
01005 _color_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1;
01006 GfxMainBlitter(GetSprite(GB(img, 0, SPRITE_WIDTH), ST_NORMAL), x, y, BM_TRANSPARENT, sub);
01007 } else if (pal != PAL_NONE) {
01008 _color_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1;
01009 GfxMainBlitter(GetSprite(GB(img, 0, SPRITE_WIDTH), ST_NORMAL), x, y, BM_COLOUR_REMAP, sub);
01010 } else {
01011 GfxMainBlitter(GetSprite(GB(img, 0, SPRITE_WIDTH), ST_NORMAL), x, y, BM_NORMAL, sub);
01012 }
01013 }
01014
01015 static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub)
01016 {
01017 const DrawPixelInfo *dpi = _cur_dpi;
01018 Blitter::BlitterParams bp;
01019
01020
01021 int clip_left = (sub != NULL ? max(0, -sprite->x_offs + sub->left ) : 0);
01022 int clip_top = (sub != NULL ? max(0, -sprite->y_offs + sub->top ) : 0);
01023 int clip_right = (sub != NULL ? max(0, sprite->width - (-sprite->x_offs + sub->right + 1)) : 0);
01024 int clip_bottom = (sub != NULL ? max(0, sprite->height - (-sprite->y_offs + sub->bottom + 1)) : 0);
01025
01026 if (clip_left + clip_right >= sprite->width) return;
01027 if (clip_top + clip_bottom >= sprite->height) return;
01028
01029
01030 x += sprite->x_offs;
01031 y += sprite->y_offs;
01032
01033
01034 bp.sprite = sprite->data;
01035 bp.sprite_width = sprite->width;
01036 bp.sprite_height = sprite->height;
01037 bp.width = UnScaleByZoom(sprite->width - clip_left - clip_right, dpi->zoom);
01038 bp.height = UnScaleByZoom(sprite->height - clip_top - clip_bottom, dpi->zoom);
01039 bp.top = 0;
01040 bp.left = 0;
01041 bp.skip_left = UnScaleByZoomLower(clip_left, dpi->zoom);
01042 bp.skip_top = UnScaleByZoomLower(clip_top, dpi->zoom);
01043
01044 x += ScaleByZoom(bp.skip_left, dpi->zoom);
01045 y += ScaleByZoom(bp.skip_top, dpi->zoom);
01046
01047 bp.dst = dpi->dst_ptr;
01048 bp.pitch = dpi->pitch;
01049 bp.remap = _color_remap_ptr;
01050
01051 assert(sprite->width > 0);
01052 assert(sprite->height > 0);
01053
01054 if (bp.width <= 0) return;
01055 if (bp.height <= 0) return;
01056
01057 y -= dpi->top;
01058
01059 if (y < 0) {
01060 bp.height -= -UnScaleByZoom(y, dpi->zoom);
01061 if (bp.height <= 0) return;
01062 bp.skip_top += -UnScaleByZoom(y, dpi->zoom);
01063 y = 0;
01064 } else {
01065 bp.top = UnScaleByZoom(y, dpi->zoom);
01066 }
01067
01068
01069 y += ScaleByZoom(bp.height, dpi->zoom) - dpi->height;
01070 if (y > 0) {
01071 bp.height -= UnScaleByZoom(y, dpi->zoom);
01072 if (bp.height <= 0) return;
01073 }
01074
01075 x -= dpi->left;
01076
01077 if (x < 0) {
01078 bp.width -= -UnScaleByZoom(x, dpi->zoom);
01079 if (bp.width <= 0) return;
01080 bp.skip_left += -UnScaleByZoom(x, dpi->zoom);
01081 x = 0;
01082 } else {
01083 bp.left = UnScaleByZoom(x, dpi->zoom);
01084 }
01085
01086
01087 x += ScaleByZoom(bp.width, dpi->zoom) - dpi->width;
01088 if (x > 0) {
01089 bp.width -= UnScaleByZoom(x, dpi->zoom);
01090 if (bp.width <= 0) return;
01091 }
01092
01093 assert(bp.skip_left + bp.width <= UnScaleByZoom(sprite->width, dpi->zoom));
01094 assert(bp.skip_top + bp.height <= UnScaleByZoom(sprite->height, dpi->zoom));
01095
01096 BlitterFactoryBase::GetCurrentBlitter()->Draw(&bp, mode, dpi->zoom);
01097 }
01098
01099 void DoPaletteAnimations();
01100
01101 void GfxInitPalettes()
01102 {
01103 memcpy(_cur_palette, _palettes[_use_palette], sizeof(_cur_palette));
01104
01105 DoPaletteAnimations();
01106 _pal_first_dirty = 0;
01107 _pal_count_dirty = 256;
01108 }
01109
01110 #define EXTR(p, q) (((uint16)(_palette_animation_counter * (p)) * (q)) >> 16)
01111 #define EXTR2(p, q) (((uint16)(~_palette_animation_counter * (p)) * (q)) >> 16)
01112
01113 void DoPaletteAnimations()
01114 {
01115 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
01116 const Colour *s;
01117 const ExtraPaletteValues *ev = &_extra_palette_values;
01118
01119
01120
01121 const int colour_rotation_amount = (_use_palette == PAL_DOS) ? PALETTE_ANIM_SIZE_DOS : PALETTE_ANIM_SIZE_WIN;
01122 Colour old_val[PALETTE_ANIM_SIZE_DOS];
01123 const int oldval_size = colour_rotation_amount * sizeof(*old_val);
01124 const uint old_tc = _palette_animation_counter;
01125 uint i;
01126 uint j;
01127
01128 if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) {
01129 _palette_animation_counter = 0;
01130 }
01131
01132 Colour *palette_pos = &_cur_palette[PALETTE_ANIM_SIZE_START];
01133
01134
01135 memcpy(old_val, palette_pos, oldval_size);
01136
01137
01138 s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->dark_water_TOY : ev->dark_water;
01139 j = EXTR(320, 5);
01140 for (i = 0; i != 5; i++) {
01141 *palette_pos++ = s[j];
01142 j++;
01143 if (j == 5) j = 0;
01144 }
01145
01146
01147 s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->glitter_water_TOY : ev->glitter_water;
01148 j = EXTR(128, 15);
01149 for (i = 0; i != 5; i++) {
01150 *palette_pos++ = s[j];
01151 j += 3;
01152 if (j >= 15) j -= 15;
01153 }
01154
01155
01156 s = ev->fizzy_drink;
01157 j = EXTR2(512, 5);
01158 for (i = 0; i != 5; i++) {
01159 *palette_pos++ = s[j];
01160 j++;
01161 if (j == 5) j = 0;
01162 }
01163
01164
01165 s = ev->oil_ref;
01166 j = EXTR2(512, 7);
01167 for (i = 0; i != 7; i++) {
01168 *palette_pos++ = s[j];
01169 j++;
01170 if (j == 7) j = 0;
01171 }
01172
01173
01174 {
01175 byte i = (_palette_animation_counter >> 1) & 0x7F;
01176 byte v;
01177
01178 (v = 255, i < 0x3f) ||
01179 (v = 128, i < 0x4A || i >= 0x75) ||
01180 (v = 20);
01181 palette_pos->r = v;
01182 palette_pos->g = 0;
01183 palette_pos->b = 0;
01184 palette_pos++;
01185
01186 i ^= 0x40;
01187 (v = 255, i < 0x3f) ||
01188 (v = 128, i < 0x4A || i >= 0x75) ||
01189 (v = 20);
01190 palette_pos->r = v;
01191 palette_pos->g = 0;
01192 palette_pos->b = 0;
01193 palette_pos++;
01194 }
01195
01196
01197 s = ev->lighthouse;
01198 j = EXTR(256, 4);
01199 for (i = 0; i != 4; i++) {
01200 *palette_pos++ = s[j];
01201 j++;
01202 if (j == 4) j = 0;
01203 }
01204
01205
01206 if (_use_palette == PAL_DOS) {
01207
01208 s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->dark_water_TOY : ev->dark_water;
01209 j = EXTR(320, 5);
01210 for (i = 0; i != 5; i++) {
01211 *palette_pos++ = s[j];
01212 j++;
01213 if (j == 5) j = 0;
01214 }
01215
01216
01217 s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->glitter_water_TOY : ev->glitter_water;
01218 j = EXTR(128, 15);
01219 for (i = 0; i != 5; i++) {
01220 *palette_pos++ = s[j];
01221 j += 3;
01222 if (j >= 15) j -= 15;
01223 }
01224 }
01225
01226 if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) {
01227 _palette_animation_counter = old_tc;
01228 } else {
01229 if (memcmp(old_val, &_cur_palette[PALETTE_ANIM_SIZE_START], oldval_size) != 0) {
01230
01231 _pal_first_dirty = PALETTE_ANIM_SIZE_START;
01232 _pal_count_dirty = colour_rotation_amount;
01233 }
01234 }
01235 }
01236
01237
01239 void LoadStringWidthTable()
01240 {
01241 uint i;
01242
01243
01244 for (i = 0; i != 224; i++) {
01245 _stringwidth_table[FS_NORMAL][i] = GetGlyphWidth(FS_NORMAL, i + 32);
01246 }
01247
01248
01249 for (i = 0; i != 224; i++) {
01250 _stringwidth_table[FS_SMALL][i] = GetGlyphWidth(FS_SMALL, i + 32);
01251 }
01252
01253
01254 for (i = 0; i != 224; i++) {
01255 _stringwidth_table[FS_LARGE][i] = GetGlyphWidth(FS_LARGE, i + 32);
01256 }
01257 }
01258
01265 byte GetCharacterWidth(FontSize size, WChar key)
01266 {
01267
01268 if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32];
01269
01270 return GetGlyphWidth(size, key);
01271 }
01272
01273
01274 void ScreenSizeChanged()
01275 {
01276 _dirty_bytes_per_line = (_screen.width + DIRTY_BLOCK_WIDTH - 1) / DIRTY_BLOCK_WIDTH;
01277 _dirty_blocks = ReallocT<byte>(_dirty_blocks, _dirty_bytes_per_line * ((_screen.height + DIRTY_BLOCK_HEIGHT - 1) / DIRTY_BLOCK_HEIGHT));
01278
01279
01280 if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
01281 if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height;
01282
01283
01284 _cursor.visible = false;
01285 }
01286
01287 void UndrawMouseCursor()
01288 {
01289 if (_cursor.visible) {
01290 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
01291 _cursor.visible = false;
01292 blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), _cursor_backup, _cursor.draw_size.x, _cursor.draw_size.y);
01293 _video_driver->MakeDirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y);
01294 }
01295 }
01296
01297 void DrawMouseCursor()
01298 {
01299 #if defined(WINCE)
01300
01301 return;
01302 #endif
01303
01304