src/gfx.cpp
branchNewGRF_ports
changeset 6870 ca3fd1fbe311
parent 6868 7eb395287b3d
child 6871 5a9dc001e1ad
--- 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);