truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@1349: #include "spritecache.h" tron@1309: #include "strings.h" truelight@0: #include "gfx.h" truelight@0: #include "table/palettes.h" truelight@0: #include "hal.h" truelight@0: 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; truelight@0: static byte _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: truelight@0: #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: truelight@0: void GfxScroll(int left, int top, int width, int height, int xo, int yo) { truelight@0: byte *src, *dst; truelight@0: int p; truelight@0: int ht; truelight@0: truelight@0: if (xo == 0 && yo == 0) truelight@0: return; truelight@0: truelight@0: if (_cursor.visible) truelight@0: 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: truelight@0: void GfxFillRect(int left, int top, int right, int bottom, int color) { truelight@0: DrawPixelInfo *dpi = _cur_dpi; tron@1357: byte *dst; tron@332: const int otop = top; tron@332: const int oleft = left; truelight@0: truelight@0: if (dpi->zoom != 0) truelight@0: return; truelight@0: truelight@0: if (left > right || top > bottom) truelight@0: return; truelight@0: truelight@0: if (right < dpi->left || left >= dpi->left + dpi->width) truelight@0: return; truelight@0: truelight@0: if (bottom < dpi->top || top >= dpi->top + dpi->height) truelight@0: return; truelight@0: truelight@0: if ( (left -= dpi->left) < 0) left = 0; truelight@0: right = right - dpi->left + 1; truelight@0: 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; truelight@0: 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: truelight@0: if (!(color & 0x8000)) { truelight@0: if (!(color & 0x4000)) { 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 */ tron@1357: const byte* ctab = GetNonSprite(color & 0x3FFF) + 1; tron@1357: truelight@0: do { truelight@0: int i; truelight@0: for(i=0; i!=right;i++) truelight@0: 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@332: for (i = (bo ^= 1); i < right; i += 2) tron@332: 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: { truelight@0: DrawPixelInfo *dpi = _cur_dpi; truelight@0: if ((x-=dpi->left) < 0 || x>=dpi->width || (y-=dpi->top)<0 || y>=dpi->height) truelight@0: return; truelight@0: 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; truelight@0: int stepx, 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: truelight@0: if (x < dpi->left && x2 < dpi->left) truelight@0: return; truelight@0: truelight@0: if (y < dpi->top && y2 < dpi->top) truelight@0: return; truelight@0: truelight@0: t = dpi->left + dpi->width; truelight@0: if (x > t && x2 > t) truelight@0: return; truelight@0: truelight@0: t = dpi->top + dpi->height; truelight@0: if (y > t && y2 > t) truelight@0: return; truelight@0: } truelight@0: truelight@0: dy = (y2 - y) * 2; truelight@0: if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } truelight@0: truelight@0: dx = (x2 - x) * 2; truelight@0: if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } 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: truelight@0: truelight@0: /* returns right coordinate */ truelight@543: int DrawString(int x, int y, uint16 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: truelight@0: truelight@543: void DrawStringRightAligned(int x, int y, uint16 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: truelight@0: truelight@543: int DrawStringCentered(int x, int y, uint16 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: truelight@543: void DrawStringCenterUnderline(int x, int y, uint16 str, uint16 color) truelight@0: { truelight@0: int w = DrawStringCentered(x, y, str, color); truelight@0: GfxFillRect(x-(w>>1), y+10, x-(w>>1)+w, y+10, _string_colorremap[1]); truelight@0: } truelight@0: 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++; truelight@0: str[-1] = 0; truelight@0: } truelight@0: } truelight@0: truelight@0: truelight@0: void DrawStringMultiCenter(int x, int y, uint16 str, int maxw) truelight@0: { tron@1336: char buffer[512]; truelight@0: uint32 tmp; truelight@0: int num, w, mt, t; tron@1323: const char *src; truelight@0: byte c; truelight@0: tron@1336: GetString(buffer, str); truelight@0: tron@1336: tmp = FormatStringLinebreaks(buffer, maxw); truelight@0: num = (uint16)tmp; truelight@0: t = tmp >> 16; truelight@0: truelight@0: mt = 10; truelight@0: if (t != 0) { truelight@0: mt = 6; truelight@0: if (t != 244) mt = 18; 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: truelight@0: void DrawStringMultiLine(int x, int y, uint16 str, int maxw) { tron@1336: char buffer[512]; truelight@0: uint32 tmp; truelight@0: int num, w, mt, t; tron@1323: const char *src; truelight@0: byte c; truelight@0: tron@1336: GetString(buffer, str); truelight@0: tron@1336: tmp = FormatStringLinebreaks(buffer, maxw); truelight@0: num = (uint16)tmp; truelight@0: t = tmp >> 16; truelight@0: mt = 10; truelight@0: if (t != 0) { truelight@0: mt = 6; truelight@0: if (t != 244) mt = 18; truelight@0: } truelight@0: tron@1336: src = buffer; truelight@0: truelight@0: for(;;) { truelight@0: w = GetStringWidth(src); 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: truelight@0: void DrawFrameRect(int left, int top, int right, int bottom, int ctab, int flags) { 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: truelight@0: if (!(flags & 0x8)) { truelight@0: if (!(flags & 0x20)) { truelight@0: GfxFillRect(left, top, left, bottom-1, color); truelight@0: GfxFillRect(left+1, top, right-1, top, color); truelight@0: GfxFillRect(right, top, right, bottom-1, color_2); truelight@0: GfxFillRect(left, bottom, right, bottom, color_2); truelight@0: if (!(flags & 0x10)) { truelight@0: 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); truelight@0: GfxFillRect(left+1, top, right, top, color_2); truelight@0: GfxFillRect(right, top+1, right, bottom-1, color); truelight@0: GfxFillRect(left+1, bottom, right, bottom, color); truelight@0: if (!(flags & 0x10)) { truelight@0: GfxFillRect(left+1, top+1, right-1, bottom-1, truelight@0: flags&0x40 ? color_interior : color_3); truelight@0: } truelight@0: } truelight@0: } else if (flags & 0x1) { truelight@0: // transparency truelight@0: GfxFillRect(left, top, right, bottom, 0x4322); 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: truelight@0: void DrawSprite(uint32 img, int x, int y) { truelight@0: if (img & 0x8000) { tron@1350: _color_remap_ptr = GetNonSprite(img >> 16) + 1; tron@1350: GfxMainBlitter(GetSprite(img & 0x3FFF), x, y, 1); truelight@0: } else if (img & 0x4000) { tron@1350: _color_remap_ptr = GetNonSprite(img >> 16) + 1; tron@1350: GfxMainBlitter(GetSprite(img & 0x3FFF), x, y, 2); truelight@0: } else { tron@1350: GfxMainBlitter(GetSprite(img & 0x3FFF), 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; truelight@0: byte *dst; truelight@0: int mode; truelight@0: int width, height; truelight@0: int width_org, 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@1357: byte *dst; tron@1357: const byte* ctab; truelight@0: truelight@0: if (bp->mode & 1) { truelight@0: src_o += READ_LE_UINT16(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; truelight@0: if (num <= 0) truelight@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; truelight@0: if (num <= 0) truelight@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; truelight@0: } while (--bp->height); truelight@0: } else if (bp->mode & 2) { truelight@0: src_o += READ_LE_UINT16(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; truelight@0: if (num <= 0) truelight@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; truelight@0: if (num <= 0) truelight@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; truelight@0: } while (--bp->height); truelight@0: truelight@0: } else { truelight@0: src_o += READ_LE_UINT16(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; truelight@0: if (num <= 0) truelight@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; truelight@0: if (num <= 0) truelight@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; truelight@0: } while (--num); 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; truelight@0: } while (--bp->height); truelight@0: } truelight@0: } truelight@0: truelight@0: static void GfxBlitZoomInUncomp(BlitterParams *bp) truelight@0: { tron@1357: const byte *src = bp->sprite; truelight@0: byte *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; truelight@0: } while (--height); 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; truelight@0: } while (--height); 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; truelight@0: } while (--height); 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; truelight@0: } while (--height); 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@1357: byte *dst; tron@1357: const byte* ctab; truelight@0: truelight@0: if (bp->mode & 1) { truelight@0: src_o += READ_LE_UINT16(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; truelight@0: if (num <= 0) truelight@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; truelight@0: if (num <= 0) truelight@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)); truelight@0: } while (--bp->height); truelight@0: } else if (bp->mode & 2) { truelight@0: src_o += READ_LE_UINT16(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; truelight@0: if (num <= 0) truelight@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; truelight@0: if (num <= 0) truelight@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)); truelight@0: } while (--bp->height); truelight@0: truelight@0: } else { truelight@0: src_o += READ_LE_UINT16(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; truelight@0: if (num <= 0) truelight@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; truelight@0: if (num <= 0) truelight@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)); truelight@0: truelight@0: } while (--bp->height); truelight@0: } truelight@0: } truelight@0: truelight@0: static void GfxBlitZoomMediumUncomp(BlitterParams *bp) truelight@0: { tron@1357: const byte *src = bp->sprite; truelight@0: byte *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@1357: byte *dst; tron@1357: const byte* ctab; truelight@0: truelight@0: if (bp->mode & 1) { truelight@0: src_o += READ_LE_UINT16(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) { truelight@0: src_o += READ_LE_UINT16(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 { truelight@0: src_o += READ_LE_UINT16(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; truelight@0: byte *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: { truelight@0: DrawPixelInfo *dpi = _cur_dpi; truelight@0: int start_x, start_y; truelight@0: byte info; truelight@0: BlitterParams bp; truelight@0: 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) { truelight@0: start_y += bp.height &~ zoom_mask; truelight@193: bp.height &= zoom_mask; truelight@0: if (bp.height == 0) return; truelight@0: y&=zoom_mask; truelight@0: } truelight@0: truelight@0: if ( (y -= dpi->top) < 0) { truelight@0: if ((bp.height += y) <= 0) truelight@0: return; truelight@0: start_y -= y; truelight@0: y = 0; truelight@0: } else { truelight@0: 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) { truelight@0: if ( (bp.height -= y) <= 0) truelight@0: return; truelight@0: } truelight@0: truelight@0: start_x = 0; truelight@0: x &= zoom_mask; truelight@0: if ( (x -= dpi->left) < 0) { truelight@0: if ((bp.width += x) <= 0) truelight@0: return; truelight@0: start_x -= x; truelight@0: x = 0; truelight@0: } truelight@0: bp.start_x = start_x; truelight@0: bp.dst += x>>(dpi->zoom); truelight@0: truelight@0: if ( (x = x + bp.width - dpi->width) > 0) { truelight@0: if ( (bp.width -= x) <= 0) truelight@0: return; truelight@0: } truelight@0: truelight@0: zf_tile[dpi->zoom](&bp); truelight@0: } else { truelight@0: truelight@0: bp.sprite += bp.width * (bp.height & ~zoom_mask); truelight@0: bp.height &= zoom_mask; truelight@0: if (bp.height == 0) truelight@0: return; truelight@0: truelight@0: y &= zoom_mask; truelight@0: truelight@0: if ( (y -= dpi->top) < 0) { truelight@0: if ((bp.height += y) <= 0) truelight@0: return; truelight@0: bp.sprite -= bp.width * y; truelight@0: y = 0; truelight@0: } else { truelight@0: bp.dst += bp.pitch * (y>>(dpi->zoom)); truelight@0: } truelight@0: truelight@0: if ( (y = y + bp.height - dpi->height) > 0) { truelight@0: if ( (bp.height -= y) <= 0) truelight@0: return; truelight@0: } truelight@0: truelight@0: start_x = 0; truelight@0: truelight@0: x &= zoom_mask; truelight@0: truelight@0: if ( (x -= dpi->left) < 0) { truelight@0: if ((bp.width += x) <= 0) truelight@0: return; truelight@0: start_x -= x; truelight@0: bp.sprite -= x; truelight@0: x = 0; truelight@0: } truelight@0: bp.dst += x>>(dpi->zoom); truelight@0: truelight@0: if ( (x = x + bp.width - dpi->width) > 0) { truelight@0: if ( (bp.width -= x) <= 0) truelight@0: return; truelight@0: start_x += x; truelight@0: } truelight@0: bp.start_x = start_x; truelight@0: truelight@0: if (info&2) { truelight@0: int totpix = bp.height_org * bp.width_org; truelight@0: byte *dst = (byte*)alloca(totpix); tron@1357: const byte *src = bp.sprite_org; truelight@0: pasky@461: bp.sprite = dst + (bp.sprite - bp.sprite_org); truelight@0: truelight@0: while (totpix != 0) { tron@2004: signed char b; tron@2004: truelight@0: assert(totpix > 0); tron@2004: truelight@0: b = *src++; truelight@0: if (b >= 0) { tron@2004: uint count = b; tron@2004: uint i; tron@2004: tron@2004: for (i = 0; i != count; i++) dst[i] = src[i]; truelight@0: dst += count; truelight@0: src += count; truelight@0: totpix -= count; truelight@0: } else { tron@2004: const byte *tmp = dst - (((b & 7) << 8) | *src++); tron@2004: uint count = -(b >> 3); tron@2004: uint i; truelight@0: tron@2004: for (i = 0; i != count; i++) dst[i] = tmp[i]; truelight@0: dst += count; truelight@0: totpix -= count; truelight@0: } truelight@0: } truelight@0: } truelight@0: zf_uncomp[dpi->zoom](&bp); truelight@0: } truelight@0: } truelight@0: darkvater@798: #if 0 tron@410: static void GfxScalePalette(int pal, byte scaling) truelight@0: { tron@1991: const Colour* src; tron@1991: uint i; truelight@0: truelight@0: GfxInitPalettes(); truelight@0: truelight@0: src = GET_PALETTE(pal); tron@1991: for (i = 0; i < lengthof(_cur_palette); i++) { tron@1991: _cur_palette[i].r = src[i].r * scaling >> 8; tron@1991: _cur_palette[i].g = src[i].g * scaling >> 8; tron@1991: _cur_palette[i].b = src[i].b * scaling >> 8; tron@1991: } truelight@0: } darkvater@798: #endif 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: truelight@0: #define EXTR(p,q) (((uint16)(_timer_counter * (p)) * (q)) >> 16) truelight@0: #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. */ tron@915: int c = _use_dos_palette?38:28; truelight@0: int j; truelight@0: int i; truelight@0: const ExtraPaletteValues *ev = &_extra_palette_values; tron@1991: Colour old_val[38]; // max(38, 28) 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 truelight@0: s = ev->a; truelight@0: if (_opt.landscape == LT_CANDY) s = ev->ac; tron@1991: j = EXTR(320,5); truelight@0: 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 truelight@0: s = ev->b; truelight@0: if (_opt.landscape == LT_CANDY) s = ev->bc; tron@1991: j = EXTR(128, 15); truelight@0: 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); truelight@0: 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); truelight@0: 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: { truelight@0: byte i,v; truelight@0: i = (_timer_counter >> 1) & 0x7F; 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); truelight@0: 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 dominik@614: if(_use_dos_palette) { dominik@614: // Dark blue water DOS dominik@614: s = ev->a; dominik@614: if (_opt.landscape == LT_CANDY) s = ev->ac; tron@1991: j = EXTR(320,5); dominik@614: 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 dominik@614: s = ev->b; dominik@614: if (_opt.landscape == LT_CANDY) s = ev->bc; tron@1991: j = EXTR(128, 15); dominik@614: 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: { truelight@0: int i; truelight@0: byte *b; truelight@0: truelight@0: b = _stringwidth_table; truelight@0: truelight@0: // 2 equals space. truelight@0: for(i=2; i != 0xE2; i++) { tron@1351: *b++ = (byte)((i < 93 || i >= 129 || i == 98) ? GetSprite(i)->width : 0); truelight@0: } truelight@0: truelight@0: for(i=0xE2; i != 0x1C2; i++) { tron@1351: *b++ = (byte)((i < 317 || i >= 353) ? GetSprite(i)->width + 1 : 0); truelight@0: } truelight@0: truelight@0: for(i=0x1C2; i != 0x2A2; i++) { tron@1351: *b++ = (byte)((i < 541 || i >= 577) ? 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: { truelight@0: int x,y,w,h; truelight@0: truelight@0: // Don't draw the mouse cursor if it's already drawn truelight@0: if (_cursor.visible) { truelight@0: if (!_cursor.dirty) truelight@0: return; truelight@0: UndrawMouseCursor(); truelight@0: } truelight@0: truelight@0: w = _cursor.size.x; truelight@0: x = _cursor.pos.x + _cursor.offs.x; truelight@0: if (x < 0) { w += x; x=0; } truelight@0: 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; truelight@0: if (y < 0) { h += y; y=0; } truelight@0: 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: dominik@1130: 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: { truelight@0: DrawPixelInfo dp,*old; truelight@0: truelight@0: old = _cur_dpi; truelight@0: _cur_dpi = &dp; truelight@0: dp = _screen; truelight@0: GfxFillRect(left, top, right-1, bottom-1, rand() & 255); truelight@0: _cur_dpi = old; truelight@0: } darkvater@798: #endif truelight@0: truelight@0: extern bool _dbg_screen_rect; 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: truelight@0: _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; truelight@0: int x=0,y=0; darkvater@306: const int w = (_screen.width + 63) & ~63; darkvater@306: const int h = (_screen.height + 7) & ~7; truelight@0: truelight@0: do { truelight@0: if (*b != 0) { truelight@0: int left,top; truelight@0: int right = x + 64; truelight@0: int bottom = y; truelight@0: byte *p = b; truelight@0: int h2; truelight@0: // First try coalescing downwards truelight@0: do { truelight@0: *p = 0; truelight@0: p += DIRTY_BYTES_PER_LINE; truelight@0: bottom += 8; truelight@0: } while (bottom != h && *p); truelight@0: truelight@0: // Try coalescing to the right too. truelight@0: h2 = (bottom - y) >> 3; truelight@0: assert(h2>0); truelight@0: p = b; truelight@0: truelight@0: while (right != w) { truelight@0: byte *p2 = ++p; truelight@0: int h = h2; truelight@0: // Check if a full line of dirty flags is set. truelight@0: do { truelight@0: if (!*p2) goto no_more_coalesc; truelight@0: p2 += DIRTY_BYTES_PER_LINE; truelight@0: } while (--h); truelight@0: truelight@0: // Wohoo, can combine it one step to the right! truelight@0: // Do that, and clear the bits. truelight@0: right += 64; truelight@0: truelight@0: h = h2; truelight@0: p2 = p; truelight@0: do { truelight@0: *p2 = 0; truelight@0: p2 += DIRTY_BYTES_PER_LINE; truelight@0: } while (--h); truelight@0: } truelight@0: no_more_coalesc:; truelight@0: truelight@0: left = x; truelight@0: top = y; truelight@0: truelight@0: if (left < _invalid_rect.left)left = _invalid_rect.left; truelight@0: if (top < _invalid_rect.top) top = _invalid_rect.top; truelight@0: if (right > _invalid_rect.right)right = _invalid_rect.right; truelight@0: if (bottom > _invalid_rect.bottom)bottom = _invalid_rect.bottom; truelight@0: truelight@0: if (left < right && top < bottom) { truelight@0: RedrawScreenRect(left, top, right, bottom); truelight@0: } truelight@0: truelight@0: } truelight@0: } while (b++, (x+=64) != w || (x=0,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; truelight@0: int width,height,i; 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: truelight@0: if (left >= right || top >= bottom) truelight@0: return; truelight@0: truelight@0: if (left < _invalid_rect.left) _invalid_rect.left = left; truelight@0: if (top < _invalid_rect.top) _invalid_rect.top = top; truelight@0: if (right > _invalid_rect.right)_invalid_rect.right = right; truelight@0: if (bottom > _invalid_rect.bottom)_invalid_rect.bottom = bottom; truelight@0: truelight@0: left >>= 6; truelight@0: top >>= 3; truelight@0: truelight@0: b = _dirty_blocks + top * DIRTY_BYTES_PER_LINE + left; truelight@0: truelight@0: width = ((right-1) >> 6) - left + 1; truelight@0: height = ((bottom-1) >> 3) - top + 1; truelight@0: truelight@0: assert(width > 0 && height > 0); truelight@0: truelight@0: do { truelight@0: i=width; truelight@0: do b[--i] = 0xFF; while (i); truelight@0: truelight@0: b += DIRTY_BYTES_PER_LINE; truelight@0: } while (--height); truelight@0: } truelight@0: tron@1093: void MarkWholeScreenDirty(void) truelight@0: { truelight@0: SetDirtyBlocks(0, 0, _screen.width, _screen.height); truelight@0: } truelight@0: truelight@0: bool FillDrawPixelInfo(DrawPixelInfo *n, DrawPixelInfo *o, int left, int top, int width, int height) truelight@0: { truelight@0: int t; truelight@0: truelight@0: if (o == NULL) truelight@0: 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) { truelight@0: if ((width += left) < 0) truelight@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) { truelight@0: if ((width -= t) < 0) truelight@0: return false; truelight@0: } truelight@0: n->width = width; truelight@0: truelight@0: n->top = 0; truelight@0: if ((top -= o->top) < 0) { truelight@0: if ((height += top) < 0) truelight@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) { truelight@0: if ((height-=t) < 0) truelight@0: return false; truelight@0: } truelight@0: n->height = height; truelight@0: 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: truelight@0: if (cv->sprite == cursor) truelight@0: return; truelight@0: tron@1350: p = GetSprite(cursor & 0x3FFF); 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: { truelight@0: CursorVars *cv = &_cursor; truelight@0: if (cv->animate_timeout && !--cv->animate_timeout) 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: { truelight@0: if ((_screen.width != w || _screen.height != h) && !_video_driver->change_resolution(w, h)) truelight@193: return false; truelight@0: truelight@0: _cur_resolution[0] = w; truelight@0: _cur_resolution[1] = h; truelight@0: return true; 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: truelight@543: uint16 GetDrawStringPlayerColor(byte player) truelight@543: { truelight@543: // Get the color for DrawString-subroutines which matches the color truelight@543: // of the player truelight@543: if (player == OWNER_SPECTATOR || player == OWNER_SPECTATOR - 1) truelight@543: return 1; dominik@657: return (_color_list[_player_colors[player]].window_color_1b) | IS_PALETTE_COLOR; truelight@543: }