src/sampler.cc
branchpyrit
changeset 77 dbe8438d5dca
parent 53 228cb8bfdd54
child 82 930a2d3ecaed
--- a/src/sampler.cc	Mon Apr 21 19:35:27 2008 +0200
+++ b/src/sampler.cc	Tue Apr 22 13:33:12 2008 +0200
@@ -40,91 +40,222 @@
 	const int samples = gridsamples[oversample];
 	if ( phase == 0 )
 	{
-		phase++;
-		sx = -1;
-		return w*h*samples;
+		if (subsample > 1)
+		{
+			phase = 1;
+			sx = -1;
+			return (w/subsample+1)*(h/subsample+1);
+		}
+		else
+		{
+			phase = 2;
+			sx = -1;
+			return w*h*samples;
+		}
 	}
-	else if ( phase == 1 && oversample )
+	if ( phase == 1 )
 	{
-		phase = -1;
+		// finalize subsampling
+		const Float subsample2 = 1.0/(subsample*subsample);
+		int num_samples = 0;
+		Colour ic;
+		phase = 2;
+		sx = -1;
+		for (int y = 0; y < h/subsample; y++)
+			for (int x = 0; x < w/subsample; x++)
+			{
+				int x1 = x*subsample;
+				int y1 = y*subsample;
+				int x2 = (x+1)*subsample;
+				int y2 = (y+1)*subsample;
+				if (x2 > w-1)	x2 = w-1;
+				if (y2 > h-1)	y2 = h-1;
+				if (x1 == x2 || y1 == y2)
+					continue;
+				Float *p;
+				p = buffer + 3*(y1*w + x1);
+				Colour c1(*p, *(p+1), *(p+2));
+				p = buffer + 3*(y1*w + x2);
+				Colour c2(*p, *(p+1), *(p+2));
+				p = buffer + 3*(y2*w + x1);
+				Colour c3(*p, *(p+1), *(p+2));
+				p = buffer + 3*(y2*w + x2);
+				Colour c4(*p, *(p+1), *(p+2));
+				Float m = (c1-c2).mag2();
+				m = max(m, (c2-c3).mag2());
+				m = max(m, (c3-c4).mag2());
+				m = max(m, (c4-c1).mag2());
+				if (m < 0.002)
+				{
+					// interpolate
+					for (int i = 0; i < subsample; i++)
+						for (int j = 0; j < subsample; j++)
+						{
+							ic = c1*(subsample-i)*(subsample-j)*subsample2
+								+ c2*(i)*(subsample-j)*subsample2
+								+ c3*(subsample-i)*(j)*subsample2
+								+ c4*(i)*(j)*subsample2;
+							p = buffer + 3*((y1+j)*w + x1+i);
+							*(p + 0) = ic.r;
+							*(p + 1) = oversample ? -ic.g : ic.g;
+							*(p + 2) = ic.b;
+						}
+				}
+				else
+				{
+					// mark as to be computed
+					num_samples += subsample * subsample;
+					for (int i = 0; i < subsample; i++)
+						for (int j = 0; j < subsample; j++)
+							if (oversample || i != 0 || j != 0)
+								*(buffer + 3*((y1+j)*w + x1+i)) = -1.;
+				}
+			}
+		return num_samples;
+	}
+	if ( phase == 2 && oversample )
+	{
+		// finalize oversampling
 		Float *buf;
-		for (buf = buffer; buf != buffer + w*h*3; buf++)
-			*buf = *buf * (1.0/samples);
-		return 0;
+		if (subsample > 1)
+			for (buf = buffer; buf != buffer + w*h*3; buf += 3)
+				if (*(buf+1) < 0)
+				{
+					// interpolated
+					*(buf+1) = -*(buf+1);
+				}
+				else
+				{
+					*buf = *buf * (1.0/samples);
+					*(buf+1) = *(buf+1) * (1.0/samples);
+					*(buf+2) = *(buf+2) * (1.0/samples);
+				}
+		else
+			for (buf = buffer; buf != buffer + w*h*3; buf++)
+				*buf = *buf * (1.0/samples);
 	}
