From a7fc167f214fd29eb62713c712e858031c31daf1 Mon Sep 17 00:00:00 2001
From: John Hawthorn <john.hawthorn@gmail.com>
Date: Mon, 21 Dec 2009 17:13:04 -0800
Subject: added super sampling scale

---
 src/meh.h   |  4 ++--
 src/scale.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 76 insertions(+), 8 deletions(-)

diff --git a/src/meh.h b/src/meh.h
index f2d5e3c..602ecee 100644
--- a/src/meh.h
+++ b/src/meh.h
@@ -33,8 +33,8 @@ struct image{
 
 
 /* scale */
-void scale(struct image *img, int width, int height, int bytesperline, char* __restrict__ newBuf);
-void nearestscale(struct image *img, int width, int height, int bytesperline, char* __restrict__ newBuf);
+void scale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf);
+void nearestscale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf);
 
 /* XLib */
 void setaspect(unsigned int w, unsigned int h);
diff --git a/src/scale.c b/src/scale.c
index 21fa505..6555af3 100644
--- a/src/scale.c
+++ b/src/scale.c
@@ -1,4 +1,6 @@
 
+#include <assert.h>
+#include <string.h>
 #include <stdint.h>
 #include <sys/time.h>
 #include "meh.h"
@@ -34,9 +36,64 @@
 	ibuf = &img->buf[y * img->bufheight / height * img->bufwidth * 3];\
 	ibufn = ibuf + dy;
 
+/*
+ * Super sampling scale. Down only.
+ */
+static void superscale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf){
+	uint32_t x, y, i;
+	unsigned char * __restrict__ ibuf;
+	ibuf = &img->buf[0];
+
+	TDEBUG_START
+
+	int divx[bytesperline];
+	int divy[bytesperline];
+	memset(divx, 0, sizeof divx);
+	memset(divy, 0, sizeof divy);
+	for(x = 0; x < img->bufwidth; x++){
+		 divx[x * width / img->bufwidth]++;
+	}
+	for(y = 0; y < img->bufheight; y++){
+		 divy[y * height / img->bufheight]++;
+	}
+
+	int xoff[img->bufwidth];
+	for(x = 0; x < img->bufwidth; x++){
+		xoff[x] = (x * width / img->bufwidth) * 3;
+	}
 
-void scale(struct image *img, int width, int height, int bytesperline, char* __restrict__ newBuf){
-	int x, y;
+	int tmp[width * 4];
+	unsigned int y0;
+	for(y = 0; y < img->bufheight;){
+		int ydiv = divy[y * height / img->bufheight];
+		char * __restrict__ ydest = &newBuf[bytesperline * (y * height / img->bufheight)];
+		memset(tmp, 0, sizeof tmp);
+		ibuf = &img->buf[y * img->bufwidth * 3];
+		for(y0 = y; y < y0 + ydiv; y++){
+			for(x = 0; x < img->bufwidth; x++){
+				int * __restrict__ dest = tmp + xoff[x];
+				for(i = 0; i < 3; i++){
+					*dest++ += *ibuf++;
+				}
+			}
+		}
+		int * __restrict__ src = tmp;
+		for(x = 0; x < width; x++){
+			ydest[2] = *src++ / ydiv / divx[x];
+			ydest[1] = *src++ / ydiv / divx[x];
+			ydest[0] = *src++ / ydiv / divx[x];
+			ydest += 4;
+		}
+	}
+
+	TDEBUG_END("superscale")
+}
+
+/*
+ * Bilinear scale. Used for up only.
+ */
+static void bilinearscale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf){
+	unsigned int x, y;
 	const unsigned char * __restrict__ ibuf;
 	const unsigned char * __restrict__ ibufn;
 	const unsigned char * const bufend = &img->buf[img->bufwidth * img->bufheight * 3];
@@ -86,11 +143,22 @@ void scale(struct image *img, int width, int height, int bytesperline, char* __r
 		y++;
 	}
 
-	TDEBUG_END("scale")
+	TDEBUG_END("bilinearscale")
+}
+
+void scale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf){
+	if(width < img->bufwidth){
+		superscale(img, width, height, bytesperline, newBuf);
+	}else{
+		bilinearscale(img, width, height, bytesperline, newBuf);
+	}
 }
 
-void nearestscale(struct image *img, int width, int height, int bytesperline, char* __restrict__ newBuf){
-	int x, y;
+/*
+ * Nearest neighbour. Fast up and down.
+ */
+void nearestscale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf){
+	unsigned int x, y;
 	unsigned char * __restrict__ ibuf;
 	unsigned int jdy = bytesperline / 4 - width;
 	unsigned int dx = (img->bufwidth << 10) / width;
@@ -111,7 +179,7 @@ void nearestscale(struct image *img, int width, int height, int bytesperline, ch
 		newBuf += jdy;
 	}
 
-	TDEBUG_END("linearscale")
+	TDEBUG_END("nearestscale")
 }
 
 
-- 
cgit v1.2.3