tron@2186: /* $Id$ */ tron@2186: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@2163: #include "functions.h" tron@2154: #include "player.h" tron@1349: #include "spritecache.h" tron@1309: #include "strings.h" Darkvater@2097: #include "string.h" truelight@0: #include "gfx.h" truelight@0: #include "table/palettes.h" celestar@2187: #include "table/sprites.h" truelight@0: #include "hal.h" tron@2153: #include "variables.h" truelight@0: tron@2649: #ifdef _DEBUG tron@2649: bool _dbg_screen_rect; tron@2649: #endif tron@2649: tron@1991: Colour _cur_palette[256]; tron@1991: tron@1357: static void GfxMainBlitter(const Sprite *sprite, int x, int y, int mode); truelight@0: truelight@0: static int _stringwidth_out; tron@2062: static Pixel _cursor_backup[64 * 64]; truelight@0: static Rect _invalid_rect; tron@1357: static const byte *_color_remap_ptr; truelight@0: static byte _string_colorremap[3]; truelight@0: tron@2010: #define DIRTY_BYTES_PER_LINE (MAX_SCREEN_WIDTH / 64) truelight@0: static byte _dirty_blocks[DIRTY_BYTES_PER_LINE * MAX_SCREEN_HEIGHT / 8]; truelight@0: truelight@0: truelight@543: truelight@543: void memcpy_pitch(void *d, void *s, int w, int h, int spitch, int dpitch) truelight@0: { truelight@0: byte *dp = (byte*)d; truelight@0: byte *sp = (byte*)s; truelight@0: truelight@0: assert(h >= 0); tron@1056: for (; h != 0; --h) { truelight@0: memcpy(dp, sp, w); truelight@0: dp += dpitch; truelight@0: sp += spitch; tron@1056: } truelight@0: } truelight@0: truelight@0: tron@2010: void GfxScroll(int left, int top, int width, int height, int xo, int yo) tron@2010: { tron@2062: const Pixel *src; tron@2062: Pixel *dst; truelight@0: int p; truelight@0: int ht; truelight@0: tron@2010: if (xo == 0 && yo == 0) return; truelight@0: tron@2010: if (_cursor.visible) UndrawMouseCursor(); truelight@543: UndrawTextMessage(); truelight@0: truelight@0: p = _screen.pitch; truelight@0: tron@375: if (yo > 0) { truelight@0: // Calculate pointers tron@375: dst = _screen.dst_ptr + (top + height - 1) * p + left; truelight@0: src = dst - yo * p; truelight@0: truelight@0: // Decrease height and increase top truelight@0: top += yo; truelight@0: height -= yo; truelight@0: assert(height > 0); truelight@0: truelight@0: // Adjust left & width truelight@0: if (xo >= 0) { tron@375: dst += xo; truelight@0: left += xo; truelight@0: width -= xo; truelight@0: } else { tron@375: src -= xo; truelight@0: width += xo; truelight@0: } truelight@0: tron@375: for (ht = height; ht > 0; --ht) { tron@375: memcpy(dst, src, width); truelight@0: src -= p; truelight@0: dst -= p; tron@375: } truelight@0: } else { tron@375: // Calculate pointers truelight@0: dst = _screen.dst_ptr + top * p + left; truelight@0: src = dst - yo * p; truelight@0: truelight@0: // Decrese height. (yo is <=0). truelight@0: height += yo; truelight@0: assert(height > 0); truelight@0: truelight@0: // Adjust left & width truelight@0: if (xo >= 0) { truelight@0: dst += xo; truelight@0: left += xo; truelight@0: width -= xo; truelight@0: } else { truelight@0: src -= xo; truelight@0: width += xo; truelight@0: } truelight@0: tron@375: // the y-displacement may be 0 therefore we have to use memmove, tron@375: // because source and destination may overlap tron@375: for (ht = height; ht > 0; --ht) { tron@375: memmove(dst, src, width); truelight@0: src += p; truelight@0: dst += p; tron@375: } truelight@0: } tron@375: // This part of the screen is now dirty. tron@375: _video_driver->make_dirty(left, top, width, height); truelight@0: } truelight@0: truelight@0: tron@2010: void GfxFillRect(int left, int top, int right, int bottom, int color) tron@2010: { tron@2548: const DrawPixelInfo* dpi = _cur_dpi; tron@2062: Pixel *dst; tron@332: const int otop = top; tron@332: const int oleft = left; truelight@0: tron@2010: if (dpi->zoom != 0) return; tron@2010: if (left > right || top > bottom) return; tron@2010: if (right < dpi->left || left >= dpi->left + dpi->width) return; tron@2010: if (bottom < dpi->top || top >= dpi->top + dpi->height) return; truelight@0: truelight@0: if ( (left -= dpi->left) < 0) left = 0; truelight@0: right = right - dpi->left + 1; tron@2010: if (right > dpi->width) right = dpi->width; truelight@0: right -= left; truelight@0: assert(right > 0); truelight@0: truelight@0: if ( (top -= dpi->top) < 0) top = 0; truelight@0: bottom = bottom - dpi->top + 1; tron@2010: if (bottom > dpi->height) bottom = dpi->height; truelight@0: bottom -= top; truelight@0: assert(bottom > 0); truelight@0: truelight@0: dst = dpi->dst_ptr + top * dpi->pitch + left; truelight@0: celestar@2218: if (!(color & PALETTE_MODIFIER_GREYOUT)) { celestar@2218: if (!(color & USE_COLORTABLE)) { truelight@0: do { truelight@0: memset(dst, color, right); truelight@0: dst += dpi->pitch; truelight@0: } while (--bottom); truelight@0: } else { truelight@0: /* use colortable mode */ celestar@2218: const byte* ctab = GetNonSprite(color & COLORTABLE_MASK) + 1; tron@1357: truelight@0: do { truelight@0: int i; tron@2005: for (i = 0; i != right; i++) dst[i] = ctab[dst[i]]; truelight@0: dst += dpi->pitch; truelight@0: } while (--bottom); truelight@0: } truelight@0: } else { tron@332: byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1; truelight@0: do { truelight@0: int i; tron@2005: for (i = (bo ^= 1); i < right; i += 2) dst[i] = (byte)color; truelight@0: dst += dpi->pitch; tron@332: } while (--bottom > 0); truelight@0: } truelight@0: } truelight@0: tron@410: static void GfxSetPixel(int x, int y, int color) truelight@0: { tron@2548: const DrawPixelInfo* dpi = _cur_dpi; truelight@0: if ((x-=dpi->left) < 0 || x>=dpi->width || (y-=dpi->top)<0 || y>=dpi->height) truelight@0: return; tron@2010: dpi->dst_ptr[y * dpi->pitch + x] = color; truelight@0: } truelight@0: truelight@0: void GfxDrawLine(int x, int y, int x2, int y2, int color) truelight@0: { truelight@0: int dy; truelight@0: int dx; tron@2010: int stepx; tron@2010: int stepy; truelight@0: int frac; truelight@0: truelight@0: // Check clipping first truelight@0: { truelight@0: DrawPixelInfo *dpi = _cur_dpi; truelight@0: int t; truelight@0: tron@2010: if (x < dpi->left && x2 < dpi->left) return; truelight@0: tron@2010: if (y < dpi->top && y2 < dpi->top) return; truelight@0: truelight@0: t = dpi->left + dpi->width; tron@2010: if (x > t && x2 > t) return; truelight@0: truelight@0: t = dpi->top + dpi->height; tron@2010: if (y > t && y2 > t) return; truelight@0: } truelight@0: truelight@0: dy = (y2 - y) * 2; tron@2010: if (dy < 0) { tron@2010: dy = -dy; tron@2010: stepy = -1; tron@2010: } else { tron@2010: stepy = 1; tron@2010: } truelight@0: truelight@0: dx = (x2 - x) * 2; tron@2010: if (dx < 0) { tron@2010: dx = -dx; tron@2010: stepx = -1; tron@2010: } else { tron@2010: stepx = 1; tron@2010: } truelight@0: truelight@0: GfxSetPixel(x, y, color); truelight@0: if (dx > dy) { truelight@0: frac = dy - (dx >> 1); truelight@0: while (x != x2) { truelight@0: if (frac >= 0) { truelight@0: y += stepy; truelight@0: frac -= dx; truelight@0: } truelight@0: x += stepx; truelight@0: frac += dy; truelight@0: GfxSetPixel(x, y, color); truelight@0: } truelight@0: } else { truelight@0: frac = dx - (dy >> 1); truelight@0: while (y != y2) { truelight@0: if (frac >= 0) { truelight@0: x += stepx; truelight@0: frac -= dy; truelight@0: } truelight@0: y += stepy; truelight@0: frac += dx; truelight@0: GfxSetPixel(x, y, color); truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: // ASSIGNMENT OF ASCII LETTERS < 32 truelight@0: // 0 - end of string truelight@0: // 1 - SETX truelight@0: // 2 - SETXY truelight@193: // 3-7 - truelight@0: // 8 - TINYFONT truelight@0: // 9 - BIGFONT truelight@0: // 10 - newline truelight@193: // 11-14 - truelight@0: // 15-31 - 17 colors truelight@0: truelight@0: truelight@0: enum { truelight@0: ASCII_SETX = 1, truelight@0: ASCII_SETXY = 2, truelight@0: truelight@0: ASCII_TINYFONT = 8, truelight@0: ASCII_BIGFONT = 9, truelight@0: ASCII_NL = 10, truelight@0: truelight@0: ASCII_COLORSTART = 15, truelight@0: }; truelight@0: Darkvater@2097: /** Truncate a given string to a maximum width if neccessary. Darkvater@2097: * If the string is truncated, add three dots ('...') to show this. Darkvater@2097: * @param *dest string that is checked and possibly truncated Darkvater@2097: * @param maxw maximum width in pixels of the string Darkvater@2097: * @return new width of (truncated) string */ Darkvater@2113: static int TruncateString(char *str, int maxw) Darkvater@2097: { Darkvater@2113: int w = 0; Darkvater@2097: int base = _stringwidth_base; Darkvater@2097: int ddd, ddd_w; Darkvater@2097: Darkvater@2097: byte c; Darkvater@2097: char *ddd_pos; Darkvater@2097: Darkvater@2097: base = _stringwidth_base; Darkvater@2097: ddd_w = ddd = GetCharacterWidth(base + '.') * 3; Darkvater@2097: Darkvater@2113: for (ddd_pos = str; (c = *str++) != '\0'; ) { Darkvater@2097: if (c >= ASCII_LETTERSTART) { Darkvater@2097: w += GetCharacterWidth(base + c); Darkvater@2097: Darkvater@2097: if (w >= maxw) { Darkvater@2097: // string got too big... insert dotdotdot Darkvater@2097: ddd_pos[0] = ddd_pos[1] = ddd_pos[2] = '.'; Darkvater@2097: ddd_pos[3] = 0; Darkvater@2097: return ddd_w; Darkvater@2097: } Darkvater@2097: } else { Darkvater@2097: if (c == ASCII_SETX) str++; Darkvater@2097: else if (c == ASCII_SETXY) str += 2; Darkvater@2097: else if (c == ASCII_TINYFONT) { Darkvater@2097: base = 224; Darkvater@2097: ddd = GetCharacterWidth(base + '.') * 3; Darkvater@2097: } else if (c == ASCII_BIGFONT) { Darkvater@2097: base = 448; Darkvater@2097: ddd = GetCharacterWidth(base + '.') * 3; Darkvater@2097: } Darkvater@2097: } Darkvater@2097: Darkvater@2097: // Remember the last position where three dots fit. Darkvater@2097: if (w + ddd < maxw) { Darkvater@2097: ddd_w = w + ddd; Darkvater@2113: ddd_pos = str; Darkvater@2097: } Darkvater@2097: } Darkvater@2097: Darkvater@2097: return w; Darkvater@2097: } Darkvater@2097: Darkvater@2113: static inline int TruncateStringID(StringID src, char *dest, int maxw) Darkvater@2097: { Darkvater@2097: GetString(dest, src); Darkvater@2097: return TruncateString(dest, maxw); Darkvater@2097: } truelight@0: truelight@0: /* returns right coordinate */ Darkvater@2097: int DrawString(int x, int y, StringID str, uint16 color) truelight@0: { tron@1336: char buffer[512]; tron@1336: tron@1336: GetString(buffer, str); tron@1336: return DoDrawString(buffer, x, y, color); truelight@0: } truelight@0: Darkvater@2097: int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw) Darkvater@2097: { Darkvater@2097: char buffer[512]; Darkvater@2097: TruncateStringID(str, buffer, maxw); Darkvater@2097: return DoDrawString(buffer, x, y, color); Darkvater@2097: } truelight@0: Darkvater@2097: Darkvater@2097: void DrawStringRightAligned(int x, int y, StringID str, uint16 color) truelight@0: { tron@1336: char buffer[512]; tron@1336: tron@1336: GetString(buffer, str); tron@1336: DoDrawString(buffer, x - GetStringWidth(buffer), y, color); truelight@0: } truelight@0: Darkvater@2097: void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, uint maxw) Darkvater@2097: { Darkvater@2097: char buffer[512]; truelight@0: Darkvater@2097: TruncateStringID(str, buffer, maxw); Darkvater@2097: DoDrawString(buffer, x - GetStringWidth(buffer), y, color); Darkvater@2097: } Darkvater@2097: Darkvater@2097: Darkvater@2097: int DrawStringCentered(int x, int y, StringID str, uint16 color) truelight@0: { tron@1336: char buffer[512]; truelight@0: int w; truelight@0: tron@1336: GetString(buffer, str); truelight@0: tron@1336: w = GetStringWidth(buffer); tron@1336: DoDrawString(buffer, x - w / 2, y, color); truelight@0: truelight@0: return w; truelight@0: } truelight@0: Darkvater@2113: int DrawStringCenteredTruncated(int xl, int xr, int y, StringID str, uint16 color) Darkvater@2097: { Darkvater@2097: char buffer[512]; Darkvater@2113: int w = TruncateStringID(str, buffer, xr - xl); Darkvater@2113: return DoDrawString(buffer, (xl + xr - w) / 2, y, color); Darkvater@2097: } Darkvater@2097: Darkvater@2134: int DoDrawStringCentered(int x, int y, const char *str, uint16 color) Darkvater@2134: { Darkvater@2134: int w = GetStringWidth(str); Darkvater@2134: DoDrawString(str, x - w / 2, y, color); Darkvater@2134: return w; Darkvater@2134: } Darkvater@2134: Darkvater@2097: void DrawStringCenterUnderline(int x, int y, StringID str, uint16 color) truelight@0: { truelight@0: int w = DrawStringCentered(x, y, str, color); tron@2010: GfxFillRect(x - (w >> 1), y + 10, x - (w >> 1) + w, y + 10, _string_colorremap[1]); truelight@0: } truelight@0: Darkvater@2113: void DrawStringCenterUnderlineTruncated(int xl, int xr, int y, StringID str, uint16 color) Darkvater@2097: { Darkvater@2113: int w = DrawStringCenteredTruncated(xl, xr, y, str, color); Darkvater@2113: GfxFillRect((xl + xr - w) / 2, y + 10, (xl + xr + w) / 2, y + 10, _string_colorremap[1]); Darkvater@2097: } Darkvater@2097: tron@1323: static uint32 FormatStringLinebreaks(char *str, int maxw) tron@1095: { truelight@0: int num = 0; truelight@0: int base = _stringwidth_base; truelight@0: int w; tron@1323: char *last_space; truelight@0: byte c; truelight@0: truelight@0: for(;;) { truelight@0: w = 0; truelight@0: last_space = NULL; truelight@0: truelight@0: for(;;) { truelight@0: c = *str++; Darkvater@1390: if (c == ASCII_LETTERSTART) last_space = str; truelight@0: truelight@0: if (c >= ASCII_LETTERSTART) { Darkvater@1390: w += GetCharacterWidth(base + (byte)c); truelight@0: if (w > maxw) { truelight@0: str = last_space; truelight@0: if (str == NULL) truelight@0: return num + (base << 16); truelight@0: break; truelight@0: } truelight@0: } else { truelight@0: if (c == 0) return num + (base << 16); truelight@0: if (c == ASCII_NL) break; truelight@0: truelight@0: if (c == ASCII_SETX) str++; truelight@0: else if (c == ASCII_SETXY) str += 2; truelight@0: else if (c == ASCII_TINYFONT) base = 224; truelight@0: else if (c == ASCII_BIGFONT) base = 448; truelight@0: } truelight@0: } truelight@0: truelight@0: num++; tron@2548: str[-1] = '\0'; truelight@0: } truelight@0: } truelight@0: tron@2634: void DrawStringMultiCenter(int x, int y, StringID str, int maxw) truelight@0: { tron@1336: char buffer[512]; truelight@0: uint32 tmp; tron@2631: int num, w, mt; tron@1323: const char *src; truelight@0: byte c; truelight@0: tron@1336: GetString(buffer, str); truelight@0: tron@1336: tmp = FormatStringLinebreaks(buffer, maxw); tron@2635: num = GB(tmp, 0, 16); truelight@0: tron@2631: switch (GB(tmp, 16, 16)) { tron@2631: case 0: mt = 10; break; tron@2631: case 244: mt = 6; break; tron@2631: default: mt = 18; break; truelight@0: } truelight@0: truelight@0: y -= (mt >> 1) * num; truelight@0: tron@1336: src = buffer; truelight@0: truelight@0: for(;;) { truelight@0: w = GetStringWidth(src); truelight@0: DoDrawString(src, x - (w>>1), y, 0xFE); truelight@0: _stringwidth_base = _stringwidth_out; truelight@0: truelight@0: for(;;) { truelight@0: c = *src++; truelight@0: if (c == 0) { truelight@0: y += mt; truelight@0: if (--num < 0) { truelight@0: _stringwidth_base = 0; truelight@0: return; truelight@0: } truelight@0: break; truelight@0: } else if (c == ASCII_SETX) { truelight@0: src++; truelight@0: } else if (c == ASCII_SETXY) { truelight@0: src+=2; truelight@0: } truelight@0: } truelight@0: } truelight@0: } truelight@0: tron@2634: void DrawStringMultiLine(int x, int y, StringID str, int maxw) tron@2010: { tron@1336: char buffer[512]; truelight@0: uint32 tmp; tron@2753: int num, mt; tron@1323: const char *src; truelight@0: byte c; truelight@0: tron@1336: GetString(buffer, str); truelight@0: tron@1336: tmp = FormatStringLinebreaks(buffer, maxw); tron@2635: num = GB(tmp, 0, 16); tron@2631: tron@2631: switch (GB(tmp, 16, 16)) { tron@2631: case 0: mt = 10; break; tron@2631: case 244: mt = 6; break; tron@2631: default: mt = 18; break; truelight@0: } truelight@0: tron@1336: src = buffer; truelight@0: truelight@0: for(;;) { truelight@0: DoDrawString(src, x, y, 0xFE); truelight@0: _stringwidth_base = _stringwidth_out; truelight@0: truelight@0: for(;;) { truelight@0: c = *src++; truelight@0: if (c == 0) { truelight@0: y += mt; truelight@0: if (--num < 0) { truelight@0: _stringwidth_base = 0; truelight@0: return; truelight@0: } truelight@0: break; truelight@0: } else if (c == ASCII_SETX) { truelight@0: src++; truelight@0: } else if (c == ASCII_SETXY) { truelight@0: src+=2; truelight@0: } truelight@0: } truelight@0: } truelight@0: } truelight@0: tron@1323: int GetStringWidth(const char *str) tron@1323: { Darkvater@1390: int w = 0; truelight@0: byte c; truelight@0: int base = _stringwidth_base; Darkvater@1390: for (c = *str; c != '\0'; c = *(++str)) { truelight@0: if (c >= ASCII_LETTERSTART) { Darkvater@1390: w += GetCharacterWidth(base + c); truelight@0: } else { truelight@0: if (c == ASCII_SETX) str++; truelight@0: else if (c == ASCII_SETXY) str += 2; truelight@0: else if (c == ASCII_TINYFONT) base = 224; truelight@0: else if (c == ASCII_BIGFONT) base = 448; truelight@0: } truelight@0: } Darkvater@1390: return w; truelight@0: } truelight@0: tron@2010: void DrawFrameRect(int left, int top, int right, int bottom, int ctab, int flags) tron@2010: { truelight@0: byte color_2 = _color_list[ctab].window_color_1a; truelight@0: byte color_interior = _color_list[ctab].window_color_bga; truelight@0: byte color_3 = _color_list[ctab].window_color_bgb; truelight@0: byte color = _color_list[ctab].window_color_2; truelight@0: tron@2025: if (!(flags & 0x8)) { truelight@0: if (!(flags & 0x20)) { tron@2010: GfxFillRect(left, top, left, bottom - 1, color); tron@2010: GfxFillRect(left + 1, top, right - 1, top, color); tron@2010: GfxFillRect(right, top, right, bottom - 1, color_2); truelight@0: GfxFillRect(left, bottom, right, bottom, color_2); truelight@0: if (!(flags & 0x10)) { tron@2010: GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, color_interior); truelight@0: } truelight@0: } else { truelight@0: GfxFillRect(left, top, left, bottom, color_2); tron@2010: GfxFillRect(left + 1, top, right, top, color_2); tron@2010: GfxFillRect(right, top + 1, right, bottom - 1, color); tron@2010: GfxFillRect(left + 1, bottom, right, bottom, color); truelight@0: if (!(flags & 0x10)) { tron@2010: GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, tron@2010: flags & 0x40 ? color_interior : color_3); truelight@0: } truelight@0: } truelight@0: } else if (flags & 0x1) { truelight@0: // transparency celestar@2218: GfxFillRect(left, top, right, bottom, 0x322 | USE_COLORTABLE); truelight@0: } else { truelight@0: GfxFillRect(left, top, right, bottom, color_interior); truelight@0: } truelight@0: } truelight@0: tron@1323: int DoDrawString(const char *string, int x, int y, uint16 real_color) tron@1323: { truelight@0: DrawPixelInfo *dpi = _cur_dpi; truelight@0: int base = _stringwidth_base; dominik@509: byte c; truelight@543: byte color; truelight@0: int xo = x, yo = y; truelight@0: truelight@543: color = real_color & 0xFF; truelight@543: truelight@0: if (color != 0xFE) { truelight@0: if (x >= dpi->left + dpi->width || truelight@0: x + _screen.width*2 <= dpi->left || truelight@0: y >= dpi->top + dpi->height || truelight@0: y + _screen.height <= dpi->top) truelight@0: return x; truelight@0: truelight@0: if (color != 0xFF) { truelight@0: switch_color:; dominik@657: if (real_color & IS_PALETTE_COLOR) { truelight@543: _string_colorremap[1] = color; truelight@543: _string_colorremap[2] = 215; truelight@543: } else { truelight@543: _string_colorremap[1] = _string_colormap[color].text; truelight@543: _string_colorremap[2] = _string_colormap[color].shadow; truelight@543: } truelight@0: _color_remap_ptr = _string_colorremap; truelight@0: } truelight@0: } truelight@0: truelight@0: check_bounds: truelight@0: if (y + 19 <= dpi->top || dpi->top + dpi->height <= y) { truelight@0: skip_char:; truelight@0: for(;;) { truelight@0: c = *string++; truelight@193: if (c < ASCII_LETTERSTART) goto skip_cont; truelight@0: } truelight@0: } truelight@0: truelight@0: for(;;) { truelight@0: c = *string++; truelight@0: skip_cont:; truelight@0: if (c == 0) { truelight@0: _stringwidth_out = base; truelight@0: return x; truelight@0: } truelight@0: if (c >= ASCII_LETTERSTART) { truelight@0: if (x >= dpi->left + dpi->width) goto skip_char; truelight@0: if (x + 26 >= dpi->left) { tron@1350: GfxMainBlitter(GetSprite(base + 2 + c - ASCII_LETTERSTART), x, y, 1); truelight@0: } Darkvater@1390: x += GetCharacterWidth(base + c); truelight@0: } else if (c == ASCII_NL) { // newline = {} truelight@0: x = xo; truelight@0: y += 10; truelight@0: if (base != 0) { truelight@0: y -= 4; truelight@0: if (base != 0xE0) truelight@0: y += 12; truelight@0: } truelight@0: goto check_bounds; truelight@0: } else if (c >= ASCII_COLORSTART) { // change color? truelight@0: color = (byte)(c - ASCII_COLORSTART); truelight@0: goto switch_color; truelight@0: } else if (c == ASCII_SETX) { // {SETX} tron@1323: x = xo + (byte)*string++; truelight@0: } else if (c == ASCII_SETXY) {// {SETXY} tron@1323: x = xo + (byte)*string++; tron@1323: y = yo + (byte)*string++; truelight@0: } else if (c == ASCII_TINYFONT) { // {TINYFONT} truelight@0: base = 0xE0; truelight@0: } else if (c == ASCII_BIGFONT) { // {BIGFONT} truelight@0: base = 0x1C0; truelight@0: } else { truelight@0: printf("Unknown string command character %d\n", c); truelight@0: } truelight@0: } truelight@0: } truelight@0: Darkvater@2097: int DoDrawStringTruncated(const char *str, int x, int y, uint16 color, uint maxw) Darkvater@2097: { Darkvater@2097: char buffer[512]; Darkvater@2097: ttd_strlcpy(buffer, str, sizeof(buffer)); Darkvater@2097: TruncateString(buffer, maxw); Darkvater@2097: return DoDrawString(buffer, x, y, color); Darkvater@2097: } Darkvater@2097: tron@2010: void DrawSprite(uint32 img, int x, int y) tron@2010: { celestar@2187: if (img & PALETTE_MODIFIER_COLOR) { celestar@2187: _color_remap_ptr = GetNonSprite(GB(img, PALETTE_SPRITE_START, PALETTE_SPRITE_WIDTH)) + 1; celestar@2187: GfxMainBlitter(GetSprite(img & SPRITE_MASK), x, y, 1); celestar@2187: } else if (img & PALETTE_MODIFIER_TRANSPARENT) { celestar@2187: _color_remap_ptr = GetNonSprite(GB(img, PALETTE_SPRITE_START, PALETTE_SPRITE_WIDTH)) + 1; celestar@2187: GfxMainBlitter(GetSprite(img & SPRITE_MASK), x, y, 2); truelight@0: } else { celestar@2187: GfxMainBlitter(GetSprite(img & SPRITE_MASK), x, y, 0); truelight@0: } truelight@0: } truelight@0: truelight@0: typedef struct BlitterParams { truelight@0: int start_x, start_y; tron@1357: const byte* sprite; tron@1357: const byte* sprite_org; tron@2062: Pixel *dst; truelight@0: int mode; truelight@0: int width, height; tron@2010: int width_org; tron@2010: int height_org; truelight@0: int pitch; truelight@0: byte info; truelight@0: } BlitterParams; truelight@0: truelight@0: static void GfxBlitTileZoomIn(BlitterParams *bp) truelight@0: { tron@1357: const byte* src_o = bp->sprite; tron@1357: const byte* src; truelight@0: int num, skip; truelight@0: byte done; tron@2062: Pixel *dst; tron@1357: const byte* ctab; truelight@0: truelight@0: if (bp->mode & 1) { Darkvater@9918: src_o += ReadLE16Aligned(src_o + bp->start_y * 2); truelight@193: truelight@0: do { truelight@0: do { truelight@0: done = src_o[0]; truelight@0: num = done & 0x7F; truelight@0: skip = src_o[1]; truelight@0: src = src_o + 2; truelight@0: src_o += num + 2; truelight@0: truelight@0: dst = bp->dst; truelight@0: truelight@0: if ( (skip -= bp->start_x) > 0) { truelight@0: dst += skip; truelight@0: } else { truelight@0: src -= skip; truelight@0: num += skip; tron@2010: if (num <= 0) continue; truelight@0: skip = 0; truelight@0: } truelight@0: truelight@0: skip = skip + num - bp->width; truelight@0: if (skip > 0) { truelight@0: num -= skip; tron@2010: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: ctab = _color_remap_ptr; truelight@0: tron@1997: for (; num >= 4; num -=4) { truelight@0: dst[3] = ctab[src[3]]; truelight@0: dst[2] = ctab[src[2]]; truelight@0: dst[1] = ctab[src[1]]; truelight@0: dst[0] = ctab[src[0]]; truelight@0: dst += 4; truelight@0: src += 4; truelight@0: } tron@1997: for (; num != 0; num--) *dst++ = ctab[*src++]; truelight@0: } while (!(done & 0x80)); truelight@0: truelight@0: bp->dst += bp->pitch; tron@2010: } while (--bp->height != 0); truelight@0: } else if (bp->mode & 2) { Darkvater@9918: src_o += ReadLE16Aligned(src_o + bp->start_y * 2); truelight@0: do { truelight@0: do { truelight@0: done = src_o[0]; truelight@0: num = done & 0x7F; truelight@0: skip = src_o[1]; truelight@0: src_o += num + 2; truelight@0: truelight@0: dst = bp->dst; truelight@0: truelight@0: if ( (skip -= bp->start_x) > 0) { truelight@0: dst += skip; truelight@0: } else { truelight@0: num += skip; tron@2010: if (num <= 0) continue; truelight@0: skip = 0; truelight@0: } truelight@0: truelight@0: skip = skip + num - bp->width; truelight@0: if (skip > 0) { truelight@0: num -= skip; tron@2010: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: ctab = _color_remap_ptr; tron@1997: for (; num != 0; num--) { truelight@0: *dst = ctab[*dst]; truelight@0: dst++; truelight@0: } truelight@0: } while (!(done & 0x80)); truelight@0: truelight@0: bp->dst += bp->pitch; tron@2010: } while (--bp->height != 0); truelight@0: } else { Darkvater@9918: src_o += ReadLE16Aligned(src_o + bp->start_y * 2); truelight@0: do { truelight@0: do { truelight@0: done = src_o[0]; truelight@0: num = done & 0x7F; truelight@0: skip = src_o[1]; truelight@0: src = src_o + 2; truelight@0: src_o += num + 2; truelight@0: truelight@0: dst = bp->dst; truelight@0: truelight@0: if ( (skip -= bp->start_x) > 0) { truelight@0: dst += skip; truelight@0: } else { truelight@0: src -= skip; truelight@0: num += skip; tron@2010: if (num <= 0) continue; truelight@0: skip = 0; truelight@0: } truelight@0: truelight@0: skip = skip + num - bp->width; truelight@0: if (skip > 0) { truelight@0: num -= skip; tron@2010: if (num <= 0) continue; truelight@0: } truelight@0: #if defined(_WIN32) truelight@0: if (num & 1) *dst++ = *src++; truelight@0: if (num & 2) { *(uint16*)dst = *(uint16*)src; dst += 2; src += 2; } truelight@0: if (num >>= 2) { truelight@0: do { truelight@0: *(uint32*)dst = *(uint32*)src; truelight@0: dst += 4; truelight@0: src += 4; tron@2010: } while (--num != 0); truelight@0: } truelight@0: #else truelight@0: memcpy(dst, src, num); truelight@0: #endif truelight@0: } while (!(done & 0x80)); truelight@0: truelight@0: bp->dst += bp->pitch; tron@2010: } while (--bp->height != 0); truelight@0: } truelight@0: } truelight@0: truelight@0: static void GfxBlitZoomInUncomp(BlitterParams *bp) truelight@0: { tron@1357: const byte *src = bp->sprite; tron@2062: Pixel *dst = bp->dst; truelight@0: int height = bp->height; truelight@0: int width = bp->width; truelight@0: int i; truelight@0: truelight@0: assert(height > 0); truelight@0: assert(width > 0); truelight@0: truelight@0: if (bp->mode & 1) { truelight@0: if (bp->info & 1) { tron@1357: const byte *ctab = _color_remap_ptr; truelight@0: truelight@0: do { tron@1996: for (i = 0; i != width; i++) { tron@1996: byte b = ctab[src[i]]; tron@1996: tron@1996: if (b != 0) dst[i] = b; truelight@0: } truelight@0: src += bp->width_org; truelight@0: dst += bp->pitch; tron@2010: } while (--height != 0); truelight@0: } truelight@0: } else if (bp->mode & 2) { truelight@0: if (bp->info & 1) { tron@1357: const byte *ctab = _color_remap_ptr; tron@1357: truelight@0: do { tron@1996: for (i = 0; i != width; i++) tron@1996: if (src[i] != 0) dst[i] = ctab[dst[i]]; truelight@0: src += bp->width_org; truelight@0: dst += bp->pitch; tron@2010: } while (--height != 0); truelight@0: } truelight@0: } else { truelight@0: if (!(bp->info & 1)) { truelight@0: do { truelight@0: memcpy(dst, src, width); truelight@0: src += bp->width_org; truelight@0: dst += bp->pitch; tron@2010: } while (--height != 0); truelight@0: } else { truelight@0: do { truelight@0: int n = width; tron@2004: tron@2004: for (; n >= 4; n -= 4) { tron@1996: if (src[0] != 0) dst[0] = src[0]; tron@1996: if (src[1] != 0) dst[1] = src[1]; tron@1996: if (src[2] != 0) dst[2] = src[2]; tron@1996: if (src[3] != 0) dst[3] = src[3]; truelight@0: truelight@0: dst += 4; truelight@0: src += 4; truelight@0: } truelight@0: tron@2004: for (; n != 0; n--) { tron@1996: if (src[0] != 0) dst[0] = src[0]; truelight@0: src++; truelight@0: dst++; truelight@0: } truelight@0: truelight@0: src += bp->width_org - width; truelight@0: dst += bp->pitch - width; tron@2010: } while (--height != 0); truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: static void GfxBlitTileZoomMedium(BlitterParams *bp) truelight@0: { tron@1357: const byte* src_o = bp->sprite; tron@1357: const byte* src; truelight@0: int num, skip; truelight@0: byte done; tron@2062: Pixel *dst; tron@1357: const byte* ctab; truelight@0: truelight@0: if (bp->mode & 1) { Darkvater@9918: src_o += ReadLE16Aligned(src_o + bp->start_y * 2); truelight@0: do { truelight@0: do { truelight@0: done = src_o[0]; truelight@0: num = done & 0x7F; truelight@0: skip = src_o[1]; truelight@0: src = src_o + 2; truelight@0: src_o += num + 2; truelight@0: truelight@0: dst = bp->dst; truelight@0: truelight@0: if (skip & 1) { truelight@0: skip++; truelight@0: src++; tron@2004: if (--num == 0) continue; truelight@0: } truelight@0: truelight@0: if ( (skip -= bp->start_x) > 0) { truelight@0: dst += skip >> 1; truelight@0: } else { truelight@0: src -= skip; truelight@0: num += skip; tron@2010: if (num <= 0) continue; truelight@0: skip = 0; truelight@0: } truelight@0: truelight@0: skip = skip + num - bp->width; truelight@0: if (skip > 0) { truelight@0: num -= skip; tron@2010: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: ctab = _color_remap_ptr; truelight@0: num = (num + 1) >> 1; tron@1997: for (; num != 0; num--) { truelight@0: *dst = ctab[*src]; truelight@0: dst++; tron@1997: src += 2; truelight@0: } truelight@0: } while (!(done & 0x80)); truelight@0: bp->dst += bp->pitch; tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2010: } while (--bp->height != 0); truelight@0: } else if (bp->mode & 2) { Darkvater@9918: src_o += ReadLE16Aligned(src_o + bp->start_y * 2); truelight@0: do { truelight@0: do { truelight@0: done = src_o[0]; truelight@0: num = done & 0x7F; truelight@0: skip = src_o[1]; truelight@0: src_o += num + 2; truelight@0: truelight@0: dst = bp->dst; truelight@0: truelight@0: if (skip & 1) { truelight@0: skip++; tron@2004: if (--num == 0) continue; truelight@0: } truelight@0: truelight@0: if ( (skip -= bp->start_x) > 0) { truelight@0: dst += skip >> 1; truelight@0: } else { truelight@0: num += skip; tron@2010: if (num <= 0) continue; truelight@0: skip = 0; truelight@0: } truelight@0: truelight@0: skip = skip + num - bp->width; truelight@0: if (skip > 0) { truelight@0: num -= skip; tron@2010: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: ctab = _color_remap_ptr; truelight@0: num = (num + 1) >> 1; tron@1997: for (; num != 0; num--) { truelight@0: *dst = ctab[*dst]; truelight@0: dst++; truelight@0: } truelight@0: } while (!(done & 0x80)); truelight@0: bp->dst += bp->pitch; tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2010: } while (--bp->height != 0); truelight@0: } else { Darkvater@9918: src_o += ReadLE16Aligned(src_o + bp->start_y * 2); truelight@0: do { truelight@0: do { truelight@0: done = src_o[0]; truelight@0: num = done & 0x7F; truelight@0: skip = src_o[1]; truelight@0: src = src_o + 2; truelight@0: src_o += num + 2; truelight@0: truelight@0: dst = bp->dst; truelight@0: truelight@0: if (skip & 1) { truelight@0: skip++; truelight@0: src++; tron@2004: if (--num == 0) continue; truelight@0: } truelight@0: truelight@0: if ( (skip -= bp->start_x) > 0) { truelight@0: dst += skip >> 1; truelight@0: } else { truelight@0: src -= skip; truelight@0: num += skip; tron@2010: if (num <= 0) continue; truelight@0: skip = 0; truelight@0: } truelight@0: truelight@0: skip = skip + num - bp->width; truelight@0: if (skip > 0) { truelight@0: num -= skip; tron@2010: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: num = (num + 1) >> 1; truelight@0: tron@1997: for (; num != 0; num--) { truelight@0: *dst = *src; truelight@0: dst++; tron@1997: src += 2; truelight@0: } truelight@0: truelight@0: } while (!(done & 0x80)); truelight@0: truelight@0: bp->dst += bp->pitch; tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2010: } while (--bp->height != 0); truelight@0: } truelight@0: } truelight@0: truelight@0: static void GfxBlitZoomMediumUncomp(BlitterParams *bp) truelight@0: { tron@1357: const byte *src = bp->sprite; tron@2062: Pixel *dst = bp->dst; truelight@0: int height = bp->height; truelight@0: int width = bp->width; truelight@0: int i; truelight@0: truelight@0: assert(height > 0); truelight@0: assert(width > 0); truelight@0: truelight@0: if (bp->mode & 1) { truelight@0: if (bp->info & 1) { tron@1357: const byte *ctab = _color_remap_ptr; tron@1357: tron@1996: for (height >>= 1; height != 0; height--) { tron@1996: for (i = 0; i != width >> 1; i++) { tron@1996: byte b = ctab[src[i * 2]]; tron@1996: tron@1996: if (b != 0) dst[i] = b; tron@1996: } truelight@0: src += bp->width_org * 2; truelight@0: dst += bp->pitch; tron@1996: } truelight@0: } truelight@0: } else if (bp->mode & 2) { truelight@0: if (bp->info & 1) { tron@1357: const byte *ctab = _color_remap_ptr; tron@1357: tron@1996: for (height >>= 1; height != 0; height--) { tron@1996: for (i = 0; i != width >> 1; i++) tron@1996: if (src[i * 2] != 0) dst[i] = ctab[dst[i]]; truelight@0: src += bp->width_org * 2; truelight@0: dst += bp->pitch; tron@1996: } truelight@0: } truelight@0: } else { truelight@0: if (bp->info & 1) { tron@1996: for (height >>= 1; height != 0; height--) { tron@1996: for (i = 0; i != width >> 1; i++) tron@1996: if (src[i * 2] != 0) dst[i] = src[i * 2]; truelight@0: src += bp->width_org * 2; truelight@0: dst += bp->pitch; tron@1996: } truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: static void GfxBlitTileZoomOut(BlitterParams *bp) truelight@0: { tron@1357: const byte* src_o = bp->sprite; tron@1357: const byte* src; truelight@0: int num, skip; truelight@0: byte done; tron@2062: Pixel *dst; tron@1357: const byte* ctab; truelight@0: truelight@0: if (bp->mode & 1) { Darkvater@9918: src_o += ReadLE16Aligned(src_o + bp->start_y * 2); truelight@0: for(;;) { truelight@0: do { truelight@0: done = src_o[0]; truelight@0: num = done & 0x7F; truelight@0: skip = src_o[1]; truelight@0: src = src_o + 2; truelight@0: src_o += num + 2; truelight@0: truelight@0: dst = bp->dst; truelight@0: truelight@0: if (skip & 1) { truelight@0: skip++; truelight@0: src++; tron@2004: if (--num == 0) continue; truelight@0: } truelight@0: truelight@0: if (skip & 2) { tron@2004: skip += 2; tron@2004: src += 2; tron@2004: num -= 2; tron@2004: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: if ( (skip -= bp->start_x) > 0) { truelight@0: dst += skip >> 2; truelight@0: } else { truelight@0: src -= skip; truelight@0: num += skip; tron@2004: if (num <= 0) continue; truelight@0: skip = 0; truelight@0: } truelight@0: truelight@0: skip = skip + num - bp->width; truelight@0: if (skip > 0) { truelight@0: num -= skip; tron@2004: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: ctab = _color_remap_ptr; truelight@0: num = (num + 3) >> 2; tron@1997: for (; num != 0; num--) { truelight@0: *dst = ctab[*src]; truelight@0: dst++; tron@1997: src += 4; truelight@0: } truelight@0: } while (!(done & 0x80)); truelight@0: bp->dst += bp->pitch; tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2004: if (--bp->height == 0) return; truelight@0: } truelight@0: } else if (bp->mode & 2) { Darkvater@9918: src_o += ReadLE16Aligned(src_o + bp->start_y * 2); truelight@0: for(;;) { truelight@0: do { truelight@0: done = src_o[0]; truelight@0: num = done & 0x7F; truelight@0: skip = src_o[1]; truelight@0: src_o += num + 2; truelight@0: truelight@0: dst = bp->dst; truelight@0: truelight@0: if (skip & 1) { truelight@0: skip++; tron@2004: if (--num == 0) continue; truelight@0: } truelight@0: truelight@0: if (skip & 2) { tron@2004: skip += 2; tron@2004: num -= 2; tron@2004: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: if ( (skip -= bp->start_x) > 0) { truelight@0: dst += skip >> 2; truelight@0: } else { truelight@0: num += skip; tron@2004: if (num <= 0) continue; truelight@0: skip = 0; truelight@0: } truelight@0: truelight@0: skip = skip + num - bp->width; truelight@0: if (skip > 0) { truelight@0: num -= skip; tron@2004: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: ctab = _color_remap_ptr; truelight@0: num = (num + 3) >> 2; tron@1997: for (; num != 0; num--) { truelight@0: *dst = ctab[*dst]; truelight@0: dst++; truelight@0: } truelight@0: truelight@0: } while (!(done & 0x80)); truelight@0: bp->dst += bp->pitch; tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2004: if (--bp->height == 0) return; truelight@0: } truelight@0: } else { Darkvater@9918: src_o += ReadLE16Aligned(src_o + bp->start_y * 2); truelight@0: for(;;) { truelight@0: do { truelight@0: done = src_o[0]; truelight@0: num = done & 0x7F; truelight@0: skip = src_o[1]; truelight@0: src = src_o + 2; truelight@0: src_o += num + 2; truelight@0: truelight@0: dst = bp->dst; truelight@0: truelight@0: if (skip & 1) { truelight@0: skip++; truelight@0: src++; tron@2004: if (--num == 0) continue; truelight@0: } truelight@0: truelight@0: if (skip & 2) { tron@2004: skip += 2; tron@2004: src += 2; tron@2004: num -= 2; tron@2004: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: if ( (skip -= bp->start_x) > 0) { truelight@0: dst += skip >> 2; truelight@0: } else { truelight@0: src -= skip; truelight@0: num += skip; tron@2004: if (num <= 0) continue; truelight@0: skip = 0; truelight@0: } truelight@0: truelight@0: skip = skip + num - bp->width; truelight@0: if (skip > 0) { truelight@0: num -= skip; tron@2004: if (num <= 0) continue; truelight@0: } truelight@0: truelight@0: num = (num + 3) >> 2; truelight@0: tron@1997: for (; num != 0; num--) { truelight@0: *dst = *src; truelight@0: dst++; tron@1997: src += 4; truelight@0: } truelight@0: } while (!(done & 0x80)); truelight@0: truelight@0: bp->dst += bp->pitch; tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2004: if (--bp->height == 0) return; truelight@0: truelight@0: do { truelight@0: done = src_o[0]; truelight@0: src_o += (done & 0x7F) + 2; truelight@0: } while (!(done & 0x80)); tron@2004: if (--bp->height == 0) return; truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: static void GfxBlitZoomOutUncomp(BlitterParams *bp) truelight@0: { tron@1357: const byte* src = bp->sprite; tron@2062: Pixel *dst = bp->dst; truelight@0: int height = bp->height; truelight@0: int width = bp->width; truelight@0: int i; truelight@0: truelight@0: assert(height > 0); truelight@0: assert(width > 0); truelight@0: truelight@0: if (bp->mode & 1) { truelight@0: if (bp->info & 1) { tron@1357: const byte *ctab = _color_remap_ptr; tron@1357: tron@1996: for (height >>= 2; height != 0; height--) { tron@1996: for (i = 0; i != width >> 2; i++) { tron@1996: byte b = ctab[src[i * 4]]; tron@1996: tron@1996: if (b != 0) dst[i] = b; tron@1996: } truelight@0: src += bp->width_org * 4; truelight@0: dst += bp->pitch; tron@1996: } truelight@0: } truelight@0: } else if (bp->mode & 2) { truelight@0: if (bp->info & 1) { tron@1357: const byte *ctab = _color_remap_ptr; tron@1357: tron@1996: for (height >>= 2; height != 0; height--) { tron@1996: for (i = 0; i != width >> 2; i++) tron@1996: if (src[i * 4] != 0) dst[i] = ctab[dst[i]]; truelight@0: src += bp->width_org * 4; truelight@0: dst += bp->pitch; tron@1996: } truelight@0: } truelight@0: } else { truelight@0: if (bp->info & 1) { tron@1996: for (height >>= 2; height != 0; height--) { tron@1996: for (i = 0; i != width >> 2; i++) tron@1996: if (src[i * 4] != 0) dst[i] = src[i * 4]; truelight@0: src += bp->width_org * 4; truelight@0: dst += bp->pitch; tron@1996: } truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: typedef void (*BlitZoomFunc)(BlitterParams *bp); truelight@0: tron@1357: static void GfxMainBlitter(const Sprite* sprite, int x, int y, int mode) truelight@0: { tron@2548: const DrawPixelInfo* dpi = _cur_dpi; truelight@0: int start_x, start_y; truelight@0: byte info; truelight@0: BlitterParams bp; tron@2005: int zoom_mask = ~((1 << dpi->zoom) - 1); truelight@0: truelight@0: static const BlitZoomFunc zf_tile[3] = truelight@0: { truelight@0: GfxBlitTileZoomIn, truelight@0: GfxBlitTileZoomMedium, truelight@0: GfxBlitTileZoomOut truelight@0: }; truelight@0: static const BlitZoomFunc zf_uncomp[3] = truelight@0: { truelight@0: GfxBlitZoomInUncomp, truelight@0: GfxBlitZoomMediumUncomp, truelight@0: GfxBlitZoomOutUncomp truelight@0: }; truelight@0: truelight@0: /* decode sprite header */ tron@1351: x += sprite->x_offs; tron@1351: y += sprite->y_offs; tron@1351: bp.width_org = bp.width = sprite->width; tron@1348: bp.height_org = bp.height = sprite->height; tron@1348: info = sprite->info; truelight@0: bp.info = info; tron@1348: bp.sprite_org = bp.sprite = sprite->data; truelight@0: bp.dst = dpi->dst_ptr; truelight@0: bp.mode = mode; truelight@0: bp.pitch = dpi->pitch; truelight@0: truelight@0: assert(bp.height > 0); truelight@0: assert(bp.width > 0); truelight@0: truelight@0: if (info & 8) { truelight@0: /* tile blit */ truelight@0: start_y = 0; truelight@0: truelight@0: if (dpi->zoom > 0) { tron@2005: start_y += bp.height & ~zoom_mask; truelight@193: bp.height &= zoom_mask; truelight@0: if (bp.height == 0) return; tron@2005: y &= zoom_mask; truelight@0: } truelight@0: truelight@0: if ( (y -= dpi->top) < 0) { tron@2005: bp.height += y; tron@2005: if (bp.height <= 0) return; truelight@0: start_y -= y; truelight@0: y = 0; truelight@0: } else { tron@2005: bp.dst += bp.pitch * (y >> dpi->zoom); truelight@0: } truelight@0: bp.start_y = start_y; truelight@0: truelight@0: if ( (y = y + bp.height - dpi->height) > 0) { tron@2005: bp.height -= y; tron@2005: if (bp.height <= 0) return; truelight@0: } truelight@0: truelight@0: start_x = 0; truelight@0: x &= zoom_mask; truelight@0: if ( (x -= dpi->left) < 0) { tron@2005: bp.width += x; tron@2005: if (bp.width <= 0) return; truelight@0: start_x -= x; truelight@0: x = 0; truelight@0: } truelight@0: bp.start_x = start_x; tron@2005: bp.dst += x >> dpi->zoom; truelight@0: truelight@0: if ( (x = x + bp.width - dpi->width) > 0) { tron@2005: bp.width -= x; tron@2005: if (bp.width <= 0) return; truelight@0: } truelight@0: truelight@0: zf_tile[dpi->zoom](&bp); truelight@0: } else { truelight@0: bp.sprite += bp.width * (bp.height & ~zoom_mask); truelight@0: bp.height &= zoom_mask; tron@2005: if (bp.height == 0) return; truelight@0: truelight@0: y &= zoom_mask; truelight@0: truelight@0: if ( (y -= dpi->top) < 0) { tron@2005: bp.height += y; tron@2005: if (bp.height <= 0) return; truelight@0: bp.sprite -= bp.width * y; truelight@0: y = 0; truelight@0: } else { tron@2005: bp.dst += bp.pitch * (y >> dpi->zoom); truelight@0: } truelight@0: tron@2037: if (bp.height > dpi->height - y) { tron@2037: bp.height = dpi->height - y; tron@2005: if (bp.height <= 0) return; truelight@0: } truelight@0: truelight@0: x &= zoom_mask; truelight@0: truelight@0: if ( (x -= dpi->left) < 0) { tron@2005: bp.width += x; tron@2005: if (bp.width <= 0) return; truelight@0: bp.sprite -= x; truelight@0: x = 0; truelight@0: } tron@2005: bp.dst += x >> dpi->zoom; truelight@0: tron@2037: if (bp.width > dpi->width - x) { tron@2037: bp.width = dpi->width - x; tron@2005: if (bp.width <= 0) return; truelight@0: } truelight@0: truelight@0: zf_uncomp[dpi->zoom](&bp); truelight@0: } truelight@0: } truelight@0: tron@1093: void DoPaletteAnimations(void); dominik@614: tron@1093: void GfxInitPalettes(void) truelight@0: { tron@1991: memcpy(_cur_palette, _palettes[_use_dos_palette ? 1 : 0], sizeof(_cur_palette)); dominik@614: truelight@0: _pal_first_dirty = 0; truelight@0: _pal_last_dirty = 255; dominik@614: DoPaletteAnimations(); truelight@0: } truelight@0: tron@2010: #define EXTR(p, q) (((uint16)(_timer_counter * (p)) * (q)) >> 16) tron@2010: #define EXTR2(p, q) (((uint16)(~_timer_counter * (p)) * (q)) >> 16) truelight@0: tron@1093: void DoPaletteAnimations(void) truelight@0: { tron@1991: const Colour* s; tron@1991: Colour* d; dominik@614: /* Amount of colors to be rotated. dominik@614: * A few more for the DOS palette, because the water colors are dominik@614: * 245-254 for DOS and 217-226 for Windows. */ truelight@0: const ExtraPaletteValues *ev = &_extra_palette_values; tron@2005: int c = _use_dos_palette ? 38 : 28; tron@1991: Colour old_val[38]; // max(38, 28) tron@2005: uint i; tron@2005: uint j; truelight@0: tron@1991: d = &_cur_palette[217]; tron@1991: memcpy(old_val, d, c * sizeof(*old_val)); truelight@0: truelight@0: // Dark blue water tron@2005: s = (_opt.landscape == LT_CANDY) ? ev->ac : ev->a; tron@2005: j = EXTR(320, 5); tron@2005: for (i = 0; i != 5; i++) { tron@1991: *d++ = s[j]; tron@1991: j++; tron@1991: if (j == 5) j = 0; truelight@0: } truelight@0: truelight@0: // Glittery water tron@2005: s = (_opt.landscape == LT_CANDY) ? ev->bc : ev->b; tron@1991: j = EXTR(128, 15); tron@2005: for (i = 0; i != 5; i++) { tron@1991: *d++ = s[j]; tron@1991: j += 3; tron@1991: if (j >= 15) j -= 15; truelight@0: } truelight@0: truelight@0: s = ev->e; tron@1991: j = EXTR2(512, 5); tron@2005: for (i = 0; i != 5; i++) { tron@1991: *d++ = s[j]; tron@1991: j++; tron@1991: if (j == 5) j = 0; truelight@0: } truelight@0: truelight@0: // Oil refinery fire animation truelight@0: s = ev->oil_ref; tron@1991: j = EXTR2(512, 7); tron@2005: for (i = 0; i != 7; i++) { tron@1991: *d++ = s[j]; tron@1991: j++; tron@1991: if (j == 7) j = 0; truelight@0: } truelight@0: truelight@0: // Radio tower blinking truelight@0: { tron@2005: byte i = (_timer_counter >> 1) & 0x7F; tron@2005: byte v; tron@2005: truelight@0: (v = 255, i < 0x3f) || truelight@0: (v = 128, i < 0x4A || i >= 0x75) || truelight@0: (v = 20); tron@1991: d->r = v; tron@1991: d->g = 0; tron@1991: d->b = 0; tron@1991: d++; truelight@0: truelight@0: i ^= 0x40; truelight@0: (v = 255, i < 0x3f) || truelight@0: (v = 128, i < 0x4A || i >= 0x75) || truelight@0: (v = 20); tron@1991: d->r = v; tron@1991: d->g = 0; tron@1991: d->b = 0; tron@1991: d++; truelight@0: } truelight@0: truelight@0: // Handle lighthouse and stadium animation truelight@0: s = ev->lighthouse; tron@1991: j = EXTR(256, 4); tron@2005: for (i = 0; i != 4; i++) { tron@1991: *d++ = s[j]; tron@1991: j++; tron@1991: if (j == 4) j = 0; truelight@0: } truelight@0: dominik@614: // Animate water for old DOS graphics tron@2005: if (_use_dos_palette) { dominik@614: // Dark blue water DOS tron@2005: s = (_opt.landscape == LT_CANDY) ? ev->ac : ev->a; tron@2005: j = EXTR(320, 5); tron@2005: for (i = 0; i != 5; i++) { tron@1991: *d++ = s[j]; tron@1991: j++; tron@1991: if (j == 5) j = 0; dominik@614: } tron@915: dominik@614: // Glittery water DOS tron@2005: s = (_opt.landscape == LT_CANDY) ? ev->bc : ev->b; tron@1991: j = EXTR(128, 15); tron@2005: for (i = 0; i != 5; i++) { tron@1991: *d++ = s[j]; tron@1991: j += 3; tron@1991: if (j >= 15) j -= 15; dominik@614: } dominik@614: } dominik@614: tron@1991: if (memcmp(old_val, &_cur_palette[217], c * sizeof(*old_val)) != 0) { truelight@0: if (_pal_first_dirty > 217) _pal_first_dirty = 217; tron@1991: if (_pal_last_dirty < 217 + c) _pal_last_dirty = 217 + c; truelight@0: } truelight@0: } truelight@0: truelight@0: tron@1093: void LoadStringWidthTable(void) truelight@0: { tron@2005: byte *b = _stringwidth_table; tron@2005: uint i; truelight@0: truelight@0: // 2 equals space. tron@2005: for (i = 2; i != 226; i++) { tron@2411: *b++ = i != 97 && (i < 99 || i > 113) && i != 116 && i != 117 && (i < 123 || i > 129) && (i < 151 || i > 153) && i != 155 ? GetSprite(i)->width : 0; truelight@0: } truelight@0: tron@2005: for (i = 226; i != 450; i++) { tron@2411: *b++ = i != 321 && (i < 323 || i > 353) && i != 367 && (i < 375 || i > 377) && i != 379 ? GetSprite(i)->width + 1 : 0; truelight@0: } truelight@0: tron@2005: for (i = 450; i != 674; i++) { Darkvater@9939: *b++ = (i < 545 || i > 577) && i != 588 && i != 590 && i != 591 && i != 593 && (i < 599 || i > 601) && i != 603 ? GetSprite(i)->width + 1 : 0; truelight@0: } truelight@0: } truelight@0: tron@1093: void ScreenSizeChanged(void) truelight@0: { truelight@0: // check the dirty rect truelight@0: if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width; truelight@0: if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height; truelight@0: truelight@0: // screen size changed and the old bitmap is invalid now, so we don't want to undraw it truelight@0: _cursor.visible = false; truelight@0: } truelight@0: tron@1093: void UndrawMouseCursor(void) truelight@0: { truelight@0: if (_cursor.visible) { truelight@0: _cursor.visible = false; truelight@0: memcpy_pitch( truelight@0: _screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch, truelight@0: _cursor_backup, truelight@0: _cursor.draw_size.x, _cursor.draw_size.y, _cursor.draw_size.x, _screen.pitch); truelight@193: truelight@0: _video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y); truelight@0: } truelight@0: } truelight@0: tron@1093: void DrawMouseCursor(void) truelight@0: { tron@2010: int x; tron@2010: int y; tron@2010: int w; tron@2010: int h; truelight@0: truelight@0: // Don't draw the mouse cursor if it's already drawn truelight@0: if (_cursor.visible) { tron@2010: if (!_cursor.dirty) return; truelight@0: UndrawMouseCursor(); truelight@0: } truelight@0: truelight@0: w = _cursor.size.x; truelight@0: x = _cursor.pos.x + _cursor.offs.x; tron@2010: if (x < 0) { tron@2010: w += x; tron@2010: x = 0; tron@2010: } tron@2010: if (w > _screen.width - x) w = _screen.width - x; truelight@0: if (w <= 0) return; truelight@0: _cursor.draw_pos.x = x; truelight@0: _cursor.draw_size.x = w; truelight@0: truelight@0: h = _cursor.size.y; truelight@0: y = _cursor.pos.y + _cursor.offs.y; tron@2010: if (y < 0) { tron@2010: h += y; tron@2010: y = 0; tron@2010: } tron@2010: if (h > _screen.height - y) h = _screen.height - y; truelight@0: if (h <= 0) return; truelight@0: _cursor.draw_pos.y = y; truelight@0: _cursor.draw_size.y = h; truelight@0: tron@2010: assert(w * h < (int)sizeof(_cursor_backup)); truelight@0: truelight@0: // Make backup of stuff below cursor truelight@0: memcpy_pitch( truelight@0: _cursor_backup, truelight@0: _screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch, darkvater@306: _cursor.draw_size.x, _cursor.draw_size.y, _screen.pitch, _cursor.draw_size.x); truelight@0: truelight@0: // Draw cursor on screen truelight@0: _cur_dpi = &_screen; truelight@0: DrawSprite(_cursor.sprite, _cursor.pos.x, _cursor.pos.y); truelight@0: truelight@0: _video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y); truelight@0: truelight@0: _cursor.visible = true; truelight@0: _cursor.dirty = false; truelight@0: } truelight@0: darkvater@798: #if defined(_DEBUG) tron@410: static void DbgScreenRect(int left, int top, int right, int bottom) truelight@0: { tron@2010: DrawPixelInfo dp; tron@2010: DrawPixelInfo* old; truelight@0: truelight@0: old = _cur_dpi; truelight@0: _cur_dpi = &dp; truelight@0: dp = _screen; tron@2010: GfxFillRect(left, top, right - 1, bottom - 1, rand() & 255); truelight@0: _cur_dpi = old; truelight@0: } darkvater@798: #endif truelight@0: truelight@0: void RedrawScreenRect(int left, int top, int right, int bottom) truelight@0: { truelight@0: assert(right <= _screen.width && bottom <= _screen.height); truelight@0: if (_cursor.visible) { truelight@0: if (right > _cursor.draw_pos.x && truelight@0: left < _cursor.draw_pos.x + _cursor.draw_size.x && truelight@0: bottom > _cursor.draw_pos.y && truelight@0: top < _cursor.draw_pos.y + _cursor.draw_size.y) { truelight@0: UndrawMouseCursor(); truelight@0: } truelight@0: } truelight@543: UndrawTextMessage(); truelight@0: truelight@0: #if defined(_DEBUG) truelight@0: if (_dbg_screen_rect) truelight@0: DbgScreenRect(left, top, right, bottom); truelight@0: else truelight@0: #endif truelight@0: DrawOverlappedWindowForAll(left, top, right, bottom); truelight@0: tron@2010: _video_driver->make_dirty(left, top, right - left, bottom - top); truelight@0: } truelight@0: tron@1093: void DrawDirtyBlocks(void) truelight@0: { truelight@0: byte *b = _dirty_blocks; tron@2398: const int w = ALIGN(_screen.width, 64); tron@2398: const int h = ALIGN(_screen.height, 8); tron@2025: int x; tron@2025: int y; truelight@0: tron@2025: y = 0; truelight@0: do { tron@2025: x = 0; tron@2025: do { tron@2025: if (*b != 0) { tron@2025: int left; tron@2025: int top; tron@2025: int right = x + 64; tron@2025: int bottom = y; tron@2025: byte *p = b; tron@2025: int h2; truelight@0: tron@2025: // First try coalescing downwards truelight@0: do { tron@2025: *p = 0; tron@2025: p += DIRTY_BYTES_PER_LINE; tron@2025: bottom += 8; tron@2025: } while (bottom != h && *p != 0); truelight@0: tron@2025: // Try coalescing to the right too. tron@2025: h2 = (bottom - y) >> 3; tron@2025: assert(h2 > 0); tron@2025: p = b; truelight@0: tron@2025: while (right != w) { tron@2025: byte *p2 = ++p; tron@2025: int h = h2; tron@2025: // Check if a full line of dirty flags is set. tron@2025: do { tron@2025: if (!*p2) goto no_more_coalesc; tron@2025: p2 += DIRTY_BYTES_PER_LINE; tron@2025: } while (--h != 0); tron@2025: tron@2025: // Wohoo, can combine it one step to the right! tron@2025: // Do that, and clear the bits. tron@2025: right += 64; tron@2025: tron@2025: h = h2; tron@2025: p2 = p; tron@2025: do { tron@2025: *p2 = 0; tron@2025: p2 += DIRTY_BYTES_PER_LINE; tron@2025: } while (--h != 0); tron@2025: } tron@2025: no_more_coalesc: tron@2025: tron@2025: left = x; tron@2025: top = y; tron@2025: tron@2025: if (left < _invalid_rect.left ) left = _invalid_rect.left; tron@2025: if (top < _invalid_rect.top ) top = _invalid_rect.top; tron@2025: if (right > _invalid_rect.right ) right = _invalid_rect.right; tron@2025: if (bottom > _invalid_rect.bottom) bottom = _invalid_rect.bottom; tron@2025: tron@2025: if (left < right && top < bottom) { tron@2025: RedrawScreenRect(left, top, right, bottom); tron@2025: } tron@2025: truelight@0: } tron@2025: } while (b++, (x += 64) != w); tron@2025: } while (b += -(w >> 6) + DIRTY_BYTES_PER_LINE, (y += 8) != h); truelight@0: truelight@0: _invalid_rect.left = w; truelight@0: _invalid_rect.top = h; truelight@0: _invalid_rect.right = 0; truelight@0: _invalid_rect.bottom = 0; truelight@0: } truelight@0: truelight@0: truelight@0: void SetDirtyBlocks(int left, int top, int right, int bottom) truelight@0: { truelight@0: byte *b; tron@2010: int width; tron@2010: int height; truelight@0: truelight@0: if (left < 0) left = 0; truelight@0: if (top < 0) top = 0; truelight@0: if (right > _screen.width) right = _screen.width; truelight@0: if (bottom > _screen.height) bottom = _screen.height; truelight@0: tron@2010: if (left >= right || top >= bottom) return; truelight@0: tron@2010: if (left < _invalid_rect.left ) _invalid_rect.left = left; tron@2010: if (top < _invalid_rect.top ) _invalid_rect.top = top; tron@2010: if (right > _invalid_rect.right ) _invalid_rect.right = right; tron@2010: if (bottom > _invalid_rect.bottom) _invalid_rect.bottom = bottom; truelight@0: truelight@0: left >>= 6; tron@2010: top >>= 3; truelight@0: truelight@0: b = _dirty_blocks + top * DIRTY_BYTES_PER_LINE + left; truelight@0: tron@2010: width = ((right - 1) >> 6) - left + 1; tron@2010: height = ((bottom - 1) >> 3) - top + 1; truelight@0: truelight@0: assert(width > 0 && height > 0); truelight@0: truelight@0: do { tron@2010: int i = width; tron@2010: truelight@0: do b[--i] = 0xFF; while (i); truelight@0: truelight@0: b += DIRTY_BYTES_PER_LINE; tron@2010: } while (--height != 0); truelight@0: } truelight@0: tron@1093: void MarkWholeScreenDirty(void) truelight@0: { truelight@0: SetDirtyBlocks(0, 0, _screen.width, _screen.height); truelight@0: } truelight@0: tron@2548: bool FillDrawPixelInfo(DrawPixelInfo* n, const DrawPixelInfo* o, int left, int top, int width, int height) truelight@0: { truelight@0: int t; truelight@0: tron@2010: if (o == NULL) o = _cur_dpi; truelight@0: truelight@0: n->zoom = 0; truelight@0: truelight@0: assert(width > 0); truelight@0: assert(height > 0); truelight@0: truelight@0: n->left = 0; truelight@0: if ((left -= o->left) < 0) { tron@2010: width += left; tron@2010: if (width < 0) return false; truelight@0: n->left = -left; truelight@0: left = 0; truelight@0: } truelight@0: truelight@0: if ((t=width + left - o->width) > 0) { tron@2010: width -= t; tron@2010: if (width < 0) return false; truelight@0: } truelight@0: n->width = width; truelight@0: truelight@0: n->top = 0; truelight@0: if ((top -= o->top) < 0) { tron@2010: height += top; tron@2010: if (height < 0) return false; truelight@0: n->top = -top; truelight@0: top = 0; truelight@0: } truelight@0: truelight@0: n->dst_ptr = o->dst_ptr + left + top * (n->pitch = o->pitch); truelight@0: truelight@0: if ((t=height + top - o->height) > 0) { tron@2010: height -= t; tron@2010: if (height < 0) return false; truelight@0: } truelight@0: n->height = height; truelight@0: truelight@0: return true; truelight@0: } truelight@0: Darkvater@1914: static void SetCursorSprite(CursorID cursor) truelight@0: { truelight@0: CursorVars *cv = &_cursor; tron@1348: const Sprite *p; truelight@0: tron@2010: if (cv->sprite == cursor) return; truelight@0: celestar@2187: p = GetSprite(cursor & SPRITE_MASK); truelight@0: cv->sprite = cursor; tron@1348: cv->size.y = p->height; tron@1351: cv->size.x = p->width; tron@1351: cv->offs.x = p->x_offs; tron@1351: cv->offs.y = p->y_offs; truelight@0: truelight@0: cv->dirty = true; truelight@0: } truelight@0: tron@1093: static void SwitchAnimatedCursor(void) truelight@0: { truelight@0: CursorVars *cv = &_cursor; Darkvater@1914: const CursorID *cur = cv->animate_cur; Darkvater@1914: CursorID sprite; truelight@0: Darkvater@1914: // ANIM_CURSOR_END is 0xFFFF in table/animcursors.h Darkvater@1914: if (cur == NULL || *cur == 0xFFFF) cur = cv->animate_list; Darkvater@1914: truelight@0: sprite = cur[0]; truelight@0: cv->animate_timeout = cur[1]; truelight@0: cv->animate_cur = cur + 2; truelight@0: truelight@0: SetCursorSprite(sprite); truelight@0: } truelight@0: tron@1093: void CursorTick(void) tron@1093: { tron@2010: if (_cursor.animate_timeout != 0 && --_cursor.animate_timeout == 0) truelight@0: SwitchAnimatedCursor(); truelight@0: } truelight@0: Darkvater@1914: void SetMouseCursor(CursorID cursor) truelight@0: { truelight@0: // Turn off animation truelight@0: _cursor.animate_timeout = 0; truelight@0: // Set cursor truelight@0: SetCursorSprite(cursor); truelight@0: } truelight@0: Darkvater@1914: void SetAnimatedMouseCursor(const CursorID *table) truelight@0: { truelight@0: _cursor.animate_list = table; truelight@0: _cursor.animate_cur = NULL; truelight@0: SwitchAnimatedCursor(); truelight@0: } truelight@0: truelight@0: bool ChangeResInGame(int w, int h) truelight@193: { tron@2645: return tron@2645: (_screen.width == w && _screen.height == h) || tron@2645: _video_driver->change_resolution(w, h); truelight@0: } darkvater@298: Darkvater@1829: void ToggleFullScreen(bool fs) {_video_driver->toggle_fullscreen(fs);} Darkvater@1829: Darkvater@1806: static int CDECL compare_res(const void *pa, const void *pb) darkvater@298: { Darkvater@1806: int x = ((const uint16*)pa)[0] - ((const uint16*)pb)[0]; Darkvater@1806: if (x != 0) return x; Darkvater@1806: return ((const uint16*)pa)[1] - ((const uint16*)pb)[1]; Darkvater@1806: } Darkvater@1806: Darkvater@1806: void SortResolutions(int count) Darkvater@1806: { Darkvater@1806: qsort(_resolutions, count, sizeof(_resolutions[0]), compare_res); darkvater@298: } truelight@543: Darkvater@2436: uint16 GetDrawStringPlayerColor(PlayerID player) truelight@543: { truelight@543: // Get the color for DrawString-subroutines which matches the color truelight@543: // of the player tron@2639: if (player == OWNER_SPECTATOR || player == OWNER_SPECTATOR - 1) return 1; dominik@657: return (_color_list[_player_colors[player]].window_color_1b) | IS_PALETTE_COLOR; truelight@543: }