-	else
-	{
-		phase = -1;
-		return 0;
-	}
+	phase = -1;
+	return 0;
 }
 
 bool DefaultSampler::nextSample(Sample* s)
 {
-	/* grid oversampling */
-	static const int gridsamples[] = {1,5,9,16};
-	static const Float osa5x[] = {0.0, -0.4, +0.4, +0.4, -0.4};
-	static const Float osa5y[] = {0.0, -0.4, -0.4, +0.4, +0.4};
-	static const Float osa9x[] = {-0.34,  0.00, +0.34,
-		-0.34,  0.00, +0.34, -0.34,  0.00, +0.34};
-	static const Float osa9y[] = {-0.34, -0.34, -0.34,
-			0.00,  0.00,  0.00, +0.34, +0.34, +0.34};
-	static const Float osa16x[] = {-0.375, -0.125, +0.125, +0.375,
-		-0.375, -0.125, +0.125, +0.375, -0.375, -0.125, +0.125, +0.375,
-		-0.375, -0.125, +0.125, +0.375};
-	static const Float osa16y[] = {-0.375, -0.375, -0.375, -0.375,
-		-0.125, -0.125, -0.125, -0.125, +0.125, +0.125, +0.125, +0.125,
-		+0.375, +0.375, +0.375, +0.375};
-	static const Float *osaSx[] = {NULL, osa5x, osa9x, osa16x};
-	static const Float *osaSy[] = {NULL, osa5y, osa9y, osa16y};
-	const int samples = gridsamples[oversample];
-	const Float *osax = osaSx[oversample];
-	const Float *osay = osaSy[oversample];
-
-	if (sx < 0)
+	if (phase == 1)
 	{
-		// first sample
-		s->x = -(Float)w/h/2.0;
-		s->y = -0.5;
-		sx = 0;
-		sy = 0;
-		osa_samp = 0;
-	}
-	else
-	{
-		osa_samp++;
-
-		if (oversample && oversample <= 3 && osa_samp < samples)
+		// subsampling
+		if (sx < 0)
 		{
-			s->x = osax[osa_samp]/h + (Float)sx/h - (Float)w/h/2.0;
-			s->y = osay[osa_samp]/h + (Float)sy/h - 0.5;
+			// first sample
+			s->x = -(Float)w/h/2.0;
+			s->y = -0.5;
+			sx = 0;
+			sy = 0;
+			osa_samp = 0;
 		}
 		else
 		{
-			sx++;
-			if (sx >= w)
+			if (sx == w-1)
 			{
+				if (sy == h-1)
+					return false;
+				sy += subsample;
+				if (sy > h-1)
+					sy = h-1;
 				sx = 0;
-				sy++;
 			}
-
-			if (sy >= h)
-				return false;
+			else
+			{
+				sx += subsample;
+				if (sx > w-1)
+					sx = w-1;
+			}
 
 			s->x = (Float)sx/h - (Float)w/h/2.0;
 			s->y = (Float)sy/h - 0.5;
-			osa_samp = 0;
 		}
 	}
-
-	if (osa_samp == 0 && oversample && oversample <= 3)
+	else if (phase == 2)
 	{
-		s->x += osax[0]/h;
-		s->y += osay[0]/h;
-		Float *buf = buffer + 3*(sy*w + sx);
-		*(buf++) = 0;
-		*(buf++) = 0;
-		*(buf++) = 0;
+		/* grid oversampling */
+		static const int gridsamples[] = {1,5,9,16};
+		static const Float osa5x[] = {0.0, -0.4, +0.4, +0.4, -0.4};
+		static const Float osa5y[] = {0.0, -0.4, -0.4, +0.4, +0.4};
+		static const Float osa9x[] = {-0.34,  0.00, +0.34,
+			-0.34,  0.00, +0.34, -0.34,  0.00, +0.34};
+		static const Float osa9y[] = {-0.34, -0.34, -0.34,
+				0.00,  0.00,  0.00, +0.34, +0.34, +0.34};
+		static const Float osa16x[] = {-0.375, -0.125, +0.125, +0.375,
+			-0.375, -0.125, +0.125, +0.375, -0.375, -0.125, +0.125, +0.375,
+			-0.375, -0.125, +0.125, +0.375};
+		static const Float osa16y[] = {-0.375, -0.375, -0.375, -0.375,
+			-0.125, -0.125, -0.125, -0.125, +0.125, +0.125, +0.125, +0.125,
+			+0.375, +0.375, +0.375, +0.375};
+		static const Float *osaSx[] = {NULL, osa5x, osa9x, osa16x};
+		static const Float *osaSy[] = {NULL, osa5y, osa9y, osa16y};
+		const int samples = gridsamples[oversample];
+		const Float *osax = osaSx[oversample];
+		const Float *osay = osaSy[oversample];
+
+		if (sx < 0)
+		{
+			// first sample
+			s->x = -(Float)w/h/2.0;
+			s->y = -0.5;
+			sx = 0;
+			sy = 0;
+			osa_samp = 0;
+		}
+		else
+		{
+			osa_samp++;
+
+			if (oversample && oversample <= 3 && osa_samp < samples)
+			{
+				s->x = osax[osa_samp]/h + (Float)sx/h - (Float)w/h/2.0;
+				s->y = osay[osa_samp]/h + (Float)sy/h - 0.5;
+			}
+			else
+			{
+				sx++;
+				if (sx >= w)
+				{
+					sx = 0;
+					sy++;
+				}
+				if (sy >= h)
+					return false;
+
+				if (subsample > 1)
+				{
+					// find next not interpolated pixel
+					while ( *(buffer + 3*(sy*w + sx)) >= 0. )
+					{
+						sx++;
+						if (sx >= w)
+						{
+							sx = 0;
+							sy++;
+						}
+						if (sy >= h)
+							return false;
+					}
+				}
+
+				s->x = (Float)sx/h - (Float)w/h/2.0;
+				s->y = (Float)sy/h - 0.5;
+				osa_samp = 0;
+			}
+		}
+
+		if (osa_samp == 0 && oversample && oversample <= 3)
+		{
+			s->x += osax[0]/h;
+			s->y += osay[0]/h;
+			Float *buf = buffer + 3*(sy*w + sx);
+			*(buf++) = 0;
+			*(buf++) = 0;
+			*(buf++) = 0;
+		}
 	}
 
 	s->sx = sx;
@@ -137,7 +268,7 @@
 void DefaultSampler::saveSample(Sample &samp, Colour &col)
 {
 	Float *buf = buffer + 3*(samp.sy * w + samp.sx);
-	if (oversample)
+	if (phase == 2 && oversample)
 	{
 		*(buf+0) += col.r;
 		*(buf+1) += col.g;