--- a/src/gfx.cpp Thu Sep 06 19:42:48 2007 +0000
+++ b/src/gfx.cpp Sat Oct 06 21:16:00 2007 +0000
@@ -43,11 +43,19 @@
Colour _cur_palette[256];
byte _stringwidth_table[FS_END][224];
-static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode);
+static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL);
FontSize _cur_fontsize;
static FontSize _last_fontsize;
static uint8 _cursor_backup[64 * 64 * 4];
+
+/**
+ * The rect for repaint.
+ *
+ * This rectangle defines the area which should be repaint by the video driver.
+ *
+ * @ingroup dirty
+ */
static Rect _invalid_rect;
static const byte *_color_remap_ptr;
static byte _string_colorremap[3];
@@ -131,6 +139,71 @@
blitter->DrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, color);
}
+void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int color)
+{
+ Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
+ DrawPixelInfo *dpi = _cur_dpi;
+
+ x -= dpi->left;
+ x2 -= dpi->left;
+ y -= dpi->top;
+ y2 -= dpi->top;
+
+ /* Check clipping */
+ if (x < 0 && x2 < 0) return;
+ if (y < 0 && y2 < 0) return;
+ if (x > dpi->width && x2 > dpi->width) return;
+ if (y > dpi->height && y2 > dpi->height) return;
+
+ blitter->DrawLine(dpi->dst_ptr, UnScaleByZoom(x, dpi->zoom), UnScaleByZoom(y, dpi->zoom),
+ UnScaleByZoom(x2, dpi->zoom), UnScaleByZoom(y2, dpi->zoom),
+ UnScaleByZoom(dpi->width, dpi->zoom), UnScaleByZoom(dpi->height, dpi->zoom), color);
+}
+
+/**
+ * Draws the projection of a parallelepiped.
+ * This can be used to draw boxes in world coordinates.
+ *
+ * @param x Screen X-coordinate of top front corner.
+ * @param y Screen Y-coordinate of top front corner.
+ * @param dx1 Screen X-length of first edge.
+ * @param dy1 Screen Y-length of first edge.
+ * @param dx2 Screen X-length of second edge.
+ * @param dy2 Screen Y-length of second edge.
+ * @param dx3 Screen X-length of third edge.
+ * @param dy3 Screen Y-length of third edge.
+ */
+void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
+{
+ /* ....
+ * .. ....
+ * .. ....
+ * .. ^
+ * <--__(dx1,dy1) /(dx2,dy2)
+ * : --__ / :
+ * : --__ / :
+ * : *(x,y) :
+ * : | :
+ * : | ..
+ * .... |(dx3,dy3)
+ * .... | ..
+ * ....V.
+ */
+
+ static const byte color = 255;
+
+ GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, color);
+ GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, color);
+ GfxDrawLineUnscaled(x, y, x + dx3, y + dy3, color);
+
+ GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, color);
+ GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, color);
+ GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, color);
+ GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, color);
+ GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, color);
+ GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, color);
+}
+
/** Truncate a given string to a maximum width if neccessary.
* If the string is truncated, add three dots ('...') to show this.
@@ -269,7 +342,8 @@
GfxFillRect((xl + xr - w) / 2, y + 10, (xl + xr + w) / 2, y + 10, _string_colorremap[1]);
}
-/** 'Correct' a string to a maximum length. Longer strings will be cut into
+/**
+ * 'Correct' a string to a maximum length. Longer strings will be cut into
* additional lines at whitespace characters if possible. The string parameter
* is modified with terminating characters mid-string which are the
* placeholders for the newlines.
@@ -284,7 +358,8 @@
* @param maxw the maximum width the string can have on one line
* @return return a 32bit wide number consisting of 2 packed values:
* 0 - 15 the number of lines ADDED to the string
- * 16 - 31 the fontsize in which the length calculation was done at */
+ * 16 - 31 the fontsize in which the length calculation was done at
+ */
uint32 FormatStringLinebreaks(char *str, int maxw)
{
FontSize size = _cur_fontsize;
@@ -577,24 +652,33 @@
return DoDrawString(buffer, x, y, color);
}
-void DrawSprite(SpriteID img, SpriteID pal, int x, int y)
+void DrawSprite(SpriteID img, SpriteID pal, int x, int y, const SubSprite *sub)
{
if (HASBIT(img, PALETTE_MODIFIER_TRANSPARENT)) {
_color_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH)) + 1;
- GfxMainBlitter(GetSprite(GB(img, 0, SPRITE_WIDTH)), x, y, BM_TRANSPARENT);
+ GfxMainBlitter(GetSprite(GB(img, 0, SPRITE_WIDTH)), x, y, BM_TRANSPARENT, sub);
} else if (pal != PAL_NONE) {
_color_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH)) + 1;
- GfxMainBlitter(GetSprite(GB(img, 0, SPRITE_WIDTH)), x, y, BM_COLOUR_REMAP);
+ GfxMainBlitter(GetSprite(GB(img, 0, SPRITE_WIDTH)), x, y, BM_COLOUR_REMAP, sub);
} else {
- GfxMainBlitter(GetSprite(GB(img, 0, SPRITE_WIDTH)), x, y, BM_NORMAL);
+ GfxMainBlitter(GetSprite(GB(img, 0, SPRITE_WIDTH)), x, y, BM_NORMAL, sub);
}
}
-static inline void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode)
+static inline void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub)
{
const DrawPixelInfo *dpi = _cur_dpi;
Blitter::BlitterParams bp;
+ /* Amount of pixels to clip from the source sprite */
+ int clip_left = (sub != NULL ? max(0, -sprite->x_offs + sub->left ) : 0);
+ int clip_top = (sub != NULL ? max(0, -sprite->y_offs + sub->top ) : 0);
+ int clip_right = (sub != NULL ? max(0, sprite->width - (-sprite->x_offs + sub->right + 1)) : 0);
+ int clip_bottom = (sub != NULL ? max(0, sprite->height - (-sprite->y_offs + sub->bottom + 1)) : 0);
+
+ if (clip_left + clip_right >= sprite->width) return;
+ if (clip_top + clip_bottom >= sprite->height) return;
+
/* Move to the correct offset */
x += sprite->x_offs;
y += sprite->y_offs;
@@ -603,12 +687,16 @@
bp.sprite = sprite->data;
bp.sprite_width = sprite->width;
bp.sprite_height = sprite->height;
- bp.width = UnScaleByZoom(sprite->width, dpi->zoom);
- bp.height = UnScaleByZoom(sprite->height, dpi->zoom);
+ bp.width = UnScaleByZoom(sprite->width - clip_left - clip_right, dpi->zoom);
+ bp.height = UnScaleByZoom(sprite->height - clip_top - clip_bottom, dpi->zoom);
bp.top = 0;
bp.left = 0;
- bp.skip_left = 0;
- bp.skip_top = 0;
+ bp.skip_left = UnScaleByZoom(clip_left, dpi->zoom);
+ bp.skip_top = UnScaleByZoom(clip_top, dpi->zoom);
+
+ x += ScaleByZoom(bp.skip_left, dpi->zoom);
+ y += ScaleByZoom(bp.skip_top, dpi->zoom);
+
bp.dst = dpi->dst_ptr;
bp.pitch = dpi->pitch;
bp.remap = _color_remap_ptr;
@@ -919,6 +1007,11 @@
_video_driver->MakeDirty(left, top, right - left, bottom - top);
}
+/*!
+ * Repaints the rectangle blocks which are marked as 'dirty'.
+ *
+ * @see SetDirtyBlocks
+ */
void DrawDirtyBlocks()
{
byte *b = _dirty_blocks;
@@ -1003,7 +1096,21 @@
}
}
-
+/*!
+ * This function extends the internal _invalid_rect rectangle as it
+ * now contains the rectangle defined by the given parameters. Note
+ * the point (0,0) is top left.
+ *
+ * @param left The left edge of the rectangle
+ * @param top The top edge of the rectangle
+ * @param right The right edge of the rectangle
+ * @param bottom The bottm edge of the rectangle
+ * @see DrawDirtyBlocks
+ *
+ * @todo The name of the function should be called like @c AddDirtyBlock as
+ * it neither set a dirty rect nor add several dirty rects although
+ * the function name is in plural. (Progman)
+ */
void SetDirtyBlocks(int left, int top, int right, int bottom)
{
byte *b;
@@ -1041,6 +1148,11 @@
} while (--height != 0);
}
+/*!
+ * This function mark the whole screen as dirty. This results in repainting
+ * the whole screen. Use this with care as this function will break the
+ * idea about marking only parts of the screen as 'dirty'.
+ */
void MarkWholeScreenDirty()
{
SetDirtyBlocks(0, 0, _screen.width, _screen.height);