From ed95053221960709a4fe2363fa77c8d8d2d2a2ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= <superstippi@gmx.de>
Date: Fri, 25 Feb 2011 08:34:18 +0000
Subject: [PATCH] Applied patch by John Scipione that adds the scale2x
 algorithm to BIconUtils and uses it when old B_CMAP8 icons are to be upscaled
 exactly 2x. Looks much better than the previous blurry bilinear scaling.
 Small cleanups by myself, closes #7130, thanks a lot!

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40678 a95241bf-73f2-0310-859d-f6bbb57e9c96
---
 src/libs/icon/IconUtils.cpp | 77 +++++++++++++++++++++++++++++++------
 1 file changed, 65 insertions(+), 12 deletions(-)

diff --git a/src/libs/icon/IconUtils.cpp b/src/libs/icon/IconUtils.cpp
index 83a99f384b..c67a64e7b0 100644
--- a/src/libs/icon/IconUtils.cpp
+++ b/src/libs/icon/IconUtils.cpp
@@ -1,10 +1,11 @@
 /*
- * Copyright 2006-2008, Haiku. All rights reserved.
+ * Copyright 2006-2011, Haiku. All rights reserved.
  * Distributed under the terms of the MIT License.
  *
  * Authors:
  *		Stephan Aßmus <superstippi@gmx.de>
  *		Ingo Weinhold <bonefish@cs.tu-berlin.de>
+ * 		John Scipione <jscipione@gmail.com>
  */
 
 
@@ -100,6 +101,50 @@ scale_bilinear(uint8* bits, int32 srcWidth, int32 srcHeight, int32 dstWidth,
 }
 
 
+static void
+scale2x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight,
+	int32 srcBPR, int32 dstBPR)
+{
+	/*
+	 * This implements the AdvanceMAME Scale2x algorithm found on:
+	 * http://scale2x.sourceforge.net/
+	 * 
+	 * It is an incredibly simple and powerful image doubling routine that does
+	 * an astonishing job of doubling game graphic data while interpolating out
+	 * the jaggies.
+	 *
+	 * Derived from the (public domain) SDL version of the library by Pete
+	 * Shinners
+	 */
+
+	// Assume that both src and dst are 4 BPP (B_RGBA32)
+	for (int32 y = 0; y < srcHeight; ++y) {
+		for (int32 x = 0; x < srcWidth; ++x) {
+			uint32 b = *(uint32*)(srcBits + (MAX(0, y - 1) * srcBPR)
+				+ (4 * x));
+			uint32 d = *(uint32*)(srcBits + (y * srcBPR)
+				+ (4 * MAX(0, x - 1)));
+			uint32 e = *(uint32*)(srcBits + (y * srcBPR)
+				+ (4 * x));
+			uint32 f = *(uint32*)(srcBits + (y * srcBPR)
+				+ (4 * MIN(srcWidth - 1, x + 1)));
+			uint32 h = *(uint32*)(srcBits + (MIN(srcHeight - 1, y + 1)
+				* srcBPR) + (4 * x));
+
+			uint32 e0 = d == b && b != f && d != h ? d : e;
+			uint32 e1 = b == f && b != d && f != h ? f : e;
+			uint32 e2 = d == h && d != b && h != f ? d : e;
+			uint32 e3 = h == f && d != h && b != f ? f : e;
+
+			*(uint32*)(dstBits + y * 2 * dstBPR + x * 2 * 4) = e0;
+			*(uint32*)(dstBits + y * 2 * dstBPR + (x * 2 + 1) * 4) = e1;
+			*(uint32*)(dstBits + (y * 2 + 1) * dstBPR + x * 2 * 4) = e2;
+			*(uint32*)(dstBits + (y * 2 + 1) * dstBPR + (x * 2 + 1) * 4) = e3;
+		}
+	}
+}
+
+
 //	#pragma mark -
 
 
@@ -448,12 +493,6 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height,
 		return B_ERROR;
 	}
 
-//#if __HAIKU__
-//
-//	return result->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8);
-//
-//#else
-
 	if (result->ColorSpace() != B_RGBA32 && result->ColorSpace() != B_RGB32) {
 		// TODO: support other color spaces
 		return B_BAD_VALUE;
@@ -464,6 +503,9 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height,
 
 	const rgb_color* colorMap = system_colors()->color_list;
 
+	const uint8* srcStart = src;
+	uint8* dstStart = dst;
+
 	for (uint32 y = 0; y < height; y++) {
 		uint32* d = (uint32*)dst;
 		const uint8* s = src;
@@ -480,15 +522,26 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height,
 		dst += dstBPR;
 	}
 
+	// reset src and dst back to their original locations
+	src = srcStart;
+	dst = dstStart;
+
 	if (dstWidth > width || dstHeight > height) {
-		// up scaling
-		scale_bilinear((uint8*)result->Bits(), width, height, dstWidth,
-			dstHeight, dstBPR);
+		if (dstWidth == 2 * width && dstHeight == 2 * height) {
+			// scale using the scale2x algorithm
+			BBitmap* converted = new BBitmap(BRect(0, 0, width - 1, height - 1),
+				result->ColorSpace());
+			converted->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8);
+			uint8* convertedBits = (uint8*)converted->Bits();
+			int32 convertedBPR = converted->BytesPerRow();
+			scale2x(convertedBits, dst, width, height, convertedBPR, dstBPR);
+		} else {
+			// bilinear scaling
+			scale_bilinear(dst, width, height, dstWidth, dstHeight, dstBPR);
+		}
 	}
 
 	return B_OK;
-
-//#endif // __HAIKU__
 }